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 env := append(os.Environ(),
33 "SAFCM_GROUPS=all group1 group2 host.example.org",
34 "SAFCM_GROUP_all=all",
35 "SAFCM_GROUP_group1=group1",
36 "SAFCM_GROUP_group2=group2",
37 "SAFCM_GROUP_host.example.org=host.example.org",
49 expResp safcm.MsgSyncResp
53 // NOTE: Also update MsgSyncResp in safcm test cases when
54 // changing anything here!
66 "echo; env | grep SAFCM_",
70 [][]byte{[]byte("fake stdout/stderr")},
77 "echo; env | grep SAFCM_",
82 `3: sync remote: commands: running "/bin/sh" "-c" "echo; env | grep SAFCM_"`,
83 "5: sync remote: commands: command output:\nfake stdout/stderr",
86 CommandChanges: []safcm.CommandChange{
88 Command: "echo; env | grep SAFCM_",
89 Output: "fake stdout/stderr",
96 "successful command (dry-run)",
106 "echo; env | grep SAFCM_",
116 CommandChanges: []safcm.CommandChange{
118 Command: "echo; env | grep SAFCM_",
139 [][]byte{[]byte("fake stdout/stderr")},
141 []error{fmt.Errorf("fake error")},
151 `3: sync remote: commands: running "/bin/sh" "-c" "echo hi; false"`,
152 "5: sync remote: commands: command output:\nfake stdout/stderr",
155 CommandChanges: []safcm.CommandChange{
157 Command: "echo hi; false",
158 Output: "fake stdout/stderr",
163 fmt.Errorf("\"echo hi; false\" failed: fake error"),
166 "failed command (dry-run)",
186 CommandChanges: []safcm.CommandChange{
188 Command: "echo hi; false",
196 "multiple commands, abort on first failed",
213 []byte("fake stdout/stderr first"),
214 []byte("fake stdout/stderr second"),
225 fmt.Errorf("fake error"),
250 `3: sync remote: commands: running "/bin/sh" "-c" "echo first"`,
251 "5: sync remote: commands: command output:\nfake stdout/stderr first",
252 `3: sync remote: commands: running "/bin/sh" "-c" "echo second"`,
253 "5: sync remote: commands: command output:\nfake stdout/stderr second",
254 `3: sync remote: commands: running "/bin/sh" "-c" "false"`,
257 CommandChanges: []safcm.CommandChange{
259 Command: "echo first",
260 Output: "fake stdout/stderr first",
263 Command: "echo second",
264 Output: "fake stdout/stderr second",
273 fmt.Errorf("\"false\" failed: fake error"),
285 Files: map[string]*safcm.File{
288 Mode: fs.ModeDir | 0700,
292 TriggerCommands: []string{
298 Mode: fs.ModeDir | 0755,
302 TriggerCommands: []string{
311 Data: []byte("content\n"),
313 TriggerCommands: []string{
314 "echo trigger dir/file",
319 "echo; env | grep SAFCM_",
327 []byte("fake stdout/stderr ."),
328 []byte("fake stdout/stderr dir"),
329 []byte("fake stdout/stderr"),
359 "echo; env | grep SAFCM_",
364 `3: sync remote: commands: running "/bin/sh" "-c" "echo trigger ."`,
365 "5: sync remote: commands: command output:\nfake stdout/stderr .",
366 `3: sync remote: commands: running "/bin/sh" "-c" "echo trigger dir"`,
367 "5: sync remote: commands: command output:\nfake stdout/stderr dir",
368 `3: sync remote: commands: running "/bin/sh" "-c" "echo; env | grep SAFCM_"`,
369 "5: sync remote: commands: command output:\nfake stdout/stderr",
372 CommandChanges: []safcm.CommandChange{
374 Command: "echo trigger .",
376 Output: "fake stdout/stderr .",
379 Command: "echo trigger dir",
381 Output: "fake stdout/stderr dir",
384 Command: "echo; env | grep SAFCM_",
385 Output: "fake stdout/stderr",
401 Files: map[string]*safcm.File{
404 Mode: fs.ModeDir | 0700,
408 TriggerCommands: []string{
414 Mode: fs.ModeDir | 0755,
418 TriggerCommands: []string{
427 Data: []byte("content\n"),
429 TriggerCommands: []string{
430 "echo trigger dir/file",
435 "echo; env | grep SAFCM_",
443 []byte("fake stdout/stderr ."),
444 []byte("fake stdout/stderr dir"),
452 fmt.Errorf("fake error"),
470 `3: sync remote: commands: running "/bin/sh" "-c" "echo trigger ."`,
471 "5: sync remote: commands: command output:\nfake stdout/stderr .",
472 `3: sync remote: commands: running "/bin/sh" "-c" "false"`,
473 "5: sync remote: commands: command output:\nfake stdout/stderr dir",
476 CommandChanges: []safcm.CommandChange{
478 Command: "echo trigger .",
480 Output: "fake stdout/stderr .",
485 Output: "fake stdout/stderr dir",
490 fmt.Errorf("\"false\" failed: fake error"),
494 for _, tc := range tests {
495 s, res := prepareSync(tc.req, &testRunner{
499 resStdout: tc.stdout,
500 resStderr: tc.stderr,
503 s.triggers = tc.triggers
505 err := s.syncCommands()
506 // Ugly but the simplest way to compare errors (including nil)
507 if fmt.Sprintf("%s", err) != fmt.Sprintf("%s", tc.expErr) {
508 t.Errorf("%s: err = %#v, want %#v",
509 tc.name, err, tc.expErr)
513 if !reflect.DeepEqual(tc.expResp, s.resp) {
514 t.Errorf("%s: resp: %s", tc.name,
515 cmp.Diff(tc.expResp, s.resp))
517 if !reflect.DeepEqual(tc.expDbg, dbg) {
518 t.Errorf("%s: dbg: %s", tc.name,
519 cmp.Diff(tc.expDbg, dbg))