Add get method for ApiList for invoker
[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         "path"
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         "github.com/stretchr/testify/mock"
44 )
45
46 func TestOnboardInvoker(t *testing.T) {
47         apiRegisterMock := publishmocks.APIRegister{}
48         apiRegisterMock.On("AreAPIsRegistered", mock.Anything).Return(true)
49         invokerUnderTest, requestHandler := getEcho(&apiRegisterMock)
50
51         aefProfiles := []publishserviceapi.AefProfile{
52                 getAefProfile("aefId"),
53         }
54         apiId := "apiId"
55         var apiList invokermanagementapi.APIList = []publishserviceapi.ServiceAPIDescription{
56                 {
57                         ApiId:       &apiId,
58                         AefProfiles: &aefProfiles,
59                 },
60         }
61         newInvoker := getInvoker("invoker a", apiList)
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         assert.Equal(t, "api_invoker_id_invoker_a", *resultInvoker.ApiInvokerId)
71         assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination)
72         assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
73         assert.Equal(t, "onboarding_secret_invoker_a", *resultInvoker.OnboardingInformation.OnboardingSecret)
74         assert.Equal(t, "http://example.com/onboardedInvokers/"+*resultInvoker.ApiInvokerId, result.Recorder.Header().Get(echo.HeaderLocation))
75         assert.True(t, invokerUnderTest.IsInvokerRegistered("api_invoker_id_invoker_a"))
76         assert.True(t, invokerUnderTest.VerifyInvokerSecret("api_invoker_id_invoker_a", "onboarding_secret_invoker_a"))
77         apiRegisterMock.AssertCalled(t, "AreAPIsRegistered", mock.Anything)
78
79         // Onboard an invoker missing required NotificationDestination, should get 400 with problem details
80         invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
81                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
82                         ApiInvokerPublicKey: "key",
83                 },
84         }
85         result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
86
87         assert.Equal(t, http.StatusBadRequest, result.Code())
88         var problemDetails common29122.ProblemDetails
89         err = result.UnmarshalBodyToObject(&problemDetails)
90         assert.NoError(t, err, "error unmarshaling response")
91         badRequest := http.StatusBadRequest
92         assert.Equal(t, &badRequest, problemDetails.Status)
93         errMsg := "Invoker missing required NotificationDestination"
94         assert.Equal(t, &errMsg, problemDetails.Cause)
95
96         // Onboard an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
97         invalidInvoker = invokermanagementapi.APIInvokerEnrolmentDetails{
98                 NotificationDestination: "url",
99         }
100
101         result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
102
103         assert.Equal(t, http.StatusBadRequest, result.Code())
104         err = result.UnmarshalBodyToObject(&problemDetails)
105         assert.NoError(t, err, "error unmarshaling response")
106         assert.Equal(t, &badRequest, problemDetails.Status)
107         errMsg = "Invoker missing required OnboardingInformation.ApiInvokerPublicKey"
108         assert.Equal(t, &errMsg, problemDetails.Cause)
109 }
110
111 func TestDeleteInvoker(t *testing.T) {
112         invokerUnderTest, requestHandler := getEcho(nil)
113
114         newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
115                 NotificationDestination: "url",
116                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
117                         ApiInvokerPublicKey: "key",
118                 },
119         }
120
121         // Onboard an invoker
122         result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
123
124         invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation)
125         assert.True(t, invokerUnderTest.IsInvokerRegistered(path.Base(invokerUrl)))
126
127         // Delete the invoker
128         result = testutil.NewRequest().Delete(invokerUrl).Go(t, requestHandler)
129
130         assert.Equal(t, http.StatusNoContent, result.Code())
131         assert.False(t, invokerUnderTest.IsInvokerRegistered(path.Base(invokerUrl)))
132 }
133
134 func TestUpdateInvoker(t *testing.T) {
135         _, requestHandler := getEcho(nil)
136
137         newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
138                 NotificationDestination: "url",
139                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
140                         ApiInvokerPublicKey: "key",
141                 },
142         }
143
144         // Onboard an invoker
145         result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
146         var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails
147         result.UnmarshalBodyToObject(&resultInvoker)
148
149         invokerId := resultInvoker.ApiInvokerId
150         invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation)
151
152         // Update the invoker with valid invoker, should return 200 with invoker details
153         result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(resultInvoker).Go(t, requestHandler)
154
155         assert.Equal(t, http.StatusOK, result.Code())
156         err := result.UnmarshalBodyToObject(&resultInvoker)
157         assert.NoError(t, err, "error unmarshaling response")
158         assert.Equal(t, invokerId, resultInvoker.ApiInvokerId)
159         assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination)
160         assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey)
161
162         // Update with an invoker missing required NotificationDestination, should get 400 with problem details
163         validOnboardingInfo := invokermanagementapi.OnboardingInformation{
164                 ApiInvokerPublicKey: "key",
165         }
166         invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
167                 ApiInvokerId:          invokerId,
168                 OnboardingInformation: validOnboardingInfo,
169         }
170         result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
171
172         assert.Equal(t, http.StatusBadRequest, result.Code())
173         var problemDetails common29122.ProblemDetails
174         err = result.UnmarshalBodyToObject(&problemDetails)
175         assert.NoError(t, err, "error unmarshaling response")
176         badRequest := http.StatusBadRequest
177         assert.Equal(t, &badRequest, problemDetails.Status)
178         errMsg := "Invoker missing required NotificationDestination"
179         assert.Equal(t, &errMsg, problemDetails.Cause)
180
181         // Update with an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
182         invalidInvoker.NotificationDestination = "url"
183         invalidInvoker.OnboardingInformation = invokermanagementapi.OnboardingInformation{}
184         result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
185
186         assert.Equal(t, http.StatusBadRequest, result.Code())
187         err = result.UnmarshalBodyToObject(&problemDetails)
188         assert.NoError(t, err, "error unmarshaling response")
189         assert.Equal(t, &badRequest, problemDetails.Status)
190         errMsg = "Invoker missing required OnboardingInformation.ApiInvokerPublicKey"
191         assert.Equal(t, &errMsg, problemDetails.Cause)
192
193         // Update with an invoker with other ApiInvokerId than the one provided in the URL, should get 400 with problem details
194         invalidId := "1"
195         invalidInvoker.ApiInvokerId = &invalidId
196         invalidInvoker.OnboardingInformation = validOnboardingInfo
197         result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
198
199         assert.Equal(t, http.StatusBadRequest, result.Code())
200         err = result.UnmarshalBodyToObject(&problemDetails)
201         assert.NoError(t, err, "error unmarshaling response")
202         assert.Equal(t, &badRequest, problemDetails.Status)
203         errMsg = "Invoker ApiInvokerId not matching"
204         assert.Equal(t, &errMsg, problemDetails.Cause)
205
206         // Update an invoker that has not been onboarded, shold get 404 with problem details
207         missingId := "1"
208         newInvoker.ApiInvokerId = &missingId
209         result = testutil.NewRequest().Put("/onboardedInvokers/"+missingId).WithJsonBody(newInvoker).Go(t, requestHandler)
210
211         assert.Equal(t, http.StatusNotFound, result.Code())
212         err = result.UnmarshalBodyToObject(&problemDetails)
213         assert.NoError(t, err, "error unmarshaling response")
214         notFound := http.StatusNotFound
215         assert.Equal(t, &notFound, problemDetails.Status)
216         errMsg = "The invoker to update has not been onboarded"
217         assert.Equal(t, &errMsg, problemDetails.Cause)
218 }
219
220 func TestGetInvokerApiList(t *testing.T) {
221         apiRegisterMock := publishmocks.APIRegister{}
222         apiRegisterMock.On("AreAPIsRegistered", mock.Anything).Return(true)
223         invokerUnderTest, requestHandler := getEcho(&apiRegisterMock)
224
225         // Onboard two invokers
226         aefProfiles := []publishserviceapi.AefProfile{
227                 getAefProfile("aefId"),
228         }
229         apiId := "apiId"
230         var apiList invokermanagementapi.APIList = []publishserviceapi.ServiceAPIDescription{
231                 {
232                         ApiId:       &apiId,
233                         AefProfiles: &aefProfiles,
234                 },
235         }
236         newInvoker := getInvoker("invoker a", apiList)
237         testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
238         aefProfiles = []publishserviceapi.AefProfile{
239                 getAefProfile("aefId2"),
240         }
241         apiId2 := "apiId2"
242         apiList = []publishserviceapi.ServiceAPIDescription{
243                 {
244                         ApiId:       &apiId2,
245                         AefProfiles: &aefProfiles,
246                 },
247         }
248         newInvoker = getInvoker("invoker b", apiList)
249         testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
250
251         wantedApiList := invokerUnderTest.GetInvokerApiList("api_invoker_id_invoker_a")
252         assert.NotNil(t, wantedApiList)
253         assert.Equal(t, apiId, *(*wantedApiList)[0].ApiId)
254 }
255
256 func getEcho(apiRegister publishservice.APIRegister) (*InvokerManager, *echo.Echo) {
257         swagger, err := invokermanagementapi.GetSwagger()
258         if err != nil {
259                 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
260                 os.Exit(1)
261         }
262
263         swagger.Servers = nil
264
265         im := NewInvokerManager(apiRegister)
266
267         e := echo.New()
268         e.Use(echomiddleware.Logger())
269         e.Use(middleware.OapiRequestValidator(swagger))
270
271         invokermanagementapi.RegisterHandlers(e, im)
272         return im, e
273 }
274
275 func getAefProfile(aefId string) publishserviceapi.AefProfile {
276         return publishserviceapi.AefProfile{
277                 AefId: aefId,
278                 Versions: []publishserviceapi.Version{
279                         {
280                                 Resources: &[]publishserviceapi.Resource{
281                                         {
282                                                 CommType: "REQUEST_RESPONSE",
283                                         },
284                                 },
285                         },
286                 },
287         }
288 }
289
290 func getInvoker(invokerInfo string, apiList invokermanagementapi.APIList) invokermanagementapi.APIInvokerEnrolmentDetails {
291         newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
292                 ApiInvokerInformation:   &invokerInfo,
293                 NotificationDestination: "url",
294                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
295                         ApiInvokerPublicKey: "key",
296                 },
297                 ApiList: &apiList,
298         }
299         return newInvoker
300 }