]> ruderich.org/simon Gitweb - safcm/safcm.git/blobdiff - cmd/safcm/sync_sync_test.go
Update copyright years
[safcm/safcm.git] / cmd / safcm / sync_sync_test.go
index f6aafd52445e6664f4958ab82703736a51e93982..4b614d19b30168ba4bd20bb43c75b2b540379316 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2021  Simon Ruderich
+// Copyright (C) 2021-2024  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
@@ -22,12 +22,10 @@ import (
        "log"
        "os"
        "path/filepath"
-       "reflect"
        "testing"
 
-       "github.com/google/go-cmp/cmp"
-
        "ruderich.org/simon/safcm"
+       "ruderich.org/simon/safcm/testutil"
 )
 
 func TestHostSyncReq(t *testing.T) {
@@ -35,38 +33,38 @@ func TestHostSyncReq(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       defer os.Chdir(cwd)
+       defer os.Chdir(cwd) //nolint:errcheck
 
        tests := []struct {
                name      string
                project   string
                host      string
                detected  []string
-               level     safcm.LogLevel
                exp       safcm.MsgSyncReq
                expEvents []string
                expErr    error
        }{
 
                // NOTE: Also update MsgSyncReq in safcm-remote test cases
-               // when changing anything here!
+               // changing the MsgSyncReq struct!
 
                {
                        "project: host1",
                        "project",
                        "host1.example.org",
                        nil,
-                       safcm.LogDebug3,
                        safcm.MsgSyncReq{
                                Groups: []string{
                                        "all",
                                        "group",
+                                       "group3",
                                        "remove",
                                        "host1.example.org",
                                },
                                Files: map[string]*safcm.File{
-                                       "/": &safcm.File{Path: "/",
+                                       "/": {
                                                OrigGroup: "group",
+                                               Path:      "/",
                                                Mode:      fs.ModeDir | 0755 | fs.ModeSetgid,
                                                Uid:       -1,
                                                Gid:       -1,
@@ -74,14 +72,14 @@ func TestHostSyncReq(t *testing.T) {
                                                        "touch /.update",
                                                },
                                        },
-                                       "/etc": &safcm.File{
+                                       "/etc": {
                                                OrigGroup: "group",
                                                Path:      "/etc",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
                                        },
-                                       "/etc/.hidden": &safcm.File{
+                                       "/etc/.hidden": {
                                                OrigGroup: "group",
                                                Path:      "/etc/.hidden",
                                                Mode:      0100 | fs.ModeSetuid | fs.ModeSetgid | fs.ModeSticky,
@@ -89,15 +87,15 @@ func TestHostSyncReq(t *testing.T) {
                                                Gid:       -1,
                                                Data:      []byte("..."),
                                        },
-                                       "/etc/motd": &safcm.File{
+                                       "/etc/motd": {
                                                OrigGroup: "group",
                                                Path:      "/etc/motd",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               Data:      []byte("Welcome to Host ONE\n\n\n\n"),
+                                               Data:      []byte("Welcome to Host ONE\n\n\n\n\n\nall\n\n\nhost1.example.org\n\n\n\n"),
                                        },
-                                       "/etc/rc.local": &safcm.File{
+                                       "/etc/rc.local": {
                                                OrigGroup: "group",
                                                Path:      "/etc/rc.local",
                                                Mode:      0700,
@@ -108,7 +106,7 @@ func TestHostSyncReq(t *testing.T) {
                                                        "/etc/rc.local",
                                                },
                                        },
-                                       "/etc/resolv.conf": &safcm.File{
+                                       "/etc/resolv.conf": {
                                                OrigGroup: "group",
                                                Path:      "/etc/resolv.conf",
                                                Mode:      0641,
@@ -121,7 +119,7 @@ func TestHostSyncReq(t *testing.T) {
                                                        "echo resolv.conf updated",
                                                },
                                        },
-                                       "/etc/test": &safcm.File{
+                                       "/etc/test": {
                                                OrigGroup: "group",
                                                Path:      "/etc/test",
                                                Mode:      os.ModeSymlink | 0777,
@@ -137,110 +135,21 @@ func TestHostSyncReq(t *testing.T) {
                                Services: []string{
                                        "unbound",
                                },
-                               Commands: []string{
-                                       "echo command one",
-                                       "echo -n command two",
-                               },
-                       },
-                       []string{
-                               "host1.example.org: <nil> 3 host groups: all group host1.example.org remove",
-                               "host1.example.org: <nil> 3 host group priorities (desc. order): host1.example.org",
-                       },
-                       nil,
-               },
-
-               {
-                       "project: host1 (log level info)",
-                       "project",
-                       "host1.example.org",
-                       nil,
-                       safcm.LogInfo,
-                       safcm.MsgSyncReq{
-                               Groups: []string{
-                                       "all",
-                                       "group",
-                                       "remove",
-                                       "host1.example.org",
-                               },
-                               Files: map[string]*safcm.File{
-                                       "/": &safcm.File{Path: "/",
+                               Commands: []*safcm.Command{
+                                       {
                                                OrigGroup: "group",
-                                               Mode:      fs.ModeDir | 0755 | fs.ModeSetgid,
-                                               Uid:       -1,
-                                               Gid:       -1,
-                                               TriggerCommands: []string{
-                                                       "touch /.update",
-                                               },
+                                               Cmd:       "echo command one",
                                        },
-                                       "/etc": &safcm.File{
+                                       {
                                                OrigGroup: "group",
-                                               Path:      "/etc",
-                                               Mode:      fs.ModeDir | 0755,
-                                               Uid:       -1,
-                                               Gid:       -1,
-                                       },
-                                       "/etc/.hidden": &safcm.File{
-                                               OrigGroup: "group",
-                                               Path:      "/etc/.hidden",
-                                               Mode:      0100 | fs.ModeSetuid | fs.ModeSetgid | fs.ModeSticky,
-                                               Uid:       -1,
-                                               Gid:       -1,
-                                               Data:      []byte("..."),
-                                       },
-                                       "/etc/motd": &safcm.File{
-                                               OrigGroup: "group",
-                                               Path:      "/etc/motd",
-                                               Mode:      0644,
-                                               Uid:       -1,
-                                               Gid:       -1,
-                                               Data:      []byte("Welcome to Host ONE\n\n\n\n"),
-                                       },
-                                       "/etc/rc.local": &safcm.File{
-                                               OrigGroup: "group",
-                                               Path:      "/etc/rc.local",
-                                               Mode:      0700,
-                                               Uid:       -1,
-                                               Gid:       -1,
-                                               Data:      []byte("#!/bin/sh\n"),
-                                               TriggerCommands: []string{
-                                                       "/etc/rc.local",
-                                               },
-                                       },
-                                       "/etc/resolv.conf": &safcm.File{
-                                               OrigGroup: "group",
-                                               Path:      "/etc/resolv.conf",
-                                               Mode:      0641,
-                                               User:      "user",
-                                               Uid:       -1,
-                                               Group:     "group",
-                                               Gid:       -1,
-                                               Data:      []byte("nameserver ::1\n"),
-                                               TriggerCommands: []string{
-                                                       "echo resolv.conf updated",
-                                               },
-                                       },
-                                       "/etc/test": &safcm.File{
-                                               OrigGroup: "group",
-                                               Path:      "/etc/test",
-                                               Mode:      os.ModeSymlink | 0777,
-                                               Uid:       -1,
-                                               Gid:       -1,
-                                               Data:      []byte("doesnt-exist"),
+                                               Cmd:       "echo -n command two",
                                        },
                                },
-                               Packages: []string{
-                                       "unbound",
-                                       "unbound-anchor",
-                               },
-                               Services: []string{
-                                       "unbound",
-                               },
-                               Commands: []string{
-                                       "echo command one",
-                                       "echo -n command two",
-                               },
                        },
-                       nil,
+                       []string{
+                               "3 false host groups: all group group3 host1.example.org remove",
+                               "3 false host group priorities (descending): host1.example.org",
+                       },
                        nil,
                },
 
@@ -249,13 +158,12 @@ func TestHostSyncReq(t *testing.T) {
                        "project-conflict-file",
                        "host1.example.org",
                        nil,
-                       safcm.LogDebug3,
                        safcm.MsgSyncReq{},
                        []string{
-                               "host1.example.org: <nil> 3 host groups: all dns host1.example.org",
-                               "host1.example.org: <nil> 3 host group priorities (desc. order): host1.example.org",
+                               "3 false host groups: all dns host1.example.org",
+                               "3 false host group priorities (descending): host1.example.org",
                        },
-                       fmt.Errorf("groups dns and all both provide file \"/etc/resolv.conf\"\nUse 'group_order' in config.yaml to declare preference"),
+                       fmt.Errorf("groups dns and all both provide \"/etc/resolv.conf\"\nUse 'group_priority' in config.yaml to declare preference"),
                },
                {
                        "conflict: file from detected group",
@@ -264,13 +172,12 @@ func TestHostSyncReq(t *testing.T) {
                        []string{
                                "detected_other",
                        },
-                       safcm.LogDebug3,
                        safcm.MsgSyncReq{},
                        []string{
-                               "host2.example.org: <nil> 3 host groups: all detected_other host2.example.org other",
-                               "host2.example.org: <nil> 3 host group priorities (desc. order): host2.example.org",
+                               "3 false host groups: all detected_other host2.example.org other",
+                               "3 false host group priorities (descending): host2.example.org",
                        },
-                       fmt.Errorf("groups other and all both provide file \"/etc/resolv.conf\"\nUse 'group_order' in config.yaml to declare preference"),
+                       fmt.Errorf("groups other and all both provide \"/etc/resolv.conf\"\nUse 'group_priority' in config.yaml to declare preference"),
                },
 
                {
@@ -278,13 +185,12 @@ func TestHostSyncReq(t *testing.T) {
                        "project-conflict-dir",
                        "host1.example.org",
                        nil,
-                       safcm.LogDebug3,
                        safcm.MsgSyncReq{},
                        []string{
-                               "host1.example.org: <nil> 3 host groups: all dns host1.example.org",
-                               "host1.example.org: <nil> 3 host group priorities (desc. order): host1.example.org",
+                               "3 false host groups: all dns host1.example.org",
+                               "3 false host group priorities (descending): host1.example.org",
                        },
-                       fmt.Errorf("groups dns and all both provide file \"/etc\"\nUse 'group_order' in config.yaml to declare preference"),
+                       fmt.Errorf("groups dns and all both provide \"/etc\"\nUse 'group_priority' in config.yaml to declare preference"),
                },
                {
                        "conflict: dir from detected group",
@@ -293,13 +199,12 @@ func TestHostSyncReq(t *testing.T) {
                        []string{
                                "detected_other",
                        },
-                       safcm.LogDebug3,
                        safcm.MsgSyncReq{},
                        []string{
-                               "host2.example.org: <nil> 3 host groups: all detected_other host2.example.org other",
-                               "host2.example.org: <nil> 3 host group priorities (desc. order): host2.example.org",
+                               "3 false host groups: all detected_other host2.example.org other",
+                               "3 false host group priorities (descending): host2.example.org",
                        },
-                       fmt.Errorf("groups other and all both provide file \"/etc\"\nUse 'group_order' in config.yaml to declare preference"),
+                       fmt.Errorf("groups other and all both provide \"/etc\"\nUse 'group_priority' in config.yaml to declare preference"),
                },
 
                {
@@ -307,42 +212,40 @@ func TestHostSyncReq(t *testing.T) {
                        "project-group-cycle",
                        "host1.example.org",
                        nil,
-                       safcm.LogDebug3,
                        safcm.MsgSyncReq{},
                        nil,
                        fmt.Errorf("groups.yaml: cycle while expanding group \"group-b\""),
                },
 
                {
-                       "group_order",
-                       "project-group_order",
+                       "group_priority",
+                       "project-group_priority",
                        "host1.example.org",
                        nil,
-                       safcm.LogDebug3,
                        safcm.MsgSyncReq{
                                Groups: []string{"all", "group-b", "group-a", "host1.example.org"},
                                Files: map[string]*safcm.File{
                                        "/": {
+                                               OrigGroup: "host1.example.org",
                                                Path:      "/",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "host1.example.org",
                                        },
                                        "/etc": {
+                                               OrigGroup: "host1.example.org",
                                                Path:      "/etc",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "host1.example.org",
                                        },
                                        "/etc/dir-to-file": {
+                                               OrigGroup: "group-a",
                                                Path:      "/etc/dir-to-file",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("dir-to-file: from group-a\n"),
-                                               OrigGroup: "group-a",
                                        },
                                        "/etc/dir-to-filex": {
                                                OrigGroup: "group-b",
@@ -353,12 +256,12 @@ func TestHostSyncReq(t *testing.T) {
                                                Data:      []byte("dir-to-filex\n"),
                                        },
                                        "/etc/dir-to-link": {
+                                               OrigGroup: "group-a",
                                                Path:      "/etc/dir-to-link",
                                                Mode:      fs.ModeSymlink | 0777,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("target"),
-                                               OrigGroup: "group-a",
                                        },
                                        "/etc/dir-to-linkx": {
                                                OrigGroup: "group-b",
@@ -369,121 +272,125 @@ func TestHostSyncReq(t *testing.T) {
                                                Data:      []byte("dir-to-linkx\n"),
                                        },
                                        "/etc/file-to-dir": {
+                                               OrigGroup: "group-a",
                                                Path:      "/etc/file-to-dir",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group-a",
                                        },
                                        "/etc/file-to-dir/file": {
+                                               OrigGroup: "group-a",
                                                Path:      "/etc/file-to-dir/file",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("file: from group-a\n"),
-                                               OrigGroup: "group-a",
                                        },
                                        "/etc/file-to-dir/dir": {
+                                               OrigGroup: "group-a",
                                                Path:      "/etc/file-to-dir/dir",
                                                Mode:      fs.ModeDir | 0755,
                                                Uid:       -1,
                                                Gid:       -1,
-                                               OrigGroup: "group-a",
                                        },
                                        "/etc/file-to-dir/dir/file2": {
+                                               OrigGroup: "group-a",
                                                Path:      "/etc/file-to-dir/dir/file2",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("file2: from group-a\n"),
-                                               OrigGroup: "group-a",
                                        },
                                        "/etc/motd": {
+                                               OrigGroup: "host1.example.org",
                                                Path:      "/etc/motd",
                                                Mode:      0644,
                                                Uid:       -1,
                                                Gid:       -1,
                                                Data:      []byte("motd: from host1\n"),
-                                               OrigGroup: "host1.example.org",
                                        },
                                },
                        },
                        []string{
-                               "host1.example.org: <nil> 3 host groups: all group-a group-b host1.example.org",
-                               "host1.example.org: <nil> 3 host group priorities (desc. order): host1.example.org group-a group-b all",
-                               `host1.example.org: <nil> 4 files: "/etc": group group-a overwrites triggers from group group-b`,
-                               `host1.example.org: <nil> 4 files: "/etc": group host1.example.org overwrites triggers from group group-a`,
+                               "3 false host groups: all group-a group-b host1.example.org",
+                               "3 false host group priorities (descending): host1.example.org group-a group-b all",
+                               `4 false files: "/etc": group group-a overwrites triggers from group group-b`,
+                               `4 false files: "/etc": group host1.example.org overwrites triggers from group group-a`,
+                       },
+                       nil,
+               },
+
+               {
+                       "group_priority (single group)",
+                       "project-group_priority-single",
+                       "host1.example.org",
+                       nil,
+                       safcm.MsgSyncReq{
+                               Groups: []string{"all", "group-b", "group-a", "host1.example.org"},
+                               Files: map[string]*safcm.File{
+                                       "/": {
+                                               OrigGroup: "group-a",
+                                               Path:      "/",
+                                               Mode:      fs.ModeDir | 0755,
+                                               Uid:       -1,
+                                               Gid:       -1,
+                                       },
+                                       "/file.txt": {
+                                               OrigGroup: "group-a",
+                                               Path:      "/file.txt",
+                                               Mode:      0644,
+                                               Uid:       -1,
+                                               Gid:       -1,
+                                               Data:      []byte("file.txt: from group-a\n"),
+                                       },
+                               },
+                       },
+                       []string{
+                               "3 false host groups: all group-a group-b host1.example.org",
+                               "3 false host group priorities (descending): host1.example.org group-a",
                        },
                        nil,
                },
        }
 
        for _, tc := range tests {
-               err = os.Chdir(filepath.Join(cwd, "testdata", tc.project))
-               if err != nil {
-                       t.Fatal(err)
-               }
-
-               // `safcm fixperms` in case user has strict umask
-               log.SetOutput(io.Discard)
-               err := MainFixperms()
-               if err != nil {
-                       t.Fatal(err)
-               }
-               log.SetOutput(os.Stderr)
-
-               cfg, allHosts, allGroups, err := LoadBaseFiles()
-               if err != nil {
-                       t.Fatal(err)
-               }
-               cfg.LogLevel = tc.level
-
-               var events []string
-               ch := make(chan Event)
-               done := make(chan struct{})
-               go func() {
-                       for {
-                               x, ok := <-ch
-                               if !ok {
-                                       break
-                               }
-                               if x.ConnEvent.Type != 0 {
-                                       panic("unexpected ConnEvent")
-                               }
-                               events = append(events,
-                                       fmt.Sprintf("%s: %v %d %s",
-                                               x.Host.Name,
-                                               x.Error, x.Log.Level,
-                                               x.Log.Text))
+               t.Run(tc.name, func(t *testing.T) {
+                       err = os.Chdir(filepath.Join(cwd,
+                               "testdata", tc.project))
+                       if err != nil {
+                               t.Fatal(err)
                        }
-                       done <- struct{}{}
-               }()
 
-               s := &Sync{
-                       host:      allHosts.Map[tc.host],
-                       config:    cfg,
-                       allHosts:  allHosts,
-                       allGroups: allGroups,
-                       events:    ch,
-               }
+                       // `safcm fixperms` in case user has strict umask
+                       log.SetOutput(io.Discard)
+                       err := MainFixperms()
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       log.SetOutput(os.Stderr)
 
-               res, err := s.hostSyncReq(tc.detected)
-               if !reflect.DeepEqual(tc.exp, res) {
-                       t.Errorf("%s: res: %s", tc.name,
-                               cmp.Diff(tc.exp, res))
-               }
-               // Ugly but the simplest way to compare errors (including nil)
-               if fmt.Sprintf("%s", err) != fmt.Sprintf("%s", tc.expErr) {
-                       t.Errorf("%s: err = %#v, want %#v",
-                               tc.name, err, tc.expErr)
-               }
+                       cfg, allHosts, allGroups, err := LoadBaseFiles()
+                       if err != nil {
+                               t.Fatal(err)
+                       }
 
-               close(ch)
-               <-done
-               if !reflect.DeepEqual(tc.expEvents, events) {
-                       t.Errorf("%s: events: %s", tc.name,
-                               cmp.Diff(tc.expEvents, events))
-               }
+                       var events []string
+                       s := &Sync{
+                               host:      allHosts.Map[tc.host],
+                               config:    cfg,
+                               allHosts:  allHosts,
+                               allGroups: allGroups,
+                               logFunc: func(level safcm.LogLevel, escaped bool, msg string) {
+                                       events = append(events,
+                                               fmt.Sprintf("%d %v %s", level, escaped, msg))
+                               },
+                       }
 
+                       res, err := s.hostSyncReq(tc.detected)
+                       testutil.AssertEqual(t, "res", res, tc.exp)
+                       testutil.AssertErrorEqual(t, "err", err, tc.expErr)
+                       testutil.AssertEqual(t, "events",
+                               events, tc.expEvents)
+               })
        }
 }