]> ruderich.org/simon Gitweb - safcm/safcm.git/blob - cmd/safcm/sync_changes_test.go
767564fd14221a2c37405349b9bc867a777cdaa0
[safcm/safcm.git] / cmd / safcm / sync_changes_test.go
1 // Copyright (C) 2021  Simon Ruderich
2 //
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 package main
17
18 import (
19         "io/fs"
20         "testing"
21
22         "github.com/google/go-cmp/cmp"
23
24         "ruderich.org/simon/safcm"
25         "ruderich.org/simon/safcm/cmd/safcm/config"
26 )
27
28 func TestFormatFileChanges(t *testing.T) {
29         tests := []struct {
30                 name    string
31                 dryRun  bool
32                 changes []safcm.FileChange
33                 exp     string
34         }{
35
36                 {
37                         "regular",
38                         false,
39                         []safcm.FileChange{
40                                 {
41                                         Path:    "created: file",
42                                         Created: true,
43                                         New: safcm.FileChangeInfo{
44                                                 Mode:  0644,
45                                                 User:  "user",
46                                                 Uid:   1000,
47                                                 Group: "group",
48                                                 Gid:   2000,
49                                         },
50                                 },
51                                 {
52                                         Path:    "created: link",
53                                         Created: true,
54                                         New: safcm.FileChangeInfo{
55                                                 Mode:  fs.ModeSymlink | 0777,
56                                                 User:  "user",
57                                                 Uid:   1000,
58                                                 Group: "group",
59                                                 Gid:   2000,
60                                         },
61                                 },
62                                 {
63                                         Path: "type change: file -> dir",
64                                         Old: safcm.FileChangeInfo{
65                                                 Mode:  0751,
66                                                 User:  "user",
67                                                 Uid:   1000,
68                                                 Group: "group",
69                                                 Gid:   2000,
70                                         },
71                                         New: safcm.FileChangeInfo{
72                                                 Mode:  fs.ModeDir | 0751,
73                                                 User:  "user",
74                                                 Uid:   1000,
75                                                 Group: "group",
76                                                 Gid:   2000,
77                                         },
78                                         DataDiff: `@@ -1,2 +1 @@
79 -content
80  
81 `,
82                                 },
83                                 {
84                                         Path: "user change",
85                                         Old: safcm.FileChangeInfo{
86                                                 Mode:  0755,
87                                                 User:  "user",
88                                                 Uid:   1000,
89                                                 Group: "group",
90                                                 Gid:   2000,
91                                         },
92                                         New: safcm.FileChangeInfo{
93                                                 Mode:  0755,
94                                                 User:  "user2",
95                                                 Uid:   1001,
96                                                 Group: "group",
97                                                 Gid:   2000,
98                                         },
99                                 },
100                                 {
101                                         Path: "group change",
102                                         Old: safcm.FileChangeInfo{
103                                                 Mode:  0755,
104                                                 User:  "user",
105                                                 Uid:   1000,
106                                                 Group: "group",
107                                                 Gid:   2000,
108                                         },
109                                         New: safcm.FileChangeInfo{
110                                                 Mode:  0755,
111                                                 User:  "user",
112                                                 Uid:   1000,
113                                                 Group: "group2",
114                                                 Gid:   2001,
115                                         },
116                                 },
117                                 {
118                                         Path: "mode change",
119                                         Old: safcm.FileChangeInfo{
120                                                 Mode:  0755,
121                                                 User:  "user",
122                                                 Uid:   1000,
123                                                 Group: "group",
124                                                 Gid:   2000,
125                                         },
126                                         New: safcm.FileChangeInfo{
127                                                 Mode:  0750,
128                                                 User:  "user",
129                                                 Uid:   1000,
130                                                 Group: "group",
131                                                 Gid:   2000,
132                                         },
133                                 },
134                                 {
135                                         Path: "mode change (setuid)",
136                                         Old: safcm.FileChangeInfo{
137                                                 Mode:  0755,
138                                                 User:  "user",
139                                                 Uid:   1000,
140                                                 Group: "group",
141                                                 Gid:   2000,
142                                         },
143                                         New: safcm.FileChangeInfo{
144                                                 Mode:  0755 | fs.ModeSetuid,
145                                                 User:  "user",
146                                                 Uid:   1000,
147                                                 Group: "group",
148                                                 Gid:   2000,
149                                         },
150                                 },
151                                 {
152                                         Path: "content change",
153                                         Old: safcm.FileChangeInfo{
154                                                 Mode:  0644,
155                                                 User:  "user",
156                                                 Uid:   1000,
157                                                 Group: "group",
158                                                 Gid:   2000,
159                                         },
160                                         New: safcm.FileChangeInfo{
161                                                 Mode:  0644,
162                                                 User:  "user",
163                                                 Uid:   1000,
164                                                 Group: "group",
165                                                 Gid:   2000,
166                                         },
167                                         DataDiff: `@@ -1,2 +1,2 @@
168 -old content
169 +content
170  
171 `,
172                                 },
173                                 {
174                                         Path: "multiple changes",
175                                         Old: safcm.FileChangeInfo{
176                                                 Mode:  0644,
177                                                 User:  "user",
178                                                 Uid:   1000,
179                                                 Group: "group",
180                                                 Gid:   2000,
181                                         },
182                                         New: safcm.FileChangeInfo{
183                                                 Mode:  fs.ModeDir | 0755,
184                                                 User:  "user2",
185                                                 Uid:   1001,
186                                                 Group: "group2",
187                                                 Gid:   2001,
188                                         },
189                                         DataDiff: `@@ -1,2 +1 @@
190 -content
191  
192 `,
193                                 },
194                         },
195                         `changed 9 file(s):
196 "created: file": created, file, user(1000) group(2000), 0644
197 "created: link": created, symlink, user(1000) group(2000), 0777
198 "type change: file -> dir": file -> dir
199    @@ -1,2 +1 @@
200    -content
201     
202 "user change": user(1000) group(2000) -> user2(1001) group(2000)
203 "group change": user(1000) group(2000) -> user(1000) group2(2001)
204 "mode change": 0755 -> 0750
205 "mode change (setuid)": 0755 -> 04755
206 "content change":
207    @@ -1,2 +1,2 @@
208    -old content
209    +content
210     
211 "multiple changes": file -> dir, user(1000) group(2000) -> user2(1001) group2(2001), 0644 -> 0755
212    @@ -1,2 +1 @@
213    -content
214     
215 `,
216                 },
217
218                 {
219                         "dry-run",
220                         true,
221                         []safcm.FileChange{
222                                 {
223                                         Path:    "file",
224                                         Created: true,
225                                         New: safcm.FileChangeInfo{
226                                                 Mode:  0644,
227                                                 User:  "user",
228                                                 Uid:   1000,
229                                                 Group: "group",
230                                                 Gid:   2000,
231                                         },
232                                 },
233                         },
234                         `changed 1 file(s): (dry-run)
235 "file": created, file, user(1000) group(2000), 0644
236 `,
237                 },
238
239                 {
240                         "escaping",
241                         false,
242                         []safcm.FileChange{
243                                 {
244                                         Path:    "\x00",
245                                         Created: true,
246                                         New: safcm.FileChangeInfo{
247                                                 Mode:  0xFFFFFFFF,
248                                                 User:  "\x01",
249                                                 Uid:   -1,
250                                                 Group: "\x02",
251                                                 Gid:   -2,
252                                         },
253                                         DataDiff: "\x03",
254                                 },
255                                 {
256                                         Path: "\x00",
257                                         Old: safcm.FileChangeInfo{
258                                                 Mode:  0x00000000,
259                                                 User:  "\x01",
260                                                 Uid:   -1,
261                                                 Group: "\x02",
262                                                 Gid:   -2,
263                                         },
264                                         New: safcm.FileChangeInfo{
265                                                 Mode:  0xFFFFFFFF,
266                                                 User:  "\x03",
267                                                 Uid:   -3,
268                                                 Group: "\x04",
269                                                 Gid:   -4,
270                                         },
271                                         DataDiff: "\x05",
272                                 },
273                         },
274                         `changed 2 file(s):
275 "\x00": created, invalid type dLDpSc?---------, \x01(-1) \x02(-2), 07777
276    \x03
277    \ No newline at end of file
278 "\x00": file -> invalid type dLDpSc?---------, \x01(-1) \x02(-2) -> \x03(-3) \x04(-4), 0 -> 07777
279    \x05
280    \ No newline at end of file
281 `,
282                 },
283         }
284
285         for _, tc := range tests {
286                 t.Run(tc.name, func(t *testing.T) {
287                 s := &Sync{
288                         config: &config.Config{
289                                 DryRun: tc.dryRun,
290                         },
291                 }
292
293                 res := s.formatFileChanges(tc.changes)
294                 if tc.exp != res {
295                         t.Errorf("res: %s",
296                                 cmp.Diff(tc.exp, res))
297                 }
298                 })
299         }
300 }
301
302 func TestFormatPackageChanges(t *testing.T) {
303         tests := []struct {
304                 name    string
305                 dryRun  bool
306                 changes []safcm.PackageChange
307                 exp     string
308         }{
309
310                 {
311                         "regular",
312                         false,
313                         []safcm.PackageChange{
314                                 {
315                                         Name: "package-one",
316                                 },
317                                 {
318                                         Name: "package-two",
319                                 },
320                         },
321                         `installed 2 package(s):
322 "package-one"
323 "package-two"
324 `,
325                 },
326
327                 {
328                         "dry-run",
329                         true,
330                         []safcm.PackageChange{
331                                 {
332                                         Name: "package-one",
333                                 },
334                                 {
335                                         Name: "package-two",
336                                 },
337                         },
338                         `installed 2 package(s): (dry-run)
339 "package-one"
340 "package-two"
341 `,
342                 },
343
344                 {
345                         "escaping",
346                         false,
347                         []safcm.PackageChange{
348                                 {
349                                         Name: "\x00",
350                                 },
351                         },
352                         `installed 1 package(s):
353 "\x00"
354 `,
355                 },
356         }
357
358         for _, tc := range tests {
359                 t.Run(tc.name, func(t *testing.T) {
360                 s := &Sync{
361                         config: &config.Config{
362                                 DryRun: tc.dryRun,
363                         },
364                 }
365
366                 res := s.formatPackageChanges(tc.changes)
367                 if tc.exp != res {
368                         t.Errorf("res: %s",
369                                 cmp.Diff(tc.exp, res))
370                 }
371                 })
372         }
373 }
374
375 func TestFormatServiceChanges(t *testing.T) {
376         tests := []struct {
377                 name    string
378                 dryRun  bool
379                 changes []safcm.ServiceChange
380                 exp     string
381         }{
382
383                 {
384                         "regular",
385                         false,
386                         []safcm.ServiceChange{
387                                 {
388                                         Name:    "service-one",
389                                         Started: true,
390                                 },
391                                 {
392                                         Name:    "service-two",
393                                         Enabled: true,
394                                 },
395                                 {
396                                         Name:    "service-three",
397                                         Started: true,
398                                         Enabled: true,
399                                 },
400                         },
401                         `modified 3 service(s):
402 "service-one": started
403 "service-two": enabled
404 "service-three": started, enabled
405 `,
406                 },
407
408                 {
409                         "dry-run",
410                         true,
411                         []safcm.ServiceChange{
412                                 {
413                                         Name:    "service-one",
414                                         Started: true,
415                                 },
416                                 {
417                                         Name:    "service-two",
418                                         Enabled: true,
419                                 },
420                                 {
421                                         Name:    "service-three",
422                                         Started: true,
423                                         Enabled: true,
424                                 },
425                         },
426                         `modified 3 service(s): (dry-run)
427 "service-one": started
428 "service-two": enabled
429 "service-three": started, enabled
430 `,
431                 },
432
433                 {
434                         "escaping",
435                         false,
436                         []safcm.ServiceChange{
437                                 {
438                                         Name: "\x00",
439                                 },
440                                 {
441                                         Name:    "\x01",
442                                         Started: true,
443                                         Enabled: true,
444                                 },
445                         },
446                         `modified 2 service(s):
447 "\x00": 
448 "\x01": started, enabled
449 `,
450                 },
451         }
452
453         for _, tc := range tests {
454                 t.Run(tc.name, func(t *testing.T) {
455                 s := &Sync{
456                         config: &config.Config{
457                                 DryRun: tc.dryRun,
458                         },
459                 }
460
461                 res := s.formatServiceChanges(tc.changes)
462                 if tc.exp != res {
463                         t.Errorf("res: %s",
464                                 cmp.Diff(tc.exp, res))
465                 }
466                 })
467         }
468 }
469
470 func TestFormatCommandChanges(t *testing.T) {
471         tests := []struct {
472                 name    string
473                 dryRun  bool
474                 quiet   bool
475                 changes []safcm.CommandChange
476                 exp     string
477         }{
478
479                 {
480                         "regular",
481                         false,
482                         false,
483                         []safcm.CommandChange{
484                                 {
485                                         Command: "fake command",
486                                         Output:  "fake output",
487                                 },
488                                 {
489                                         Command: "fake command with no output",
490                                 },
491                                 {
492                                         Command: "fake command with newline",
493                                         Output:  "fake output\n",
494                                 },
495                                 {
496                                         Command: "fake command with more output",
497                                         Output:  "fake out\nfake put\nfake\n",
498                                 },
499                                 {
500                                         Command: "fake failed command",
501                                         Output:  "fake output",
502                                         Error:   "fake error",
503                                 },
504                         },
505                         `executed 5 command(s):
506 "fake command":
507    > fake output
508    > \ No newline at end of file
509 "fake command with no output"
510 "fake command with newline":
511    > fake output
512 "fake command with more output":
513    > fake out
514    > fake put
515    > fake
516 "fake failed command", failed: "fake error":
517    > fake output
518    > \ No newline at end of file
519 `,
520                 },
521
522                 {
523                         "dry-run",
524                         true,
525                         false,
526                         []safcm.CommandChange{
527                                 {
528                                         Command: "fake command",
529                                         Output:  "fake output",
530                                 },
531                         },
532                         `executed 1 command(s): (dry-run)
533 "fake command":
534    > fake output
535    > \ No newline at end of file
536 `,
537                 },
538
539                 {
540                         "quiet",
541                         false,
542                         true,
543                         []safcm.CommandChange{
544                                 {
545                                         Command: "fake command",
546                                         Output:  "fake output",
547                                 },
548                                 {
549                                         Command: "fake command with no output",
550                                 },
551                                 {
552                                         Command: "fake command with newline",
553                                         Output:  "fake output\n",
554                                 },
555                                 {
556                                         Command: "fake command with more output",
557                                         Output:  "fake out\nfake put\nfake\n",
558                                 },
559                                 {
560                                         Command: "fake failed command",
561                                         Output:  "fake output",
562                                         Error:   "fake error",
563                                 },
564                         },
565                         `executed 5 command(s), 1 with no output:
566 "fake command":
567    > fake output
568    > \ No newline at end of file
569 "fake command with newline":
570    > fake output
571 "fake command with more output":
572    > fake out
573    > fake put
574    > fake
575 "fake failed command", failed: "fake error":
576    > fake output
577    > \ No newline at end of file
578 `,
579                 },
580
581                 {
582                         "quiet (only quiet commands)",
583                         false,
584                         true,
585                         []safcm.CommandChange{
586                                 {
587                                         Command: "fake command with no output",
588                                 },
589                                 {
590                                         Command: "fake command with no output",
591                                 },
592                         },
593                         `executed 2 command(s), 2 with no output
594 `,
595                 },
596
597                 {
598                         "quiet (quiet with errors)",
599                         false,
600                         true,
601                         []safcm.CommandChange{
602                                 {
603                                         Command: "fake command with no output but error",
604                                         Error:   "fake error",
605                                 },
606                                 {
607                                         Command: "fake command with no output",
608                                 },
609                         },
610                         `executed 2 command(s), 1 with no output:
611 "fake command with no output but error", failed: "fake error"
612 `,
613                 },
614
615                 {
616                         "quiet & dry-run",
617                         true,
618                         true,
619                         []safcm.CommandChange{
620                                 {
621                                         Command: "fake command",
622                                 },
623                                 {
624                                         Command: "fake command with no output",
625                                 },
626                                 {
627                                         Command: "fake command with newline",
628                                 },
629                                 {
630                                         Command: "fake command with more output",
631                                 },
632                                 {
633                                         Command: "fake failed command",
634                                 },
635                         },
636                         `executed 5 command(s): (dry-run)
637 "fake command"
638 "fake command with no output"
639 "fake command with newline"
640 "fake command with more output"
641 "fake failed command"
642 `,
643                 },
644
645                 {
646                         "escaping",
647                         false,
648                         false,
649                         []safcm.CommandChange{
650                                 {
651                                         Command: "\x00",
652                                         Trigger: "\x01",
653                                         Output:  "\x02",
654                                         Error:   "\x03",
655                                 },
656                         },
657                         `executed 1 command(s):
658 "\x00", trigger for "\x01", failed: "\x03":
659    > \x02
660    > \ No newline at end of file
661 `,
662                 },
663         }
664
665         for _, tc := range tests {
666                 t.Run(tc.name, func(t *testing.T) {
667                 s := &Sync{
668                         config: &config.Config{
669                                 DryRun: tc.dryRun,
670                                 Quiet:  tc.quiet,
671                         },
672                 }
673
674                 res := s.formatCommandChanges(tc.changes)
675                 if tc.exp != res {
676                         t.Errorf("res: %s",
677                                 cmp.Diff(tc.exp, res))
678                 }
679                 })
680         }
681 }