]> ruderich.org/simon Gitweb - safcm/safcm.git/blob - cmd/safcm-remote/sync/sync_test.go
First working version
[safcm/safcm.git] / cmd / safcm-remote / sync / sync_test.go
1 // Copyright (C) 2021  Simon Ruderich
2 //
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.
7 //
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.
12 //
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/>.
15
16 package sync
17
18 import (
19         "bytes"
20         "fmt"
21         "os/exec"
22         "reflect"
23         "sync"
24         "testing"
25
26         "github.com/google/go-cmp/cmp"
27         "github.com/google/go-cmp/cmp/cmpopts"
28
29         "ruderich.org/simon/safcm"
30         "ruderich.org/simon/safcm/cmd/safcm-remote/log"
31         "ruderich.org/simon/safcm/cmd/safcm-remote/run"
32 )
33
34 type testRunner struct {
35         t         *testing.T
36         name      string
37         expCmds   []*exec.Cmd
38         resStdout [][]byte
39         resStderr [][]byte
40         resError  []error
41 }
42
43 func (r *testRunner) Run(cmd *exec.Cmd) error {
44         stdout, stderr, resErr := r.check("run", cmd)
45         _, err := cmd.Stdout.Write(stdout)
46         if err != nil {
47                 panic(err)
48         }
49         _, err = cmd.Stderr.Write(stderr)
50         if err != nil {
51                 panic(err)
52         }
53         return resErr
54 }
55 func (r *testRunner) CombinedOutput(cmd *exec.Cmd) ([]byte, error) {
56         stdout, stderr, err := r.check("combinedOutput", cmd)
57         if stderr != nil {
58                 // stdout also contains stderr
59                 r.t.Fatalf("%s: CombinedOutput: stderr != nil, but %v",
60                         r.name, stderr)
61         }
62         return stdout, err
63 }
64 func (r *testRunner) check(method string, cmd *exec.Cmd) (
65         []byte, []byte, error) {
66
67         if len(r.expCmds) == 0 {
68                 r.t.Fatalf("%s: %s: empty expCmds", r.name, method)
69         }
70         if len(r.resStdout) == 0 {
71                 r.t.Fatalf("%s: %s: empty resStdout", r.name, method)
72         }
73         if len(r.resStderr) == 0 {
74                 r.t.Fatalf("%s: %s: empty resStderr", r.name, method)
75         }
76         if len(r.resError) == 0 {
77                 r.t.Fatalf("%s: %s: empty resError", r.name, method)
78         }
79
80         exp := r.expCmds[0]
81         r.expCmds = r.expCmds[1:]
82         if !reflect.DeepEqual(exp, cmd) {
83                 r.t.Errorf("%s: %s: %s", r.name, method,
84                         cmp.Diff(exp, cmd, cmpopts.IgnoreUnexported(
85                                 exec.Cmd{},
86                                 bytes.Buffer{})))
87         }
88
89         var stdout, stderr []byte
90         var err error
91
92         stdout, r.resStdout = r.resStdout[0], r.resStdout[1:]
93         stderr, r.resStderr = r.resStderr[0], r.resStderr[1:]
94         err, r.resError = r.resError[0], r.resError[1:]
95
96         return stdout, stderr, err
97 }
98
99 type syncTestResult struct {
100         ch     chan string
101         wg     sync.WaitGroup
102         dbg    []string
103         runner *testRunner
104 }
105
106 func prepareSync(req safcm.MsgSyncReq, runner *testRunner) (
107         *Sync, *syncTestResult) {
108
109         res := &syncTestResult{
110                 ch:     make(chan string),
111                 runner: runner,
112         }
113         res.wg.Add(1)
114         go func() {
115                 for {
116                         x, ok := <-res.ch
117                         if !ok {
118                                 break
119                         }
120                         res.dbg = append(res.dbg, x)
121                 }
122                 res.wg.Done()
123         }()
124
125         logger := log.NewLogger(logPrefix,
126                 func(level safcm.LogLevel, format string, a ...interface{}) {
127                         res.ch <- fmt.Sprintf("%d: %s", level,
128                                 fmt.Sprintf(format, a...))
129                 })
130         return &Sync{
131                 req: req,
132                 cmd: run.NewCmd(runner, logger),
133                 log: logger,
134         }, res
135 }
136
137 func (s *syncTestResult) Wait() []string {
138         close(s.ch)
139         s.wg.Wait()
140
141         // All expected commands must have been executed
142         if len(s.runner.expCmds) != 0 {
143                 s.runner.t.Errorf("%s: expCmds left: %v",
144                         s.runner.name, s.runner.expCmds)
145         }
146         if len(s.runner.resStdout) != 0 {
147                 s.runner.t.Errorf("%s: resStdout left: %v",
148                         s.runner.name, s.runner.resStdout)
149         }
150         if len(s.runner.resStderr) != 0 {
151                 s.runner.t.Errorf("%s: resStderr left: %v",
152                         s.runner.name, s.runner.resStderr)
153         }
154         if len(s.runner.resError) != 0 {
155                 s.runner.t.Errorf("%s: resError left: %v",
156                         s.runner.name, s.runner.resError)
157         }
158
159         return s.dbg
160 }