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 ==================================================================================
24 "github.com/spf13/viper"
30 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/cm"
31 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
32 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/models"
33 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/util"
36 var caughtKubeExecArgs string
37 var kubeExecRetOut string
38 var kubeExecRetErr error
39 var caughtHelmExecArgs string
40 var helmExecRetOut string
41 var helmExecRetErr error
42 var helmStatusOutput = `
43 LAST DEPLOYED: Sat Mar 9 06:50:45 2019
49 NAME READY STATUS RESTARTS AGE
50 dummy-xapp-8984fc9fd-bkcbp 1/1 Running 0 55m
51 dummy-xapp-8984fc9fd-l6xch 1/1 Running 0 55m
52 dummy-xapp-8984fc9fd-pp4hg 1/1 Running 0 55m
55 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
56 dummy-xapp-dummy-xapp-chart ClusterIP 10.102.184.212 <none> 80/TCP 55m
58 ==> v1beta1/Deployment
59 NAME READY UP-TO-DATE AVAILABLE AGE
60 dummy-xapp 3/3 3 3 55m
63 var helListAllOutput = `Next: ""
66 Chart: dummy-xapp-chart-0.1.0
71 Updated: Mon Mar 11 06:55:05 2019
73 Chart: dummy-xapp-chart-0.1.0
78 Updated: Mon Mar 11 06:55:05 2019
85 Updated: Sun Mar 24 07:17:00 2019
88 var helListOutput = `Next: ""
91 Chart: dummy-xapp-chart-0.1.0
96 Updated: Mon Mar 11 06:55:05 2019
99 var kubeServiceOutput = `{
103 "creationTimestamp": "2020-03-31T12:27:12Z",
105 "app": "ricxapp-dummy-xapp",
106 "chart": "dummy-xapp-0.0.4",
107 "heritage": "Tiller",
108 "release": "dummy-xapp"
110 "name": "service-ricxapp-dummy-xapp-rmr",
111 "namespace": "ricxapp",
112 "resourceVersion": "4423380",
113 "selfLink": "/api/v1/namespaces/ricxapp/services/service-ricxapp-dummy-xapp-rmr",
114 "uid": "2254b77d-7dd6-43e0-beff-3e2a7b24c89a"
117 "clusterIP": "10.98.239.107",
123 "targetPort": "rmrdata"
129 "targetPort": "rmrroute"
133 "app": "ricxapp-dummy-xapp",
134 "release": "dummy-xapp"
136 "sessionAffinity": "None",
145 func TestMain(m *testing.M) {
147 appmgr.Logger.SetLevel(0)
153 func TestInit(t *testing.T) {
154 defer func() { resetHelmExecMock() }()
155 var expectedHelmCommand string = ""
156 helmExec = mockedHelmExec
160 if cm.EnvHelmVersion == cm.HELM_VERSION_2{
161 expectedHelmCommand = "init -c --skip-refresh"
162 if caughtHelmExecArgs != expectedHelmCommand {
163 t.Errorf("Init failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
168 func TestAddRepoSuccess(t *testing.T) {
171 removeTestUsernameFile()
172 removeTestPasswordFile()
174 helmExec = mockedHelmExec
176 if err := writeTestUsernameFile(); err != nil {
177 t.Errorf("AddRepo username file create failed: %s", err)
180 if err := writeTestPasswordFile(); err != nil {
181 t.Errorf("AddRepo password file create failed: %s", err)
185 if _, err := NewHelm().AddRepo(); err != nil {
186 t.Errorf("AddRepo failed: %v", err)
189 if !strings.Contains(caughtHelmExecArgs, "repo add") {
190 t.Errorf("AddRepo failed: expected %v, got %v", "repo add", caughtHelmExecArgs)
194 func TestAddRepoReturnsErrorIfNoUsernameFile(t *testing.T) {
195 if _, err := NewHelm().AddRepo(); err == nil {
196 t.Errorf("AddRepo expected to fail but it didn't")
200 func TestAddRepoReturnsErrorIfNoPasswordFile(t *testing.T) {
201 defer func() { resetHelmExecMock(); removeTestUsernameFile() }()
202 helmExec = mockedHelmExec
204 if err := writeTestUsernameFile(); err != nil {
205 t.Errorf("AddRepo username file create failed: %s", err)
208 if _, err := NewHelm().AddRepo(); err == nil {
209 t.Errorf("AddRepo expected to fail but it didn't")
213 func TestInstallSuccess(t *testing.T) {
215 xappDesc := models.XappDescriptor{XappName: &name, Namespace: "ricxapp"}
217 defer func() { resetHelmExecMock() }()
218 helmExec = mockedHelmExec
219 helmExecRetOut = helmStatusOutput
221 defer func() { resetKubeExecMock() }()
222 kubeExec = mockedKubeExec
223 kubeExecRetOut = kubeServiceOutput
225 xapp, err := NewHelm().Install(xappDesc)
227 t.Errorf("Install failed: %v", err)
229 validateXappModel(t, xapp)
232 func TestInstallReturnsErrorIfHelmRepoUpdateFails(t *testing.T) {
234 xappDesc := models.XappDescriptor{XappName: &name, Namespace: "ricxapp"}
236 defer func() { resetHelmExecMock() }()
237 helmExec = mockedHelmExec
238 helmExecRetErr = errors.New("some helm command error")
240 if _, err := NewHelm().Install(xappDesc); err == nil {
241 t.Errorf("Install expected to fail but it didn't")
245 func TestStatusSuccess(t *testing.T) {
248 defer func() { resetHelmExecMock() }()
249 helmExec = mockedHelmExec
250 helmExecRetOut = helmStatusOutput
252 xapp, err := NewHelm().Status(name)
254 t.Errorf("Status failed: %v", err)
256 validateXappModel(t, xapp)
259 func TestStatusReturnsErrorIfHelmStatusFails(t *testing.T) {
262 defer func() { resetHelmExecMock() }()
263 helmExec = mockedHelmExec
264 helmExecRetErr = errors.New("some helm command error")
266 if _, err := NewHelm().Status(name); err == nil {
267 t.Errorf("Status expected to fail but it didn't")
271 func TestParseStatusSuccess(t *testing.T) {
272 defer func() { resetHelmExecMock() }()
273 var expectedHelmCommand string = ""
274 helmExec = mockedHelmExec
275 helmExecRetOut = helListOutput
277 defer func() { resetKubeExecMock() }()
278 kubeExec = mockedKubeExec
279 kubeExecRetOut = kubeServiceOutput
281 xapp, err := NewHelm().ParseStatus("dummy-xapp", helmStatusOutput)
283 t.Errorf("ParseStatus failed: %v", err)
286 validateXappModel(t, xapp)
288 if cm.EnvHelmVersion == cm.HELM_VERSION_2 {
289 expectedHelmCommand = "list --deployed --output yaml --namespace=ricxapp dummy-xapp"
291 expectedHelmCommand = "list --deployed --output yaml --namespace=ricxapp -f dummy-xapp"
293 if caughtHelmExecArgs != expectedHelmCommand {
294 t.Errorf("ParseStatus failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
298 func TestListSuccess(t *testing.T) {
299 defer func() { resetHelmExecMock() }()
300 helmExec = mockedHelmExec
301 helmExecRetOut = helListAllOutput
303 names, err := NewHelm().List()
305 t.Errorf("List failed: %v", err)
308 if !reflect.DeepEqual(names, []string{"dummy-xapp", "dummy-xapp2"}) {
309 t.Errorf("List failed: %v", err)
311 expectedHelmCommand := "list --all --deployed --output yaml --namespace=ricxapp"
312 if caughtHelmExecArgs != expectedHelmCommand {
313 t.Errorf("List: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
317 func TestListReturnsErrorIfHelmListFails(t *testing.T) {
318 defer func() { resetHelmExecMock() }()
319 helmExec = mockedHelmExec
320 helmExecRetErr = errors.New("some helm command error")
322 if _, err := NewHelm().List(); err == nil {
323 t.Errorf("List expected to fail but it didn't")
327 func TestDeleteSuccess(t *testing.T) {
330 var expectedHelmCommand string = ""
331 defer func() { resetHelmExecMock() }()
332 helmExec = mockedHelmExec
333 helmExecRetOut = helmStatusOutput
335 defer func() { resetKubeExecMock() }()
336 kubeExec = mockedKubeExec
337 kubeExecRetOut = kubeServiceOutput
339 xapp, err := NewHelm().Delete(name)
341 t.Errorf("Delete failed: %v", err)
344 validateXappModel(t, xapp)
346 if cm.EnvHelmVersion == cm.HELM_VERSION_2 {
347 expectedHelmCommand = "del --purge dummy-xapp"
349 expectedHelmCommand = "uninstall dummy-xapp -n ricxapp"
351 if caughtHelmExecArgs != expectedHelmCommand {
352 t.Errorf("Delete failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
356 func TestDeleteReturnsErrorIfHelmStatusFails(t *testing.T) {
359 defer func() { resetHelmExecMock() }()
360 helmExec = mockedHelmExec
361 helmExecRetErr = errors.New("some helm command error")
363 if _, err := NewHelm().Delete(name); err == nil {
364 t.Errorf("Delete expected to fail but it didn't")
368 func TestFetchSuccessIfCmdArgHasTestSuffix(t *testing.T) {
369 if err := NewHelm().Fetch("kissa", "koira"); err != nil {
370 t.Errorf("Fetch failed: %v", err)
374 func TestGetVersionSuccess(t *testing.T) {
375 defer func() { resetHelmExecMock() }()
376 var expectedHelmCommand string = ""
377 helmExec = mockedHelmExec
378 helmExecRetOut = helListOutput
380 if version := NewHelm().GetVersion("dummy-xapp"); version != "1.0" {
381 t.Errorf("GetVersion failed: expected 1.0, got %v", version)
384 if cm.EnvHelmVersion == cm.HELM_VERSION_2{
385 expectedHelmCommand = "list --deployed --output yaml --namespace=ricxapp dummy-xapp"
387 expectedHelmCommand = "list --deployed --output yaml --namespace=ricxapp -f dummy-xapp"
389 if caughtHelmExecArgs != expectedHelmCommand {
390 t.Errorf("GetVersion failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
394 func TestGetVersionReturnsEmptyStringIfHelmListFails(t *testing.T) {
395 defer func() { resetHelmExecMock() }()
396 helmExec = mockedHelmExec
397 helmExecRetErr = errors.New("some helm command error")
399 if version := NewHelm().GetVersion("dummy-xapp"); version != "" {
400 t.Errorf("GetVersion expected to return empty string, got %v", version)
404 func TestGetAddressSuccess(t *testing.T) {
405 ip, port := NewHelm().GetAddress(helmStatusOutput)
406 if ip != "10.102.184.212" {
407 t.Errorf("GetAddress failed: expected 10.102.184.212, got %v", ip)
409 if port != "80/TCP" {
410 t.Errorf("GetAddress failed: expected 80/TCP, got %v", port)
414 func TestGetEndpointInfoSuccess(t *testing.T) {
415 defer func() { resetKubeExecMock() }()
416 kubeExec = mockedKubeExec
417 kubeExecRetOut = kubeServiceOutput
419 svc, port := NewHelm().GetEndpointInfo("dummy-xapp")
420 expectedSvc := "service-ricxapp-dummy-xapp-rmr.ricxapp"
421 if svc != expectedSvc {
422 t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedSvc, svc)
425 t.Errorf("GetEndpointInfo failed: expected port 4560, got %v", port)
427 expectedKubeCommand := " get service -n ricxapp service-ricxapp-dummy-xapp-rmr -o json"
428 if caughtKubeExecArgs != expectedKubeCommand {
429 t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedKubeCommand, caughtKubeExecArgs)
433 func TestGetEndpointInfoReturnsDefaultPortIfJsonParseFails(t *testing.T) {
434 defer func() { resetKubeExecMock() }()
435 kubeExec = mockedKubeExec
436 kubeExecRetOut = "not-json-syntax"
438 svc, port := NewHelm().GetEndpointInfo("dummy-xapp")
439 expectedSvc := "service-ricxapp-dummy-xapp-rmr.ricxapp"
440 if svc != expectedSvc {
441 t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedSvc, svc)
444 t.Errorf("GetEndpointInfo failed: expected port 4560, got %v", port)
448 func TestGetEndpointInfoReturnsDefaultPortIfKubeGetServiceFails(t *testing.T) {
449 defer func() { resetKubeExecMock() }()
450 kubeExec = mockedKubeExec
451 kubeExecRetErr = errors.New("some helm command error")
453 svc, port := NewHelm().GetEndpointInfo("dummy-xapp")
454 expectedSvc := "service-ricxapp-dummy-xapp-rmr.ricxapp"
455 if svc != expectedSvc {
456 t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedSvc, svc)
459 t.Errorf("GetEndpointInfo failed: expected port 4560, got %v", port)
463 func TestHelmStatusAllSuccess(t *testing.T) {
464 defer func() { resetHelmExecMock() }()
465 helmExec = mockedHelmExec
466 helmExecRetOut = helListAllOutput
468 if _, err := NewHelm().StatusAll(); err != nil {
469 t.Errorf("StatusAll failed: %v", err)
471 // Todo: check StatusAll response content
474 func TestStatusAllReturnsErrorIfHelmListFails(t *testing.T) {
475 defer func() { resetHelmExecMock() }()
476 helmExec = mockedHelmExec
477 helmExecRetErr = errors.New("some helm command error")
479 if _, err := NewHelm().StatusAll(); err == nil {
480 t.Errorf("StatusAll expected to fail but it didn't")
484 func TestGetNamesSuccess(t *testing.T) {
485 names, err := NewHelm().GetNames(helListAllOutput)
487 t.Errorf("GetNames failed: %v", err)
489 if !reflect.DeepEqual(names, []string{"dummy-xapp", "dummy-xapp2"}) {
490 t.Errorf("GetNames failed: %v", err)
494 func TestAddTillerEnv(t *testing.T) {
495 if NewHelm().AddTillerEnv() != nil {
496 t.Errorf("AddTillerEnv failed!")
500 func TestGetInstallArgs(t *testing.T) {
502 var expectedArgs string = ""
504 x := models.XappDescriptor{XappName: &name, Namespace: "ricxapp"}
506 if cm.EnvHelmVersion == cm.HELM_VERSION_3 {
507 expectedArgs = "install dummy-xapp helm-repo/dummy-xapp --namespace=ricxapp"
509 expectedArgs = "install helm-repo/dummy-xapp --namespace=ricxapp --name=dummy-xapp"
512 if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
513 t.Errorf("GetInstallArgs failed: expected '%v', got '%v'", expectedArgs, args)
516 expectedArgs += " --set ricapp.appconfig.override=dummy-xapp-appconfig"
517 if args := NewHelm().GetInstallArgs(x, true); args != expectedArgs {
518 t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
521 x.HelmVersion = "1.2.3"
522 if cm.EnvHelmVersion == cm.HELM_VERSION_3 {
523 expectedArgs = "install dummy-xapp helm-repo/dummy-xapp --namespace=ricxapp --version=1.2.3"
525 expectedArgs = "install helm-repo/dummy-xapp --namespace=ricxapp --version=1.2.3 --name=dummy-xapp"
527 if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
528 t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
532 x.ReleaseName = "ueec-xapp"
533 if cm.EnvHelmVersion == cm.HELM_VERSION_3 {
534 expectedArgs = "install dummy-xapp helm-repo/dummy-xapp --namespace=ricxapp --version=1.2.3"
536 expectedArgs = "install helm-repo/dummy-xapp --namespace=ricxapp --version=1.2.3 --name=ueec-xapp"
538 if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
539 t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
542 x.OverrideFile = "../../test/dummy-xapp_values.json"
543 expectedArgs += " -f=/tmp/appmgr_override.yaml"
544 if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
545 t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
549 func writeTestUsernameFile() error {
550 f, err := os.Create(viper.GetString("helm.helm-username-file"))
554 _, err = f.WriteString("some-username")
559 func removeTestUsernameFile() error {
560 return os.Remove(viper.GetString("helm.helm-username-file"))
563 func writeTestPasswordFile() (err error) {
564 f, err := os.Create(viper.GetString("helm.helm-password-file"))
569 _, err = f.WriteString("some-password")
574 func removeTestPasswordFile() error {
575 return os.Remove(viper.GetString("helm.helm-password-file"))
578 func getXappData() (x models.Xapp) {
579 //name1 := "dummy-xapp-8984fc9fd-l6xch"
580 //name2 := "dummy-xapp-8984fc9fd-pp4hg"
581 x = generateXapp("dummy-xapp", "deployed", "1.0", "dummy-xapp-8984fc9fd-bkcbp", "running", "service-ricxapp-dummy-xapp-rmr.ricxapp", "4560")
582 //x.Instances = append(x.Instances, x.Instances[0])
583 //x.Instances = append(x.Instances, x.Instances[0])
584 //x.Instances[1].Name = &name1
585 //x.Instances[2].Name = &name2
590 func generateXapp(name, status, ver, iname, istatus, ip, port string) (x models.Xapp) {
594 p, _ := strconv.Atoi(port)
595 var msgs appmgr.RtmData
597 instance := &models.XappInstance{
602 TxMessages: msgs.TxMessages,
603 RxMessages: msgs.RxMessages,
605 x.Instances = append(x.Instances, instance)
610 func mockedKubeExec(args string) (out []byte, err error) {
611 caughtKubeExecArgs = args
612 return []byte(kubeExecRetOut), kubeExecRetErr
615 func resetKubeExecMock() {
616 kubeExec = util.KubectlExec
617 caughtKubeExecArgs = ""
622 func mockedHelmExec(args string) (out []byte, err error) {
623 caughtHelmExecArgs = args
624 return []byte(helmExecRetOut), helmExecRetErr
627 func resetHelmExecMock() {
628 helmExec = util.HelmExec
629 caughtHelmExecArgs = ""
634 func validateXappModel(t *testing.T, xapp models.Xapp) {
635 expXapp := getXappData()
638 if *expXapp.Name != *xapp.Name || expXapp.Status != xapp.Status || expXapp.Version != xapp.Version {
639 t.Errorf("\n%v \n%v", *xapp.Name, *expXapp.Name)
642 if *expXapp.Instances[0].Name != *xapp.Instances[0].Name || expXapp.Instances[0].Status != xapp.Instances[0].Status {
643 t.Errorf("\n1:%v 2:%v", *expXapp.Instances[0].Name, *xapp.Instances[0].Name)
646 if expXapp.Instances[0].IP != xapp.Instances[0].IP || expXapp.Instances[0].Port != xapp.Instances[0].Port {
647 t.Errorf("\n%v - %v, %v - %v", expXapp.Instances[0].IP, xapp.Instances[0].IP, expXapp.Instances[0].Port, xapp.Instances[0].Port)