1
// Copyright Istio Authors
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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.
23
"google.golang.org/protobuf/types/known/durationpb"
25
meshconfig "istio.io/api/mesh/v1alpha1"
26
"istio.io/api/networking/v1alpha3"
27
"istio.io/istio/pkg/model"
28
"istio.io/istio/pkg/test/util/assert"
31
func TestNodeMetadata(t *testing.T) {
34
in model.BootstrapNodeMetadata
36
inOut model.BootstrapNodeMetadata
40
model.BootstrapNodeMetadata{},
42
model.BootstrapNodeMetadata{NodeMetadata: model.NodeMetadata{Raw: map[string]any{}}},
46
model.BootstrapNodeMetadata{NodeMetadata: model.NodeMetadata{InstanceIPs: []string{"abc", "1.2.3.4"}}},
47
`{"INSTANCE_IPS":"abc,1.2.3.4"}`,
48
model.BootstrapNodeMetadata{
49
NodeMetadata: model.NodeMetadata{
50
InstanceIPs: []string{"abc", "1.2.3.4"},
52
"INSTANCE_IPS": "abc,1.2.3.4",
59
model.BootstrapNodeMetadata{NodeMetadata: model.NodeMetadata{Labels: map[string]string{"foo": "bar"}}},
60
`{"LABELS":{"foo":"bar"}}`,
61
model.BootstrapNodeMetadata{
62
NodeMetadata: model.NodeMetadata{
63
Labels: map[string]string{"foo": "bar"},
65
"LABELS": map[string]any{
74
model.BootstrapNodeMetadata{
75
NodeMetadata: model.NodeMetadata{
76
ProxyConfig: (*model.NodeMetaProxyConfig)(&meshconfig.ProxyConfig{
78
DrainDuration: durationpb.New(time.Second * 5),
79
ControlPlaneAuthPolicy: meshconfig.AuthenticationPolicy_MUTUAL_TLS,
80
EnvoyAccessLogService: &meshconfig.RemoteService{
82
TlsSettings: &v1alpha3.ClientTLSSettings{
83
SubjectAltNames: []string{"san"},
90
`{"PROXY_CONFIG":{"configPath":"foo","drainDuration":"5s","controlPlaneAuthPolicy":"MUTUAL_TLS","envoyAccessLogService":{"address":"address","tlsSettings":{"subjectAltNames":["san"]}}}}`,
91
model.BootstrapNodeMetadata{
92
NodeMetadata: model.NodeMetadata{
93
ProxyConfig: (*model.NodeMetaProxyConfig)(&meshconfig.ProxyConfig{
95
DrainDuration: durationpb.New(time.Second * 5),
96
ControlPlaneAuthPolicy: meshconfig.AuthenticationPolicy_MUTUAL_TLS,
97
EnvoyAccessLogService: &meshconfig.RemoteService{
99
TlsSettings: &v1alpha3.ClientTLSSettings{
100
SubjectAltNames: []string{"san"},
105
"PROXY_CONFIG": map[string]any{
106
"drainDuration": "5s",
108
"controlPlaneAuthPolicy": "MUTUAL_TLS",
109
"envoyAccessLogService": map[string]any{
110
"address": "address",
111
"tlsSettings": map[string]any{
112
"subjectAltNames": []any{"san"},
121
for _, tt := range tests {
122
t.Run(tt.name, func(t *testing.T) {
123
j, err := json.Marshal(tt.in)
125
t.Fatalf("failed to marshal: %v", err)
127
if string(j) != tt.out {
128
t.Errorf("Got json '%s', expected '%s'", string(j), tt.out)
130
var meta model.BootstrapNodeMetadata
131
if err := json.Unmarshal(j, &meta); err != nil {
132
t.Fatalf("failed to unmarshal: %v", err)
135
assert.Equal(t, (*meshconfig.ProxyConfig)(meta.NodeMetadata.ProxyConfig), (*meshconfig.ProxyConfig)(tt.inOut.NodeMetadata.ProxyConfig))
136
// cmp cannot handle the type-alias in the metadata, so check them separately.
137
meta.NodeMetadata.ProxyConfig = nil
138
tt.inOut.NodeMetadata.ProxyConfig = nil
139
assert.Equal(t, meta, tt.inOut)
144
func TestStringList(t *testing.T) {
147
expect model.StringList
150
{in: `"a,b,c"`, expect: []string{"a", "b", "c"}},
151
{in: `"\"a,b,c"`, expect: []string{`"a`, "b", "c"}},
152
{in: `"a"`, expect: []string{"a"}},
153
{in: `""`, expect: []string{}},
154
{in: `"123,@#$#,abcdef"`, expect: []string{"123", "@#$#", "abcdef"}},
156
for _, tt := range cases {
157
t.Run(tt.in, func(t *testing.T) {
158
var out model.StringList
159
if err := json.Unmarshal([]byte(tt.in), &out); err != nil {
162
if !reflect.DeepEqual(out, tt.expect) {
163
t.Fatalf("Expected %v, got %v", tt.expect, out)
165
b, err := json.Marshal(out)
172
if !reflect.DeepEqual(string(b), tt.in) {
173
t.Fatalf("Expected %v, got %v", tt.in, string(b))
178
var out model.StringList
179
assert.Error(t, json.Unmarshal([]byte("1"), &out))
182
func TestPodPortList(t *testing.T) {
186
expect model.PodPortList
187
expUnmarshalErr string
189
{"no port", `"[]"`, model.PodPortList{}, ""},
190
{"one port", `"[{\"name\":\"foo\",\"containerPort\":9080,\"protocol\":\"TCP\"}]"`, model.PodPortList{{"foo", 9080, "TCP"}}, ""},
193
`"[{\"name\":\"foo\",\"containerPort\":9080,\"protocol\":\"TCP\"},{\"containerPort\":8888,\"protocol\":\"TCP\"}]"`,
194
model.PodPortList{{"foo", 9080, "TCP"}, {ContainerPort: 8888, Protocol: "TCP"}},
197
{"invalid syntax", `[]`, nil, "invalid syntax"},
199
for _, tt := range cases {
200
t.Run(tt.name, func(t *testing.T) {
201
var out model.PodPortList
202
if err := json.Unmarshal([]byte(tt.in), &out); err != nil {
203
if tt.expUnmarshalErr == "" {
207
t.Fatalf("%s: Expected null unmarshal output but obtained a non-null one.", tt.name)
209
if err.Error() != tt.expUnmarshalErr {
210
t.Fatalf("%s: Expected error: %s but got error: %s.", tt.name, tt.expUnmarshalErr, err.Error())
214
if !reflect.DeepEqual(out, tt.expect) {
215
t.Fatalf("%s: Expected %v, got %v", tt.name, tt.expect, out)
217
b, err := json.Marshal(out)
221
if !reflect.DeepEqual(string(b), tt.in) {
222
t.Fatalf("%s: Expected %v, got %v", tt.name, tt.in, string(b))
228
func TestStringBool(t *testing.T) {
234
{"1", `"1"`, `"true"`},
235
{"0", `"0"`, `"false"`},
236
{"false", `"false"`, `"false"`},
237
{"true", `"true"`, `"true"`},
238
{"invalid input", `"foo"`, ``},
239
{"no quotes", `true`, ``},
241
for _, tt := range cases {
242
t.Run(tt.name, func(t *testing.T) {
243
var out model.StringBool
244
if err := json.Unmarshal([]byte(tt.in), &out); err != nil {
250
b, err := json.Marshal(out)
254
if !reflect.DeepEqual(string(b), tt.expect) {
255
t.Fatalf("Expected %v, got %v", tt.expect, string(b))
265
func TestGetLocalityLabel(t *testing.T) {
273
label: "region/zone/subzone-1",
274
expected: "region/zone/subzone-1",
277
name: "label with k8s label separator",
278
label: "region" + k8sSeparator + "zone" + k8sSeparator + "subzone-2",
279
expected: "region/zone/subzone-2",
282
name: "label with both k8s label separators and slashes",
283
label: "region/zone/subzone.2",
284
expected: "region/zone/subzone.2",
288
for _, testCase := range cases {
289
t.Run(testCase.name, func(t *testing.T) {
290
got := model.GetLocalityLabel(testCase.label)
291
if got != testCase.expected {
292
t.Errorf("expected locality %s, but got %s", testCase.expected, got)