sigs.k8s.io/cluster-api@v1.7.1/bootstrap/kubeadm/types/upstreamv1beta3/bootstraptokenstring_test.go (about)

     1  /*
     2  Copyright 2021 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 upstreamv1beta3
    18  
    19  import (
    20  	"encoding/json"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/pkg/errors"
    25  )
    26  
    27  func TestMarshalJSON(t *testing.T) {
    28  	var tests = []struct {
    29  		bts      BootstrapTokenString
    30  		expected string
    31  	}{
    32  		{BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, `"abcdef.abcdef0123456789"`},
    33  		{BootstrapTokenString{ID: "foo", Secret: "bar"}, `"foo.bar"`},
    34  		{BootstrapTokenString{ID: "h", Secret: "b"}, `"h.b"`},
    35  	}
    36  	for _, rt := range tests {
    37  		t.Run(rt.bts.ID, func(t *testing.T) {
    38  			b, err := json.Marshal(rt.bts)
    39  			if err != nil {
    40  				t.Fatalf("json.Marshal returned an unexpected error: %v", err)
    41  			}
    42  			if string(b) != rt.expected {
    43  				t.Errorf(
    44  					"failed BootstrapTokenString.MarshalJSON:\n\texpected: %s\n\t  actual: %s",
    45  					rt.expected,
    46  					string(b),
    47  				)
    48  			}
    49  		})
    50  	}
    51  }
    52  
    53  func TestUnmarshalJSON(t *testing.T) {
    54  	var tests = []struct {
    55  		input         string
    56  		bts           *BootstrapTokenString
    57  		expectedError bool
    58  	}{
    59  		{`"f.s"`, &BootstrapTokenString{}, true},
    60  		{`"abcdef."`, &BootstrapTokenString{}, true},
    61  		{`"abcdef:abcdef0123456789"`, &BootstrapTokenString{}, true},
    62  		{`abcdef.abcdef0123456789`, &BootstrapTokenString{}, true},
    63  		{`"abcdef.abcdef0123456789`, &BootstrapTokenString{}, true},
    64  		{`"abcdef.ABCDEF0123456789"`, &BootstrapTokenString{}, true},
    65  		{`"abcdef.abcdef0123456789"`, &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, false},
    66  		{`"123456.aabbccddeeffgghh"`, &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}, false},
    67  	}
    68  	for _, rt := range tests {
    69  		t.Run(rt.input, func(t *testing.T) {
    70  			newbts := &BootstrapTokenString{}
    71  			err := json.Unmarshal([]byte(rt.input), newbts)
    72  			if (err != nil) != rt.expectedError {
    73  				t.Errorf("failed BootstrapTokenString.UnmarshalJSON:\n\texpected error: %t\n\t  actual error: %v", rt.expectedError, err)
    74  			} else if diff := cmp.Diff(rt.bts, newbts); diff != "" {
    75  				t.Errorf(
    76  					"failed BootstrapTokenString.UnmarshalJSON:\n\texpected: %v\n\t  actual: %v\n\t diff: %v",
    77  					rt.bts,
    78  					newbts,
    79  					diff,
    80  				)
    81  			}
    82  		})
    83  	}
    84  }
    85  
    86  func TestJSONRoundtrip(t *testing.T) {
    87  	var tests = []struct {
    88  		input string
    89  		bts   *BootstrapTokenString
    90  	}{
    91  		{`"abcdef.abcdef0123456789"`, nil},
    92  		{"", &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}},
    93  	}
    94  	for _, rt := range tests {
    95  		t.Run(rt.input, func(t *testing.T) {
    96  			if err := roundtrip(rt.input, rt.bts); err != nil {
    97  				t.Errorf("failed BootstrapTokenString JSON roundtrip with error: %v", err)
    98  			}
    99  		})
   100  	}
   101  }
   102  
   103  func roundtrip(input string, bts *BootstrapTokenString) error {
   104  	var b []byte
   105  	var err error
   106  	newbts := &BootstrapTokenString{}
   107  	// If string input was specified, roundtrip like this: string -> (unmarshal) -> object -> (marshal) -> string
   108  	if input != "" {
   109  		if err := json.Unmarshal([]byte(input), newbts); err != nil {
   110  			return errors.Wrap(err, "expected no unmarshal error, got error")
   111  		}
   112  		if b, err = json.Marshal(newbts); err != nil {
   113  			return errors.Wrap(err, "expected no marshal error, got error")
   114  		}
   115  		if input != string(b) {
   116  			return errors.Errorf(
   117  				"expected token: %s\n\t  actual: %s",
   118  				input,
   119  				string(b),
   120  			)
   121  		}
   122  	} else { // Otherwise, roundtrip like this: object -> (marshal) -> string -> (unmarshal) -> object
   123  		if b, err = json.Marshal(bts); err != nil {
   124  			return errors.Wrap(err, "expected no marshal error, got error")
   125  		}
   126  		if err := json.Unmarshal(b, newbts); err != nil {
   127  			return errors.Wrap(err, "expected no unmarshal error, got error")
   128  		}
   129  		if diff := cmp.Diff(bts, newbts); diff != "" {
   130  			return errors.Errorf(
   131  				"expected object: %v\n\t  actual: %v\n\t got diff: %v",
   132  				bts,
   133  				newbts,
   134  				diff,
   135  			)
   136  		}
   137  	}
   138  	return nil
   139  }
   140  
   141  func TestTokenFromIDAndSecret(t *testing.T) {
   142  	var tests = []struct {
   143  		bts      BootstrapTokenString
   144  		expected string
   145  	}{
   146  		{BootstrapTokenString{ID: "foo", Secret: "bar"}, "foo.bar"},
   147  		{BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}, "abcdef.abcdef0123456789"},
   148  		{BootstrapTokenString{ID: "h", Secret: "b"}, "h.b"},
   149  	}
   150  	for _, rt := range tests {
   151  		t.Run(rt.bts.ID, func(t *testing.T) {
   152  			actual := rt.bts.String()
   153  			if actual != rt.expected {
   154  				t.Errorf(
   155  					"failed BootstrapTokenString.String():\n\texpected: %s\n\t  actual: %s",
   156  					rt.expected,
   157  					actual,
   158  				)
   159  			}
   160  		})
   161  	}
   162  }
   163  
   164  func TestNewBootstrapTokenString(t *testing.T) {
   165  	var tests = []struct {
   166  		token         string
   167  		expectedError bool
   168  		bts           *BootstrapTokenString
   169  	}{
   170  		{token: "", expectedError: true, bts: nil},
   171  		{token: ".", expectedError: true, bts: nil},
   172  		{token: "1234567890123456789012", expectedError: true, bts: nil},   // invalid parcel size
   173  		{token: "12345.1234567890123456", expectedError: true, bts: nil},   // invalid parcel size
   174  		{token: ".1234567890123456", expectedError: true, bts: nil},        // invalid parcel size
   175  		{token: "123456.", expectedError: true, bts: nil},                  // invalid parcel size
   176  		{token: "123456:1234567890.123456", expectedError: true, bts: nil}, // invalid separation
   177  		{token: "abcdef:1234567890123456", expectedError: true, bts: nil},  // invalid separation
   178  		{token: "Abcdef.1234567890123456", expectedError: true, bts: nil},  // invalid token id
   179  		{token: "123456.AABBCCDDEEFFGGHH", expectedError: true, bts: nil},  // invalid token secret
   180  		{token: "123456.AABBCCD-EEFFGGHH", expectedError: true, bts: nil},  // invalid character
   181  		{token: "abc*ef.1234567890123456", expectedError: true, bts: nil},  // invalid character
   182  		{token: "abcdef.1234567890123456", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "1234567890123456"}},
   183  		{token: "123456.aabbccddeeffgghh", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}},
   184  		{token: "abcdef.abcdef0123456789", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}},
   185  		{token: "123456.1234560123456789", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "1234560123456789"}},
   186  	}
   187  	for _, rt := range tests {
   188  		t.Run(rt.token, func(t *testing.T) {
   189  			actual, err := NewBootstrapTokenString(rt.token)
   190  			if (err != nil) != rt.expectedError {
   191  				t.Errorf(
   192  					"failed NewBootstrapTokenString for the token %q\n\texpected error: %t\n\t  actual error: %v",
   193  					rt.token,
   194  					rt.expectedError,
   195  					err,
   196  				)
   197  			} else if diff := cmp.Diff(actual, rt.bts); diff != "" {
   198  				t.Errorf(
   199  					"failed NewBootstrapTokenString for the token %q\n\texpected: %v\n\t  actual: %v\n\t diff: %v",
   200  					rt.token,
   201  					rt.bts,
   202  					actual,
   203  					diff,
   204  				)
   205  			}
   206  		})
   207  	}
   208  }
   209  
   210  func TestNewBootstrapTokenStringFromIDAndSecret(t *testing.T) {
   211  	var tests = []struct {
   212  		id, secret    string
   213  		expectedError bool
   214  		bts           *BootstrapTokenString
   215  	}{
   216  		{id: "", secret: "", expectedError: true, bts: nil},
   217  		{id: "1234567890123456789012", secret: "", expectedError: true, bts: nil}, // invalid parcel size
   218  		{id: "12345", secret: "1234567890123456", expectedError: true, bts: nil},  // invalid parcel size
   219  		{id: "", secret: "1234567890123456", expectedError: true, bts: nil},       // invalid parcel size
   220  		{id: "123456", secret: "", expectedError: true, bts: nil},                 // invalid parcel size
   221  		{id: "Abcdef", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid token id
   222  		{id: "123456", secret: "AABBCCDDEEFFGGHH", expectedError: true, bts: nil}, // invalid token secret
   223  		{id: "123456", secret: "AABBCCD-EEFFGGHH", expectedError: true, bts: nil}, // invalid character
   224  		{id: "abc*ef", secret: "1234567890123456", expectedError: true, bts: nil}, // invalid character
   225  		{id: "abcdef", secret: "1234567890123456", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "1234567890123456"}},
   226  		{id: "123456", secret: "aabbccddeeffgghh", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "aabbccddeeffgghh"}},
   227  		{id: "abcdef", secret: "abcdef0123456789", expectedError: false, bts: &BootstrapTokenString{ID: "abcdef", Secret: "abcdef0123456789"}},
   228  		{id: "123456", secret: "1234560123456789", expectedError: false, bts: &BootstrapTokenString{ID: "123456", Secret: "1234560123456789"}},
   229  	}
   230  	for _, rt := range tests {
   231  		t.Run(rt.id, func(t *testing.T) {
   232  			actual, err := NewBootstrapTokenStringFromIDAndSecret(rt.id, rt.secret)
   233  			if (err != nil) != rt.expectedError {
   234  				t.Errorf(
   235  					"failed NewBootstrapTokenStringFromIDAndSecret for the token with id %q and secret %q\n\texpected error: %t\n\t  actual error: %v",
   236  					rt.id,
   237  					rt.secret,
   238  					rt.expectedError,
   239  					err,
   240  				)
   241  			} else if diff := cmp.Diff(actual, rt.bts); diff != "" {
   242  				t.Errorf(
   243  					"failed NewBootstrapTokenStringFromIDAndSecret for the token with id %q and secret %q\n\texpected: %v\n\t  actual: %v\n\t diff: %v",
   244  					rt.id,
   245  					rt.secret,
   246  					rt.bts,
   247  					actual,
   248  					diff,
   249  				)
   250  			}
   251  		})
   252  	}
   253  }