Add function registration to provider management

Change-Id: I9d25939faac09c641f19b24b30ef9ea484b879c3
diff --git a/capif/generate.sh b/capif/generate.sh
index 3645465..9ab2c95 100755
--- a/capif/generate.sh
+++ b/capif/generate.sh
@@ -54,4 +54,6 @@
 oapi-codegen --config internal/readonly/providermanagementapi/generator_settings_types.yaml internal/readonly/api/TS29222_CAPIF_API_Provider_Management_API.yaml
 oapi-codegen --config internal/readonly/providermanagementapi/generator_settings_server.yaml internal/readonly/api/TS29222_CAPIF_API_Provider_Management_API.yaml
 oapi-codegen --config internal/readonly/discoverserviceapi/generator_settings_types.yaml internal/readonly/api/TS29222_CAPIF_Discover_Service_API.yaml
-oapi-codegen --config internal/readonly/discoverserviceapi/generator_settings_server.yaml internal/readonly/api/TS29222_CAPIF_Discover_Service_API.yaml
\ No newline at end of file
+oapi-codegen --config internal/readonly/discoverserviceapi/generator_settings_server.yaml internal/readonly/api/TS29222_CAPIF_Discover_Service_API.yaml
+
+go generate ./...
\ No newline at end of file
diff --git a/capif/go.mod b/capif/go.mod
index 935c3b6..c3b4d28 100644
--- a/capif/go.mod
+++ b/capif/go.mod
@@ -102,6 +102,7 @@
 	github.com/spf13/cast v1.4.1 // indirect
 	github.com/spf13/cobra v1.3.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
+	github.com/stretchr/objx v0.2.0 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
 	github.com/valyala/fasttemplate v1.2.1 // indirect
 	github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
diff --git a/capif/internal/discoverservice/discoverservice.go b/capif/internal/discoverservice/discoverservice.go
index e85d07c..84bef69 100644
--- a/capif/internal/discoverservice/discoverservice.go
+++ b/capif/internal/discoverservice/discoverservice.go
@@ -21,6 +21,7 @@
 package discoverservice
 
 import (
+	"net/http"
 	"sync"
 
 	"github.com/labstack/echo/v4"
@@ -49,5 +50,5 @@
 
 func (ds *DiscoverService) GetAllServiceAPIs(ctx echo.Context, params discoverserviceapi.GetAllServiceAPIsParams) error {
 
-	return nil
+	return ctx.NoContent(http.StatusNotImplemented)
 }
diff --git a/capif/internal/helmmanagement/helm.go b/capif/internal/helmmanagement/helm.go
new file mode 100644
index 0000000..6f91e92
--- /dev/null
+++ b/capif/internal/helmmanagement/helm.go
@@ -0,0 +1,134 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   ========================LICENSE_END===================================
+//
+
+package helmmanagement
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+
+	log "github.com/sirupsen/logrus"
+	"helm.sh/helm/v3/pkg/action"
+	"helm.sh/helm/v3/pkg/chart/loader"
+	"helm.sh/helm/v3/pkg/cli"
+	"helm.sh/helm/v3/pkg/kube"
+	"k8s.io/cli-runtime/pkg/genericclioptions"
+	"k8s.io/client-go/rest"
+)
+
+// Generate mocks by running "go generate ./..."
+//go:generate mockery --name HelmManager
+type HelmManager interface {
+	InstallHelmChart(namespace, repoName, chartName, releaseName string) error
+	UninstallHelmChart(namespace, chartName string)
+}
+
+type helmManagerImpl struct {
+	settings *cli.EnvSettings
+}
+
+func NewHelmManager(settings *cli.EnvSettings) *helmManagerImpl {
+	return &helmManagerImpl{
+		settings: settings,
+	}
+}
+
+func (hm *helmManagerImpl) InstallHelmChart(namespace, repoName, chartName, releaseName string) error {
+	actionConfig, err := getActionConfig(namespace)
+	if err != nil {
+		return err
+	}
+
+	install := action.NewInstall(actionConfig)
+
+	cp, err := install.ChartPathOptions.LocateChart(fmt.Sprintf("%s/%s", repoName, chartName), hm.settings)
+	if err != nil {
+		log.Error("Unable to locate chart!")
+		return err
+	}
+
+	chartRequested, err := loader.Load(cp)
+	if err != nil {
+		log.Error("Unable to load chart path!")
+		return err
+	}
+
+	install.Namespace = namespace
+	install.ReleaseName = releaseName
+	_, err = install.Run(chartRequested, nil)
+	if err != nil {
+		log.Error("Unable to run chart!")
+		return err
+	}
+	log.Debug("Successfully onboarded ", namespace, repoName, chartName, releaseName)
+	return nil
+}
+
+func (hm *helmManagerImpl) UninstallHelmChart(namespace, chartName string) {
+	actionConfig, err := getActionConfig(namespace)
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	iCli := action.NewUninstall(actionConfig)
+
+	resp, err := iCli.Run(chartName)
+	if err != nil {
+		fmt.Println(err)
+	}
+	log.Debug("Successfully uninstalled chart: ", resp.Release.Name)
+}
+
+func getActionConfig(namespace string) (*action.Configuration, error) {
+	actionConfig := new(action.Configuration)
+	// Create the rest config instance with ServiceAccount values loaded in them
+	config, err := rest.InClusterConfig()
+	if err != nil {
+		// fallback to kubeconfig
+		home, exists := os.LookupEnv("HOME")
+		if !exists {
+			home = "/root"
+		}
+		kubeconfigPath := filepath.Join(home, ".kube", "config")
+		if envvar := os.Getenv("KUBECONFIG"); len(envvar) > 0 {
+			kubeconfigPath = envvar
+		}
+		if err := actionConfig.Init(kube.GetConfig(kubeconfigPath, "", namespace), namespace, os.Getenv("HELM_DRIVER"),
+			func(format string, v ...interface{}) {
+				fmt.Sprintf(format, v)
+			}); err != nil {
+			fmt.Println(err)
+		}
+	} else {
+		// Create the ConfigFlags struct instance with initialized values from ServiceAccount
+		kubeConfig := genericclioptions.NewConfigFlags(false)
+		kubeConfig.APIServer = &config.Host
+		kubeConfig.BearerToken = &config.BearerToken
+		kubeConfig.CAFile = &config.CAFile
+		kubeConfig.Namespace = &namespace
+		if err := actionConfig.Init(kubeConfig, namespace, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
+			fmt.Sprintf(format, v)
+		}); err != nil {
+			fmt.Println(err)
+		}
+	}
+	return actionConfig, err
+}
diff --git a/capif/internal/helmmanagement/mocks/HelmManager.go b/capif/internal/helmmanagement/mocks/HelmManager.go
new file mode 100644
index 0000000..56d3acd
--- /dev/null
+++ b/capif/internal/helmmanagement/mocks/HelmManager.go
@@ -0,0 +1,29 @@
+// Code generated by mockery v1.0.0. DO NOT EDIT.
+
+package mocks
+
+import mock "github.com/stretchr/testify/mock"
+
+// HelmManager is an autogenerated mock type for the HelmManager type
+type HelmManager struct {
+	mock.Mock
+}
+
+// InstallHelmChart provides a mock function with given fields: namespace, repoName, chartName, releaseName
+func (_m *HelmManager) InstallHelmChart(namespace string, repoName string, chartName string, releaseName string) error {
+	ret := _m.Called(namespace, repoName, chartName, releaseName)
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(string, string, string, string) error); ok {
+		r0 = rf(namespace, repoName, chartName, releaseName)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// UninstallHelmChart provides a mock function with given fields: namespace, chartName
+func (_m *HelmManager) UninstallHelmChart(namespace string, chartName string) {
+	_m.Called(namespace, chartName)
+}
diff --git a/capif/internal/invokermanagement/invokermanagement_test.go b/capif/internal/invokermanagement/invokermanagement_test.go
index ba1dcc8..a9914f1 100644
--- a/capif/internal/invokermanagement/invokermanagement_test.go
+++ b/capif/internal/invokermanagement/invokermanagement_test.go
@@ -208,12 +208,12 @@
 
 	swagger.Servers = nil
 
-	coreFunction := NewInvokerManager()
+	im := NewInvokerManager()
 
 	e := echo.New()
 	e.Use(echomiddleware.Logger())
 	e.Use(middleware.OapiRequestValidator(swagger))
 
-	invokermanagementapi.RegisterHandlers(e, coreFunction)
+	invokermanagementapi.RegisterHandlers(e, im)
 	return e
 }
diff --git a/capif/internal/providermanagement/providermanagement.go b/capif/internal/providermanagement/providermanagement.go
index 22632c5..8fe8af4 100644
--- a/capif/internal/providermanagement/providermanagement.go
+++ b/capif/internal/providermanagement/providermanagement.go
@@ -23,37 +23,32 @@
 import (
 	"fmt"
 	"net/http"
-	"os"
 	"path"
-	"path/filepath"
 	"strconv"
 	"strings"
 	"sync"
 
 	"github.com/labstack/echo/v4"
 	log "github.com/sirupsen/logrus"
-	"helm.sh/helm/v3/pkg/action"
-	"helm.sh/helm/v3/pkg/chart/loader"
-	"helm.sh/helm/v3/pkg/cli"
-	"helm.sh/helm/v3/pkg/kube"
-	"k8s.io/cli-runtime/pkg/genericclioptions"
-	"k8s.io/client-go/rest"
+	"oransc.org/nonrtric/plt/capif/internal/helmmanagement"
 	"oransc.org/nonrtric/plt/capif/internal/readonly/common"
 	"oransc.org/nonrtric/plt/capif/internal/readonly/providermanagementapi"
 )
 
 type ProviderManager struct {
-	settings           *cli.EnvSettings
+	helmManager        helmmanagement.HelmManager
 	onboardedProviders map[string]providermanagementapi.APIProviderEnrolmentDetails
-	nextId             int64
+	nextDomainId       int64
+	nextFuncId         int64
 	lock               sync.Mutex
 }
 
-func NewProviderManager(settings *cli.EnvSettings) *ProviderManager {
+func NewProviderManager(hm helmmanagement.HelmManager) *ProviderManager {
 	return &ProviderManager{
-		settings:           settings,
+		helmManager:        hm,
 		onboardedProviders: make(map[string]providermanagementapi.APIProviderEnrolmentDetails),
-		nextId:             1000,
+		nextDomainId:       1000,
+		nextFuncId:         1000,
 	}
 }
 
@@ -82,16 +77,13 @@
 	pm.lock.Lock()
 	defer pm.lock.Unlock()
 
-	newProvider.ApiProvDomId = pm.getId()
-	pm.nextId = pm.nextId + 1
-
-	pm.onboardedProviders[*newProvider.ApiProvDomId] = newProvider
+	newProvider.ApiProvDomId = pm.getDomainId()
 
 	domainInfo := strings.Split(*newProvider.ApiProvDomInfo, ",")
-	err = pm.installHelmChart(domainInfo[0], domainInfo[1], domainInfo[2], domainInfo[3])
-	if err != nil {
-		return sendCoreError(ctx, http.StatusInternalServerError, "Unable to install Helm chart for provider due to: "+err.Error())
-	}
+	registeredFuncs, failReason := pm.registerFunctions(domainInfo[0], domainInfo[1], newProvider.ApiProvFuncs)
+	newProvider.ApiProvFuncs = registeredFuncs
+	newProvider.FailReason = failReason
+	pm.onboardedProviders[*newProvider.ApiProvDomId] = newProvider
 
 	uri := ctx.Request().Host + ctx.Request().URL.String()
 	ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, *newProvider.ApiProvDomId))
@@ -105,111 +97,61 @@
 }
 
 func (pm *ProviderManager) DeleteRegistrationsRegistrationId(ctx echo.Context, registrationId string) error {
-	log.Debug("Entering DeleteRegistrationsRegistrationId: ", registrationId)
 	pm.lock.Lock()
 	defer pm.lock.Unlock()
 
 	log.Debug(pm.onboardedProviders)
 	if provider, ok := pm.onboardedProviders[registrationId]; ok {
-		log.Debug("Deleting provider")
+		log.Debug("Deleting provider", registrationId)
 		delete(pm.onboardedProviders, registrationId)
 
 		domainInfo := strings.Split(*provider.ApiProvDomInfo, ",")
-		uninstallHelmChart(domainInfo[0], domainInfo[3])
+		if provider.ApiProvFuncs != nil {
+			for _, provFunc := range *provider.ApiProvFuncs {
+				funcInfo := strings.Split(*provFunc.ApiProvFuncInfo, ",")
+				pm.helmManager.UninstallHelmChart(domainInfo[0], funcInfo[0])
+			}
+		}
 	}
 
-	log.Debug("Exiting DeleteRegistrationsRegistrationId")
 	return ctx.NoContent(http.StatusNoContent)
 }
 
 func (cf *ProviderManager) PutRegistrationsRegistrationId(ctx echo.Context, registrationId string) error {
 
-	return nil
+	return ctx.NoContent(http.StatusNotImplemented)
 }
 
-func (pm *ProviderManager) installHelmChart(namespace, repoName, chartName, releaseName string) error {
-	actionConfig, err := getActionConfig(namespace)
-	if err != nil {
-		return err
+func (pm *ProviderManager) registerFunctions(namespace, repoName string, provFuncs *[]providermanagementapi.APIProviderFunctionDetails) (*[]providermanagementapi.APIProviderFunctionDetails, *string) {
+	failReason := ""
+	if provFuncs == nil {
+		return nil, &failReason
+	}
+	registeredFuncs := []providermanagementapi.APIProviderFunctionDetails{}
+
+	for _, provFunc := range *provFuncs {
+		funcInfo := strings.Split(*provFunc.ApiProvFuncInfo, ",")
+		err := pm.helmManager.InstallHelmChart(namespace, repoName, funcInfo[0], funcInfo[1])
+		if err != nil {
+			failReason = fmt.Sprintf("%v, Unable to install Helm chart for %v due to: %v", failReason, funcInfo[0], err.Error())
+		} else {
+			provFunc.ApiProvFuncId = pm.getFuncId()
+			registeredFuncs = append(registeredFuncs, provFunc)
+			log.Debug("Installed Helm chart for", funcInfo[0])
+		}
 	}
 
-	install := action.NewInstall(actionConfig)
-
-	cp, err := install.ChartPathOptions.LocateChart(fmt.Sprintf("%s/%s", repoName, chartName), pm.settings)
-	if err != nil {
-		log.Error("Unable to locate chart!")
-		return err
-	}
-
-	chartRequested, err := loader.Load(cp)
-	if err != nil {
-		log.Error("Unable to load chart path!")
-		return err
-	}
-
-	install.Namespace = namespace
-	install.ReleaseName = releaseName
-	_, err = install.Run(chartRequested, nil)
-	if err != nil {
-		log.Error("Unable to run chart!")
-		return err
-	}
-	log.Debug("Successfully onboarded ", namespace, repoName, chartName, releaseName)
-	return nil
+	return &registeredFuncs, &failReason
 }
 
-func uninstallHelmChart(namespace, chartName string) {
-	actionConfig, err := getActionConfig(namespace)
-	if err != nil {
-		fmt.Println(err)
-	}
-
-	iCli := action.NewUninstall(actionConfig)
-
-	resp, err := iCli.Run(chartName)
-	if err != nil {
-		fmt.Println(err)
-	}
-	log.Debug("Successfully uninstalled chart: ", resp.Release.Name)
+func (pm *ProviderManager) getDomainId() *string {
+	idAsString := "Domain" + strconv.FormatInt(pm.nextDomainId, 10)
+	pm.nextDomainId = pm.nextDomainId + 1
+	return &idAsString
 }
 
-func getActionConfig(namespace string) (*action.Configuration, error) {
-	actionConfig := new(action.Configuration)
-	// Create the rest config instance with ServiceAccount values loaded in them
-	config, err := rest.InClusterConfig()
-	if err != nil {
-		// fallback to kubeconfig
-		home, exists := os.LookupEnv("HOME")
-		if !exists {
-			home = "/root"
-		}
-		kubeconfigPath := filepath.Join(home, ".kube", "config")
-		if envvar := os.Getenv("KUBECONFIG"); len(envvar) > 0 {
-			kubeconfigPath = envvar
-		}
-		if err := actionConfig.Init(kube.GetConfig(kubeconfigPath, "", namespace), namespace, os.Getenv("HELM_DRIVER"),
-			func(format string, v ...interface{}) {
-				fmt.Sprintf(format, v)
-			}); err != nil {
-			fmt.Println(err)
-		}
-	} else {
-		// Create the ConfigFlags struct instance with initialized values from ServiceAccount
-		kubeConfig := genericclioptions.NewConfigFlags(false)
-		kubeConfig.APIServer = &config.Host
-		kubeConfig.BearerToken = &config.BearerToken
-		kubeConfig.CAFile = &config.CAFile
-		kubeConfig.Namespace = &namespace
-		if err := actionConfig.Init(kubeConfig, namespace, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
-			fmt.Sprintf(format, v)
-		}); err != nil {
-			fmt.Println(err)
-		}
-	}
-	return actionConfig, err
-}
-
-func (pm *ProviderManager) getId() *string {
-	idAsString := strconv.FormatInt(pm.nextId, 10)
+func (pm *ProviderManager) getFuncId() *string {
+	idAsString := "Func" + strconv.FormatInt(pm.nextFuncId, 10)
+	pm.nextFuncId = pm.nextFuncId + 1
 	return &idAsString
 }
diff --git a/capif/internal/providermanagement/providermanagement_test.go b/capif/internal/providermanagement/providermanagement_test.go
new file mode 100644
index 0000000..ad01b49
--- /dev/null
+++ b/capif/internal/providermanagement/providermanagement_test.go
@@ -0,0 +1,146 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   ========================LICENSE_END===================================
+//
+
+package providermanagement
+
+import (
+	"errors"
+	"fmt"
+	"net/http"
+	"os"
+	"testing"
+
+	"github.com/deepmap/oapi-codegen/pkg/middleware"
+	"github.com/deepmap/oapi-codegen/pkg/testutil"
+	"github.com/labstack/echo/v4"
+	echomiddleware "github.com/labstack/echo/v4/middleware"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"oransc.org/nonrtric/plt/capif/internal/helmmanagement"
+	"oransc.org/nonrtric/plt/capif/internal/helmmanagement/mocks"
+	"oransc.org/nonrtric/plt/capif/internal/readonly/common"
+	"oransc.org/nonrtric/plt/capif/internal/readonly/providermanagementapi"
+)
+
+func TestProviderHandlingSuccessfully(t *testing.T) {
+	helmMock := &mocks.HelmManager{}
+	helmMock.On("InstallHelmChart", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(nil)
+	requestHandler := getEcho(helmMock)
+
+	domainInfo := "namespace,repoName"
+	funcInfo := "chartName,releaseName"
+	testFuncs := []providermanagementapi.APIProviderFunctionDetails{
+		{
+			ApiProvFuncInfo: &funcInfo,
+			ApiProvFuncRole: "AEF",
+		},
+	}
+	newProvider := providermanagementapi.APIProviderEnrolmentDetails{
+		ApiProvDomInfo: &domainInfo,
+		ApiProvFuncs:   &testFuncs,
+	}
+
+	// Register a valid provider
+	result := testutil.NewRequest().Post("/registrations").WithJsonBody(newProvider).Go(t, requestHandler)
+
+	assert.Equal(t, http.StatusCreated, result.Code())
+	var resultProvider providermanagementapi.APIProviderEnrolmentDetails
+	err := result.UnmarshalBodyToObject(&resultProvider)
+	assert.NoError(t, err, "error unmarshaling response")
+	assert.NotEmpty(t, resultProvider.ApiProvDomId)
+	for _, funcInfo := range *resultProvider.ApiProvFuncs {
+		assert.NotEmpty(t, funcInfo.ApiProvFuncId)
+	}
+	assert.Empty(t, resultProvider.FailReason)
+	assert.Equal(t, "http://example.com/registrations/"+*resultProvider.ApiProvDomId, result.Recorder.Header().Get(echo.HeaderLocation))
+	helmMock.AssertCalled(t, "InstallHelmChart", "namespace", "repoName", "chartName", "releaseName")
+
+	// Delete the provider
+	helmMock.On("UninstallHelmChart", mock.AnythingOfType("string"), mock.AnythingOfType("string"))
+	result = testutil.NewRequest().Delete("/registrations/"+*resultProvider.ApiProvDomId).Go(t, requestHandler)
+
+	assert.Equal(t, http.StatusNoContent, result.Code())
+	helmMock.AssertCalled(t, "UninstallHelmChart", "namespace", "chartName")
+}
+
+func TestProviderHandlingValidation(t *testing.T) {
+	requestHandler := getEcho(&mocks.HelmManager{})
+
+	newProvider := providermanagementapi.APIProviderEnrolmentDetails{}
+
+	// Register a valid provider
+	result := testutil.NewRequest().Post("/registrations").WithJsonBody(newProvider).Go(t, requestHandler)
+
+	assert.Equal(t, http.StatusBadRequest, result.Code())
+	var problemDetails common.ProblemDetails
+	err := result.UnmarshalBodyToObject(&problemDetails)
+	assert.NoError(t, err, "error unmarshaling response")
+	badRequest := 400
+	assert.Equal(t, &badRequest, problemDetails.Status)
+	errMsg := "Provider missing required ApiProvDomInfo"
+	assert.Equal(t, &errMsg, problemDetails.Cause)
+}
+
+func TestUnableToInstallFunction(t *testing.T) {
+	helmMock := &mocks.HelmManager{}
+	helmMock.On("InstallHelmChart", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(errors.New("problem"))
+	requestHandler := getEcho(helmMock)
+
+	domainInfo := "namespace,repoName"
+	funcInfo := "chartName,releaseName"
+	testFuncs := []providermanagementapi.APIProviderFunctionDetails{
+		{
+			ApiProvFuncInfo: &funcInfo,
+			ApiProvFuncRole: "AEF",
+		},
+	}
+	newProvider := providermanagementapi.APIProviderEnrolmentDetails{
+		ApiProvDomInfo: &domainInfo,
+		ApiProvFuncs:   &testFuncs,
+	}
+
+	// Register a valid provider
+	result := testutil.NewRequest().Post("/registrations").WithJsonBody(newProvider).Go(t, requestHandler)
+
+	assert.Equal(t, http.StatusCreated, result.Code())
+	var resultProvider providermanagementapi.APIProviderEnrolmentDetails
+	err := result.UnmarshalBodyToObject(&resultProvider)
+	assert.NoError(t, err, "error unmarshaling response")
+	assert.Equal(t, ", Unable to install Helm chart for chartName due to: problem", *resultProvider.FailReason)
+}
+
+func getEcho(helmMock helmmanagement.HelmManager) *echo.Echo {
+	swagger, err := providermanagementapi.GetSwagger()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
+		os.Exit(1)
+	}
+
+	swagger.Servers = nil
+
+	pm := NewProviderManager(helmMock)
+
+	e := echo.New()
+	e.Use(echomiddleware.Logger())
+	e.Use(middleware.OapiRequestValidator(swagger))
+
+	providermanagementapi.RegisterHandlers(e, pm)
+	return e
+}
diff --git a/capif/internal/publishservice/publishservice.go b/capif/internal/publishservice/publishservice.go
index 5926715..8276264 100644
--- a/capif/internal/publishservice/publishservice.go
+++ b/capif/internal/publishservice/publishservice.go
@@ -21,6 +21,7 @@
 package publishservice
 
 import (
+	"net/http"
 	"sync"
 
 	"github.com/labstack/echo/v4"
@@ -49,25 +50,25 @@
 
 func (ps *PublishService) GetApfIdServiceApis(ctx echo.Context, apfId publishapi.ApfId) error {
 
-	return nil
+	return ctx.NoContent(http.StatusNotImplemented)
 }
 
 func (ps *PublishService) PostApfIdServiceApis(ctx echo.Context, apfId publishapi.ApfId) error {
 
-	return nil
+	return ctx.NoContent(http.StatusNotImplemented)
 }
 
 func (ps *PublishService) DeleteApfIdServiceApisServiceApiId(ctx echo.Context, apfId publishapi.ApfId, serviceApiId publishapi.ServiceApiId) error {
 
-	return nil
+	return ctx.NoContent(http.StatusNotImplemented)
 }
 
 func (ps *PublishService) GetApfIdServiceApisServiceApiId(ctx echo.Context, apfId publishapi.ApfId, serviceApiId publishapi.ServiceApiId) error {
 
-	return nil
+	return ctx.NoContent(http.StatusNotImplemented)
 }
 
 func (ps *PublishService) PutApfIdServiceApisServiceApiId(ctx echo.Context, apfId publishapi.ApfId, serviceApiId publishapi.ServiceApiId) error {
 
-	return nil
+	return ctx.NoContent(http.StatusNotImplemented)
 }
diff --git a/capif/main.go b/capif/main.go
index 790f0c0..2350e98 100644
--- a/capif/main.go
+++ b/capif/main.go
@@ -38,6 +38,7 @@
 	"helm.sh/helm/v3/pkg/getter"
 	"helm.sh/helm/v3/pkg/repo"
 	"oransc.org/nonrtric/plt/capif/internal/discoverservice"
+	"oransc.org/nonrtric/plt/capif/internal/helmmanagement"
 	"oransc.org/nonrtric/plt/capif/internal/invokermanagement"
 	"oransc.org/nonrtric/plt/capif/internal/providermanagement"
 	"oransc.org/nonrtric/plt/capif/internal/publishservice"
@@ -52,7 +53,7 @@
 var repoName string
 
 func main() {
-	var port = flag.Int("port", 8090, "Port for test HTTP server")
+	var port = flag.Int("port", 8090, "Port for CAPIF Core Function HTTP server")
 	flag.StringVar(&url, "url", "http://chartmuseum:8080", "ChartMuseum url")
 	flag.StringVar(&repoName, "repoName", "local-dev", "Repository name")
 	flag.Parse()
@@ -87,7 +88,7 @@
 		log.Fatalf("Error loading ProviderManagement swagger spec\n: %s", err)
 	}
 	providerManagerSwagger.Servers = nil
-	providerManager := providermanagement.NewProviderManager(settings)
+	providerManager := providermanagement.NewProviderManager(helmmanagement.NewHelmManager(settings))
 	g = e.Group("/api-provider-management/v1")
 	g.Use(middleware.OapiRequestValidator(providerManagerSwagger))
 	providermanagementapi.RegisterHandlersWithBaseURL(e, providerManager, "/api-provider-management/v1")