istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/labels/instance_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package labels_test
    16  
    17  import (
    18  	"testing"
    19  
    20  	"istio.io/istio/pkg/config/labels"
    21  	"istio.io/istio/pkg/test/util/assert"
    22  )
    23  
    24  func TestInstance(t *testing.T) {
    25  	type result struct {
    26  		subsetOf bool
    27  		selected bool
    28  	}
    29  
    30  	cases := []struct {
    31  		left     labels.Instance
    32  		right    labels.Instance
    33  		expected result
    34  	}{
    35  		{
    36  			left:     nil,
    37  			right:    labels.Instance{"app": "a"},
    38  			expected: result{true, false},
    39  		},
    40  		{
    41  			left:     labels.Instance{},
    42  			right:    labels.Instance{"app": "a"},
    43  			expected: result{true, false},
    44  		},
    45  		{
    46  			left:     labels.Instance{"app": "a"},
    47  			right:    nil,
    48  			expected: result{false, false},
    49  		},
    50  		{
    51  			left:     labels.Instance{"app": "a"},
    52  			right:    labels.Instance{"app": "a", "prod": "env"},
    53  			expected: result{true, true},
    54  		},
    55  		{
    56  			left:     labels.Instance{"app": "a", "prod": "env"},
    57  			right:    labels.Instance{"app": "a"},
    58  			expected: result{false, false},
    59  		},
    60  		{
    61  			left:     labels.Instance{"app": "a"},
    62  			right:    labels.Instance{"app": "b", "prod": "env"},
    63  			expected: result{false, false},
    64  		},
    65  		{
    66  			left:     labels.Instance{"foo": ""},
    67  			right:    labels.Instance{"app": "a"},
    68  			expected: result{false, false},
    69  		},
    70  		{
    71  			left:     labels.Instance{"foo": ""},
    72  			right:    labels.Instance{"app": "a", "foo": ""},
    73  			expected: result{true, true},
    74  		},
    75  		{
    76  			left:     labels.Instance{"app": "a", "foo": ""},
    77  			right:    labels.Instance{"foo": ""},
    78  			expected: result{false, false},
    79  		},
    80  	}
    81  	for _, c := range cases {
    82  		var got result
    83  		got.subsetOf = c.left.SubsetOf(c.right)
    84  		got.selected = c.left.Match(c.right)
    85  		if got != c.expected {
    86  			t.Errorf("%v.SubsetOf(%v) got %v, expected %v", c.left, c.right, got, c.expected)
    87  		}
    88  	}
    89  }
    90  
    91  func TestString(t *testing.T) {
    92  	cases := []struct {
    93  		input    labels.Instance
    94  		expected string
    95  	}{
    96  		{
    97  			input:    nil,
    98  			expected: "",
    99  		},
   100  		{
   101  			input:    labels.Instance{},
   102  			expected: "",
   103  		},
   104  		{
   105  			input:    labels.Instance{"app": "a"},
   106  			expected: "app=a",
   107  		},
   108  		{
   109  			input:    labels.Instance{"app": "a", "prod": "env"},
   110  			expected: "app=a,prod=env",
   111  		},
   112  		{
   113  			input:    labels.Instance{"foo": ""},
   114  			expected: "foo",
   115  		},
   116  		{
   117  			input:    labels.Instance{"app": "a", "foo": ""},
   118  			expected: "app=a,foo",
   119  		},
   120  	}
   121  	for _, tt := range cases {
   122  		t.Run(tt.expected, func(t *testing.T) {
   123  			assert.Equal(t, tt.input.String(), tt.expected)
   124  		})
   125  	}
   126  }
   127  
   128  func TestInstanceValidate(t *testing.T) {
   129  	cases := []struct {
   130  		name  string
   131  		tags  labels.Instance
   132  		valid bool
   133  	}{
   134  		{
   135  			name:  "empty tags",
   136  			valid: true,
   137  		},
   138  		{
   139  			name: "bad tag",
   140  			tags: labels.Instance{"^": "^"},
   141  		},
   142  		{
   143  			name:  "good tag",
   144  			tags:  labels.Instance{"key": "value"},
   145  			valid: true,
   146  		},
   147  		{
   148  			name:  "good tag - empty value",
   149  			tags:  labels.Instance{"key": ""},
   150  			valid: true,
   151  		},
   152  		{
   153  			name:  "good tag - DNS prefix",
   154  			tags:  labels.Instance{"k8s.io/key": "value"},
   155  			valid: true,
   156  		},
   157  		{
   158  			name:  "good tag - subdomain DNS prefix",
   159  			tags:  labels.Instance{"app.kubernetes.io/name": "value"},
   160  			valid: true,
   161  		},
   162  		{
   163  			name: "bad tag - empty key",
   164  			tags: labels.Instance{"": "value"},
   165  		},
   166  		{
   167  			name: "bad tag key 1",
   168  			tags: labels.Instance{".key": "value"},
   169  		},
   170  		{
   171  			name: "bad tag key 2",
   172  			tags: labels.Instance{"key_": "value"},
   173  		},
   174  		{
   175  			name: "bad tag key 3",
   176  			tags: labels.Instance{"key$": "value"},
   177  		},
   178  		{
   179  			name: "bad tag key - invalid DNS prefix",
   180  			tags: labels.Instance{"istio./key": "value"},
   181  		},
   182  		{
   183  			name: "bad tag value 1",
   184  			tags: labels.Instance{"key": ".value"},
   185  		},
   186  		{
   187  			name: "bad tag value 2",
   188  			tags: labels.Instance{"key": "value_"},
   189  		},
   190  		{
   191  			name: "bad tag value 3",
   192  			tags: labels.Instance{"key": "value$"},
   193  		},
   194  	}
   195  	for _, c := range cases {
   196  		if got := c.tags.Validate(); (got == nil) != c.valid {
   197  			t.Errorf("%s failed: got valid=%v but wanted valid=%v: %v", c.name, got == nil, c.valid, got)
   198  		}
   199  	}
   200  }
   201  
   202  func BenchmarkLabelString(b *testing.B) {
   203  	big := labels.Instance{}
   204  	for i := 0; i < 50; i++ {
   205  		big["topology.kubernetes.io/region"] = "some value"
   206  	}
   207  	small := labels.Instance{
   208  		"app": "foo",
   209  		"baz": "bar",
   210  	}
   211  	cases := []struct {
   212  		name  string
   213  		label labels.Instance
   214  	}{
   215  		{"small", small},
   216  		{"big", big},
   217  	}
   218  	for _, tt := range cases {
   219  		b.Run(tt.name, func(b *testing.B) {
   220  			for n := 0; n < b.N; n++ {
   221  				_ = tt.label.String()
   222  			}
   223  		})
   224  	}
   225  }