]> ruderich.org/simon Gitweb - safcm/safcm.git/blob - cmd/safcm/sync_test.go
Move synchronization loop into new package frontend
[safcm/safcm.git] / cmd / safcm / 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 main
17
18 import (
19         "bytes"
20         "fmt"
21         "log"
22         "os"
23         "testing"
24
25         "ruderich.org/simon/safcm"
26         "ruderich.org/simon/safcm/cmd/safcm/config"
27         "ruderich.org/simon/safcm/frontend"
28         "ruderich.org/simon/safcm/rpc"
29         "ruderich.org/simon/safcm/testutil"
30 )
31
32 func TestHostsToSync(t *testing.T) {
33         cwd, err := os.Getwd()
34         if err != nil {
35                 t.Fatal(err)
36         }
37         defer os.Chdir(cwd)
38
39         err = os.Chdir("testdata/project")
40         if err != nil {
41                 t.Fatal(err)
42         }
43         _, allHosts, allGroups, err := LoadBaseFiles()
44         if err != nil {
45                 t.Fatal(err)
46         }
47
48         const errMsg = `
49
50 Groups depending on "detected" groups cannot be used to select hosts as these
51 are only available after the hosts were contacted.
52 `
53
54         tests := []struct {
55                 name   string
56                 names  []string
57                 exp    []*config.Host
58                 expErr error
59         }{
60                 {
61                         "empty names",
62                         nil,
63                         nil,
64                         nil,
65                 },
66
67                 {
68                         "no match",
69                         []string{"unknown-host/group"},
70                         nil,
71                         fmt.Errorf("hosts/groups not found: \"unknown-host/group\""),
72                 },
73
74                 {
75                         "host: single name",
76                         []string{"host2"},
77                         []*config.Host{
78                                 allHosts.Map["host2"],
79                         },
80                         nil,
81                 },
82                 {
83                         "host: multiple names",
84                         []string{"host2", "host1.example.org"},
85                         []*config.Host{
86                                 allHosts.Map["host1.example.org"],
87                                 allHosts.Map["host2"],
88                         },
89                         nil,
90                 },
91                 {
92                         "host: multiple identical names",
93                         []string{"host2", "host2"},
94                         []*config.Host{
95                                 allHosts.Map["host2"],
96                         },
97                         nil,
98                 },
99                 {
100                         "host: multiple names, including unknown",
101                         []string{"host2", "unknown-host"},
102                         nil,
103                         fmt.Errorf("hosts/groups not found: \"unknown-host\""),
104                 },
105                 {
106                         "host: multiple names, including unknowns",
107                         []string{"host2", "unknown-host", "unknown-host-2"},
108                         nil,
109                         fmt.Errorf("hosts/groups not found: \"unknown-host\" \"unknown-host-2\""),
110                 },
111
112                 {
113                         "group: single name",
114                         []string{"group3"},
115                         []*config.Host{
116                                 allHosts.Map["host1.example.org"],
117                         },
118                         nil,
119                 },
120                 {
121                         "group: multiple names",
122                         []string{"group3", "group2"},
123                         []*config.Host{
124                                 allHosts.Map["host1.example.org"],
125                                 allHosts.Map["host2"],
126                         },
127                         nil,
128                 },
129                 {
130                         "group: multiple identical names",
131                         []string{"group3", "group2", "group3"},
132                         []*config.Host{
133                                 allHosts.Map["host1.example.org"],
134                                 allHosts.Map["host2"],
135                         },
136                         nil,
137                 },
138                 {
139                         "group: multiple names, including unknown",
140                         []string{"group3", "group2", "unknown-group"},
141                         nil,
142                         fmt.Errorf("hosts/groups not found: \"unknown-group\""),
143                 },
144                 {
145                         "group: \"all\"",
146                         []string{"all"},
147                         []*config.Host{
148                                 allHosts.Map["host1.example.org"],
149                                 allHosts.Map["host2"],
150                                 allHosts.Map["host3.example.net"],
151                         },
152                         nil,
153                 },
154
155                 {
156                         "group: single name (detected)",
157                         []string{"group"},
158                         nil,
159                         fmt.Errorf(`group "group" depends on "detected" groups` + errMsg),
160                 },
161                 {
162                         "group: multiple names (detected)",
163                         []string{"group", "group2"},
164                         nil,
165                         fmt.Errorf(`group "group" depends on "detected" groups` + errMsg),
166                 },
167
168                 {
169                         "\"all\" and name",
170                         []string{"all", "group2"},
171                         []*config.Host{
172                                 allHosts.Map["host1.example.org"],
173                                 allHosts.Map["host2"],
174                                 allHosts.Map["host3.example.net"],
175                         },
176                         nil,
177                 },
178                 {
179                         "\"all\" and names",
180                         []string{"all", "group2", "host2"},
181                         []*config.Host{
182                                 allHosts.Map["host1.example.org"],
183                                 allHosts.Map["host2"],
184                                 allHosts.Map["host3.example.net"],
185                         },
186                         nil,
187                 },
188         }
189
190         for _, tc := range tests {
191                 t.Run(tc.name, func(t *testing.T) {
192                         res, err := hostsToSync(tc.names, allHosts, allGroups)
193                         testutil.AssertEqual(t, "res", res, tc.exp)
194                         testutil.AssertErrorEqual(t, "err", err, tc.expErr)
195                 })
196         }
197 }
198
199 func TestLogEvent(t *testing.T) {
200         // Restore default logger
201         defer log.SetFlags(log.Flags())
202         defer log.SetOutput(os.Stderr)
203
204         tests := []struct {
205                 name      string
206                 event     frontend.Event
207                 level     safcm.LogLevel
208                 isTTY     bool
209                 exp       string
210                 expFailed bool
211         }{
212
213                 {
214                         "Error",
215                         frontend.Event{
216                                 Error: fmt.Errorf("fake error"),
217                         },
218                         safcm.LogDebug3,
219                         false,
220                         "[error]   [fake-host] fake error\n",
221                         true,
222                 },
223                 {
224                         "Error (tty)",
225                         frontend.Event{
226                                 Error: fmt.Errorf("fake error"),
227                         },
228                         safcm.LogDebug3,
229                         true,
230                         "[error]   [\x1b[31mfake-host\x1b[0m] fake error\n",
231                         true,
232                 },
233                 {
234                         "Error: escape",
235                         frontend.Event{
236                                 Error: fmt.Errorf("\x00"),
237                         },
238                         safcm.LogDebug3,
239                         false,
240                         "[error]   [fake-host] \\x00\n",
241                         true,
242                 },
243                 {
244                         "Error: escape (tty)",
245                         frontend.Event{
246                                 Error: fmt.Errorf("\x00"),
247                         },
248                         safcm.LogDebug3,
249                         true,
250                         "[error]   [\x1b[31mfake-host\x1b[0m] \x1b[35m\\x00\x1b[0m\n",
251                         true,
252                 },
253
254                 {
255                         "Log: info",
256                         frontend.Event{
257                                 Log: frontend.Log{
258                                         Level: safcm.LogInfo,
259                                         Text:  "info log",
260                                 },
261                         },
262                         safcm.LogDebug3,
263                         false,
264                         "[info]    [fake-host] info log\n",
265                         false,
266                 },
267                 {
268                         "Log: info (tty)",
269                         frontend.Event{
270                                 Log: frontend.Log{
271                                         Level: safcm.LogInfo,
272                                         Text:  "info log",
273                                 },
274                         },
275                         safcm.LogDebug3,
276                         true,
277                         "[info]    [fake-host] info log\n",
278                         false,
279                 },
280                 {
281                         "Log: verbose",
282                         frontend.Event{
283                                 Log: frontend.Log{
284                                         Level: safcm.LogVerbose,
285                                         Text:  "verbose log",
286                                 },
287                         },
288                         safcm.LogDebug3,
289                         false,
290                         "[verbose] [fake-host] verbose log\n",
291                         false,
292                 },
293                 {
294                         "Log: debug",
295                         frontend.Event{
296                                 Log: frontend.Log{
297                                         Level: safcm.LogDebug,
298                                         Text:  "debug log",
299                                 },
300                         },
301                         safcm.LogDebug3,
302                         false,
303                         "[debug]   [fake-host] debug log\n",
304                         false,
305                 },
306                 {
307                         "Log: debug2",
308                         frontend.Event{
309                                 Log: frontend.Log{
310                                         Level: safcm.LogDebug2,
311                                         Text:  "debug2 log",
312                                 },
313                         },
314                         safcm.LogDebug3,
315                         false,
316                         "[debug2]  [fake-host] debug2 log\n",
317                         false,
318                 },
319                 {
320                         "Log: debug3",
321                         frontend.Event{
322                                 Log: frontend.Log{
323                                         Level: safcm.LogDebug3,
324                                         Text:  "debug3 log",
325                                 },
326                         },
327                         safcm.LogDebug3,
328                         false,
329                         fmt.Sprintf("[INVALID=%d] [fake-host] debug3 log\n",
330                                 safcm.LogDebug3),
331                         false,
332                 },
333                 {
334                         "Log: debug3 (tty)",
335                         frontend.Event{
336                                 Log: frontend.Log{
337                                         Level: safcm.LogDebug3,
338                                         Text:  "debug3 log",
339                                 },
340                         },
341                         safcm.LogDebug3,
342                         true,
343                         fmt.Sprintf("[INVALID=%d] [\x1b[31mfake-host\x1b[0m] debug3 log\n",
344                                 safcm.LogDebug3),
345                         false,
346                 },
347                 {
348                         "Log: escape",
349                         frontend.Event{
350                                 Log: frontend.Log{
351                                         Level: safcm.LogInfo,
352                                         Text:  "\x00",
353                                 },
354                         },
355                         safcm.LogDebug3,
356                         false,
357                         "[info]    [fake-host] \\x00\n",
358                         false,
359                 },
360                 {
361                         "Log: escape (tty)",
362                         frontend.Event{
363                                 Log: frontend.Log{
364                                         Level: safcm.LogInfo,
365                                         Text:  "\x00",
366                                 },
367                         },
368                         safcm.LogDebug3,
369                         true,
370                         "[info]    [fake-host] \x1b[35m\\x00\x1b[0m\n",
371                         false,
372                 },
373
374                 {
375                         "ConnEvent: stderr",
376                         frontend.Event{
377                                 ConnEvent: rpc.ConnEvent{
378                                         Type: rpc.ConnEventStderr,
379                                         Data: "fake stderr",
380                                 },
381                         },
382                         safcm.LogDebug3,
383                         false,
384                         "[stderr]  [fake-host] fake stderr\n",
385                         false,
386                 },
387                 {
388                         "ConnEvent: stderr (tty)",
389                         frontend.Event{
390                                 ConnEvent: rpc.ConnEvent{
391                                         Type: rpc.ConnEventStderr,
392                                         Data: "fake stderr",
393                                 },
394                         },
395                         safcm.LogDebug3,
396                         true,
397                         "[stderr]  [fake-host] fake stderr\n",
398                         false,
399                 },
400                 {
401                         "ConnEvent: debug",
402                         frontend.Event{
403                                 ConnEvent: rpc.ConnEvent{
404                                         Type: rpc.ConnEventDebug,
405                                         Data: "conn debug",
406                                 },
407                         },
408                         safcm.LogDebug3,
409                         false,
410                         "[debug3]  [fake-host] conn debug\n",
411                         false,
412                 },
413                 {
414                         "ConnEvent: upload",
415                         frontend.Event{
416                                 ConnEvent: rpc.ConnEvent{
417                                         Type: rpc.ConnEventUpload,
418                                 },
419                         },
420                         safcm.LogDebug3,
421                         false,
422                         "[info]    [fake-host] remote helper upload in progress\n",
423                         false,
424                 },
425                 {
426                         "ConnEvent: upload (ignored)",
427                         frontend.Event{
428                                 ConnEvent: rpc.ConnEvent{
429                                         Type: rpc.ConnEventUpload,
430                                 },
431                         },
432                         safcm.LogError,
433                         false,
434                         "",
435                         false,
436                 },
437                 {
438                         "ConnEvent: invalid",
439                         frontend.Event{
440                                 ConnEvent: rpc.ConnEvent{
441                                         Type: 42,
442                                         Data: "invalid",
443                                 },
444                         },
445                         safcm.LogError,
446                         false,
447                         "[INVALID=42] [fake-host] invalid\n",
448                         false,
449                 },
450                 {
451                         "ConnEvent: invalid (tty)",
452                         frontend.Event{
453                                 ConnEvent: rpc.ConnEvent{
454                                         Type: 42,
455                                         Data: "invalid",
456                                 },
457                         },
458                         safcm.LogError,
459                         true,
460                         "[INVALID=42] [\x1b[31mfake-host\x1b[0m] invalid\n",
461                         false,
462                 },
463                 {
464                         "ConnEvent: escape",
465                         frontend.Event{
466                                 ConnEvent: rpc.ConnEvent{
467                                         Type: rpc.ConnEventStderr,
468                                         Data: "\x00",
469                                 },
470                         },
471                         safcm.LogDebug3,
472                         false,
473                         "[stderr]  [fake-host] \\x00\n",
474                         false,
475                 },
476                 {
477                         "ConnEvent: escape (tty)",
478                         frontend.Event{
479                                 ConnEvent: rpc.ConnEvent{
480                                         Type: rpc.ConnEventDebug,
481                                         Data: "\x01",
482                                 },
483                         },
484                         safcm.LogDebug3,
485                         true,
486                         "[debug3]  [fake-host] \x1b[35m\\x01\x1b[0m\n",
487                         false,
488                 },
489
490                 {
491                         "Escaped",
492                         frontend.Event{
493                                 Log: frontend.Log{
494                                         Level: safcm.LogInfo,
495                                         Text:  "\x00",
496                                 },
497                                 Escaped: true,
498                         },
499                         safcm.LogDebug3,
500                         false,
501                         "[info]    [fake-host] \x00\n",
502                         false,
503                 },
504                 {
505                         "Escaped (tty)",
506                         frontend.Event{
507                                 Log: frontend.Log{
508                                         Level: safcm.LogInfo,
509                                         Text:  "\x00",
510                                 },
511                                 Escaped: true,
512                         },
513                         safcm.LogDebug3,
514                         true,
515                         "[info]    [fake-host] \x00\n",
516                         false,
517                 },
518
519                 {
520                         "empty (invalid)",
521                         frontend.Event{},
522                         safcm.LogDebug3,
523                         false,
524                         "[INVALID=0] [fake-host] \n",
525                         false,
526                 },
527         }
528
529         for _, tc := range tests {
530                 t.Run(tc.name, func(t *testing.T) {
531                         tc.event.Host = &Sync{
532                                 host: &config.Host{
533                                         Name: "fake-host",
534                                 },
535                         }
536
537                         var buf bytes.Buffer
538                         log.SetFlags(0)
539                         log.SetOutput(&buf)
540
541                         var failed bool
542                         logEvent(tc.event, tc.level, tc.isTTY, &failed)
543
544                         testutil.AssertEqual(t, "log",
545                                 buf.String(), tc.exp)
546                         testutil.AssertEqual(t, "failed",
547                                 failed, tc.expFailed)
548                 })
549         }
550 }