From 48a943de59afa094d586cee17b313f1de5ecbaf2 Mon Sep 17 00:00:00 2001 From: elinuxhenrik Date: Thu, 8 Dec 2022 16:26:42 +0100 Subject: [PATCH] Add event handling to invokermanagement Issue-ID: NONRTRIC-814 Signed-off-by: elinuxhenrik Change-Id: Idd5de718396db11e4eac5a900960aafa255fc495 --- .../invokermanagement/invokermanagement.go | 18 +++++++++- .../invokermanagement/invokermanagement_test.go | 40 ++++++++++++++++++---- capifcore/main.go | 2 +- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/capifcore/internal/invokermanagement/invokermanagement.go b/capifcore/internal/invokermanagement/invokermanagement.go index c1ff264..ecf8de5 100644 --- a/capifcore/internal/invokermanagement/invokermanagement.go +++ b/capifcore/internal/invokermanagement/invokermanagement.go @@ -27,6 +27,7 @@ import ( "strings" "sync" + "oransc.org/nonrtric/capifcore/internal/eventsapi" publishapi "oransc.org/nonrtric/capifcore/internal/publishserviceapi" "oransc.org/nonrtric/capifcore/internal/common29122" @@ -54,15 +55,17 @@ type InvokerManager struct { onboardedInvokers map[string]invokerapi.APIInvokerEnrolmentDetails publishRegister publishservice.PublishRegister nextId int64 + eventChannel chan<- eventsapi.EventNotification lock sync.Mutex } // Creates a manager that implements both the InvokerRegister and the invokermanagementapi.ServerInterface interfaces. -func NewInvokerManager(publishRegister publishservice.PublishRegister) *InvokerManager { +func NewInvokerManager(publishRegister publishservice.PublishRegister, eventChannel chan<- eventsapi.EventNotification) *InvokerManager { return &InvokerManager{ onboardedInvokers: make(map[string]invokerapi.APIInvokerEnrolmentDetails), publishRegister: publishRegister, nextId: 1000, + eventChannel: eventChannel, } } @@ -126,6 +129,7 @@ func (im *InvokerManager) PostOnboardedInvokers(ctx echo.Context) error { newInvoker.ApiList = &apiList im.onboardedInvokers[*newInvoker.ApiInvokerId] = newInvoker + go im.sendEvent(*newInvoker.ApiInvokerId, eventsapi.CAPIFEventAPIINVOKERONBOARDED) uri := ctx.Request().Host + ctx.Request().URL.String() ctx.Response().Header().Set(echo.HeaderLocation, ctx.Scheme()+`://`+path.Join(uri, *newInvoker.ApiInvokerId)) @@ -144,6 +148,7 @@ func (im *InvokerManager) DeleteOnboardedInvokersOnboardingId(ctx echo.Context, defer im.lock.Unlock() delete(im.onboardedInvokers, onboardingId) + go im.sendEvent(onboardingId, eventsapi.CAPIFEventAPIINVOKEROFFBOARDED) return ctx.NoContent(http.StatusNoContent) } @@ -221,6 +226,17 @@ func (im *InvokerManager) getId(invokerInfo *string) *string { return &idAsString } +func (im *InvokerManager) sendEvent(invokerId string, eventType eventsapi.CAPIFEvent) { + invokerIds := []string{invokerId} + event := eventsapi.EventNotification{ + EventDetail: &eventsapi.CAPIFEventDetail{ + ApiInvokerIds: &invokerIds, + }, + Events: eventType, + } + im.eventChannel <- event +} + // This function wraps sending of an error in the Error format, and // handling the failure to marshal that. func sendCoreError(ctx echo.Context, code int, message string) error { diff --git a/capifcore/internal/invokermanagement/invokermanagement_test.go b/capifcore/internal/invokermanagement/invokermanagement_test.go index c662d6d..4613cc4 100644 --- a/capifcore/internal/invokermanagement/invokermanagement_test.go +++ b/capifcore/internal/invokermanagement/invokermanagement_test.go @@ -25,7 +25,9 @@ import ( "os" "strings" "testing" + "time" + "oransc.org/nonrtric/capifcore/internal/eventsapi" "oransc.org/nonrtric/capifcore/internal/invokermanagementapi" "github.com/labstack/echo/v4" @@ -55,7 +57,7 @@ func TestOnboardInvoker(t *testing.T) { } publishRegisterMock := publishmocks.PublishRegister{} publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices) - invokerUnderTest, requestHandler := getEcho(&publishRegisterMock) + invokerUnderTest, eventChannel, requestHandler := getEcho(&publishRegisterMock) invokerInfo := "invoker a" newInvoker := getInvoker(invokerInfo) @@ -78,6 +80,12 @@ func TestOnboardInvoker(t *testing.T) { assert.True(t, invokerUnderTest.VerifyInvokerSecret(wantedInvokerId, wantedInvokerSecret)) publishRegisterMock.AssertCalled(t, "GetAllPublishedServices") assert.Equal(t, invokermanagementapi.APIList(publishedServices), *resultInvoker.ApiList) + if invokerEvent, ok := waitForEvent(eventChannel, 1*time.Second); ok { + assert.Fail(t, "No event sent") + } else { + assert.Equal(t, *resultInvoker.ApiInvokerId, (*invokerEvent.EventDetail.ApiInvokerIds)[0]) + assert.Equal(t, eventsapi.CAPIFEventAPIINVOKERONBOARDED, invokerEvent.Events) + } // Onboard an invoker missing required NotificationDestination, should get 400 with problem details invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{ @@ -112,7 +120,7 @@ func TestOnboardInvoker(t *testing.T) { } func TestDeleteInvoker(t *testing.T) { - invokerUnderTest, requestHandler := getEcho(nil) + invokerUnderTest, eventChannel, requestHandler := getEcho(nil) invokerId := "invokerId" newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{ @@ -130,12 +138,18 @@ func TestDeleteInvoker(t *testing.T) { assert.Equal(t, http.StatusNoContent, result.Code()) assert.False(t, invokerUnderTest.IsInvokerRegistered(invokerId)) + if invokerEvent, ok := waitForEvent(eventChannel, 1*time.Second); ok { + assert.Fail(t, "No event sent") + } else { + assert.Equal(t, invokerId, (*invokerEvent.EventDetail.ApiInvokerIds)[0]) + assert.Equal(t, eventsapi.CAPIFEventAPIINVOKEROFFBOARDED, invokerEvent.Events) + } } func TestUpdateInvoker(t *testing.T) { publishRegisterMock := publishmocks.PublishRegister{} publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{}) - serviceUnderTest, requestHandler := getEcho(&publishRegisterMock) + serviceUnderTest, _, requestHandler := getEcho(&publishRegisterMock) invokerId := "invokerId" invoker := invokermanagementapi.APIInvokerEnrolmentDetails{ @@ -241,7 +255,7 @@ func TestGetInvokerApiList(t *testing.T) { }) publishRegisterMock := publishmocks.PublishRegister{} publishRegisterMock.On("GetAllPublishedServices").Return(apiList) - invokerUnderTest, _ := getEcho(&publishRegisterMock) + invokerUnderTest, _, _ := getEcho(&publishRegisterMock) invokerInfo := "invoker a" newInvoker := getInvoker(invokerInfo) @@ -260,7 +274,7 @@ func TestGetInvokerApiList(t *testing.T) { assert.Equal(t, apiId, *(*wantedApiList)[0].ApiId) } -func getEcho(publishRegister publishservice.PublishRegister) (*InvokerManager, *echo.Echo) { +func getEcho(publishRegister publishservice.PublishRegister) (*InvokerManager, chan eventsapi.EventNotification, *echo.Echo) { swagger, err := invokermanagementapi.GetSwagger() if err != nil { fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err) @@ -269,14 +283,15 @@ func getEcho(publishRegister publishservice.PublishRegister) (*InvokerManager, * swagger.Servers = nil - im := NewInvokerManager(publishRegister) + eventChannel := make(chan eventsapi.EventNotification) + im := NewInvokerManager(publishRegister, eventChannel) e := echo.New() e.Use(echomiddleware.Logger()) e.Use(middleware.OapiRequestValidator(swagger)) invokermanagementapi.RegisterHandlers(e, im) - return im, e + return im, eventChannel, e } func getAefProfile(aefId string) publishserviceapi.AefProfile { @@ -305,3 +320,14 @@ func getInvoker(invokerInfo string) invokermanagementapi.APIInvokerEnrolmentDeta } return newInvoker } + +// waitForEvent waits for the channel to receive an event for the specified max timeout. +// Returns true if waiting timed out. +func waitForEvent(ch chan eventsapi.EventNotification, timeout time.Duration) (*eventsapi.EventNotification, bool) { + select { + case event := <-ch: + return &event, false // completed normally + case <-time.After(timeout): + return nil, true // timed out + } +} diff --git a/capifcore/main.go b/capifcore/main.go index ef15462..2cd5ccc 100644 --- a/capifcore/main.go +++ b/capifcore/main.go @@ -124,7 +124,7 @@ func getEcho() *echo.Echo { log.Fatalf("Error loading InvokerManagement swagger spec\n: %s", err) } invokerManagerSwagger.Servers = nil - invokerManager := invokermanagement.NewInvokerManager(publishService) + invokerManager := invokermanagement.NewInvokerManager(publishService, eventChannel) group = e.Group("/api-invoker-management/v1") group.Use(middleware.OapiRequestValidator(invokerManagerSwagger)) invokermanagementapi.RegisterHandlersWithBaseURL(e, invokerManager, "/api-invoker-management/v1") -- 2.16.6