Improve error messages and tests
[nonrtric/plt/sme.git] / capifcore / internal / discoverservice / discoverservice_test.go
1 // -
2 //   ========================LICENSE_START=================================
3 //   O-RAN-SC
4 //   %%
5 //   Copyright (C) 2022: Nordix Foundation
6 //   %%
7 //   Licensed under the Apache License, Version 2.0 (the "License");
8 //   you may not use this file except in compliance with the License.
9 //   You may obtain a copy of the License at
10 //
11 //        http://www.apache.org/licenses/LICENSE-2.0
12 //
13 //   Unless required by applicable law or agreed to in writing, software
14 //   distributed under the License is distributed on an "AS IS" BASIS,
15 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 //   See the License for the specific language governing permissions and
17 //   limitations under the License.
18 //   ========================LICENSE_END===================================
19 //
20
21 package discoverservice
22
23 import (
24         "fmt"
25         "net/http"
26         "os"
27         "testing"
28
29         "oransc.org/nonrtric/capifcore/internal/common29122"
30         "oransc.org/nonrtric/capifcore/internal/discoverserviceapi"
31         "oransc.org/nonrtric/capifcore/internal/invokermanagement"
32         "oransc.org/nonrtric/capifcore/internal/invokermanagementapi"
33
34         "github.com/labstack/echo/v4"
35
36         publishapi "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
37
38         "oransc.org/nonrtric/capifcore/internal/invokermanagement/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 var protocolHTTP11 = publishapi.ProtocolHTTP11
47 var dataFormatJSON = publishapi.DataFormatJSON
48
49 func TestGetAllServiceAPIs(t *testing.T) {
50         var err error
51
52         apiName1 := "apiName1"
53         apiName2 := "apiName2"
54         apiList := []publishapi.ServiceAPIDescription{
55                 getAPI(apiName1, "aefId", "apiCategory", "v1", nil, nil, ""),
56                 getAPI(apiName2, "aefId", "apiCategory", "v1", nil, nil, ""),
57         }
58         invokerId := "api_invoker_id"
59         invokerRegisterrMock := getInvokerRegisterMock(invokerId, apiList)
60         requestHandler := getEcho(invokerRegisterrMock)
61
62         // Get all APIs, without any filter
63         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId).Go(t, requestHandler)
64
65         assert.Equal(t, http.StatusOK, result.Code())
66         var resultInvoker discoverserviceapi.DiscoveredAPIs
67         err = result.UnmarshalBodyToObject(&resultInvoker)
68         assert.NoError(t, err, "error unmarshaling response")
69         assert.Equal(t, 2, len(*resultInvoker.ServiceAPIDescriptions))
70         assert.Equal(t, apiName1, (*resultInvoker.ServiceAPIDescriptions)[0].ApiName)
71         assert.Equal(t, apiName2, (*resultInvoker.ServiceAPIDescriptions)[1].ApiName)
72         assert.Equal(t, 2, len(*resultInvoker.ServiceAPIDescriptions))
73 }
74
75 func TestGetAllServiceAPIsWhenMissingProvider(t *testing.T) {
76         invokerId := "unregistered"
77         invokerRegisterrMock := getInvokerRegisterMock(invokerId, nil)
78
79         requestHandler := getEcho(invokerRegisterrMock)
80
81         // Get all APIs, without any filter
82         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId).Go(t, requestHandler)
83
84         assert.Equal(t, http.StatusNotFound, result.Code())
85         var problemDetails common29122.ProblemDetails
86         err := result.UnmarshalBodyToObject(&problemDetails)
87         assert.NoError(t, err, "error unmarshaling response")
88         notFound := http.StatusNotFound
89         assert.Equal(t, &notFound, problemDetails.Status)
90         assert.Contains(t, *problemDetails.Cause, invokerId)
91         assert.Contains(t, *problemDetails.Cause, "not registered")
92 }
93
94 func TestFilterApiName(t *testing.T) {
95         var err error
96
97         apiName := "apiName1"
98         apiList := []publishapi.ServiceAPIDescription{
99                 getAPI(apiName, "", "", "", nil, nil, ""),
100                 getAPI("apiName2", "", "", "", nil, nil, ""),
101         }
102         invokerId := "api_invoker_id"
103         invokerRegisterrMock := getInvokerRegisterMock(invokerId, apiList)
104         requestHandler := getEcho(invokerRegisterrMock)
105
106         // Get APIs with filter
107         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId+"&api-name="+apiName).Go(t, requestHandler)
108
109         assert.Equal(t, http.StatusOK, result.Code())
110         var resultInvoker discoverserviceapi.DiscoveredAPIs
111         err = result.UnmarshalBodyToObject(&resultInvoker)
112         assert.NoError(t, err, "error unmarshaling response")
113         assert.Equal(t, 1, len(*resultInvoker.ServiceAPIDescriptions))
114         assert.Equal(t, apiName, (*resultInvoker.ServiceAPIDescriptions)[0].ApiName)
115 }
116
117 func TestFilterAefId(t *testing.T) {
118         var err error
119
120         apiName := "apiName1"
121         aefId := "aefId"
122         apiList := []publishapi.ServiceAPIDescription{
123                 getAPI(apiName, aefId, "", "", nil, nil, ""),
124                 getAPI("apiName2", "otherAefId", "", "", nil, nil, ""),
125         }
126         invokerId := "api_invoker_id"
127         invokerRegisterrMock := getInvokerRegisterMock(invokerId, apiList)
128         requestHandler := getEcho(invokerRegisterrMock)
129
130         // Get APIs with filter
131         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId+"&aef-id="+aefId).Go(t, requestHandler)
132
133         assert.Equal(t, http.StatusOK, result.Code())
134         var resultInvoker discoverserviceapi.DiscoveredAPIs
135         err = result.UnmarshalBodyToObject(&resultInvoker)
136         assert.NoError(t, err, "error unmarshaling response")
137         assert.Equal(t, 1, len(*resultInvoker.ServiceAPIDescriptions))
138         assert.Equal(t, apiName, (*resultInvoker.ServiceAPIDescriptions)[0].ApiName)
139 }
140
141 func TestFilterVersion(t *testing.T) {
142         var err error
143
144         apiName := "apiName1"
145         version := "v1"
146         apiList := []publishapi.ServiceAPIDescription{
147                 getAPI(apiName, "", "", version, nil, nil, ""),
148                 getAPI("apiName2", "", "", "v2", nil, nil, ""),
149         }
150         invokerId := "api_invoker_id"
151         invokerRegisterrMock := getInvokerRegisterMock(invokerId, apiList)
152         requestHandler := getEcho(invokerRegisterrMock)
153
154         // Get APIs with filter
155         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId+"&api-version="+version).Go(t, requestHandler)
156
157         assert.Equal(t, http.StatusOK, result.Code())
158         var resultInvoker discoverserviceapi.DiscoveredAPIs
159         err = result.UnmarshalBodyToObject(&resultInvoker)
160         assert.NoError(t, err, "error unmarshaling response")
161         assert.Equal(t, 1, len(*resultInvoker.ServiceAPIDescriptions))
162         assert.Equal(t, apiName, (*resultInvoker.ServiceAPIDescriptions)[0].ApiName)
163 }
164
165 func TestFilterCommType(t *testing.T) {
166         var err error
167
168         apiName := "apiName1"
169         commType := publishapi.CommunicationTypeREQUESTRESPONSE
170         apiList := []publishapi.ServiceAPIDescription{
171                 getAPI(apiName, "", "", "", nil, nil, commType),
172                 getAPI("apiName2", "", "", "", nil, nil, publishapi.CommunicationTypeSUBSCRIBENOTIFY),
173         }
174         invokerId := "api_invoker_id"
175         invokerRegisterrMock := getInvokerRegisterMock(invokerId, apiList)
176         requestHandler := getEcho(invokerRegisterrMock)
177
178         // Get APIs with filter
179         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId+"&comm-type="+string(commType)).Go(t, requestHandler)
180
181         assert.Equal(t, http.StatusOK, result.Code())
182         var resultInvoker discoverserviceapi.DiscoveredAPIs
183         err = result.UnmarshalBodyToObject(&resultInvoker)
184         assert.NoError(t, err, "error unmarshaling response")
185         assert.Equal(t, 1, len(*resultInvoker.ServiceAPIDescriptions))
186         assert.Equal(t, apiName, (*resultInvoker.ServiceAPIDescriptions)[0].ApiName)
187 }
188
189 func TestFilterVersionAndCommType(t *testing.T) {
190         var err error
191
192         apiName := "apiName2"
193         version := "v1"
194         commType := publishapi.CommunicationTypeSUBSCRIBENOTIFY
195         apiList := []publishapi.ServiceAPIDescription{
196                 getAPI("apiName1", "", "", version, nil, nil, publishapi.CommunicationTypeREQUESTRESPONSE),
197                 getAPI(apiName, "", "", version, nil, nil, commType),
198                 getAPI("apiName3", "", "", "v2", nil, nil, commType),
199         }
200         invokerId := "api_invoker_id"
201         invokerRegisterrMock := getInvokerRegisterMock(invokerId, apiList)
202         requestHandler := getEcho(invokerRegisterrMock)
203
204         // Get APIs with filter
205         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId+"&api-version="+version+"&comm-type="+string(commType)).Go(t, requestHandler)
206
207         assert.Equal(t, http.StatusOK, result.Code())
208         var resultInvoker discoverserviceapi.DiscoveredAPIs
209         err = result.UnmarshalBodyToObject(&resultInvoker)
210         assert.NoError(t, err, "error unmarshaling response")
211         assert.Equal(t, 1, len(*resultInvoker.ServiceAPIDescriptions))
212         assert.Equal(t, apiName, (*resultInvoker.ServiceAPIDescriptions)[0].ApiName)
213 }
214
215 func TestFilterAPICategory(t *testing.T) {
216         var err error
217
218         apiName := "apiName1"
219         apiCategory := "apiCategory"
220         apiList := []publishapi.ServiceAPIDescription{
221                 getAPI(apiName, "", apiCategory, "", nil, nil, ""),
222                 getAPI("apiName2", "", "", "", nil, nil, ""),
223         }
224         invokerId := "api_invoker_id"
225         invokerRegisterrMock := getInvokerRegisterMock(invokerId, apiList)
226         requestHandler := getEcho(invokerRegisterrMock)
227
228         // Get APIs with filter
229         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId+"&api-cat="+apiCategory).Go(t, requestHandler)
230
231         assert.Equal(t, http.StatusOK, result.Code())
232         var resultInvoker discoverserviceapi.DiscoveredAPIs
233         err = result.UnmarshalBodyToObject(&resultInvoker)
234         assert.NoError(t, err, "error unmarshaling response")
235         assert.Equal(t, 1, len(*resultInvoker.ServiceAPIDescriptions))
236         assert.Equal(t, apiName, (*resultInvoker.ServiceAPIDescriptions)[0].ApiName)
237 }
238
239 func TestFilterProtocol(t *testing.T) {
240         var err error
241
242         apiName := "apiName1"
243         apiList := []publishapi.ServiceAPIDescription{
244                 getAPI(apiName, "", "", "", &protocolHTTP11, nil, ""),
245                 getAPI("apiName2", "", "", "", nil, nil, ""),
246         }
247         invokerId := "api_invoker_id"
248         invokerRegisterrMock := getInvokerRegisterMock(invokerId, apiList)
249         requestHandler := getEcho(invokerRegisterrMock)
250
251         // Get APIs with filter
252         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId+"&protocol="+string(protocolHTTP11)).Go(t, requestHandler)
253
254         assert.Equal(t, http.StatusOK, result.Code())
255         var resultInvoker discoverserviceapi.DiscoveredAPIs
256         err = result.UnmarshalBodyToObject(&resultInvoker)
257         assert.NoError(t, err, "error unmarshaling response")
258         assert.Equal(t, 1, len(*resultInvoker.ServiceAPIDescriptions))
259         assert.Equal(t, apiName, (*resultInvoker.ServiceAPIDescriptions)[0].ApiName)
260 }
261
262 var DataFormatOther publishapi.DataFormat = "OTHER"
263
264 func TestFilterDataFormat(t *testing.T) {
265         var err error
266
267         apiName := "apiName1"
268         apiList := []publishapi.ServiceAPIDescription{
269                 getAPI(apiName, "", "", "", nil, &dataFormatJSON, ""),
270                 getAPI("apiName2", "", "", "", nil, nil, ""),
271         }
272         invokerId := "api_invoker_id"
273         invokerRegisterrMock := getInvokerRegisterMock(invokerId, apiList)
274         requestHandler := getEcho(invokerRegisterrMock)
275
276         // Get APIs with filter
277         result := testutil.NewRequest().Get("/allServiceAPIs?api-invoker-id="+invokerId+"&data-format="+string(dataFormatJSON)).Go(t, requestHandler)
278
279         assert.Equal(t, http.StatusOK, result.Code())
280         var resultInvoker discoverserviceapi.DiscoveredAPIs
281         err = result.UnmarshalBodyToObject(&resultInvoker)
282         assert.NoError(t, err, "error unmarshaling response")
283         assert.Equal(t, 1, len(*resultInvoker.ServiceAPIDescriptions))
284         assert.Equal(t, apiName, (*resultInvoker.ServiceAPIDescriptions)[0].ApiName)
285 }
286
287 func getEcho(invokerManager invokermanagement.InvokerRegister) *echo.Echo {
288         swagger, err := discoverserviceapi.GetSwagger()
289         if err != nil {
290                 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
291                 os.Exit(1)
292         }
293
294         swagger.Servers = nil
295
296         ds := NewDiscoverService(invokerManager)
297
298         e := echo.New()
299         e.Use(echomiddleware.Logger())
300         e.Use(middleware.OapiRequestValidator(swagger))
301
302         discoverserviceapi.RegisterHandlers(e, ds)
303         return e
304 }
305
306 func getInvokerRegisterMock(invokerId string, apisToReturn []publishapi.ServiceAPIDescription) *mocks.InvokerRegister {
307         apiList := invokermanagementapi.APIList(apisToReturn)
308         invokerRegisterrMock := mocks.InvokerRegister{}
309         if apisToReturn != nil {
310                 invokerRegisterrMock.On("GetInvokerApiList", invokerId).Return(&apiList)
311         } else {
312                 invokerRegisterrMock.On("GetInvokerApiList", invokerId).Return(nil)
313         }
314         return &invokerRegisterrMock
315 }
316
317 func getAPI(apiName, aefId, apiCategory, apiVersion string, protocol *publishapi.Protocol, dataFormat *publishapi.DataFormat, commType publishapi.CommunicationType) publishapi.ServiceAPIDescription {
318         apiId := "apiId_" + apiName
319         description := "description"
320         domainName := "domain"
321         otherDomainName := "otherDomain"
322         var otherProtocol publishapi.Protocol = "HTTP_2"
323         categoryPointer := &apiCategory
324         if apiCategory == "" {
325                 categoryPointer = nil
326         }
327         return publishapi.ServiceAPIDescription{
328                 ApiId:              &apiId,
329                 ApiName:            apiName,
330                 Description:        &description,
331                 ServiceAPICategory: categoryPointer,
332                 AefProfiles: &[]publishapi.AefProfile{
333                         {
334                                 AefId:      aefId,
335                                 DomainName: &domainName,
336                                 Protocol:   protocol,
337                                 DataFormat: dataFormat,
338                                 Versions: []publishapi.Version{
339                                         {
340                                                 ApiVersion: apiVersion,
341                                                 Resources: &[]publishapi.Resource{
342                                                         {
343                                                                 ResourceName: "app",
344                                                                 CommType:     commType,
345                                                                 Uri:          "uri",
346                                                                 Operations: &[]publishapi.Operation{
347                                                                         "POST",
348                                                                 },
349                                                         },
350                                                 },
351                                         },
352                                         {
353                                                 ApiVersion: "v2",
354                                                 Resources: &[]publishapi.Resource{
355                                                         {
356                                                                 ResourceName: "app",
357                                                                 CommType:     publishapi.CommunicationTypeSUBSCRIBENOTIFY,
358                                                                 Uri:          "uri",
359                                                                 Operations: &[]publishapi.Operation{
360                                                                         "POST",
361                                                                 },
362                                                         },
363                                                 },
364                                         },
365                                 },
366                         },
367                         {
368                                 AefId:      "otherAefId",
369                                 DomainName: &otherDomainName,
370                                 Protocol:   &otherProtocol,
371                                 DataFormat: &DataFormatOther,
372                                 Versions: []publishapi.Version{
373                                         {
374                                                 ApiVersion: "v3",
375                                                 Resources: &[]publishapi.Resource{
376                                                         {
377                                                                 ResourceName: "app",
378                                                                 CommType:     commType,
379                                                                 Uri:          "uri",
380                                                                 Operations: &[]publishapi.Operation{
381                                                                         "POST",
382                                                                 },
383                                                         },
384                                                 },
385                                         },
386                                 },
387                         },
388                 },
389         }
390 }