// Copyright (C) 2021 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 // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package config import ( "fmt" "io/fs" "os" "reflect" "testing" "github.com/google/go-cmp/cmp" "ruderich.org/simon/safcm" ) func TestLoadTemplates(t *testing.T) { cwd, err := os.Getwd() if err != nil { t.Fatal(err) } defer os.Chdir(cwd) err = os.Chdir("../testdata/project") if err != nil { t.Fatal(err) } allHosts, err := LoadHosts() if err != nil { t.Fatal(err) } allGroups, err := LoadGroups(&Config{}, allHosts) if err != nil { t.Fatal(err) } host := "host1.example.org" groups, err := ResolveHostGroups(host, allGroups, []string{"detected_amd64", "detected_linux"}) if err != nil { t.Fatal(err) } tests := []struct { group string exp map[string]*safcm.File expErr error }{ { "empty", nil, nil, }, { "group", map[string]*safcm.File{ "/": { Path: "/", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc": { Path: "/etc", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc/.hidden": { Path: "/etc/.hidden", Mode: 0644, Uid: -1, Gid: -1, Data: []byte("..."), }, "/etc/motd": { Path: "/etc/motd", Mode: 0644, Uid: -1, Gid: -1, Data: []byte(`Welcome to Host ONE This is GNU/Linux host `), }, "/etc/rc.local": { Path: "/etc/rc.local", Mode: 0755, Uid: -1, Gid: -1, Data: []byte("#!/bin/sh\n"), }, "/etc/resolv.conf": { Path: "/etc/resolv.conf", Mode: 0644, Uid: -1, Gid: -1, Data: []byte("nameserver ::1\n"), }, "/etc/test": { Path: "/etc/test", Mode: fs.ModeSymlink | 0777, Uid: -1, Gid: -1, Data: []byte("doesnt-exist"), }, }, nil, }, { "templates-invalid-group", map[string]*safcm.File{ "/": { Path: "/", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc": { Path: "/etc", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc/motd": { Path: "/etc/motd", Mode: 0644, Uid: -1, Gid: -1, Data: []byte(` {{if .InGroup "invalid-group"}} ... {{end}} `), }, }, fmt.Errorf("templates-invalid-group/templates.yaml: template: templates-invalid-group/files/etc/motd:2:5: executing \"templates-invalid-group/files/etc/motd\" at <.InGroup>: error calling InGroup: group \"invalid-group\" does not exist"), }, { "templates-invalid-host", map[string]*safcm.File{ "/": { Path: "/", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc": { Path: "/etc", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc/motd": { Path: "/etc/motd", Mode: 0644, Uid: -1, Gid: -1, Data: []byte(` {{if .IsHost "invalid-host"}} ... {{end}} `), }, }, fmt.Errorf("templates-invalid-host/templates.yaml: template: templates-invalid-host/files/etc/motd:2:5: executing \"templates-invalid-host/files/etc/motd\" at <.IsHost>: error calling IsHost: host \"invalid-host\" does not exist"), }, { "templates-invalid-path", nil, fmt.Errorf("templates-invalid-path/templates.yaml: \"/etc/motd\" does not exist in files/"), }, { "templates-invalid-template", map[string]*safcm.File{ "/": { Path: "/", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc": { Path: "/etc", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc/motd": { Path: "/etc/motd", Mode: 0644, Uid: -1, Gid: -1, Data: []byte("{{\n"), }, }, fmt.Errorf("templates-invalid-template/templates.yaml: invalid template: templates-invalid-template/files/etc/motd:2: unclosed action started at templates-invalid-template/files/etc/motd:1"), }, { "templates-invalid-type", map[string]*safcm.File{ "/": { Path: "/", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc": { Path: "/etc", Mode: fs.ModeDir | 0755, Uid: -1, Gid: -1, }, "/etc/motd": { Path: "/etc/motd", Mode: 0644, Uid: -1, Gid: -1, Data: []byte{}, }, }, fmt.Errorf("templates-invalid-type/templates.yaml: \"/etc\" is not a regular file"), }, } for _, tc := range tests { t.Run(tc.group, func(t *testing.T) { // Use LoadFiles() so we work on real data and don't make any // mistakes generating it files, err := LoadFiles(tc.group) if err != nil { t.Fatalf("err = %#v, want nil", err) } err = LoadTemplates(tc.group, files, host, groups, allHosts, allGroups) if !reflect.DeepEqual(tc.exp, files) { t.Errorf("res: %s", cmp.Diff(tc.exp, files)) } // Ugly but the simplest way to compare errors (including nil) if fmt.Sprintf("%s", err) != fmt.Sprintf("%s", tc.expErr) { t.Errorf("err = %#v, want %#v", err, tc.expErr) } }) } }