sigs.k8s.io/cluster-api@v1.7.1/internal/apis/core/v1alpha3/conversion_test.go (about)

     1  /*
     2  Copyright 2020 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 v1alpha3
    18  
    19  import (
    20  	"testing"
    21  
    22  	fuzz "github.com/google/gofuzz"
    23  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    24  	"k8s.io/apimachinery/pkg/api/apitesting/fuzzer"
    25  	runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
    26  	"sigs.k8s.io/controller-runtime/pkg/conversion"
    27  
    28  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    29  	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
    30  )
    31  
    32  func TestFuzzyConversion(t *testing.T) {
    33  	t.Run("for Cluster", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{
    34  		Hub:                &clusterv1.Cluster{},
    35  		Spoke:              &Cluster{},
    36  		SpokeAfterMutation: clusterSpokeAfterMutation,
    37  		FuzzerFuncs:        []fuzzer.FuzzerFuncs{ClusterJSONFuzzFuncs},
    38  	}))
    39  
    40  	t.Run("for Machine", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{
    41  		Hub:         &clusterv1.Machine{},
    42  		Spoke:       &Machine{},
    43  		FuzzerFuncs: []fuzzer.FuzzerFuncs{BootstrapFuzzFuncs, MachineStatusFuzzFunc},
    44  	}))
    45  
    46  	t.Run("for MachineSet", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{
    47  		Hub:         &clusterv1.MachineSet{},
    48  		Spoke:       &MachineSet{},
    49  		FuzzerFuncs: []fuzzer.FuzzerFuncs{BootstrapFuzzFuncs, CustomObjectMetaFuzzFunc},
    50  	}))
    51  
    52  	t.Run("for MachineDeployment", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{
    53  		Hub:         &clusterv1.MachineDeployment{},
    54  		Spoke:       &MachineDeployment{},
    55  		FuzzerFuncs: []fuzzer.FuzzerFuncs{BootstrapFuzzFuncs, CustomObjectMetaFuzzFunc},
    56  	}))
    57  
    58  	t.Run("for MachineHealthCheck", utilconversion.FuzzTestFunc(utilconversion.FuzzTestFuncInput{
    59  		Hub:   &clusterv1.MachineHealthCheck{},
    60  		Spoke: &MachineHealthCheck{},
    61  	}))
    62  }
    63  
    64  func MachineStatusFuzzFunc(_ runtimeserializer.CodecFactory) []interface{} {
    65  	return []interface{}{
    66  		MachineStatusFuzzer,
    67  	}
    68  }
    69  
    70  func MachineStatusFuzzer(in *MachineStatus, c fuzz.Continue) {
    71  	c.FuzzNoCustom(in)
    72  
    73  	// These fields have been removed in v1beta1
    74  	// data is going to be lost, so we're forcing zero values to avoid round trip errors.
    75  	in.Version = nil
    76  }
    77  
    78  func CustomObjectMetaFuzzFunc(_ runtimeserializer.CodecFactory) []interface{} {
    79  	return []interface{}{
    80  		CustomObjectMetaFuzzer,
    81  	}
    82  }
    83  
    84  func CustomObjectMetaFuzzer(in *ObjectMeta, c fuzz.Continue) {
    85  	c.FuzzNoCustom(in)
    86  
    87  	// These fields have been removed in v1alpha4
    88  	// data is going to be lost, so we're forcing zero values here.
    89  	in.Name = ""
    90  	in.GenerateName = ""
    91  	in.Namespace = ""
    92  	in.OwnerReferences = nil
    93  }
    94  
    95  func BootstrapFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} {
    96  	return []interface{}{
    97  		BootstrapFuzzer,
    98  	}
    99  }
   100  
   101  func BootstrapFuzzer(obj *Bootstrap, c fuzz.Continue) {
   102  	c.FuzzNoCustom(obj)
   103  
   104  	// Bootstrap.Data has been removed in v1alpha4, so setting it to nil in order to avoid v1alpha3 --> <hub> --> v1alpha3 round trip errors.
   105  	obj.Data = nil
   106  }
   107  
   108  // clusterSpokeAfterMutation modifies the spoke version of the Cluster such that it can pass an equality test in the
   109  // spoke-hub-spoke conversion scenario.
   110  func clusterSpokeAfterMutation(c conversion.Convertible) {
   111  	cluster := c.(*Cluster)
   112  
   113  	// Create a temporary 0-length slice using the same underlying array as cluster.Status.Conditions to avoid
   114  	// allocations.
   115  	tmp := cluster.Status.Conditions[:0]
   116  
   117  	for i := range cluster.Status.Conditions {
   118  		condition := cluster.Status.Conditions[i]
   119  
   120  		// Keep everything that is not ControlPlaneInitializedCondition
   121  		if condition.Type != ConditionType(clusterv1.ControlPlaneInitializedCondition) {
   122  			tmp = append(tmp, condition)
   123  		}
   124  	}
   125  
   126  	// Point cluster.Status.Conditions and our slice that does not have ControlPlaneInitializedCondition
   127  	cluster.Status.Conditions = tmp
   128  }
   129  
   130  func ClusterJSONFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} {
   131  	return []interface{}{
   132  		ClusterVariableFuzzer,
   133  	}
   134  }
   135  
   136  func ClusterVariableFuzzer(in *clusterv1.ClusterVariable, c fuzz.Continue) {
   137  	c.FuzzNoCustom(in)
   138  
   139  	// Not every random byte array is valid JSON, e.g. a string without `""`,so we're setting a valid value.
   140  	in.Value = apiextensionsv1.JSON{Raw: []byte("\"test-string\"")}
   141  }