2 ==================================================================================
3 Copyright (c) 2019 AT&T Intellectual Property.
4 Copyright (c) 2019 Nokia
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================================
30 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
31 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/models"
32 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/util"
36 expectedHelmSearchCmd = "search helm-repo"
37 expectedHelmFetchCmd = `fetch --untar --untardir /tmp helm-repo/dummy-xapp`
40 var caughtKubeExecArgs []string
41 var kubeExecRetOut string
42 var kubeExecRetErr error
43 var caughtHelmExecArgs string
44 var helmExecRetOut string
45 var helmExecRetErr error
47 var expectedKubectlGetCmd []string = []string{
48 `get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp configmap-ricxapp-anr-appconfig`,
49 `get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp configmap-ricxapp-appmgr-appconfig`,
50 `get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp configmap-ricxapp-dualco-appconfig`,
51 `get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp configmap-ricxapp-reporter-appconfig`,
52 `get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp configmap-ricxapp-uemgr-appconfig`,
55 var helmSearchOutput = `
56 helm-repo/anr 0.0.1 1.0 Helm Chart for Nokia ANR (Automatic Neighbour Relation) xAPP
57 helm-repo/appmgr 0.0.2 1.0 Helm Chart for xAppManager
58 helm-repo/dualco 0.0.1 1.0 Helm Chart for Nokia dualco xAPP
59 helm-repo/reporter 0.0.1 1.0 Helm Chart for Reporting xAPP
60 helm-repo/uemgr 0.0.1 1.0 Helm Chart for Nokia uemgr xAPP
63 var kubectlConfigmapOutput = `
72 "protPort": "tcp:4560",
75 "txMessages": ["RIC_X2_LOAD_INFORMATION"],
76 "rxMessages": ["RIC_X2_LOAD_INFORMATION"],
77 "policies": [11, 22, 33]
80 "namespace": "ricxapp",
96 type ConfigSample struct {
101 type MockedConfigMapper struct {
104 func (cm *MockedConfigMapper) ReadSchema(name string, c *models.XAppConfig) (err error) {
108 func (cm *MockedConfigMapper) UploadConfig() (cfg []models.XAppConfig) {
112 func (cm *MockedConfigMapper) UpdateConfigMap(r models.XAppConfig) (errList models.ConfigValidationErrors, err error) {
116 func (cm *MockedConfigMapper) ReadConfigMap(name string, ns string, c *interface{}) (err error) {
120 func (cm *MockedConfigMapper) FetchChart(name string) (err error) {
124 func (cm *MockedConfigMapper) GetRtmData(name string) (msgs appmgr.RtmData) {
128 func (cm *MockedConfigMapper) GetNamespace(ns string) (n string) {
132 func (cm *MockedConfigMapper) GetNamesFromHelmRepo() (names []string) {
137 func TestMain(m *testing.M) {
139 appmgr.Logger.SetLevel(0)
145 func TestUploadConfigAllSuccess(t *testing.T) {
147 var expectedResult models.AllXappConfig
149 xapps := []string{"anr", "appmgr", "dualco", "reporter", "uemgr"}
151 if ret := json.Unmarshal([]byte(cfgData), &cfg); ret != nil {
152 t.Errorf("UploadConfigAll Json unmarshal failed: %v", ret)
155 for i, _ := range xapps {
156 expectedResult = append(expectedResult,
159 Metadata: &models.ConfigMetadata{
167 defer func() { resetHelmExecMock() }()
168 helmExec = mockedHelmExec
169 //Fake helm search success
170 helmExecRetOut = helmSearchOutput
172 defer func() { resetKubeExecMock() }()
173 kubeExec = mockedKubeExec
174 //Fake 'kubectl get configmap' success
175 kubeExecRetOut = strings.ReplaceAll(cfgData, "\\", "")
177 result := NewCM().UploadConfigAll()
178 if !reflect.DeepEqual(result, expectedResult) {
179 t.Errorf("UploadConfigAll failed: expected: %v, got: %v", expectedResult, result)
181 if caughtHelmExecArgs != expectedHelmSearchCmd {
182 t.Errorf("UploadConfigAll failed: expected: %v, got: %v", expectedHelmSearchCmd, caughtHelmExecArgs)
184 if !reflect.DeepEqual(caughtKubeExecArgs, expectedKubectlGetCmd) {
185 t.Errorf("UploadConfigAll failed: expected: %v, got: %v", expectedKubectlGetCmd, caughtKubeExecArgs)
189 func TestUploadConfigAllReturnsEmptyMapIfAllConfigMapReadsFail(t *testing.T) {
190 var expectedResult models.AllXappConfig
192 defer func() { resetHelmExecMock() }()
193 helmExec = mockedHelmExec
194 //Fake helm search success
195 helmExecRetOut = helmSearchOutput
197 defer func() { resetKubeExecMock() }()
198 kubeExec = mockedKubeExec
199 //Fake 'kubectl get configmap' failure
200 kubeExecRetErr = errors.New("some error")
202 result := NewCM().UploadConfigAll()
203 if !reflect.DeepEqual(result, expectedResult) {
204 t.Errorf("UploadConfigAll failed: expected: %v, got: %v", expectedResult, result)
208 func TestUploadConfigElementSuccess(t *testing.T) {
210 var expectedResult models.AllXappConfig
212 xapps := []string{"anr", "appmgr", "dualco", "reporter", "uemgr"}
214 if ret := json.Unmarshal([]byte(cfgData), &cfg); ret != nil {
215 t.Errorf("UploadConfigElement Json unmarshal failed: %v", ret)
218 for i, _ := range xapps {
219 expectedResult = append(expectedResult,
221 Config: cfg.(map[string]interface{})["active"],
222 Metadata: &models.ConfigMetadata{
230 defer func() { resetHelmExecMock() }()
231 helmExec = mockedHelmExec
232 //Fake helm search success
233 helmExecRetOut = helmSearchOutput
235 defer func() { resetKubeExecMock() }()
236 kubeExec = mockedKubeExec
237 //Fake 'kubectl get configmap' success
238 kubeExecRetOut = strings.ReplaceAll(cfgData, "\\", "")
240 result := NewCM().UploadConfigElement("active")
241 if !reflect.DeepEqual(result, expectedResult) {
242 t.Errorf("UploadConfigElement failed: expected: %v, got: %v", expectedResult, result)
244 if caughtHelmExecArgs != expectedHelmSearchCmd {
245 t.Errorf("UploadConfigElement failed: expected: %v, got: %v", expectedHelmSearchCmd, caughtHelmExecArgs)
247 if !reflect.DeepEqual(caughtKubeExecArgs, expectedKubectlGetCmd) {
248 t.Errorf("UploadConfigElement failed: expected: %v, got: %v", expectedKubectlGetCmd, caughtKubeExecArgs)
252 func TestUploadConfigElementReturnsEmptyMapIfElementMissingFromConfigMap(t *testing.T) {
253 var expectedResult models.AllXappConfig
255 defer func() { resetHelmExecMock() }()
256 helmExec = mockedHelmExec
257 //Fake helm search success
258 helmExecRetOut = helmSearchOutput
260 defer func() { resetKubeExecMock() }()
261 kubeExec = mockedKubeExec
262 //Fake 'kubectl get configmap' success
263 kubeExecRetOut = strings.ReplaceAll(cfgData, "\\", "")
265 //Try to upload non-existing configuration element
266 result := NewCM().UploadConfigElement("some-not-existing-element")
267 if !reflect.DeepEqual(result, expectedResult) {
268 t.Errorf("UploadConfigElement failed: expected: %v, got: %v", expectedResult, result)
272 func TestGetRtmDataSuccess(t *testing.T) {
273 expectedKubeCmd := []string{
274 `get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp configmap-ricxapp-dummy-xapp-appconfig`,
276 expectedMsgs := appmgr.RtmData{
277 TxMessages: []string{"RIC_X2_LOAD_INFORMATION"},
278 RxMessages: []string{"RIC_X2_LOAD_INFORMATION"},
279 Policies: []int64{11, 22, 33},
282 defer func() { resetKubeExecMock() }()
283 kubeExec = mockedKubeExec
284 //Fake 'kubectl get configmap' success
285 kubeExecRetOut = kubectlConfigmapOutput
287 result := NewCM().GetRtmData("dummy-xapp")
288 if !reflect.DeepEqual(result, expectedMsgs) {
289 t.Errorf("GetRtmData failed: expected: %v, got: %v", expectedMsgs, result)
291 if !reflect.DeepEqual(caughtKubeExecArgs, expectedKubeCmd) {
292 t.Errorf("GetRtmData failed: expected: '%v', got: '%v'", expectedKubeCmd, caughtKubeExecArgs)
296 func TestGetRtmDataReturnsNoDataIfConfigmapGetFails(t *testing.T) {
297 var expectedMsgs appmgr.RtmData
299 defer func() { resetKubeExecMock() }()
300 kubeExec = mockedKubeExec
301 //Fake 'kubectl get configmap' failure
302 kubeExecRetErr = errors.New("some error")
304 result := NewCM().GetRtmData("dummy-xapp")
305 if !reflect.DeepEqual(result, expectedMsgs) {
306 t.Errorf("GetRtmData failed: expected: %v, got: %v", expectedMsgs, result)
310 func TestGetRtmDataReturnsNoDataIfJsonParseFails(t *testing.T) {
311 var expectedMsgs appmgr.RtmData
313 defer func() { resetKubeExecMock() }()
314 kubeExec = mockedKubeExec
315 //Fake 'kubectl get configmap' to return nothing what will cause JSON parse failure
317 result := NewCM().GetRtmData("dummy-xapp")
318 if !reflect.DeepEqual(result, expectedMsgs) {
319 t.Errorf("GetRtmData failed: expected: %v, got: %v", expectedMsgs, result)
323 func TestHelmNamespace(t *testing.T) {
324 if NewCM().GetNamespace("pltxapp") != "pltxapp" {
325 t.Errorf("getNamespace failed!")
328 if NewCM().GetNamespace("") != "ricxapp" {
329 t.Errorf("getNamespace failed!")
333 func TestFetchChartFails(t *testing.T) {
334 if NewCM().FetchChart("dummy-xapp") == nil {
335 t.Errorf("TestFetchChart failed!")
339 func TestFetchChartSuccess(t *testing.T) {
340 defer func() { resetHelmExecMock() }()
341 helmExec = mockedHelmExec
343 if NewCM().FetchChart("dummy-xapp") != nil {
344 t.Errorf("TestFetchChart failed!")
348 func TestGetNamespaceSuccess(t *testing.T) {
349 if ns := NewCM().GetNamespace("my-ns"); ns != "my-ns" {
350 t.Errorf("GetNamespace failed: expected: my-ns, got: %s", ns)
354 func TestGetNamespaceReturnsConfiguredNamespaceName(t *testing.T) {
355 if ns := NewCM().GetNamespace(""); ns != "ricxapp" {
356 t.Errorf("GetNamespace failed: expected: ricxapp, got: %s", ns)
360 func TestGetNamesFromHelmRepoSuccess(t *testing.T) {
361 expectedResult := []string{"anr", "appmgr", "dualco", "reporter", "uemgr"}
363 defer func() { resetHelmExecMock() }()
364 helmExec = mockedHelmExec
365 //Fake helm search success
366 helmExecRetOut = helmSearchOutput
368 names := NewCM().GetNamesFromHelmRepo()
369 if !reflect.DeepEqual(names, expectedResult) {
370 t.Errorf("GetNamesFromHelmRepo failed: expected %v, got %v", expectedResult, names)
372 if caughtHelmExecArgs != expectedHelmSearchCmd {
373 t.Errorf("GetNamesFromHelmRepo failed: expected: %v, got: %v", expectedHelmSearchCmd, caughtHelmExecArgs)
377 func TestGetNamesFromHelmRepoFailure(t *testing.T) {
378 expectedResult := []string{}
380 defer func() { resetHelmExecMock() }()
381 helmExec = mockedHelmExec
382 helmExecRetOut = helmSearchOutput
383 helmExecRetErr = errors.New("Command failed!")
385 names := NewCM().GetNamesFromHelmRepo()
387 t.Errorf("GetNamesFromHelmRepo failed: expected %v, got %v", expectedResult, names)
391 func TestBuildConfigMapSuccess(t *testing.T) {
392 expectedKubeCmd := []string{
393 `get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp configmap-ricxapp-dummy-xapp-appconfig`,
396 namespace := "ricxapp"
397 m := models.ConfigMetadata{XappName: &name, Namespace: &namespace}
398 s := `{"Metadata": {"XappName": "ueec", "Namespace": "ricxapp"}, ` +
399 `"Config": {"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}}`
401 defer func() { resetKubeExecMock() }()
402 kubeExec = mockedKubeExec
403 //Fake 'kubectl get configmap' success
404 kubeExecRetOut = `{"logger": {"level": 2}}`
406 cmString, err := NewCM().BuildConfigMap(models.XAppConfig{Metadata: &m, Config: s})
408 t.Errorf("BuildConfigMap failed: %v -> %v", err, cmString)
410 if !reflect.DeepEqual(caughtKubeExecArgs, expectedKubeCmd) {
411 t.Errorf("BuildConfigMap failed: expected: %v, got: %v", expectedKubeCmd, caughtKubeExecArgs)
415 func TestBuildConfigMapReturnErrorIfJsonMarshalFails(t *testing.T) {
417 namespace := "ricxapp"
418 m := models.ConfigMetadata{XappName: &name, Namespace: &namespace}
419 //Give channel as a configuration input, this will fail JSON marshal
420 cmString, err := NewCM().BuildConfigMap(models.XAppConfig{Metadata: &m, Config: make(chan int)})
422 t.Errorf("BuildConfigMap failed: %v -> %v", err, cmString)
426 func TestBuildConfigMapReturnErrorIfKubectlGetConfigmapFails(t *testing.T) {
428 namespace := "ricxapp"
429 m := models.ConfigMetadata{XappName: &name, Namespace: &namespace}
430 s := `{"Metadata": {"XappName": "ueec", "Namespace": "ricxapp"}, ` +
431 `"Config": {"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}}`
433 defer func() { resetKubeExecMock() }()
434 kubeExec = mockedKubeExec
435 //Fake 'kubectl get configmap' failure
436 kubeExecRetErr = errors.New("some error")
438 cmString, err := NewCM().BuildConfigMap(models.XAppConfig{Metadata: &m, Config: s})
440 t.Errorf("BuildConfigMap failed: %v -> %v", err, cmString)
441 } else if err.Error() != "some error" {
442 t.Errorf("BuildConfigMap failed: expected: 'some error', got: '%s'", err.Error())
446 func TestBuildConfigMapReturnErrorIfJsonParserFails(t *testing.T) {
448 namespace := "ricxapp"
449 m := models.ConfigMetadata{XappName: &name, Namespace: &namespace}
450 s := `{"Metadata": {"XappName": "ueec", "Namespace": "ricxapp"}, ` +
451 `"Config": {"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}}`
453 defer func() { resetKubeExecMock() }()
454 kubeExec = mockedKubeExec
455 //Return empty json that causes JSON parser to fail
458 cmString, err := NewCM().BuildConfigMap(models.XAppConfig{Metadata: &m, Config: s})
460 t.Errorf("BuildConfigMap failed: %v -> %v", err, cmString)
464 func TestGenerateJSONFileSuccess(t *testing.T) {
465 err := NewCM().GenerateJSONFile("{}")
467 t.Errorf("GenerateJSONFile failed: %v", err)
471 func TestReplaceConfigMapSuccess(t *testing.T) {
473 namespace := "ricxapp"
475 defer func() { resetKubeExecMock() }()
476 kubeExec = mockedKubeExec
477 //Fake 'kubectl create configmap' success
480 err := NewCM().ReplaceConfigMap(name, namespace)
482 t.Errorf("ReplaceConfigMap failed: %v", err)
486 func TestUpdateConfigMapReturnsErrorIfSchemaFileIsMissing(t *testing.T) {
488 namespace := "ricxapp"
489 config := models.XAppConfig{Metadata: &models.ConfigMetadata{XappName: &name, Namespace: &namespace}}
491 defer func() { resetHelmExecMock() }()
492 helmExec = mockedHelmExec
493 helmExecRetOut = `{}`
495 //Will fail at schema reading, because schema file is mission
496 validationErrors, err := NewCM().UpdateConfigMap(config)
498 t.Errorf("UpdateConfigMap failed: %v -> %v", err, validationErrors)
500 if caughtHelmExecArgs != expectedHelmFetchCmd {
501 t.Errorf("UpdateConfigMap failed: expected: %v, got: %v", expectedHelmFetchCmd, caughtHelmExecArgs)
505 func TestUpdateConfigMapReturnsErrorIfHelmFetchChartFails(t *testing.T) {
507 namespace := "ricxapp"
508 config := models.XAppConfig{Metadata: &models.ConfigMetadata{XappName: &name, Namespace: &namespace}}
510 defer func() { resetHelmExecMock() }()
511 helmExec = mockedHelmExec
512 helmExecRetErr = errors.New("some error")
514 validationErrors, err := NewCM().UpdateConfigMap(config)
516 t.Errorf("UpdateConfigMap failed: %v -> %v", err, validationErrors)
520 func TestValidationSuccess(t *testing.T) {
522 var cfg map[string]interface{}
523 err := json.Unmarshal([]byte(`{"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}`), &cfg)
525 err = NewCM().ReadFile("../../test/schema.json", &d)
527 t.Errorf("ReadFile failed: %v -> %v", err, d)
530 feedback, err := NewCM().doValidate(d, cfg)
532 t.Errorf("doValidate failed: %v -> %v", err, feedback)
536 func TestValidationFails(t *testing.T) {
538 var cfg map[string]interface{}
540 err := json.Unmarshal([]byte(`{"active": "INVALID", "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}`), &cfg)
542 err = NewCM().ReadFile("../../test/schema.json", &d)
544 t.Errorf("ConfigMetadata failed: %v -> %v", err, d)
547 feedback, err := NewCM().doValidate(d, cfg)
549 t.Errorf("doValidate should fail but didn't: %v -> %v", err, feedback)
551 appmgr.Logger.Debug("Feedbacks: %v", feedback)
554 func TestReadFileReturnsErrorIfFileReadFails(t *testing.T) {
557 if err := NewCM().ReadFile("not/existing/test/schema.json", &d); err == nil {
558 t.Errorf("ReadFile should fail but it didn't")
562 func TestReadFileReturnsErrorIfJsonUnmarshalFails(t *testing.T) {
565 if err := NewCM().ReadFile("../../test/faulty_schema.json", &d); err == nil {
566 t.Errorf("ReadFile should fail but it didn't")
570 func mockedKubeExec(args string) (out []byte, err error) {
571 caughtKubeExecArgs = append(caughtKubeExecArgs, args)
572 return []byte(kubeExecRetOut), kubeExecRetErr
575 func resetKubeExecMock() {
576 kubeExec = util.KubectlExec
577 caughtKubeExecArgs = nil
582 func mockedHelmExec(args string) (out []byte, err error) {
583 caughtHelmExecArgs = args
584 return []byte(helmExecRetOut), helmExecRetErr
587 func resetHelmExecMock() {
588 helmExec = util.HelmExec
589 caughtHelmExecArgs = ""