1 // SPDX-License-Identifier: GPL-3.0-or-later
2 // Copyright (C) 2021-2024 Simon Ruderich
10 "ruderich.org/simon/safcm"
11 "ruderich.org/simon/safcm/testutil"
14 func TestFormatChanges(t *testing.T) {
20 resp safcm.MsgSyncResp
24 // Just a few basic tests and border cases; see the other
25 // tests for more detailed tests of each format function
42 FileChanges: []safcm.FileChange{
46 New: safcm.FileChangeInfo{
55 PackageChanges: []safcm.PackageChange{
63 ServiceChanges: []safcm.ServiceChange{
73 Name: "service-three",
78 CommandChanges: []safcm.CommandChange{
80 Command: "fake command",
81 Output: "fake output",
84 Command: "fake command with no output",
88 "\nchanged 1 file(s):\n\"created\": created, file, user(1000) group(2000), 0644\n\ninstalled 2 package(s):\n\"package-one\"\n\"package-two\"\n\nmodified 3 service(s):\n\"service-one\": started\n\"service-two\": enabled\n\"service-three\": started, enabled\n\nexecuted 2 command(s):\n\"fake command\":\n > fake output\n > \\ No newline at end of file\n\"fake command with no output\"\n",
92 "command changes only, dry-run",
97 CommandChanges: []safcm.CommandChange{
99 Command: "fake command",
102 Command: "fake command with no output",
105 Command: "fake command with newline",
108 Command: "fake command with more output",
111 Command: "fake failed command",
115 "\nwill execute 5 command(s): (dry-run)\n\"fake command\"\n\"fake command with no output\"\n\"fake command with newline\"\n\"fake command with more output\"\n\"fake failed command\"\n",
118 "command changes only, quiet & dry-run",
123 CommandChanges: []safcm.CommandChange{
125 Command: "fake command",
128 Command: "fake command with no output",
131 Command: "fake command with newline",
134 Command: "fake command with more output",
137 Command: "fake failed command",
141 "will execute 5 command(s) (dry-run)\n",
145 for _, tc := range tests {
146 t.Run(tc.name, func(t *testing.T) {
153 res := c.FormatChanges(tc.resp)
154 testutil.AssertEqual(t, "res", res, tc.exp)
159 func TestFormatFileChanges(t *testing.T) {
164 changes []safcm.FileChange
174 Path: "created: file",
176 New: safcm.FileChangeInfo{
185 Path: "created: link",
187 New: safcm.FileChangeInfo{
188 Mode: fs.ModeSymlink | 0777,
196 Path: "type change: file -> dir",
197 Old: safcm.FileChangeInfo{
204 New: safcm.FileChangeInfo{
205 Mode: fs.ModeDir | 0751,
211 DataDiff: `@@ -1,2 +1 @@
218 Old: safcm.FileChangeInfo{
225 New: safcm.FileChangeInfo{
234 Path: "group change",
235 Old: safcm.FileChangeInfo{
242 New: safcm.FileChangeInfo{
252 Old: safcm.FileChangeInfo{
259 New: safcm.FileChangeInfo{
268 Path: "mode change (setuid)",
269 Old: safcm.FileChangeInfo{
276 New: safcm.FileChangeInfo{
277 Mode: 0755 | fs.ModeSetuid,
285 Path: "content change",
286 Old: safcm.FileChangeInfo{
293 New: safcm.FileChangeInfo{
300 DataDiff: `@@ -1,2 +1,2 @@
307 Path: "multiple changes",
308 Old: safcm.FileChangeInfo{
315 New: safcm.FileChangeInfo{
316 Mode: fs.ModeDir | 0755,
322 DataDiff: `@@ -1,2 +1 @@
329 "created: file": created, file, user(1000) group(2000), 0644
330 "created: link": created, symlink, user(1000) group(2000), 0777
331 "type change: file -> dir": file -> dir
335 "user change": user(1000) group(2000) -> user2(1001) group(2000)
336 "group change": user(1000) group(2000) -> user(1000) group2(2001)
337 "mode change": 0755 -> 0750
338 "mode change (setuid)": 0755 -> 04755
344 "multiple changes": file -> dir, user(1000) group(2000) -> user2(1001) group2(2001), 0644 -> 0755
357 Path: "created: file",
359 New: safcm.FileChangeInfo{
368 Path: "created: link",
370 New: safcm.FileChangeInfo{
371 Mode: fs.ModeSymlink | 0777,
379 Path: "type change: file -> dir",
380 Old: safcm.FileChangeInfo{
387 New: safcm.FileChangeInfo{
388 Mode: fs.ModeDir | 0751,
394 DataDiff: `@@ -1,2 +1 @@
401 Old: safcm.FileChangeInfo{
408 New: safcm.FileChangeInfo{
417 Path: "group change",
418 Old: safcm.FileChangeInfo{
425 New: safcm.FileChangeInfo{
435 Old: safcm.FileChangeInfo{
442 New: safcm.FileChangeInfo{
451 Path: "mode change (setuid)",
452 Old: safcm.FileChangeInfo{
459 New: safcm.FileChangeInfo{
460 Mode: 0755 | fs.ModeSetuid,
468 Path: "content change",
469 Old: safcm.FileChangeInfo{
476 New: safcm.FileChangeInfo{
483 DataDiff: `@@ -1,2 +1,2 @@
490 Path: "multiple changes",
491 Old: safcm.FileChangeInfo{
498 New: safcm.FileChangeInfo{
499 Mode: fs.ModeDir | 0755,
505 DataDiff: `@@ -1,2 +1 @@
511 "changed 9 file(s):\n\x1b[36m\"created: file\"\x1b[0m: \x1b[32mcreated\x1b[0m, file, user(1000) group(2000), 0644\n\x1b[36m\"created: link\"\x1b[0m: \x1b[32mcreated\x1b[0m, symlink, user(1000) group(2000), 0777\n\x1b[36m\"type change: file -> dir\"\x1b[0m: file -> dir\n @@ -1,2 +1 @@\n\x1b[31m -content\x1b[0m\n \n\x1b[36m\"user change\"\x1b[0m: user(1000) group(2000) -> user2(1001) group(2000)\n\x1b[36m\"group change\"\x1b[0m: user(1000) group(2000) -> user(1000) group2(2001)\n\x1b[36m\"mode change\"\x1b[0m: 0755 -> 0750\n\x1b[36m\"mode change (setuid)\"\x1b[0m: 0755 -> 04755\n\x1b[36m\"content change\"\x1b[0m:\n @@ -1,2 +1,2 @@\n\x1b[31m -old content\x1b[0m\n\x1b[32m +content\x1b[0m\n \n\x1b[36m\"multiple changes\"\x1b[0m: file -> dir, user(1000) group(2000) -> user2(1001) group2(2001), 0644 -> 0755\n @@ -1,2 +1 @@\n\x1b[31m -content\x1b[0m\n \n",
522 New: safcm.FileChangeInfo{
531 `will change 1 file(s): (dry-run)
532 "file": created, file, user(1000) group(2000), 0644
544 New: safcm.FileChangeInfo{
553 "will change 1 file(s): (dry-run)\n\x1B[36m\"file\"\x1B[0m: \x1B[32mcreated\x1B[0m, file, user(1000) group(2000), 0644\n",
564 New: safcm.FileChangeInfo{
575 Old: safcm.FileChangeInfo{
582 New: safcm.FileChangeInfo{
593 "\x00": created, invalid type dLDpSc?---------, \x01(-1) \x02(-2), 07777
595 \ No newline at end of file
596 "\x00": file -> invalid type dLDpSc?---------, \x01(-1) \x02(-2) -> \x03(-3) \x04(-4), 0 -> 07777
598 \ No newline at end of file
610 New: safcm.FileChangeInfo{
621 Old: safcm.FileChangeInfo{
628 New: safcm.FileChangeInfo{
638 "changed 2 file(s):\n\x1b[36m\"\\x00\"\x1b[0m: \x1b[32mcreated\x1b[0m, invalid type dLDpSc?---------, \\x01(-1) \\x02(-2), 07777\n \\x03\n \\ No newline at end of file\n\x1b[36m\"\\x00\"\x1b[0m: file -> invalid type dLDpSc?---------, \\x01(-1) \\x02(-2) -> \\x03(-3) \\x04(-4), 0 -> 07777\n \\x05\n \\ No newline at end of file\n",
642 for _, tc := range tests {
643 t.Run(tc.name, func(t *testing.T) {
649 res := c.FormatFileChanges(tc.changes)
650 testutil.AssertEqual(t, "res", res, tc.exp)
655 func TestFormatPackageChanges(t *testing.T) {
660 changes []safcm.PackageChange
668 []safcm.PackageChange{
676 `installed 2 package(s):
686 []safcm.PackageChange{
694 "installed 2 package(s):\n\x1b[36m\"package-one\"\x1b[0m\n\x1b[36m\"package-two\"\x1b[0m\n",
701 []safcm.PackageChange{
709 `will install 2 package(s): (dry-run)
719 []safcm.PackageChange{
727 "will install 2 package(s): (dry-run)\n\x1b[36m\"package-one\"\x1b[0m\n\x1b[36m\"package-two\"\x1b[0m\n",
734 []safcm.PackageChange{
739 `installed 1 package(s):
748 []safcm.PackageChange{
753 "installed 1 package(s):\n\x1b[36m\"\\x00\"\x1b[0m\n",
757 for _, tc := range tests {
758 t.Run(tc.name, func(t *testing.T) {
764 res := c.FormatPackageChanges(tc.changes)
765 testutil.AssertEqual(t, "res", res, tc.exp)
770 func TestFormatServiceChanges(t *testing.T) {
775 changes []safcm.ServiceChange
783 []safcm.ServiceChange{
793 Name: "service-three",
798 `modified 3 service(s):
799 "service-one": started
800 "service-two": enabled
801 "service-three": started, enabled
809 []safcm.ServiceChange{
819 Name: "service-three",
824 "modified 3 service(s):\n\x1b[36m\"service-one\"\x1b[0m: started\n\x1b[36m\"service-two\"\x1b[0m: enabled\n\x1b[36m\"service-three\"\x1b[0m: started, enabled\n",
831 []safcm.ServiceChange{
841 Name: "service-three",
846 `will modify 3 service(s): (dry-run)
847 "service-one": started
848 "service-two": enabled
849 "service-three": started, enabled
857 []safcm.ServiceChange{
867 Name: "service-three",
872 "will modify 3 service(s): (dry-run)\n\x1b[36m\"service-one\"\x1b[0m: started\n\x1b[36m\"service-two\"\x1b[0m: enabled\n\x1b[36m\"service-three\"\x1b[0m: started, enabled\n",
879 []safcm.ServiceChange{
889 `modified 2 service(s):
891 "\x01": started, enabled
899 []safcm.ServiceChange{
909 "modified 2 service(s):\n\x1b[36m\"\\x00\"\x1b[0m: \n\x1b[36m\"\\x01\"\x1b[0m: started, enabled\n",
913 for _, tc := range tests {
914 t.Run(tc.name, func(t *testing.T) {
920 res := c.FormatServiceChanges(tc.changes)
921 testutil.AssertEqual(t, "res", res, tc.exp)
926 func TestFormatCommandChanges(t *testing.T) {
932 changes []safcm.CommandChange
941 []safcm.CommandChange{
943 Command: "fake command",
944 Output: "fake output",
947 Command: "fake command with no output",
950 Command: "fake command with newline",
951 Output: "fake output\n",
954 Command: "fake command with more output",
955 Output: "fake out\nfake put\nfake\n",
958 Command: "fake failed command",
959 Output: "fake output",
963 `executed 5 command(s):
966 > \ No newline at end of file
967 "fake command with no output"
968 "fake command with newline":
970 "fake command with more output":
974 "fake failed command", failed: "fake error":
976 > \ No newline at end of file
985 []safcm.CommandChange{
987 Command: "fake command",
988 Output: "fake output",
991 Command: "fake command with no output",
994 Command: "fake command with newline",
995 Output: "fake output\n",
998 Command: "fake command with more output",
999 Output: "fake out\nfake put\nfake\n",
1002 Command: "fake failed command",
1003 Output: "fake output",
1004 Error: "fake error",
1007 "executed 5 command(s):\n\x1b[36m\"fake command\"\x1b[0m:\n > fake output\n > \\ No newline at end of file\n\x1b[36m\"fake command with no output\"\x1b[0m\n\x1b[36m\"fake command with newline\"\x1b[0m:\n > fake output\n\x1b[36m\"fake command with more output\"\x1b[0m:\n > fake out\n > fake put\n > fake\n\x1b[36m\"fake failed command\"\x1b[0m, failed: \"fake error\":\n > fake output\n > \\ No newline at end of file\n",
1015 []safcm.CommandChange{
1017 Command: "fake command",
1020 `will execute 1 command(s): (dry-run)
1030 []safcm.CommandChange{
1032 Command: "fake command",
1035 "will execute 1 command(s): (dry-run)\n\x1b[36m\"fake command\"\x1b[0m\n",
1043 []safcm.CommandChange{
1045 Command: "fake command",
1046 Output: "fake output",
1049 Command: "fake command with no output",
1052 Command: "fake command with newline",
1053 Output: "fake output\n",
1056 Command: "fake command with more output",
1057 Output: "fake out\nfake put\nfake\n",
1060 Command: "fake failed command",
1061 Output: "fake output",
1062 Error: "fake error",
1065 `executed 5 command(s), 1 with no output (hidden):
1068 > \ No newline at end of file
1069 "fake command with newline":
1071 "fake command with more output":
1075 "fake failed command", failed: "fake error":
1077 > \ No newline at end of file
1086 []safcm.CommandChange{
1088 Command: "fake command",
1089 Output: "fake output",
1092 Command: "fake command with no output",
1095 Command: "fake command with newline",
1096 Output: "fake output\n",
1099 Command: "fake command with more output",
1100 Output: "fake out\nfake put\nfake\n",
1103 Command: "fake failed command",
1104 Output: "fake output",
1105 Error: "fake error",
1108 "executed 5 command(s), 1 with no output (hidden):\n\x1b[36m\"fake command\"\x1b[0m:\n > fake output\n > \\ No newline at end of file\n\x1b[36m\"fake command with newline\"\x1b[0m:\n > fake output\n\x1b[36m\"fake command with more output\"\x1b[0m:\n > fake out\n > fake put\n > fake\n\x1b[36m\"fake failed command\"\x1b[0m, failed: \"fake error\":\n > fake output\n > \\ No newline at end of file\n",
1112 "quiet (only quiet commands)",
1116 []safcm.CommandChange{
1118 Command: "fake command with no output",
1121 Command: "fake command with no output",
1124 `executed 2 command(s), 2 with no output (hidden)
1129 "quiet (quiet with errors)",
1133 []safcm.CommandChange{
1135 Command: "fake command with no output but error",
1136 Error: "fake error",
1139 Command: "fake command with no output",
1142 `executed 2 command(s), 1 with no output (hidden):
1143 "fake command with no output but error", failed: "fake error"
1152 []safcm.CommandChange{
1154 Command: "fake command",
1157 Command: "fake command with no output",
1160 Command: "fake command with newline",
1163 Command: "fake command with more output",
1166 Command: "fake failed command",
1169 `will execute 5 command(s) (dry-run)
1178 []safcm.CommandChange{
1186 `executed 1 command(s):
1187 "\x00", trigger for "\x01", failed: "\x03":
1189 > \ No newline at end of file
1198 []safcm.CommandChange{
1206 "executed 1 command(s):\n\x1b[36m\"\\x00\"\x1b[0m, trigger for \"\\x01\", failed: \"\\x03\":\n > \x1b[35m\\x02\x1b[0m\n > \\ No newline at end of file\n",
1210 for _, tc := range tests {
1211 t.Run(tc.name, func(t *testing.T) {
1218 res := c.FormatCommandChanges(tc.changes)
1219 testutil.AssertEqual(t, "res", res, tc.exp)