]> ruderich.org/simon Gitweb - safcm/safcm.git/blob - cmd/safcm/config/groups_test.go
Use SPDX license identifiers
[safcm/safcm.git] / cmd / safcm / config / groups_test.go
1 // SPDX-License-Identifier: GPL-3.0-or-later
2 // Copyright (C) 2021-2024  Simon Ruderich
3
4 package config
5
6 import (
7         "fmt"
8         "os"
9         "path/filepath"
10         "testing"
11
12         "ruderich.org/simon/safcm/testutil"
13 )
14
15 func TestLoadGroups(t *testing.T) {
16         cwd, err := os.Getwd()
17         if err != nil {
18                 t.Fatal(err)
19         }
20         defer os.Chdir(cwd) //nolint:errcheck
21
22         err = os.Chdir("../testdata/project")
23         if err != nil {
24                 t.Fatal(err)
25         }
26         hosts, err := LoadHosts()
27         if err != nil {
28                 t.Fatal(err)
29         }
30         err = os.Chdir(cwd)
31         if err != nil {
32                 t.Fatal(err)
33         }
34
35         tests := []struct {
36                 path   string
37                 cfg    *Config
38                 hosts  *Hosts
39                 exp    map[string][]string
40                 expErr error
41         }{
42
43                 {
44                         "../testdata/project",
45                         &Config{
46                                 GroupPriority: []string{
47                                         "detected_linux",
48                                         "detected_freebsd",
49                                 },
50                         },
51                         hosts,
52                         map[string][]string{
53                                 "group": {
54                                         "detected_linux",
55                                         "detected_freebsd",
56                                         "host1.example.org",
57                                 },
58                                 "group:remove": {
59                                         "host2",
60                                         "detected_mips",
61                                 },
62                                 "group2": {
63                                         "all",
64                                 },
65                                 "group2:remove": {
66                                         "remove",
67                                 },
68                                 "group3": {
69                                         "host1.example.org",
70                                 },
71                                 "group3:remove": {
72                                         "host2",
73                                 },
74                                 "all_except_some": {
75                                         "all",
76                                 },
77                                 "all_except_some:remove": {
78                                         "host1.example.org",
79                                         "group2",
80                                 },
81                                 "remove": {
82                                         "host1.example.org",
83                                         "host2",
84                                         "host3.example.net",
85                                 },
86                                 "remove:remove": {
87                                         "host2",
88                                 },
89                         },
90                         nil,
91                 },
92
93                 {
94                         "../testdata/project",
95                         &Config{
96                                 GroupPriority: []string{
97                                         "detected_freebsd",
98                                         "does-not-exist",
99                                 },
100                         },
101                         hosts,
102                         nil,
103                         fmt.Errorf("config.yaml: group_priority: group \"does-not-exist\" does not exist"),
104                 },
105                 {
106                         "../testdata/project",
107                         &Config{
108                                 GroupPriority: []string{
109                                         "detected_freebsd",
110                                         "special:group",
111                                 },
112                         },
113                         hosts,
114                         nil,
115                         fmt.Errorf("config.yaml: group_priority: invalid group name \"special:group\""),
116                 },
117                 {
118                         "../testdata/project",
119                         &Config{
120                                 GroupPriority: []string{
121                                         "detected_freebsd",
122                                         "group:remove",
123                                 },
124                         },
125                         hosts,
126                         nil,
127                         fmt.Errorf("config.yaml: group_priority: invalid group name \"group:remove\""),
128                 },
129
130                 {
131                         "../testdata/group-invalid-all",
132                         &Config{},
133                         hosts,
134                         nil,
135                         fmt.Errorf("groups.yaml: group \"all\": conflict with pre-defined group \"all\""),
136                 },
137                 {
138                         "../testdata/group-invalid-all-remove",
139                         &Config{},
140                         hosts,
141                         nil,
142                         fmt.Errorf("groups.yaml: group \"all:remove\": conflict with pre-defined group \"all:remove\""),
143                 },
144                 {
145                         "../testdata/group-invalid-conflict",
146                         &Config{},
147                         hosts,
148                         nil,
149                         fmt.Errorf("groups.yaml: group \"host2\": conflict with existing host"),
150                 },
151                 {
152                         "../testdata/group-invalid-conflict-remove",
153                         &Config{},
154                         hosts,
155                         nil,
156                         fmt.Errorf("groups.yaml: group \"host2:remove\": conflict with existing host"),
157                 },
158                 {
159                         "../testdata/group-invalid-detected",
160                         &Config{},
161                         &Hosts{},
162                         nil,
163                         fmt.Errorf("groups.yaml: group \"detected_linux\": name must not start with \"detected\" (reserved for detected groups)"),
164                 },
165                 {
166                         "../testdata/group-invalid-member",
167                         &Config{},
168                         &Hosts{},
169                         nil,
170                         fmt.Errorf("groups.yaml: group \"group1\": member \"special:member\" must not contain \":\""),
171                 },
172                 {
173                         "../testdata/group-invalid-missing",
174                         &Config{},
175                         &Hosts{},
176                         nil,
177                         fmt.Errorf("groups.yaml: group \"group2\": member \"does-not-exist\" not found"),
178                 },
179                 {
180                         "../testdata/group-invalid-name",
181                         &Config{},
182                         &Hosts{},
183                         nil,
184                         fmt.Errorf("groups.yaml: group \"invalid.group.name\": name contains invalid characters (must match ^[a-z0-9_-]+$)"),
185                 },
186         }
187
188         for _, tc := range tests {
189                 t.Run(tc.path, func(t *testing.T) {
190                         err := os.Chdir(filepath.Join(cwd, tc.path))
191                         if err != nil {
192                                 t.Fatal(err)
193                         }
194
195                         res, err := LoadGroups(tc.cfg, tc.hosts)
196                         testutil.AssertEqual(t, "res", res, tc.exp)
197                         testutil.AssertErrorEqual(t, "err", err, tc.expErr)
198                 })
199         }
200 }
201
202 func TestResolveHostGroups(t *testing.T) {
203         cwd, err := os.Getwd()
204         if err != nil {
205                 t.Fatal(err)
206         }
207         defer os.Chdir(cwd) //nolint:errcheck
208
209         err = os.Chdir("../testdata/project")
210         if err != nil {
211                 t.Fatal(err)
212         }
213         allHosts, err := LoadHosts()
214         if err != nil {
215                 t.Fatal(err)
216         }
217         allGroups, err := LoadGroups(&Config{}, allHosts)
218         if err != nil {
219                 t.Fatal(err)
220         }
221
222         tests := []struct {
223                 name     string
224                 host     string
225                 detected []string
226                 exp      []string
227                 expErr   error
228         }{
229
230                 {
231                         "host1",
232                         "host1.example.org",
233                         nil,
234                         []string{
235                                 "all",
236                                 "group",
237                                 "group3",
238                                 "host1.example.org",
239                                 "remove",
240                         },
241                         nil,
242                 },
243                 {
244                         "host2",
245                         "host2",
246                         nil,
247                         []string{
248                                 "all",
249                                 "group2",
250                                 "host2",
251                         },
252                         nil,
253                 },
254                 {
255                         "host3",
256                         "host3.example.net",
257                         nil,
258                         []string{
259                                 "all",
260                                 "all_except_some",
261                                 "host3.example.net",
262                                 "remove",
263                         },
264                         nil,
265                 },
266                 {
267                         "unknown host",
268                         "unknown",
269                         nil,
270                         []string{
271                                 "all",
272                                 "group2",
273                                 "unknown",
274                         },
275                         nil,
276                 },
277
278                 {
279                         "host1, detected_mips",
280                         "host1.example.org",
281                         []string{
282                                 "detected_mips",
283                         },
284                         []string{
285                                 "all",
286                                 "detected_mips",
287                                 "group3",
288                                 "host1.example.org",
289                                 "remove",
290                         },
291                         nil,
292                 },
293                 {
294                         "host2, detected_linux",
295                         "host2",
296                         []string{
297                                 "detected_linux",
298                         },
299                         []string{
300                                 "all",
301                                 "detected_linux",
302                                 "group2",
303                                 "host2",
304                         },
305                         nil,
306                 },
307         }
308
309         for _, tc := range tests {
310                 t.Run(tc.name, func(t *testing.T) {
311                         res, err := ResolveHostGroups(tc.host, allGroups,
312                                 tc.detected)
313                         testutil.AssertEqual(t, "res", res, tc.exp)
314                         testutil.AssertErrorEqual(t, "err", err, tc.expErr)
315                 })
316         }
317 }
318
319 func TestTransitivelyDetectedGroups(t *testing.T) {
320         tests := []struct {
321                 name   string
322                 groups map[string][]string
323                 exp    map[string]bool
324         }{
325
326                 {
327                         "no detected",
328                         map[string][]string{
329                                 "group-a": {
330                                         "a",
331                                         "b",
332                                         "group-b",
333                                 },
334                                 "group-a:remove": {
335                                         "d",
336                                 },
337                                 "group-b": {
338                                         "c",
339                                         "d",
340                                 },
341                         },
342                         map[string]bool{},
343                 },
344
345                 {
346                         "detected as direct member",
347                         map[string][]string{
348                                 "group-a": {
349                                         "a",
350                                         "b",
351                                         "detected_foo",
352                                 },
353                                 "group-b": {
354                                         "c",
355                                         "d",
356                                 },
357                         },
358                         map[string]bool{
359                                 "group-a": true,
360                         },
361                 },
362
363                 {
364                         "detected as direct :remove member",
365                         map[string][]string{
366                                 "group-a": {
367                                         "a",
368                                         "b",
369                                         "group-b",
370                                 },
371                                 "group-a:remove": {
372                                         "d",
373                                         "detected_foo",
374                                 },
375                                 "group-b": {
376                                         "c",
377                                         "d",
378                                 },
379                         },
380                         map[string]bool{
381                                 "group-a": true,
382                         },
383                 },
384
385                 {
386                         "detected as transitive member",
387                         map[string][]string{
388                                 "group-a": {
389                                         "group-b",
390                                 },
391                                 "group-b": {
392                                         "group-c",
393                                 },
394                                 "group-c": {
395                                         "group-d",
396                                         "detected_bar",
397                                 },
398                                 "group-d": {
399                                         "group-e",
400                                 },
401                                 "group-e": {
402                                         "detected_foo",
403                                 },
404                                 "group-f": {
405                                         "a",
406                                         "b",
407                                 },
408                         },
409                         map[string]bool{
410                                 "group-a": true,
411                                 "group-b": true,
412                                 "group-c": true,
413                                 "group-d": true,
414                                 "group-e": true,
415                         },
416                 },
417
418                 {
419                         "detected as transitive :remove member",
420                         map[string][]string{
421                                 "group-a": {
422                                         "group-b",
423                                 },
424                                 "group-b": {
425                                         "group-c",
426                                 },
427                                 "group-c": {
428                                         "group-d",
429                                 },
430                                 "group-d": {
431                                         "group-e",
432                                 },
433                                 "group-e": {
434                                         "all",
435                                 },
436                                 "group-e:remove": {
437                                         "detected_foo",
438                                 },
439                                 "group-f": {
440                                         "a",
441                                         "b",
442                                 },
443                         },
444                         map[string]bool{
445                                 "group-a": true,
446                                 "group-b": true,
447                                 "group-c": true,
448                                 "group-d": true,
449                                 "group-e": true,
450                         },
451                 },
452         }
453
454         for _, tc := range tests {
455                 t.Run(tc.name, func(t *testing.T) {
456                         res := TransitivelyDetectedGroups(tc.groups)
457                         testutil.AssertEqual(t, "res", res, tc.exp)
458                 })
459         }
460 }