2 // ========================LICENSE_START=================================
5 // Copyright (C) 2022: Nordix Foundation
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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===================================
21 package publishservice
30 "oransc.org/nonrtric/capifcore/internal/common29122"
31 "oransc.org/nonrtric/capifcore/internal/eventsapi"
32 "oransc.org/nonrtric/capifcore/internal/providermanagement"
34 "github.com/labstack/echo/v4"
36 publishapi "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
38 "oransc.org/nonrtric/capifcore/internal/helmmanagement"
39 helmMocks "oransc.org/nonrtric/capifcore/internal/helmmanagement/mocks"
40 serviceMocks "oransc.org/nonrtric/capifcore/internal/providermanagement/mocks"
42 "github.com/deepmap/oapi-codegen/pkg/middleware"
43 "github.com/deepmap/oapi-codegen/pkg/testutil"
44 echomiddleware "github.com/labstack/echo/v4/middleware"
45 "github.com/stretchr/testify/assert"
46 "github.com/stretchr/testify/mock"
49 func TestPublishUnpublishService(t *testing.T) {
52 serviceRegisterMock := serviceMocks.ServiceRegister{}
53 serviceRegisterMock.On("GetAefsForPublisher", apfId).Return([]string{aefId, "otherAefId"})
54 helmManagerMock := helmMocks.HelmManager{}
55 helmManagerMock.On("InstallHelmChart", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
56 serviceUnderTest, eventChannel, requestHandler := getEcho(&serviceRegisterMock, &helmManagerMock)
58 // Check no services published for provider
59 result := testutil.NewRequest().Get("/"+apfId+"/service-apis").Go(t, requestHandler)
61 assert.Equal(t, http.StatusNotFound, result.Code())
63 apiName := "app-management"
64 namespace := "namespace"
65 repoName := "repoName"
66 chartName := "chartName"
67 releaseName := "releaseName"
68 description := fmt.Sprintf("Description,%s,%s,%s,%s", namespace, repoName, chartName, releaseName)
69 newServiceDescription := getServiceAPIDescription(aefId, apiName, description)
71 // Publish a service for provider
72 result = testutil.NewRequest().Post("/"+apfId+"/service-apis").WithJsonBody(newServiceDescription).Go(t, requestHandler)
74 assert.Equal(t, http.StatusCreated, result.Code())
75 var resultService publishapi.ServiceAPIDescription
76 err := result.UnmarshalBodyToObject(&resultService)
77 assert.NoError(t, err, "error unmarshaling response")
78 newApiId := "api_id_" + apiName
79 assert.Equal(t, *resultService.ApiId, newApiId)
80 assert.Equal(t, "http://example.com/"+apfId+"/service-apis/"+*resultService.ApiId, result.Recorder.Header().Get(echo.HeaderLocation))
81 newServiceDescription.ApiId = &newApiId
82 wantedAPILIst := []publishapi.ServiceAPIDescription{newServiceDescription}
83 assert.True(t, serviceUnderTest.AreAPIsPublished(&wantedAPILIst))
84 assert.True(t, serviceUnderTest.IsAPIPublished(aefId, apiName))
85 serviceRegisterMock.AssertCalled(t, "GetAefsForPublisher", apfId)
86 helmManagerMock.AssertCalled(t, "InstallHelmChart", namespace, repoName, chartName, releaseName)
87 assert.ElementsMatch(t, []string{aefId}, serviceUnderTest.getAllAefIds())
88 if publishEvent, ok := waitForEvent(eventChannel, 1*time.Second); ok {
89 assert.Fail(t, "No event sent")
91 assert.Equal(t, *resultService.ApiId, (*publishEvent.EventDetail.ApiIds)[0])
92 assert.Equal(t, eventsapi.CAPIFEventSERVICEAPIAVAILABLE, publishEvent.Events)
95 // Check that the service is published for the provider
96 result = testutil.NewRequest().Get("/"+apfId+"/service-apis/"+newApiId).Go(t, requestHandler)
98 assert.Equal(t, http.StatusOK, result.Code())
99 err = result.UnmarshalBodyToObject(&resultService)
100 assert.NoError(t, err, "error unmarshaling response")
101 assert.Equal(t, *resultService.ApiId, newApiId)
103 // Delete the service
104 helmManagerMock.On("UninstallHelmChart", mock.Anything, mock.Anything).Return(nil)
105 result = testutil.NewRequest().Delete("/"+apfId+"/service-apis/"+newApiId).Go(t, requestHandler)
107 assert.Equal(t, http.StatusNoContent, result.Code())
108 helmManagerMock.AssertCalled(t, "UninstallHelmChart", namespace, chartName)
109 assert.Empty(t, serviceUnderTest.getAllAefIds())
111 // Check no services published
112 result = testutil.NewRequest().Get("/"+apfId+"/service-apis/"+newApiId).Go(t, requestHandler)
114 if publishEvent, ok := waitForEvent(eventChannel, 1*time.Second); ok {
115 assert.Fail(t, "No event sent")
117 assert.Equal(t, *resultService.ApiId, (*publishEvent.EventDetail.ApiIds)[0])
118 assert.Equal(t, eventsapi.CAPIFEventSERVICEAPIUNAVAILABLE, publishEvent.Events)
121 assert.Equal(t, http.StatusNotFound, result.Code())
124 func TestPostUnpublishedServiceWithUnregisteredFunction(t *testing.T) {
127 serviceRegisterMock := serviceMocks.ServiceRegister{}
128 serviceRegisterMock.On("GetAefsForPublisher", apfId).Return([]string{"otherAefId"})
129 _, _, requestHandler := getEcho(&serviceRegisterMock, nil)
131 newServiceDescription := getServiceAPIDescription(aefId, "apiName", "description")
134 result := testutil.NewRequest().Post("/"+apfId+"/service-apis").WithJsonBody(newServiceDescription).Go(t, requestHandler)
136 assert.Equal(t, http.StatusNotFound, result.Code())
137 var resultError common29122.ProblemDetails
138 err := result.UnmarshalBodyToObject(&resultError)
139 assert.NoError(t, err, "error unmarshaling response")
140 assert.Contains(t, *resultError.Cause, aefId)
141 assert.Contains(t, *resultError.Cause, "not registered")
142 notFound := http.StatusNotFound
143 assert.Equal(t, ¬Found, resultError.Status)
146 func TestGetServices(t *testing.T) {
149 serviceRegisterMock := serviceMocks.ServiceRegister{}
150 serviceRegisterMock.On("GetAefsForPublisher", apfId).Return([]string{aefId})
151 _, _, requestHandler := getEcho(&serviceRegisterMock, nil)
153 // Check no services published for provider
154 result := testutil.NewRequest().Get("/"+apfId+"/service-apis").Go(t, requestHandler)
156 assert.Equal(t, http.StatusNotFound, result.Code())
158 serviceDescription1 := getServiceAPIDescription(aefId, "api1", "Description")
159 serviceDescription2 := getServiceAPIDescription(aefId, "api2", "Description")
161 // Publish a service for provider
162 testutil.NewRequest().Post("/"+apfId+"/service-apis").WithJsonBody(serviceDescription1).Go(t, requestHandler)
163 testutil.NewRequest().Post("/"+apfId+"/service-apis").WithJsonBody(serviceDescription2).Go(t, requestHandler)
165 // Get all services for provider
166 result = testutil.NewRequest().Get("/"+apfId+"/service-apis").Go(t, requestHandler)
167 assert.Equal(t, http.StatusOK, result.Code())
168 var resultServices []publishapi.ServiceAPIDescription
169 err := result.UnmarshalBodyToObject(&resultServices)
170 assert.NoError(t, err, "error unmarshaling response")
171 assert.Len(t, resultServices, 2)
172 apiId1 := "api_id_api1"
173 serviceDescription1.ApiId = &apiId1
174 apiId2 := "api_id_api2"
175 serviceDescription2.ApiId = &apiId2
176 assert.Contains(t, resultServices, serviceDescription1)
177 assert.Contains(t, resultServices, serviceDescription2)
180 func TestGetPublishedServices(t *testing.T) {
181 serviceUnderTest := NewPublishService(nil, nil, nil)
183 profiles := make([]publishapi.AefProfile, 1)
184 serviceDescription := publishapi.ServiceAPIDescription{
185 AefProfiles: &profiles,
187 serviceUnderTest.publishedServices["publisher1"] = []publishapi.ServiceAPIDescription{
190 serviceUnderTest.publishedServices["publisher2"] = []publishapi.ServiceAPIDescription{
193 result := serviceUnderTest.GetAllPublishedServices()
194 assert.Len(t, result, 2)
197 func TestUpdateDescription(t *testing.T) {
199 serviceApiId := "serviceApiId"
202 description := "description"
203 serviceRegisterMock := serviceMocks.ServiceRegister{}
204 serviceRegisterMock.On("GetAefsForPublisher", apfId).Return([]string{aefId, "otherAefId"})
205 helmManagerMock := helmMocks.HelmManager{}
206 helmManagerMock.On("InstallHelmChart", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil)
207 serviceUnderTest, eventChannel, requestHandler := getEcho(&serviceRegisterMock, &helmManagerMock)
209 serviceDescription := getServiceAPIDescription(aefId, apiName, description)
210 serviceDescription.ApiId = &serviceApiId
211 serviceUnderTest.publishedServices[apfId] = []publishapi.ServiceAPIDescription{serviceDescription}
214 updatedServiceDescription := getServiceAPIDescription(aefId, apiName, description)
215 updatedServiceDescription.ApiId = &description
216 newDescription := "new description"
217 updatedServiceDescription.Description = &newDescription
218 result := testutil.NewRequest().Put("/"+apfId+"/service-apis/"+serviceApiId).WithJsonBody(updatedServiceDescription).Go(t, requestHandler)
220 var resultService publishapi.ServiceAPIDescription
221 assert.Equal(t, http.StatusOK, result.Code())
222 err := result.UnmarshalBodyToObject(&resultService)
223 assert.NoError(t, err, "error unmarshaling response")
224 assert.Equal(t, resultService.Description, &newDescription)
226 if publishEvent, ok := waitForEvent(eventChannel, 1*time.Second); ok {
227 assert.Fail(t, "No event sent")
229 assert.Equal(t, *resultService.ApiId, (*publishEvent.EventDetail.ApiIds)[0])
230 assert.Equal(t, eventsapi.CAPIFEventSERVICEAPIUPDATE, publishEvent.Events)
234 func getEcho(serviceRegister providermanagement.ServiceRegister, helmManager helmmanagement.HelmManager) (*PublishService, chan eventsapi.EventNotification, *echo.Echo) {
235 swagger, err := publishapi.GetSwagger()
237 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
241 swagger.Servers = nil
243 eventChannel := make(chan eventsapi.EventNotification)
244 ps := NewPublishService(serviceRegister, helmManager, eventChannel)
247 e.Use(echomiddleware.Logger())
248 e.Use(middleware.OapiRequestValidator(swagger))
250 publishapi.RegisterHandlers(e, ps)
251 return ps, eventChannel, e
254 func getServiceAPIDescription(aefId, apiName, description string) publishapi.ServiceAPIDescription {
255 domainName := "domainName"
256 var protocol publishapi.Protocol = "HTTP_1_1"
257 return publishapi.ServiceAPIDescription{
258 AefProfiles: &[]publishapi.AefProfile{
261 DomainName: &domainName,
263 Versions: []publishapi.Version{
266 Resources: &[]publishapi.Resource{
268 CommType: "REQUEST_RESPONSE",
269 Operations: &[]publishapi.Operation{
281 Description: &description,
285 // waitForEvent waits for the channel to receive an event for the specified max timeout.
286 // Returns true if waiting timed out.
287 func waitForEvent(ch chan eventsapi.EventNotification, timeout time.Duration) (*eventsapi.EventNotification, bool) {
290 return &event, false // completed normally
291 case <-time.After(timeout):
292 return nil, true // timed out