...

Source file src/k8s.io/apimachinery/pkg/util/validation/validation_test.go

Documentation: k8s.io/apimachinery/pkg/util/validation

     1  /*
     2  Copyright 2014 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 validation
    18  
    19  import (
    20  	"strings"
    21  	"testing"
    22  
    23  	"k8s.io/apimachinery/pkg/util/validation/field"
    24  )
    25  
    26  func TestIsDNS1123Label(t *testing.T) {
    27  	goodValues := []string{
    28  		"a", "ab", "abc", "a1", "a-1", "a--1--2--b",
    29  		"0", "01", "012", "1a", "1-a", "1--a--b--2",
    30  		strings.Repeat("a", 63),
    31  	}
    32  	for _, val := range goodValues {
    33  		if msgs := IsDNS1123Label(val); len(msgs) != 0 {
    34  			t.Errorf("expected true for '%s': %v", val, msgs)
    35  		}
    36  	}
    37  
    38  	badValues := []string{
    39  		"", "A", "ABC", "aBc", "A1", "A-1", "1-A",
    40  		"-", "a-", "-a", "1-", "-1",
    41  		"_", "a_", "_a", "a_b", "1_", "_1", "1_2",
    42  		".", "a.", ".a", "a.b", "1.", ".1", "1.2",
    43  		" ", "a ", " a", "a b", "1 ", " 1", "1 2",
    44  		strings.Repeat("a", 64),
    45  	}
    46  	for _, val := range badValues {
    47  		if msgs := IsDNS1123Label(val); len(msgs) == 0 {
    48  			t.Errorf("expected false for '%s'", val)
    49  		}
    50  	}
    51  }
    52  
    53  func TestIsDNS1123Subdomain(t *testing.T) {
    54  	goodValues := []string{
    55  		"a", "ab", "abc", "a1", "a-1", "a--1--2--b",
    56  		"0", "01", "012", "1a", "1-a", "1--a--b--2",
    57  		"a.a", "ab.a", "abc.a", "a1.a", "a-1.a", "a--1--2--b.a",
    58  		"a.1", "ab.1", "abc.1", "a1.1", "a-1.1", "a--1--2--b.1",
    59  		"0.a", "01.a", "012.a", "1a.a", "1-a.a", "1--a--b--2",
    60  		"0.1", "01.1", "012.1", "1a.1", "1-a.1", "1--a--b--2.1",
    61  		"a.b.c.d.e", "aa.bb.cc.dd.ee", "1.2.3.4.5", "11.22.33.44.55",
    62  		strings.Repeat("a", 253),
    63  	}
    64  	for _, val := range goodValues {
    65  		if msgs := IsDNS1123Subdomain(val); len(msgs) != 0 {
    66  			t.Errorf("expected true for '%s': %v", val, msgs)
    67  		}
    68  	}
    69  
    70  	badValues := []string{
    71  		"", "A", "ABC", "aBc", "A1", "A-1", "1-A",
    72  		"-", "a-", "-a", "1-", "-1",
    73  		"_", "a_", "_a", "a_b", "1_", "_1", "1_2",
    74  		".", "a.", ".a", "a..b", "1.", ".1", "1..2",
    75  		" ", "a ", " a", "a b", "1 ", " 1", "1 2",
    76  		"A.a", "aB.a", "ab.A", "A1.a", "a1.A",
    77  		"A.1", "aB.1", "A1.1", "1A.1",
    78  		"0.A", "01.A", "012.A", "1A.a", "1a.A",
    79  		"A.B.C.D.E", "AA.BB.CC.DD.EE", "a.B.c.d.e", "aa.bB.cc.dd.ee",
    80  		"a@b", "a,b", "a_b", "a;b",
    81  		"a:b", "a%b", "a?b", "a$b",
    82  		strings.Repeat("a", 254),
    83  	}
    84  	for _, val := range badValues {
    85  		if msgs := IsDNS1123Subdomain(val); len(msgs) == 0 {
    86  			t.Errorf("expected false for '%s'", val)
    87  		}
    88  	}
    89  }
    90  
    91  func TestIsDNS1035Label(t *testing.T) {
    92  	goodValues := []string{
    93  		"a", "ab", "abc", "a1", "a-1", "a--1--2--b",
    94  		strings.Repeat("a", 63),
    95  	}
    96  	for _, val := range goodValues {
    97  		if msgs := IsDNS1035Label(val); len(msgs) != 0 {
    98  			t.Errorf("expected true for '%s': %v", val, msgs)
    99  		}
   100  	}
   101  
   102  	badValues := []string{
   103  		"0", "01", "012", "1a", "1-a", "1--a--b--2",
   104  		"", "A", "ABC", "aBc", "A1", "A-1", "1-A",
   105  		"-", "a-", "-a", "1-", "-1",
   106  		"_", "a_", "_a", "a_b", "1_", "_1", "1_2",
   107  		".", "a.", ".a", "a.b", "1.", ".1", "1.2",
   108  		" ", "a ", " a", "a b", "1 ", " 1", "1 2",
   109  		strings.Repeat("a", 64),
   110  	}
   111  	for _, val := range badValues {
   112  		if msgs := IsDNS1035Label(val); len(msgs) == 0 {
   113  			t.Errorf("expected false for '%s'", val)
   114  		}
   115  	}
   116  }
   117  
   118  func TestIsCIdentifier(t *testing.T) {
   119  	goodValues := []string{
   120  		"a", "ab", "abc", "a1", "_a", "a_", "a_b", "a_1", "a__1__2__b", "__abc_123",
   121  		"A", "AB", "AbC", "A1", "_A", "A_", "A_B", "A_1", "A__1__2__B", "__123_ABC",
   122  	}
   123  	for _, val := range goodValues {
   124  		if msgs := IsCIdentifier(val); len(msgs) != 0 {
   125  			t.Errorf("expected true for '%s': %v", val, msgs)
   126  		}
   127  	}
   128  
   129  	badValues := []string{
   130  		"", "1", "123", "1a",
   131  		"-", "a-", "-a", "1-", "-1", "1_", "1_2",
   132  		".", "a.", ".a", "a.b", "1.", ".1", "1.2",
   133  		" ", "a ", " a", "a b", "1 ", " 1", "1 2",
   134  		"#a#",
   135  	}
   136  	for _, val := range badValues {
   137  		if msgs := IsCIdentifier(val); len(msgs) == 0 {
   138  			t.Errorf("expected false for '%s'", val)
   139  		}
   140  	}
   141  }
   142  
   143  func TestIsValidPortNum(t *testing.T) {
   144  	goodValues := []int{1, 2, 1000, 16384, 32768, 65535}
   145  	for _, val := range goodValues {
   146  		if msgs := IsValidPortNum(val); len(msgs) != 0 {
   147  			t.Errorf("expected true for %d, got %v", val, msgs)
   148  		}
   149  	}
   150  
   151  	badValues := []int{0, -1, 65536, 100000}
   152  	for _, val := range badValues {
   153  		if msgs := IsValidPortNum(val); len(msgs) == 0 {
   154  			t.Errorf("expected false for %d", val)
   155  		}
   156  	}
   157  }
   158  
   159  func TestIsInRange(t *testing.T) {
   160  	goodValues := []struct {
   161  		value int
   162  		min   int
   163  		max   int
   164  	}{{1, 0, 10}, {5, 5, 20}, {25, 10, 25}}
   165  	for _, val := range goodValues {
   166  		if msgs := IsInRange(val.value, val.min, val.max); len(msgs) > 0 {
   167  			t.Errorf("expected no errors for %#v, but got %v", val, msgs)
   168  		}
   169  	}
   170  
   171  	badValues := []struct {
   172  		value int
   173  		min   int
   174  		max   int
   175  	}{{1, 2, 10}, {5, -4, 2}, {25, 100, 120}}
   176  	for _, val := range badValues {
   177  		if msgs := IsInRange(val.value, val.min, val.max); len(msgs) == 0 {
   178  			t.Errorf("expected errors for %#v", val)
   179  		}
   180  	}
   181  }
   182  
   183  func createGroupIDs(ids ...int64) []int64 {
   184  	var output []int64
   185  	for _, id := range ids {
   186  		output = append(output, int64(id))
   187  	}
   188  	return output
   189  }
   190  
   191  func createUserIDs(ids ...int64) []int64 {
   192  	var output []int64
   193  	for _, id := range ids {
   194  		output = append(output, int64(id))
   195  	}
   196  	return output
   197  }
   198  
   199  func TestIsValidGroupID(t *testing.T) {
   200  	goodValues := createGroupIDs(0, 1, 1000, 65535, 2147483647)
   201  	for _, val := range goodValues {
   202  		if msgs := IsValidGroupID(val); len(msgs) != 0 {
   203  			t.Errorf("expected true for '%d': %v", val, msgs)
   204  		}
   205  	}
   206  
   207  	badValues := createGroupIDs(-1, -1003, 2147483648, 4147483647)
   208  	for _, val := range badValues {
   209  		if msgs := IsValidGroupID(val); len(msgs) == 0 {
   210  			t.Errorf("expected false for '%d'", val)
   211  		}
   212  	}
   213  }
   214  
   215  func TestIsValidUserID(t *testing.T) {
   216  	goodValues := createUserIDs(0, 1, 1000, 65535, 2147483647)
   217  	for _, val := range goodValues {
   218  		if msgs := IsValidUserID(val); len(msgs) != 0 {
   219  			t.Errorf("expected true for '%d': %v", val, msgs)
   220  		}
   221  	}
   222  
   223  	badValues := createUserIDs(-1, -1003, 2147483648, 4147483647)
   224  	for _, val := range badValues {
   225  		if msgs := IsValidUserID(val); len(msgs) == 0 {
   226  			t.Errorf("expected false for '%d'", val)
   227  		}
   228  	}
   229  }
   230  
   231  func TestIsValidPortName(t *testing.T) {
   232  	goodValues := []string{"telnet", "re-mail-ck", "pop3", "a", "a-1", "1-a", "a-1-b-2-c", "1-a-2-b-3"}
   233  	for _, val := range goodValues {
   234  		if msgs := IsValidPortName(val); len(msgs) != 0 {
   235  			t.Errorf("expected true for %q: %v", val, msgs)
   236  		}
   237  	}
   238  
   239  	badValues := []string{"longerthan15characters", "", strings.Repeat("a", 16), "12345", "1-2-3-4", "-begin", "end-", "two--hyphens", "whois++"}
   240  	for _, val := range badValues {
   241  		if msgs := IsValidPortName(val); len(msgs) == 0 {
   242  			t.Errorf("expected false for %q", val)
   243  		}
   244  	}
   245  }
   246  
   247  func TestIsQualifiedName(t *testing.T) {
   248  	successCases := []string{
   249  		"simple",
   250  		"now-with-dashes",
   251  		"1-starts-with-num",
   252  		"1234",
   253  		"simple/simple",
   254  		"now-with-dashes/simple",
   255  		"now-with-dashes/now-with-dashes",
   256  		"now.with.dots/simple",
   257  		"now-with.dashes-and.dots/simple",
   258  		"1-num.2-num/3-num",
   259  		"1234/5678",
   260  		"1.2.3.4/5678",
   261  		"Uppercase_Is_OK_123",
   262  		"example.com/Uppercase_Is_OK_123",
   263  		"requests.storage-foo",
   264  		strings.Repeat("a", 63),
   265  		strings.Repeat("a", 253) + "/" + strings.Repeat("b", 63),
   266  	}
   267  	for i := range successCases {
   268  		if errs := IsQualifiedName(successCases[i]); len(errs) != 0 {
   269  			t.Errorf("case[%d]: %q: expected success: %v", i, successCases[i], errs)
   270  		}
   271  	}
   272  
   273  	errorCases := []string{
   274  		"nospecialchars%^=@",
   275  		"cantendwithadash-",
   276  		"-cantstartwithadash-",
   277  		"only/one/slash",
   278  		"Example.com/abc",
   279  		"example_com/abc",
   280  		"example.com/",
   281  		"/simple",
   282  		strings.Repeat("a", 64),
   283  		strings.Repeat("a", 254) + "/abc",
   284  	}
   285  	for i := range errorCases {
   286  		if errs := IsQualifiedName(errorCases[i]); len(errs) == 0 {
   287  			t.Errorf("case[%d]: %q: expected failure", i, errorCases[i])
   288  		}
   289  	}
   290  }
   291  
   292  func TestIsValidLabelValue(t *testing.T) {
   293  	successCases := []string{
   294  		"simple",
   295  		"now-with-dashes",
   296  		"1-starts-with-num",
   297  		"end-with-num-1",
   298  		"1234",                  // only num
   299  		strings.Repeat("a", 63), // to the limit
   300  		"",                      // empty value
   301  	}
   302  	for i := range successCases {
   303  		if errs := IsValidLabelValue(successCases[i]); len(errs) != 0 {
   304  			t.Errorf("case %s expected success: %v", successCases[i], errs)
   305  		}
   306  	}
   307  
   308  	errorCases := []string{
   309  		"nospecialchars%^=@",
   310  		"Tama-nui-te-rā.is.Māori.sun",
   311  		"\\backslashes\\are\\bad",
   312  		"-starts-with-dash",
   313  		"ends-with-dash-",
   314  		".starts.with.dot",
   315  		"ends.with.dot.",
   316  		strings.Repeat("a", 64), // over the limit
   317  	}
   318  	for i := range errorCases {
   319  		if errs := IsValidLabelValue(errorCases[i]); len(errs) == 0 {
   320  			t.Errorf("case[%d] expected failure", i)
   321  		}
   322  	}
   323  }
   324  
   325  func TestIsValidIP(t *testing.T) {
   326  	for _, tc := range []struct {
   327  		name   string
   328  		in     string
   329  		family int
   330  		err    string
   331  	}{
   332  		// GOOD VALUES
   333  		{
   334  			name:   "ipv4",
   335  			in:     "1.2.3.4",
   336  			family: 4,
   337  		},
   338  		{
   339  			name:   "ipv4, all zeros",
   340  			in:     "0.0.0.0",
   341  			family: 4,
   342  		},
   343  		{
   344  			name:   "ipv4, max",
   345  			in:     "255.255.255.255",
   346  			family: 4,
   347  		},
   348  		{
   349  			name:   "ipv6",
   350  			in:     "1234::abcd",
   351  			family: 6,
   352  		},
   353  		{
   354  			name:   "ipv6, all zeros, collapsed",
   355  			in:     "::",
   356  			family: 6,
   357  		},
   358  		{
   359  			name:   "ipv6, max",
   360  			in:     "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
   361  			family: 6,
   362  		},
   363  
   364  		// GOOD, THOUGH NON-CANONICAL, VALUES
   365  		{
   366  			name:   "ipv6, all zeros, expanded (non-canonical)",
   367  			in:     "0:0:0:0:0:0:0:0",
   368  			family: 6,
   369  		},
   370  		{
   371  			name:   "ipv6, leading 0s (non-canonical)",
   372  			in:     "0001:002:03:4::",
   373  			family: 6,
   374  		},
   375  		{
   376  			name:   "ipv6, capital letters (non-canonical)",
   377  			in:     "1234::ABCD",
   378  			family: 6,
   379  		},
   380  
   381  		// BAD VALUES WE CURRENTLY CONSIDER GOOD
   382  		{
   383  			name:   "ipv4 with leading 0s",
   384  			in:     "1.1.1.01",
   385  			family: 4,
   386  		},
   387  		{
   388  			name:   "ipv4-in-ipv6 value",
   389  			in:     "::ffff:1.1.1.1",
   390  			family: 4,
   391  		},
   392  
   393  		// BAD VALUES
   394  		{
   395  			name: "empty string",
   396  			in:   "",
   397  			err:  "must be a valid IP address",
   398  		},
   399  		{
   400  			name: "junk",
   401  			in:   "aaaaaaa",
   402  			err:  "must be a valid IP address",
   403  		},
   404  		{
   405  			name: "domain name",
   406  			in:   "myhost.mydomain",
   407  			err:  "must be a valid IP address",
   408  		},
   409  		{
   410  			name: "cidr",
   411  			in:   "1.2.3.0/24",
   412  			err:  "must be a valid IP address",
   413  		},
   414  		{
   415  			name: "ipv4 with out-of-range octets",
   416  			in:   "1.2.3.400",
   417  			err:  "must be a valid IP address",
   418  		},
   419  		{
   420  			name: "ipv4 with negative octets",
   421  			in:   "-1.0.0.0",
   422  			err:  "must be a valid IP address",
   423  		},
   424  		{
   425  			name: "ipv6 with out-of-range segment",
   426  			in:   "2001:db8::10005",
   427  			err:  "must be a valid IP address",
   428  		},
   429  		{
   430  			name: "ipv4:port",
   431  			in:   "1.2.3.4:80",
   432  			err:  "must be a valid IP address",
   433  		},
   434  		{
   435  			name: "ipv6 with brackets",
   436  			in:   "[2001:db8::1]",
   437  			err:  "must be a valid IP address",
   438  		},
   439  		{
   440  			name: "[ipv6]:port",
   441  			in:   "[2001:db8::1]:80",
   442  			err:  "must be a valid IP address",
   443  		},
   444  		{
   445  			name: "host:port",
   446  			in:   "example.com:80",
   447  			err:  "must be a valid IP address",
   448  		},
   449  		{
   450  			name: "ipv6 with zone",
   451  			in:   "1234::abcd%eth0",
   452  			err:  "must be a valid IP address",
   453  		},
   454  		{
   455  			name: "ipv4 with zone",
   456  			in:   "169.254.0.0%eth0",
   457  			err:  "must be a valid IP address",
   458  		},
   459  	} {
   460  		t.Run(tc.name, func(t *testing.T) {
   461  			errs := IsValidIP(field.NewPath(""), tc.in)
   462  			if tc.err == "" {
   463  				if len(errs) != 0 {
   464  					t.Errorf("expected %q to be valid but got: %v", tc.in, errs)
   465  				}
   466  			} else {
   467  				if len(errs) != 1 {
   468  					t.Errorf("expected %q to have 1 error but got: %v", tc.in, errs)
   469  				} else if !strings.Contains(errs[0].Detail, tc.err) {
   470  					t.Errorf("expected error for %q to contain %q but got: %q", tc.in, tc.err, errs[0].Detail)
   471  				}
   472  			}
   473  
   474  			errs = IsValidIPv4Address(field.NewPath(""), tc.in)
   475  			if tc.family == 4 {
   476  				if len(errs) != 0 {
   477  					t.Errorf("expected %q to pass IsValidIPv4Address but got: %v", tc.in, errs)
   478  				}
   479  			} else {
   480  				if len(errs) == 0 {
   481  					t.Errorf("expected %q to fail IsValidIPv4Address", tc.in)
   482  				}
   483  			}
   484  
   485  			errs = IsValidIPv6Address(field.NewPath(""), tc.in)
   486  			if tc.family == 6 {
   487  				if len(errs) != 0 {
   488  					t.Errorf("expected %q to pass IsValidIPv6Address but got: %v", tc.in, errs)
   489  				}
   490  			} else {
   491  				if len(errs) == 0 {
   492  					t.Errorf("expected %q to fail IsValidIPv6Address", tc.in)
   493  				}
   494  			}
   495  		})
   496  	}
   497  }
   498  
   499  func TestIsValidCIDR(t *testing.T) {
   500  	for _, tc := range []struct {
   501  		name string
   502  		in   string
   503  		err  string
   504  	}{
   505  		// GOOD VALUES
   506  		{
   507  			name: "ipv4",
   508  			in:   "1.0.0.0/8",
   509  		},
   510  		{
   511  			name: "ipv4, all IPs",
   512  			in:   "0.0.0.0/0",
   513  		},
   514  		{
   515  			name: "ipv4, single IP",
   516  			in:   "1.1.1.1/32",
   517  		},
   518  		{
   519  			name: "ipv6",
   520  			in:   "2001:4860:4860::/48",
   521  		},
   522  		{
   523  			name: "ipv6, all IPs",
   524  			in:   "::/0",
   525  		},
   526  		{
   527  			name: "ipv6, single IP",
   528  			in:   "::1/128",
   529  		},
   530  
   531  		// GOOD, THOUGH NON-CANONICAL, VALUES
   532  		{
   533  			name: "ipv6, extra 0s (non-canonical)",
   534  			in:   "2a00:79e0:2:0::/64",
   535  		},
   536  		{
   537  			name: "ipv6, capital letters (non-canonical)",
   538  			in:   "2001:DB8::/64",
   539  		},
   540  
   541  		// BAD VALUES WE CURRENTLY CONSIDER GOOD
   542  		{
   543  			name: "ipv4 with leading 0s",
   544  			in:   "1.1.01.0/24",
   545  		},
   546  		{
   547  			name: "ipv4-in-ipv6 with ipv4-sized prefix",
   548  			in:   "::ffff:1.1.1.0/24",
   549  		},
   550  		{
   551  			name: "ipv4-in-ipv6 with ipv6-sized prefix",
   552  			in:   "::ffff:1.1.1.0/120",
   553  		},
   554  		{
   555  			name: "ipv4 with bits past prefix",
   556  			in:   "1.2.3.4/24",
   557  		},
   558  		{
   559  			name: "ipv6 with bits past prefix",
   560  			in:   "2001:db8::1/64",
   561  		},
   562  		{
   563  			name: "prefix length with leading 0s",
   564  			in:   "192.168.0.0/016",
   565  		},
   566  
   567  		// BAD VALUES
   568  		{
   569  			name: "empty string",
   570  			in:   "",
   571  			err:  "must be a valid CIDR value",
   572  		},
   573  		{
   574  			name: "junk",
   575  			in:   "aaaaaaa",
   576  			err:  "must be a valid CIDR value",
   577  		},
   578  		{
   579  			name: "IP address",
   580  			in:   "1.2.3.4",
   581  			err:  "must be a valid CIDR value",
   582  		},
   583  		{
   584  			name: "partial URL",
   585  			in:   "192.168.0.1/healthz",
   586  			err:  "must be a valid CIDR value",
   587  		},
   588  		{
   589  			name: "partial URL 2",
   590  			in:   "192.168.0.1/0/99",
   591  			err:  "must be a valid CIDR value",
   592  		},
   593  		{
   594  			name: "negative prefix length",
   595  			in:   "192.168.0.0/-16",
   596  			err:  "must be a valid CIDR value",
   597  		},
   598  		{
   599  			name: "prefix length with sign",
   600  			in:   "192.168.0.0/+16",
   601  			err:  "must be a valid CIDR value",
   602  		},
   603  	} {
   604  		t.Run(tc.name, func(t *testing.T) {
   605  			errs := IsValidCIDR(field.NewPath(""), tc.in)
   606  			if tc.err == "" {
   607  				if len(errs) != 0 {
   608  					t.Errorf("expected %q to be valid but got: %v", tc.in, errs)
   609  				}
   610  			} else {
   611  				if len(errs) != 1 {
   612  					t.Errorf("expected %q to have 1 error but got: %v", tc.in, errs)
   613  				} else if !strings.Contains(errs[0].Detail, tc.err) {
   614  					t.Errorf("expected error for %q to contain %q but got: %q", tc.in, tc.err, errs[0].Detail)
   615  				}
   616  			}
   617  		})
   618  	}
   619  }
   620  
   621  func TestIsHTTPHeaderName(t *testing.T) {
   622  	goodValues := []string{
   623  		// Common ones
   624  		"Accept-Encoding", "Host", "If-Modified-Since", "X-Forwarded-For",
   625  		// Weirdo, but still conforming names
   626  		"a", "ab", "abc", "a1", "-a", "a-", "a-b", "a-1", "a--1--2--b", "--abc-123",
   627  		"A", "AB", "AbC", "A1", "-A", "A-", "A-B", "A-1", "A--1--2--B", "--123-ABC",
   628  	}
   629  	for _, val := range goodValues {
   630  		if msgs := IsHTTPHeaderName(val); len(msgs) != 0 {
   631  			t.Errorf("expected true for '%s': %v", val, msgs)
   632  		}
   633  	}
   634  
   635  	badValues := []string{
   636  		"Host:", "X-Forwarded-For:", "X-@Home",
   637  		"", "_", "a_", "_a", "1_", "1_2", ".", "a.", ".a", "a.b", "1.", ".1", "1.2",
   638  		" ", "a ", " a", "a b", "1 ", " 1", "1 2", "#a#", "^", ",", ";", "=", "<",
   639  		"?", "@", "{",
   640  	}
   641  	for _, val := range badValues {
   642  		if msgs := IsHTTPHeaderName(val); len(msgs) == 0 {
   643  			t.Errorf("expected false for '%s'", val)
   644  		}
   645  	}
   646  }
   647  
   648  func TestIsValidPercent(t *testing.T) {
   649  	goodValues := []string{
   650  		"0%",
   651  		"00000%",
   652  		"1%",
   653  		"01%",
   654  		"99%",
   655  		"100%",
   656  		"101%",
   657  	}
   658  	for _, val := range goodValues {
   659  		if msgs := IsValidPercent(val); len(msgs) != 0 {
   660  			t.Errorf("expected true for %q: %v", val, msgs)
   661  		}
   662  	}
   663  
   664  	badValues := []string{
   665  		"",
   666  		"0",
   667  		"100",
   668  		"0.0%",
   669  		"99.9%",
   670  		"hundred",
   671  		" 1%",
   672  		"1% ",
   673  		"-0%",
   674  		"-1%",
   675  		"+1%",
   676  	}
   677  	for _, val := range badValues {
   678  		if msgs := IsValidPercent(val); len(msgs) == 0 {
   679  			t.Errorf("expected false for %q", val)
   680  		}
   681  	}
   682  }
   683  
   684  func TestIsConfigMapKey(t *testing.T) {
   685  	successCases := []string{
   686  		"a",
   687  		"good",
   688  		"good-good",
   689  		"still.good",
   690  		"this.is.also.good",
   691  		".so.is.this",
   692  		"THIS_IS_GOOD",
   693  		"so_is_this_17",
   694  	}
   695  
   696  	for i := range successCases {
   697  		if errs := IsConfigMapKey(successCases[i]); len(errs) != 0 {
   698  			t.Errorf("[%d] expected success: %v", i, errs)
   699  		}
   700  	}
   701  
   702  	failureCases := []string{
   703  		".",
   704  		"..",
   705  		"..bad",
   706  		"b*d",
   707  		"bad!&bad",
   708  	}
   709  
   710  	for i := range failureCases {
   711  		if errs := IsConfigMapKey(failureCases[i]); len(errs) == 0 {
   712  			t.Errorf("[%d] expected failure", i)
   713  		}
   714  	}
   715  }
   716  
   717  func TestIsWildcardDNS1123Subdomain(t *testing.T) {
   718  	goodValues := []string{
   719  		"*.example.com",
   720  		"*.bar.com",
   721  		"*.foo.bar.com",
   722  	}
   723  	for _, val := range goodValues {
   724  		if errs := IsWildcardDNS1123Subdomain(val); len(errs) != 0 {
   725  			t.Errorf("expected no errors for %q: %v", val, errs)
   726  		}
   727  	}
   728  
   729  	badValues := []string{
   730  		"*.*.bar.com",
   731  		"*.foo.*.com",
   732  		"*bar.com",
   733  		"f*.bar.com",
   734  		"*",
   735  	}
   736  	for _, val := range badValues {
   737  		if errs := IsWildcardDNS1123Subdomain(val); len(errs) == 0 {
   738  			t.Errorf("expected errors for %q", val)
   739  		}
   740  	}
   741  }
   742  
   743  func TestIsFullyQualifiedDomainName(t *testing.T) {
   744  	goodValues := []string{
   745  		"a.com",
   746  		"k8s.io",
   747  		"dev.k8s.io",
   748  		"dev.k8s.io.",
   749  		"foo.example.com",
   750  		"this.is.a.really.long.fqdn",
   751  		"bbc.co.uk",
   752  		"10.0.0.1", // DNS labels can start with numbers and there is no requirement for letters.
   753  		"hyphens-are-good.k8s.io",
   754  		strings.Repeat("a", 63) + ".k8s.io",
   755  		strings.Repeat("a", 63) + "." + strings.Repeat("b", 63) + "." + strings.Repeat("c", 63) + "." + strings.Repeat("d", 54) + ".k8s.io",
   756  	}
   757  	for _, val := range goodValues {
   758  		if err := IsFullyQualifiedDomainName(field.NewPath(""), val).ToAggregate(); err != nil {
   759  			t.Errorf("expected no errors for %q: %v", val, err)
   760  		}
   761  	}
   762  
   763  	badValues := []string{
   764  		".",
   765  		"...",
   766  		".io",
   767  		"com",
   768  		".com",
   769  		"Dev.k8s.io",
   770  		".foo.example.com",
   771  		"*.example.com",
   772  		"*.bar.com",
   773  		"*.foo.bar.com",
   774  		"underscores_are_bad.k8s.io",
   775  		"foo@bar.example.com",
   776  		"http://foo.example.com",
   777  		strings.Repeat("a", 64) + ".k8s.io",
   778  		strings.Repeat("a", 63) + "." + strings.Repeat("b", 63) + "." + strings.Repeat("c", 63) + "." + strings.Repeat("d", 55) + ".k8s.io",
   779  	}
   780  	for _, val := range badValues {
   781  		if err := IsFullyQualifiedDomainName(field.NewPath(""), val).ToAggregate(); err == nil {
   782  			t.Errorf("expected errors for %q", val)
   783  		}
   784  	}
   785  }
   786  
   787  func TestIsFullyQualifiedName(t *testing.T) {
   788  	goodValues := []string{
   789  		"dev.k8s.io",
   790  		"foo.example.com",
   791  		"this.is.a.really.long.fqdn",
   792  		"bbc.co.uk",
   793  		"10.0.0.1", // DNS labels can start with numbers and there is no requirement for letters.
   794  		"hyphens-are-good.k8s.io",
   795  		strings.Repeat("a", 246) + ".k8s.io",
   796  	}
   797  	for _, val := range goodValues {
   798  		if err := IsFullyQualifiedName(field.NewPath(""), val).ToAggregate(); err != nil {
   799  			t.Errorf("expected no errors for %q: %v", val, err)
   800  		}
   801  	}
   802  
   803  	badValues := []string{
   804  		"...",
   805  		"dev.k8s.io.",
   806  		".io",
   807  		"Dev.k8s.io",
   808  		"k8s.io",
   809  		"*.example.com",
   810  		"*.bar.com",
   811  		"*.foo.bar.com",
   812  		"underscores_are_bad.k8s.io",
   813  		"foo@bar.example.com",
   814  		"http://foo.example.com",
   815  		strings.Repeat("a", 247) + ".k8s.io",
   816  	}
   817  	for _, val := range badValues {
   818  		if err := IsFullyQualifiedName(field.NewPath(""), val).ToAggregate(); err == nil {
   819  			t.Errorf("expected errors for %q", val)
   820  		}
   821  	}
   822  
   823  	messageTests := []struct {
   824  		name       string
   825  		targetName string
   826  		err        string
   827  	}{{
   828  		name:       "name needs to be fully qualified, i.e., contains at least 2 dots",
   829  		targetName: "k8s.io",
   830  		err:        "should be a domain with at least three segments separated by dots",
   831  	}, {
   832  		name:       "name should not include scheme",
   833  		targetName: "http://foo.k8s.io",
   834  		err:        "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
   835  	}, {
   836  		name:       "email should be invalid",
   837  		targetName: "example@foo.k8s.io",
   838  		err:        "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
   839  	}, {
   840  		name:       "name cannot be empty",
   841  		targetName: "",
   842  		err:        "Required value",
   843  	}, {
   844  		name:       "name must conform to RFC 1123",
   845  		targetName: "A.B.C",
   846  		err:        "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters",
   847  	}}
   848  	for _, tc := range messageTests {
   849  		err := IsFullyQualifiedName(field.NewPath(""), tc.targetName).ToAggregate()
   850  		switch {
   851  		case tc.err == "" && err != nil:
   852  			t.Errorf("%q: unexpected error: %v", tc.name, err)
   853  		case tc.err != "" && err == nil:
   854  			t.Errorf("%q: unexpected no error, expected %s", tc.name, tc.err)
   855  		case tc.err != "" && err != nil && !strings.Contains(err.Error(), tc.err):
   856  			t.Errorf("%q: expected %s, got %v", tc.name, tc.err, err)
   857  		}
   858  	}
   859  }
   860  
   861  func TestIsDomainPrefixedPath(t *testing.T) {
   862  	goodValues := []string{
   863  		"a/b",
   864  		"a/b/c/d",
   865  		"a.com/foo",
   866  		"a.b.c.d/foo",
   867  		"k8s.io/foo/bar",
   868  		"k8s.io/FOO/BAR",
   869  		"dev.k8s.io/more/path",
   870  		"this.is.a.really.long.fqdn/even/longer/path/just/because",
   871  		"bbc.co.uk/path/goes/here",
   872  		"10.0.0.1/foo",
   873  		"hyphens-are-good.k8s.io/and-in-paths-too",
   874  		strings.Repeat("a", 240) + ".k8s.io/a",
   875  		"k8s.io/" + strings.Repeat("a", 240),
   876  	}
   877  	for _, val := range goodValues {
   878  		if err := IsDomainPrefixedPath(field.NewPath(""), val).ToAggregate(); err != nil {
   879  			t.Errorf("expected no errors for %q: %v", val, err)
   880  		}
   881  	}
   882  
   883  	badValues := []string{
   884  		".",
   885  		"...",
   886  		"/b",
   887  		"com",
   888  		".com",
   889  		"a.b.c.d/foo?a=b",
   890  		"a.b.c.d/foo#a",
   891  		"Dev.k8s.io",
   892  		".foo.example.com",
   893  		"*.example.com",
   894  		"example.com/foo{}[]@^`",
   895  		"underscores_are_bad.k8s.io",
   896  		"underscores_are_bad.k8s.io/foo",
   897  		"foo@bar.example.com",
   898  		"foo@bar.example.com/foo",
   899  		strings.Repeat("a", 247) + ".k8s.io",
   900  	}
   901  	for _, val := range badValues {
   902  		if err := IsDomainPrefixedPath(field.NewPath(""), val).ToAggregate(); err == nil {
   903  			t.Errorf("expected errors for %q", val)
   904  		}
   905  	}
   906  }
   907  
   908  func TestIsRelaxedEnvVarName(t *testing.T) {
   909  	goodValues := []string{
   910  		"-", ":", "_", "+a", ">a", "<a",
   911  		"a.", "a..", "*a", "%a", "?a",
   912  		"a:a", "a_a", "aAz", "~a", "|a",
   913  		"a0a", "a9", "/a", "a ", "#a",
   914  		"0a", "0 a", "'a", "(a", "@a",
   915  	}
   916  	for _, val := range goodValues {
   917  		if msgs := IsRelaxedEnvVarName(val); len(msgs) != 0 {
   918  			t.Errorf("expected true for '%s': %v", val, msgs)
   919  		}
   920  	}
   921  
   922  	badValues := []string{
   923  		"", "=", "a=", "1=a", "a=b", "#%=&&",
   924  		string(rune(1)) + "abc", string(rune(130)) + "abc",
   925  		"Ç ç", "Ä ä", "Ñ ñ", "Ø ø",
   926  	}
   927  
   928  	for _, val := range badValues {
   929  		if msgs := IsRelaxedEnvVarName(val); len(msgs) == 0 {
   930  			t.Errorf("expected false for '%s'", val)
   931  		}
   932  	}
   933  }
   934  

View as plain text