Improve appmgr UT coverage
[ric-plt/appmgr.git] / pkg / helm / helm_test.go
index 109103c..1bfdb22 100755 (executable)
 package helm
 
 import (
+       "errors"
+       "github.com/spf13/viper"
        "os"
        "reflect"
        "strconv"
+       "strings"
        "testing"
 
        "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
@@ -30,6 +33,12 @@ import (
        "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/util"
 )
 
+var caughtKubeExecArgs string
+var kubeExecRetOut string
+var kubeExecRetErr error
+var caughtHelmExecArgs string
+var helmExecRetOut string
+var helmExecRetErr error
 var helmStatusOutput = `
 LAST DEPLOYED: Sat Mar  9 06:50:45 2019
 NAMESPACE: default
@@ -51,7 +60,7 @@ NAME        READY  UP-TO-DATE  AVAILABLE  AGE
 dummy-xapp  3/3    3           3          55m
 `
 
-var helListOutput = `Next: ""
+var helListAllOutput = `Next: ""
 Releases:
 - AppVersion: "1.0"
   Chart: dummy-xapp-chart-0.1.0
@@ -76,7 +85,18 @@ Releases:
   Updated: Sun Mar 24 07:17:00 2019
   `
 
-var helmServiceOutput = `{
+var helListOutput = `Next: ""
+Releases:
+- AppVersion: "1.0"
+  Chart: dummy-xapp-chart-0.1.0
+  Name: dummy-xapp
+  Namespace: default
+  Revision: 1
+  Status: DEPLOYED
+  Updated: Mon Mar 11 06:55:05 2019
+  `
+
+var kubeServiceOutput = `{
     "apiVersion": "v1",
     "kind": "Service",
     "metadata": {
@@ -130,44 +150,332 @@ func TestMain(m *testing.M) {
        os.Exit(code)
 }
 
-func TestHelmStatus(t *testing.T) {
-       util.KubectlExec = func(args string) (out []byte, err error) {
-               return []byte(helmServiceOutput), nil
+func TestInit(t *testing.T) {
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+
+       NewHelm().Init()
+
+       expectedHelmCommand := "init -c --skip-refresh"
+       if caughtHelmExecArgs != expectedHelmCommand {
+               t.Errorf("Init failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
+       }
+}
+
+func TestAddRepoSuccess(t *testing.T) {
+       defer func() {
+               resetHelmExecMock()
+               removeTestUsernameFile()
+               removeTestPasswordFile()
+       }()
+       helmExec = mockedHelmExec
+
+       if err := writeTestUsernameFile(); err != nil {
+               t.Errorf("AddRepo username file create failed: %s", err)
+               return
+       }
+       if err := writeTestPasswordFile(); err != nil {
+               t.Errorf("AddRepo password file create failed: %s", err)
+               return
+       }
+
+       if _, err := NewHelm().AddRepo(); err != nil {
+               t.Errorf("AddRepo failed: %v", err)
+       }
+
+       if !strings.Contains(caughtHelmExecArgs, "repo add") {
+               t.Errorf("AddRepo failed: expected %v, got %v", "repo add", caughtHelmExecArgs)
+       }
+}
+
+func TestAddRepoReturnsErrorIfNoUsernameFile(t *testing.T) {
+       if _, err := NewHelm().AddRepo(); err == nil {
+               t.Errorf("AddRepo expected to fail but it didn't")
        }
+}
+
+func TestAddRepoReturnsErrorIfNoPasswordFile(t *testing.T) {
+       defer func() { resetHelmExecMock(); removeTestUsernameFile() }()
+       helmExec = mockedHelmExec
+
+       if err := writeTestUsernameFile(); err != nil {
+               t.Errorf("AddRepo username file create failed: %s", err)
+               return
+       }
+       if _, err := NewHelm().AddRepo(); err == nil {
+               t.Errorf("AddRepo expected to fail but it didn't")
+       }
+}
+
+func TestInstallSuccess(t *testing.T) {
+       name := "dummy-xapp"
+       xappDesc := models.XappDescriptor{XappName: &name, Namespace: "ricxapp"}
+
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetOut = helmStatusOutput
+
+       defer func() { resetKubeExecMock() }()
+       kubeExec = mockedKubeExec
+       kubeExecRetOut = kubeServiceOutput
+
+       xapp, err := NewHelm().Install(xappDesc)
+       if err != nil {
+               t.Errorf("Install failed: %v", err)
+       }
+       validateXappModel(t, xapp)
+}
+
+func TestInstallReturnsErrorIfHelmRepoUpdateFails(t *testing.T) {
+       name := "dummy-xapp"
+       xappDesc := models.XappDescriptor{XappName: &name, Namespace: "ricxapp"}
+
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetErr = errors.New("some helm command error")
+
+       if _, err := NewHelm().Install(xappDesc); err == nil {
+               t.Errorf("Install expected to fail but it didn't")
+       }
+}
+
+func TestStatusSuccess(t *testing.T) {
+       name := "dummy-xapp"
+
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetOut = helmStatusOutput
+
+       xapp, err := NewHelm().Status(name)
+       if err != nil {
+               t.Errorf("Status failed: %v", err)
+       }
+       validateXappModel(t, xapp)
+}
+
+func TestStatusReturnsErrorIfHelmStatusFails(t *testing.T) {
+       name := "dummy-xapp"
+
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetErr = errors.New("some helm command error")
+
+       if _, err := NewHelm().Status(name); err == nil {
+               t.Errorf("Status expected to fail but it didn't")
+       }
+}
+
+func TestParseStatusSuccess(t *testing.T) {
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetOut = helListOutput
+
+       defer func() { resetKubeExecMock() }()
+       kubeExec = mockedKubeExec
+       kubeExecRetOut = kubeServiceOutput
+
        xapp, err := NewHelm().ParseStatus("dummy-xapp", helmStatusOutput)
        if err != nil {
-               t.Errorf("Helm install failed: %v", err)
+               t.Errorf("ParseStatus failed: %v", err)
        }
-       x := getXappData()
-       xapp.Version = "1.0"
 
-       if *x.Name != *xapp.Name || x.Status != xapp.Status || x.Version != xapp.Version {
-               t.Errorf("\n%v \n%v", *xapp.Name, *x.Name)
+       validateXappModel(t, xapp)
+
+       expectedHelmCommand := "list --deployed --output yaml --namespace=ricxapp dummy-xapp"
+       if caughtHelmExecArgs != expectedHelmCommand {
+               t.Errorf("ParseStatus failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
+       }
+}
+
+func TestListSuccess(t *testing.T) {
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetOut = helListAllOutput
+
+       names, err := NewHelm().List()
+       if err != nil {
+               t.Errorf("List failed: %v", err)
        }
 
-       if *x.Instances[0].Name != *xapp.Instances[0].Name || x.Instances[0].Status != xapp.Instances[0].Status {
-               t.Errorf("\n1:%v 2:%v", *x.Instances[0].Name, *xapp.Instances[0].Name)
+       if !reflect.DeepEqual(names, []string{"dummy-xapp", "dummy-xapp2"}) {
+               t.Errorf("List failed: %v", err)
+       }
+       expectedHelmCommand := "list --all --deployed --output yaml --namespace=ricxapp"
+       if caughtHelmExecArgs != expectedHelmCommand {
+               t.Errorf("List: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
        }
+}
+
+func TestListReturnsErrorIfHelmListFails(t *testing.T) {
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetErr = errors.New("some helm command error")
 
-       if x.Instances[0].IP != xapp.Instances[0].IP || x.Instances[0].Port != xapp.Instances[0].Port {
-               t.Errorf("\n%v - %v, %v - %v", x.Instances[0].IP, xapp.Instances[0].IP, x.Instances[0].Port, xapp.Instances[0].Port)
+       if _, err := NewHelm().List(); err == nil {
+               t.Errorf("List expected to fail but it didn't")
        }
 }
 
-func TestHelmLists(t *testing.T) {
-       names, err := NewHelm().GetNames(helListOutput)
+func TestDeleteSuccess(t *testing.T) {
+       name := "dummy-xapp"
+
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetOut = helmStatusOutput
+
+       defer func() { resetKubeExecMock() }()
+       kubeExec = mockedKubeExec
+       kubeExecRetOut = kubeServiceOutput
+
+       xapp, err := NewHelm().Delete(name)
        if err != nil {
-               t.Errorf("Helm status failed: %v", err)
+               t.Errorf("Delete failed: %v", err)
+       }
+
+       validateXappModel(t, xapp)
+
+       expectedHelmCommand := "del --purge dummy-xapp"
+       if caughtHelmExecArgs != expectedHelmCommand {
+               t.Errorf("Delete failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
        }
+}
+
+func TestDeleteReturnsErrorIfHelmStatusFails(t *testing.T) {
+       name := "dummy-xapp"
 
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetErr = errors.New("some helm command error")
+
+       if _, err := NewHelm().Delete(name); err == nil {
+               t.Errorf("Delete expected to fail but it didn't")
+       }
+}
+
+func TestFetchSuccessIfCmdArgHasTestSuffix(t *testing.T) {
+       if err := NewHelm().Fetch("kissa", "koira"); err != nil {
+               t.Errorf("Fetch failed: %v", err)
+       }
+}
+
+func TestGetVersionSuccess(t *testing.T) {
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetOut = helListOutput
+
+       if version := NewHelm().GetVersion("dummy-xapp"); version != "1.0" {
+               t.Errorf("GetVersion failed: expected 1.0, got %v", version)
+       }
+
+       expectedHelmCommand := "list --deployed --output yaml --namespace=ricxapp dummy-xapp"
+       if caughtHelmExecArgs != expectedHelmCommand {
+               t.Errorf("GetVersion failed: expected %v, got %v", expectedHelmCommand, caughtHelmExecArgs)
+       }
+}
+
+func TestGetVersionReturnsEmptyStringIfHelmListFails(t *testing.T) {
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetErr = errors.New("some helm command error")
+
+       if version := NewHelm().GetVersion("dummy-xapp"); version != "" {
+               t.Errorf("GetVersion expected to return empty string, got %v", version)
+       }
+}
+
+func TestGetAddressSuccess(t *testing.T) {
+       ip, port := NewHelm().GetAddress(helmStatusOutput)
+       if ip != "10.102.184.212" {
+               t.Errorf("GetAddress failed: expected 10.102.184.212, got %v", ip)
+       }
+       if port != "80/TCP" {
+               t.Errorf("GetAddress failed: expected 80/TCP, got %v", port)
+       }
+}
+
+func TestGetEndpointInfoSuccess(t *testing.T) {
+       defer func() { resetKubeExecMock() }()
+       kubeExec = mockedKubeExec
+       kubeExecRetOut = kubeServiceOutput
+
+       svc, port := NewHelm().GetEndpointInfo("dummy-xapp")
+       expectedSvc := "service-ricxapp-dummy-xapp-rmr.ricxapp"
+       if svc != expectedSvc {
+               t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedSvc, svc)
+       }
+       if port != 4560 {
+               t.Errorf("GetEndpointInfo failed: expected port 4560, got %v", port)
+       }
+       expectedKubeCommand := " get service -n ricxapp service-ricxapp-dummy-xapp-rmr -o json"
+       if caughtKubeExecArgs != expectedKubeCommand {
+               t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedKubeCommand, caughtKubeExecArgs)
+       }
+}
+
+func TestGetEndpointInfoReturnsDefaultPortIfJsonParseFails(t *testing.T) {
+       defer func() { resetKubeExecMock() }()
+       kubeExec = mockedKubeExec
+       kubeExecRetOut = "not-json-syntax"
+
+       svc, port := NewHelm().GetEndpointInfo("dummy-xapp")
+       expectedSvc := "service-ricxapp-dummy-xapp-rmr.ricxapp"
+       if svc != expectedSvc {
+               t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedSvc, svc)
+       }
+       if port != 4560 {
+               t.Errorf("GetEndpointInfo failed: expected port 4560, got %v", port)
+       }
+}
+
+func TestGetEndpointInfoReturnsDefaultPortIfKubeGetServiceFails(t *testing.T) {
+       defer func() { resetKubeExecMock() }()
+       kubeExec = mockedKubeExec
+       kubeExecRetErr = errors.New("some helm command error")
+
+       svc, port := NewHelm().GetEndpointInfo("dummy-xapp")
+       expectedSvc := "service-ricxapp-dummy-xapp-rmr.ricxapp"
+       if svc != expectedSvc {
+               t.Errorf("GetEndpointInfo failed: expected %v, got %v", expectedSvc, svc)
+       }
+       if port != 4560 {
+               t.Errorf("GetEndpointInfo failed: expected port 4560, got %v", port)
+       }
+}
+
+func TestHelmStatusAllSuccess(t *testing.T) {
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetOut = helListAllOutput
+
+       if _, err := NewHelm().StatusAll(); err != nil {
+               t.Errorf("StatusAll failed: %v", err)
+       }
+       // Todo: check StatusAll response content
+}
+
+func TestStatusAllReturnsErrorIfHelmListFails(t *testing.T) {
+       defer func() { resetHelmExecMock() }()
+       helmExec = mockedHelmExec
+       helmExecRetErr = errors.New("some helm command error")
+
+       if _, err := NewHelm().StatusAll(); err == nil {
+               t.Errorf("StatusAll expected to fail but it didn't")
+       }
+}
+
+func TestGetNamesSuccess(t *testing.T) {
+       names, err := NewHelm().GetNames(helListAllOutput)
+       if err != nil {
+               t.Errorf("GetNames failed: %v", err)
+       }
        if !reflect.DeepEqual(names, []string{"dummy-xapp", "dummy-xapp2"}) {
-               t.Errorf("Helm status failed: %v", err)
+               t.Errorf("GetNames failed: %v", err)
        }
 }
 
 func TestAddTillerEnv(t *testing.T) {
        if NewHelm().AddTillerEnv() != nil {
-               t.Errorf("TestAddTillerEnv failed!")
+               t.Errorf("AddTillerEnv failed!")
        }
 }
 
@@ -177,22 +485,62 @@ func TestGetInstallArgs(t *testing.T) {
 
        expectedArgs := "install helm-repo/dummy-xapp  --namespace=ricxapp --name=dummy-xapp"
        if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
-               t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
+               t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
+       }
+
+       expectedArgs += " --set ricapp.appconfig.override=dummy-xapp-appconfig"
+       if args := NewHelm().GetInstallArgs(x, true); args != expectedArgs {
+               t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
        }
 
        x.HelmVersion = "1.2.3"
        expectedArgs = "install helm-repo/dummy-xapp  --namespace=ricxapp --version=1.2.3 --name=dummy-xapp"
        if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
-               t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
+               t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
        }
 
        x.ReleaseName = "ueec-xapp"
        expectedArgs = "install helm-repo/dummy-xapp  --namespace=ricxapp --version=1.2.3 --name=ueec-xapp"
        if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
-               t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
+               t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
+       }
+
+       x.OverrideFile = "../../test/dummy-xapp_values.json"
+       expectedArgs += " -f=/tmp/appmgr_override.yaml"
+       if args := NewHelm().GetInstallArgs(x, false); args != expectedArgs {
+               t.Errorf("GetInstallArgs failed: expected %v, got %v", expectedArgs, args)
        }
 }
 
+func writeTestUsernameFile() error {
+       f, err := os.Create(viper.GetString("helm.helm-username-file"))
+       if err != nil {
+               return err
+       }
+       _, err = f.WriteString("some-username")
+       f.Close()
+       return err
+}
+
+func removeTestUsernameFile() error {
+       return os.Remove(viper.GetString("helm.helm-username-file"))
+}
+
+func writeTestPasswordFile() (err error) {
+       f, err := os.Create(viper.GetString("helm.helm-password-file"))
+       if err != nil {
+               return err
+       }
+
+       _, err = f.WriteString("some-password")
+       f.Close()
+       return err
+}
+
+func removeTestPasswordFile() error {
+       return os.Remove(viper.GetString("helm.helm-password-file"))
+}
+
 func getXappData() (x models.Xapp) {
        //name1 := "dummy-xapp-8984fc9fd-l6xch"
        //name2 := "dummy-xapp-8984fc9fd-pp4hg"
@@ -224,3 +572,44 @@ func generateXapp(name, status, ver, iname, istatus, ip, port string) (x models.
 
        return
 }
+
+func mockedKubeExec(args string) (out []byte, err error) {
+       caughtKubeExecArgs = args
+       return []byte(kubeExecRetOut), kubeExecRetErr
+}
+
+func resetKubeExecMock() {
+       kubeExec = util.KubectlExec
+       caughtKubeExecArgs = ""
+       kubeExecRetOut = ""
+       kubeExecRetErr = nil
+}
+
+func mockedHelmExec(args string) (out []byte, err error) {
+       caughtHelmExecArgs = args
+       return []byte(helmExecRetOut), helmExecRetErr
+}
+
+func resetHelmExecMock() {
+       helmExec = util.HelmExec
+       caughtHelmExecArgs = ""
+       helmExecRetOut = ""
+       helmExecRetErr = nil
+}
+
+func validateXappModel(t *testing.T, xapp models.Xapp) {
+       expXapp := getXappData()
+       xapp.Version = "1.0"
+
+       if *expXapp.Name != *xapp.Name || expXapp.Status != xapp.Status || expXapp.Version != xapp.Version {
+               t.Errorf("\n%v \n%v", *xapp.Name, *expXapp.Name)
+       }
+
+       if *expXapp.Instances[0].Name != *xapp.Instances[0].Name || expXapp.Instances[0].Status != xapp.Instances[0].Status {
+               t.Errorf("\n1:%v 2:%v", *expXapp.Instances[0].Name, *xapp.Instances[0].Name)
+       }
+
+       if expXapp.Instances[0].IP != xapp.Instances[0].IP || expXapp.Instances[0].Port != xapp.Instances[0].Port {
+               t.Errorf("\n%v - %v, %v - %v", expXapp.Instances[0].IP, xapp.Instances[0].IP, expXapp.Instances[0].Port, xapp.Instances[0].Port)
+       }
+}