// ========================LICENSE_START=================================
// O-RAN-SC
// %%
-// Copyright (C) 2022: Nordix Foundation
+// Copyright (C) 2022-2023: Nordix Foundation
+// Copyright (C) 2024: OpenInfra Foundation Europe
// %%
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
"oransc.org/nonrtric/capifcore/internal/eventsapi"
"oransc.org/nonrtric/capifcore/internal/invokermanagementapi"
+ "oransc.org/nonrtric/capifcore/internal/keycloak"
"github.com/labstack/echo/v4"
"oransc.org/nonrtric/capifcore/internal/common29122"
"oransc.org/nonrtric/capifcore/internal/publishserviceapi"
+ keycloackmocks "oransc.org/nonrtric/capifcore/internal/keycloak/mocks"
"oransc.org/nonrtric/capifcore/internal/publishservice"
publishmocks "oransc.org/nonrtric/capifcore/internal/publishservice/mocks"
"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) {
AefProfiles: &aefProfiles,
},
}
- publishRegisterMock := publishmocks.PublishRegister{}
- publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
- invokerUnderTest, eventChannel, requestHandler := getEcho(&publishRegisterMock)
invokerInfo := "invoker a"
+ wantedInvokerSecret := "onboarding_secret_" + strings.Replace(invokerInfo, " ", "_", 1)
+ var client keycloak.Client
+ client.Secret = &wantedInvokerSecret
+ publishRegisterMock := publishmocks.PublishRegister{}
+ publishRegisterMock.On("GetAllowedPublishedServices", mock.AnythingOfType("[]publishserviceapi.ServiceAPIDescription")).Return(publishedServices)
+
+ accessMgmMock := keycloackmocks.AccessManagement{}
+ accessMgmMock.On("AddClient", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(nil)
+ accessMgmMock.On("GetClientRepresentation", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(&client, nil)
+
+ invokerUnderTest, eventChannel, requestHandler := getEcho(&publishRegisterMock, &accessMgmMock)
+
newInvoker := getInvoker(invokerInfo)
// Onboard a valid invoker
assert.Equal(t, wantedInvokerId, *resultInvoker.ApiInvokerId)
assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination)
assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
- wantedInvokerSecret := "onboarding_secret_" + strings.Replace(invokerInfo, " ", "_", 1)
+
assert.Equal(t, wantedInvokerSecret, *resultInvoker.OnboardingInformation.OnboardingSecret)
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, "GetAllPublishedServices")
+
+ publishRegisterMock.AssertCalled(t, "GetAllowedPublishedServices", mock.AnythingOfType("[]publishserviceapi.ServiceAPIDescription"))
+
assert.Equal(t, invokermanagementapi.APIList(publishedServices), *resultInvoker.ApiList)
if invokerEvent, timeout := waitForEvent(eventChannel, 1*time.Second); timeout {
assert.Fail(t, "No event sent")
assert.Equal(t, eventsapi.CAPIFEventAPIINVOKERONBOARDED, invokerEvent.Events)
}
+ // Onboarding the same invoker should result in Forbidden
+ result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
+
+ assert.Equal(t, http.StatusForbidden, result.Code())
+ var problemDetails common29122.ProblemDetails
+ err = result.UnmarshalBodyToObject(&problemDetails)
+ assert.NoError(t, err, "error unmarshaling response")
+ assert.Equal(t, http.StatusForbidden, *problemDetails.Status)
+ assert.Contains(t, *problemDetails.Cause, "already onboarded")
+
// Onboard an invoker missing required NotificationDestination, should get 400 with problem details
invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
OnboardingInformation: invokermanagementapi.OnboardingInformation{
- ApiInvokerPublicKey: "key",
+ ApiInvokerPublicKey: "newKey",
},
}
result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
assert.Equal(t, http.StatusBadRequest, result.Code())
- var problemDetails common29122.ProblemDetails
err = result.UnmarshalBodyToObject(&problemDetails)
assert.NoError(t, err, "error unmarshaling response")
- badRequest := http.StatusBadRequest
- assert.Equal(t, &badRequest, problemDetails.Status)
+ assert.Equal(t, http.StatusBadRequest, *problemDetails.Status)
assert.Contains(t, *problemDetails.Cause, "missing")
assert.Contains(t, *problemDetails.Cause, "NotificationDestination")
// Onboard an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
invalidInvoker = invokermanagementapi.APIInvokerEnrolmentDetails{
- NotificationDestination: "url",
+ NotificationDestination: "http://golang.cafe/",
}
result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
assert.Equal(t, http.StatusBadRequest, result.Code())
err = result.UnmarshalBodyToObject(&problemDetails)
assert.NoError(t, err, "error unmarshaling response")
- assert.Equal(t, &badRequest, problemDetails.Status)
+ assert.Equal(t, http.StatusBadRequest, *problemDetails.Status)
assert.Contains(t, *problemDetails.Cause, "missing")
assert.Contains(t, *problemDetails.Cause, "OnboardingInformation.ApiInvokerPublicKey")
}
func TestDeleteInvoker(t *testing.T) {
- invokerUnderTest, eventChannel, requestHandler := getEcho(nil)
+ invokerUnderTest, eventChannel, requestHandler := getEcho(nil, nil)
invokerId := "invokerId"
newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
}
}
+func TestFailedUpdateInvoker(t *testing.T) {
+ publishRegisterMock := publishmocks.PublishRegister{}
+ publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
+ serviceUnderTest, _, requestHandler := getEcho(&publishRegisterMock, nil)
+
+ invokerInfo := "invoker a"
+ invokerId := "api_invoker_id_" + strings.Replace(invokerInfo, " ", "_", 1)
+
+ // Attempt to update with an invoker without the ApiInvokerId provided in the parameter body. We should get 400 with problem details.
+ invalidInvoker := getInvoker(invokerInfo)
+ serviceUnderTest.onboardedInvokers[invokerId] = invalidInvoker
+
+ result := testutil.NewRequest().Put("/onboardedInvokers/"+invokerId).WithJsonBody(invalidInvoker).Go(t, requestHandler)
+ assert.Equal(t, http.StatusBadRequest, result.Code())
+
+ var problemDetails common29122.ProblemDetails
+ err := result.UnmarshalBodyToObject(&problemDetails)
+ assert.NoError(t, err, "error unmarshaling response")
+ assert.Equal(t, http.StatusBadRequest, *problemDetails.Status)
+
+ assert.Contains(t, *problemDetails.Cause, "APIInvokerEnrolmentDetails ApiInvokerId doesn't match path parameter")
+}
+
func TestUpdateInvoker(t *testing.T) {
publishRegisterMock := publishmocks.PublishRegister{}
publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
- serviceUnderTest, _, requestHandler := getEcho(&publishRegisterMock)
+ serviceUnderTest, _, requestHandler := getEcho(&publishRegisterMock, nil)
invokerId := "invokerId"
invoker := invokermanagementapi.APIInvokerEnrolmentDetails{
ApiInvokerId: &invokerId,
- NotificationDestination: "url",
+ NotificationDestination: "http://golang.cafe/",
OnboardingInformation: invokermanagementapi.OnboardingInformation{
ApiInvokerPublicKey: "key",
},
serviceUnderTest.onboardedInvokers[invokerId] = invoker
// Update the invoker with valid invoker, should return 200 with updated invoker details
- newNotifURL := "newUrl"
+ newNotifURL := "http://golang.org/"
invoker.NotificationDestination = common29122.Uri(newNotifURL)
newPublicKey := "newPublicKey"
invoker.OnboardingInformation.ApiInvokerPublicKey = newPublicKey
var problemDetails common29122.ProblemDetails
err = result.UnmarshalBodyToObject(&problemDetails)
assert.NoError(t, err, "error unmarshaling response")
- badRequest := http.StatusBadRequest
- assert.Equal(t, &badRequest, problemDetails.Status)
+ assert.Equal(t, http.StatusBadRequest, *problemDetails.Status)
assert.Contains(t, *problemDetails.Cause, "missing")
assert.Contains(t, *problemDetails.Cause, "NotificationDestination")
// Update with an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
- invalidInvoker.NotificationDestination = "url"
+ invalidInvoker.NotificationDestination = "http://golang.org/"
invalidInvoker.OnboardingInformation = invokermanagementapi.OnboardingInformation{}
result = testutil.NewRequest().Put("/onboardedInvokers/"+invokerId).WithJsonBody(invalidInvoker).Go(t, requestHandler)
assert.Equal(t, http.StatusBadRequest, result.Code())
err = result.UnmarshalBodyToObject(&problemDetails)
assert.NoError(t, err, "error unmarshaling response")
- assert.Equal(t, &badRequest, problemDetails.Status)
+ assert.Equal(t, http.StatusBadRequest, *problemDetails.Status)
assert.Contains(t, *problemDetails.Cause, "missing")
assert.Contains(t, *problemDetails.Cause, "OnboardingInformation.ApiInvokerPublicKey")
assert.Equal(t, http.StatusBadRequest, result.Code())
err = result.UnmarshalBodyToObject(&problemDetails)
assert.NoError(t, err, "error unmarshaling response")
- assert.Equal(t, &badRequest, problemDetails.Status)
- assert.Contains(t, *problemDetails.Cause, "not matching")
- assert.Contains(t, *problemDetails.Cause, "ApiInvokerId")
+ assert.Equal(t, http.StatusBadRequest, *problemDetails.Status)
+ assert.Contains(t, *problemDetails.Cause, "APIInvokerEnrolmentDetails ApiInvokerId doesn't match path parameter")
// Update an invoker that has not been onboarded, should get 404 with problem details
missingId := "1"
assert.Equal(t, http.StatusNotFound, result.Code())
err = result.UnmarshalBodyToObject(&problemDetails)
assert.NoError(t, err, "error unmarshaling response")
- notFound := http.StatusNotFound
- assert.Equal(t, ¬Found, problemDetails.Status)
+ assert.Equal(t, http.StatusNotFound, *problemDetails.Status)
assert.Contains(t, *problemDetails.Cause, "not been onboarded")
assert.Contains(t, *problemDetails.Cause, "invoker")
}
})
publishRegisterMock := publishmocks.PublishRegister{}
publishRegisterMock.On("GetAllPublishedServices").Return(apiList)
- invokerUnderTest, _, _ := getEcho(&publishRegisterMock)
+ invokerUnderTest, _, _ := getEcho(&publishRegisterMock, nil)
invokerInfo := "invoker a"
newInvoker := getInvoker(invokerInfo)
assert.Equal(t, apiId, *(*wantedApiList)[0].ApiId)
}
-func getEcho(publishRegister publishservice.PublishRegister) (*InvokerManager, chan eventsapi.EventNotification, *echo.Echo) {
+func getEcho(publishRegister publishservice.PublishRegister, keycloakMgm keycloak.AccessManagement) (*InvokerManager, chan eventsapi.EventNotification, *echo.Echo) {
swagger, err := invokermanagementapi.GetSwagger()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
swagger.Servers = nil
eventChannel := make(chan eventsapi.EventNotification)
- im := NewInvokerManager(publishRegister, eventChannel)
+ im := NewInvokerManager(publishRegister, keycloakMgm, eventChannel)
e := echo.New()
e.Use(echomiddleware.Logger())
func getInvoker(invokerInfo string) invokermanagementapi.APIInvokerEnrolmentDetails {
newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
ApiInvokerInformation: &invokerInfo,
- NotificationDestination: "url",
+ NotificationDestination: "http://golang.cafe/",
OnboardingInformation: invokermanagementapi.OnboardingInformation{
ApiInvokerPublicKey: "key",
},