1 // Copyright (C) 2021 Simon Ruderich
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.
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.
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/>.
22 "ruderich.org/simon/safcm"
23 "ruderich.org/simon/safcm/testutil"
26 func TestFormatChanges(t *testing.T) {
32 resp safcm.MsgSyncResp
36 // Just a few basic tests and border cases; see the other
37 // tests for more detailed tests of each format function
54 FileChanges: []safcm.FileChange{
58 New: safcm.FileChangeInfo{
67 PackageChanges: []safcm.PackageChange{
75 ServiceChanges: []safcm.ServiceChange{
85 Name: "service-three",
90 CommandChanges: []safcm.CommandChange{
92 Command: "fake command",
93 Output: "fake output",
96 Command: "fake command with no output",
100 "\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",
104 "command changes only, dry-run",
109 CommandChanges: []safcm.CommandChange{
111 Command: "fake command",
114 Command: "fake command with no output",
117 Command: "fake command with newline",
120 Command: "fake command with more output",
123 Command: "fake failed command",
127 "\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",
130 "command changes only, quiet & dry-run",
135 CommandChanges: []safcm.CommandChange{
137 Command: "fake command",
140 Command: "fake command with no output",
143 Command: "fake command with newline",
146 Command: "fake command with more output",
149 Command: "fake failed command",
153 "will execute 5 command(s) (dry-run)\n",
157 for _, tc := range tests {
158 t.Run(tc.name, func(t *testing.T) {
165 res := c.FormatChanges(tc.resp)
166 testutil.AssertEqual(t, "res", res, tc.exp)
171 func TestFormatFileChanges(t *testing.T) {
176 changes []safcm.FileChange
186 Path: "created: file",
188 New: safcm.FileChangeInfo{
197 Path: "created: link",
199 New: safcm.FileChangeInfo{
200 Mode: fs.ModeSymlink | 0777,
208 Path: "type change: file -> dir",
209 Old: safcm.FileChangeInfo{
216 New: safcm.FileChangeInfo{
217 Mode: fs.ModeDir | 0751,
223 DataDiff: `@@ -1,2 +1 @@
230 Old: safcm.FileChangeInfo{
237 New: safcm.FileChangeInfo{
246 Path: "group change",
247 Old: safcm.FileChangeInfo{
254 New: safcm.FileChangeInfo{
264 Old: safcm.FileChangeInfo{
271 New: safcm.FileChangeInfo{
280 Path: "mode change (setuid)",
281 Old: safcm.FileChangeInfo{
288 New: safcm.FileChangeInfo{
289 Mode: 0755 | fs.ModeSetuid,
297 Path: "content change",
298 Old: safcm.FileChangeInfo{
305 New: safcm.FileChangeInfo{
312 DataDiff: `@@ -1,2 +1,2 @@
319 Path: "multiple changes",
320 Old: safcm.FileChangeInfo{
327 New: safcm.FileChangeInfo{
328 Mode: fs.ModeDir | 0755,
334 DataDiff: `@@ -1,2 +1 @@
341 "created: file": created, file, user(1000) group(2000), 0644
342 "created: link": created, symlink, user(1000) group(2000), 0777
343 "type change: file -> dir": file -> dir
347 "user change": user(1000) group(2000) -> user2(1001) group(2000)
348 "group change": user(1000) group(2000) -> user(1000) group2(2001)
349 "mode change": 0755 -> 0750
350 "mode change (setuid)": 0755 -> 04755
356 "multiple changes": file -> dir, user(1000) group(2000) -> user2(1001) group2(2001), 0644 -> 0755
369 Path: "created: file",
371 New: safcm.FileChangeInfo{
380 Path: "created: link",
382 New: safcm.FileChangeInfo{
383 Mode: fs.ModeSymlink | 0777,
391 Path: "type change: file -> dir",
392 Old: safcm.FileChangeInfo{
399 New: safcm.FileChangeInfo{
400 Mode: fs.ModeDir | 0751,
406 DataDiff: `@@ -1,2 +1 @@
413 Old: safcm.FileChangeInfo{
420 New: safcm.FileChangeInfo{
429 Path: "group change",
430 Old: safcm.FileChangeInfo{
437 New: safcm.FileChangeInfo{
447 Old: safcm.FileChangeInfo{
454 New: safcm.FileChangeInfo{
463 Path: "mode change (setuid)",
464 Old: safcm.FileChangeInfo{
471 New: safcm.FileChangeInfo{
472 Mode: 0755 | fs.ModeSetuid,
480 Path: "content change",
481 Old: safcm.FileChangeInfo{
488 New: safcm.FileChangeInfo{
495 DataDiff: `@@ -1,2 +1,2 @@
502 Path: "multiple changes",
503 Old: safcm.FileChangeInfo{
510 New: safcm.FileChangeInfo{
511 Mode: fs.ModeDir | 0755,
517 DataDiff: `@@ -1,2 +1 @@
523 "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",
534 New: safcm.FileChangeInfo{
543 `will change 1 file(s): (dry-run)
544 "file": created, file, user(1000) group(2000), 0644
556 New: safcm.FileChangeInfo{
565 "will change 1 file(s): (dry-run)\n\x1B[36m\"file\"\x1B[0m: \x1B[32mcreated\x1B[0m, file, user(1000) group(2000), 0644\n",
576 New: safcm.FileChangeInfo{
587 Old: safcm.FileChangeInfo{
594 New: safcm.FileChangeInfo{
605 "\x00": created, invalid type dLDpSc?---------, \x01(-1) \x02(-2), 07777
607 \ No newline at end of file
608 "\x00": file -> invalid type dLDpSc?---------, \x01(-1) \x02(-2) -> \x03(-3) \x04(-4), 0 -> 07777
610 \ No newline at end of file
622 New: safcm.FileChangeInfo{
633 Old: safcm.FileChangeInfo{
640 New: safcm.FileChangeInfo{
650 "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",
654 for _, tc := range tests {
655 t.Run(tc.name, func(t *testing.T) {
661 res := c.FormatFileChanges(tc.changes)
662 testutil.AssertEqual(t, "res", res, tc.exp)
667 func TestFormatPackageChanges(t *testing.T) {
672 changes []safcm.PackageChange
680 []safcm.PackageChange{
688 `installed 2 package(s):
698 []safcm.PackageChange{
706 "installed 2 package(s):\n\x1b[36m\"package-one\"\x1b[0m\n\x1b[36m\"package-two\"\x1b[0m\n",
713 []safcm.PackageChange{
721 `will install 2 package(s): (dry-run)
731 []safcm.PackageChange{
739 "will install 2 package(s): (dry-run)\n\x1b[36m\"package-one\"\x1b[0m\n\x1b[36m\"package-two\"\x1b[0m\n",
746 []safcm.PackageChange{
751 `installed 1 package(s):
760 []safcm.PackageChange{
765 "installed 1 package(s):\n\x1b[36m\"\\x00\"\x1b[0m\n",
769 for _, tc := range tests {
770 t.Run(tc.name, func(t *testing.T) {
776 res := c.FormatPackageChanges(tc.changes)
777 testutil.AssertEqual(t, "res", res, tc.exp)
782 func TestFormatServiceChanges(t *testing.T) {
787 changes []safcm.ServiceChange
795 []safcm.ServiceChange{
805 Name: "service-three",
810 `modified 3 service(s):
811 "service-one": started
812 "service-two": enabled
813 "service-three": started, enabled
821 []safcm.ServiceChange{
831 Name: "service-three",
836 "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",
843 []safcm.ServiceChange{
853 Name: "service-three",
858 `will modify 3 service(s): (dry-run)
859 "service-one": started
860 "service-two": enabled
861 "service-three": started, enabled
869 []safcm.ServiceChange{
879 Name: "service-three",
884 "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",
891 []safcm.ServiceChange{
901 `modified 2 service(s):
903 "\x01": started, enabled
911 []safcm.ServiceChange{
921 "modified 2 service(s):\n\x1b[36m\"\\x00\"\x1b[0m: \n\x1b[36m\"\\x01\"\x1b[0m: started, enabled\n",
925 for _, tc := range tests {
926 t.Run(tc.name, func(t *testing.T) {
932 res := c.FormatServiceChanges(tc.changes)
933 testutil.AssertEqual(t, "res", res, tc.exp)
938 func TestFormatCommandChanges(t *testing.T) {
944 changes []safcm.CommandChange
953 []safcm.CommandChange{
955 Command: "fake command",
956 Output: "fake output",
959 Command: "fake command with no output",
962 Command: "fake command with newline",
963 Output: "fake output\n",
966 Command: "fake command with more output",
967 Output: "fake out\nfake put\nfake\n",
970 Command: "fake failed command",
971 Output: "fake output",
975 `executed 5 command(s):
978 > \ No newline at end of file
979 "fake command with no output"
980 "fake command with newline":
982 "fake command with more output":
986 "fake failed command", failed: "fake error":
988 > \ No newline at end of file
997 []safcm.CommandChange{
999 Command: "fake command",
1000 Output: "fake output",
1003 Command: "fake command with no output",
1006 Command: "fake command with newline",
1007 Output: "fake output\n",
1010 Command: "fake command with more output",
1011 Output: "fake out\nfake put\nfake\n",
1014 Command: "fake failed command",
1015 Output: "fake output",
1016 Error: "fake error",
1019 "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",
1027 []safcm.CommandChange{
1029 Command: "fake command",
1032 `will execute 1 command(s): (dry-run)
1042 []safcm.CommandChange{
1044 Command: "fake command",
1047 "will execute 1 command(s): (dry-run)\n\x1b[36m\"fake command\"\x1b[0m\n",
1055 []safcm.CommandChange{
1057 Command: "fake command",
1058 Output: "fake output",
1061 Command: "fake command with no output",
1064 Command: "fake command with newline",
1065 Output: "fake output\n",
1068 Command: "fake command with more output",
1069 Output: "fake out\nfake put\nfake\n",
1072 Command: "fake failed command",
1073 Output: "fake output",
1074 Error: "fake error",
1077 `executed 5 command(s), 1 with no output (hidden):
1080 > \ No newline at end of file
1081 "fake command with newline":
1083 "fake command with more output":
1087 "fake failed command", failed: "fake error":
1089 > \ No newline at end of file
1098 []safcm.CommandChange{
1100 Command: "fake command",
1101 Output: "fake output",
1104 Command: "fake command with no output",
1107 Command: "fake command with newline",
1108 Output: "fake output\n",
1111 Command: "fake command with more output",
1112 Output: "fake out\nfake put\nfake\n",
1115 Command: "fake failed command",
1116 Output: "fake output",
1117 Error: "fake error",
1120 "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",
1124 "quiet (only quiet commands)",
1128 []safcm.CommandChange{
1130 Command: "fake command with no output",
1133 Command: "fake command with no output",
1136 `executed 2 command(s), 2 with no output (hidden)
1141 "quiet (quiet with errors)",
1145 []safcm.CommandChange{
1147 Command: "fake command with no output but error",
1148 Error: "fake error",
1151 Command: "fake command with no output",
1154 `executed 2 command(s), 1 with no output (hidden):
1155 "fake command with no output but error", failed: "fake error"
1164 []safcm.CommandChange{
1166 Command: "fake command",
1169 Command: "fake command with no output",
1172 Command: "fake command with newline",
1175 Command: "fake command with more output",
1178 Command: "fake failed command",
1181 `will execute 5 command(s) (dry-run)
1190 []safcm.CommandChange{
1198 `executed 1 command(s):
1199 "\x00", trigger for "\x01", failed: "\x03":
1201 > \ No newline at end of file
1210 []safcm.CommandChange{
1218 "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",
1222 for _, tc := range tests {
1223 t.Run(tc.name, func(t *testing.T) {
1230 res := c.FormatCommandChanges(tc.changes)
1231 testutil.AssertEqual(t, "res", res, tc.exp)