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/>.
26 "github.com/google/go-cmp/cmp"
28 "ruderich.org/simon/safcm"
31 func TestSyncCommands(t *testing.T) {
32 exe, err := os.Executable()
36 env := append(os.Environ(),
38 "SAFCM_GROUPS=all group1 group2 host.example.org",
39 "SAFCM_GROUP_all=all",
40 "SAFCM_GROUP_group1=group1",
41 "SAFCM_GROUP_group2=group2",
42 "SAFCM_GROUP_host.example.org=host.example.org",
54 expResp safcm.MsgSyncResp
58 // NOTE: Also update MsgSyncResp in safcm test cases when
59 // changing anything here!
71 "echo; env | grep SAFCM_",
75 [][]byte{[]byte("fake stdout/stderr")},
82 "echo; env | grep SAFCM_",
87 `3: sync remote: commands: running "/bin/sh" "-c" "echo; env | grep SAFCM_"`,
88 "5: sync remote: commands: command output:\nfake stdout/stderr",
91 CommandChanges: []safcm.CommandChange{
93 Command: "echo; env | grep SAFCM_",
94 Output: "fake stdout/stderr",
101 "successful command (dry-run)",
111 "echo; env | grep SAFCM_",
121 CommandChanges: []safcm.CommandChange{
123 Command: "echo; env | grep SAFCM_",
144 [][]byte{[]byte("fake stdout/stderr")},
146 []error{fmt.Errorf("fake error")},
156 `3: sync remote: commands: running "/bin/sh" "-c" "echo hi; false"`,
157 "5: sync remote: commands: command output:\nfake stdout/stderr",
160 CommandChanges: []safcm.CommandChange{
162 Command: "echo hi; false",
163 Output: "fake stdout/stderr",
168 fmt.Errorf("\"echo hi; false\" failed: fake error"),
171 "failed command (dry-run)",
191 CommandChanges: []safcm.CommandChange{
193 Command: "echo hi; false",
201 "multiple commands, abort on first failed",
218 []byte("fake stdout/stderr first"),
219 []byte("fake stdout/stderr second"),
230 fmt.Errorf("fake error"),
255 `3: sync remote: commands: running "/bin/sh" "-c" "echo first"`,
256 "5: sync remote: commands: command output:\nfake stdout/stderr first",
257 `3: sync remote: commands: running "/bin/sh" "-c" "echo second"`,
258 "5: sync remote: commands: command output:\nfake stdout/stderr second",
259 `3: sync remote: commands: running "/bin/sh" "-c" "false"`,
262 CommandChanges: []safcm.CommandChange{
264 Command: "echo first",
265 Output: "fake stdout/stderr first",
268 Command: "echo second",
269 Output: "fake stdout/stderr second",
278 fmt.Errorf("\"false\" failed: fake error"),
290 Files: map[string]*safcm.File{
293 Mode: fs.ModeDir | 0700,
297 TriggerCommands: []string{
303 Mode: fs.ModeDir | 0755,
307 TriggerCommands: []string{
316 Data: []byte("content\n"),
318 TriggerCommands: []string{
319 "echo trigger dir/file",
324 "echo; env | grep SAFCM_",
332 []byte("fake stdout/stderr ."),
333 []byte("fake stdout/stderr dir"),
334 []byte("fake stdout/stderr"),
364 "echo; env | grep SAFCM_",
369 `3: sync remote: commands: running "/bin/sh" "-c" "echo trigger ."`,
370 "5: sync remote: commands: command output:\nfake stdout/stderr .",
371 `3: sync remote: commands: running "/bin/sh" "-c" "echo trigger dir"`,
372 "5: sync remote: commands: command output:\nfake stdout/stderr dir",
373 `3: sync remote: commands: running "/bin/sh" "-c" "echo; env | grep SAFCM_"`,
374 "5: sync remote: commands: command output:\nfake stdout/stderr",
377 CommandChanges: []safcm.CommandChange{
379 Command: "echo trigger .",
381 Output: "fake stdout/stderr .",
384 Command: "echo trigger dir",
386 Output: "fake stdout/stderr dir",
389 Command: "echo; env | grep SAFCM_",
390 Output: "fake stdout/stderr",
406 Files: map[string]*safcm.File{
409 Mode: fs.ModeDir | 0700,
413 TriggerCommands: []string{
419 Mode: fs.ModeDir | 0755,
423 TriggerCommands: []string{
432 Data: []byte("content\n"),
434 TriggerCommands: []string{
435 "echo trigger dir/file",
440 "echo; env | grep SAFCM_",
448 []byte("fake stdout/stderr ."),
449 []byte("fake stdout/stderr dir"),
457 fmt.Errorf("fake error"),
475 `3: sync remote: commands: running "/bin/sh" "-c" "echo trigger ."`,
476 "5: sync remote: commands: command output:\nfake stdout/stderr .",
477 `3: sync remote: commands: running "/bin/sh" "-c" "false"`,
478 "5: sync remote: commands: command output:\nfake stdout/stderr dir",
481 CommandChanges: []safcm.CommandChange{
483 Command: "echo trigger .",
485 Output: "fake stdout/stderr .",
490 Output: "fake stdout/stderr dir",
495 fmt.Errorf("\"false\" failed: fake error"),
499 for _, tc := range tests {
500 s, res := prepareSync(tc.req, &testRunner{
504 resStdout: tc.stdout,
505 resStderr: tc.stderr,
508 s.triggers = tc.triggers
510 err := s.syncCommands()
511 // Ugly but the simplest way to compare errors (including nil)
512 if fmt.Sprintf("%s", err) != fmt.Sprintf("%s", tc.expErr) {
513 t.Errorf("%s: err = %#v, want %#v",
514 tc.name, err, tc.expErr)
518 if !reflect.DeepEqual(tc.expResp, s.resp) {
519 t.Errorf("%s: resp: %s", tc.name,
520 cmp.Diff(tc.expResp, s.resp))
522 if !reflect.DeepEqual(tc.expDbg, dbg) {
523 t.Errorf("%s: dbg: %s", tc.name,
524 cmp.Diff(tc.expDbg, dbg))