c662d6d6693c903585371490833ff54d367f3252
[nonrtric/plt/sme.git] / capifcore / internal / invokermanagement / invokermanagement_test.go
1 // -
2 //
3 //      ========================LICENSE_START=================================
4 //      O-RAN-SC
5 //      %%
6 //      Copyright (C) 2022: Nordix Foundation
7 //      %%
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
11 //
12 //           http://www.apache.org/licenses/LICENSE-2.0
13 //
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
21
22 import (
23         "fmt"
24         "net/http"
25         "os"
26         "strings"
27         "testing"
28
29         "oransc.org/nonrtric/capifcore/internal/invokermanagementapi"
30
31         "github.com/labstack/echo/v4"
32
33         "oransc.org/nonrtric/capifcore/internal/common29122"
34         "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
35
36         "oransc.org/nonrtric/capifcore/internal/publishservice"
37         publishmocks "oransc.org/nonrtric/capifcore/internal/publishservice/mocks"
38
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"
43 )
44
45 func TestOnboardInvoker(t *testing.T) {
46         aefProfiles := []publishserviceapi.AefProfile{
47                 getAefProfile("aefId"),
48         }
49         apiId := "apiId"
50         publishedServices := []publishserviceapi.ServiceAPIDescription{
51                 {
52                         ApiId:       &apiId,
53                         AefProfiles: &aefProfiles,
54                 },
55         }
56         publishRegisterMock := publishmocks.PublishRegister{}
57         publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
58         invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
59
60         invokerInfo := "invoker a"
61         newInvoker := getInvoker(invokerInfo)
62
63         // Onboard a valid invoker
64         result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
65
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)
81
82         // Onboard an invoker missing required NotificationDestination, should get 400 with problem details
83         invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
84                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
85                         ApiInvokerPublicKey: "key",
86                 },
87         }
88         result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
89
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")
98
99         // Onboard an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
100         invalidInvoker = invokermanagementapi.APIInvokerEnrolmentDetails{
101                 NotificationDestination: "url",
102         }
103
104         result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
105
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")
112 }
113
114 func TestDeleteInvoker(t *testing.T) {
115         invokerUnderTest, requestHandler := getEcho(nil)
116
117         invokerId := "invokerId"
118         newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
119                 ApiInvokerId:            &invokerId,
120                 NotificationDestination: "url",
121                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
122                         ApiInvokerPublicKey: "key",
123                 },
124         }
125         invokerUnderTest.onboardedInvokers[invokerId] = newInvoker
126         assert.True(t, invokerUnderTest.IsInvokerRegistered(invokerId))
127
128         // Delete the invoker
129         result := testutil.NewRequest().Delete("/onboardedInvokers/"+invokerId).Go(t, requestHandler)
130
131         assert.Equal(t, http.StatusNoContent, result.Code())
132         assert.False(t, invokerUnderTest.IsInvokerRegistered(invokerId))
133 }
134
135 func TestUpdateInvoker(t *testing.T) {
136         publishRegisterMock := publishmocks.PublishRegister{}
137         publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
138         serviceUnderTest, requestHandler := getEcho(&publishRegisterMock)
139
140         invokerId := "invokerId"
141         invoker := invokermanagementapi.APIInvokerEnrolmentDetails{
142                 ApiInvokerId:            &invokerId,
143                 NotificationDestination: "url",
144                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
145                         ApiInvokerPublicKey: "key",
146                 },
147         }
148         serviceUnderTest.onboardedInvokers[invokerId] = invoker
149
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)
156
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)
164
165         // Update with an invoker missing required NotificationDestination, should get 400 with problem details
166         validOnboardingInfo := invokermanagementapi.OnboardingInformation{
167                 ApiInvokerPublicKey: "key",
168         }
169         invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
170                 ApiInvokerId:          &invokerId,
171                 OnboardingInformation: validOnboardingInfo,
172         }
173         result = testutil.NewRequest().Put("/onboardedInvokers/"+invokerId).WithJsonBody(invalidInvoker).Go(t, requestHandler)
174
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")
183
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)
188
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")
195
196         // Update with an invoker with other ApiInvokerId than the one provided in the URL, should get 400 with problem details
197         invalidId := "1"
198         invalidInvoker.ApiInvokerId = &invalidId
199         invalidInvoker.OnboardingInformation = validOnboardingInfo
200         result = testutil.NewRequest().Put("/onboardedInvokers/"+invokerId).WithJsonBody(invalidInvoker).Go(t, requestHandler)
201
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")
208
209         // Update an invoker that has not been onboarded, shold get 404 with problem details
210         missingId := "1"
211         invoker.ApiInvokerId = &missingId
212         result = testutil.NewRequest().Put("/onboardedInvokers/"+missingId).WithJsonBody(invoker).Go(t, requestHandler)
213
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, &notFound, problemDetails.Status)
219         assert.Contains(t, *problemDetails.Cause, "not been onboarded")
220         assert.Contains(t, *problemDetails.Cause, "invoker")
221 }
222
223 func TestGetInvokerApiList(t *testing.T) {
224         aefProfiles1 := []publishserviceapi.AefProfile{
225                 getAefProfile("aefId"),
226         }
227         apiId := "apiId"
228         apiList := []publishserviceapi.ServiceAPIDescription{
229                 {
230                         ApiId:       &apiId,
231                         AefProfiles: &aefProfiles1,
232                 },
233         }
234         aefProfiles2 := []publishserviceapi.AefProfile{
235                 getAefProfile("aefId2"),
236         }
237         apiId2 := "apiId2"
238         apiList = append(apiList, publishserviceapi.ServiceAPIDescription{
239                 ApiId:       &apiId2,
240                 AefProfiles: &aefProfiles2,
241         })
242         publishRegisterMock := publishmocks.PublishRegister{}
243         publishRegisterMock.On("GetAllPublishedServices").Return(apiList)
244         invokerUnderTest, _ := getEcho(&publishRegisterMock)
245
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
256
257         wantedApiList := invokerUnderTest.GetInvokerApiList(invokerAId)
258         assert.NotNil(t, wantedApiList)
259         assert.Len(t, *wantedApiList, 2)
260         assert.Equal(t, apiId, *(*wantedApiList)[0].ApiId)
261 }
262
263 func getEcho(publishRegister publishservice.PublishRegister) (*InvokerManager, *echo.Echo) {
264         swagger, err := invokermanagementapi.GetSwagger()
265         if err != nil {
266                 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
267                 os.Exit(1)
268         }
269
270         swagger.Servers = nil
271
272         im := NewInvokerManager(publishRegister)
273
274         e := echo.New()
275         e.Use(echomiddleware.Logger())
276         e.Use(middleware.OapiRequestValidator(swagger))
277
278         invokermanagementapi.RegisterHandlers(e, im)
279         return im, e
280 }
281
282 func getAefProfile(aefId string) publishserviceapi.AefProfile {
283         return publishserviceapi.AefProfile{
284                 AefId: aefId,
285                 Versions: []publishserviceapi.Version{
286                         {
287                                 Resources: &[]publishserviceapi.Resource{
288                                         {
289                                                 CommType: "REQUEST_RESPONSE",
290                                         },
291                                 },
292                         },
293                 },
294         }
295 }
296
297 func getInvoker(invokerInfo string) invokermanagementapi.APIInvokerEnrolmentDetails {
298         newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
299                 ApiInvokerInformation:   &invokerInfo,
300                 NotificationDestination: "url",
301                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
302                         ApiInvokerPublicKey: "key",
303                 },
304                 ApiList: nil,
305         }
306         return newInvoker
307 }