...

Source file src/k8s.io/kubectl/pkg/util/hash/hash_test.go

Documentation: k8s.io/kubectl/pkg/util/hash

     1  /*
     2  Copyright 2017 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 hash
    18  
    19  import (
    20  	"reflect"
    21  	"strings"
    22  	"testing"
    23  
    24  	"k8s.io/api/core/v1"
    25  )
    26  
    27  func TestConfigMapHash(t *testing.T) {
    28  	cases := []struct {
    29  		desc string
    30  		cm   *v1.ConfigMap
    31  		hash string
    32  		err  string
    33  	}{
    34  		// empty map
    35  		{"empty data", &v1.ConfigMap{Data: map[string]string{}, BinaryData: map[string][]byte{}}, "42745tchd9", ""},
    36  		// one key
    37  		{"one key", &v1.ConfigMap{Data: map[string]string{"one": ""}}, "9g67k2htb6", ""},
    38  		// three keys (tests sorting order)
    39  		{"three keys", &v1.ConfigMap{Data: map[string]string{"two": "2", "one": "", "three": "3"}}, "f5h7t85m9b", ""},
    40  		// empty binary data map
    41  		{"empty binary data", &v1.ConfigMap{BinaryData: map[string][]byte{}}, "dk855m5d49", ""},
    42  		// one key with binary data
    43  		{"one key with binary data", &v1.ConfigMap{BinaryData: map[string][]byte{"one": []byte("")}}, "mk79584b8c", ""},
    44  		// three keys with binary data (tests sorting order)
    45  		{"three keys with binary data", &v1.ConfigMap{BinaryData: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, "t458mc6db2", ""},
    46  		// two keys, one with string and another with binary data
    47  		{"two keys with one each", &v1.ConfigMap{Data: map[string]string{"one": ""}, BinaryData: map[string][]byte{"two": []byte("")}}, "698h7c7t9m", ""},
    48  	}
    49  
    50  	for _, c := range cases {
    51  		h, err := ConfigMapHash(c.cm)
    52  		if SkipRest(t, c.desc, err, c.err) {
    53  			continue
    54  		}
    55  		if c.hash != h {
    56  			t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
    57  		}
    58  	}
    59  }
    60  
    61  func TestSecretHash(t *testing.T) {
    62  	cases := []struct {
    63  		desc   string
    64  		secret *v1.Secret
    65  		hash   string
    66  		err    string
    67  	}{
    68  		// empty map
    69  		{"empty data", &v1.Secret{Type: "my-type", Data: map[string][]byte{}}, "t75bgf6ctb", ""},
    70  		// one key
    71  		{"one key", &v1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}}, "74bd68bm66", ""},
    72  		// three keys (tests sorting order)
    73  		{"three keys", &v1.Secret{Type: "my-type", Data: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, "dgcb6h9tmk", ""},
    74  	}
    75  
    76  	for _, c := range cases {
    77  		h, err := SecretHash(c.secret)
    78  		if SkipRest(t, c.desc, err, c.err) {
    79  			continue
    80  		}
    81  		if c.hash != h {
    82  			t.Errorf("case %q, expect hash %q but got %q", c.desc, c.hash, h)
    83  		}
    84  	}
    85  }
    86  
    87  func TestEncodeConfigMap(t *testing.T) {
    88  	cases := []struct {
    89  		desc   string
    90  		cm     *v1.ConfigMap
    91  		expect string
    92  		err    string
    93  	}{
    94  		// empty map
    95  		{"empty data", &v1.ConfigMap{Data: map[string]string{}}, `{"data":{},"kind":"ConfigMap","name":""}`, ""},
    96  		// one key
    97  		{"one key", &v1.ConfigMap{Data: map[string]string{"one": ""}}, `{"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
    98  		// three keys (tests sorting order)
    99  		{"three keys", &v1.ConfigMap{Data: map[string]string{"two": "2", "one": "", "three": "3"}}, `{"data":{"one":"","three":"3","two":"2"},"kind":"ConfigMap","name":""}`, ""},
   100  		// empty binary map
   101  		{"empty data", &v1.ConfigMap{BinaryData: map[string][]byte{}}, `{"data":null,"kind":"ConfigMap","name":""}`, ""},
   102  		// one key with binary data
   103  		{"one key", &v1.ConfigMap{BinaryData: map[string][]byte{"one": []byte("")}}, `{"binaryData":{"one":""},"data":null,"kind":"ConfigMap","name":""}`, ""},
   104  		// three keys with binary data (tests sorting order)
   105  		{"three keys", &v1.ConfigMap{BinaryData: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, `{"binaryData":{"one":"","three":"Mw==","two":"Mg=="},"data":null,"kind":"ConfigMap","name":""}`, ""},
   106  		// two keys, one string and one binary values
   107  		{"two keys with one each", &v1.ConfigMap{Data: map[string]string{"one": ""}, BinaryData: map[string][]byte{"two": []byte("")}}, `{"binaryData":{"two":""},"data":{"one":""},"kind":"ConfigMap","name":""}`, ""},
   108  	}
   109  	for _, c := range cases {
   110  		s, err := encodeConfigMap(c.cm)
   111  		if SkipRest(t, c.desc, err, c.err) {
   112  			continue
   113  		}
   114  		if s != c.expect {
   115  			t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.cm)
   116  		}
   117  	}
   118  }
   119  
   120  func TestEncodeSecret(t *testing.T) {
   121  	cases := []struct {
   122  		desc   string
   123  		secret *v1.Secret
   124  		expect string
   125  		err    string
   126  	}{
   127  		// empty map
   128  		{"empty data", &v1.Secret{Type: "my-type", Data: map[string][]byte{}}, `{"data":{},"kind":"Secret","name":"","type":"my-type"}`, ""},
   129  		// one key
   130  		{"one key", &v1.Secret{Type: "my-type", Data: map[string][]byte{"one": []byte("")}}, `{"data":{"one":""},"kind":"Secret","name":"","type":"my-type"}`, ""},
   131  		// three keys (tests sorting order) - note json.Marshal base64 encodes the values because they come in as []byte
   132  		{"three keys", &v1.Secret{Type: "my-type", Data: map[string][]byte{"two": []byte("2"), "one": []byte(""), "three": []byte("3")}}, `{"data":{"one":"","three":"Mw==","two":"Mg=="},"kind":"Secret","name":"","type":"my-type"}`, ""},
   133  	}
   134  	for _, c := range cases {
   135  		s, err := encodeSecret(c.secret)
   136  		if SkipRest(t, c.desc, err, c.err) {
   137  			continue
   138  		}
   139  		if s != c.expect {
   140  			t.Errorf("case %q, expect %q but got %q from encode %#v", c.desc, c.expect, s, c.secret)
   141  		}
   142  	}
   143  }
   144  
   145  func TestHash(t *testing.T) {
   146  	// hash the empty string to be sure that sha256 is being used
   147  	expect := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
   148  	sum := hash("")
   149  	if expect != sum {
   150  		t.Errorf("expected hash %q but got %q", expect, sum)
   151  	}
   152  }
   153  
   154  // warn devs who change types that they might have to update a hash function
   155  // not perfect, as it only checks the number of top-level fields
   156  func TestTypeStability(t *testing.T) {
   157  	errfmt := `case %q, expected %d fields but got %d
   158  Depending on the field(s) you added, you may need to modify the hash function for this type.
   159  To guide you: the hash function targets fields that comprise the contents of objects,
   160  not their metadata (e.g. the Data of a ConfigMap, but nothing in ObjectMeta).
   161  `
   162  	cases := []struct {
   163  		typeName string
   164  		obj      interface{}
   165  		expect   int
   166  	}{
   167  		{"ConfigMap", v1.ConfigMap{}, 5},
   168  		{"Secret", v1.Secret{}, 6},
   169  	}
   170  	for _, c := range cases {
   171  		val := reflect.ValueOf(c.obj)
   172  		if num := val.NumField(); c.expect != num {
   173  			t.Errorf(errfmt, c.typeName, c.expect, num)
   174  		}
   175  	}
   176  }
   177  
   178  // SkipRest returns true if there was a non-nil error or if we expected an error that didn't happen,
   179  // and logs the appropriate error on the test object.
   180  // The return value indicates whether we should skip the rest of the test case due to the error result.
   181  func SkipRest(t *testing.T, desc string, err error, contains string) bool {
   182  	if err != nil {
   183  		if len(contains) == 0 {
   184  			t.Errorf("case %q, expect nil error but got %q", desc, err.Error())
   185  		} else if !strings.Contains(err.Error(), contains) {
   186  			t.Errorf("case %q, expect error to contain %q but got %q", desc, contains, err.Error())
   187  		}
   188  		return true
   189  	} else if len(contains) > 0 {
   190  		t.Errorf("case %q, expect error to contain %q but got nil error", desc, contains)
   191  		return true
   192  	}
   193  	return false
   194  }
   195  

View as plain text