Add get all published services 75/9775/1
authorelinuxhenrik <henrik.b.andersson@est.tech>
Wed, 23 Nov 2022 17:55:03 +0000 (18:55 +0100)
committerelinuxhenrik <henrik.b.andersson@est.tech>
Thu, 24 Nov 2022 12:34:57 +0000 (13:34 +0100)
When an invoker is registered the ApiList is now populated by the
invoker manager.

Issue-ID: NONRTRIC-814
Signed-off-by: elinuxhenrik <henrik.b.andersson@est.tech>
Change-Id: I20464ce975c2f5ae9e4506d46ee2bfab43f25cd2

capifcore/internal/invokermanagement/invokermanagement.go
capifcore/internal/invokermanagement/invokermanagement_test.go
capifcore/internal/publishservice/mocks/PublishRegister.go
capifcore/internal/publishservice/publishservice.go
capifcore/internal/publishservice/publishservice_test.go

index 7f5782e..69d7149 100644 (file)
@@ -39,8 +39,14 @@ import (
 
 //go:generate mockery --name InvokerRegister
 type InvokerRegister interface {
+       // Checks if the invoker is registered.
+       // Returns true of the provided invoker is registered, false otherwise.
        IsInvokerRegistered(invokerId string) bool
+       // Verifies that the provided secret is the invoker's registered secret.
+       // Returns true if the provided secret is the registered invoker's secret, false otherwise.
        VerifyInvokerSecret(invokerId, secret string) bool
+       // Gets the provided invoker's registered APIs.
+       // Returns a list of all the invoker's registered APIs.
        GetInvokerApiList(invokerId string) *invokerapi.APIList
 }
 
@@ -51,6 +57,7 @@ type InvokerManager struct {
        lock              sync.Mutex
 }
 
+// Creates a manager that implements both the InvokerRegister and the invokermanagementapi.ServerInterface interfaces.
 func NewInvokerManager(publishRegister publishservice.PublishRegister) *InvokerManager {
        return &InvokerManager{
                onboardedInvokers: make(map[string]invokerapi.APIInvokerEnrolmentDetails),
@@ -86,6 +93,7 @@ func (im *InvokerManager) GetInvokerApiList(invokerId string) *invokerapi.APILis
        return nil
 }
 
+// Creates a new individual API Invoker profile.
 func (im *InvokerManager) PostOnboardedInvokers(ctx echo.Context) error {
        var newInvoker invokerapi.APIInvokerEnrolmentDetails
        err := ctx.Bind(&newInvoker)
@@ -110,6 +118,9 @@ func (im *InvokerManager) PostOnboardedInvokers(ctx echo.Context) error {
        }
        newInvoker.OnboardingInformation.OnboardingSecret = &onboardingSecret
 
+       var apiList invokerapi.APIList = im.publishRegister.GetAllPublishedServices()
+       newInvoker.ApiList = &apiList
+
        im.onboardedInvokers[*newInvoker.ApiInvokerId] = newInvoker
 
        uri := ctx.Request().Host + ctx.Request().URL.String()
@@ -123,6 +134,7 @@ func (im *InvokerManager) PostOnboardedInvokers(ctx echo.Context) error {
        return nil
 }
 
+// Deletes an individual API Invoker.
 func (im *InvokerManager) DeleteOnboardedInvokersOnboardingId(ctx echo.Context, onboardingId string) error {
        im.lock.Lock()
        defer im.lock.Unlock()
@@ -132,6 +144,7 @@ func (im *InvokerManager) DeleteOnboardedInvokersOnboardingId(ctx echo.Context,
        return ctx.NoContent(http.StatusNoContent)
 }
 
+// Updates an individual API invoker details.
 func (im *InvokerManager) PutOnboardedInvokersOnboardingId(ctx echo.Context, onboardingId string) error {
        var invoker invokerapi.APIInvokerEnrolmentDetails
        err := ctx.Bind(&invoker)
index 365a7d0..0b90de8 100644 (file)
@@ -41,26 +41,25 @@ import (
        "github.com/deepmap/oapi-codegen/pkg/testutil"
        echomiddleware "github.com/labstack/echo/v4/middleware"
        "github.com/stretchr/testify/assert"
-       "github.com/stretchr/testify/mock"
 )
 
 func TestOnboardInvoker(t *testing.T) {
-       publishRegisterMock := publishmocks.PublishRegister{}
-       publishRegisterMock.On("AreAPIsPublished", mock.Anything).Return(true)
-       invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
-
        aefProfiles := []publishserviceapi.AefProfile{
                getAefProfile("aefId"),
        }
        apiId := "apiId"
-       var apiList invokermanagementapi.APIList = []publishserviceapi.ServiceAPIDescription{
+       publishedServices := []publishserviceapi.ServiceAPIDescription{
                {
                        ApiId:       &apiId,
                        AefProfiles: &aefProfiles,
                },
        }
+       publishRegisterMock := publishmocks.PublishRegister{}
+       publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
+       invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
+
        invokerInfo := "invoker a"
-       newInvoker := getInvoker(invokerInfo, apiList)
+       newInvoker := getInvoker(invokerInfo)
 
        // Onboard a valid invoker
        result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
@@ -78,7 +77,8 @@ func TestOnboardInvoker(t *testing.T) {
        assert.Equal(t, "http://example.com/onboardedInvokers/"+*resultInvoker.ApiInvokerId, result.Recorder.Header().Get(echo.HeaderLocation))
        assert.True(t, invokerUnderTest.IsInvokerRegistered(wantedInvokerId))
        assert.True(t, invokerUnderTest.VerifyInvokerSecret(wantedInvokerId, wantedInvokerSecret))
-       publishRegisterMock.AssertCalled(t, "AreAPIsPublished", mock.Anything)
+       publishRegisterMock.AssertCalled(t, "GetAllPublishedServices")
+       assert.Equal(t, invokermanagementapi.APIList(publishedServices), *resultInvoker.ApiList)
 
        // Onboard an invoker missing required NotificationDestination, should get 400 with problem details
        invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
@@ -113,7 +113,9 @@ func TestOnboardInvoker(t *testing.T) {
 }
 
 func TestDeleteInvoker(t *testing.T) {
-       invokerUnderTest, requestHandler := getEcho(nil)
+       publishRegisterMock := publishmocks.PublishRegister{}
+       publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
+       invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
 
        newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
                NotificationDestination: "url",
@@ -136,7 +138,9 @@ func TestDeleteInvoker(t *testing.T) {
 }
 
 func TestUpdateInvoker(t *testing.T) {
-       _, requestHandler := getEcho(nil)
+       publishRegisterMock := publishmocks.PublishRegister{}
+       publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
+       _, requestHandler := getEcho(&publishRegisterMock)
 
        newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
                NotificationDestination: "url",
@@ -150,18 +154,22 @@ func TestUpdateInvoker(t *testing.T) {
        var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails
        result.UnmarshalBodyToObject(&resultInvoker)
 
+       // Update the invoker with valid invoker, should return 200 with updated invoker details
        invokerId := resultInvoker.ApiInvokerId
        invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation)
-
-       // Update the invoker with valid invoker, should return 200 with invoker details
+       resultInvoker.ApiList = nil
+       newNotifURL := "newUrl"
+       resultInvoker.NotificationDestination = common29122.Uri(newNotifURL)
+       newPublicKey := "newPublicKey"
+       resultInvoker.OnboardingInformation.ApiInvokerPublicKey = newPublicKey
        result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(resultInvoker).Go(t, requestHandler)
 
        assert.Equal(t, http.StatusOK, result.Code())
        err := result.UnmarshalBodyToObject(&resultInvoker)
        assert.NoError(t, err, "error unmarshaling response")
        assert.Equal(t, invokerId, resultInvoker.ApiInvokerId)
-       assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination)
-       assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
+       assert.Equal(t, newNotifURL, string(resultInvoker.NotificationDestination))
+       assert.Equal(t, newPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
 
        // Update with an invoker missing required NotificationDestination, should get 400 with problem details
        validOnboardingInfo := invokermanagementapi.OnboardingInformation{
@@ -222,35 +230,32 @@ func TestUpdateInvoker(t *testing.T) {
 }
 
 func TestGetInvokerApiList(t *testing.T) {
-       publishRegisterMock := publishmocks.PublishRegister{}
-       publishRegisterMock.On("AreAPIsPublished", mock.Anything).Return(true)
-       invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
-
-       // Onboard two invokers
-       aefProfiles := []publishserviceapi.AefProfile{
+       aefProfiles1 := []publishserviceapi.AefProfile{
                getAefProfile("aefId"),
        }
        apiId := "apiId"
-       var apiList invokermanagementapi.APIList = []publishserviceapi.ServiceAPIDescription{
+       apiList := []publishserviceapi.ServiceAPIDescription{
                {
                        ApiId:       &apiId,
-                       AefProfiles: &aefProfiles,
+                       AefProfiles: &aefProfiles1,
                },
        }
-       invokerInfo := "invoker a"
-       newInvoker := getInvoker(invokerInfo, apiList)
-       testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
-       aefProfiles = []publishserviceapi.AefProfile{
+       aefProfiles2 := []publishserviceapi.AefProfile{
                getAefProfile("aefId2"),
        }
        apiId2 := "apiId2"
-       apiList = []publishserviceapi.ServiceAPIDescription{
-               {
-                       ApiId:       &apiId2,
-                       AefProfiles: &aefProfiles,
-               },
-       }
-       newInvoker = getInvoker("invoker b", apiList)
+       apiList = append(apiList, publishserviceapi.ServiceAPIDescription{
+               ApiId:       &apiId2,
+               AefProfiles: &aefProfiles2,
+       })
+       publishRegisterMock := publishmocks.PublishRegister{}
+       publishRegisterMock.On("GetAllPublishedServices").Return(apiList)
+       invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
+
+       invokerInfo := "invoker a"
+       newInvoker := getInvoker(invokerInfo)
+       testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
+       newInvoker = getInvoker("invoker b")
        testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
 
        wantedApiList := invokerUnderTest.GetInvokerApiList("api_invoker_id_" + strings.Replace(invokerInfo, " ", "_", 1))
@@ -292,14 +297,14 @@ func getAefProfile(aefId string) publishserviceapi.AefProfile {
        }
 }
 
-func getInvoker(invokerInfo string, apiList invokermanagementapi.APIList) invokermanagementapi.APIInvokerEnrolmentDetails {
+func getInvoker(invokerInfo string) invokermanagementapi.APIInvokerEnrolmentDetails {
        newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
                ApiInvokerInformation:   &invokerInfo,
                NotificationDestination: "url",
                OnboardingInformation: invokermanagementapi.OnboardingInformation{
                        ApiInvokerPublicKey: "key",
                },
-               ApiList: &apiList,
+               ApiList: nil,
        }
        return newInvoker
 }
index b264825..a798a71 100644 (file)
@@ -27,6 +27,22 @@ func (_m *PublishRegister) AreAPIsPublished(serviceDescriptions *[]publishservic
        return r0
 }
 
+// GetAllPublishedServices provides a mock function with given fields:
+func (_m *PublishRegister) GetAllPublishedServices() []publishserviceapi.ServiceAPIDescription {
+       ret := _m.Called()
+
+       var r0 []publishserviceapi.ServiceAPIDescription
+       if rf, ok := ret.Get(0).(func() []publishserviceapi.ServiceAPIDescription); ok {
+               r0 = rf()
+       } else {
+               if ret.Get(0) != nil {
+                       r0 = ret.Get(0).([]publishserviceapi.ServiceAPIDescription)
+               }
+       }
+
+       return r0
+}
+
 // IsAPIPublished provides a mock function with given fields: aefId, path
 func (_m *PublishRegister) IsAPIPublished(aefId string, path string) bool {
        ret := _m.Called(aefId, path)
index 2b7f52d..2314039 100644 (file)
@@ -31,7 +31,7 @@ import (
        "k8s.io/utils/strings/slices"
 
        "oransc.org/nonrtric/capifcore/internal/common29122"
-       "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
+       publishapi "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
 
        "oransc.org/nonrtric/capifcore/internal/helmmanagement"
        "oransc.org/nonrtric/capifcore/internal/providermanagement"
@@ -41,26 +41,34 @@ import (
 
 //go:generate mockery --name PublishRegister
 type PublishRegister interface {
-       AreAPIsPublished(serviceDescriptions *[]publishserviceapi.ServiceAPIDescription) bool
+       // Checks if the provided APIs are published.
+       // Returns true if all provided APIs have been published, false otherwise.
+       AreAPIsPublished(serviceDescriptions *[]publishapi.ServiceAPIDescription) bool
+       // Checks if the provided API is published.
+       // Returns true if the provided API has been published, false otherwise.
        IsAPIPublished(aefId, path string) bool
+       // Gets all published APIs.
+       // Returns a list of all APIs that has been published.
+       GetAllPublishedServices() []publishapi.ServiceAPIDescription
 }
 
 type PublishService struct {
-       publishedServices map[string][]*publishserviceapi.ServiceAPIDescription
+       publishedServices map[string][]publishapi.ServiceAPIDescription
        serviceRegister   providermanagement.ServiceRegister
        helmManager       helmmanagement.HelmManager
        lock              sync.Mutex
 }
 
+// Creates a service that implements both the PublishRegister and the publishserviceapi.ServerInterface interfaces.
 func NewPublishService(serviceRegister providermanagement.ServiceRegister, hm helmmanagement.HelmManager) *PublishService {
        return &PublishService{
                helmManager:       hm,
-               publishedServices: make(map[string][]*publishserviceapi.ServiceAPIDescription),
+               publishedServices: make(map[string][]publishapi.ServiceAPIDescription),
                serviceRegister:   serviceRegister,
        }
 }
 
-func (ps *PublishService) AreAPIsPublished(serviceDescriptions *[]publishserviceapi.ServiceAPIDescription) bool {
+func (ps *PublishService) AreAPIsPublished(serviceDescriptions *[]publishapi.ServiceAPIDescription) bool {
 
        if serviceDescriptions != nil {
                registeredApis := ps.getAllAefIds()
@@ -76,13 +84,13 @@ func (ps *PublishService) getAllAefIds() []string {
        allIds := []string{}
        for _, descriptions := range ps.publishedServices {
                for _, description := range descriptions {
-                       allIds = append(allIds, getIdsFromDescription(*description)...)
+                       allIds = append(allIds, getIdsFromDescription(description)...)
                }
        }
        return allIds
 }
 
-func getIdsFromDescription(description publishserviceapi.ServiceAPIDescription) []string {
+func getIdsFromDescription(description publishapi.ServiceAPIDescription) []string {
        allIds := []string{}
        if description.AefProfiles != nil {
                for _, aefProfile := range *description.AefProfiles {
@@ -92,7 +100,7 @@ func getIdsFromDescription(description publishserviceapi.ServiceAPIDescription)
        return allIds
 }
 
-func checkNewDescriptions(newDescriptions []publishserviceapi.ServiceAPIDescription, registeredAefIds []string) bool {
+func checkNewDescriptions(newDescriptions []publishapi.ServiceAPIDescription, registeredAefIds []string) bool {
        registered := true
        for _, newApi := range newDescriptions {
                if !checkProfiles(newApi.AefProfiles, registeredAefIds) {
@@ -103,7 +111,7 @@ func checkNewDescriptions(newDescriptions []publishserviceapi.ServiceAPIDescript
        return registered
 }
 
-func checkProfiles(newProfiles *[]publishserviceapi.AefProfile, registeredAefIds []string) bool {
+func checkProfiles(newProfiles *[]publishapi.AefProfile, registeredAefIds []string) bool {
        allRegistered := true
        if newProfiles != nil {
                for _, profile := range *newProfiles {
@@ -120,6 +128,15 @@ func (ps *PublishService) IsAPIPublished(aefId, path string) bool {
        return slices.Contains(ps.getAllAefIds(), aefId)
 }
 
+func (ps *PublishService) GetAllPublishedServices() []publishapi.ServiceAPIDescription {
+       publishedDescriptions := []publishapi.ServiceAPIDescription{}
+       for _, descriptions := range ps.publishedServices {
+               publishedDescriptions = append(publishedDescriptions, descriptions...)
+       }
+       return publishedDescriptions
+}
+
+// Retrieve all published APIs.
 func (ps *PublishService) GetApfIdServiceApis(ctx echo.Context, apfId string) error {
        serviceDescriptions, ok := ps.publishedServices[apfId]
        if ok {
@@ -135,8 +152,9 @@ func (ps *PublishService) GetApfIdServiceApis(ctx echo.Context, apfId string) er
        return nil
 }
 
+// Publish a new API.
 func (ps *PublishService) PostApfIdServiceApis(ctx echo.Context, apfId string) error {
-       var newServiceAPIDescription publishserviceapi.ServiceAPIDescription
+       var newServiceAPIDescription publishapi.ServiceAPIDescription
        err := ctx.Bind(&newServiceAPIDescription)
        if err != nil {
                return sendCoreError(ctx, http.StatusBadRequest, "Invalid format for service "+apfId)
@@ -162,9 +180,9 @@ func (ps *PublishService) PostApfIdServiceApis(ctx echo.Context, apfId string) e
 
        _, ok := ps.publishedServices[apfId]
        if ok {
-               ps.publishedServices[apfId] = append(ps.publishedServices[apfId], &newServiceAPIDescription)
+               ps.publishedServices[apfId] = append(ps.publishedServices[apfId], newServiceAPIDescription)
        } else {
-               ps.publishedServices[apfId] = append([]*publishserviceapi.ServiceAPIDescription{}, &newServiceAPIDescription)
+               ps.publishedServices[apfId] = append([]publishapi.ServiceAPIDescription{}, newServiceAPIDescription)
        }
 
        uri := ctx.Request().Host + ctx.Request().URL.String()
@@ -178,7 +196,7 @@ func (ps *PublishService) PostApfIdServiceApis(ctx echo.Context, apfId string) e
        return nil
 }
 
-func (ps *PublishService) installHelmChart(newServiceAPIDescription publishserviceapi.ServiceAPIDescription, ctx echo.Context) (bool, error) {
+func (ps *PublishService) installHelmChart(newServiceAPIDescription publishapi.ServiceAPIDescription, ctx echo.Context) (bool, error) {
        info := strings.Split(*newServiceAPIDescription.Description, ",")
        if len(info) == 5 {
                err := ps.helmManager.InstallHelmChart(info[1], info[2], info[3], info[4])
@@ -190,6 +208,7 @@ func (ps *PublishService) installHelmChart(newServiceAPIDescription publishservi
        return false, nil
 }
 
+// Unpublish a published service API.
 func (ps *PublishService) DeleteApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error {
        serviceDescriptions, ok := ps.publishedServices[string(apfId)]
        if ok {
@@ -208,6 +227,7 @@ func (ps *PublishService) DeleteApfIdServiceApisServiceApiId(ctx echo.Context, a
        return ctx.NoContent(http.StatusNoContent)
 }
 
+// Retrieve a published service API.
 func (ps *PublishService) GetApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error {
        ps.lock.Lock()
        defer ps.lock.Unlock()
@@ -229,26 +249,28 @@ func (ps *PublishService) GetApfIdServiceApisServiceApiId(ctx echo.Context, apfI
        return ctx.NoContent(http.StatusNotFound)
 }
 
-func getServiceDescription(serviceApiId string, descriptions []*publishserviceapi.ServiceAPIDescription) (int, *publishserviceapi.ServiceAPIDescription) {
+func getServiceDescription(serviceApiId string, descriptions []publishapi.ServiceAPIDescription) (int, *publishapi.ServiceAPIDescription) {
        for pos, description := range descriptions {
                if serviceApiId == *description.ApiId {
-                       return pos, description
+                       return pos, &description
                }
        }
        return -1, nil
 }
 
-func removeServiceDescription(i int, a []*publishserviceapi.ServiceAPIDescription) []*publishserviceapi.ServiceAPIDescription {
-       a[i] = a[len(a)-1] // Copy last element to index i.
-       a[len(a)-1] = nil  // Erase last element (write zero value).
-       a = a[:len(a)-1]   // Truncate slice.
+func removeServiceDescription(i int, a []publishapi.ServiceAPIDescription) []publishapi.ServiceAPIDescription {
+       a[i] = a[len(a)-1]                               // Copy last element to index i.
+       a[len(a)-1] = publishapi.ServiceAPIDescription{} // Erase last element (write zero value).
+       a = a[:len(a)-1]                                 // Truncate slice.
        return a
 }
 
+// Modify an existing published service API.
 func (ps *PublishService) ModifyIndAPFPubAPI(ctx echo.Context, apfId string, serviceApiId string) error {
        return ctx.NoContent(http.StatusNotImplemented)
 }
 
+// Update a published service API.
 func (ps *PublishService) PutApfIdServiceApisServiceApiId(ctx echo.Context, apfId string, serviceApiId string) error {
        return ctx.NoContent(http.StatusNotImplemented)
 }
index 9bb02b6..ab92363 100644 (file)
@@ -162,6 +162,23 @@ func TestGetServices(t *testing.T) {
        assert.Contains(t, resultServices, serviceDescription2)
 }
 
+func TestGetPublishedServices(t *testing.T) {
+       serviceUnderTest := NewPublishService(nil, nil)
+
+       profiles := make([]publishapi.AefProfile, 1)
+       serviceDescription := publishapi.ServiceAPIDescription{
+               AefProfiles: &profiles,
+       }
+       serviceUnderTest.publishedServices["publisher1"] = []publishapi.ServiceAPIDescription{
+               serviceDescription,
+       }
+       serviceUnderTest.publishedServices["publisher2"] = []publishapi.ServiceAPIDescription{
+               serviceDescription,
+       }
+       result := serviceUnderTest.GetAllPublishedServices()
+       assert.Len(t, result, 2)
+}
+
 func getEcho(serviceRegister providermanagement.ServiceRegister, helmManager helmmanagement.HelmManager) (*PublishService, *echo.Echo) {
        swagger, err := publishapi.GetSwagger()
        if err != nil {