Make definition tags specific
[multicloud/k8s.git] / src / k8splugin / api / instancehandler_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         "github.com/gorilla/mux"
30         pkgerrors "github.com/pkg/errors"
31         "k8s.io/apimachinery/pkg/runtime/schema"
32 )
33
34 //Creating an embedded interface via anonymous variable
35 //This allows us to make mockDB satisfy the DatabaseConnection
36 //interface even if we are not implementing all the methods in it
37 type mockInstanceClient struct {
38         app.InstanceManager
39         // Items and err will be used to customize each test
40         // via a localized instantiation of mockInstanceClient
41         items []app.InstanceResponse
42         err   error
43 }
44
45 func (m *mockInstanceClient) Create(inp app.InstanceRequest) (app.InstanceResponse, error) {
46         if m.err != nil {
47                 return app.InstanceResponse{}, m.err
48         }
49
50         return m.items[0], nil
51 }
52
53 func (m *mockInstanceClient) Get(id string) (app.InstanceResponse, error) {
54         if m.err != nil {
55                 return app.InstanceResponse{}, m.err
56         }
57
58         return m.items[0], nil
59 }
60
61 func (m *mockInstanceClient) Find(rbName string, ver string, profile string, labelKeys map[string]string) ([]app.InstanceResponse, error) {
62         if m.err != nil {
63                 return nil, m.err
64         }
65
66         return m.items, nil
67 }
68
69 func (m *mockInstanceClient) Delete(id string) error {
70         return m.err
71 }
72
73 func executeRequest(request *http.Request, router *mux.Router) *http.Response {
74         recorder := httptest.NewRecorder()
75         router.ServeHTTP(recorder, request)
76         resp := recorder.Result()
77         return resp
78 }
79
80 func TestInstanceCreateHandler(t *testing.T) {
81         testCases := []struct {
82                 label        string
83                 input        io.Reader
84                 expected     app.InstanceResponse
85                 expectedCode int
86                 instClient   *mockInstanceClient
87         }{
88                 {
89                         label:        "Missing body failure",
90                         expectedCode: http.StatusBadRequest,
91                 },
92                 {
93                         label:        "Invalid JSON request format",
94                         input:        bytes.NewBuffer([]byte("invalid")),
95                         expectedCode: http.StatusUnprocessableEntity,
96                 },
97                 {
98                         label: "Missing parameter failure",
99                         input: bytes.NewBuffer([]byte(`{
100                                 "rb-name": "test-rbdef",
101                                 "profile-name": "profile1",
102                                 "cloud-region": "kud"
103                         }`)),
104                         expectedCode: http.StatusUnprocessableEntity,
105                 },
106                 {
107                         label: "Succesfully create an Instance",
108                         input: bytes.NewBuffer([]byte(`{
109                                 "cloud-region": "region1",
110                                 "rb-name": "test-rbdef",
111                                 "rb-version": "v1",
112                                 "profile-name": "profile1"
113                         }`)),
114                         expected: app.InstanceResponse{
115                                 ID: "HaKpys8e",
116                                 Request: app.InstanceRequest{
117                                         RBName:      "test-rbdef",
118                                         RBVersion:   "v1",
119                                         ProfileName: "profile1",
120                                         CloudRegion: "region1",
121                                 },
122                                 Namespace: "testnamespace",
123                                 Resources: []helm.KubernetesResource{
124                                         {
125                                                 GVK: schema.GroupVersionKind{
126                                                         Group:   "apps",
127                                                         Version: "v1",
128                                                         Kind:    "Deployment"},
129                                                 Name: "test-deployment",
130                                         },
131                                         {
132                                                 GVK: schema.GroupVersionKind{
133                                                         Group:   "",
134                                                         Version: "v1",
135                                                         Kind:    "Service"},
136                                                 Name: "test-service",
137                                         },
138                                 },
139                         },
140                         expectedCode: http.StatusCreated,
141                         instClient: &mockInstanceClient{
142                                 items: []app.InstanceResponse{
143                                         {
144                                                 ID: "HaKpys8e",
145                                                 Request: app.InstanceRequest{
146                                                         RBName:      "test-rbdef",
147                                                         RBVersion:   "v1",
148                                                         ProfileName: "profile1",
149                                                         CloudRegion: "region1",
150                                                 },
151                                                 Namespace: "testnamespace",
152                                                 Resources: []helm.KubernetesResource{
153                                                         {
154                                                                 GVK: schema.GroupVersionKind{
155                                                                         Group:   "apps",
156                                                                         Version: "v1",
157                                                                         Kind:    "Deployment"},
158                                                                 Name: "test-deployment",
159                                                         },
160                                                         {
161                                                                 GVK: schema.GroupVersionKind{
162                                                                         Group:   "",
163                                                                         Version: "v1",
164                                                                         Kind:    "Service"},
165                                                                 Name: "test-service",
166                                                         },
167                                                 },
168                                         },
169                                 },
170                         },
171                 },
172         }
173
174         for _, testCase := range testCases {
175                 t.Run(testCase.label, func(t *testing.T) {
176
177                         request := httptest.NewRequest("POST", "/v1/instance", testCase.input)
178                         resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil))
179
180                         if testCase.expectedCode != resp.StatusCode {
181                                 body, _ := ioutil.ReadAll(resp.Body)
182                                 t.Log(string(body))
183                                 t.Fatalf("Request method returned: \n%v\n and it was expected: \n%v", resp.StatusCode, testCase.expectedCode)
184                         }
185
186                         if resp.StatusCode == http.StatusCreated {
187                                 var response app.InstanceResponse
188                                 err := json.NewDecoder(resp.Body).Decode(&response)
189                                 if err != nil {
190                                         t.Fatalf("Parsing the returned response got an error (%s)", err)
191                                 }
192                         }
193                 })
194         }
195 }
196
197 func TestInstanceGetHandler(t *testing.T) {
198         testCases := []struct {
199                 label            string
200                 input            string
201                 expectedCode     int
202                 expectedResponse *app.InstanceResponse
203                 instClient       *mockInstanceClient
204         }{
205                 {
206                         label:        "Fail to retrieve Instance",
207                         input:        "HaKpys8e",
208                         expectedCode: http.StatusInternalServerError,
209                         instClient: &mockInstanceClient{
210                                 err: pkgerrors.New("Internal error"),
211                         },
212                 },
213                 {
214                         label:        "Succesful get an Instance",
215                         input:        "HaKpys8e",
216                         expectedCode: http.StatusOK,
217                         expectedResponse: &app.InstanceResponse{
218                                 ID: "HaKpys8e",
219                                 Request: app.InstanceRequest{
220                                         RBName:      "test-rbdef",
221                                         RBVersion:   "v1",
222                                         ProfileName: "profile1",
223                                         CloudRegion: "region1",
224                                 },
225                                 Namespace: "testnamespace",
226                                 Resources: []helm.KubernetesResource{
227                                         {
228                                                 GVK: schema.GroupVersionKind{
229                                                         Group:   "apps",
230                                                         Version: "v1",
231                                                         Kind:    "Deployment"},
232                                                 Name: "test-deployment",
233                                         },
234                                         {
235                                                 GVK: schema.GroupVersionKind{
236                                                         Group:   "",
237                                                         Version: "v1",
238                                                         Kind:    "Service"},
239                                                 Name: "test-service",
240                                         },
241                                 },
242                         },
243                         instClient: &mockInstanceClient{
244                                 items: []app.InstanceResponse{
245                                         {
246                                                 ID: "HaKpys8e",
247                                                 Request: app.InstanceRequest{
248                                                         RBName:      "test-rbdef",
249                                                         RBVersion:   "v1",
250                                                         ProfileName: "profile1",
251                                                         CloudRegion: "region1",
252                                                 },
253                                                 Namespace: "testnamespace",
254                                                 Resources: []helm.KubernetesResource{
255                                                         {
256                                                                 GVK: schema.GroupVersionKind{
257                                                                         Group:   "apps",
258                                                                         Version: "v1",
259                                                                         Kind:    "Deployment"},
260                                                                 Name: "test-deployment",
261                                                         },
262                                                         {
263                                                                 GVK: schema.GroupVersionKind{
264                                                                         Group:   "",
265                                                                         Version: "v1",
266                                                                         Kind:    "Service"},
267                                                                 Name: "test-service",
268                                                         },
269                                                 },
270                                         },
271                                 },
272                         },
273                 },
274         }
275
276         for _, testCase := range testCases {
277                 t.Run(testCase.label, func(t *testing.T) {
278                         request := httptest.NewRequest("GET", "/v1/instance/"+testCase.input, nil)
279                         resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil))
280
281                         if testCase.expectedCode != resp.StatusCode {
282                                 t.Fatalf("Request method returned: %v and it was expected: %v",
283                                         resp.StatusCode, testCase.expectedCode)
284                         }
285                         if resp.StatusCode == http.StatusOK {
286                                 var response app.InstanceResponse
287                                 err := json.NewDecoder(resp.Body).Decode(&response)
288                                 if err != nil {
289                                         t.Fatalf("Parsing the returned response got an error (%s)", err)
290                                 }
291                                 if !reflect.DeepEqual(testCase.expectedResponse, &response) {
292                                         t.Fatalf("TestGetHandler returned:\n result=%v\n expected=%v",
293                                                 &response, testCase.expectedResponse)
294                                 }
295                         }
296                 })
297         }
298 }
299
300 func TestDeleteHandler(t *testing.T) {
301         testCases := []struct {
302                 label        string
303                 input        string
304                 expectedCode int
305                 instClient   *mockInstanceClient
306         }{
307                 {
308                         label:        "Fail to destroy VNF",
309                         input:        "HaKpys8e",
310                         expectedCode: http.StatusInternalServerError,
311                         instClient: &mockInstanceClient{
312                                 err: pkgerrors.New("Internal error"),
313                         },
314                 },
315                 {
316                         label:        "Succesful delete a VNF",
317                         input:        "HaKpys8e",
318                         expectedCode: http.StatusAccepted,
319                         instClient:   &mockInstanceClient{},
320                 },
321         }
322
323         for _, testCase := range testCases {
324                 t.Run(testCase.label, func(t *testing.T) {
325                         request := httptest.NewRequest("DELETE", "/v1/instance/"+testCase.input, nil)
326                         resp := executeRequest(request, NewRouter(nil, nil, testCase.instClient, nil, nil, nil))
327
328                         if testCase.expectedCode != resp.StatusCode {
329                                 t.Fatalf("Request method returned: %v and it was expected: %v", resp.StatusCode, testCase.expectedCode)
330                         }
331                 })
332         }
333 }
334
335 // TODO: Update this test when the UpdateVNF endpoint is fixed.
336 /*
337 func TestVNFInstanceUpdate(t *testing.T) {
338         t.Run("Succesful update a VNF", func(t *testing.T) {
339                 payload := []byte(`{
340                         "cloud_region_id": "region1",
341                         "csar_id": "UUID-1",
342                         "oof_parameters": [{
343                                 "key1": "value1",
344                                 "key2": "value2",
345                                 "key3": {}
346                         }],
347                         "network_parameters": {
348                                 "oam_ip_address": {
349                                         "connection_point": "string",
350                                         "ip_address": "string",
351                                         "workload_name": "string"
352                                 }
353                         }
354                 }`)
355                 expected := &UpdateVnfResponse{
356                         DeploymentID: "1",
357                 }
358
359                 var result UpdateVnfResponse
360
361                 req := httptest.NewRequest("PUT", "/v1/vnf_instances/1", bytes.NewBuffer(payload))
362
363                 GetVNFClient = func(configPath string) (krd.VNFInstanceClientInterface, error) {
364                         return &mockClient{
365                                 update: func() error {
366                                         return nil
367                                 },
368                         }, nil
369                 }
370                 utils.ReadCSARFromFileSystem = func(csarID string) (*krd.KubernetesData, error) {
371                         kubeData := &krd.KubernetesData{
372                                 Deployment: &appsV1.Deployment{},
373                                 Service:    &coreV1.Service{},
374                         }
375                         return kubeData, nil
376                 }
377
378                 response := executeRequest(req)
379                 checkResponseCode(t, http.StatusCreated, response.Code)
380
381                 err := json.NewDecoder(response.Body).Decode(&result)
382                 if err != nil {
383                         t.Fatalf("TestVNFInstanceUpdate returned:\n result=%v\n expected=%v", err, expected.DeploymentID)
384                 }
385
386                 if resp.DeploymentID != expected.DeploymentID {
387                         t.Fatalf("TestVNFInstanceUpdate returned:\n result=%v\n expected=%v", resp.DeploymentID, expected.DeploymentID)
388                 }
389         })
390 }
391 */