...

Source file src/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package kubelet
    18  
    19  import (
    20  	"net/url"
    21  	"reflect"
    22  	"runtime"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/google/go-cmp/cmp"
    28  	"github.com/google/go-cmp/cmp/cmpopts"
    29  	"github.com/stretchr/testify/assert"
    30  )
    31  
    32  func Test_getLoggingCmd(t *testing.T) {
    33  	tests := []struct {
    34  		name        string
    35  		args        nodeLogQuery
    36  		wantLinux   []string
    37  		wantWindows []string
    38  		wantOtherOS []string
    39  	}{
    40  		{
    41  			args:        nodeLogQuery{},
    42  			wantLinux:   []string{"--utc", "--no-pager", "--output=short-precise"},
    43  			wantWindows: []string{"-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", "Get-WinEvent -FilterHashtable @{LogName='Application'} | Sort-Object TimeCreated | Format-Table -AutoSize -Wrap"},
    44  		},
    45  	}
    46  	for _, tt := range tests {
    47  		t.Run(tt.name, func(t *testing.T) {
    48  			_, got, err := getLoggingCmd(&tt.args, []string{})
    49  			switch os := runtime.GOOS; os {
    50  			case "linux":
    51  				if !reflect.DeepEqual(got, tt.wantLinux) {
    52  					t.Errorf("getLoggingCmd() = %v, want %v", got, tt.wantLinux)
    53  				}
    54  			case "windows":
    55  				if !reflect.DeepEqual(got, tt.wantWindows) {
    56  					t.Errorf("getLoggingCmd() = %v, want %v", got, tt.wantWindows)
    57  				}
    58  			default:
    59  				if err == nil {
    60  					t.Errorf("getLoggingCmd() = %v, want err", got)
    61  				}
    62  			}
    63  		})
    64  	}
    65  }
    66  
    67  func Test_newNodeLogQuery(t *testing.T) {
    68  	validTimeValue := "2019-12-04T02:00:00Z"
    69  	validT, _ := time.Parse(time.RFC3339, validTimeValue)
    70  	tests := []struct {
    71  		name    string
    72  		query   url.Values
    73  		want    *nodeLogQuery
    74  		wantErr bool
    75  	}{
    76  		{name: "empty", query: url.Values{}, want: nil},
    77  		{query: url.Values{"unknown": []string{"true"}}, want: nil},
    78  
    79  		{query: url.Values{"sinceTime": []string{""}}, want: nil},
    80  		{query: url.Values{"sinceTime": []string{"2019-12-04 02:00:00"}}, wantErr: true},
    81  		{query: url.Values{"sinceTime": []string{"2019-12-04 02:00:00.000"}}, wantErr: true},
    82  		{query: url.Values{"sinceTime": []string{"2019-12-04 02"}}, wantErr: true},
    83  		{query: url.Values{"sinceTime": []string{"2019-12-04 02:00"}}, wantErr: true},
    84  		{query: url.Values{"sinceTime": []string{validTimeValue}},
    85  			want: &nodeLogQuery{options: options{SinceTime: &validT}}},
    86  
    87  		{query: url.Values{"untilTime": []string{""}}, want: nil},
    88  		{query: url.Values{"untilTime": []string{"2019-12-04 02:00:00"}}, wantErr: true},
    89  		{query: url.Values{"untilTime": []string{"2019-12-04 02:00:00.000"}}, wantErr: true},
    90  		{query: url.Values{"untilTime": []string{"2019-12-04 02"}}, wantErr: true},
    91  		{query: url.Values{"untilTime": []string{"2019-12-04 02:00"}}, wantErr: true},
    92  		{query: url.Values{"untilTime": []string{validTimeValue}},
    93  			want: &nodeLogQuery{options: options{UntilTime: &validT}}},
    94  
    95  		{query: url.Values{"tailLines": []string{"100"}}, want: &nodeLogQuery{options: options{TailLines: intPtr(100)}}},
    96  		{query: url.Values{"tailLines": []string{"foo"}}, wantErr: true},
    97  		{query: url.Values{"tailLines": []string{" "}}, wantErr: true},
    98  
    99  		{query: url.Values{"pattern": []string{"foo"}}, want: &nodeLogQuery{options: options{Pattern: "foo"}}},
   100  
   101  		{query: url.Values{"boot": []string{""}}, want: nil},
   102  		{query: url.Values{"boot": []string{"0"}}, want: &nodeLogQuery{options: options{Boot: intPtr(0)}}},
   103  		{query: url.Values{"boot": []string{"-23"}}, want: &nodeLogQuery{options: options{Boot: intPtr(-23)}}},
   104  		{query: url.Values{"boot": []string{"foo"}}, wantErr: true},
   105  		{query: url.Values{"boot": []string{" "}}, wantErr: true},
   106  
   107  		{query: url.Values{"query": []string{""}}, wantErr: true},
   108  		{query: url.Values{"query": []string{"   ", "    "}}, wantErr: true},
   109  		{query: url.Values{"query": []string{"foo"}}, want: &nodeLogQuery{Services: []string{"foo"}}},
   110  		{query: url.Values{"query": []string{"foo", "bar"}}, want: &nodeLogQuery{Services: []string{"foo", "bar"}}},
   111  		{query: url.Values{"query": []string{"foo", "/bar"}}, want: &nodeLogQuery{Services: []string{"foo"},
   112  			Files: []string{"/bar"}}},
   113  		{query: url.Values{"query": []string{"/foo", `\bar`}}, want: &nodeLogQuery{Files: []string{"/foo", `\bar`}}},
   114  	}
   115  	for _, tt := range tests {
   116  		t.Run(tt.query.Encode(), func(t *testing.T) {
   117  			got, err := newNodeLogQuery(tt.query)
   118  			if len(err) > 0 != tt.wantErr {
   119  				t.Errorf("newNodeLogQuery() error = %v, wantErr %v", err, tt.wantErr)
   120  				return
   121  			}
   122  			if !reflect.DeepEqual(got, tt.want) {
   123  				t.Errorf("different: %s", cmp.Diff(tt.want, got, cmpopts.IgnoreUnexported(nodeLogQuery{})))
   124  			}
   125  		})
   126  	}
   127  }
   128  
   129  func Test_validateServices(t *testing.T) {
   130  	var (
   131  		service1 = "svc1"
   132  		service2 = "svc2"
   133  		service3 = "svc.foo"
   134  		service4 = "svc_foo"
   135  		service5 = "svc@foo"
   136  		service6 = "svc:foo"
   137  		invalid1 = "svc\n"
   138  		invalid2 = "svc.foo\n"
   139  	)
   140  	tests := []struct {
   141  		name     string
   142  		services []string
   143  		wantErr  bool
   144  	}{
   145  		{name: "one service", services: []string{service1}},
   146  		{name: "two services", services: []string{service1, service2}},
   147  		{name: "dot service", services: []string{service3}},
   148  		{name: "underscore service", services: []string{service4}},
   149  		{name: "at service", services: []string{service5}},
   150  		{name: "colon service", services: []string{service6}},
   151  		{name: "invalid service new line", services: []string{invalid1}, wantErr: true},
   152  		{name: "invalid service with dot", services: []string{invalid2}, wantErr: true},
   153  		{name: "long service", services: []string{strings.Repeat(service1, 100)}, wantErr: true},
   154  		{name: "max number of services", services: []string{service1, service2, service3, service4, service5}, wantErr: true},
   155  	}
   156  	for _, tt := range tests {
   157  		errs := validateServices(tt.services)
   158  		t.Run(tt.name, func(t *testing.T) {
   159  			if len(errs) > 0 != tt.wantErr {
   160  				t.Errorf("validateServices() error = %v, wantErr %v", errs, tt.wantErr)
   161  				return
   162  			}
   163  		})
   164  	}
   165  }
   166  
   167  func Test_nodeLogQuery_validate(t *testing.T) {
   168  	var (
   169  		service1 = "svc1"
   170  		service2 = "svc2"
   171  		file1    = "/test1.log"
   172  		file2    = "/test2.log"
   173  		pattern  = "foo"
   174  		invalid  = "foo\\"
   175  	)
   176  	since, err := time.Parse(time.RFC3339, "2023-01-04T02:00:00Z")
   177  	assert.NoError(t, err)
   178  	until, err := time.Parse(time.RFC3339, "2023-02-04T02:00:00Z")
   179  	assert.NoError(t, err)
   180  
   181  	tests := []struct {
   182  		name     string
   183  		Services []string
   184  		Files    []string
   185  		options  options
   186  		wantErr  bool
   187  	}{
   188  		{name: "empty", wantErr: true},
   189  		{name: "empty with options", options: options{SinceTime: &since}, wantErr: true},
   190  		{name: "one service", Services: []string{service1}},
   191  		{name: "two services", Services: []string{service1, service2}},
   192  		{name: "one service one file", Services: []string{service1}, Files: []string{file1}, wantErr: true},
   193  		{name: "two files", Files: []string{file1, file2}, wantErr: true},
   194  		{name: "one file options", Files: []string{file1}, options: options{Pattern: pattern}, wantErr: true},
   195  		{name: "invalid pattern", Services: []string{service1}, options: options{Pattern: invalid}, wantErr: true},
   196  		{name: "since", Services: []string{service1}, options: options{SinceTime: &since}},
   197  		{name: "until", Services: []string{service1}, options: options{UntilTime: &until}},
   198  		{name: "since until", Services: []string{service1}, options: options{SinceTime: &until, UntilTime: &since},
   199  			wantErr: true},
   200  		// boot is not supported on Windows.
   201  		{name: "boot", Services: []string{service1}, options: options{Boot: intPtr(-1)}, wantErr: runtime.GOOS == "windows"},
   202  		{name: "boot out of range", Services: []string{service1}, options: options{Boot: intPtr(1)}, wantErr: true},
   203  		{name: "tailLines", Services: []string{service1}, options: options{TailLines: intPtr(100)}},
   204  		{name: "tailLines out of range", Services: []string{service1}, options: options{TailLines: intPtr(100000)}},
   205  	}
   206  	for _, tt := range tests {
   207  		t.Run(tt.name, func(t *testing.T) {
   208  			n := &nodeLogQuery{
   209  				Services: tt.Services,
   210  				Files:    tt.Files,
   211  				options:  tt.options,
   212  			}
   213  			errs := n.validate()
   214  			if len(errs) > 0 != tt.wantErr {
   215  				t.Errorf("nodeLogQuery.validate() error = %v, wantErr %v", errs, tt.wantErr)
   216  				return
   217  			}
   218  		})
   219  	}
   220  }
   221  
   222  func intPtr(i int) *int {
   223  	return &i
   224  }
   225  

View as plain text