Improve appmgr UT coverage

Improve existing unit tests coverage for appmgr's 'cm', 'helm' and 'resthooks'
packages.
Fix also 'helm install' command's overwrite configuration '---set' flag to be
'--set'.

Signed-off-by: Timo Tietavainen <timo.tietavainen@nokia.com>
Change-Id: I2a2f13575fc10191c7ee1fe21e8d3ec344cb71cc
diff --git a/pkg/cm/cm_test.go b/pkg/cm/cm_test.go
index 01f5bc5..b180fc9 100755
--- a/pkg/cm/cm_test.go
+++ b/pkg/cm/cm_test.go
@@ -24,6 +24,7 @@
 	"errors"
 	"os"
 	"reflect"
+	"strings"
 	"testing"
 
 	"gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
@@ -31,6 +32,26 @@
 	"gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/util"
 )
 
+const (
+	expectedHelmSearchCmd = "search helm-repo"
+	expectedHelmFetchCmd  = `fetch --untar --untardir /tmp helm-repo/dummy-xapp`
+)
+
+var caughtKubeExecArgs []string
+var kubeExecRetOut string
+var kubeExecRetErr error
+var caughtHelmExecArgs string
+var helmExecRetOut string
+var helmExecRetErr error
+
+var expectedKubectlGetCmd []string = []string{
+	`get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp  configmap-ricxapp-anr-appconfig`,
+	`get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp  configmap-ricxapp-appmgr-appconfig`,
+	`get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp  configmap-ricxapp-dualco-appconfig`,
+	`get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp  configmap-ricxapp-reporter-appconfig`,
+	`get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp  configmap-ricxapp-uemgr-appconfig`,
+}
+
 var helmSearchOutput = `
 helm-repo/anr           0.0.1           1.0             Helm Chart for Nokia ANR (Automatic Neighbour Relation) xAPP
 helm-repo/appmgr        0.0.2           1.0             Helm Chart for xAppManager
@@ -62,6 +83,15 @@
     }
 }
 `
+var cfgData = `{
+	"active":true,
+	"interfaceId": {
+		"globalENBId":{
+			"plmnId": "1234",
+			"eNBId":"55"
+		}
+	}
+}`
 
 type ConfigSample struct {
 	Level int
@@ -112,20 +142,181 @@
 	os.Exit(code)
 }
 
-func TestGetRtmData(t *testing.T) {
+func TestUploadConfigAllSuccess(t *testing.T) {
+	var cfg interface{}
+	var expectedResult models.AllXappConfig
+	ns := "ricxapp"
+	xapps := []string{"anr", "appmgr", "dualco", "reporter", "uemgr"}
+
+	if ret := json.Unmarshal([]byte(cfgData), &cfg); ret != nil {
+		t.Errorf("UploadConfigAll Json unmarshal failed: %v", ret)
+	}
+
+	for i, _ := range xapps {
+		expectedResult = append(expectedResult,
+			&models.XAppConfig{
+				Config: cfg,
+				Metadata: &models.ConfigMetadata{
+					Namespace: &ns,
+					XappName:  &xapps[i],
+				},
+			},
+		)
+	}
+
+	defer func() { resetHelmExecMock() }()
+	helmExec = mockedHelmExec
+	//Fake helm search success
+	helmExecRetOut = helmSearchOutput
+
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl get configmap' success
+	kubeExecRetOut = strings.ReplaceAll(cfgData, "\\", "")
+
+	result := NewCM().UploadConfigAll()
+	if !reflect.DeepEqual(result, expectedResult) {
+		t.Errorf("UploadConfigAll failed: expected: %v, got: %v", expectedResult, result)
+	}
+	if caughtHelmExecArgs != expectedHelmSearchCmd {
+		t.Errorf("UploadConfigAll failed: expected: %v, got: %v", expectedHelmSearchCmd, caughtHelmExecArgs)
+	}
+	if !reflect.DeepEqual(caughtKubeExecArgs, expectedKubectlGetCmd) {
+		t.Errorf("UploadConfigAll failed: expected: %v, got: %v", expectedKubectlGetCmd, caughtKubeExecArgs)
+	}
+}
+
+func TestUploadConfigAllReturnsEmptyMapIfAllConfigMapReadsFail(t *testing.T) {
+	var expectedResult models.AllXappConfig
+
+	defer func() { resetHelmExecMock() }()
+	helmExec = mockedHelmExec
+	//Fake helm search success
+	helmExecRetOut = helmSearchOutput
+
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl get configmap' failure
+	kubeExecRetErr = errors.New("some error")
+
+	result := NewCM().UploadConfigAll()
+	if !reflect.DeepEqual(result, expectedResult) {
+		t.Errorf("UploadConfigAll failed: expected: %v, got: %v", expectedResult, result)
+	}
+}
+
+func TestUploadConfigElementSuccess(t *testing.T) {
+	var cfg interface{}
+	var expectedResult models.AllXappConfig
+	ns := "ricxapp"
+	xapps := []string{"anr", "appmgr", "dualco", "reporter", "uemgr"}
+
+	if ret := json.Unmarshal([]byte(cfgData), &cfg); ret != nil {
+		t.Errorf("UploadConfigElement Json unmarshal failed: %v", ret)
+	}
+
+	for i, _ := range xapps {
+		expectedResult = append(expectedResult,
+			&models.XAppConfig{
+				Config: cfg.(map[string]interface{})["active"],
+				Metadata: &models.ConfigMetadata{
+					Namespace: &ns,
+					XappName:  &xapps[i],
+				},
+			},
+		)
+	}
+
+	defer func() { resetHelmExecMock() }()
+	helmExec = mockedHelmExec
+	//Fake helm search success
+	helmExecRetOut = helmSearchOutput
+
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl get configmap' success
+	kubeExecRetOut = strings.ReplaceAll(cfgData, "\\", "")
+
+	result := NewCM().UploadConfigElement("active")
+	if !reflect.DeepEqual(result, expectedResult) {
+		t.Errorf("UploadConfigElement failed: expected: %v, got: %v", expectedResult, result)
+	}
+	if caughtHelmExecArgs != expectedHelmSearchCmd {
+		t.Errorf("UploadConfigElement failed: expected: %v, got: %v", expectedHelmSearchCmd, caughtHelmExecArgs)
+	}
+	if !reflect.DeepEqual(caughtKubeExecArgs, expectedKubectlGetCmd) {
+		t.Errorf("UploadConfigElement failed: expected: %v, got: %v", expectedKubectlGetCmd, caughtKubeExecArgs)
+	}
+}
+
+func TestUploadConfigElementReturnsEmptyMapIfElementMissingFromConfigMap(t *testing.T) {
+	var expectedResult models.AllXappConfig
+
+	defer func() { resetHelmExecMock() }()
+	helmExec = mockedHelmExec
+	//Fake helm search success
+	helmExecRetOut = helmSearchOutput
+
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl get configmap' success
+	kubeExecRetOut = strings.ReplaceAll(cfgData, "\\", "")
+
+	//Try to upload non-existing configuration element
+	result := NewCM().UploadConfigElement("some-not-existing-element")
+	if !reflect.DeepEqual(result, expectedResult) {
+		t.Errorf("UploadConfigElement failed: expected: %v, got: %v", expectedResult, result)
+	}
+}
+
+func TestGetRtmDataSuccess(t *testing.T) {
+	expectedKubeCmd := []string{
+		`get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp  configmap-ricxapp-dummy-xapp-appconfig`,
+	}
 	expectedMsgs := appmgr.RtmData{
 		TxMessages: []string{"RIC_X2_LOAD_INFORMATION"},
 		RxMessages: []string{"RIC_X2_LOAD_INFORMATION"},
 		Policies:   []int64{11, 22, 33},
 	}
 
-	util.KubectlExec = func(args string) (out []byte, err error) {
-		return []byte(kubectlConfigmapOutput), nil
-	}
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl get configmap' success
+	kubeExecRetOut = kubectlConfigmapOutput
 
 	result := NewCM().GetRtmData("dummy-xapp")
 	if !reflect.DeepEqual(result, expectedMsgs) {
-		t.Errorf("TestGetRtmData failed: expected: %v, got: %v", expectedMsgs, result)
+		t.Errorf("GetRtmData failed: expected: %v, got: %v", expectedMsgs, result)
+	}
+	if !reflect.DeepEqual(caughtKubeExecArgs, expectedKubeCmd) {
+		t.Errorf("GetRtmData failed: expected: '%v', got: '%v'", expectedKubeCmd, caughtKubeExecArgs)
+	}
+}
+
+func TestGetRtmDataReturnsNoDataIfConfigmapGetFails(t *testing.T) {
+	var expectedMsgs appmgr.RtmData
+
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl get configmap' failure
+	kubeExecRetErr = errors.New("some error")
+
+	result := NewCM().GetRtmData("dummy-xapp")
+	if !reflect.DeepEqual(result, expectedMsgs) {
+		t.Errorf("GetRtmData failed: expected: %v, got: %v", expectedMsgs, result)
+	}
+}
+
+func TestGetRtmDataReturnsNoDataIfJsonParseFails(t *testing.T) {
+	var expectedMsgs appmgr.RtmData
+
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl get configmap' to return nothing what will cause JSON parse failure
+
+	result := NewCM().GetRtmData("dummy-xapp")
+	if !reflect.DeepEqual(result, expectedMsgs) {
+		t.Errorf("GetRtmData failed: expected: %v, got: %v", expectedMsgs, result)
 	}
 }
 
@@ -146,32 +337,50 @@
 }
 
 func TestFetchChartSuccess(t *testing.T) {
-	util.HelmExec = func(args string) (out []byte, err error) {
-		return
-	}
+	defer func() { resetHelmExecMock() }()
+	helmExec = mockedHelmExec
 
 	if NewCM().FetchChart("dummy-xapp") != nil {
 		t.Errorf("TestFetchChart failed!")
 	}
 }
 
+func TestGetNamespaceSuccess(t *testing.T) {
+	if ns := NewCM().GetNamespace("my-ns"); ns != "my-ns" {
+		t.Errorf("GetNamespace failed: expected: my-ns, got: %s", ns)
+	}
+}
+
+func TestGetNamespaceReturnsConfiguredNamespaceName(t *testing.T) {
+	if ns := NewCM().GetNamespace(""); ns != "ricxapp" {
+		t.Errorf("GetNamespace failed: expected: ricxapp, got: %s", ns)
+	}
+}
+
 func TestGetNamesFromHelmRepoSuccess(t *testing.T) {
 	expectedResult := []string{"anr", "appmgr", "dualco", "reporter", "uemgr"}
-	util.HelmExec = func(args string) (out []byte, err error) {
-		return []byte(helmSearchOutput), nil
-	}
+
+	defer func() { resetHelmExecMock() }()
+	helmExec = mockedHelmExec
+	//Fake helm search success
+	helmExecRetOut = helmSearchOutput
 
 	names := NewCM().GetNamesFromHelmRepo()
 	if !reflect.DeepEqual(names, expectedResult) {
 		t.Errorf("GetNamesFromHelmRepo failed: expected %v, got %v", expectedResult, names)
 	}
+	if caughtHelmExecArgs != expectedHelmSearchCmd {
+		t.Errorf("GetNamesFromHelmRepo failed: expected: %v, got: %v", expectedHelmSearchCmd, caughtHelmExecArgs)
+	}
 }
 
 func TestGetNamesFromHelmRepoFailure(t *testing.T) {
 	expectedResult := []string{}
-	util.HelmExec = func(args string) (out []byte, err error) {
-		return []byte(helmSearchOutput), errors.New("Command failed!")
-	}
+
+	defer func() { resetHelmExecMock() }()
+	helmExec = mockedHelmExec
+	helmExecRetOut = helmSearchOutput
+	helmExecRetErr = errors.New("Command failed!")
 
 	names := NewCM().GetNamesFromHelmRepo()
 	if names != nil {
@@ -180,26 +389,128 @@
 }
 
 func TestBuildConfigMapSuccess(t *testing.T) {
+	expectedKubeCmd := []string{
+		`get configmap -o jsonpath='{.data.config-file\.json}' -n ricxapp  configmap-ricxapp-dummy-xapp-appconfig`,
+	}
 	name := "dummy-xapp"
 	namespace := "ricxapp"
 	m := models.ConfigMetadata{XappName: &name, Namespace: &namespace}
-	s := `{"Metadata": {"XappName": "ueec", "Namespace": "ricxapp"}, "Config": {"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}}`
+	s := `{"Metadata": {"XappName": "ueec", "Namespace": "ricxapp"}, ` +
+		`"Config": {"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}}`
 
-	util.KubectlExec = func(args string) (out []byte, err error) {
-		return []byte(`{"logger": {"level": 2}}`), nil
-	}
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl get configmap' success
+	kubeExecRetOut = `{"logger": {"level": 2}}`
 
 	cmString, err := NewCM().BuildConfigMap(models.XAppConfig{Metadata: &m, Config: s})
 	if err != nil {
 		t.Errorf("BuildConfigMap failed: %v -> %v", err, cmString)
 	}
+	if !reflect.DeepEqual(caughtKubeExecArgs, expectedKubeCmd) {
+		t.Errorf("BuildConfigMap failed: expected: %v, got: %v", expectedKubeCmd, caughtKubeExecArgs)
+	}
 }
 
-func TestUpdateConfigMapFails(t *testing.T) {
+func TestBuildConfigMapReturnErrorIfJsonMarshalFails(t *testing.T) {
+	name := "dummy-xapp"
+	namespace := "ricxapp"
+	m := models.ConfigMetadata{XappName: &name, Namespace: &namespace}
+	//Give channel as a configuration input, this will fail JSON marshal
+	cmString, err := NewCM().BuildConfigMap(models.XAppConfig{Metadata: &m, Config: make(chan int)})
+	if err == nil {
+		t.Errorf("BuildConfigMap failed: %v -> %v", err, cmString)
+	}
+}
+
+func TestBuildConfigMapReturnErrorIfKubectlGetConfigmapFails(t *testing.T) {
+	name := "dummy-xapp"
+	namespace := "ricxapp"
+	m := models.ConfigMetadata{XappName: &name, Namespace: &namespace}
+	s := `{"Metadata": {"XappName": "ueec", "Namespace": "ricxapp"}, ` +
+		`"Config": {"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}}`
+
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl get configmap' failure
+	kubeExecRetErr = errors.New("some error")
+
+	cmString, err := NewCM().BuildConfigMap(models.XAppConfig{Metadata: &m, Config: s})
+	if err == nil {
+		t.Errorf("BuildConfigMap failed: %v -> %v", err, cmString)
+	} else if err.Error() != "some error" {
+		t.Errorf("BuildConfigMap failed: expected: 'some error', got: '%s'", err.Error())
+	}
+}
+
+func TestBuildConfigMapReturnErrorIfJsonParserFails(t *testing.T) {
+	name := "dummy-xapp"
+	namespace := "ricxapp"
+	m := models.ConfigMetadata{XappName: &name, Namespace: &namespace}
+	s := `{"Metadata": {"XappName": "ueec", "Namespace": "ricxapp"}, ` +
+		`"Config": {"active": true, "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}}`
+
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Return empty json that causes JSON parser to fail
+	kubeExecRetOut = ``
+
+	cmString, err := NewCM().BuildConfigMap(models.XAppConfig{Metadata: &m, Config: s})
+	if err == nil {
+		t.Errorf("BuildConfigMap failed: %v -> %v", err, cmString)
+	}
+}
+
+func TestGenerateJSONFileSuccess(t *testing.T) {
+	err := NewCM().GenerateJSONFile("{}")
+	if err != nil {
+		t.Errorf("GenerateJSONFile failed: %v", err)
+	}
+}
+
+func TestReplaceConfigMapSuccess(t *testing.T) {
+	name := "dummy-xapp"
+	namespace := "ricxapp"
+
+	defer func() { resetKubeExecMock() }()
+	kubeExec = mockedKubeExec
+	//Fake 'kubectl create configmap' success
+	kubeExecRetOut = ""
+
+	err := NewCM().ReplaceConfigMap(name, namespace)
+	if err != nil {
+		t.Errorf("ReplaceConfigMap failed: %v", err)
+	}
+}
+
+func TestUpdateConfigMapReturnsErrorIfSchemaFileIsMissing(t *testing.T) {
 	name := "dummy-xapp"
 	namespace := "ricxapp"
 	config := models.XAppConfig{Metadata: &models.ConfigMetadata{XappName: &name, Namespace: &namespace}}
 
+	defer func() { resetHelmExecMock() }()
+	helmExec = mockedHelmExec
+	helmExecRetOut = `{}`
+
+	//Will fail at schema reading, because schema file is mission
+	validationErrors, err := NewCM().UpdateConfigMap(config)
+	if err == nil {
+		t.Errorf("UpdateConfigMap failed: %v -> %v", err, validationErrors)
+	}
+	if caughtHelmExecArgs != expectedHelmFetchCmd {
+		t.Errorf("UpdateConfigMap failed: expected: %v, got: %v", expectedHelmFetchCmd, caughtHelmExecArgs)
+	}
+}
+
+func TestUpdateConfigMapReturnsErrorIfHelmFetchChartFails(t *testing.T) {
+	name := "dummy-xapp"
+	namespace := "ricxapp"
+	config := models.XAppConfig{Metadata: &models.ConfigMetadata{XappName: &name, Namespace: &namespace}}
+
+	defer func() { resetHelmExecMock() }()
+	helmExec = mockedHelmExec
+	helmExecRetErr = errors.New("some error")
+
 	validationErrors, err := NewCM().UpdateConfigMap(config)
 	if err == nil {
 		t.Errorf("UpdateConfigMap failed: %v -> %v", err, validationErrors)
@@ -225,6 +536,7 @@
 func TestValidationFails(t *testing.T) {
 	var d interface{}
 	var cfg map[string]interface{}
+
 	err := json.Unmarshal([]byte(`{"active": "INVALID", "interfaceId":{"globalENBId": {"eNBId": 77, "plmnId": "6666"}}}`), &cfg)
 
 	err = NewCM().ReadFile("../../test/schema.json", &d)
@@ -234,7 +546,47 @@
 
 	feedback, err := NewCM().doValidate(d, cfg)
 	if err == nil {
-		t.Errorf("doValidate should faile but didn't: %v -> %v", err, feedback)
+		t.Errorf("doValidate should fail but didn't: %v -> %v", err, feedback)
 	}
 	appmgr.Logger.Debug("Feedbacks: %v", feedback)
 }
+
+func TestReadFileReturnsErrorIfFileReadFails(t *testing.T) {
+	var d interface{}
+
+	if err := NewCM().ReadFile("not/existing/test/schema.json", &d); err == nil {
+		t.Errorf("ReadFile should fail but it didn't")
+	}
+}
+
+func TestReadFileReturnsErrorIfJsonUnmarshalFails(t *testing.T) {
+	var d interface{}
+
+	if err := NewCM().ReadFile("../../test/faulty_schema.json", &d); err == nil {
+		t.Errorf("ReadFile should fail but it didn't")
+	}
+}
+
+func mockedKubeExec(args string) (out []byte, err error) {
+	caughtKubeExecArgs = append(caughtKubeExecArgs, args)
+	return []byte(kubeExecRetOut), kubeExecRetErr
+}
+
+func resetKubeExecMock() {
+	kubeExec = util.KubectlExec
+	caughtKubeExecArgs = nil
+	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
+}