3 // ========================LICENSE_START=================================
6 // Copyright (C) 2022: Nordix Foundation
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
12 // http://www.apache.org/licenses/LICENSE-2.0
14 // Unless required by applicable law or agreed to in writing, software
15 // distributed under the License is distributed on an "AS IS" BASIS,
16 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 // See the License for the specific language governing permissions and
18 // limitations under the License.
19 // ========================LICENSE_END===================================
20 package invokermanagement
30 "oransc.org/nonrtric/capifcore/internal/invokermanagementapi"
32 "github.com/labstack/echo/v4"
34 "oransc.org/nonrtric/capifcore/internal/common29122"
35 "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
37 "oransc.org/nonrtric/capifcore/internal/publishservice"
38 publishmocks "oransc.org/nonrtric/capifcore/internal/publishservice/mocks"
40 "github.com/deepmap/oapi-codegen/pkg/middleware"
41 "github.com/deepmap/oapi-codegen/pkg/testutil"
42 echomiddleware "github.com/labstack/echo/v4/middleware"
43 "github.com/stretchr/testify/assert"
44 "github.com/stretchr/testify/mock"
47 func TestOnboardInvoker(t *testing.T) {
48 publishRegisterMock := publishmocks.PublishRegister{}
49 publishRegisterMock.On("AreAPIsPublished", mock.Anything).Return(true)
50 invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
52 aefProfiles := []publishserviceapi.AefProfile{
53 getAefProfile("aefId"),
56 var apiList invokermanagementapi.APIList = []publishserviceapi.ServiceAPIDescription{
59 AefProfiles: &aefProfiles,
62 invokerInfo := "invoker a"
63 newInvoker := getInvoker(invokerInfo, apiList)
65 // Onboard a valid invoker
66 result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
68 assert.Equal(t, http.StatusCreated, result.Code())
69 var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails
70 err := result.UnmarshalBodyToObject(&resultInvoker)
71 assert.NoError(t, err, "error unmarshaling response")
72 wantedInvokerId := "api_invoker_id_" + strings.Replace(invokerInfo, " ", "_", 1)
73 assert.Equal(t, wantedInvokerId, *resultInvoker.ApiInvokerId)
74 assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination)
75 assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
76 wantedInvokerSecret := "onboarding_secret_" + strings.Replace(invokerInfo, " ", "_", 1)
77 assert.Equal(t, wantedInvokerSecret, *resultInvoker.OnboardingInformation.OnboardingSecret)
78 assert.Equal(t, "http://example.com/onboardedInvokers/"+*resultInvoker.ApiInvokerId, result.Recorder.Header().Get(echo.HeaderLocation))
79 assert.True(t, invokerUnderTest.IsInvokerRegistered(wantedInvokerId))
80 assert.True(t, invokerUnderTest.VerifyInvokerSecret(wantedInvokerId, wantedInvokerSecret))
81 publishRegisterMock.AssertCalled(t, "AreAPIsPublished", mock.Anything)
83 // Onboard an invoker missing required NotificationDestination, should get 400 with problem details
84 invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
85 OnboardingInformation: invokermanagementapi.OnboardingInformation{
86 ApiInvokerPublicKey: "key",
89 result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
91 assert.Equal(t, http.StatusBadRequest, result.Code())
92 var problemDetails common29122.ProblemDetails
93 err = result.UnmarshalBodyToObject(&problemDetails)
94 assert.NoError(t, err, "error unmarshaling response")
95 badRequest := http.StatusBadRequest
96 assert.Equal(t, &badRequest, problemDetails.Status)
97 assert.Contains(t, *problemDetails.Cause, "missing")
98 assert.Contains(t, *problemDetails.Cause, "NotificationDestination")
100 // Onboard an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
101 invalidInvoker = invokermanagementapi.APIInvokerEnrolmentDetails{
102 NotificationDestination: "url",
105 result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
107 assert.Equal(t, http.StatusBadRequest, result.Code())
108 err = result.UnmarshalBodyToObject(&problemDetails)
109 assert.NoError(t, err, "error unmarshaling response")
110 assert.Equal(t, &badRequest, problemDetails.Status)
111 assert.Contains(t, *problemDetails.Cause, "missing")
112 assert.Contains(t, *problemDetails.Cause, "OnboardingInformation.ApiInvokerPublicKey")
115 func TestDeleteInvoker(t *testing.T) {
116 invokerUnderTest, requestHandler := getEcho(nil)
118 newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
119 NotificationDestination: "url",
120 OnboardingInformation: invokermanagementapi.OnboardingInformation{
121 ApiInvokerPublicKey: "key",
125 // Onboard an invoker
126 result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
128 invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation)
129 assert.True(t, invokerUnderTest.IsInvokerRegistered(path.Base(invokerUrl)))
131 // Delete the invoker
132 result = testutil.NewRequest().Delete(invokerUrl).Go(t, requestHandler)
134 assert.Equal(t, http.StatusNoContent, result.Code())
135 assert.False(t, invokerUnderTest.IsInvokerRegistered(path.Base(invokerUrl)))
138 func TestUpdateInvoker(t *testing.T) {
139 _, requestHandler := getEcho(nil)
141 newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
142 NotificationDestination: "url",
143 OnboardingInformation: invokermanagementapi.OnboardingInformation{
144 ApiInvokerPublicKey: "key",
148 // Onboard an invoker
149 result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
150 var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails
151 result.UnmarshalBodyToObject(&resultInvoker)
153 invokerId := resultInvoker.ApiInvokerId
154 invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation)
156 // Update the invoker with valid invoker, should return 200 with invoker details
157 result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(resultInvoker).Go(t, requestHandler)
159 assert.Equal(t, http.StatusOK, result.Code())
160 err := result.UnmarshalBodyToObject(&resultInvoker)
161 assert.NoError(t, err, "error unmarshaling response")
162 assert.Equal(t, invokerId, resultInvoker.ApiInvokerId)
163 assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination)
164 assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
166 // Update with an invoker missing required NotificationDestination, should get 400 with problem details
167 validOnboardingInfo := invokermanagementapi.OnboardingInformation{
168 ApiInvokerPublicKey: "key",
170 invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
171 ApiInvokerId: invokerId,
172 OnboardingInformation: validOnboardingInfo,
174 result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
176 assert.Equal(t, http.StatusBadRequest, result.Code())
177 var problemDetails common29122.ProblemDetails
178 err = result.UnmarshalBodyToObject(&problemDetails)
179 assert.NoError(t, err, "error unmarshaling response")
180 badRequest := http.StatusBadRequest
181 assert.Equal(t, &badRequest, problemDetails.Status)
182 assert.Contains(t, *problemDetails.Cause, "missing")
183 assert.Contains(t, *problemDetails.Cause, "NotificationDestination")
185 // Update with an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
186 invalidInvoker.NotificationDestination = "url"
187 invalidInvoker.OnboardingInformation = invokermanagementapi.OnboardingInformation{}
188 result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
190 assert.Equal(t, http.StatusBadRequest, result.Code())
191 err = result.UnmarshalBodyToObject(&problemDetails)
192 assert.NoError(t, err, "error unmarshaling response")
193 assert.Equal(t, &badRequest, problemDetails.Status)
194 assert.Contains(t, *problemDetails.Cause, "missing")
195 assert.Contains(t, *problemDetails.Cause, "OnboardingInformation.ApiInvokerPublicKey")
197 // Update with an invoker with other ApiInvokerId than the one provided in the URL, should get 400 with problem details
199 invalidInvoker.ApiInvokerId = &invalidId
200 invalidInvoker.OnboardingInformation = validOnboardingInfo
201 result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
203 assert.Equal(t, http.StatusBadRequest, result.Code())
204 err = result.UnmarshalBodyToObject(&problemDetails)
205 assert.NoError(t, err, "error unmarshaling response")
206 assert.Equal(t, &badRequest, problemDetails.Status)
207 assert.Contains(t, *problemDetails.Cause, "not matching")
208 assert.Contains(t, *problemDetails.Cause, "ApiInvokerId")
210 // Update an invoker that has not been onboarded, shold get 404 with problem details
212 newInvoker.ApiInvokerId = &missingId
213 result = testutil.NewRequest().Put("/onboardedInvokers/"+missingId).WithJsonBody(newInvoker).Go(t, requestHandler)
215 assert.Equal(t, http.StatusNotFound, result.Code())
216 err = result.UnmarshalBodyToObject(&problemDetails)
217 assert.NoError(t, err, "error unmarshaling response")
218 notFound := http.StatusNotFound
219 assert.Equal(t, ¬Found, problemDetails.Status)
220 assert.Contains(t, *problemDetails.Cause, "not been onboarded")
221 assert.Contains(t, *problemDetails.Cause, "invoker")
224 func TestGetInvokerApiList(t *testing.T) {
225 publishRegisterMock := publishmocks.PublishRegister{}
226 publishRegisterMock.On("AreAPIsPublished", mock.Anything).Return(true)
227 invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
229 // Onboard two invokers
230 aefProfiles := []publishserviceapi.AefProfile{
231 getAefProfile("aefId"),
234 var apiList invokermanagementapi.APIList = []publishserviceapi.ServiceAPIDescription{
237 AefProfiles: &aefProfiles,
240 invokerInfo := "invoker a"
241 newInvoker := getInvoker(invokerInfo, apiList)
242 testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
243 aefProfiles = []publishserviceapi.AefProfile{
244 getAefProfile("aefId2"),
247 apiList = []publishserviceapi.ServiceAPIDescription{
250 AefProfiles: &aefProfiles,
253 newInvoker = getInvoker("invoker b", apiList)
254 testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
256 wantedApiList := invokerUnderTest.GetInvokerApiList("api_invoker_id_" + strings.Replace(invokerInfo, " ", "_", 1))
257 assert.NotNil(t, wantedApiList)
258 assert.Equal(t, apiId, *(*wantedApiList)[0].ApiId)
261 func getEcho(publishRegister publishservice.PublishRegister) (*InvokerManager, *echo.Echo) {
262 swagger, err := invokermanagementapi.GetSwagger()
264 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
268 swagger.Servers = nil
270 im := NewInvokerManager(publishRegister)
273 e.Use(echomiddleware.Logger())
274 e.Use(middleware.OapiRequestValidator(swagger))
276 invokermanagementapi.RegisterHandlers(e, im)
280 func getAefProfile(aefId string) publishserviceapi.AefProfile {
281 return publishserviceapi.AefProfile{
283 Versions: []publishserviceapi.Version{
285 Resources: &[]publishserviceapi.Resource{
287 CommType: "REQUEST_RESPONSE",
295 func getInvoker(invokerInfo string, apiList invokermanagementapi.APIList) invokermanagementapi.APIInvokerEnrolmentDetails {
296 newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
297 ApiInvokerInformation: &invokerInfo,
298 NotificationDestination: "url",
299 OnboardingInformation: invokermanagementapi.OnboardingInformation{
300 ApiInvokerPublicKey: "key",