diff --git a/internal/utils/testdata/components-with-crds.yaml b/internal/utils/testdata/components-with-crds.yaml new file mode 100644 index 00000000..2b59143c --- /dev/null +++ b/internal/utils/testdata/components-with-crds.yaml @@ -0,0 +1,69 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: flux-system +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + name: alerts.notification.toolkit.fluxcd.io +spec: + group: notification.toolkit.fluxcd.io + names: + kind: Alert + listKind: AlertList + plural: alerts + singular: alert + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + name: buckets.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: Bucket + listKind: BucketList + plural: buckets + singular: bucket + scope: Namespaced + versions: + - name: v1beta1 + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kustomize-controller + namespace: flux-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: notification-controller + namespace: flux-system diff --git a/internal/utils/testdata/components-without-crds.yaml b/internal/utils/testdata/components-without-crds.yaml new file mode 100644 index 00000000..d95f31d7 --- /dev/null +++ b/internal/utils/testdata/components-without-crds.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: flux-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kustomize-controller + namespace: flux-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: notification-controller + namespace: flux-system diff --git a/internal/utils/utils.go b/internal/utils/utils.go index f37249c1..2299562a 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -223,11 +223,7 @@ func ParseObjectKindName(input string) (kind, name string) { // ParseObjectKindNameNamespace extracts the kind, name and namespace of a resource // based on the '/.' format func ParseObjectKindNameNamespace(input string) (kind, name, namespace string) { - name = input - parts := strings.Split(input, "/") - if len(parts) == 2 { - kind, name = parts[0], parts[1] - } + kind, name = ParseObjectKindName(input) if nn := strings.Split(name, "."); len(nn) > 1 { name = strings.Join(nn[:len(nn)-1], ".") diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go index b4ed6eb4..f316e8cd 100644 --- a/internal/utils/utils_test.go +++ b/internal/utils/utils_test.go @@ -16,7 +16,15 @@ limitations under the License. package utils -import "testing" +import ( + "io/ioutil" + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/fluxcd/pkg/runtime/dependency" +) func TestCompatibleVersion(t *testing.T) { tests := []struct { @@ -40,3 +48,103 @@ func TestCompatibleVersion(t *testing.T) { }) } } + +func TestParseObjectKindNameNamespace(t *testing.T) { + tests := []struct { + name string + input string + wantKind string + wantName string + wantNamespace string + }{ + {"with kind name namespace", "Kustomization/foo.flux-system", "Kustomization", "foo", "flux-system"}, + {"without namespace", "Kustomization/foo", "Kustomization", "foo", ""}, + {"name with dots", "Kustomization/foo.bar.flux-system", "Kustomization", "foo.bar", "flux-system"}, + {"multiple slashes", "foo/bar/baz", "", "foo/bar/baz", ""}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotKind, gotName, gotNamespace := ParseObjectKindNameNamespace(tt.input) + if gotKind != tt.wantKind { + t.Errorf("kind = %s, want %s", gotKind, tt.wantKind) + } + if gotName != tt.wantName { + t.Errorf("name = %s, want %s", gotName, tt.wantName) + } + if gotNamespace != tt.wantNamespace { + t.Errorf("namespace = %s, want %s", gotNamespace, tt.wantNamespace) + } + }) + } +} + +func TestMakeDependsOn(t *testing.T) { + input := []string{ + "someNSA/someNameA", + "someNSB/someNameB", + "someNameC", + "someNSD/", + "", + } + want := []dependency.CrossNamespaceDependencyReference{ + {Namespace: "someNSA", Name: "someNameA"}, + {Namespace: "someNSB", Name: "someNameB"}, + {Namespace: "", Name: "someNameC"}, + {Namespace: "someNSD", Name: ""}, + {Namespace: "", Name: ""}, + } + + got := MakeDependsOn(input) + if !reflect.DeepEqual(got, want) { + t.Errorf("MakeDependsOn() = %v, want %v", got, want) + } +} + +func TestValidateComponents(t *testing.T) { + tests := []struct { + name string + input []string + expectErr bool + }{ + {"default and extra components", []string{"source-controller", "image-reflector-controller"}, false}, + {"unknown components", []string{"some-comp-1", "some-comp-2"}, true}, + {"mix of default and unknown", []string{"source-controller", "some-comp-1"}, true}, + {"empty", []string{}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidateComponents(tt.input); (err != nil) != tt.expectErr { + t.Errorf("ValidateComponents() error = %v, expectErr %v", err, tt.expectErr) + } + }) + } +} + +func TestExtractCRDs(t *testing.T) { + tests := []struct { + name string + inManifestFile string + expectErr bool + }{ + {"with crds", "components-with-crds.yaml", false}, + {"without crds", "components-without-crds.yaml", true}, + {"non-existent file", "non-existent-file.yaml", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create temporary directory to write the result in. + dir, err := ioutil.TempDir("", "flux-TestExtractCRDs") + if err != nil { + t.Fatalf("failed to create temporary directory: %v", err) + } + defer os.RemoveAll(dir) + + outManifestPath := filepath.Join(dir, "crds.yaml") + inManifestPath := filepath.Join("testdata", tt.inManifestFile) + if err = ExtractCRDs(inManifestPath, outManifestPath); (err != nil) != tt.expectErr { + t.Errorf("ExtractCRDs() error = %v, expectErr %v", err, tt.expectErr) + } + }) + } +}