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
29 "oransc.org/nonrtric/capifcore/internal/invokermanagementapi"
31 "github.com/labstack/echo/v4"
33 "oransc.org/nonrtric/capifcore/internal/common29122"
34 "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
36 "oransc.org/nonrtric/capifcore/internal/publishservice"
37 publishmocks "oransc.org/nonrtric/capifcore/internal/publishservice/mocks"
39 "github.com/deepmap/oapi-codegen/pkg/middleware"
40 "github.com/deepmap/oapi-codegen/pkg/testutil"
41 echomiddleware "github.com/labstack/echo/v4/middleware"
42 "github.com/stretchr/testify/assert"
45 func TestOnboardInvoker(t *testing.T) {
46 aefProfiles := []publishserviceapi.AefProfile{
47 getAefProfile("aefId"),
50 publishedServices := []publishserviceapi.ServiceAPIDescription{
53 AefProfiles: &aefProfiles,
56 publishRegisterMock := publishmocks.PublishRegister{}
57 publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
58 invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
60 invokerInfo := "invoker a"
61 newInvoker := getInvoker(invokerInfo)
63 // Onboard a valid invoker
64 result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
66 assert.Equal(t, http.StatusCreated, result.Code())
67 var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails
68 err := result.UnmarshalBodyToObject(&resultInvoker)
69 assert.NoError(t, err, "error unmarshaling response")
70 wantedInvokerId := "api_invoker_id_" + strings.Replace(invokerInfo, " ", "_", 1)
71 assert.Equal(t, wantedInvokerId, *resultInvoker.ApiInvokerId)
72 assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination)
73 assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
74 wantedInvokerSecret := "onboarding_secret_" + strings.Replace(invokerInfo, " ", "_", 1)
75 assert.Equal(t, wantedInvokerSecret, *resultInvoker.OnboardingInformation.OnboardingSecret)
76 assert.Equal(t, "http://example.com/onboardedInvokers/"+*resultInvoker.ApiInvokerId, result.Recorder.Header().Get(echo.HeaderLocation))
77 assert.True(t, invokerUnderTest.IsInvokerRegistered(wantedInvokerId))
78 assert.True(t, invokerUnderTest.VerifyInvokerSecret(wantedInvokerId, wantedInvokerSecret))
79 publishRegisterMock.AssertCalled(t, "GetAllPublishedServices")
80 assert.Equal(t, invokermanagementapi.APIList(publishedServices), *resultInvoker.ApiList)
82 // Onboard an invoker missing required NotificationDestination, should get 400 with problem details
83 invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
84 OnboardingInformation: invokermanagementapi.OnboardingInformation{
85 ApiInvokerPublicKey: "key",
88 result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
90 assert.Equal(t, http.StatusBadRequest, result.Code())
91 var problemDetails common29122.ProblemDetails
92 err = result.UnmarshalBodyToObject(&problemDetails)
93 assert.NoError(t, err, "error unmarshaling response")
94 badRequest := http.StatusBadRequest
95 assert.Equal(t, &badRequest, problemDetails.Status)
96 assert.Contains(t, *problemDetails.Cause, "missing")
97 assert.Contains(t, *problemDetails.Cause, "NotificationDestination")
99 // Onboard an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
100 invalidInvoker = invokermanagementapi.APIInvokerEnrolmentDetails{
101 NotificationDestination: "url",
104 result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
106 assert.Equal(t, http.StatusBadRequest, result.Code())
107 err = result.UnmarshalBodyToObject(&problemDetails)
108 assert.NoError(t, err, "error unmarshaling response")
109 assert.Equal(t, &badRequest, problemDetails.Status)
110 assert.Contains(t, *problemDetails.Cause, "missing")
111 assert.Contains(t, *problemDetails.Cause, "OnboardingInformation.ApiInvokerPublicKey")
114 func TestDeleteInvoker(t *testing.T) {
115 invokerUnderTest, requestHandler := getEcho(nil)
117 invokerId := "invokerId"
118 newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
119 ApiInvokerId: &invokerId,
120 NotificationDestination: "url",
121 OnboardingInformation: invokermanagementapi.OnboardingInformation{
122 ApiInvokerPublicKey: "key",
125 invokerUnderTest.onboardedInvokers[invokerId] = newInvoker
126 assert.True(t, invokerUnderTest.IsInvokerRegistered(invokerId))
128 // Delete the invoker
129 result := testutil.NewRequest().Delete("/onboardedInvokers/"+invokerId).Go(t, requestHandler)
131 assert.Equal(t, http.StatusNoContent, result.Code())
132 assert.False(t, invokerUnderTest.IsInvokerRegistered(invokerId))
135 func TestUpdateInvoker(t *testing.T) {
136 publishRegisterMock := publishmocks.PublishRegister{}
137 publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
138 serviceUnderTest, requestHandler := getEcho(&publishRegisterMock)
140 invokerId := "invokerId"
141 invoker := invokermanagementapi.APIInvokerEnrolmentDetails{
142 ApiInvokerId: &invokerId,
143 NotificationDestination: "url",
144 OnboardingInformation: invokermanagementapi.OnboardingInformation{
145 ApiInvokerPublicKey: "key",
148 serviceUnderTest.onboardedInvokers[invokerId] = invoker
150 // Update the invoker with valid invoker, should return 200 with updated invoker details
151 newNotifURL := "newUrl"
152 invoker.NotificationDestination = common29122.Uri(newNotifURL)
153 newPublicKey := "newPublicKey"
154 invoker.OnboardingInformation.ApiInvokerPublicKey = newPublicKey
155 result := testutil.NewRequest().Put("/onboardedInvokers/"+invokerId).WithJsonBody(invoker).Go(t, requestHandler)
157 var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails
158 assert.Equal(t, http.StatusOK, result.Code())
159 err := result.UnmarshalBodyToObject(&resultInvoker)
160 assert.NoError(t, err, "error unmarshaling response")
161 assert.Equal(t, invokerId, *resultInvoker.ApiInvokerId)
162 assert.Equal(t, newNotifURL, string(resultInvoker.NotificationDestination))
163 assert.Equal(t, newPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
165 // Update with an invoker missing required NotificationDestination, should get 400 with problem details
166 validOnboardingInfo := invokermanagementapi.OnboardingInformation{
167 ApiInvokerPublicKey: "key",
169 invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
170 ApiInvokerId: &invokerId,
171 OnboardingInformation: validOnboardingInfo,
173 result = testutil.NewRequest().Put("/onboardedInvokers/"+invokerId).WithJsonBody(invalidInvoker).Go(t, requestHandler)
175 assert.Equal(t, http.StatusBadRequest, result.Code())
176 var problemDetails common29122.ProblemDetails
177 err = result.UnmarshalBodyToObject(&problemDetails)
178 assert.NoError(t, err, "error unmarshaling response")
179 badRequest := http.StatusBadRequest
180 assert.Equal(t, &badRequest, problemDetails.Status)
181 assert.Contains(t, *problemDetails.Cause, "missing")
182 assert.Contains(t, *problemDetails.Cause, "NotificationDestination")
184 // Update with an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
185 invalidInvoker.NotificationDestination = "url"
186 invalidInvoker.OnboardingInformation = invokermanagementapi.OnboardingInformation{}
187 result = testutil.NewRequest().Put("/onboardedInvokers/"+invokerId).WithJsonBody(invalidInvoker).Go(t, requestHandler)
189 assert.Equal(t, http.StatusBadRequest, result.Code())
190 err = result.UnmarshalBodyToObject(&problemDetails)
191 assert.NoError(t, err, "error unmarshaling response")
192 assert.Equal(t, &badRequest, problemDetails.Status)
193 assert.Contains(t, *problemDetails.Cause, "missing")
194 assert.Contains(t, *problemDetails.Cause, "OnboardingInformation.ApiInvokerPublicKey")
196 // Update with an invoker with other ApiInvokerId than the one provided in the URL, should get 400 with problem details
198 invalidInvoker.ApiInvokerId = &invalidId
199 invalidInvoker.OnboardingInformation = validOnboardingInfo
200 result = testutil.NewRequest().Put("/onboardedInvokers/"+invokerId).WithJsonBody(invalidInvoker).Go(t, requestHandler)
202 assert.Equal(t, http.StatusBadRequest, result.Code())
203 err = result.UnmarshalBodyToObject(&problemDetails)
204 assert.NoError(t, err, "error unmarshaling response")
205 assert.Equal(t, &badRequest, problemDetails.Status)
206 assert.Contains(t, *problemDetails.Cause, "not matching")
207 assert.Contains(t, *problemDetails.Cause, "ApiInvokerId")
209 // Update an invoker that has not been onboarded, shold get 404 with problem details
211 invoker.ApiInvokerId = &missingId
212 result = testutil.NewRequest().Put("/onboardedInvokers/"+missingId).WithJsonBody(invoker).Go(t, requestHandler)
214 assert.Equal(t, http.StatusNotFound, result.Code())
215 err = result.UnmarshalBodyToObject(&problemDetails)
216 assert.NoError(t, err, "error unmarshaling response")
217 notFound := http.StatusNotFound
218 assert.Equal(t, ¬Found, problemDetails.Status)
219 assert.Contains(t, *problemDetails.Cause, "not been onboarded")
220 assert.Contains(t, *problemDetails.Cause, "invoker")
223 func TestGetInvokerApiList(t *testing.T) {
224 aefProfiles1 := []publishserviceapi.AefProfile{
225 getAefProfile("aefId"),
228 apiList := []publishserviceapi.ServiceAPIDescription{
231 AefProfiles: &aefProfiles1,
234 aefProfiles2 := []publishserviceapi.AefProfile{
235 getAefProfile("aefId2"),
238 apiList = append(apiList, publishserviceapi.ServiceAPIDescription{
240 AefProfiles: &aefProfiles2,
242 publishRegisterMock := publishmocks.PublishRegister{}
243 publishRegisterMock.On("GetAllPublishedServices").Return(apiList)
244 invokerUnderTest, _ := getEcho(&publishRegisterMock)
246 invokerInfo := "invoker a"
247 newInvoker := getInvoker(invokerInfo)
248 invokerAId := "api_invoker_id_" + strings.ReplaceAll(invokerInfo, " ", "_")
249 newInvoker.ApiInvokerId = &invokerAId
250 invokerUnderTest.onboardedInvokers[invokerAId] = newInvoker
251 invokerInfo = "invoker b"
252 newInvoker = getInvoker(invokerInfo)
253 invokerId := "api_invoker_id_" + strings.ReplaceAll(invokerInfo, " ", "_")
254 newInvoker.ApiInvokerId = &invokerId
255 invokerUnderTest.onboardedInvokers[invokerId] = newInvoker
257 wantedApiList := invokerUnderTest.GetInvokerApiList(invokerAId)
258 assert.NotNil(t, wantedApiList)
259 assert.Len(t, *wantedApiList, 2)
260 assert.Equal(t, apiId, *(*wantedApiList)[0].ApiId)
263 func getEcho(publishRegister publishservice.PublishRegister) (*InvokerManager, *echo.Echo) {
264 swagger, err := invokermanagementapi.GetSwagger()
266 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
270 swagger.Servers = nil
272 im := NewInvokerManager(publishRegister)
275 e.Use(echomiddleware.Logger())
276 e.Use(middleware.OapiRequestValidator(swagger))
278 invokermanagementapi.RegisterHandlers(e, im)
282 func getAefProfile(aefId string) publishserviceapi.AefProfile {
283 return publishserviceapi.AefProfile{
285 Versions: []publishserviceapi.Version{
287 Resources: &[]publishserviceapi.Resource{
289 CommType: "REQUEST_RESPONSE",
297 func getInvoker(invokerInfo string) invokermanagementapi.APIInvokerEnrolmentDetails {
298 newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
299 ApiInvokerInformation: &invokerInfo,
300 NotificationDestination: "url",
301 OnboardingInformation: invokermanagementapi.OnboardingInformation{
302 ApiInvokerPublicKey: "key",