Merge "Update nfn-operator to add provider networks"
[multicloud/k8s.git] / src / k8splugin / api / brokerhandler_test.go
1 /*
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.
12 */
13
14 package api
15
16 import (
17         "bytes"
18         "encoding/json"
19         "io"
20         "io/ioutil"
21         "net/http"
22         "net/http/httptest"
23         "reflect"
24         "testing"
25
26         "github.com/onap/multicloud-k8s/src/k8splugin/internal/app"
27         "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm"
28
29         pkgerrors "github.com/pkg/errors"
30         "k8s.io/apimachinery/pkg/runtime/schema"
31 )
32
33 func TestBrokerCreateHandler(t *testing.T) {
34         testCases := []struct {
35                 label        string
36                 input        io.Reader
37                 expected     brokerPOSTResponse
38                 expectedCode int
39                 instClient   *mockInstanceClient
40         }{
41                 {
42                         label:        "Missing body failure",
43                         expectedCode: http.StatusBadRequest,
44                 },
45                 {
46                         label:        "Invalid JSON request format",
47                         input:        bytes.NewBuffer([]byte("invalid")),
48                         expectedCode: http.StatusUnprocessableEntity,
49                 },
50                 {
51                         label: "Missing vf-module-*-id parameter",
52                         input: bytes.NewBuffer([]byte(`{
53                                 "vf-module-model-customization-id": "84sdfkio938",
54                                 "vf-module-model-invariant-id": "123456qwerty",
55                                 "sdnc_directives": {
56                                         "attributes": [
57                                                 {
58                                                         "attribute_name": "vf_module_name",
59                                                         "attribute_value": "test-vf-module-name"
60                                                 },
61                                                 {
62                                                         "attribute_name": "k8s-rb-profile-name",
63                                                         "attribute_value": "profile1"
64                                                 }
65                                         ]
66                                 }
67                         }`)),
68                         expectedCode: http.StatusBadRequest,
69                 },
70                 {
71                         label: "Missing parameter from sdnc_directives",
72                         input: bytes.NewBuffer([]byte(`{
73                                 "vf-module-model-customization-id": "84sdfkio938",
74                                 "vf-module-model-invariant-id": "123456qwerty",
75                                 "vf-module-model-version-id": "123qweasdzxc",
76                                 "sdnc_directives": {
77                                         "attributes": [
78                                                 {
79                                                         "attribute_name": "vf_module_name",
80                                                         "attribute_value": "test-vf-module-name"
81                                                 }
82                                         ]
83                                 }
84                         }`)),
85                         expectedCode: http.StatusBadRequest,
86                 },
87                 {
88                         label: "Succesfully create an Instance",
89                         input: bytes.NewBuffer([]byte(`{
90                                 "vf-module-model-customization-id": "84sdfkio938",
91                                 "vf-module-model-invariant-id": "123456qwerty",
92                                 "vf-module-model-version-id": "123qweasdzxc",
93                                 "sdnc_directives": {
94                                         "attributes": [
95                                                 {
96                                                         "attribute_name": "vf_module_name",
97                                                         "attribute_value": "test-vf-module-name"
98                                                 },
99                                                 {
100                                                         "attribute_name": "k8s-rb-profile-name",
101                                                         "attribute_value": "profile1"
102                                                 }
103                                         ]
104                                 }
105                         }`)),
106                         expected: brokerPOSTResponse{
107                                 WorkloadID:     "HaKpys8e",
108                                 TemplateType:   "heat",
109                                 WorkloadStatus: "CREATE_COMPLETE",
110                                 TemplateResponse: []helm.KubernetesResource{
111                                         {
112                                                 GVK: schema.GroupVersionKind{
113                                                         Group:   "apps",
114                                                         Version: "v1",
115                                                         Kind:    "Deployment"},
116                                                 Name: "test-deployment",
117                                         },
118                                         {
119                                                 GVK: schema.GroupVersionKind{
120                                                         Group:   "",
121                                                         Version: "v1",
122                                                         Kind:    "Service"},
123                                                 Name: "test-service",
124                                         },
125                                 },
126                         },
127                         expectedCode: http.StatusCreated,
128                         instClient: &mockInstanceClient{
129                                 items: []app.InstanceResponse{
130                                         {
131                                                 ID: "HaKpys8e",
132                                                 Request: app.InstanceRequest{
133                                                         RBName:      "123456qwerty",
134                                                         RBVersion:   "123qweasdzxc",
135                                                         ProfileName: "profile1",
136                                                         CloudRegion: "region1",
137                                                 },
138                                                 Namespace: "testnamespace",
139                                                 Resources: []helm.KubernetesResource{
140                                                         {
141                                                                 GVK: schema.GroupVersionKind{
142                                                                         Group:   "apps",
143                                                                         Version: "v1",
144                                                                         Kind:    "Deployment"},
145                                                                 Name: "test-deployment",
146                                                         },
147                                                         {
148                                                                 GVK: schema.GroupVersionKind{
149                                                                         Group:   "",
150                                                                         Version: "v1",
151                                                                         Kind:    "Service"},
152                                                                 Name: "test-service",
153                                                         },
154                                                 },
155                                         },
156                                 },
157                         },
158                 },
159         }
160
161         for _, testCase := range testCases {
162                 t.Run(testCase.label, func(t *testing.T) {
163
164                         request := httptest.NewRequest("POST", "/cloudowner/cloudregion/infra_workload", testCase.input)
165                         resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil))
166
167                         if testCase.expectedCode != resp.StatusCode {
168                                 body, _ := ioutil.ReadAll(resp.Body)
169                                 t.Log(string(body))
170                                 t.Fatalf("Request method returned: \n%v\n and it was expected: \n%v", resp.StatusCode, testCase.expectedCode)
171                         }
172
173                         if resp.StatusCode == http.StatusCreated {
174                                 var response brokerPOSTResponse
175                                 err := json.NewDecoder(resp.Body).Decode(&response)
176                                 if err != nil {
177                                         t.Fatalf("Parsing the returned response got an error (%s)", err)
178                                 }
179                                 if !reflect.DeepEqual(testCase.expected, response) {
180                                         t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
181                                                 response, testCase.expected)
182                                 }
183                         }
184                 })
185         }
186 }
187
188 func TestBrokerGetHandler(t *testing.T) {
189         testCases := []struct {
190                 label            string
191                 input            string
192                 expectedCode     int
193                 expectedResponse brokerGETResponse
194                 instClient       *mockInstanceClient
195         }{
196                 {
197                         label:        "Fail to retrieve Instance",
198                         input:        "HaKpys8e",
199                         expectedCode: http.StatusInternalServerError,
200                         instClient: &mockInstanceClient{
201                                 err: pkgerrors.New("Internal error"),
202                         },
203                 },
204                 {
205                         label:        "Succesful get an Instance",
206                         input:        "HaKpys8e",
207                         expectedCode: http.StatusOK,
208                         expectedResponse: brokerGETResponse{
209                                 TemplateType:   "heat",
210                                 WorkloadID:     "HaKpys8e",
211                                 WorkloadStatus: "CREATE_COMPLETE",
212                         },
213                         instClient: &mockInstanceClient{
214                                 items: []app.InstanceResponse{
215                                         {
216                                                 ID: "HaKpys8e",
217                                                 Request: app.InstanceRequest{
218                                                         RBName:      "test-rbdef",
219                                                         RBVersion:   "v1",
220                                                         ProfileName: "profile1",
221                                                         CloudRegion: "region1",
222                                                 },
223                                                 Namespace: "testnamespace",
224                                                 Resources: []helm.KubernetesResource{
225                                                         {
226                                                                 GVK: schema.GroupVersionKind{
227                                                                         Group:   "apps",
228                                                                         Version: "v1",
229                                                                         Kind:    "Deployment"},
230                                                                 Name: "test-deployment",
231                                                         },
232                                                         {
233                                                                 GVK: schema.GroupVersionKind{
234                                                                         Group:   "",
235                                                                         Version: "v1",
236                                                                         Kind:    "Service"},
237                                                                 Name: "test-service",
238                                                         },
239                                                 },
240                                         },
241                                 },
242                         },
243                 },
244         }
245
246         for _, testCase := range testCases {
247                 t.Run(testCase.label, func(t *testing.T) {
248                         request := httptest.NewRequest("GET", "/cloudowner/cloudregion/infra_workload/"+testCase.input, nil)
249                         resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil))
250
251                         if testCase.expectedCode != resp.StatusCode {
252                                 t.Fatalf("Request method returned: %v and it was expected: %v",
253                                         resp.StatusCode, testCase.expectedCode)
254                         }
255                         if resp.StatusCode == http.StatusOK {
256                                 var response brokerGETResponse
257                                 err := json.NewDecoder(resp.Body).Decode(&response)
258                                 if err != nil {
259                                         t.Fatalf("Parsing the returned response got an error (%s)", err)
260                                 }
261                                 if !reflect.DeepEqual(testCase.expectedResponse, response) {
262                                         t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
263                                                 response, testCase.expectedResponse)
264                                 }
265                         }
266                 })
267         }
268 }
269
270 func TestBrokerFindHandler(t *testing.T) {
271         testCases := []struct {
272                 label            string
273                 input            string
274                 expectedCode     int
275                 expectedResponse brokerGETResponse
276                 instClient       *mockInstanceClient
277         }{
278                 {
279                         label:        "Successful find an Instance",
280                         input:        "test-vf-module-name",
281                         expectedCode: http.StatusOK,
282                         expectedResponse: brokerGETResponse{
283                                 TemplateType:   "heat",
284                                 WorkloadID:     "HaKpys8e",
285                                 WorkloadStatus: "CREATE_COMPLETE",
286                                 WorkloadStatusReason: map[string]interface{}{
287                                         "stacks": []map[string]interface{}{
288                                                 {
289                                                         "stack_status": "CREATE_COMPLETE",
290                                                         "id":           "HaKpys8e",
291                                                 },
292                                         },
293                                 },
294                         },
295                         instClient: &mockInstanceClient{
296                                 miniitems: []app.InstanceMiniResponse{
297                                         {
298                                                 ID: "HaKpys8e",
299                                                 Request: app.InstanceRequest{
300                                                         RBName:      "test-rbdef",
301                                                         RBVersion:   "v1",
302                                                         ProfileName: "profile1",
303                                                         CloudRegion: "region1",
304                                                 },
305                                                 Namespace: "testnamespace",
306                                         },
307                                 },
308                         },
309                 },
310                 {
311                         label:        "Fail to find an Instance",
312                         input:        "test-vf-module-name-1",
313                         expectedCode: http.StatusOK,
314                         expectedResponse: brokerGETResponse{
315                                 TemplateType:   "heat",
316                                 WorkloadID:     "",
317                                 WorkloadStatus: "GET_COMPLETE",
318                                 WorkloadStatusReason: map[string]interface{}{
319                                         "stacks": []map[string]interface{}{},
320                                 },
321                         },
322                         instClient: &mockInstanceClient{},
323                 },
324         }
325
326         for _, testCase := range testCases {
327                 t.Run(testCase.label, func(t *testing.T) {
328                         request := httptest.NewRequest("GET", "/cloudowner/cloudregion/infra_workload?name="+testCase.input, nil)
329                         resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil))
330
331                         if testCase.expectedCode != resp.StatusCode {
332                                 t.Fatalf("Request method returned: %v and it was expected: %v",
333                                         resp.StatusCode, testCase.expectedCode)
334                         }
335                         if resp.StatusCode == http.StatusOK {
336                                 var response brokerGETResponse
337                                 err := json.NewDecoder(resp.Body).Decode(&response)
338                                 if err != nil {
339                                         t.Fatalf("Parsing the returned response got an error (%s)", err)
340                                 }
341                                 if testCase.expectedResponse.WorkloadID != response.WorkloadID {
342                                         t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
343                                                 response.WorkloadID, testCase.expectedResponse.WorkloadID)
344                                 }
345                                 tcStacks := testCase.expectedResponse.WorkloadStatusReason["stacks"].([]map[string]interface{})
346                                 if len(tcStacks) != 0 {
347                                         //We expect only one response in this testcase.
348                                         resStacks := response.WorkloadStatusReason["stacks"].([]interface{})[0].(map[string]interface{})
349                                         if !reflect.DeepEqual(tcStacks[0], resStacks) {
350                                                 t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
351                                                         resStacks, tcStacks)
352                                         }
353                                 }
354                         }
355                 })
356         }
357 }
358
359 func TestBrokerDeleteHandler(t *testing.T) {
360         testCases := []struct {
361                 label            string
362                 input            string
363                 expectedCode     int
364                 expectedResponse brokerDELETEResponse
365                 instClient       *mockInstanceClient
366         }{
367                 {
368                         label:        "Fail to destroy VNF",
369                         input:        "HaKpys8e",
370                         expectedCode: http.StatusInternalServerError,
371                         instClient: &mockInstanceClient{
372                                 err: pkgerrors.New("Internal error"),
373                         },
374                 },
375                 {
376                         label:        "Succesful delete a VNF",
377                         input:        "HaKpys8e",
378                         expectedCode: http.StatusAccepted,
379                         expectedResponse: brokerDELETEResponse{
380                                 TemplateType:   "heat",
381                                 WorkloadID:     "HaKpys8e",
382                                 WorkloadStatus: "DELETE_COMPLETE",
383                         },
384                         instClient: &mockInstanceClient{},
385                 },
386         }
387
388         for _, testCase := range testCases {
389                 t.Run(testCase.label, func(t *testing.T) {
390                         request := httptest.NewRequest("DELETE", "/cloudowner/cloudregion/infra_workload/"+testCase.input, nil)
391                         resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil))
392
393                         if testCase.expectedCode != resp.StatusCode {
394                                 t.Fatalf("Request method returned: %v and it was expected: %v", resp.StatusCode, testCase.expectedCode)
395                         }
396                         if resp.StatusCode == http.StatusOK {
397                                 var response brokerGETResponse
398                                 err := json.NewDecoder(resp.Body).Decode(&response)
399                                 if err != nil {
400                                         t.Fatalf("Parsing the returned response got an error (%s)", err)
401                                 }
402                                 if !reflect.DeepEqual(testCase.expectedResponse, response) {
403                                         t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
404                                                 response, testCase.expectedResponse)
405                                 }
406                         }
407                 })
408         }
409 }