...

Source file src/k8s.io/component-base/config/testing/roundtrip.go

Documentation: k8s.io/component-base/config/testing

     1  /*
     2  Copyright 2019 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 testing
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"testing"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/apimachinery/pkg/runtime/schema"
    29  	"k8s.io/apimachinery/pkg/runtime/serializer"
    30  )
    31  
    32  // RoundTripTest runs roundtrip tests for given scheme
    33  func RoundTripTest(t *testing.T, scheme *runtime.Scheme, codecs serializer.CodecFactory) {
    34  	tc := GetRoundtripTestCases(t, scheme, codecs)
    35  	RunTestsOnYAMLData(t, tc)
    36  }
    37  
    38  // GetRoundtripTestCases returns the testcases for roundtrip testing for given scheme
    39  func GetRoundtripTestCases(t *testing.T, scheme *runtime.Scheme, codecs serializer.CodecFactory) []TestCase {
    40  	cases := []TestCase{}
    41  	versionsForKind := map[schema.GroupKind][]string{}
    42  	for gvk := range scheme.AllKnownTypes() {
    43  		if gvk.Version != runtime.APIVersionInternal {
    44  			versionsForKind[gvk.GroupKind()] = append(versionsForKind[gvk.GroupKind()], gvk.Version)
    45  		}
    46  	}
    47  
    48  	for gk, versions := range versionsForKind {
    49  		testdir := filepath.Join("testdata", gk.Kind, "roundtrip")
    50  		dirs, err := os.ReadDir(testdir)
    51  		if err != nil {
    52  			t.Fatalf("failed to read testdir %s: %v", testdir, err)
    53  		}
    54  
    55  		for _, dir := range dirs {
    56  			for _, vin := range versions {
    57  				for _, vout := range versions {
    58  					marshalGVK := gk.WithVersion(vout)
    59  					codec, err := getCodecForGV(codecs, marshalGVK.GroupVersion())
    60  					if err != nil {
    61  						t.Fatalf("failed to get codec for %v: %v", marshalGVK.GroupVersion().String(), err)
    62  					}
    63  
    64  					testname := dir.Name()
    65  					cases = append(cases, TestCase{
    66  						name:  fmt.Sprintf("%s_%sTo%s_%s", gk.Kind, vin, vout, testname),
    67  						in:    filepath.Join(testdir, testname, vin+".yaml"),
    68  						out:   filepath.Join(testdir, testname, vout+".yaml"),
    69  						codec: codec,
    70  					})
    71  				}
    72  			}
    73  		}
    74  	}
    75  	return cases
    76  }
    77  
    78  func roundTrip(t *testing.T, tc TestCase) {
    79  	object := decodeYAML(t, tc.in, tc.codec)
    80  
    81  	// original object of internal type
    82  	original := object
    83  
    84  	// encode (serialize) the object using the provided codec
    85  	data, err := runtime.Encode(tc.codec, object)
    86  	if err != nil {
    87  		t.Fatalf("failed to encode object: %v", err)
    88  	}
    89  
    90  	// ensure that the encoding should not alter the object
    91  	if !apiequality.Semantic.DeepEqual(original, object) {
    92  		t.Fatalf("encode altered the object, diff (- want, + got): \n%v", cmp.Diff(original, object))
    93  	}
    94  
    95  	// decode (deserialize) the encoded data back into an object
    96  	obj2, err := runtime.Decode(tc.codec, data)
    97  	if err != nil {
    98  		t.Fatalf("failed to decode: %v", err)
    99  	}
   100  
   101  	// ensure that the object produced from decoding the encoded data is equal
   102  	// to the original object
   103  	if !apiequality.Semantic.DeepEqual(original, obj2) {
   104  		t.Fatalf("object was not the same after roundtrip, diff (- want, + got):\n%v", cmp.Diff(object, obj2))
   105  	}
   106  
   107  	// match with the input file, checks if they're the same after roundtrip
   108  	matchOutputFile(t, data, tc.out)
   109  }
   110  

View as plain text