1
16
17 package util
18
19 import (
20 "errors"
21 "fmt"
22 "os"
23 "path/filepath"
24 "testing"
25 "time"
26
27 "github.com/blang/semver/v4"
28 "github.com/stretchr/testify/require"
29 )
30
31 func TestPackagesAvailableSuccess(t *testing.T) {
32 testcases := [][]string{
33 {"bash"},
34 {"bash", "curl", "grep"},
35 {},
36 }
37
38 for _, packages := range testcases {
39 available, err := PackagesAvailable(packages...)
40 require.Nil(t, err)
41 require.True(t, available)
42 }
43 }
44
45 func TestPackagesAvailableFailure(t *testing.T) {
46 testcases := [][]string{
47 {
48 "fakepackagefoo",
49 },
50 {
51 "fakepackagefoo",
52 "fakepackagebar",
53 "fakepackagebaz",
54 },
55 {
56 "bash",
57 "fakepackagefoo",
58 "fakepackagebar",
59 },
60 }
61
62 for _, packages := range testcases {
63 actual, err := PackagesAvailable(packages...)
64 require.Nil(t, err)
65 require.False(t, actual)
66 }
67 }
68
69 func TestMoreRecent(t *testing.T) {
70 baseTmpDir, err := os.MkdirTemp("", "")
71 require.Nil(t, err)
72
73
74 testFileOne := filepath.Join(baseTmpDir, "testone.txt")
75 require.Nil(t, os.WriteFile(
76 testFileOne,
77 []byte("file-one-contents"),
78 os.FileMode(0o644),
79 ))
80
81 time.Sleep(1 * time.Second)
82
83 testFileTwo := filepath.Join(baseTmpDir, "testtwo.txt")
84 require.Nil(t, os.WriteFile(
85 testFileTwo,
86 []byte("file-two-contents"),
87 os.FileMode(0o644),
88 ))
89
90 notFile := filepath.Join(baseTmpDir, "noexist.txt")
91
92 defer cleanupTmp(t, baseTmpDir)
93
94 type args struct {
95 a string
96 b string
97 }
98 type want struct {
99 r bool
100 err error
101 }
102 cases := map[string]struct {
103 args args
104 want want
105 }{
106 "AIsRecent": {
107 args: args{
108 a: testFileTwo,
109 b: testFileOne,
110 },
111 want: want{
112 r: true,
113 err: nil,
114 },
115 },
116 "AIsNotRecent": {
117 args: args{
118 a: testFileOne,
119 b: testFileTwo,
120 },
121 want: want{
122 r: false,
123 err: nil,
124 },
125 },
126 "ADoesNotExist": {
127 args: args{
128 a: notFile,
129 b: testFileTwo,
130 },
131 want: want{
132 r: false,
133 err: nil,
134 },
135 },
136 "BDoesNotExist": {
137 args: args{
138 a: testFileOne,
139 b: notFile,
140 },
141 want: want{
142 r: true,
143 err: nil,
144 },
145 },
146 "NeitherExists": {
147 args: args{
148 a: notFile,
149 b: notFile,
150 },
151 want: want{
152 r: false,
153 err: errors.New("neither file exists"),
154 },
155 },
156 }
157
158 for name, tc := range cases {
159 t.Run(name, func(t *testing.T) {
160 more, err := MoreRecent(tc.args.a, tc.args.b)
161 require.IsType(t, tc.want.err, err)
162 require.Equal(t, tc.want.r, more)
163 })
164 }
165 }
166
167 func TestCopyFile(t *testing.T) {
168 srcDir, err := os.MkdirTemp("", "src")
169 require.Nil(t, err)
170 dstDir, err := os.MkdirTemp("", "dst")
171 require.Nil(t, err)
172
173
174 srcFileOnePath := filepath.Join(srcDir, "testone.txt")
175 require.Nil(t, os.WriteFile(
176 srcFileOnePath,
177 []byte("file-one-contents"),
178 os.FileMode(0o644),
179 ))
180
181 dstFileOnePath := filepath.Join(dstDir, "testone.txt")
182
183 defer cleanupTmp(t, srcDir)
184 defer cleanupTmp(t, dstDir)
185
186 type args struct {
187 src string
188 dst string
189 required bool
190 }
191 cases := map[string]struct {
192 args args
193 shouldError bool
194 }{
195 "CopyFileSuccess": {
196 args: args{
197 src: srcFileOnePath,
198 dst: dstFileOnePath,
199 required: true,
200 },
201 shouldError: false,
202 },
203 "CopyFileNotExistNotIgnore": {
204 args: args{
205 src: "path/does/not/exit",
206 dst: dstFileOnePath,
207 required: true,
208 },
209 shouldError: true,
210 },
211 "CopyFileNotExistIgnore": {
212 args: args{
213 src: "path/does/not/exit",
214 dst: dstFileOnePath,
215 required: false,
216 },
217 shouldError: false,
218 },
219 }
220
221 for name, tc := range cases {
222 t.Run(name, func(t *testing.T) {
223 copyErr := CopyFileLocal(tc.args.src, tc.args.dst, tc.args.required)
224 if tc.shouldError {
225 require.NotNil(t, copyErr)
226 } else {
227 require.Nil(t, copyErr)
228 }
229 if copyErr == nil {
230 _, err := os.Stat(tc.args.dst)
231 if err != nil && tc.args.required {
232 t.Fatal("file does not exist in destination")
233 }
234 }
235 })
236 }
237 }
238
239 func TestCopyDirContentLocal(t *testing.T) {
240 srcDir, err := os.MkdirTemp("", "src")
241 require.Nil(t, err)
242 dstDir, err := os.MkdirTemp("", "dst")
243 require.Nil(t, err)
244
245
246 srcFileOnePath := filepath.Join(srcDir, "testone.txt")
247 require.Nil(t, os.WriteFile(
248 srcFileOnePath,
249 []byte("file-one-contents"),
250 os.FileMode(0o644),
251 ))
252
253 srcFileTwoPath := filepath.Join(srcDir, "testtwo.txt")
254 require.Nil(t, os.WriteFile(
255 srcFileTwoPath,
256 []byte("file-two-contents"),
257 os.FileMode(0o644),
258 ))
259
260 defer cleanupTmp(t, srcDir)
261 defer cleanupTmp(t, dstDir)
262
263 type args struct {
264 src string
265 dst string
266 }
267 type want struct {
268 err error
269 }
270 cases := map[string]struct {
271 args args
272 want want
273 }{
274 "CopyDirContentsSuccess": {
275 args: args{
276 src: srcDir,
277 dst: dstDir,
278 },
279 want: want{
280 err: nil,
281 },
282 },
283 "CopyDirContentsSuccessDstNotExist": {
284 args: args{
285 src: srcDir,
286 dst: filepath.Join(dstDir, "path-not-exist"),
287 },
288 want: want{
289 err: nil,
290 },
291 },
292 }
293
294 for name, tc := range cases {
295 t.Run(name, func(t *testing.T) {
296 copyErr := CopyDirContentsLocal(tc.args.src, tc.args.dst)
297 require.Equal(t, tc.want.err, copyErr)
298 })
299 }
300 }
301
302 func TestRemoveAndReplaceDir(t *testing.T) {
303 dir, err := os.MkdirTemp("", "rm")
304 require.Nil(t, err)
305
306
307 fileOnePath := filepath.Join(dir, "testone.txt")
308 require.Nil(t, os.WriteFile(
309 fileOnePath,
310 []byte("file-one-contents"),
311 os.FileMode(0o644),
312 ))
313
314 fileTwoPath := filepath.Join(dir, "testtwo.txt")
315 require.Nil(t, os.WriteFile(
316 fileTwoPath,
317 []byte("file-two-contents"),
318 os.FileMode(0o644),
319 ))
320
321 defer cleanupTmp(t, dir)
322
323 type args struct {
324 dir string
325 }
326 type want struct {
327 err error
328 }
329 cases := map[string]struct {
330 args args
331 want want
332 }{
333 "RemoveAndReplaceSuccess": {
334 args: args{
335 dir: dir,
336 },
337 want: want{
338 err: nil,
339 },
340 },
341 "RemoveAndReplaceNotExist": {
342 args: args{
343 dir: filepath.Join(dir, "not-exit"),
344 },
345 want: want{
346 err: nil,
347 },
348 },
349 }
350
351 for name, tc := range cases {
352 t.Run(name, func(t *testing.T) {
353 err := RemoveAndReplaceDir(tc.args.dir)
354 require.Equal(t, tc.want.err, err)
355 })
356 }
357 }
358
359 func TestExist(t *testing.T) {
360 dir, err := os.MkdirTemp("", "rm")
361 require.Nil(t, err)
362
363
364 fileOnePath := filepath.Join(dir, "testone.txt")
365 require.Nil(t, os.WriteFile(
366 fileOnePath,
367 []byte("file-one-contents"),
368 os.FileMode(0o644),
369 ))
370
371 defer cleanupTmp(t, dir)
372
373 type args struct {
374 dir string
375 }
376 type want struct {
377 exist bool
378 }
379 cases := map[string]struct {
380 args args
381 want want
382 }{
383 "DirExists": {
384 args: args{
385 dir: dir,
386 },
387 want: want{
388 exist: true,
389 },
390 },
391 "FileExists": {
392 args: args{
393 dir: fileOnePath,
394 },
395 want: want{
396 exist: true,
397 },
398 },
399 "DirNotExists": {
400 args: args{
401 dir: filepath.Join(dir, "path-not-exit"),
402 },
403 want: want{
404 exist: false,
405 },
406 },
407 "FileNotExists": {
408 args: args{
409 dir: filepath.Join(dir, "notexist.txt"),
410 },
411 want: want{
412 exist: false,
413 },
414 },
415 }
416
417 for name, tc := range cases {
418 t.Run(name, func(t *testing.T) {
419 exist := Exists(tc.args.dir)
420 require.Equal(t, tc.want.exist, exist)
421 })
422 }
423 }
424
425 func cleanupTmp(t *testing.T, dir string) {
426 require.Nil(t, os.RemoveAll(dir))
427 }
428
429 func TestTagStringToSemver(t *testing.T) {
430
431 version, err := TagStringToSemver("v1.2.3")
432 require.Nil(t, err)
433 require.Equal(t, version, semver.Version{Major: 1, Minor: 2, Patch: 3})
434
435
436 version, err = TagStringToSemver("invalid")
437 require.NotNil(t, err)
438 require.Equal(t, version, semver.Version{})
439
440
441 version, err = TagStringToSemver("")
442 require.NotNil(t, err)
443 require.Equal(t, version, semver.Version{})
444 }
445
446 func TestSemverToTagString(t *testing.T) {
447 version := semver.Version{Major: 1, Minor: 2, Patch: 3}
448 require.Equal(t, SemverToTagString(version), "v1.2.3")
449 }
450
451 func TestAddTagPrefix(t *testing.T) {
452 require.Equal(t, "v0.0.0", AddTagPrefix("0.0.0"))
453 require.Equal(t, "v1.0.0", AddTagPrefix("v1.0.0"))
454 }
455
456 func TestTrimTagPrefix(t *testing.T) {
457 require.Equal(t, "0.0.0", TrimTagPrefix("0.0.0"))
458 require.Equal(t, "1.0.0", TrimTagPrefix("1.0.0"))
459 }
460
461 func TestWrapText(t *testing.T) {
462
463 longText := `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut molestie accumsan orci, id congue nibh sollicitudin in. Nulla condimentum arcu eu est hendrerit tempus. Nunc risus nibh, aliquam in ultrices fringilla, aliquet ac purus. Aenean non nibh magna. Nunc lacinia suscipit malesuada. Vivamus porta a leo vel ornare. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi pellentesque orci magna, sed semper nulla fringilla at. Nam elementum ipsum maximus lectus tempor faucibus. Donec eu enim nulla. Integer egestas venenatis tristique. Curabitur id purus sem. Vivamus nec mollis lorem.`
464 wrappedText := "Lorem ipsum dolor sit amet, consectetur\n"
465 wrappedText += "adipiscing elit. Ut molestie accumsan\n"
466 wrappedText += "orci, id congue nibh sollicitudin in.\n"
467 wrappedText += "Nulla condimentum arcu eu est hendrerit\n"
468 wrappedText += "tempus. Nunc risus nibh, aliquam in\n"
469 wrappedText += "ultrices fringilla, aliquet ac purus.\n"
470 wrappedText += "Aenean non nibh magna. Nunc lacinia\n"
471 wrappedText += "suscipit malesuada. Vivamus porta a leo\n"
472 wrappedText += "vel ornare. Orci varius natoque\n"
473 wrappedText += "penatibus et magnis dis parturient\n"
474 wrappedText += "montes, nascetur ridiculus mus. Morbi\n"
475 wrappedText += "pellentesque orci magna, sed semper\n"
476 wrappedText += "nulla fringilla at. Nam elementum ipsum\n"
477 wrappedText += "maximus lectus tempor faucibus. Donec eu\n"
478 wrappedText += "enim nulla. Integer egestas venenatis\n"
479 wrappedText += "tristique. Curabitur id purus sem.\n"
480 wrappedText += "Vivamus nec mollis lorem."
481 require.Equal(t, WrapText(longText, 40), wrappedText)
482 }
483
484 func TestStripSensitiveData(t *testing.T) {
485 testCases := []struct {
486 text string
487 mustChange bool
488 }{
489 {text: "a", mustChange: false},
490 {text: `s;!3Vc2]x~qL&'Sc/W/>^}8pau\.xr;;5uL:mL:h:x-oauth-basic`, mustChange: false},
491 {text: `ab0ff5efdbafcf1def98cac7bd4fa5856d53d000:x-oauth-basic`, mustChange: true},
492 {text: `X-Some-Header: ab0ff5efdbafcf1def98cac7bd4fa5856d53d000:x-oauth-basic;`, mustChange: true},
493 {text: `error: failed to push some refs to 'https://git:538b8ca9618eaf316b8ca37bcf78da2c24639c14@github.com/kubernetes/kubernetes.git'`, mustChange: true},
494 {text: `error: failed to push some refs to 'https://git:538b8c9618a316bca3bcf78da2c24639c35@github.com/kubernetes/kubernetes.git'`, mustChange: true},
495 }
496 for _, tc := range testCases {
497 testBytes := []byte(tc.text)
498 if tc.mustChange {
499 require.NotEqual(t, StripSensitiveData(testBytes), testBytes, fmt.Sprintf("Failed sanitizing %s", tc.text))
500 } else {
501 require.ElementsMatch(t, StripSensitiveData(testBytes), testBytes)
502 }
503 }
504 }
505
506 func TestStripControlCharacters(t *testing.T) {
507 testCases := []struct {
508 text []byte
509 mustChange bool
510 }{
511 {text: append([]byte{27}, []byte("[1m")...), mustChange: true},
512 {text: append([]byte{27}, []byte("[1K")...), mustChange: true},
513 {text: append([]byte{27}, []byte("[1B")...), mustChange: true},
514 {text: append([]byte{27}, []byte("(1B")...), mustChange: true},
515 {text: append([]byte{27}, []byte("[1;1m")...), mustChange: true},
516 {text: append([]byte{27}, []byte("[1;12m")...), mustChange: true},
517 {text: append([]byte{27}, []byte("[21K")...), mustChange: true},
518 {text: append([]byte{}, []byte("[1;13m")...), mustChange: false},
519 {text: append([]byte{27}, []byte("[1,13m")...), mustChange: false},
520 {text: append([]byte("Test line"), []byte{13}...), mustChange: true},
521 {text: append([]byte("Test line"), []byte{13, 15}...), mustChange: false},
522 {text: []byte("Test line"), mustChange: false},
523 }
524 for _, tc := range testCases {
525 if tc.mustChange {
526 require.NotEqual(t, StripControlCharacters(tc.text), tc.text)
527 } else {
528 require.ElementsMatch(t, StripControlCharacters(tc.text), tc.text)
529 }
530 }
531 }
532
533 func TestCleanLogFile(t *testing.T) {
534 line1 := "This is a test log\n"
535 line2 := "It should not contain a test token here:\n"
536 line3 := "nor control characters o bare line feeds here:\n"
537 line4 := "Bare line feed: "
538 line5 := "\nControl Chars: "
539
540
541 originalTokenLine := "7aa33bd2186c40849c4c2df321241e241def98ca:x-oauth-basic"
542 sanitizedTokenLine := string(StripSensitiveData([]byte(originalTokenLine)))
543 require.NotEqual(t, originalTokenLine, sanitizedTokenLine)
544
545
546 originalLog := line1 + line2 + originalTokenLine + line3 +
547 line4 + string([]byte{13}) + line5 +
548 string(append([]byte{27}, []byte("[1;1m")...)) + "\n"
549
550
551 cleanLog := line1 + line2 + sanitizedTokenLine + line3 + line4 + line5 + "\n"
552
553 logfile, err := os.CreateTemp("", "clean-log-test-")
554 require.Nil(t, err, "creating test logfile")
555 defer os.Remove(logfile.Name())
556 err = os.WriteFile(logfile.Name(), []byte(originalLog), os.FileMode(0o644))
557 require.Nil(t, err, "writing test file")
558
559
560 err = CleanLogFile(logfile.Name())
561 require.Nil(t, err, "running log cleaner")
562
563 resultingData, err := os.ReadFile(logfile.Name())
564 require.Nil(t, err, "reading modified file")
565 require.NotEmpty(t, resultingData)
566
567
568 require.NotEqual(t, originalLog, string(resultingData))
569 require.Equal(t, cleanLog, string(resultingData))
570 }
571
View as plain text