]> ruderich.org/simon Gitweb - safcm/safcm.git/blobdiff - cmd/safcm/main_sync_test.go
Move implementation of cmd/safcm-remote/ to remote/
[safcm/safcm.git] / cmd / safcm / main_sync_test.go
index 39784fa12ef270ab380ff3402112a55f5660cc50..387caeebef07972ebbb8fce8d24097fc1d8ea4c1 100644 (file)
@@ -26,6 +26,7 @@ import (
        "testing"
        "time"
 
+       ft "ruderich.org/simon/safcm/remote/sync/filetest"
        "ruderich.org/simon/safcm/testutil"
 )
 
@@ -72,8 +73,31 @@ func TestSyncSshEndToEnd(t *testing.T) {
                t.Fatal(err)
        }
 
+       ft.CreateDirectoryExists("no-changes.example.org", 0755)
+       ft.CreateDirectoryExists("no-changes.example.org/files", 0755)
+       ft.CreateDirectoryExists("no-changes.example.org/files/etc", 0755)
+       ft.CreateDirectoryExists("no-changes.example.org/files/tmp", 0755)
+
+       noChangePermissions := `
+/: 0755 root root
+/etc: 0755 root root
+/tmp: 1777 root root
+`
+       if runtime.GOOS == "openbsd" || runtime.GOOS == "freebsd" {
+               noChangePermissions = `
+/: 0755 root wheel
+/etc: 0755 root wheel
+/tmp: 1777 root wheel
+`
+       }
+       ft.CreateFile("no-changes.example.org/permissions.yaml",
+               noChangePermissions, 0644)
+
+       skipUnlessCiRun := len(os.Getenv("SAFCM_CI_RUN")) == 0
+
        tests := []struct {
                name   string
+               skip   bool
                remove bool
                args   []string
                exp    string
@@ -82,6 +106,7 @@ func TestSyncSshEndToEnd(t *testing.T) {
 
                {
                        "no settings",
+                       false,
                        true,
                        []string{"no-settings.example.org"},
                        `<LOG>[info]    [no-settings.example.org] remote helper upload in progress
@@ -92,6 +117,7 @@ func TestSyncSshEndToEnd(t *testing.T) {
                {
                        "no settings (no helper upload)",
                        false,
+                       false,
                        []string{"no-settings.example.org"},
                        `<LOG>[info]    [no-settings.example.org] no changes
 `,
@@ -99,6 +125,7 @@ func TestSyncSshEndToEnd(t *testing.T) {
                },
                {
                        "no settings (error)",
+                       false,
                        true,
                        []string{"-log", "error", "no-settings.example.org"},
                        ``,
@@ -106,26 +133,214 @@ func TestSyncSshEndToEnd(t *testing.T) {
                },
                {
                        "no settings (verbose)",
+                       false,
                        true,
                        []string{"-log", "verbose", "no-settings.example.org"},
                        `<LOG>[info]    [no-settings.example.org] remote helper upload in progress
 <LOG>[verbose] [no-settings.example.org] host groups: all <DET> <DET> no-settings.example.org
-<LOG>[verbose] [no-settings.example.org] host group priorities (desc. order): no-settings.example.org
+<LOG>[verbose] [no-settings.example.org] host group priorities (descending): no-settings.example.org
 <LOG>[info]    [no-settings.example.org] no changes
 `,
                        nil,
                },
                {
                        "no settings (debug2)",
+                       false,
                        true,
                        []string{"-log", "debug2", "no-settings.example.org"},
                        `<LOG>[info]    [no-settings.example.org] remote helper upload in progress
 <LOG>[verbose] [no-settings.example.org] host groups: all <DET> <DET> no-settings.example.org
-<LOG>[verbose] [no-settings.example.org] host group priorities (desc. order): no-settings.example.org
+<LOG>[verbose] [no-settings.example.org] host group priorities (descending): no-settings.example.org
 <LOG>[info]    [no-settings.example.org] no changes
 `,
                        nil,
                },
+
+               // NOTE: We use -n on regular runs to prevent changing
+               // anything important on the host when running as root!
+
+               {
+                       "no changes (dry-run)",
+                       false,
+                       true,
+                       []string{"-n", "no-changes.example.org"},
+                       `<LOG>[info]    [no-changes.example.org] remote helper upload in progress
+<LOG>[info]    [no-changes.example.org] no changes
+`,
+                       nil,
+               },
+               {
+                       "no changes (dry-run, debug2)",
+                       false,
+                       true,
+                       []string{"-n", "-log", "debug2", "no-changes.example.org"},
+                       `<LOG>[info]    [no-changes.example.org] remote helper upload in progress
+<LOG>[verbose] [no-changes.example.org] host groups: all <DET> <DET> no-changes.example.org
+<LOG>[verbose] [no-changes.example.org] host group priorities (descending): no-changes.example.org
+<LOG>[debug]   [no-changes.example.org] files: "/" (no-changes.example.org): unchanged
+<LOG>[debug]   [no-changes.example.org] files: "/etc" (no-changes.example.org): unchanged
+<LOG>[debug]   [no-changes.example.org] files: "/tmp" (no-changes.example.org): unchanged
+<LOG>[info]    [no-changes.example.org] no changes
+`,
+                       nil,
+               },
+               {
+                       "no changes",
+                       skipUnlessCiRun,
+                       true,
+                       []string{"no-changes.example.org"},
+                       `<LOG>[info]    [no-changes.example.org] remote helper upload in progress
+<LOG>[info]    [no-changes.example.org] no changes
+`,
+                       nil,
+               },
+               {
+                       "no changes (debug2)",
+                       skipUnlessCiRun,
+                       true,
+                       []string{"-log", "debug2", "no-changes.example.org"},
+                       `<LOG>[info]    [no-changes.example.org] remote helper upload in progress
+<LOG>[verbose] [no-changes.example.org] host groups: all <DET> <DET> no-changes.example.org
+<LOG>[verbose] [no-changes.example.org] host group priorities (descending): no-changes.example.org
+<LOG>[debug]   [no-changes.example.org] files: "/" (no-changes.example.org): unchanged
+<LOG>[debug]   [no-changes.example.org] files: "/etc" (no-changes.example.org): unchanged
+<LOG>[debug]   [no-changes.example.org] files: "/tmp" (no-changes.example.org): unchanged
+<LOG>[info]    [no-changes.example.org] no changes
+`,
+                       nil,
+               },
+
+               {
+                       "no effect commands (dry-run)",
+                       false,
+                       true,
+                       []string{"-n", "no-effect-commands.example.org"},
+                       `<LOG>[info]    [no-effect-commands.example.org] remote helper upload in progress
+<LOG>[info]    [no-effect-commands.example.org] 
+will execute 2 command(s): (dry-run)
+"echo this is a command"
+"true"
+`,
+                       nil,
+               },
+               {
+                       "no effect commands (dry-run)",
+                       false,
+                       true,
+                       []string{"-n", "-log", "debug2", "no-effect-commands.example.org"},
+                       `<LOG>[info]    [no-effect-commands.example.org] remote helper upload in progress
+<LOG>[verbose] [no-effect-commands.example.org] host groups: all <DET> <DET> no-effect-commands.example.org
+<LOG>[verbose] [no-effect-commands.example.org] host group priorities (descending): no-effect-commands.example.org
+<LOG>[info]    [no-effect-commands.example.org] 
+will execute 2 command(s): (dry-run)
+"echo this is a command"
+"true"
+`,
+                       nil,
+               },
+               {
+                       "no effect commands",
+                       false,
+                       true,
+                       []string{"no-effect-commands.example.org"},
+                       `<LOG>[info]    [no-effect-commands.example.org] remote helper upload in progress
+<LOG>[info]    [no-effect-commands.example.org] 
+executed 2 command(s):
+"echo this is a command":
+   > this is a command
+"true"
+`,
+                       nil,
+               },
+               {
+                       "no effect commands (debug2)",
+                       false,
+                       true,
+                       []string{"-log", "debug2", "no-effect-commands.example.org"},
+                       `<LOG>[info]    [no-effect-commands.example.org] remote helper upload in progress
+<LOG>[verbose] [no-effect-commands.example.org] host groups: all <DET> <DET> no-effect-commands.example.org
+<LOG>[verbose] [no-effect-commands.example.org] host group priorities (descending): no-effect-commands.example.org
+<LOG>[verbose] [no-effect-commands.example.org] commands: running "/bin/sh" "-c" "echo this is a command" (no-effect-commands.example.org)
+<LOG>[debug2]  [no-effect-commands.example.org] commands: command output:
+this is a command
+<LOG>[verbose] [no-effect-commands.example.org] commands: running "/bin/sh" "-c" "true" (no-effect-commands.example.org)
+<LOG>[info]    [no-effect-commands.example.org] 
+executed 2 command(s):
+"echo this is a command":
+   > this is a command
+"true"
+`,
+                       nil,
+               },
+
+               {
+                       "no effect commands failing (dry-run)",
+                       false,
+                       true,
+                       []string{"-n", "no-effect-commands-failing.example.org"},
+                       `<LOG>[info]    [no-effect-commands-failing.example.org] remote helper upload in progress
+<LOG>[info]    [no-effect-commands-failing.example.org] 
+will execute 2 command(s): (dry-run)
+"echo this is a command"
+"echo failing; false"
+`,
+                       nil,
+               },
+               {
+                       "no effect commands failing (dry-run)",
+                       false,
+                       true,
+                       []string{"-n", "-log", "debug2", "no-effect-commands-failing.example.org"},
+                       `<LOG>[info]    [no-effect-commands-failing.example.org] remote helper upload in progress
+<LOG>[verbose] [no-effect-commands-failing.example.org] host groups: all <DET> <DET> no-effect-commands-failing.example.org
+<LOG>[verbose] [no-effect-commands-failing.example.org] host group priorities (descending): no-effect-commands-failing.example.org
+<LOG>[info]    [no-effect-commands-failing.example.org] 
+will execute 2 command(s): (dry-run)
+"echo this is a command"
+"echo failing; false"
+`,
+                       nil,
+               },
+               {
+                       "no effect commands failing",
+                       false,
+                       true,
+                       []string{"no-effect-commands-failing.example.org"},
+                       `<LOG>[info]    [no-effect-commands-failing.example.org] remote helper upload in progress
+<LOG>[info]    [no-effect-commands-failing.example.org] 
+executed 2 command(s):
+"echo this is a command":
+   > this is a command
+"echo failing; false", failed: "exit status 1":
+   > failing
+<LOG>[error]   [no-effect-commands-failing.example.org] commands: "echo failing; false" failed: exit status 1
+`,
+                       fmt.Errorf("exit status 1"),
+               },
+               {
+                       "no effect commands failing (debug2)",
+                       false,
+                       true,
+                       []string{"-log", "debug2", "no-effect-commands-failing.example.org"},
+                       `<LOG>[info]    [no-effect-commands-failing.example.org] remote helper upload in progress
+<LOG>[verbose] [no-effect-commands-failing.example.org] host groups: all <DET> <DET> no-effect-commands-failing.example.org
+<LOG>[verbose] [no-effect-commands-failing.example.org] host group priorities (descending): no-effect-commands-failing.example.org
+<LOG>[verbose] [no-effect-commands-failing.example.org] commands: running "/bin/sh" "-c" "echo this is a command" (no-effect-commands-failing.example.org)
+<LOG>[debug2]  [no-effect-commands-failing.example.org] commands: command output:
+this is a command
+<LOG>[verbose] [no-effect-commands-failing.example.org] commands: running "/bin/sh" "-c" "echo failing; false" (no-effect-commands-failing.example.org)
+<LOG>[debug2]  [no-effect-commands-failing.example.org] commands: command output:
+failing
+<LOG>[info]    [no-effect-commands-failing.example.org] 
+executed 2 command(s):
+"echo this is a command":
+   > this is a command
+"echo failing; false", failed: "exit status 1":
+   > failing
+<LOG>[error]   [no-effect-commands-failing.example.org] commands: "echo failing; false" failed: exit status 1
+`,
+                       fmt.Errorf("exit status 1"),
+               },
        }
 
        remotePath := fmt.Sprintf("/tmp/safcm-remote-%d", os.Getuid())
@@ -133,6 +348,20 @@ func TestSyncSshEndToEnd(t *testing.T) {
        logRegexp := regexp.MustCompile(`^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} `)
        detectedRegexp := regexp.MustCompile(`detected_\S+`)
 
+       t.Run("error before connection is established", func(t *testing.T) {
+               // Fake $PATH so safcm cannot find the `ssh` binary.
+               path := os.Getenv("PATH")
+               os.Setenv("PATH", "")
+               defer os.Setenv("PATH", path)
+
+               cmd := exec.Command("../../../../../safcm",
+                       "sync", "-n", "no-settings.example.org")
+               _, err := cmd.CombinedOutput()
+               if err == nil {
+                       t.Errorf("err = nil")
+               }
+       })
+
        for _, tc := range tests {
                t.Run(tc.name, func(t *testing.T) {
                        if tc.remove {