+++ /dev/null
-// 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 <http://www.gnu.org/licenses/>.
-
-package sync
-
-import (
- "fmt"
- "io/fs"
- "os"
- "os/exec"
- "testing"
-
- "ruderich.org/simon/safcm"
- "ruderich.org/simon/safcm/testutil"
-)
-
-func TestSyncCommands(t *testing.T) {
- exe, err := os.Executable()
- if err != nil {
- t.Fatal(err)
- }
- env := append(os.Environ(),
- "SAFCM_HELPER="+exe,
- "SAFCM_GROUPS=all group1 group2 host.example.org",
- "SAFCM_GROUP_all=all",
- "SAFCM_GROUP_group1=group1",
- "SAFCM_GROUP_group2=group2",
- "SAFCM_GROUP_host.example.org=host.example.org",
- )
-
- tests := []struct {
- name string
- req safcm.MsgSyncReq
- triggers []string
- stdout [][]byte
- stderr [][]byte
- errors []error
- expCmds []*exec.Cmd
- expDbg []string
- expResp safcm.MsgSyncResp
- expErr error
- }{
-
- // NOTE: Also update MsgSyncResp in safcm test cases when
- // changing the MsgSyncResp struct!
-
- {
- "successful command",
- safcm.MsgSyncReq{
- Groups: []string{
- "all",
- "group1",
- "group2",
- "host.example.org",
- },
- Commands: []*safcm.Command{
- {
- OrigGroup: "group",
- Cmd: "echo; env | grep SAFCM_",
- },
- },
- },
- nil,
- [][]byte{[]byte("fake stdout/stderr")},
- [][]byte{nil},
- []error{nil},
- []*exec.Cmd{{
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "echo; env | grep SAFCM_",
- },
- Env: env,
- }},
- []string{
- `3: commands: running "/bin/sh" "-c" "echo; env | grep SAFCM_" (group)`,
- "5: commands: command output:\nfake stdout/stderr",
- },
- safcm.MsgSyncResp{
- CommandChanges: []safcm.CommandChange{
- {
- Command: "echo; env | grep SAFCM_",
- Output: "fake stdout/stderr",
- },
- },
- },
- nil,
- },
- {
- "successful command (dry-run)",
- safcm.MsgSyncReq{
- DryRun: true,
- Groups: []string{
- "all",
- "group1",
- "group2",
- "host.example.org",
- },
- Commands: []*safcm.Command{
- {
- OrigGroup: "group",
- Cmd: "echo; env | grep SAFCM_",
- },
- },
- },
- nil,
- nil,
- nil,
- nil,
- nil,
- nil,
- safcm.MsgSyncResp{
- CommandChanges: []safcm.CommandChange{
- {
- Command: "echo; env | grep SAFCM_",
- },
- },
- },
- nil,
- },
-
- {
- "failed command",
- safcm.MsgSyncReq{
- Groups: []string{
- "all",
- "group1",
- "group2",
- "host.example.org",
- },
- Commands: []*safcm.Command{
- {
- OrigGroup: "group",
- Cmd: "echo hi; false",
- },
- },
- },
- nil,
- [][]byte{[]byte("fake stdout/stderr")},
- [][]byte{nil},
- []error{fmt.Errorf("fake error")},
- []*exec.Cmd{{
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "echo hi; false",
- },
- Env: env,
- }},
- []string{
- `3: commands: running "/bin/sh" "-c" "echo hi; false" (group)`,
- "5: commands: command output:\nfake stdout/stderr",
- },
- safcm.MsgSyncResp{
- CommandChanges: []safcm.CommandChange{
- {
- Command: "echo hi; false",
- Output: "fake stdout/stderr",
- Error: "fake error",
- },
- },
- },
- fmt.Errorf("\"echo hi; false\" failed: fake error"),
- },
- {
- "failed command (dry-run)",
- safcm.MsgSyncReq{
- DryRun: true,
- Groups: []string{
- "all",
- "group1",
- "group2",
- "host.example.org",
- },
- Commands: []*safcm.Command{
- {
- OrigGroup: "group",
- Cmd: "echo hi; false",
- },
- },
- },
- nil,
- nil,
- nil,
- nil,
- nil,
- nil,
- safcm.MsgSyncResp{
- CommandChanges: []safcm.CommandChange{
- {
- Command: "echo hi; false",
- },
- },
- },
- nil,
- },
-
- {
- "multiple commands, abort on first failed",
- safcm.MsgSyncReq{
- Groups: []string{
- "all",
- "group1",
- "group2",
- "host.example.org",
- },
- Commands: []*safcm.Command{
- {
- OrigGroup: "group1",
- Cmd: "echo first",
- }, {
- OrigGroup: "group2",
- Cmd: "echo second",
- }, {
- OrigGroup: "group3",
- Cmd: "false",
- }, {
- OrigGroup: "group4",
- Cmd: "echo third",
- },
- },
- },
- nil,
- [][]byte{
- []byte("fake stdout/stderr first"),
- []byte("fake stdout/stderr second"),
- nil,
- },
- [][]byte{
- nil,
- nil,
- nil,
- },
- []error{
- nil,
- nil,
- fmt.Errorf("fake error"),
- },
- []*exec.Cmd{{
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "echo first",
- },
- Env: env,
- }, {
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "echo second",
- },
- Env: env,
- }, {
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "false",
- },
- Env: env,
- }},
- []string{
- `3: commands: running "/bin/sh" "-c" "echo first" (group1)`,
- "5: commands: command output:\nfake stdout/stderr first",
- `3: commands: running "/bin/sh" "-c" "echo second" (group2)`,
- "5: commands: command output:\nfake stdout/stderr second",
- `3: commands: running "/bin/sh" "-c" "false" (group3)`,
- },
- safcm.MsgSyncResp{
- CommandChanges: []safcm.CommandChange{
- {
- Command: "echo first",
- Output: "fake stdout/stderr first",
- },
- {
- Command: "echo second",
- Output: "fake stdout/stderr second",
- },
- {
- Command: "false",
- Output: "",
- Error: "fake error",
- },
- },
- },
- fmt.Errorf("\"false\" failed: fake error"),
- },
-
- {
- "triggers",
- safcm.MsgSyncReq{
- Groups: []string{
- "all",
- "group1",
- "group2",
- "host.example.org",
- },
- Files: map[string]*safcm.File{
- ".": {
- Path: ".",
- Mode: fs.ModeDir | 0700,
- Uid: -1,
- Gid: -1,
- OrigGroup: "group",
- TriggerCommands: []string{
- "echo trigger .",
- },
- },
- "dir": {
- Path: "dir",
- Mode: fs.ModeDir | 0755,
- Uid: -1,
- Gid: -1,
- OrigGroup: "group",
- TriggerCommands: []string{
- "echo trigger dir",
- },
- },
- "dir/file": {
- Path: "dir/file",
- Mode: 0644,
- Uid: -1,
- Gid: -1,
- Data: []byte("content\n"),
- OrigGroup: "group",
- TriggerCommands: []string{
- "echo trigger dir/file",
- },
- },
- },
- Commands: []*safcm.Command{
- {
- OrigGroup: "group",
- Cmd: "echo; env | grep SAFCM_",
- },
- },
- },
- []string{
- ".",
- "dir",
- },
- [][]byte{
- []byte("fake stdout/stderr ."),
- []byte("fake stdout/stderr dir"),
- []byte("fake stdout/stderr"),
- },
- [][]byte{
- nil,
- nil,
- nil,
- },
- []error{
- nil,
- nil,
- nil,
- },
- []*exec.Cmd{{
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "echo trigger .",
- },
- Env: env,
- }, {
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "echo trigger dir",
- },
- Env: env,
- }, {
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "echo; env | grep SAFCM_",
- },
- Env: env,
- }},
- []string{
- `3: commands: running "/bin/sh" "-c" "echo trigger ." (".")`,
- "5: commands: command output:\nfake stdout/stderr .",
- `3: commands: running "/bin/sh" "-c" "echo trigger dir" ("dir")`,
- "5: commands: command output:\nfake stdout/stderr dir",
- `3: commands: running "/bin/sh" "-c" "echo; env | grep SAFCM_" (group)`,
- "5: commands: command output:\nfake stdout/stderr",
- },
- safcm.MsgSyncResp{
- CommandChanges: []safcm.CommandChange{
- {
- Command: "echo trigger .",
- Trigger: ".",
- Output: "fake stdout/stderr .",
- },
- {
- Command: "echo trigger dir",
- Trigger: "dir",
- Output: "fake stdout/stderr dir",
- },
- {
- Command: "echo; env | grep SAFCM_",
- Output: "fake stdout/stderr",
- },
- },
- },
- nil,
- },
-
- {
- "failed trigger",
- safcm.MsgSyncReq{
- Groups: []string{
- "all",
- "group1",
- "group2",
- "host.example.org",
- },
- Files: map[string]*safcm.File{
- ".": {
- Path: ".",
- Mode: fs.ModeDir | 0700,
- Uid: -1,
- Gid: -1,
- OrigGroup: "group",
- TriggerCommands: []string{
- "echo trigger .",
- },
- },
- "dir": {
- Path: "dir",
- Mode: fs.ModeDir | 0755,
- Uid: -1,
- Gid: -1,
- OrigGroup: "group",
- TriggerCommands: []string{
- "false",
- },
- },
- "dir/file": {
- Path: "dir/file",
- Mode: 0644,
- Uid: -1,
- Gid: -1,
- Data: []byte("content\n"),
- OrigGroup: "group",
- TriggerCommands: []string{
- "echo trigger dir/file",
- },
- },
- },
- Commands: []*safcm.Command{
- {
- OrigGroup: "group",
- Cmd: "echo; env | grep SAFCM_",
- },
- },
- },
- []string{
- ".",
- "dir",
- },
- [][]byte{
- []byte("fake stdout/stderr ."),
- []byte("fake stdout/stderr dir"),
- },
- [][]byte{
- nil,
- nil,
- },
- []error{
- nil,
- fmt.Errorf("fake error"),
- },
- []*exec.Cmd{{
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "echo trigger .",
- },
- Env: env,
- }, {
- Path: "/bin/sh",
- Args: []string{
- "/bin/sh", "-c",
- "false",
- },
- Env: env,
- }},
- []string{
- `3: commands: running "/bin/sh" "-c" "echo trigger ." (".")`,
- "5: commands: command output:\nfake stdout/stderr .",
- `3: commands: running "/bin/sh" "-c" "false" ("dir")`,
- "5: commands: command output:\nfake stdout/stderr dir",
- },
- safcm.MsgSyncResp{
- CommandChanges: []safcm.CommandChange{
- {
- Command: "echo trigger .",
- Trigger: ".",
- Output: "fake stdout/stderr .",
- },
- {
- Command: "false",
- Trigger: "dir",
- Output: "fake stdout/stderr dir",
- Error: "fake error",
- },
- },
- },
- fmt.Errorf("\"false\" failed: fake error"),
- },
- }
-
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- s, res := prepareSync(tc.req, &testRunner{
- t: t,
- expCmds: tc.expCmds,
- resStdout: tc.stdout,
- resStderr: tc.stderr,
- resError: tc.errors,
- })
- s.triggers = tc.triggers
-
- err := s.syncCommands()
- testutil.AssertErrorEqual(t, "err", err, tc.expErr)
- dbg := res.Wait()
-
- testutil.AssertEqual(t, "resp", s.resp, tc.expResp)
- testutil.AssertEqual(t, "dbg", dbg, tc.expDbg)
- })
- }
-}