2e2562018f
include/contain/require take a list of names; parse the argument list so the second and later names are indexed too.
157 lines
5.5 KiB
Go
157 lines
5.5 KiB
Go
package impact
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func testIndex(t *testing.T) *Index {
|
|
t.Helper()
|
|
idx, err := BuildIndex("testdata/repo")
|
|
if err != nil {
|
|
t.Fatalf("BuildIndex: %v", err)
|
|
}
|
|
return idx
|
|
}
|
|
|
|
func resolvedHosts(t *testing.T, class string) []string {
|
|
t.Helper()
|
|
res := newClassResolver(testIndex(t), fixtureNodes()).resolve(class)
|
|
hosts := make([]string, 0, len(res.hosts))
|
|
for certname := range res.hosts {
|
|
hosts = append(hosts, certname)
|
|
}
|
|
return uniqueSorted(hosts)
|
|
}
|
|
|
|
func TestResolveThroughIncludeChain(t *testing.T) {
|
|
// profiles::leaf <- profiles::mid <- profiles::base <- two role classes.
|
|
if got, want := resolvedHosts(t, "profiles::leaf"), []string{"k8s1", "k8s2", "web1"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("profiles::leaf = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestResolveContainAndClassResource(t *testing.T) {
|
|
for _, class := range []string{"profiles::contained", "profiles::viaclass"} {
|
|
if got, want := resolvedHosts(t, class), []string{"k8s1", "k8s2", "web1"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("%s = %v, want %v", class, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResolveDefinedTypeUsage(t *testing.T) {
|
|
if got, want := resolvedHosts(t, "profiles::defined::thing"), []string{"k8s1", "k8s2", "web1"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("profiles::defined::thing = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestResolveTerminatesOnCycle(t *testing.T) {
|
|
// profiles::cycle::a and ::b include each other; ::a is pulled in by
|
|
// profiles::base, so the walk must reach the roles and stop.
|
|
if got, want := resolvedHosts(t, "profiles::cycle::b"), []string{"k8s1", "k8s2", "web1"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("profiles::cycle::b = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestResolveViaHieraIncludeOnly(t *testing.T) {
|
|
// The jellyfin module is applied by hiera_include in a role yaml and by
|
|
// nothing in any manifest — a .pp-only search would call it orphaned.
|
|
if got, want := resolvedHosts(t, "jellyfin"), []string{"web1"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("jellyfin = %v, want %v", got, want)
|
|
}
|
|
// One hop further in: jellyfin::install is only reachable through jellyfin.
|
|
if got, want := resolvedHosts(t, "jellyfin::install"), []string{"web1"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("jellyfin::install = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestResolveHieraIncludeFromVirtualHierarchy(t *testing.T) {
|
|
if got, want := resolvedHosts(t, "profiles::lldpd"), []string{"k8s1", "k8s2", "prox1"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("profiles::lldpd = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestResolveHonoursHieraExclude(t *testing.T) {
|
|
// common.yaml pulls basemod in for everyone; roles/infra/proxmox.yaml
|
|
// excludes it again, so the proxmox node drops out.
|
|
if got, want := resolvedHosts(t, "basemod"), []string{"bare1", "k8s1", "k8s2", "web1"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("basemod = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestResolveOrphanClass(t *testing.T) {
|
|
res := newClassResolver(testIndex(t), fixtureNodes()).resolve("orphanmod")
|
|
if !res.orphan {
|
|
t.Errorf("orphanmod should be orphaned, hosts = %v", res.hosts)
|
|
}
|
|
if len(res.hosts) != 0 {
|
|
t.Errorf("orphanmod reached %v", res.hosts)
|
|
}
|
|
}
|
|
|
|
func TestIndexIgnoresCommentedReferences(t *testing.T) {
|
|
if got := testIndex(t).IncludedBy("profiles::commented"); len(got) != 0 {
|
|
t.Errorf("a commented-out class name was indexed as a reference: %v", got)
|
|
}
|
|
}
|
|
|
|
func TestIndexAssetOwners(t *testing.T) {
|
|
idx := testIndex(t)
|
|
for _, asset := range []string{"profiles/leaf/x.erb", "profiles/leaf/y.txt"} {
|
|
if got, want := idx.AssetOwners(asset), []string{"profiles::leaf"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("AssetOwners(%q) = %v, want %v", asset, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIndexModuleClasses(t *testing.T) {
|
|
got := testIndex(t).ModuleClasses("jellyfin")
|
|
want := []string{"jellyfin", "jellyfin::init", "jellyfin::install"}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Errorf("ModuleClasses(jellyfin) = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseHieraListsRegexFallback(t *testing.T) {
|
|
// eyaml payloads a strict parser rejects still have to yield their lists.
|
|
broken := []byte("---\nhiera_include:\n - alpha\n - beta\nhiera_exclude:\n - gamma\nbad: [unclosed\n")
|
|
include, exclude := parseHieraLists(broken)
|
|
if !reflect.DeepEqual(include, []string{"alpha", "beta"}) {
|
|
t.Errorf("include = %v", include)
|
|
}
|
|
if !reflect.DeepEqual(exclude, []string{"gamma"}) {
|
|
t.Errorf("exclude = %v", exclude)
|
|
}
|
|
}
|
|
|
|
func TestResolveInheritsScopeVarCreateResourcesAndInlineDefine(t *testing.T) {
|
|
// Four reference forms a plain include grep misses: class inheritance,
|
|
// a $class::var read, create_resources() naming a type in a string, and a
|
|
// defined type declared part-way along a line.
|
|
tests := map[string]string{
|
|
"inherits": "profiles::inherited",
|
|
"scope variable": "profiles::scopevar",
|
|
"create_resources": "profiles::created",
|
|
"inline define": "profiles::inline::thing",
|
|
}
|
|
want := []string{"k8s1", "k8s2", "web1"}
|
|
for name, class := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
if got := resolvedHosts(t, class); !reflect.DeepEqual(got, want) {
|
|
t.Errorf("%s = %v, want %v", class, got, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResolveEveryNameInAnIncludeList(t *testing.T) {
|
|
// profiles::base pulls both classes in with one comma-separated include;
|
|
// the second name must not be dropped.
|
|
want := []string{"k8s1", "k8s2", "web1"}
|
|
for _, class := range []string{"profiles::listed::a", "profiles::listed::b"} {
|
|
if got := resolvedHosts(t, class); !reflect.DeepEqual(got, want) {
|
|
t.Errorf("%s = %v, want %v", class, got, want)
|
|
}
|
|
}
|
|
}
|