istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/controlplane/control_plane_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 controlplane 16 17 import ( 18 "fmt" 19 "reflect" 20 "testing" 21 22 "istio.io/api/operator/v1alpha1" 23 "istio.io/istio/operator/pkg/component" 24 "istio.io/istio/operator/pkg/name" 25 "istio.io/istio/operator/pkg/translate" 26 "istio.io/istio/operator/pkg/util" 27 ) 28 29 func TestOrderedKeys(t *testing.T) { 30 tests := []struct { 31 desc string 32 in map[string]*v1alpha1.ExternalComponentSpec 33 want []string 34 }{ 35 { 36 desc: "not-ordered", 37 in: map[string]*v1alpha1.ExternalComponentSpec{ 38 "graphql": nil, 39 "Abacus": nil, 40 "Astrology": nil, 41 "gRPC": nil, 42 "blackjack": nil, 43 }, 44 want: []string{ 45 "Abacus", 46 "Astrology", 47 "blackjack", 48 "gRPC", 49 "graphql", 50 }, 51 }, 52 } 53 for _, tt := range tests { 54 t.Run(tt.desc, func(t *testing.T) { 55 if got := orderedKeys(tt.in); !(reflect.DeepEqual(got, tt.want)) { 56 t.Errorf("%s: got %+v want %+v", tt.desc, got, tt.want) 57 } 58 }) 59 } 60 } 61 62 func TestNewIstioOperator(t *testing.T) { 63 coreComponentOptions := &component.Options{ 64 InstallSpec: &v1alpha1.IstioOperatorSpec{}, 65 Translator: &translate.Translator{}, 66 } 67 tests := []struct { 68 desc string 69 inInstallSpec *v1alpha1.IstioOperatorSpec 70 inTranslator *translate.Translator 71 wantIstioOperator *IstioControlPlane 72 wantErr error 73 }{ 74 { 75 desc: "core-components", 76 inInstallSpec: &v1alpha1.IstioOperatorSpec{}, 77 inTranslator: &translate.Translator{ 78 ComponentMaps: map[name.ComponentName]*translate.ComponentMaps{ 79 "Pilot": { 80 ResourceName: "test-resource", 81 }, 82 }, 83 }, 84 wantErr: nil, 85 wantIstioOperator: &IstioControlPlane{ 86 components: []component.IstioComponent{ 87 &component.BaseComponent{ 88 IstioComponentBase: &component.IstioComponentBase{ 89 CommonComponentFields: &component.CommonComponentFields{ 90 Options: coreComponentOptions, 91 ComponentName: name.IstioBaseComponentName, 92 }, 93 }, 94 }, 95 &component.PilotComponent{ 96 IstioComponentBase: &component.IstioComponentBase{ 97 CommonComponentFields: &component.CommonComponentFields{ 98 Options: coreComponentOptions, 99 ResourceName: "test-resource", 100 ComponentName: name.PilotComponentName, 101 }, 102 }, 103 }, 104 &component.CNIComponent{ 105 IstioComponentBase: &component.IstioComponentBase{ 106 CommonComponentFields: &component.CommonComponentFields{ 107 ComponentName: name.CNIComponentName, 108 Options: coreComponentOptions, 109 }, 110 }, 111 }, 112 &component.IstiodRemoteComponent{ 113 IstioComponentBase: &component.IstioComponentBase{ 114 CommonComponentFields: &component.CommonComponentFields{ 115 ComponentName: name.IstiodRemoteComponentName, 116 Options: coreComponentOptions, 117 }, 118 }, 119 }, 120 &component.ZtunnelComponent{ 121 IstioComponentBase: &component.IstioComponentBase{ 122 CommonComponentFields: &component.CommonComponentFields{ 123 ComponentName: name.ZtunnelComponentName, 124 Options: coreComponentOptions, 125 }, 126 }, 127 }, 128 }, 129 }, 130 }, 131 } 132 for _, tt := range tests { 133 t.Run(tt.desc, func(t *testing.T) { 134 gotOperator, err := NewIstioControlPlane(tt.inInstallSpec, tt.inTranslator, nil, nil) 135 if ((err != nil && tt.wantErr == nil) || (err == nil && tt.wantErr != nil)) || !gotOperator.componentsEqual(tt.wantIstioOperator.components) { 136 t.Errorf("%s: wanted components & err %+v %v, got components & err %+v %v", 137 tt.desc, tt.wantIstioOperator.components, tt.wantErr, gotOperator.components, err) 138 } 139 }) 140 } 141 } 142 143 func TestIstioOperator_RenderManifest(t *testing.T) { 144 coreComponentOptions := &component.Options{ 145 InstallSpec: &v1alpha1.IstioOperatorSpec{}, 146 Translator: &translate.Translator{}, 147 } 148 tests := []struct { 149 desc string 150 testOperator *IstioControlPlane 151 wantManifests name.ManifestMap 152 wantErrs util.Errors 153 }{ 154 { 155 desc: "components-not-started-operator-started", 156 testOperator: &IstioControlPlane{ 157 components: []component.IstioComponent{ 158 &component.BaseComponent{ 159 IstioComponentBase: &component.IstioComponentBase{ 160 CommonComponentFields: &component.CommonComponentFields{ 161 Options: coreComponentOptions, 162 ComponentName: name.IstioBaseComponentName, 163 }, 164 }, 165 }, 166 &component.PilotComponent{ 167 IstioComponentBase: &component.IstioComponentBase{ 168 CommonComponentFields: &component.CommonComponentFields{ 169 Options: &component.Options{ 170 InstallSpec: &v1alpha1.IstioOperatorSpec{}, 171 Translator: &translate.Translator{}, 172 }, 173 ResourceName: "test-resource", 174 ComponentName: name.PilotComponentName, 175 }, 176 }, 177 }, 178 &component.CNIComponent{ 179 IstioComponentBase: &component.IstioComponentBase{ 180 CommonComponentFields: &component.CommonComponentFields{ 181 ComponentName: name.CNIComponentName, 182 Options: coreComponentOptions, 183 }, 184 }, 185 }, 186 }, 187 started: true, 188 }, 189 wantManifests: map[name.ComponentName][]string{}, 190 wantErrs: util.Errors{ 191 fmt.Errorf("component Base not started in RenderManifest"), 192 fmt.Errorf("component Pilot not started in RenderManifest"), 193 fmt.Errorf("component Cni not started in RenderManifest"), 194 }, 195 }, 196 { 197 desc: "operator-not-started", 198 testOperator: &IstioControlPlane{ 199 components: []component.IstioComponent{ 200 &component.BaseComponent{ 201 IstioComponentBase: &component.IstioComponentBase{ 202 CommonComponentFields: &component.CommonComponentFields{ 203 Options: coreComponentOptions, 204 ComponentName: name.IstioBaseComponentName, 205 }, 206 }, 207 }, 208 &component.PilotComponent{ 209 IstioComponentBase: &component.IstioComponentBase{ 210 CommonComponentFields: &component.CommonComponentFields{ 211 Options: &component.Options{ 212 InstallSpec: &v1alpha1.IstioOperatorSpec{}, 213 Translator: &translate.Translator{}, 214 }, 215 ResourceName: "test-resource", 216 ComponentName: name.PilotComponentName, 217 }, 218 }, 219 }, 220 &component.CNIComponent{ 221 IstioComponentBase: &component.IstioComponentBase{ 222 CommonComponentFields: &component.CommonComponentFields{ 223 ComponentName: name.CNIComponentName, 224 Options: coreComponentOptions, 225 }, 226 }, 227 }, 228 }, 229 started: false, 230 }, 231 wantManifests: map[name.ComponentName][]string{}, 232 wantErrs: util.Errors{ 233 fmt.Errorf("istioControlPlane must be Run before calling RenderManifest"), 234 }, 235 }, 236 } 237 for _, tt := range tests { 238 t.Run(tt.desc, func(t *testing.T) { 239 gotManifests, gotErrs := tt.testOperator.RenderManifest() 240 if !reflect.DeepEqual(gotManifests, tt.wantManifests) || !util.EqualErrors(gotErrs, tt.wantErrs) { 241 // reflect.DeepEqual returns false on size 0 maps 242 if !(len(gotManifests) == 0) && (len(tt.wantManifests) == 0) { 243 t.Errorf("%s: expected manifest map %+v errs %+v, got manifest map %+v errs %+v", 244 tt.desc, tt.wantManifests, tt.wantErrs, gotManifests, gotErrs) 245 } 246 } 247 }) 248 } 249 }