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"
46 func TestOnboardInvoker(t *testing.T) {
47 aefProfiles := []publishserviceapi.AefProfile{
48 getAefProfile("aefId"),
51 publishedServices := []publishserviceapi.ServiceAPIDescription{
54 AefProfiles: &aefProfiles,
57 publishRegisterMock := publishmocks.PublishRegister{}
58 publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
59 invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
61 invokerInfo := "invoker a"
62 newInvoker := getInvoker(invokerInfo)
64 // Onboard a valid invoker
65 result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
67 assert.Equal(t, http.StatusCreated, result.Code())
68 var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails
69 err := result.UnmarshalBodyToObject(&resultInvoker)
70 assert.NoError(t, err, "error unmarshaling response")
71 wantedInvokerId := "api_invoker_id_" + strings.Replace(invokerInfo, " ", "_", 1)
72 assert.Equal(t, wantedInvokerId, *resultInvoker.ApiInvokerId)
73 assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination)
74 assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
75 wantedInvokerSecret := "onboarding_secret_" + strings.Replace(invokerInfo, " ", "_", 1)
76 assert.Equal(t, wantedInvokerSecret, *resultInvoker.OnboardingInformation.OnboardingSecret)
77 assert.Equal(t, "http://example.com/onboardedInvokers/"+*resultInvoker.ApiInvokerId, result.Recorder.Header().Get(echo.HeaderLocation))
78 assert.True(t, invokerUnderTest.IsInvokerRegistered(wantedInvokerId))
79 assert.True(t, invokerUnderTest.VerifyInvokerSecret(wantedInvokerId, wantedInvokerSecret))
80 publishRegisterMock.AssertCalled(t, "GetAllPublishedServices")
81 assert.Equal(t, invokermanagementapi.APIList(publishedServices), *resultInvoker.ApiList)
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 publishRegisterMock := publishmocks.PublishRegister{}
117 publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
118 invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
120 newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
121 NotificationDestination: "url",
122 OnboardingInformation: invokermanagementapi.OnboardingInformation{
123 ApiInvokerPublicKey: "key",
127 // Onboard an invoker
128 result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
130 invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation)
131 assert.True(t, invokerUnderTest.IsInvokerRegistered(path.Base(invokerUrl)))
133 // Delete the invoker
134 result = testutil.NewRequest().Delete(invokerUrl).Go(t, requestHandler)
136 assert.Equal(t, http.StatusNoContent, result.Code())
137 assert.False(t, invokerUnderTest.IsInvokerRegistered(path.Base(invokerUrl)))
140 func TestUpdateInvoker(t *testing.T) {
141 publishRegisterMock := publishmocks.PublishRegister{}
142 publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
143 _, requestHandler := getEcho(&publishRegisterMock)
145 newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
146 NotificationDestination: "url",
147 OnboardingInformation: invokermanagementapi.OnboardingInformation{
148 ApiInvokerPublicKey: "key",
152 // Onboard an invoker
153 result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
154 var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails
155 result.UnmarshalBodyToObject(&resultInvoker)
157 // Update the invoker with valid invoker, should return 200 with updated invoker details
158 invokerId := resultInvoker.ApiInvokerId
159 invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation)
160 resultInvoker.ApiList = nil
161 newNotifURL := "newUrl"
162 resultInvoker.NotificationDestination = common29122.Uri(newNotifURL)
163 newPublicKey := "newPublicKey"
164 resultInvoker.OnboardingInformation.ApiInvokerPublicKey = newPublicKey
165 result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(resultInvoker).Go(t, requestHandler)
167 assert.Equal(t, http.StatusOK, result.Code())
168 err := result.UnmarshalBodyToObject(&resultInvoker)
169 assert.NoError(t, err, "error unmarshaling response")
170 assert.Equal(t, invokerId, resultInvoker.ApiInvokerId)
171 assert.Equal(t, newNotifURL, string(resultInvoker.NotificationDestination))
172 assert.Equal(t, newPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
174 // Update with an invoker missing required NotificationDestination, should get 400 with problem details
175 validOnboardingInfo := invokermanagementapi.OnboardingInformation{
176 ApiInvokerPublicKey: "key",
178 invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
179 ApiInvokerId: invokerId,
180 OnboardingInformation: validOnboardingInfo,
182 result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
184 assert.Equal(t, http.StatusBadRequest, result.Code())
185 var problemDetails common29122.ProblemDetails
186 err = result.UnmarshalBodyToObject(&problemDetails)
187 assert.NoError(t, err, "error unmarshaling response")
188 badRequest := http.StatusBadRequest
189 assert.Equal(t, &badRequest, problemDetails.Status)
190 assert.Contains(t, *problemDetails.Cause, "missing")
191 assert.Contains(t, *problemDetails.Cause, "NotificationDestination")
193 // Update with an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
194 invalidInvoker.NotificationDestination = "url"
195 invalidInvoker.OnboardingInformation = invokermanagementapi.OnboardingInformation{}
196 result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
198 assert.Equal(t, http.StatusBadRequest, result.Code())
199 err = result.UnmarshalBodyToObject(&problemDetails)
200 assert.NoError(t, err, "error unmarshaling response")
201 assert.Equal(t, &badRequest, problemDetails.Status)
202 assert.Contains(t, *problemDetails.Cause, "missing")
203 assert.Contains(t, *problemDetails.Cause, "OnboardingInformation.ApiInvokerPublicKey")
205 // Update with an invoker with other ApiInvokerId than the one provided in the URL, should get 400 with problem details
207 invalidInvoker.ApiInvokerId = &invalidId
208 invalidInvoker.OnboardingInformation = validOnboardingInfo
209 result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
211 assert.Equal(t, http.StatusBadRequest, result.Code())
212 err = result.UnmarshalBodyToObject(&problemDetails)
213 assert.NoError(t, err, "error unmarshaling response")
214 assert.Equal(t, &badRequest, problemDetails.Status)
215 assert.Contains(t, *problemDetails.Cause, "not matching")
216 assert.Contains(t, *problemDetails.Cause, "ApiInvokerId")
218 // Update an invoker that has not been onboarded, shold get 404 with problem details
220 newInvoker.ApiInvokerId = &missingId
221 result = testutil.NewRequest().Put("/onboardedInvokers/"+missingId).WithJsonBody(newInvoker).Go(t, requestHandler)
223 assert.Equal(t, http.StatusNotFound, result.Code())
224 err = result.UnmarshalBodyToObject(&problemDetails)
225 assert.NoError(t, err, "error unmarshaling response")
226 notFound := http.StatusNotFound
227 assert.Equal(t, ¬Found, problemDetails.Status)
228 assert.Contains(t, *problemDetails.Cause, "not been onboarded")
229 assert.Contains(t, *problemDetails.Cause, "invoker")
232 func TestGetInvokerApiList(t *testing.T) {
233 aefProfiles1 := []publishserviceapi.AefProfile{
234 getAefProfile("aefId"),
237 apiList := []publishserviceapi.ServiceAPIDescription{
240 AefProfiles: &aefProfiles1,
243 aefProfiles2 := []publishserviceapi.AefProfile{
244 getAefProfile("aefId2"),
247 apiList = append(apiList, publishserviceapi.ServiceAPIDescription{
249 AefProfiles: &aefProfiles2,
251 publishRegisterMock := publishmocks.PublishRegister{}
252 publishRegisterMock.On("GetAllPublishedServices").Return(apiList)
253 invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
255 invokerInfo := "invoker a"
256 newInvoker := getInvoker(invokerInfo)
257 testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
258 newInvoker = getInvoker("invoker b")
259 testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
261 wantedApiList := invokerUnderTest.GetInvokerApiList("api_invoker_id_" + strings.Replace(invokerInfo, " ", "_", 1))
262 assert.NotNil(t, wantedApiList)
263 assert.Equal(t, apiId, *(*wantedApiList)[0].ApiId)
266 func getEcho(publishRegister publishservice.PublishRegister) (*InvokerManager, *echo.Echo) {
267 swagger, err := invokermanagementapi.GetSwagger()
269 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
273 swagger.Servers = nil
275 im := NewInvokerManager(publishRegister)
278 e.Use(echomiddleware.Logger())
279 e.Use(middleware.OapiRequestValidator(swagger))
281 invokermanagementapi.RegisterHandlers(e, im)
285 func getAefProfile(aefId string) publishserviceapi.AefProfile {
286 return publishserviceapi.AefProfile{
288 Versions: []publishserviceapi.Version{
290 Resources: &[]publishserviceapi.Resource{
292 CommType: "REQUEST_RESPONSE",
300 func getInvoker(invokerInfo string) invokermanagementapi.APIInvokerEnrolmentDetails {
301 newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
302 ApiInvokerInformation: &invokerInfo,
303 NotificationDestination: "url",
304 OnboardingInformation: invokermanagementapi.OnboardingInformation{
305 ApiInvokerPublicKey: "key",