sigs.k8s.io/cluster-api@v1.7.1/internal/util/ssa/matchers.go (about) 1 /* 2 Copyright 2023 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package ssa 18 19 import ( 20 "encoding/json" 21 "fmt" 22 23 "github.com/onsi/gomega/types" 24 "github.com/pkg/errors" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 27 "sigs.k8s.io/cluster-api/internal/contract" 28 ) 29 30 // MatchManagedFieldsEntry is a gomega Matcher to check if a ManagedFieldsEntry has the given name and operation. 31 func MatchManagedFieldsEntry(manager string, operation metav1.ManagedFieldsOperationType) types.GomegaMatcher { 32 return &managedFieldMatcher{ 33 manager: manager, 34 operation: operation, 35 } 36 } 37 38 type managedFieldMatcher struct { 39 manager string 40 operation metav1.ManagedFieldsOperationType 41 } 42 43 func (mf *managedFieldMatcher) Match(actual interface{}) (bool, error) { 44 managedFieldsEntry, ok := actual.(metav1.ManagedFieldsEntry) 45 if !ok { 46 return false, fmt.Errorf("expecting metav1.ManagedFieldsEntry got %T", actual) 47 } 48 49 return managedFieldsEntry.Manager == mf.manager && managedFieldsEntry.Operation == mf.operation, nil 50 } 51 52 func (mf *managedFieldMatcher) FailureMessage(actual interface{}) string { 53 managedFieldsEntry := actual.(metav1.ManagedFieldsEntry) 54 return fmt.Sprintf("Expected ManagedFieldsEntry to match Manager:%s and Operation:%s, got Manager:%s, Operation:%s", 55 mf.manager, mf.operation, managedFieldsEntry.Manager, managedFieldsEntry.Operation) 56 } 57 58 func (mf *managedFieldMatcher) NegatedFailureMessage(actual interface{}) string { 59 managedFieldsEntry := actual.(metav1.ManagedFieldsEntry) 60 return fmt.Sprintf("Expected ManagedFieldsEntry to not match Manager:%s and Operation:%s, got Manager:%s, Operation:%s", 61 mf.manager, mf.operation, managedFieldsEntry.Manager, managedFieldsEntry.Operation) 62 } 63 64 // MatchFieldOwnership is a gomega Matcher to check if path is owned by the given manager and operation. 65 // Note: The path has to be specified as is observed in managed fields. Example: to check if the labels are owned 66 // by the correct manager the correct way to pass the path is contract.Path{"f:metadata","f:labels"}. 67 func MatchFieldOwnership(manager string, operation metav1.ManagedFieldsOperationType, path contract.Path) types.GomegaMatcher { 68 return &fieldOwnershipMatcher{ 69 path: path, 70 manager: manager, 71 operation: operation, 72 } 73 } 74 75 type fieldOwnershipMatcher struct { 76 path contract.Path 77 manager string 78 operation metav1.ManagedFieldsOperationType 79 } 80 81 func (fom *fieldOwnershipMatcher) Match(actual interface{}) (bool, error) { 82 managedFields, ok := actual.([]metav1.ManagedFieldsEntry) 83 if !ok { 84 return false, fmt.Errorf("expecting []metav1.ManagedFieldsEntry got %T", actual) 85 } 86 for _, managedFieldsEntry := range managedFields { 87 if managedFieldsEntry.Manager == fom.manager && managedFieldsEntry.Operation == fom.operation { 88 fieldsV1 := map[string]interface{}{} 89 if err := json.Unmarshal(managedFieldsEntry.FieldsV1.Raw, &fieldsV1); err != nil { 90 return false, errors.Wrap(err, "failed to parse managedFieldsEntry.FieldsV1") 91 } 92 FilterIntent(&FilterIntentInput{ 93 Path: contract.Path{}, 94 Value: fieldsV1, 95 ShouldFilter: IsPathNotAllowed([]contract.Path{fom.path}), 96 }) 97 return len(fieldsV1) > 0, nil 98 } 99 } 100 return false, nil 101 } 102 103 func (fom *fieldOwnershipMatcher) FailureMessage(actual interface{}) string { 104 managedFields := actual.([]metav1.ManagedFieldsEntry) 105 return fmt.Sprintf("Expected Path %s to be owned by Manager:%s and Operation:%s, did not find correct ownership: %s", 106 fom.path, fom.manager, fom.operation, managedFields) 107 } 108 109 func (fom *fieldOwnershipMatcher) NegatedFailureMessage(actual interface{}) string { 110 managedFields := actual.([]metav1.ManagedFieldsEntry) 111 return fmt.Sprintf("Expected Path %s to not be owned by Manager:%s and Operation:%s, did not find correct ownership: %s", 112 fom.path, fom.manager, fom.operation, managedFields) 113 }