2 Copyright 2018 Intel Corporation.
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 http://www.apache.org/licenses/LICENSE-2.0
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License.
27 "github.com/onap/multicloud-k8s/src/k8splugin/internal/app"
28 "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm"
30 pkgerrors "github.com/pkg/errors"
31 "k8s.io/apimachinery/pkg/runtime/schema"
34 func TestConvertDirectives(t *testing.T) {
35 testCases := []struct {
38 expected map[string]string
41 label: "Single variable",
42 expected: map[string]string{"test": "true"},
43 input: brokerRequest{SDNCDirectives: directive{[]attribute{{
49 label: "Empty parameter",
50 expected: map[string]string{"test": ""},
51 input: brokerRequest{OOFDirectives: directive{[]attribute{{
58 input: brokerRequest{},
59 expected: make(map[string]string),
62 label: "Complex helm overrides",
64 String with int will be later treated as int in helm.TemplateClient
65 (see helm/pkg/strvals/parser.go)
66 If unsure, convert type in helm chart like `{{ toString $value }}` or `{{ int $value }}`
67 (see http://masterminds.github.io/sprig/conversion.html)
69 expected: map[string]string{"name": "{a, b, c}", "servers[0].port": "80"},
70 input: brokerRequest{UserDirectives: directive{[]attribute{
76 Key: "servers[0].port",
82 label: "Override variables",
83 expected: map[string]string{"empty": "", "sdnc": "sdnc", "user": "user", "oof": "oof"},
85 SDNCDirectives: directive{[]attribute{
99 OOFDirectives: directive{[]attribute{
109 UserDirectives: directive{[]attribute{
123 for _, testCase := range testCases {
124 t.Run(testCase.label, func(t *testing.T) {
125 result := testCase.input.convertDirectives()
126 if !reflect.DeepEqual(result, testCase.expected) {
127 t.Fatalf("Unexpected result. Wanted '%v', retrieved '%v'",
128 testCase.expected, result)
134 func TestBrokerCreateHandler(t *testing.T) {
135 testCases := []struct {
138 expected brokerPOSTResponse
141 instClient *mockInstanceClient
144 label: "Missing body failure",
145 expectedCode: http.StatusBadRequest,
148 label: "Invalid JSON request format",
149 input: bytes.NewBuffer([]byte("invalid")),
150 expectedCode: http.StatusUnprocessableEntity,
153 label: "Missing vf-module-*-id parameter",
154 expectedError: "vf-module-model-customization-id is empty",
155 expectedCode: http.StatusBadRequest,
156 input: bytes.NewBuffer([]byte(`{
157 "vf-module-model-invariant-id": "123456qwerty",
158 "vf-module-model-version-id": "123qweasdzxc",
159 "generic-vnf-id": "dummy-vnf-id",
160 "vf-module-id": "dummy-vfm-id",
162 "stack_name": "dummy-stack-name"
167 "attribute_name": "k8s-rb-profile-name",
168 "attribute_value": "dummy-profile"
175 label: "Missing stack name parameter",
176 expectedError: "stack_name is missing from template_data",
177 expectedCode: http.StatusBadRequest,
178 input: bytes.NewBuffer([]byte(`{
179 "vf-module-model-customization-id": "84sdfkio938",
180 "vf-module-model-invariant-id": "123456qwerty",
181 "vf-module-model-version-id": "123qweasdzxc",
182 "generic-vnf-id": "dummy-vnf-id",
183 "vf-module-id": "dummy-vfm-id",
189 "attribute_name": "k8s-rb-profile-name",
190 "attribute_value": "dummy-profile"
197 label: "Missing profile name directive",
198 expectedError: "k8s-rb-profile-name is missing from directives",
199 expectedCode: http.StatusBadRequest,
200 input: bytes.NewBuffer([]byte(`{
201 "vf-module-model-customization-id": "84sdfkio938",
202 "vf-module-model-invariant-id": "123456qwerty",
203 "vf-module-model-version-id": "123qweasdzxc",
204 "generic-vnf-id": "dummy-vnf-id",
205 "vf-module-id": "dummy-vfm-id",
207 "stack_name": "dummy-stack-name"
216 label: "Missing vf-module-id parameter",
217 expectedError: "vf-module-id is empty",
218 expectedCode: http.StatusBadRequest,
219 input: bytes.NewBuffer([]byte(`{
220 "vf-module-model-customization-id": "84sdfkio938",
221 "vf-module-model-invariant-id": "123456qwerty",
222 "vf-module-model-version-id": "123qweasdzxc",
223 "generic-vnf-id": "dummy-vnf-id",
225 "stack_name": "dummy-stack-name"
230 "attribute_name": "k8s-rb-profile-name",
231 "attribute_value": "dummy-profile"
238 label: "Succesfully create an Instance",
239 input: bytes.NewBuffer([]byte(`{
240 "vf-module-model-customization-id": "84sdfkio938",
241 "vf-module-model-invariant-id": "123456qwerty",
242 "vf-module-model-version-id": "123qweasdzxc",
243 "generic-vnf-id": "dummy-vnf-id",
244 "vf-module-id": "dummy-vfm-id",
246 "stack_name": "dummy-stack-name"
251 "attribute_name": "k8s-rb-profile-name",
252 "attribute_value": "dummy-profile"
257 expected: brokerPOSTResponse{
258 WorkloadID: "HaKpys8e",
259 TemplateType: "heat",
260 WorkloadStatus: "CREATE_COMPLETE",
261 TemplateResponse: []helm.KubernetesResource{
263 GVK: schema.GroupVersionKind{
267 Name: "test-deployment",
270 GVK: schema.GroupVersionKind{
274 Name: "test-service",
278 expectedCode: http.StatusCreated,
279 instClient: &mockInstanceClient{
280 items: []app.InstanceResponse{
283 Request: app.InstanceRequest{
284 RBName: "123456qwerty",
285 RBVersion: "123qweasdzxc",
286 ProfileName: "profile1",
287 CloudRegion: "region1",
289 Namespace: "testnamespace",
290 Resources: []helm.KubernetesResource{
292 GVK: schema.GroupVersionKind{
296 Name: "test-deployment",
299 GVK: schema.GroupVersionKind{
303 Name: "test-service",
312 for _, testCase := range testCases {
313 t.Run(testCase.label, func(t *testing.T) {
315 request := httptest.NewRequest("POST", "/cloudowner/cloudregion/infra_workload", testCase.input)
316 resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil, nil, nil))
317 defer resp.Body.Close()
319 if testCase.expectedCode != resp.StatusCode {
320 body, _ := ioutil.ReadAll(resp.Body)
322 t.Fatalf("Request method returned code '%v', but '%v' was expected",
323 resp.StatusCode, testCase.expectedCode)
326 if resp.StatusCode == http.StatusCreated {
327 var response brokerPOSTResponse
328 err := json.NewDecoder(resp.Body).Decode(&response)
330 t.Fatalf("Parsing the returned response got an error (%s)", err)
332 if !reflect.DeepEqual(testCase.expected, response) {
333 t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
334 response, testCase.expected)
336 } else if testCase.expectedError != "" {
337 body, err := ioutil.ReadAll(resp.Body)
339 if !strings.Contains(string(body), testCase.expectedError) {
340 t.Fatalf("Request method returned body '%s', but '%s' wasn't found",
341 body, testCase.expectedError)
344 t.Fatalf("Request method returned malformed body")
351 func TestBrokerGetHandler(t *testing.T) {
352 testCases := []struct {
356 expectedResponse brokerGETResponse
357 instClient *mockInstanceClient
360 label: "Fail to retrieve Instance",
362 expectedCode: http.StatusInternalServerError,
363 instClient: &mockInstanceClient{
364 err: pkgerrors.New("Internal error"),
368 label: "Succesful get an Instance",
370 expectedCode: http.StatusOK,
371 expectedResponse: brokerGETResponse{
372 TemplateType: "heat",
373 WorkloadID: "HaKpys8e",
374 WorkloadStatus: "CREATE_COMPLETE",
376 instClient: &mockInstanceClient{
377 items: []app.InstanceResponse{
380 Request: app.InstanceRequest{
381 RBName: "test-rbdef",
383 ProfileName: "profile1",
384 CloudRegion: "region1",
386 Namespace: "testnamespace",
387 Resources: []helm.KubernetesResource{
389 GVK: schema.GroupVersionKind{
393 Name: "test-deployment",
396 GVK: schema.GroupVersionKind{
400 Name: "test-service",
409 for _, testCase := range testCases {
410 t.Run(testCase.label, func(t *testing.T) {
411 request := httptest.NewRequest("GET", "/cloudowner/cloudregion/infra_workload/"+testCase.input, nil)
412 resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil, nil, nil))
414 if testCase.expectedCode != resp.StatusCode {
415 t.Fatalf("Request method returned: %v and it was expected: %v",
416 resp.StatusCode, testCase.expectedCode)
418 if resp.StatusCode == http.StatusOK {
419 var response brokerGETResponse
420 err := json.NewDecoder(resp.Body).Decode(&response)
422 t.Fatalf("Parsing the returned response got an error (%s)", err)
424 if !reflect.DeepEqual(testCase.expectedResponse, response) {
425 t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
426 response, testCase.expectedResponse)
433 func TestBrokerFindHandler(t *testing.T) {
434 testCases := []struct {
438 expectedResponse brokerGETResponse
439 instClient *mockInstanceClient
442 label: "Successful find an Instance",
443 input: "test-vf-module-name",
444 expectedCode: http.StatusOK,
445 expectedResponse: brokerGETResponse{
446 TemplateType: "heat",
447 WorkloadID: "HaKpys8e",
448 WorkloadStatus: "CREATE_COMPLETE",
449 WorkloadStatusReason: map[string]interface{}{
450 "stacks": []map[string]interface{}{
452 "stack_status": "CREATE_COMPLETE",
458 instClient: &mockInstanceClient{
459 miniitems: []app.InstanceMiniResponse{
462 Request: app.InstanceRequest{
463 RBName: "test-rbdef",
465 ProfileName: "profile1",
466 CloudRegion: "region1",
468 Namespace: "testnamespace",
474 label: "Fail to find an Instance",
475 input: "test-vf-module-name-1",
476 expectedCode: http.StatusOK,
477 expectedResponse: brokerGETResponse{
478 TemplateType: "heat",
480 WorkloadStatus: "GET_COMPLETE",
481 WorkloadStatusReason: map[string]interface{}{
482 "stacks": []map[string]interface{}{},
485 instClient: &mockInstanceClient{},
489 for _, testCase := range testCases {
490 t.Run(testCase.label, func(t *testing.T) {
491 request := httptest.NewRequest("GET", "/cloudowner/cloudregion/infra_workload?name="+testCase.input, nil)
492 resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil, nil, nil))
494 if testCase.expectedCode != resp.StatusCode {
495 t.Fatalf("Request method returned: %v and it was expected: %v",
496 resp.StatusCode, testCase.expectedCode)
498 if resp.StatusCode == http.StatusOK {
499 var response brokerGETResponse
500 err := json.NewDecoder(resp.Body).Decode(&response)
502 t.Fatalf("Parsing the returned response got an error (%s)", err)
504 if testCase.expectedResponse.WorkloadID != response.WorkloadID {
505 t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
506 response.WorkloadID, testCase.expectedResponse.WorkloadID)
508 tcStacks := testCase.expectedResponse.WorkloadStatusReason["stacks"].([]map[string]interface{})
509 if len(tcStacks) != 0 {
510 //We expect only one response in this testcase.
511 resStacks := response.WorkloadStatusReason["stacks"].([]interface{})[0].(map[string]interface{})
512 if !reflect.DeepEqual(tcStacks[0], resStacks) {
513 t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
522 func TestBrokerDeleteHandler(t *testing.T) {
523 testCases := []struct {
527 expectedResponse brokerDELETEResponse
528 instClient *mockInstanceClient
531 label: "Fail to destroy VNF",
533 expectedCode: http.StatusInternalServerError,
534 instClient: &mockInstanceClient{
535 err: pkgerrors.New("Internal error"),
539 label: "Succesful delete a VNF",
541 expectedCode: http.StatusAccepted,
542 expectedResponse: brokerDELETEResponse{
543 TemplateType: "heat",
544 WorkloadID: "HaKpys8e",
545 WorkloadStatus: "DELETE_COMPLETE",
547 instClient: &mockInstanceClient{},
551 for _, testCase := range testCases {
552 t.Run(testCase.label, func(t *testing.T) {
553 request := httptest.NewRequest("DELETE", "/cloudowner/cloudregion/infra_workload/"+testCase.input, nil)
554 resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil, nil, nil))
556 if testCase.expectedCode != resp.StatusCode {
557 t.Fatalf("Request method returned: %v and it was expected: %v", resp.StatusCode, testCase.expectedCode)
559 if resp.StatusCode == http.StatusOK {
560 var response brokerGETResponse
561 err := json.NewDecoder(resp.Body).Decode(&response)
563 t.Fatalf("Parsing the returned response got an error (%s)", err)
565 if !reflect.DeepEqual(testCase.expectedResponse, response) {
566 t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
567 response, testCase.expectedResponse)