1
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
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