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/cmd/safcm/config"
24 "ruderich.org/simon/safcm/testutil"
27 func TestFormatChanges(t *testing.T) {
33 resp safcm.MsgSyncResp
37 // Just a few basic tests and border cases; see the other
38 // tests for more detailed tests of each format function
55 FileChanges: []safcm.FileChange{
59 New: safcm.FileChangeInfo{
68 PackageChanges: []safcm.PackageChange{
76 ServiceChanges: []safcm.ServiceChange{
86 Name: "service-three",
91 CommandChanges: []safcm.CommandChange{
93 Command: "fake command",
94 Output: "fake output",
97 Command: "fake command with no output",
101 "\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",
105 "command changes only, dry-run",
110 CommandChanges: []safcm.CommandChange{
112 Command: "fake command",
115 Command: "fake command with no output",
118 Command: "fake command with newline",
121 Command: "fake command with more output",
124 Command: "fake failed command",
128 "\nexecuted 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",
131 "command changes only, quiet & dry-run",
136 CommandChanges: []safcm.CommandChange{
138 Command: "fake command",
141 Command: "fake command with no output",
144 Command: "fake command with newline",
147 Command: "fake command with more output",
150 Command: "fake failed command",
154 "executed 5 command(s) (dry-run)\n",
158 for _, tc := range tests {
159 t.Run(tc.name, func(t *testing.T) {
161 config: &config.Config{
168 res := s.formatChanges(tc.resp)
169 testutil.AssertEqual(t, "res", res, tc.exp)
174 func TestFormatFileChanges(t *testing.T) {
179 changes []safcm.FileChange
189 Path: "created: file",
191 New: safcm.FileChangeInfo{
200 Path: "created: link",
202 New: safcm.FileChangeInfo{
203 Mode: fs.ModeSymlink | 0777,
211 Path: "type change: file -> dir",
212 Old: safcm.FileChangeInfo{
219 New: safcm.FileChangeInfo{
220 Mode: fs.ModeDir | 0751,
226 DataDiff: `@@ -1,2 +1 @@
233 Old: safcm.FileChangeInfo{
240 New: safcm.FileChangeInfo{
249 Path: "group change",
250 Old: safcm.FileChangeInfo{
257 New: safcm.FileChangeInfo{
267 Old: safcm.FileChangeInfo{
274 New: safcm.FileChangeInfo{
283 Path: "mode change (setuid)",
284 Old: safcm.FileChangeInfo{
291 New: safcm.FileChangeInfo{
292 Mode: 0755 | fs.ModeSetuid,
300 Path: "content change",
301 Old: safcm.FileChangeInfo{
308 New: safcm.FileChangeInfo{
315 DataDiff: `@@ -1,2 +1,2 @@
322 Path: "multiple changes",
323 Old: safcm.FileChangeInfo{
330 New: safcm.FileChangeInfo{
331 Mode: fs.ModeDir | 0755,
337 DataDiff: `@@ -1,2 +1 @@
344 "created: file": created, file, user(1000) group(2000), 0644
345 "created: link": created, symlink, user(1000) group(2000), 0777
346 "type change: file -> dir": file -> dir
350 "user change": user(1000) group(2000) -> user2(1001) group(2000)
351 "group change": user(1000) group(2000) -> user(1000) group2(2001)
352 "mode change": 0755 -> 0750
353 "mode change (setuid)": 0755 -> 04755
359 "multiple changes": file -> dir, user(1000) group(2000) -> user2(1001) group2(2001), 0644 -> 0755
372 Path: "created: file",
374 New: safcm.FileChangeInfo{
383 Path: "created: link",
385 New: safcm.FileChangeInfo{
386 Mode: fs.ModeSymlink | 0777,
394 Path: "type change: file -> dir",
395 Old: safcm.FileChangeInfo{
402 New: safcm.FileChangeInfo{
403 Mode: fs.ModeDir | 0751,
409 DataDiff: `@@ -1,2 +1 @@
416 Old: safcm.FileChangeInfo{
423 New: safcm.FileChangeInfo{
432 Path: "group change",
433 Old: safcm.FileChangeInfo{
440 New: safcm.FileChangeInfo{
450 Old: safcm.FileChangeInfo{
457 New: safcm.FileChangeInfo{
466 Path: "mode change (setuid)",
467 Old: safcm.FileChangeInfo{
474 New: safcm.FileChangeInfo{
475 Mode: 0755 | fs.ModeSetuid,
483 Path: "content change",
484 Old: safcm.FileChangeInfo{
491 New: safcm.FileChangeInfo{
498 DataDiff: `@@ -1,2 +1,2 @@
505 Path: "multiple changes",
506 Old: safcm.FileChangeInfo{
513 New: safcm.FileChangeInfo{
514 Mode: fs.ModeDir | 0755,
520 DataDiff: `@@ -1,2 +1 @@
526 "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",
537 New: safcm.FileChangeInfo{
546 `changed 1 file(s): (dry-run)
547 "file": created, file, user(1000) group(2000), 0644
559 New: safcm.FileChangeInfo{
568 "changed 1 file(s): (dry-run)\n\x1B[36m\"file\"\x1B[0m: \x1B[32mcreated\x1B[0m, file, user(1000) group(2000), 0644\n",
579 New: safcm.FileChangeInfo{
590 Old: safcm.FileChangeInfo{
597 New: safcm.FileChangeInfo{
608 "\x00": created, invalid type dLDpSc?---------, \x01(-1) \x02(-2), 07777
610 \ No newline at end of file
611 "\x00": file -> invalid type dLDpSc?---------, \x01(-1) \x02(-2) -> \x03(-3) \x04(-4), 0 -> 07777
613 \ No newline at end of file
625 New: safcm.FileChangeInfo{
636 Old: safcm.FileChangeInfo{
643 New: safcm.FileChangeInfo{
653 "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",
657 for _, tc := range tests {
658 t.Run(tc.name, func(t *testing.T) {
660 config: &config.Config{
666 res := s.formatFileChanges(tc.changes)
667 testutil.AssertEqual(t, "res", res, tc.exp)
672 func TestFormatPackageChanges(t *testing.T) {
677 changes []safcm.PackageChange
685 []safcm.PackageChange{
693 `installed 2 package(s):
703 []safcm.PackageChange{
711 "installed 2 package(s):\n\x1b[36m\"package-one\"\x1b[0m\n\x1b[36m\"package-two\"\x1b[0m\n",
718 []safcm.PackageChange{
726 `installed 2 package(s): (dry-run)
736 []safcm.PackageChange{
744 "installed 2 package(s): (dry-run)\n\x1b[36m\"package-one\"\x1b[0m\n\x1b[36m\"package-two\"\x1b[0m\n",
751 []safcm.PackageChange{
756 `installed 1 package(s):
765 []safcm.PackageChange{
770 "installed 1 package(s):\n\x1b[36m\"\\x00\"\x1b[0m\n",
774 for _, tc := range tests {
775 t.Run(tc.name, func(t *testing.T) {
777 config: &config.Config{
783 res := s.formatPackageChanges(tc.changes)
784 testutil.AssertEqual(t, "res", res, tc.exp)
789 func TestFormatServiceChanges(t *testing.T) {
794 changes []safcm.ServiceChange
802 []safcm.ServiceChange{
812 Name: "service-three",
817 `modified 3 service(s):
818 "service-one": started
819 "service-two": enabled
820 "service-three": started, enabled
828 []safcm.ServiceChange{
838 Name: "service-three",
843 "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",
850 []safcm.ServiceChange{
860 Name: "service-three",
865 `modified 3 service(s): (dry-run)
866 "service-one": started
867 "service-two": enabled
868 "service-three": started, enabled
876 []safcm.ServiceChange{
886 Name: "service-three",
891 "modified 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",
898 []safcm.ServiceChange{
908 `modified 2 service(s):
910 "\x01": started, enabled
918 []safcm.ServiceChange{
928 "modified 2 service(s):\n\x1b[36m\"\\x00\"\x1b[0m: \n\x1b[36m\"\\x01\"\x1b[0m: started, enabled\n",
932 for _, tc := range tests {
933 t.Run(tc.name, func(t *testing.T) {
935 config: &config.Config{
941 res := s.formatServiceChanges(tc.changes)
942 testutil.AssertEqual(t, "res", res, tc.exp)
947 func TestFormatCommandChanges(t *testing.T) {
953 changes []safcm.CommandChange
962 []safcm.CommandChange{
964 Command: "fake command",
965 Output: "fake output",
968 Command: "fake command with no output",
971 Command: "fake command with newline",
972 Output: "fake output\n",
975 Command: "fake command with more output",
976 Output: "fake out\nfake put\nfake\n",
979 Command: "fake failed command",
980 Output: "fake output",
984 `executed 5 command(s):
987 > \ No newline at end of file
988 "fake command with no output"
989 "fake command with newline":
991 "fake command with more output":
995 "fake failed command", failed: "fake error":
997 > \ No newline at end of file
1006 []safcm.CommandChange{
1008 Command: "fake command",
1009 Output: "fake output",
1012 Command: "fake command with no output",
1015 Command: "fake command with newline",
1016 Output: "fake output\n",
1019 Command: "fake command with more output",
1020 Output: "fake out\nfake put\nfake\n",
1023 Command: "fake failed command",
1024 Output: "fake output",
1025 Error: "fake error",
1028 "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",
1036 []safcm.CommandChange{
1038 Command: "fake command",
1039 Output: "fake output",
1042 `executed 1 command(s): (dry-run)
1045 > \ No newline at end of file
1054 []safcm.CommandChange{
1056 Command: "fake command",
1057 Output: "fake output",
1060 "executed 1 command(s): (dry-run)\n\x1b[36m\"fake command\"\x1b[0m:\n > fake output\n > \\ No newline at end of file\n",
1068 []safcm.CommandChange{
1070 Command: "fake command",
1071 Output: "fake output",
1074 Command: "fake command with no output",
1077 Command: "fake command with newline",
1078 Output: "fake output\n",
1081 Command: "fake command with more output",
1082 Output: "fake out\nfake put\nfake\n",
1085 Command: "fake failed command",
1086 Output: "fake output",
1087 Error: "fake error",
1090 `executed 5 command(s), 1 with no output:
1093 > \ No newline at end of file
1094 "fake command with newline":
1096 "fake command with more output":
1100 "fake failed command", failed: "fake error":
1102 > \ No newline at end of file
1111 []safcm.CommandChange{
1113 Command: "fake command",
1114 Output: "fake output",
1117 Command: "fake command with no output",
1120 Command: "fake command with newline",
1121 Output: "fake output\n",
1124 Command: "fake command with more output",
1125 Output: "fake out\nfake put\nfake\n",
1128 Command: "fake failed command",
1129 Output: "fake output",
1130 Error: "fake error",
1133 "executed 5 command(s), 1 with no output:\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",
1137 "quiet (only quiet commands)",
1141 []safcm.CommandChange{
1143 Command: "fake command with no output",
1146 Command: "fake command with no output",
1149 `executed 2 command(s), 2 with no output
1154 "quiet (quiet with errors)",
1158 []safcm.CommandChange{
1160 Command: "fake command with no output but error",
1161 Error: "fake error",
1164 Command: "fake command with no output",
1167 `executed 2 command(s), 1 with no output:
1168 "fake command with no output but error", failed: "fake error"
1177 []safcm.CommandChange{
1179 Command: "fake command",
1182 Command: "fake command with no output",
1185 Command: "fake command with newline",
1188 Command: "fake command with more output",
1191 Command: "fake failed command",
1194 `executed 5 command(s) (dry-run)
1203 []safcm.CommandChange{
1211 `executed 1 command(s):
1212 "\x00", trigger for "\x01", failed: "\x03":
1214 > \ No newline at end of file
1223 []safcm.CommandChange{
1231 "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",
1235 for _, tc := range tests {
1236 t.Run(tc.name, func(t *testing.T) {
1238 config: &config.Config{
1245 res := s.formatCommandChanges(tc.changes)
1246 testutil.AssertEqual(t, "res", res, tc.exp)