sigs.k8s.io/cluster-api@v1.6.3/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  }