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