NONRTRIC-946: Servicemanager - add Kong data plane and control plane
[nonrtric/plt/sme.git] / servicemanager / internal / providermanagement / providermanagement_test.go
1 // -
2 //   ========================LICENSE_START=================================
3 //   O-RAN-SC
4 //   %%
5 //   Copyright (C) 2024: OpenInfra Foundation Europe
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 providermanagement
22
23 import (
24         "net/http"
25         "net/http/httptest"
26         "net/url"
27         "os"
28         "strings"
29         "testing"
30
31         echo "github.com/labstack/echo/v4"
32
33         "oransc.org/nonrtric/servicemanager/internal/common29122"
34         "oransc.org/nonrtric/servicemanager/internal/envreader"
35         "oransc.org/nonrtric/servicemanager/internal/kongclear"
36
37         provapi "oransc.org/nonrtric/servicemanager/internal/providermanagementapi"
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         log "github.com/sirupsen/logrus"
43
44         "github.com/stretchr/testify/assert"
45
46         "oransc.org/nonrtric/capifcore"
47         "oransc.org/nonrtric/servicemanager/mockkong"
48 )
49
50 var (
51         domainID    = "domain_id_Kong"
52         domainInfo  = "Kong"
53         funcInfoAPF = "rApp Kong as APF"
54         funcIdAPF   = "APF_id_rApp_Kong_as_APF"
55         funcInfoAEF = "rApp Kong as AEF"
56         funcIdAEF   = "AEF_id_rApp_Kong_as_AEF"
57 )
58
59 var (
60         eServiceManager          *echo.Echo
61         eCapifWeb                *echo.Echo
62         eKong                    *echo.Echo
63         mockConfigReader         *envreader.MockConfigReader
64         serviceManagerServer *httptest.Server
65         capifServer              *httptest.Server
66         mockKongServer           *httptest.Server
67 )
68
69 func TestMain(m *testing.M) {
70         err := setupTest()
71         if err != nil {
72                 return
73         }
74
75         ret := m.Run()
76         if ret == 0 {
77                 teardown()
78         }
79         os.Exit(ret)
80 }
81
82 func setupTest() error {
83         // Start the mock Kong server
84         eKong = echo.New()
85         mockKong.RegisterHandlers(eKong)
86         mockKongServer = httptest.NewServer(eKong)
87
88         // Parse the server URL
89         parsedMockKongURL, err := url.Parse(mockKongServer.URL)
90         if err != nil {
91                 log.Fatalf("error parsing mock Kong URL: %v", err)
92                 return err
93         }
94
95         // Extract the host and port
96         mockKongHost := parsedMockKongURL.Hostname()
97         mockKongControlPlanePort := parsedMockKongURL.Port()
98
99         eCapifWeb = echo.New()
100         capifcore.RegisterHandlers(eCapifWeb, nil, nil)
101         capifServer = httptest.NewServer(eCapifWeb)
102
103         // Parse the server URL
104         parsedCapifURL, err := url.Parse(capifServer.URL)
105         if err != nil {
106                 log.Fatalf("error parsing mock Kong URL: %v", err)
107                 return err
108         }
109
110         // Extract the host and port
111         capifHost := parsedCapifURL.Hostname()
112         capifPort := parsedCapifURL.Port()
113
114         // Set up the mock config reader with the desired configuration for testing
115         mockConfigReader = &envreader.MockConfigReader{
116                 MockedConfig: map[string]string{
117                         "KONG_DOMAIN":             "kong",
118                         "KONG_PROTOCOL":           "http",
119                         "KONG_CONTROL_PLANE_IPV4":  mockKongHost,
120                         "KONG_CONTROL_PLANE_PORT":  mockKongControlPlanePort,
121                         "KONG_DATA_PLANE_IPV4":    "10.101.1.101",
122                         "KONG_DATA_PLANE_PORT":    "32080",
123                         "CAPIF_PROTOCOL":          "http",
124                         "CAPIF_IPV4":              capifHost,
125                         "CAPIF_PORT":              capifPort,
126                         "LOG_LEVEL":               "Info",
127                         "SERVICE_MANAGER_PORT":    "8095",
128                         "TEST_SERVICE_IPV4":       "10.101.1.101",
129                         "TEST_SERVICE_PORT":       "30951",
130                 },
131         }
132
133         myEnv, myPorts, err := mockConfigReader.ReadDotEnv()
134         if err != nil {
135                 log.Fatal("error loading environment file on setupTest")
136                 return err
137         }
138
139         eServiceManager = echo.New()
140         err = registerHandlers(eServiceManager, myEnv, myPorts)
141         if err != nil {
142                 log.Fatal("registerHandlers fatal error on setupTest")
143                 return err
144         }
145         serviceManagerServer = httptest.NewServer(eServiceManager)
146
147         return err
148 }
149
150
151 func capifCleanUp() {
152         t := new(testing.T) // Create a new testing.T instance for capifCleanUp
153
154         // Delete the invoker
155         invokerInfo := "invoker a"
156         invokerId := "api_invoker_id_" + strings.Replace(invokerInfo, " ", "_", 1)
157
158         result := testutil.NewRequest().Delete("/api-invoker-management/v1/onboardedInvokers/"+invokerId).Go(t, eServiceManager)
159         assert.Equal(t, http.StatusNoContent, result.Code())
160
161         // Delete the original published service
162         apfId := "APF_id_rApp_Kong_as_APF"
163         apiName := "apiName"
164         apiId := "api_id_" + apiName
165
166         result = testutil.NewRequest().Delete("/published-apis/v1/"+apfId+"/service-apis/"+apiId).Go(t, eServiceManager)
167         assert.Equal(t, http.StatusNoContent, result.Code())
168
169         // Delete the first published service
170         apfId = "APF_id_rApp_Kong_as_APF"
171         apiName = "apiName1"
172         apiId = "api_id_" + apiName
173
174         result = testutil.NewRequest().Delete("/published-apis/v1/"+apfId+"/service-apis/"+apiId).Go(t, eServiceManager)
175         assert.Equal(t, http.StatusNoContent, result.Code())
176
177         // Delete the second published service
178         apiName = "apiName2"
179         apiId = "api_id_" + apiName
180
181         result = testutil.NewRequest().Delete("/published-apis/v1/"+apfId+"/service-apis/"+apiId).Go(t, eServiceManager)
182         assert.Equal(t, http.StatusNoContent, result.Code())
183
184         // Delete the provider
185         result = testutil.NewRequest().Delete("/api-provider-management/v1/registrations/"+domainID).Go(t, eServiceManager)
186         assert.Equal(t, http.StatusNoContent, result.Code())
187 }
188
189
190 func teardown() error {
191         log.Trace("entering teardown")
192
193         myEnv, myPorts, err := mockConfigReader.ReadDotEnv()
194         if err != nil {
195                 log.Fatal("error loading environment file")
196                 return err
197         }
198
199         err = kongclear.KongClear(myEnv, myPorts)
200         if err != nil {
201                 log.Fatal("error clearing Kong on teardown")
202         }
203
204         mockKongServer.Close()
205         capifServer.Close()
206         serviceManagerServer.Close()
207
208         return nil
209 }
210
211 func TestRegisterValidProvider(t *testing.T) {
212         capifCleanUp()
213
214         // Register a valid provider
215         newProvider := getProvider()
216         result := testutil.NewRequest().Post("/api-provider-management/v1/registrations").WithJsonBody(newProvider).Go(t, eServiceManager)
217         assert.Equal(t, http.StatusCreated, result.Code())
218
219         var resultProvider provapi.APIProviderEnrolmentDetails
220         err := result.UnmarshalBodyToObject(&resultProvider)
221         assert.NoError(t, err, "error unmarshaling response")
222
223         assert.NotNil(t, resultProvider.ApiProvDomId, "error reading resultProvider")
224
225         if resultProvider.ApiProvDomId != nil {
226                 assert.Equal(t, *resultProvider.ApiProvDomId, domainID)
227
228                 apiProvFuncAPF := (*resultProvider.ApiProvFuncs)[0]
229                 apiProvFuncIdAPF := *apiProvFuncAPF.ApiProvFuncId
230                 assert.Equal(t, apiProvFuncIdAPF, funcIdAPF)
231
232                 // We don't handle AMF
233                 apiProvFuncAEF := (*resultProvider.ApiProvFuncs)[1]
234                 apiProvFuncIdAEF := *apiProvFuncAEF.ApiProvFuncId
235                 assert.Equal(t, apiProvFuncIdAEF, funcIdAEF)
236
237                 assert.Empty(t, resultProvider.FailReason)
238                 assert.Equal(t, "http://example.com/api-provider-management/v1/registrations/"+*resultProvider.ApiProvDomId, result.Recorder.Header().Get(echo.HeaderLocation))
239
240                 // Register same provider again should result in Forbidden
241                 result = testutil.NewRequest().Post("/api-provider-management/v1/registrations").WithJsonBody(newProvider).Go(t, eServiceManager)
242
243                 assert.Equal(t, http.StatusForbidden, result.Code())
244
245                 var errorObj common29122.ProblemDetails
246                 err = result.UnmarshalBodyToObject(&errorObj)
247                 assert.NoError(t, err, "error unmarshaling response")
248                 assert.Equal(t, http.StatusForbidden, *errorObj.Status)
249                 assert.Contains(t, *errorObj.Cause, "already registered")
250         }
251 }
252
253 func TestUpdateValidProviderWithNewFunction(t *testing.T) {
254         // Modify the provider
255         updatedProvider := getProvider()
256         updatedProvider.ApiProvDomId = &domainID
257
258         newDomainInfo := "New domain info"
259         updatedProvider.ApiProvDomInfo = &newDomainInfo
260         newFunctionInfo := "New function info"
261         (*updatedProvider.ApiProvFuncs)[0].ApiProvFuncInfo = &newFunctionInfo
262         newFuncInfoAEF := "new func as AEF"
263
264         testFuncs := append(*updatedProvider.ApiProvFuncs, provapi.APIProviderFunctionDetails{
265                 ApiProvFuncInfo: &newFuncInfoAEF,
266                 ApiProvFuncRole: provapi.ApiProviderFuncRoleAEF,
267                 RegInfo: provapi.RegistrationInformation{
268                         ApiProvPubKey: "key",
269                 },
270         })
271         updatedProvider.ApiProvFuncs = &testFuncs
272
273         result := testutil.NewRequest().Put("/api-provider-management/v1/registrations/"+domainID).WithJsonBody(updatedProvider).Go(t, eServiceManager)
274
275         var resultProvider provapi.APIProviderEnrolmentDetails
276         assert.Equal(t, http.StatusOK, result.Code())
277
278         err := result.UnmarshalBodyToObject(&resultProvider)
279         assert.NoError(t, err, "error unmarshaling response")
280
281         assert.Equal(t, newDomainInfo, *resultProvider.ApiProvDomInfo)
282         assert.Equal(t, newFunctionInfo, *(*resultProvider.ApiProvFuncs)[0].ApiProvFuncInfo)
283         assert.Equal(t, *(*resultProvider.ApiProvFuncs)[2].ApiProvFuncId, "AEF_id_new_func_as_AEF")
284         assert.Empty(t, resultProvider.FailReason)
285 }
286
287 func TestDeleteProvider(t *testing.T) {
288         provider := getProvider()
289         provider.ApiProvDomId = &domainID
290         (*provider.ApiProvFuncs)[0].ApiProvFuncId = &funcIdAPF
291         result := testutil.NewRequest().Delete("/api-provider-management/v1/registrations/"+domainID).Go(t, eServiceManager)
292         assert.Equal(t, http.StatusNoContent, result.Code())
293         capifCleanUp()
294 }
295
296 func getProvider() provapi.APIProviderEnrolmentDetails {
297         testFuncs := []provapi.APIProviderFunctionDetails{
298                 {
299                         ApiProvFuncInfo: &funcInfoAPF,
300                         ApiProvFuncRole: provapi.ApiProviderFuncRoleAPF,
301                         RegInfo: provapi.RegistrationInformation{
302                                 ApiProvPubKey: "APF-PublicKey",
303                         },
304                 },
305                 {
306                         ApiProvFuncInfo: &funcInfoAEF,
307                         ApiProvFuncRole: provapi.ApiProviderFuncRoleAEF,
308                         RegInfo: provapi.RegistrationInformation{
309                                 ApiProvPubKey: "AEF-PublicKey",
310                         },
311                 },
312         }
313         return provapi.APIProviderEnrolmentDetails{
314                 RegSec:         "sec",
315                 ApiProvDomInfo: &domainInfo,
316                 ApiProvFuncs:   &testFuncs,
317         }
318 }
319
320 func registerHandlers(e *echo.Echo, myEnv map[string]string, myPorts map[string]int) (err error) {
321         capifProtocol := myEnv["CAPIF_PROTOCOL"]
322         capifIPv4 := common29122.Ipv4Addr(myEnv["CAPIF_IPV4"])
323         capifPort := common29122.Port(myPorts["CAPIF_PORT"])
324
325         // Register ProviderManagement
326         providerManagerSwagger, err := provapi.GetSwagger()
327         if err != nil {
328                 log.Fatalf("Error loading ProviderManagement swagger spec\n: %s", err)
329                 return err
330         }
331         providerManagerSwagger.Servers = nil
332         providerManager := NewProviderManager(capifProtocol, capifIPv4, capifPort)
333
334         group := e.Group("/api-provider-management/v1")
335         group.Use(echomiddleware.Logger())
336         group.Use(middleware.OapiRequestValidator(providerManagerSwagger))
337         provapi.RegisterHandlersWithBaseURL(e, providerManager, "/api-provider-management/v1")
338
339         return err
340 }