X-Git-Url: https://ruderich.org/simon/gitweb/?a=blobdiff_plain;f=cmd%2Fsafcm%2Fsync_changes_test.go;fp=cmd%2Fsafcm%2Fsync_changes_test.go;h=76a016834b87d8a09d68547bcea26720511b13a4;hb=f2f2bc47e8729548f3c10117f7f008b547c4afc5;hp=0000000000000000000000000000000000000000;hpb=dc0d431a778a50e6732b9eb91384a07a207b772d;p=safcm%2Fsafcm.git diff --git a/cmd/safcm/sync_changes_test.go b/cmd/safcm/sync_changes_test.go new file mode 100644 index 0000000..76a0168 --- /dev/null +++ b/cmd/safcm/sync_changes_test.go @@ -0,0 +1,562 @@ +// Copyright (C) 2021 Simon Ruderich +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package main + +import ( + "io/fs" + "testing" + + "github.com/google/go-cmp/cmp" + + "ruderich.org/simon/safcm" + "ruderich.org/simon/safcm/cmd/safcm/config" +) + +func TestFormatFileChanges(t *testing.T) { + tests := []struct { + name string + dryRun bool + changes []safcm.FileChange + exp string + }{ + + { + "regular", + false, + []safcm.FileChange{ + { + Path: "created: file", + Created: true, + New: safcm.FileChangeInfo{ + Mode: 0644, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + }, + { + Path: "created: link", + Created: true, + New: safcm.FileChangeInfo{ + Mode: fs.ModeSymlink | 0777, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + }, + { + Path: "type change: file -> dir", + Old: safcm.FileChangeInfo{ + Mode: 0751, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + New: safcm.FileChangeInfo{ + Mode: fs.ModeDir | 0751, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + DataDiff: `@@ -1,2 +1 @@ +-content + +`, + }, + { + Path: "user change", + Old: safcm.FileChangeInfo{ + Mode: 0755, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + New: safcm.FileChangeInfo{ + Mode: 0755, + User: "user2", + Uid: 1001, + Group: "group", + Gid: 2000, + }, + }, + { + Path: "group change", + Old: safcm.FileChangeInfo{ + Mode: 0755, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + New: safcm.FileChangeInfo{ + Mode: 0755, + User: "user", + Uid: 1000, + Group: "group2", + Gid: 2001, + }, + }, + { + Path: "mode change", + Old: safcm.FileChangeInfo{ + Mode: 0755, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + New: safcm.FileChangeInfo{ + Mode: 0750, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + }, + { + Path: "mode change (setuid)", + Old: safcm.FileChangeInfo{ + Mode: 0755, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + New: safcm.FileChangeInfo{ + Mode: 0755 | fs.ModeSetuid, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + }, + { + Path: "content change", + Old: safcm.FileChangeInfo{ + Mode: 0644, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + New: safcm.FileChangeInfo{ + Mode: 0644, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + DataDiff: `@@ -1,2 +1,2 @@ +-old content ++content + +`, + }, + { + Path: "multiple changes", + Old: safcm.FileChangeInfo{ + Mode: 0644, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + New: safcm.FileChangeInfo{ + Mode: fs.ModeDir | 0755, + User: "user2", + Uid: 1001, + Group: "group2", + Gid: 2001, + }, + DataDiff: `@@ -1,2 +1 @@ +-content + +`, + }, + }, + `changed 9 file(s): +"created: file": created, file, user(1000) group(2000), 0644 +"created: link": created, symlink, user(1000) group(2000), 0777 +"type change: file -> dir": file -> dir + @@ -1,2 +1 @@ + -content + +"user change": user(1000) group(2000) -> user2(1001) group(2000) +"group change": user(1000) group(2000) -> user(1000) group2(2001) +"mode change": 0755 -> 0750 +"mode change (setuid)": 0755 -> 04755 +"content change": + @@ -1,2 +1,2 @@ + -old content + +content + +"multiple changes": file -> dir, user(1000) group(2000) -> user2(1001) group2(2001), 0644 -> 0755 + @@ -1,2 +1 @@ + -content + +`, + }, + + { + "dry-run", + true, + []safcm.FileChange{ + { + Path: "file", + Created: true, + New: safcm.FileChangeInfo{ + Mode: 0644, + User: "user", + Uid: 1000, + Group: "group", + Gid: 2000, + }, + }, + }, + `changed 1 file(s): (dry-run) +"file": created, file, user(1000) group(2000), 0644 +`, + }, + + { + "escaping", + false, + []safcm.FileChange{ + { + Path: "\x00", + Created: true, + New: safcm.FileChangeInfo{ + Mode: 0xFFFFFFFF, + User: "\x01", + Uid: -1, + Group: "\x02", + Gid: -2, + }, + DataDiff: "\x03", + }, + { + Path: "\x00", + Old: safcm.FileChangeInfo{ + Mode: 0x00000000, + User: "\x01", + Uid: -1, + Group: "\x02", + Gid: -2, + }, + New: safcm.FileChangeInfo{ + Mode: 0xFFFFFFFF, + User: "\x03", + Uid: -3, + Group: "\x04", + Gid: -4, + }, + DataDiff: "\x05", + }, + }, + `changed 2 file(s): +"\x00": created, invalid type dLDpSc?---------, \x01(-1) \x02(-2), 07777 + \x03 + \ No newline at end of file +"\x00": file -> invalid type dLDpSc?---------, \x01(-1) \x02(-2) -> \x03(-3) \x04(-4), 0 -> 07777 + \x05 + \ No newline at end of file +`, + }, + } + + for _, tc := range tests { + s := &Sync{ + config: &config.Config{ + DryRun: tc.dryRun, + }, + } + + res := s.formatFileChanges(tc.changes) + if tc.exp != res { + t.Errorf("%s: res: %s", tc.name, + cmp.Diff(tc.exp, res)) + } + } +} + +func TestFormatPackageChanges(t *testing.T) { + tests := []struct { + name string + dryRun bool + changes []safcm.PackageChange + exp string + }{ + + { + "regular", + false, + []safcm.PackageChange{ + { + Name: "package-one", + }, + { + Name: "package-two", + }, + }, + `installed 2 package(s): +"package-one" +"package-two" +`, + }, + + { + "dry-run", + true, + []safcm.PackageChange{ + { + Name: "package-one", + }, + { + Name: "package-two", + }, + }, + `installed 2 package(s): (dry-run) +"package-one" +"package-two" +`, + }, + + { + "escaping", + false, + []safcm.PackageChange{ + { + Name: "\x00", + }, + }, + `installed 1 package(s): +"\x00" +`, + }, + } + + for _, tc := range tests { + s := &Sync{ + config: &config.Config{ + DryRun: tc.dryRun, + }, + } + + res := s.formatPackageChanges(tc.changes) + if tc.exp != res { + t.Errorf("%s: res: %s", tc.name, + cmp.Diff(tc.exp, res)) + } + } +} + +func TestFormatServiceChanges(t *testing.T) { + tests := []struct { + name string + dryRun bool + changes []safcm.ServiceChange + exp string + }{ + + { + "regular", + false, + []safcm.ServiceChange{ + { + Name: "service-one", + Started: true, + }, + { + Name: "service-two", + Enabled: true, + }, + { + Name: "service-three", + Started: true, + Enabled: true, + }, + }, + `modified 3 service(s): +"service-one": started +"service-two": enabled +"service-three": started, enabled +`, + }, + + { + "dry-run", + true, + []safcm.ServiceChange{ + { + Name: "service-one", + Started: true, + }, + { + Name: "service-two", + Enabled: true, + }, + { + Name: "service-three", + Started: true, + Enabled: true, + }, + }, + `modified 3 service(s): (dry-run) +"service-one": started +"service-two": enabled +"service-three": started, enabled +`, + }, + + { + "escaping", + false, + []safcm.ServiceChange{ + { + Name: "\x00", + }, + { + Name: "\x01", + Started: true, + Enabled: true, + }, + }, + `modified 2 service(s): +"\x00": +"\x01": started, enabled +`, + }, + } + + for _, tc := range tests { + s := &Sync{ + config: &config.Config{ + DryRun: tc.dryRun, + }, + } + + res := s.formatServiceChanges(tc.changes) + if tc.exp != res { + t.Errorf("%s: res: %s", tc.name, + cmp.Diff(tc.exp, res)) + } + } +} + +func TestFormatCommandChanges(t *testing.T) { + tests := []struct { + name string + dryRun bool + changes []safcm.CommandChange + exp string + }{ + + { + "regular", + false, + []safcm.CommandChange{ + { + Command: "fake command", + Output: "fake output", + }, + { + Command: "fake command with no output", + }, + { + Command: "fake command with newline", + Output: "fake output\n", + }, + { + Command: "fake command with more output", + Output: "fake out\nfake put\nfake\n", + }, + { + Command: "fake failed command", + Output: "fake output", + Error: "fake error", + }, + }, + `executed 5 command(s): +"fake command": + > fake output + > \ No newline at end of file +"fake command with no output" +"fake command with newline": + > fake output +"fake command with more output": + > fake out + > fake put + > fake +"fake failed command", failed: "fake error": + > fake output + > \ No newline at end of file +`, + }, + + { + "dry-run", + true, + []safcm.CommandChange{ + { + Command: "fake command", + Output: "fake output", + }, + }, + `executed 1 command(s): (dry-run) +"fake command": + > fake output + > \ No newline at end of file +`, + }, + + { + "escaping", + false, + []safcm.CommandChange{ + { + Command: "\x00", + Trigger: "\x01", + Output: "\x02", + Error: "\x03", + }, + }, + `executed 1 command(s): +"\x00", trigger for "\x01", failed: "\x03": + > \x02 + > \ No newline at end of file +`, + }, + } + + for _, tc := range tests { + s := &Sync{ + config: &config.Config{ + DryRun: tc.dryRun, + }, + } + + res := s.formatCommandChanges(tc.changes) + if tc.exp != res { + t.Errorf("%s: res: %s", tc.name, + cmp.Diff(tc.exp, res)) + } + } +}