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"
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 helmExec = mockedHelmExec
159 expectedHelmCommand := "init -c --skip-refresh"
160 if caughtHelmExecArgs != expectedHelmCommand {
161 t.Errorf("Init failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
165 func TestAddRepoSuccess(t *testing.T) {
168 removeTestUsernameFile()
169 removeTestPasswordFile()
171 helmExec = mockedHelmExec
173 if err := writeTestUsernameFile(); err != nil {
174 t.Errorf("AddRepo username file create failed: %s", err)
177 if err := writeTestPasswordFile(); err != nil {
178 t.Errorf("AddRepo password file create failed: %s", err)
182 if _, err := NewHelm().AddRepo(); err != nil {
183 t.Errorf("AddRepo failed: %v", err)
186 if !strings.Contains(caughtHelmExecArgs, "repo add") {
187 t.Errorf("AddRepo failed: expected %v, got %v", "repo add", caughtHelmExecArgs)
191 func TestAddRepoReturnsErrorIfNoUsernameFile(t *testing.T) {
192 if _, err := NewHelm().AddRepo(); err == nil {
193 t.Errorf("AddRepo expected to fail but it didn't")
197 func TestAddRepoReturnsErrorIfNoPasswordFile(t *testing.T) {
198 defer func() { resetHelmExecMock(); removeTestUsernameFile() }()
199 helmExec = mockedHelmExec
201 if err := writeTestUsernameFile(); err != nil {
202 t.Errorf("AddRepo username file create failed: %s", err)
205 if _, err := NewHelm().AddRepo(); err == nil {
206 t.Errorf("AddRepo expected to fail but it didn't")
210 func TestInstallSuccess(t *testing.T) {
212 xappDesc := models.XappDescriptor{XappName: &name, Namespace: "ricxapp"}
214 defer func() { resetHelmExecMock() }()
215 helmExec = mockedHelmExec
216 helmExecRetOut = helmStatusOutput
218 defer func() { resetKubeExecMock() }()
219 kubeExec = mockedKubeExec
220 kubeExecRetOut = kubeServiceOutput
222 xapp, err := NewHelm().Install(xappDesc)
224 t.Errorf("Install failed: %v", err)
226 validateXappModel(t, xapp)
229 func TestInstallReturnsErrorIfHelmRepoUpdateFails(t *testing.T) {
231 xappDesc := models.XappDescriptor{XappName: &name, Namespace: "ricxapp"}
233 defer func() { resetHelmExecMock() }()
234 helmExec = mockedHelmExec
235 helmExecRetErr = errors.New("some helm command error")
237 if _, err := NewHelm().Install(xappDesc); err == nil {
238 t.Errorf("Install expected to fail but it didn't")
242 func TestStatusSuccess(t *testing.T) {
245 defer func() { resetHelmExecMock() }()
246 helmExec = mockedHelmExec
247 helmExecRetOut = helmStatusOutput
249 xapp, err := NewHelm().Status(name)
251 t.Errorf("Status failed: %v", err)
253 validateXappModel(t, xapp)
256 func TestStatusReturnsErrorIfHelmStatusFails(t *testing.T) {
259 defer func() { resetHelmExecMock() }()
260 helmExec = mockedHelmExec
261 helmExecRetErr = errors.New("some helm command error")
263 if _, err := NewHelm().Status(name); err == nil {
264 t.Errorf("Status expected to fail but it didn't")
268 func TestParseStatusSuccess(t *testing.T) {
269 defer func() { resetHelmExecMock() }()
270 helmExec = mockedHelmExec
271 helmExecRetOut = helListOutput
273 defer func() { resetKubeExecMock() }()
274 kubeExec = mockedKubeExec
275 kubeExecRetOut = kubeServiceOutput
277 xapp, err := NewHelm().ParseStatus("dummy-xapp", helmStatusOutput)
279 t.Errorf("ParseStatus failed: %v", err)
282 validateXappModel(t, xapp)
284 expectedHelmCommand := "list --deployed --output yaml --namespace=ricxapp dummy-xapp"
285 if caughtHelmExecArgs != expectedHelmCommand {
286 t.Errorf("ParseStatus failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
290 func TestListSuccess(t *testing.T) {
291 defer func() { resetHelmExecMock() }()
292 helmExec = mockedHelmExec
293 helmExecRetOut = helListAllOutput
295 names, err := NewHelm().List()
297 t.Errorf("List failed: %v", err)
300 if !reflect.DeepEqual(names, []string{"dummy-xapp", "dummy-xapp2"}) {
301 t.Errorf("List failed: %v", err)
303 expectedHelmCommand := "list --all --deployed --output yaml --namespace=ricxapp"
304 if caughtHelmExecArgs != expectedHelmCommand {
305 t.Errorf("List: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
309 func TestListReturnsErrorIfHelmListFails(t *testing.T) {
310 defer func() { resetHelmExecMock() }()
311 helmExec = mockedHelmExec
312 helmExecRetErr = errors.New("some helm command error")
314 if _, err := NewHelm().List(); err == nil {
315 t.Errorf("List expected to fail but it didn't")
319 func TestDeleteSuccess(t *testing.T) {
322 defer func() { resetHelmExecMock() }()
323 helmExec = mockedHelmExec
324 helmExecRetOut = helmStatusOutput
326 defer func() { resetKubeExecMock() }()
327 kubeExec = mockedKubeExec
328 kubeExecRetOut = kubeServiceOutput
330 xapp, err := NewHelm().Delete(name)
332 t.Errorf("Delete failed: %v", err)
335 validateXappModel(t, xapp)
337 expectedHelmCommand := "del --purge dummy-xapp"
338 if caughtHelmExecArgs != expectedHelmCommand {
339 t.Errorf("Delete failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
343 func TestDeleteReturnsErrorIfHelmStatusFails(t *testing.T) {
346 defer func() { resetHelmExecMock() }()
347 helmExec = mockedHelmExec
348 helmExecRetErr = errors.New("some helm command error")
350 if _, err := NewHelm().Delete(name); err == nil {
351 t.Errorf("Delete expected to fail but it didn't")
355 func TestFetchSuccessIfCmdArgHasTestSuffix(t *testing.T) {
356 if err := NewHelm().Fetch("kissa", "koira"); err != nil {
357 t.Errorf("Fetch failed: %v", err)
361 func TestGetVersionSuccess(t *testing.T) {
362 defer func() { resetHelmExecMock() }()
363 helmExec = mockedHelmExec
364 helmExecRetOut = helListOutput
366 if version := NewHelm().GetVersion("dummy-xapp"); version != "1.0" {
367 t.Errorf("GetVersion failed: expected 1.0, got %v", version)
370 expectedHelmCommand := "list --deployed --output yaml --namespace=ricxapp dummy-xapp"
371 if caughtHelmExecArgs != expectedHelmCommand {
372 t.Errorf("GetVersion failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
376 func TestGetVersionReturnsEmptyStringIfHelmListFails(t *testing.T) {
377 defer func() { resetHelmExecMock() }()
378 helmExec = mockedHelmExec
379 helmExecRetErr = errors.New("some helm command error")
381 if version := NewHelm().GetVersion("dummy-xapp"); version != "" {
382 t.Errorf("GetVersion expected to return empty string, got %v", version)
386 func TestGetAddressSuccess(t *testing.T) {
387 ip, port := NewHelm().GetAddress(helmStatusOutput)
388 if ip != "10.102.184.212" {
389 t.Errorf("GetAddress failed: expected 10.102.184.212, got %v", ip)
391 if port != "80/TCP" {
392 t.Errorf("GetAddress failed: expected 80/TCP, got %v", port)
396 func TestGetEndpointInfoSuccess(t *testing.T) {
397 defer func() { resetKubeExecMock() }()
398 kubeExec = mockedKubeExec
399 kubeExecRetOut = kubeServiceOutput
401 svc, port := NewHelm().GetEndpointInfo("dummy-xapp")
402 expectedSvc := "service-ricxapp-dummy-xapp-rmr.ricxapp"
403 if svc != expectedSvc {
404 t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedSvc, svc)
407 t.Errorf("GetEndpointInfo failed: expected port 4560, got %v", port)
409 expectedKubeCommand := " get service -n ricxapp service-ricxapp-dummy-xapp-rmr -o json"
410 if caughtKubeExecArgs != expectedKubeCommand {
411 t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedKubeCommand, caughtKubeExecArgs)
415 func TestGetEndpointInfoReturnsDefaultPortIfJsonParseFails(t *testing.T) {
416 defer func() { resetKubeExecMock() }()
417 kubeExec = mockedKubeExec
418 kubeExecRetOut = "not-json-syntax"
420 svc, port := NewHelm().GetEndpointInfo("dummy-xapp")
421 expectedSvc := "service-ricxapp-dummy-xapp-rmr.ricxapp"
422 if svc != expectedSvc {
423 t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedSvc, svc)
426 t.Errorf("GetEndpointInfo failed: expected port 4560, got %v", port)
430 func TestGetEndpointInfoReturnsDefaultPortIfKubeGetServiceFails(t *testing.T) {
431 defer func() { resetKubeExecMock() }()
432 kubeExec = mockedKubeExec
433 kubeExecRetErr = errors.New("some helm command error")
435 svc, port := NewHelm().GetEndpointInfo("dummy-xapp")
436 expectedSvc := "service-ricxapp-dummy-xapp-rmr.ricxapp"
437 if svc != expectedSvc {
438 t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedSvc, svc)
441 t.Errorf("GetEndpointInfo failed: expected port 4560, got %v", port)
445 func TestHelmStatusAllSuccess(t *testing.T) {
446 defer func() { resetHelmExecMock() }()
447 helmExec = mockedHelmExec
448 helmExecRetOut = helListAllOutput
450 if _, err := NewHelm().StatusAll(); err != nil {
451 t.Errorf("StatusAll failed: %v", err)
453 // Todo: check StatusAll response content
456 func TestStatusAllReturnsErrorIfHelmListFails(t *testing.T) {
457 defer func() { resetHelmExecMock() }()
458 helmExec = mockedHelmExec
459 helmExecRetErr = errors.New("some helm command error")
461 if _, err := NewHelm().StatusAll(); err == nil {
462 t.Errorf("StatusAll expected to fail but it didn't")
466 func TestGetNamesSuccess(t *testing.T) {
467 names, err := NewHelm().GetNames(helListAllOutput)
469 t.Errorf("GetNames failed: %v", err)
471 if !reflect.DeepEqual(names, []string{"dummy-xapp", "dummy-xapp2"}) {
472 t.Errorf("GetNames failed: %v", err)
476 func TestAddTillerEnv(t *testing.T) {
477 if NewHelm().AddTillerEnv() != nil {
478 t.Errorf("AddTillerEnv failed!")
482 func TestGetInstallArgs(t *testing.T) {
484 x := models.XappDescriptor{XappName: &name, Namespace: "ricxapp"}
486 expectedArgs := "install helm-repo/dummy-xapp --namespace=ricxapp --name=dummy-xapp"
487 if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
488 t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
491 expectedArgs += " --set ricapp.appconfig.override=dummy-xapp-appconfig"
492 if args := NewHelm().GetInstallArgs(x, true); args != expectedArgs {
493 t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
496 x.HelmVersion = "1.2.3"
497 expectedArgs = "install helm-repo/dummy-xapp --namespace=ricxapp --version=1.2.3 --name=dummy-xapp"
498 if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
499 t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
502 x.ReleaseName = "ueec-xapp"
503 expectedArgs = "install helm-repo/dummy-xapp --namespace=ricxapp --version=1.2.3 --name=ueec-xapp"
504 if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
505 t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
508 x.OverrideFile = "../../test/dummy-xapp_values.json"
509 expectedArgs += " -f=/tmp/appmgr_override.yaml"
510 if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
511 t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
515 func writeTestUsernameFile() error {
516 f, err := os.Create(viper.GetString("helm.helm-username-file"))
520 _, err = f.WriteString("some-username")
525 func removeTestUsernameFile() error {
526 return os.Remove(viper.GetString("helm.helm-username-file"))
529 func writeTestPasswordFile() (err error) {
530 f, err := os.Create(viper.GetString("helm.helm-password-file"))
535 _, err = f.WriteString("some-password")
540 func removeTestPasswordFile() error {
541 return os.Remove(viper.GetString("helm.helm-password-file"))
544 func getXappData() (x models.Xapp) {
545 //name1 := "dummy-xapp-8984fc9fd-l6xch"
546 //name2 := "dummy-xapp-8984fc9fd-pp4hg"
547 x = generateXapp("dummy-xapp", "deployed", "1.0", "dummy-xapp-8984fc9fd-bkcbp", "running", "service-ricxapp-dummy-xapp-rmr.ricxapp", "4560")
548 //x.Instances = append(x.Instances, x.Instances[0])
549 //x.Instances = append(x.Instances, x.Instances[0])
550 //x.Instances[1].Name = &name1
551 //x.Instances[2].Name = &name2
556 func generateXapp(name, status, ver, iname, istatus, ip, port string) (x models.Xapp) {
560 p, _ := strconv.Atoi(port)
561 var msgs appmgr.RtmData
563 instance := &models.XappInstance{
568 TxMessages: msgs.TxMessages,
569 RxMessages: msgs.RxMessages,
571 x.Instances = append(x.Instances, instance)
576 func mockedKubeExec(args string) (out []byte, err error) {
577 caughtKubeExecArgs = args
578 return []byte(kubeExecRetOut), kubeExecRetErr
581 func resetKubeExecMock() {
582 kubeExec = util.KubectlExec
583 caughtKubeExecArgs = ""
588 func mockedHelmExec(args string) (out []byte, err error) {
589 caughtHelmExecArgs = args
590 return []byte(helmExecRetOut), helmExecRetErr
593 func resetHelmExecMock() {
594 helmExec = util.HelmExec
595 caughtHelmExecArgs = ""
600 func validateXappModel(t *testing.T, xapp models.Xapp) {
601 expXapp := getXappData()
604 if *expXapp.Name != *xapp.Name || expXapp.Status != xapp.Status || expXapp.Version != xapp.Version {
605 t.Errorf("\n%v \n%v", *xapp.Name, *expXapp.Name)
608 if *expXapp.Instances[0].Name != *xapp.Instances[0].Name || expXapp.Instances[0].Status != xapp.Instances[0].Status {
609 t.Errorf("\n1:%v 2:%v", *expXapp.Instances[0].Name, *xapp.Instances[0].Name)
612 if expXapp.Instances[0].IP != xapp.Instances[0].IP || expXapp.Instances[0].Port != xapp.Instances[0].Port {
613 t.Errorf("\n%v - %v, %v - %v", expXapp.Instances[0].IP, xapp.Instances[0].IP, expXapp.Instances[0].Port, xapp.Instances[0].Port)