crossplane
610 строк · 15.4 Кб
1/*
2Copyright 2023 The Crossplane Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package xrd18
19import (20"context"21"testing"22
23"github.com/google/go-cmp/cmp"24"github.com/google/go-cmp/cmp/cmpopts"25extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"26kerrors "k8s.io/apimachinery/pkg/api/errors"27"k8s.io/apimachinery/pkg/runtime"28"k8s.io/apimachinery/pkg/runtime/schema"29"k8s.io/apimachinery/pkg/util/validation/field"30"sigs.k8s.io/controller-runtime/pkg/client"31"sigs.k8s.io/controller-runtime/pkg/webhook/admission"32
33"github.com/crossplane/crossplane-runtime/pkg/errors"34"github.com/crossplane/crossplane-runtime/pkg/fieldpath"35"github.com/crossplane/crossplane-runtime/pkg/test"36
37v1 "github.com/crossplane/crossplane/apis/apiextensions/v1"38)
39
40var _ admission.CustomValidator = &validator{}41
42func TestValidateUpdate(t *testing.T) {43errBoom := errors.New("boom")44
45type args struct {46old runtime.Object47new *v1.CompositeResourceDefinition48client client.Client49}50cases := map[string]struct {51args
52warns admission.Warnings53err error54}{55"UnexpectedType": {56args: args{57old: &extv1.CustomResourceDefinition{},58new: &v1.CompositeResourceDefinition{},59},60err: errors.New(errUnexpectedType),61},62"SuccessNoClaimCreate": {63args: args{64old: &v1.CompositeResourceDefinition{65Spec: v1.CompositeResourceDefinitionSpec{66Names: extv1.CustomResourceDefinitionNames{67Kind: "a",68},69},70},71new: &v1.CompositeResourceDefinition{72Spec: v1.CompositeResourceDefinitionSpec{73Names: extv1.CustomResourceDefinitionNames{74Kind: "a",75},76},77},78client: &test.MockClient{79MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, "")),80MockCreate: test.NewMockCreateFn(nil),81},82},83},84"SuccessWithClaimCreate": {85args: args{86old: &v1.CompositeResourceDefinition{87Spec: v1.CompositeResourceDefinitionSpec{88Names: extv1.CustomResourceDefinitionNames{89Kind: "A",90Plural: "as",91Singular: "a",92ListKind: "AList",93},94ClaimNames: &extv1.CustomResourceDefinitionNames{95Kind: "B",96Plural: "bs",97Singular: "b",98ListKind: "BList",99},100},101},102new: &v1.CompositeResourceDefinition{103Spec: v1.CompositeResourceDefinitionSpec{104Names: extv1.CustomResourceDefinitionNames{105Kind: "A",106Plural: "as",107Singular: "a",108ListKind: "AList",109},110ClaimNames: &extv1.CustomResourceDefinitionNames{111Kind: "B",112Plural: "bs",113Singular: "b",114ListKind: "BList",115},116},117},118client: &test.MockClient{119MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, "")),120MockCreate: test.NewMockCreateFn(nil),121},122},123},124
125"SuccessNoClaimUpdate": {126args: args{127old: &v1.CompositeResourceDefinition{128Spec: v1.CompositeResourceDefinitionSpec{129Names: extv1.CustomResourceDefinitionNames{130Kind: "a",131},132},133},134new: &v1.CompositeResourceDefinition{135Spec: v1.CompositeResourceDefinitionSpec{136Names: extv1.CustomResourceDefinitionNames{137Kind: "a",138},139},140},141client: &test.MockClient{142MockGet: test.NewMockGetFn(nil),143MockUpdate: test.NewMockUpdateFn(nil),144},145},146},147"SuccessWithClaimUpdate": {148args: args{149old: &v1.CompositeResourceDefinition{150Spec: v1.CompositeResourceDefinitionSpec{151Names: extv1.CustomResourceDefinitionNames{152Kind: "A",153Plural: "as",154Singular: "a",155ListKind: "AList",156},157ClaimNames: &extv1.CustomResourceDefinitionNames{158Kind: "B",159Plural: "bs",160Singular: "b",161ListKind: "BList",162},163},164},165new: &v1.CompositeResourceDefinition{166Spec: v1.CompositeResourceDefinitionSpec{167Names: extv1.CustomResourceDefinitionNames{168Kind: "A",169Plural: "as",170Singular: "a",171ListKind: "AList",172},173ClaimNames: &extv1.CustomResourceDefinitionNames{174Kind: "B",175Plural: "bs",176Singular: "b",177ListKind: "BList",178},179},180},181client: &test.MockClient{182MockGet: test.NewMockGetFn(nil),183MockUpdate: test.NewMockUpdateFn(nil),184},185},186},187"FailChangeClaimKind": {188args: args{189old: &v1.CompositeResourceDefinition{190Spec: v1.CompositeResourceDefinitionSpec{191Names: extv1.CustomResourceDefinitionNames{192Kind: "A",193Plural: "as",194Singular: "a",195ListKind: "AList",196},197ClaimNames: &extv1.CustomResourceDefinitionNames{198Kind: "B",199Plural: "bs",200Singular: "b",201ListKind: "BList",202},203},204},205new: &v1.CompositeResourceDefinition{206Spec: v1.CompositeResourceDefinitionSpec{207Names: extv1.CustomResourceDefinitionNames{208Kind: "A",209Plural: "as",210Singular: "a",211ListKind: "AList",212},213ClaimNames: &extv1.CustomResourceDefinitionNames{214Kind: "C",215Plural: "cs",216Singular: "c",217ListKind: "CList",218},219},220},221client: &test.MockClient{222MockGet: test.NewMockGetFn(nil),223MockUpdate: test.NewMockUpdateFn(nil),224},225},226// WARN: brittle test, depends on the sorting of the field.ErrorList227err: field.ErrorList{228field.Invalid(field.NewPath("spec", "claimNames", "plural"), "cs", "field is immutable"),229field.Invalid(field.NewPath("spec", "claimNames", "kind"), "C", "field is immutable"),230}.ToAggregate(),231},232"FailOnClaimNotFound": {233args: args{234old: &v1.CompositeResourceDefinition{235Spec: v1.CompositeResourceDefinitionSpec{236Names: extv1.CustomResourceDefinitionNames{237Kind: "A",238Plural: "as",239Singular: "a",240ListKind: "AList",241},242ClaimNames: &extv1.CustomResourceDefinitionNames{243Kind: "B",244Plural: "bs",245Singular: "b",246ListKind: "BList",247},248},249},250new: &v1.CompositeResourceDefinition{251Spec: v1.CompositeResourceDefinitionSpec{252Names: extv1.CustomResourceDefinitionNames{253Kind: "A",254Plural: "as",255Singular: "a",256ListKind: "AList",257},258ClaimNames: &extv1.CustomResourceDefinitionNames{259Kind: "B",260Plural: "bs",261Singular: "b",262ListKind: "BList",263},264},265},266client: &test.MockClient{267MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, "")),268MockCreate: test.NewMockCreateFn(nil, func(obj client.Object) error {269p, err := fieldpath.PaveObject(obj)270if err != nil {271return err272}273s, err := p.GetString("spec.names.kind")274if err != nil {275return err276}277if s == "B" {278return errBoom279}280return nil281}),282},283},284err: errBoom,285},286"FailOnClaimFound": {287args: args{288old: &v1.CompositeResourceDefinition{289Spec: v1.CompositeResourceDefinitionSpec{290Names: extv1.CustomResourceDefinitionNames{291Kind: "A",292Plural: "as",293Singular: "a",294ListKind: "AList",295},296ClaimNames: &extv1.CustomResourceDefinitionNames{297Kind: "B",298Plural: "bs",299Singular: "b",300ListKind: "BList",301},302},303},304new: &v1.CompositeResourceDefinition{305Spec: v1.CompositeResourceDefinitionSpec{306Names: extv1.CustomResourceDefinitionNames{307Kind: "A",308Plural: "as",309Singular: "a",310ListKind: "AList",311},312ClaimNames: &extv1.CustomResourceDefinitionNames{313Kind: "B",314Plural: "bs",315Singular: "b",316ListKind: "BList",317},318},319},320client: &test.MockClient{321MockGet: test.NewMockGetFn(nil),322MockUpdate: test.NewMockUpdateFn(nil, func(obj client.Object) error {323p, err := fieldpath.PaveObject(obj)324if err != nil {325return err326}327s, err := p.GetString("spec.names.kind")328if err != nil {329return err330}331if s == "B" {332return errBoom333}334return nil335}),336},337},338err: errBoom,339},340"FailOnCompositeNotFound": {341args: args{342old: &v1.CompositeResourceDefinition{343Spec: v1.CompositeResourceDefinitionSpec{344Names: extv1.CustomResourceDefinitionNames{345Kind: "A",346Plural: "as",347Singular: "a",348ListKind: "AList",349},350ClaimNames: &extv1.CustomResourceDefinitionNames{351Kind: "B",352Plural: "bs",353Singular: "b",354ListKind: "BList",355},356},357},358new: &v1.CompositeResourceDefinition{359Spec: v1.CompositeResourceDefinitionSpec{360Names: extv1.CustomResourceDefinitionNames{361Kind: "A",362Plural: "as",363Singular: "a",364ListKind: "AList",365},366ClaimNames: &extv1.CustomResourceDefinitionNames{367Kind: "B",368Plural: "bs",369Singular: "b",370ListKind: "BList",371},372},373},374client: &test.MockClient{375MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, "")),376MockCreate: test.NewMockCreateFn(nil, func(obj client.Object) error {377p, err := fieldpath.PaveObject(obj)378if err != nil {379return err380}381s, err := p.GetString("spec.names.kind")382if err != nil {383return err384}385if s == "A" {386return errBoom387}388return nil389}),390},391},392err: errBoom,393},394"FailOnCompositeFound": {395args: args{396old: &v1.CompositeResourceDefinition{397Spec: v1.CompositeResourceDefinitionSpec{398Names: extv1.CustomResourceDefinitionNames{399Kind: "A",400Plural: "as",401Singular: "a",402ListKind: "AList",403},404ClaimNames: &extv1.CustomResourceDefinitionNames{405Kind: "B",406Plural: "bs",407Singular: "b",408ListKind: "BList",409},410},411},412new: &v1.CompositeResourceDefinition{413Spec: v1.CompositeResourceDefinitionSpec{414Names: extv1.CustomResourceDefinitionNames{415Kind: "A",416Plural: "as",417Singular: "a",418ListKind: "AList",419},420ClaimNames: &extv1.CustomResourceDefinitionNames{421Kind: "B",422Plural: "bs",423Singular: "b",424ListKind: "BList",425},426},427},428client: &test.MockClient{429MockGet: test.NewMockGetFn(nil),430MockUpdate: test.NewMockUpdateFn(nil, func(obj client.Object) error {431p, err := fieldpath.PaveObject(obj)432if err != nil {433return err434}435s, err := p.GetString("spec.names.kind")436if err != nil {437return err438}439if s == "A" {440return errBoom441}442return nil443}),444},445},446err: errBoom,447},448}449
450for name, tc := range cases {451t.Run(name, func(t *testing.T) {452handler := &validator{453client: tc.client,454}455warns, err := handler.ValidateUpdate(context.TODO(), tc.old, tc.new)456if diff := cmp.Diff(tc.warns, warns); diff != "" {457t.Errorf("ValidateUpdate(): -want warnings, +got warnings:\n%s", diff)458}459if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {460if d := cmp.Diff(tc.err, err, cmpopts.EquateErrors()); d != "" {461t.Errorf("ValidateUpdate(): -want error, +got error:\n%s", diff)462}463}464})465}466}
467
468func TestValidateCreate(t *testing.T) {469type args struct {470obj *v1.CompositeResourceDefinition471client client.Client472}473errBoom := errors.New("boom")474cases := map[string]struct {475args
476warns admission.Warnings477err error478}{479"SuccessNoClaim": {480args: args{481obj: &v1.CompositeResourceDefinition{482Spec: v1.CompositeResourceDefinitionSpec{483Names: extv1.CustomResourceDefinitionNames{484Kind: "a",485},486},487},488client: &test.MockClient{489MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, "")),490MockCreate: test.NewMockCreateFn(nil),491},492},493},494"SuccessWithClaim": {495args: args{496obj: &v1.CompositeResourceDefinition{497Spec: v1.CompositeResourceDefinitionSpec{498Names: extv1.CustomResourceDefinitionNames{499Kind: "A",500Plural: "as",501Singular: "a",502ListKind: "AList",503},504ClaimNames: &extv1.CustomResourceDefinitionNames{505Kind: "B",506Plural: "bs",507Singular: "b",508ListKind: "BList",509},510},511},512client: &test.MockClient{513MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, "")),514MockCreate: test.NewMockCreateFn(nil),515},516},517},518"FailOnClaim": {519args: args{520obj: &v1.CompositeResourceDefinition{521Spec: v1.CompositeResourceDefinitionSpec{522Names: extv1.CustomResourceDefinitionNames{523Kind: "A",524Plural: "as",525Singular: "a",526ListKind: "AList",527},528ClaimNames: &extv1.CustomResourceDefinitionNames{529Kind: "B",530Plural: "bs",531Singular: "b",532ListKind: "BList",533},534},535},536client: &test.MockClient{537MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, "")),538MockCreate: test.NewMockCreateFn(nil, func(obj client.Object) error {539p, err := fieldpath.PaveObject(obj)540if err != nil {541return err542}543s, err := p.GetString("spec.names.kind")544if err != nil {545return err546}547if s == "B" {548return errBoom549}550return nil551}),552},553},554err: errBoom,555},556"FailOnComposite": {557args: args{558obj: &v1.CompositeResourceDefinition{559Spec: v1.CompositeResourceDefinitionSpec{560Names: extv1.CustomResourceDefinitionNames{561Kind: "A",562Plural: "as",563Singular: "a",564ListKind: "AList",565},566ClaimNames: &extv1.CustomResourceDefinitionNames{567Kind: "B",568Plural: "bs",569Singular: "b",570ListKind: "BList",571},572},573},574client: &test.MockClient{575MockGet: test.NewMockGetFn(kerrors.NewNotFound(schema.GroupResource{}, "")),576MockCreate: test.NewMockCreateFn(nil, func(obj client.Object) error {577p, err := fieldpath.PaveObject(obj)578if err != nil {579return err580}581s, err := p.GetString("spec.names.kind")582if err != nil {583return err584}585if s == "A" {586return errBoom587}588return nil589}),590},591},592err: errBoom,593},594}595
596for name, tc := range cases {597t.Run(name, func(t *testing.T) {598handler := &validator{599client: tc.client,600}601warns, err := handler.ValidateCreate(context.TODO(), tc.obj)602if diff := cmp.Diff(tc.warns, warns); diff != "" {603t.Errorf("ValidateUpdate(): -want warnings, +got warnings:\n%s", diff)604}605if diff := cmp.Diff(tc.err, err, cmpopts.EquateErrors()); diff != "" {606t.Errorf("ValidateUpdate(): -want error, +got error:\n%s", diff)607}608})609}610}
611