elinuxhenrik | 3d37436 | 2022-10-18 16:51:52 +0200 | [diff] [blame^] | 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 | package invokermanagement |
| 21 | |
| 22 | import ( |
| 23 | "fmt" |
| 24 | "net/http" |
| 25 | "os" |
| 26 | "testing" |
| 27 | |
| 28 | "oransc.org/nonrtric/sme/internal/invokermanagementapi" |
| 29 | |
| 30 | "github.com/labstack/echo/v4" |
| 31 | |
| 32 | "oransc.org/nonrtric/sme/internal/common29122" |
| 33 | "oransc.org/nonrtric/sme/internal/publishserviceapi" |
| 34 | |
| 35 | "oransc.org/nonrtric/sme/internal/publishservice" |
| 36 | publishmocks "oransc.org/nonrtric/sme/internal/publishservice/mocks" |
| 37 | |
| 38 | "github.com/deepmap/oapi-codegen/pkg/middleware" |
| 39 | "github.com/deepmap/oapi-codegen/pkg/testutil" |
| 40 | echomiddleware "github.com/labstack/echo/v4/middleware" |
| 41 | "github.com/stretchr/testify/assert" |
| 42 | "github.com/stretchr/testify/mock" |
| 43 | ) |
| 44 | |
| 45 | func TestOnboardInvoker(t *testing.T) { |
| 46 | var err error |
| 47 | apiId := "apiId" |
| 48 | aefId := "aefId" |
| 49 | apiRegisterMock := publishmocks.APIRegister{} |
| 50 | apiRegisterMock.On("AreAPIsRegistered", mock.Anything).Return(true) |
| 51 | invokerUnderTest, requestHandler := getEcho(&apiRegisterMock) |
| 52 | |
| 53 | description := "description" |
| 54 | domainName := "domain" |
| 55 | var protocol publishserviceapi.Protocol = "HTTP_1_1" |
| 56 | var apiList invokermanagementapi.APIList = []publishserviceapi.ServiceAPIDescription{ |
| 57 | { |
| 58 | ApiId: &apiId, |
| 59 | ApiName: "api", |
| 60 | Description: &description, |
| 61 | AefProfiles: &[]publishserviceapi.AefProfile{ |
| 62 | { |
| 63 | AefId: aefId, |
| 64 | DomainName: &domainName, |
| 65 | Protocol: &protocol, |
| 66 | Versions: []publishserviceapi.Version{ |
| 67 | { |
| 68 | ApiVersion: "v1", |
| 69 | Resources: &[]publishserviceapi.Resource{ |
| 70 | { |
| 71 | ResourceName: "app", |
| 72 | CommType: "REQUEST_RESPONSE", |
| 73 | Uri: "uri", |
| 74 | Operations: &[]publishserviceapi.Operation{ |
| 75 | "POST", |
| 76 | }, |
| 77 | }, |
| 78 | }, |
| 79 | }, |
| 80 | }, |
| 81 | }, |
| 82 | }, |
| 83 | }, |
| 84 | } |
| 85 | invokerInfo := "invoker a" |
| 86 | newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{ |
| 87 | ApiInvokerInformation: &invokerInfo, |
| 88 | NotificationDestination: "url", |
| 89 | OnboardingInformation: invokermanagementapi.OnboardingInformation{ |
| 90 | ApiInvokerPublicKey: "key", |
| 91 | }, |
| 92 | ApiList: &apiList, |
| 93 | } |
| 94 | |
| 95 | // Onboard a valid invoker |
| 96 | result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler) |
| 97 | |
| 98 | assert.Equal(t, http.StatusCreated, result.Code()) |
| 99 | var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails |
| 100 | err = result.UnmarshalBodyToObject(&resultInvoker) |
| 101 | assert.NoError(t, err, "error unmarshaling response") |
| 102 | assert.Equal(t, "api_invoker_id_invoker_a", *resultInvoker.ApiInvokerId) |
| 103 | assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination) |
| 104 | assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey) |
| 105 | assert.Equal(t, "onboarding_secret_invoker_a", *resultInvoker.OnboardingInformation.OnboardingSecret) |
| 106 | assert.Equal(t, "http://example.com/onboardedInvokers/"+*resultInvoker.ApiInvokerId, result.Recorder.Header().Get(echo.HeaderLocation)) |
| 107 | assert.True(t, invokerUnderTest.IsInvokerRegistered("api_invoker_id_invoker_a")) |
| 108 | assert.True(t, invokerUnderTest.VerifyInvokerSecret("api_invoker_id_invoker_a", "onboarding_secret_invoker_a")) |
| 109 | apiRegisterMock.AssertCalled(t, "AreAPIsRegistered", mock.Anything) |
| 110 | |
| 111 | // Onboard an invoker missing required NotificationDestination, should get 400 with problem details |
| 112 | invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{ |
| 113 | OnboardingInformation: invokermanagementapi.OnboardingInformation{ |
| 114 | ApiInvokerPublicKey: "key", |
| 115 | }, |
| 116 | } |
| 117 | result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler) |
| 118 | |
| 119 | assert.Equal(t, http.StatusBadRequest, result.Code()) |
| 120 | var problemDetails common29122.ProblemDetails |
| 121 | err = result.UnmarshalBodyToObject(&problemDetails) |
| 122 | assert.NoError(t, err, "error unmarshaling response") |
| 123 | badRequest := 400 |
| 124 | assert.Equal(t, &badRequest, problemDetails.Status) |
| 125 | errMsg := "Invoker missing required NotificationDestination" |
| 126 | assert.Equal(t, &errMsg, problemDetails.Cause) |
| 127 | |
| 128 | // Onboard an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details |
| 129 | invalidInvoker = invokermanagementapi.APIInvokerEnrolmentDetails{ |
| 130 | NotificationDestination: "url", |
| 131 | } |
| 132 | |
| 133 | result = testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(invalidInvoker).Go(t, requestHandler) |
| 134 | |
| 135 | assert.Equal(t, http.StatusBadRequest, result.Code()) |
| 136 | err = result.UnmarshalBodyToObject(&problemDetails) |
| 137 | assert.NoError(t, err, "error unmarshaling response") |
| 138 | assert.Equal(t, &badRequest, problemDetails.Status) |
| 139 | errMsg = "Invoker missing required OnboardingInformation.ApiInvokerPublicKey" |
| 140 | assert.Equal(t, &errMsg, problemDetails.Cause) |
| 141 | } |
| 142 | |
| 143 | func TestDeleteInvoker(t *testing.T) { |
| 144 | _, requestHandler := getEcho(nil) |
| 145 | |
| 146 | newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{ |
| 147 | NotificationDestination: "url", |
| 148 | OnboardingInformation: invokermanagementapi.OnboardingInformation{ |
| 149 | ApiInvokerPublicKey: "key", |
| 150 | }, |
| 151 | } |
| 152 | |
| 153 | // Onboard an invoker |
| 154 | result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler) |
| 155 | var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails |
| 156 | result.UnmarshalBodyToObject(&resultInvoker) |
| 157 | |
| 158 | invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation) |
| 159 | |
| 160 | // Delete the invoker |
| 161 | result = testutil.NewRequest().Delete(invokerUrl).Go(t, requestHandler) |
| 162 | |
| 163 | assert.Equal(t, http.StatusNoContent, result.Code()) |
| 164 | } |
| 165 | |
| 166 | func TestUpdateInvoker(t *testing.T) { |
| 167 | _, requestHandler := getEcho(nil) |
| 168 | |
| 169 | newInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{ |
| 170 | NotificationDestination: "url", |
| 171 | OnboardingInformation: invokermanagementapi.OnboardingInformation{ |
| 172 | ApiInvokerPublicKey: "key", |
| 173 | }, |
| 174 | } |
| 175 | |
| 176 | // Onboard an invoker |
| 177 | result := testutil.NewRequest().Post("/onboardedInvokers").WithJsonBody(newInvoker).Go(t, requestHandler) |
| 178 | var resultInvoker invokermanagementapi.APIInvokerEnrolmentDetails |
| 179 | result.UnmarshalBodyToObject(&resultInvoker) |
| 180 | |
| 181 | invokerId := resultInvoker.ApiInvokerId |
| 182 | invokerUrl := result.Recorder.Header().Get(echo.HeaderLocation) |
| 183 | |
| 184 | // Update the invoker with valid invoker, should return 200 with invoker details |
| 185 | result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(resultInvoker).Go(t, requestHandler) |
| 186 | |
| 187 | assert.Equal(t, http.StatusOK, result.Code()) |
| 188 | err := result.UnmarshalBodyToObject(&resultInvoker) |
| 189 | assert.NoError(t, err, "error unmarshaling response") |
| 190 | assert.Equal(t, invokerId, resultInvoker.ApiInvokerId) |
| 191 | assert.Equal(t, newInvoker.NotificationDestination, resultInvoker.NotificationDestination) |
| 192 | assert.Equal(t, newInvoker.OnboardingInformation.ApiInvokerPublicKey, resultInvoker.OnboardingInformation.ApiInvokerPublicKey) |
| 193 | |
| 194 | // Update with an invoker missing required NotificationDestination, should get 400 with problem details |
| 195 | validOnboardingInfo := invokermanagementapi.OnboardingInformation{ |
| 196 | ApiInvokerPublicKey: "key", |
| 197 | } |
| 198 | invalidInvoker := invokermanagementapi.APIInvokerEnrolmentDetails{ |
| 199 | ApiInvokerId: invokerId, |
| 200 | OnboardingInformation: validOnboardingInfo, |
| 201 | } |
| 202 | result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler) |
| 203 | |
| 204 | assert.Equal(t, http.StatusBadRequest, result.Code()) |
| 205 | var problemDetails common29122.ProblemDetails |
| 206 | err = result.UnmarshalBodyToObject(&problemDetails) |
| 207 | assert.NoError(t, err, "error unmarshaling response") |
| 208 | badRequest := 400 |
| 209 | assert.Equal(t, &badRequest, problemDetails.Status) |
| 210 | errMsg := "Invoker missing required NotificationDestination" |
| 211 | assert.Equal(t, &errMsg, problemDetails.Cause) |
| 212 | |
| 213 | // Update with an invoker missing required OnboardingInformation.ApiInvokerPublicKey, should get 400 with problem details |
| 214 | invalidInvoker.NotificationDestination = "url" |
| 215 | invalidInvoker.OnboardingInformation = invokermanagementapi.OnboardingInformation{} |
| 216 | result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler) |
| 217 | |
| 218 | assert.Equal(t, http.StatusBadRequest, result.Code()) |
| 219 | err = result.UnmarshalBodyToObject(&problemDetails) |
| 220 | assert.NoError(t, err, "error unmarshaling response") |
| 221 | assert.Equal(t, &badRequest, problemDetails.Status) |
| 222 | errMsg = "Invoker missing required OnboardingInformation.ApiInvokerPublicKey" |
| 223 | assert.Equal(t, &errMsg, problemDetails.Cause) |
| 224 | |
| 225 | // Update with an invoker with other ApiInvokerId than the one provided in the URL, should get 400 with problem details |
| 226 | invalidId := "1" |
| 227 | invalidInvoker.ApiInvokerId = &invalidId |
| 228 | invalidInvoker.OnboardingInformation = validOnboardingInfo |
| 229 | result = testutil.NewRequest().Put(invokerUrl).WithJsonBody(invalidInvoker).Go(t, requestHandler) |
| 230 | |
| 231 | assert.Equal(t, http.StatusBadRequest, result.Code()) |
| 232 | err = result.UnmarshalBodyToObject(&problemDetails) |
| 233 | assert.NoError(t, err, "error unmarshaling response") |
| 234 | assert.Equal(t, &badRequest, problemDetails.Status) |
| 235 | errMsg = "Invoker ApiInvokerId not matching" |
| 236 | assert.Equal(t, &errMsg, problemDetails.Cause) |
| 237 | |
| 238 | // Update an invoker that has not been onboarded, shold get 404 with problem details |
| 239 | missingId := "1" |
| 240 | newInvoker.ApiInvokerId = &missingId |
| 241 | result = testutil.NewRequest().Put("/onboardedInvokers/"+missingId).WithJsonBody(newInvoker).Go(t, requestHandler) |
| 242 | |
| 243 | assert.Equal(t, http.StatusNotFound, result.Code()) |
| 244 | err = result.UnmarshalBodyToObject(&problemDetails) |
| 245 | assert.NoError(t, err, "error unmarshaling response") |
| 246 | notFound := 404 |
| 247 | assert.Equal(t, ¬Found, problemDetails.Status) |
| 248 | errMsg = "The invoker to update has not been onboarded" |
| 249 | assert.Equal(t, &errMsg, problemDetails.Cause) |
| 250 | |
| 251 | } |
| 252 | |
| 253 | func getEcho(apiRegister publishservice.APIRegister) (*InvokerManager, *echo.Echo) { |
| 254 | swagger, err := invokermanagementapi.GetSwagger() |
| 255 | if err != nil { |
| 256 | fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err) |
| 257 | os.Exit(1) |
| 258 | } |
| 259 | |
| 260 | swagger.Servers = nil |
| 261 | |
| 262 | im := NewInvokerManager(apiRegister) |
| 263 | |
| 264 | e := echo.New() |
| 265 | e.Use(echomiddleware.Logger()) |
| 266 | e.Use(middleware.OapiRequestValidator(swagger)) |
| 267 | |
| 268 | invokermanagementapi.RegisterHandlers(e, im) |
| 269 | return im, e |
| 270 | } |