Add get all published services
[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         "strings"
28         "testing"
29
30         "oransc.org/nonrtric/capifcore/internal/invokermanagementapi"
31
32         "github.com/labstack/echo/v4"
33
34         "oransc.org/nonrtric/capifcore/internal/common29122"
35         "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
36
37         "oransc.org/nonrtric/capifcore/internal/publishservice"
38         publishmocks "oransc.org/nonrtric/capifcore/internal/publishservice/mocks"
39
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 )
45
46 func TestOnboardInvoker(t *testing.T) {
47         aefProfiles := []publishserviceapi.AefProfile{
48                 getAefProfile("aefId"),
49         }
50         apiId := "apiId"
51         publishedServices := []publishserviceapi.ServiceAPIDescription{
52                 {
53                         ApiId:       &apiId,
54                         AefProfiles: &aefProfiles,
55                 },
56         }
57         publishRegisterMock := publishmocks.PublishRegister{}
58         publishRegisterMock.On("GetAllPublishedServices").Return(publishedServices)
59         invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
60
61         invokerInfo := "invoker a"
62         newInvoker := getInvoker(invokerInfo)
63
64         // Onboard a valid invoker
65         result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
66
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)
82
83         // Onboard an invoker missing required NotificationDestination, should get 400 with problem details
84         invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
85                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
86                         ApiInvokerPublicKey: "key",
87                 },
88         }
89         result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
90
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")
99
100         // Onboard an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details
101         invalidInvoker = invokermanagementapi.APIInvokerEnrolmentDetails{
102                 NotificationDestination: "url",
103         }
104
105         result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler)
106
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")
113 }
114
115 func TestDeleteInvoker(t *testing.T) {
116         publishRegisterMock := publishmocks.PublishRegister{}
117         publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
118         invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
119
120         newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
121                 NotificationDestination: "url",
122                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
123                         ApiInvokerPublicKey: "key",
124                 },
125         }
126
127         // Onboard an invoker
128         result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
129
130         invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation)
131         assert.True(t, invokerUnderTest.IsInvokerRegistered(path.Base(invokerUrl)))
132
133         // Delete the invoker
134         result = testutil.NewRequest().Delete(invokerUrl).Go(t, requestHandler)
135
136         assert.Equal(t, http.StatusNoContent, result.Code())
137         assert.False(t, invokerUnderTest.IsInvokerRegistered(path.Base(invokerUrl)))
138 }
139
140 func TestUpdateInvoker(t *testing.T) {
141         publishRegisterMock := publishmocks.PublishRegister{}
142         publishRegisterMock.On("GetAllPublishedServices").Return([]publishserviceapi.ServiceAPIDescription{})
143         _, requestHandler := getEcho(&publishRegisterMock)
144
145         newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
146                 NotificationDestination: "url",
147                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
148                         ApiInvokerPublicKey: "key",
149                 },
150         }
151
152         // Onboard an invoker
153         result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler)
154         var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails
155         result.UnmarshalBodyToObject(&resultInvoker)
156
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)
166
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)
173
174         // Update with an invoker missing required NotificationDestination, should get 400 with problem details
175         validOnboardingInfo := invokermanagementapi.OnboardingInformation{
176                 ApiInvokerPublicKey: "key",
177         }
178         invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
179                 ApiInvokerId:          invokerId,
180                 OnboardingInformation: validOnboardingInfo,
181         }
182         result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
183
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")
192
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)
197
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")
204
205         // Update with an invoker with other ApiInvokerId than the one provided in the URL, should get 400 with problem details
206         invalidId := "1"
207         invalidInvoker.ApiInvokerId = &invalidId
208         invalidInvoker.OnboardingInformation = validOnboardingInfo
209         result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler)
210
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")
217
218         // Update an invoker that has not been onboarded, shold get 404 with problem details
219         missingId := "1"
220         newInvoker.ApiInvokerId = &missingId
221         result = testutil.NewRequest().Put("/onboardedInvokers/"+missingId).WithJsonBody(newInvoker).Go(t, requestHandler)
222
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, &notFound, problemDetails.Status)
228         assert.Contains(t, *problemDetails.Cause, "not been onboarded")
229         assert.Contains(t, *problemDetails.Cause, "invoker")
230 }
231
232 func TestGetInvokerApiList(t *testing.T) {
233         aefProfiles1 := []publishserviceapi.AefProfile{
234                 getAefProfile("aefId"),
235         }
236         apiId := "apiId"
237         apiList := []publishserviceapi.ServiceAPIDescription{
238                 {
239                         ApiId:       &apiId,
240                         AefProfiles: &aefProfiles1,
241                 },
242         }
243         aefProfiles2 := []publishserviceapi.AefProfile{
244                 getAefProfile("aefId2"),
245         }
246         apiId2 := "apiId2"
247         apiList = append(apiList, publishserviceapi.ServiceAPIDescription{
248                 ApiId:       &apiId2,
249                 AefProfiles: &aefProfiles2,
250         })
251         publishRegisterMock := publishmocks.PublishRegister{}
252         publishRegisterMock.On("GetAllPublishedServices").Return(apiList)
253         invokerUnderTest, requestHandler := getEcho(&publishRegisterMock)
254
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)
260
261         wantedApiList := invokerUnderTest.GetInvokerApiList("api_invoker_id_" + strings.Replace(invokerInfo, " ", "_", 1))
262         assert.NotNil(t, wantedApiList)
263         assert.Equal(t, apiId, *(*wantedApiList)[0].ApiId)
264 }
265
266 func getEcho(publishRegister publishservice.PublishRegister) (*InvokerManager, *echo.Echo) {
267         swagger, err := invokermanagementapi.GetSwagger()
268         if err != nil {
269                 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
270                 os.Exit(1)
271         }
272
273         swagger.Servers = nil
274
275         im := NewInvokerManager(publishRegister)
276
277         e := echo.New()
278         e.Use(echomiddleware.Logger())
279         e.Use(middleware.OapiRequestValidator(swagger))
280
281         invokermanagementapi.RegisterHandlers(e, im)
282         return im, e
283 }
284
285 func getAefProfile(aefId string) publishserviceapi.AefProfile {
286         return publishserviceapi.AefProfile{
287                 AefId: aefId,
288                 Versions: []publishserviceapi.Version{
289                         {
290                                 Resources: &[]publishserviceapi.Resource{
291                                         {
292                                                 CommType: "REQUEST_RESPONSE",
293                                         },
294                                 },
295                         },
296                 },
297         }
298 }
299
300 func getInvoker(invokerInfo string) invokermanagementapi.APIInvokerEnrolmentDetails {
301         newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{
302                 ApiInvokerInformation:   &invokerInfo,
303                 NotificationDestination: "url",
304                 OnboardingInformation: invokermanagementapi.OnboardingInformation{
305                         ApiInvokerPublicKey: "key",
306                 },
307                 ApiList: nil,
308         }
309         return newInvoker
310 }