Add suport for query api on root level
[multicloud/k8s.git] / src / k8splugin / api / profilehandler_test.go
1 /*
2  * Copyright 2018 Intel Corporation, Inc
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package api
18
19 import (
20         "bytes"
21         "encoding/json"
22         "io"
23         "net/http"
24         "net/http/httptest"
25         "reflect"
26         "sort"
27         "testing"
28
29         "github.com/onap/multicloud-k8s/src/k8splugin/internal/rb"
30
31         pkgerrors "github.com/pkg/errors"
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 mockRBProfile struct {
38         rb.ProfileManager
39         // Items and err will be used to customize each test
40         // via a localized instantiation of mockRBProfile
41         Items []rb.Profile
42         Err   error
43 }
44
45 func (m *mockRBProfile) Create(inp rb.Profile) (rb.Profile, error) {
46         if m.Err != nil {
47                 return rb.Profile{}, m.Err
48         }
49
50         return m.Items[0], nil
51 }
52
53 func (m *mockRBProfile) Get(rbname, rbversion, prname string) (rb.Profile, error) {
54         if m.Err != nil {
55                 return rb.Profile{}, m.Err
56         }
57
58         return m.Items[0], nil
59 }
60
61 func (m *mockRBProfile) List(rbname, rbversion string) ([]rb.Profile, error) {
62         if m.Err != nil {
63                 return []rb.Profile{}, m.Err
64         }
65
66         return m.Items, nil
67 }
68
69 func (m *mockRBProfile) Delete(rbname, rbversion, prname string) error {
70         return m.Err
71 }
72
73 func (m *mockRBProfile) Upload(rbname, rbversion, prname string, inp []byte) error {
74         return m.Err
75 }
76
77 func TestRBProfileCreateHandler(t *testing.T) {
78         testCases := []struct {
79                 label        string
80                 reader       io.Reader
81                 expected     rb.Profile
82                 expectedCode int
83                 rbProClient  *mockRBProfile
84         }{
85                 {
86                         label:        "Missing Body Failure",
87                         expectedCode: http.StatusBadRequest,
88                         rbProClient:  &mockRBProfile{},
89                         reader:       nil,
90                 },
91                 {
92                         label:        "Create New Profile for Definition",
93                         expectedCode: http.StatusCreated,
94                         reader: bytes.NewBuffer([]byte(`{
95                                 "rb-name":"test-rbdef",
96                                 "rb-version":"v1",
97                                 "profile-name":"profile1",
98                                 "release-name":"testprofilereleasename",
99                                 "namespace":"default",
100                                 "kubernetes-version":"1.12.3"
101                                 }`)),
102                         expected: rb.Profile{
103                                 RBName:            "test-rbdef",
104                                 RBVersion:         "v1",
105                                 ProfileName:       "profile1",
106                                 ReleaseName:       "testprofilereleasename",
107                                 Namespace:         "default",
108                                 KubernetesVersion: "1.12.3",
109                         },
110                         rbProClient: &mockRBProfile{
111                                 //Items that will be returned by the mocked Client
112                                 Items: []rb.Profile{
113                                         {
114                                                 RBName:            "test-rbdef",
115                                                 RBVersion:         "v1",
116                                                 ProfileName:       "profile1",
117                                                 ReleaseName:       "testprofilereleasename",
118                                                 Namespace:         "default",
119                                                 KubernetesVersion: "1.12.3",
120                                         },
121                                 },
122                         },
123                 },
124         }
125
126         for _, testCase := range testCases {
127                 t.Run(testCase.label, func(t *testing.T) {
128                         request := httptest.NewRequest("POST", "/v1/rb/definition/test-rbdef/v1/profile",
129                                 testCase.reader)
130                         resp := executeRequest(request, NewRouter(nil, testCase.rbProClient, nil, nil, nil, nil, nil, nil))
131
132                         //Check returned code
133                         if resp.StatusCode != testCase.expectedCode {
134                                 t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode)
135                         }
136
137                         //Check returned body only if statusCreated
138                         if resp.StatusCode == http.StatusCreated {
139                                 got := rb.Profile{}
140                                 json.NewDecoder(resp.Body).Decode(&got)
141
142                                 if reflect.DeepEqual(testCase.expected, got) == false {
143                                         t.Errorf("createHandler returned unexpected body: got %v;"+
144                                                 " expected %v", got, testCase.expected)
145                                 }
146                         }
147                 })
148         }
149 }
150
151 func TestRBProfileGetHandler(t *testing.T) {
152
153         testCases := []struct {
154                 label        string
155                 expected     rb.Profile
156                 prname       string
157                 expectedCode int
158                 rbProClient  *mockRBProfile
159         }{
160                 {
161                         label:        "Get Bundle Profile",
162                         expectedCode: http.StatusOK,
163                         expected: rb.Profile{
164                                 RBName:            "test-rbdef",
165                                 RBVersion:         "v1",
166                                 ProfileName:       "profile1",
167                                 ReleaseName:       "testprofilereleasename",
168                                 Namespace:         "default",
169                                 KubernetesVersion: "1.12.3",
170                         },
171                         prname: "profile1",
172                         rbProClient: &mockRBProfile{
173                                 // Profile that will be returned by the mockclient
174                                 Items: []rb.Profile{
175                                         {
176                                                 RBName:            "test-rbdef",
177                                                 RBVersion:         "v1",
178                                                 ProfileName:       "profile1",
179                                                 ReleaseName:       "testprofilereleasename",
180                                                 Namespace:         "default",
181                                                 KubernetesVersion: "1.12.3",
182                                         },
183                                 },
184                         },
185                 },
186                 {
187                         label:        "Get Non-Existing Profile",
188                         expectedCode: http.StatusNotFound,
189                         prname:       "non-existing-profile",
190                         rbProClient: &mockRBProfile{
191                                 Items: nil,
192                                 Err:   pkgerrors.New("Error finding master table"),
193                         },
194                 },
195                 {
196                         label:        "Faulty DB response",
197                         expectedCode: http.StatusInternalServerError,
198                         prname:       "profile",
199                         rbProClient: &mockRBProfile{
200                                 // list of Profiles that will be returned by the mockclient
201                                 Items: []rb.Profile{},
202                                 Err:   pkgerrors.New("Internal Error"),
203                         },
204                 },
205         }
206
207         for _, testCase := range testCases {
208                 t.Run(testCase.label, func(t *testing.T) {
209                         request := httptest.NewRequest("GET", "/v1/rb/definition/test-rbdef/v1/profile/"+testCase.prname, nil)
210                         resp := executeRequest(request, NewRouter(nil, testCase.rbProClient, nil, nil, nil, nil, nil, nil))
211
212                         //Check returned code
213                         if resp.StatusCode != testCase.expectedCode {
214                                 t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode)
215                         }
216
217                         //Check returned body only if statusOK
218                         if resp.StatusCode == http.StatusOK {
219                                 got := rb.Profile{}
220                                 json.NewDecoder(resp.Body).Decode(&got)
221
222                                 if reflect.DeepEqual(testCase.expected, got) == false {
223                                         t.Errorf("listHandler returned unexpected body: got %v;"+
224                                                 " expected %v", got, testCase.expected)
225                                 }
226                         }
227                 })
228         }
229 }
230
231 func TestRBProfileListHandler(t *testing.T) {
232
233         testCases := []struct {
234                 def          string
235                 version      string
236                 label        string
237                 expected     []rb.Profile
238                 expectedCode int
239                 rbProClient  *mockRBProfile
240         }{
241                 {
242                         def:          "test-rbdef",
243                         version:      "v1",
244                         label:        "List Profiles",
245                         expectedCode: http.StatusOK,
246                         expected: []rb.Profile{
247                                 {
248                                         RBName:            "test-rbdef",
249                                         RBVersion:         "v1",
250                                         ProfileName:       "profile1",
251                                         ReleaseName:       "testprofilereleasename",
252                                         Namespace:         "ns1",
253                                         KubernetesVersion: "1.12.3",
254                                 },
255                                 {
256                                         RBName:            "test-rbdef",
257                                         RBVersion:         "v1",
258                                         ProfileName:       "profile2",
259                                         ReleaseName:       "testprofilereleasename",
260                                         Namespace:         "ns2",
261                                         KubernetesVersion: "1.12.3",
262                                 },
263                         },
264                         rbProClient: &mockRBProfile{
265                                 // list of Profiles that will be returned by the mockclient
266                                 Items: []rb.Profile{
267                                         {
268                                                 RBName:            "test-rbdef",
269                                                 RBVersion:         "v1",
270                                                 ProfileName:       "profile1",
271                                                 ReleaseName:       "testprofilereleasename",
272                                                 Namespace:         "ns1",
273                                                 KubernetesVersion: "1.12.3",
274                                         },
275                                         {
276                                                 RBName:            "test-rbdef",
277                                                 RBVersion:         "v1",
278                                                 ProfileName:       "profile2",
279                                                 ReleaseName:       "testprofilereleasename",
280                                                 Namespace:         "ns2",
281                                                 KubernetesVersion: "1.12.3",
282                                         },
283                                 },
284                         },
285                 },
286         }
287
288         for _, testCase := range testCases {
289                 t.Run(testCase.label, func(t *testing.T) {
290                         request := httptest.NewRequest("GET", "/v1/rb/definition/"+testCase.def+"/"+testCase.version+"/profile", nil)
291                         resp := executeRequest(request, NewRouter(nil, testCase.rbProClient, nil, nil, nil, nil, nil, nil))
292
293                         //Check returned code
294                         if resp.StatusCode != testCase.expectedCode {
295                                 t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode)
296                         }
297
298                         //Check returned body only if statusOK
299                         if resp.StatusCode == http.StatusOK {
300                                 got := []rb.Profile{}
301                                 json.NewDecoder(resp.Body).Decode(&got)
302
303                                 // Since the order of returned slice is not guaranteed
304                                 // Check both and return error if both don't match
305                                 sort.Slice(got, func(i, j int) bool {
306                                         return got[i].ProfileName < got[j].ProfileName
307                                 })
308                                 // Sort both as it is not expected that testCase.expected
309                                 // is sorted
310                                 sort.Slice(testCase.expected, func(i, j int) bool {
311                                         return testCase.expected[i].ProfileName < testCase.expected[j].ProfileName
312                                 })
313
314                                 if reflect.DeepEqual(testCase.expected, got) == false {
315                                         t.Errorf("listHandler returned unexpected body: got %v;"+
316                                                 " expected %v", got, testCase.expected)
317                                 }
318                         }
319                 })
320         }
321 }
322
323 func TestRBProfileDeleteHandler(t *testing.T) {
324
325         testCases := []struct {
326                 label        string
327                 prname       string
328                 expectedCode int
329                 rbProClient  *mockRBProfile
330         }{
331                 {
332                         label:        "Delete Bundle Profile",
333                         expectedCode: http.StatusNoContent,
334                         prname:       "profile1",
335                         rbProClient:  &mockRBProfile{},
336                 },
337                 {
338                         label:        "Delete Non-Exiting Bundle Profile",
339                         expectedCode: http.StatusInternalServerError,
340                         prname:       "non-existing",
341                         rbProClient: &mockRBProfile{
342                                 Err: pkgerrors.New("Internal Error"),
343                         },
344                 },
345         }
346
347         for _, testCase := range testCases {
348                 t.Run(testCase.label, func(t *testing.T) {
349                         request := httptest.NewRequest("DELETE", "/v1/rb/definition/test-rbdef/v1/profile/"+testCase.prname, nil)
350                         resp := executeRequest(request, NewRouter(nil, testCase.rbProClient, nil, nil, nil, nil, nil, nil))
351
352                         //Check returned code
353                         if resp.StatusCode != testCase.expectedCode {
354                                 t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode)
355                         }
356                 })
357         }
358 }
359
360 func TestRBProfileUploadHandler(t *testing.T) {
361
362         testCases := []struct {
363                 label        string
364                 prname       string
365                 body         io.Reader
366                 expectedCode int
367                 rbProClient  *mockRBProfile
368         }{
369                 {
370                         label:        "Upload Bundle Profile Content",
371                         expectedCode: http.StatusOK,
372                         prname:       "profile1",
373                         body: bytes.NewBuffer([]byte{
374                                 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
375                                 0x00, 0xff, 0xf2, 0x48, 0xcd,
376                         }),
377                         rbProClient: &mockRBProfile{},
378                 },
379                 {
380                         label:        "Upload Invalid Bundle Profile Content",
381                         expectedCode: http.StatusInternalServerError,
382                         prname:       "profile1",
383                         body: bytes.NewBuffer([]byte{
384                                 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
385                                 0x00, 0xff, 0xf2, 0x48, 0xcd,
386                         }),
387                         rbProClient: &mockRBProfile{
388                                 Err: pkgerrors.New("Internal Error"),
389                         },
390                 },
391                 {
392                         label:        "Upload Empty Body Content",
393                         expectedCode: http.StatusBadRequest,
394                         prname:       "profile1",
395                         rbProClient:  &mockRBProfile{},
396                 },
397         }
398
399         for _, testCase := range testCases {
400                 t.Run(testCase.label, func(t *testing.T) {
401                         request := httptest.NewRequest("POST",
402                                 "/v1/rb/definition/test-rbdef/v1/profile/"+testCase.prname+"/content", testCase.body)
403                         resp := executeRequest(request, NewRouter(nil, testCase.rbProClient, nil, nil, nil, nil, nil, nil))
404
405                         //Check returned code
406                         if resp.StatusCode != testCase.expectedCode {
407                                 t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode)
408                         }
409                 })
410         }
411 }