summaryrefslogtreecommitdiffstats
path: root/src/k8splugin
diff options
context:
space:
mode:
Diffstat (limited to 'src/k8splugin')
-rw-r--r--src/k8splugin/api/api.go10
-rw-r--r--src/k8splugin/api/defhandler.go1
-rw-r--r--src/k8splugin/api/defhandler_test.go22
-rw-r--r--src/k8splugin/api/profilehandler.go161
-rw-r--r--src/k8splugin/api/profilehandler_test.go422
-rw-r--r--src/k8splugin/db/mongo.go13
-rw-r--r--src/k8splugin/go.mod2
-rw-r--r--src/k8splugin/go.sum4
-rw-r--r--src/k8splugin/mock_files/mock_json/create_rbdefinition.json6
-rw-r--r--src/k8splugin/mock_files/mock_json/create_rbprofile.json7
-rw-r--r--src/k8splugin/mock_files/mock_json/create_vnfd.json6
-rw-r--r--src/k8splugin/rb/definition.go12
-rw-r--r--src/k8splugin/rb/definition_test.go26
-rw-r--r--src/k8splugin/rb/profile.go185
-rw-r--r--src/k8splugin/rb/profile_test.go414
15 files changed, 1263 insertions, 28 deletions
diff --git a/src/k8splugin/api/api.go b/src/k8splugin/api/api.go
index 06f5009f..593e2b0b 100644
--- a/src/k8splugin/api/api.go
+++ b/src/k8splugin/api/api.go
@@ -106,6 +106,7 @@ func NewRouter(kubeconfig string) *mux.Router {
vnfInstanceHandler.HandleFunc("/{cloudRegionID}/{namespace}/{externalVNFID}", DeleteHandler).Methods("DELETE")
vnfInstanceHandler.HandleFunc("/{cloudRegionID}/{namespace}/{externalVNFID}", GetHandler).Methods("GET")
+ //rbd is resource bundle definition
resRouter := router.PathPrefix("/v1/rb").Subrouter()
rbdef := rbDefinitionHandler{client: rb.NewDefinitionClient()}
resRouter.HandleFunc("/definition", rbdef.createHandler).Methods("POST")
@@ -114,6 +115,15 @@ func NewRouter(kubeconfig string) *mux.Router {
resRouter.HandleFunc("/definition/{rbdID}", rbdef.getHandler).Methods("GET")
resRouter.HandleFunc("/definition/{rbdID}", rbdef.deleteHandler).Methods("DELETE")
+ //rbp is resource bundle profile
+ rbprofile := rbProfileHandler{client: rb.NewProfileClient()}
+ resRouter.HandleFunc("/profile", rbprofile.createHandler).Methods("POST")
+ resRouter.HandleFunc("/profile/{rbpID}/content", rbprofile.uploadHandler).Methods("POST")
+ resRouter.HandleFunc("/profile/help", rbprofile.helpHandler).Methods("GET")
+ resRouter.HandleFunc("/profile", rbprofile.listHandler).Methods("GET")
+ resRouter.HandleFunc("/profile/{rbpID}", rbprofile.getHandler).Methods("GET")
+ resRouter.HandleFunc("/profile/{rbpID}", rbprofile.deleteHandler).Methods("DELETE")
+
// (TODO): Fix update method
// vnfInstanceHandler.HandleFunc("/{vnfInstanceId}", UpdateHandler).Methods("PUT")
diff --git a/src/k8splugin/api/defhandler.go b/src/k8splugin/api/defhandler.go
index 222baaee..31b0f38f 100644
--- a/src/k8splugin/api/defhandler.go
+++ b/src/k8splugin/api/defhandler.go
@@ -70,7 +70,6 @@ func (h rbDefinitionHandler) createHandler(w http.ResponseWriter, r *http.Reques
}
// uploadHandler handles upload of the bundle tar file into the database
-// Note: This will be implemented in a different patch
func (h rbDefinitionHandler) uploadHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
uuid := vars["rbdID"]
diff --git a/src/k8splugin/api/defhandler_test.go b/src/k8splugin/api/defhandler_test.go
index 9739ab12..3dbd1aa4 100644
--- a/src/k8splugin/api/defhandler_test.go
+++ b/src/k8splugin/api/defhandler_test.go
@@ -24,6 +24,7 @@ import (
"net/http"
"net/http/httptest"
"reflect"
+ "sort"
"testing"
pkgerrors "github.com/pkg/errors"
@@ -116,7 +117,7 @@ func TestRBDefCreateHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
vh := rbDefinitionHandler{client: testCase.rbDefClient}
- req, err := http.NewRequest("POST", "/v1/resource/definition", testCase.reader)
+ req, err := http.NewRequest("POST", "/v1/rb/definition", testCase.reader)
if err != nil {
t.Fatal(err)
@@ -193,7 +194,7 @@ func TestRBDefListHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
vh := rbDefinitionHandler{client: testCase.rbDefClient}
- req, err := http.NewRequest("GET", "/v1/resource/definition", nil)
+ req, err := http.NewRequest("GET", "/v1/rb/definition", nil)
if err != nil {
t.Fatal(err)
}
@@ -212,6 +213,17 @@ func TestRBDefListHandler(t *testing.T) {
got := []rb.Definition{}
json.NewDecoder(rr.Body).Decode(&got)
+ // Since the order of returned slice is not guaranteed
+ // Check both and return error if both don't match
+ sort.Slice(got, func(i, j int) bool {
+ return got[i].UUID < got[i].UUID
+ })
+ // Sort both as it is not expected that testCase.expected
+ // is sorted
+ sort.Slice(testCase.expected, func(i, j int) bool {
+ return testCase.expected[i].UUID < testCase.expected[i].UUID
+ })
+
if reflect.DeepEqual(testCase.expected, got) == false {
t.Errorf("listHandler returned unexpected body: got %v;"+
" expected %v", got, testCase.expected)
@@ -267,7 +279,7 @@ func TestRBDefGetHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
vh := rbDefinitionHandler{client: testCase.rbDefClient}
- req, err := http.NewRequest("GET", "/v1/resource/definition/"+testCase.inpUUID, nil)
+ req, err := http.NewRequest("GET", "/v1/rb/definition/"+testCase.inpUUID, nil)
if err != nil {
t.Fatal(err)
}
@@ -322,7 +334,7 @@ func TestRBDefDeleteHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
vh := rbDefinitionHandler{client: testCase.rbDefClient}
- req, err := http.NewRequest("GET", "/v1/resource/definition/"+testCase.inpUUID, nil)
+ req, err := http.NewRequest("GET", "/v1/rb/definition/"+testCase.inpUUID, nil)
if err != nil {
t.Fatal(err)
}
@@ -382,7 +394,7 @@ func TestRBDefUploadHandler(t *testing.T) {
t.Run(testCase.label, func(t *testing.T) {
vh := rbDefinitionHandler{client: testCase.rbDefClient}
req, err := http.NewRequest("POST",
- "/v1/resource/definition/"+testCase.inpUUID+"/content", testCase.body)
+ "/v1/rb/definition/"+testCase.inpUUID+"/content", testCase.body)
if err != nil {
t.Fatal(err)
diff --git a/src/k8splugin/api/profilehandler.go b/src/k8splugin/api/profilehandler.go
new file mode 100644
index 00000000..1090efe5
--- /dev/null
+++ b/src/k8splugin/api/profilehandler.go
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package api
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "k8splugin/rb"
+ "net/http"
+
+ "github.com/gorilla/mux"
+)
+
+// Used to store backend implementations objects
+// Also simplifies mocking for unit testing purposes
+type rbProfileHandler struct {
+ // Interface that implements bundle Definition operations
+ // We will set this variable with a mock interface for testing
+ client rb.ProfileManager
+}
+
+// createHandler handles creation of the definition entry in the database
+func (h rbProfileHandler) createHandler(w http.ResponseWriter, r *http.Request) {
+ var v rb.Profile
+
+ if r.Body == nil {
+ http.Error(w, "Empty body", http.StatusBadRequest)
+ return
+ }
+
+ err := json.NewDecoder(r.Body).Decode(&v)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusUnprocessableEntity)
+ return
+ }
+
+ // Name is required.
+ if v.Name == "" {
+ http.Error(w, "Missing name in POST request", http.StatusBadRequest)
+ return
+ }
+
+ // Definition ID is required
+ if v.RBDID == "" {
+ http.Error(w, "Missing Resource Bundle Definition ID in POST request", http.StatusBadRequest)
+ return
+ }
+
+ ret, err := h.client.Create(v)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+ err = json.NewEncoder(w).Encode(ret)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+// uploadHandler handles upload of the bundle tar file into the database
+func (h rbProfileHandler) uploadHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ uuid := vars["rbpID"]
+
+ if r.Body == nil {
+ http.Error(w, "Empty Body", http.StatusBadRequest)
+ return
+ }
+
+ inpBytes, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ http.Error(w, "Unable to read body", http.StatusBadRequest)
+ return
+ }
+
+ err = h.client.Upload(uuid, inpBytes)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.WriteHeader(http.StatusOK)
+}
+
+// listHandler handles GET (list) operations on the endpoint
+// Returns a list of rb.Definitions
+func (h rbProfileHandler) listHandler(w http.ResponseWriter, r *http.Request) {
+ ret, err := h.client.List()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ err = json.NewEncoder(w).Encode(ret)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+// helpHandler handles GET (list) operations on the endpoint
+// Returns a list of rb.Definitions
+func (h rbProfileHandler) helpHandler(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "text/html")
+ w.WriteHeader(http.StatusOK)
+}
+
+// getHandler handles GET operations on a particular ids
+// Returns a rb.Definition
+func (h rbProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ id := vars["rbpID"]
+
+ ret, err := h.client.Get(id)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ err = json.NewEncoder(w).Encode(ret)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+// deleteHandler handles DELETE operations on a particular bundle definition id
+func (h rbProfileHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ id := vars["rbpID"]
+
+ err := h.client.Delete(id)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.WriteHeader(http.StatusNoContent)
+}
diff --git a/src/k8splugin/api/profilehandler_test.go b/src/k8splugin/api/profilehandler_test.go
new file mode 100644
index 00000000..87725882
--- /dev/null
+++ b/src/k8splugin/api/profilehandler_test.go
@@ -0,0 +1,422 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package api
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "k8splugin/rb"
+ "net/http"
+ "net/http/httptest"
+ "reflect"
+ "sort"
+ "testing"
+
+ pkgerrors "github.com/pkg/errors"
+)
+
+//Creating an embedded interface via anonymous variable
+//This allows us to make mockDB satisfy the DatabaseConnection
+//interface even if we are not implementing all the methods in it
+type mockRBProfile struct {
+ rb.ProfileManager
+ // Items and err will be used to customize each test
+ // via a localized instantiation of mockRBProfile
+ Items []rb.Profile
+ Err error
+}
+
+func (m *mockRBProfile) Create(inp rb.Profile) (rb.Profile, error) {
+ if m.Err != nil {
+ return rb.Profile{}, m.Err
+ }
+
+ return m.Items[0], nil
+}
+
+func (m *mockRBProfile) List() ([]rb.Profile, error) {
+ if m.Err != nil {
+ return []rb.Profile{}, m.Err
+ }
+
+ return m.Items, nil
+}
+
+func (m *mockRBProfile) Get(id string) (rb.Profile, error) {
+ if m.Err != nil {
+ return rb.Profile{}, m.Err
+ }
+
+ return m.Items[0], nil
+}
+
+func (m *mockRBProfile) Delete(id string) error {
+ return m.Err
+}
+
+func (m *mockRBProfile) Upload(id string, inp []byte) error {
+ return m.Err
+}
+
+func TestRBProfileCreateHandler(t *testing.T) {
+ testCases := []struct {
+ label string
+ reader io.Reader
+ expected rb.Profile
+ expectedCode int
+ rbDefClient *mockRBProfile
+ }{
+ {
+ label: "Missing Body Failure",
+ expectedCode: http.StatusBadRequest,
+ rbDefClient: &mockRBProfile{},
+ },
+ {
+ label: "Create without UUID",
+ expectedCode: http.StatusCreated,
+ reader: bytes.NewBuffer([]byte(`{
+ "rbdid":"abcde123-e89b-8888-a456-986655447236",
+ "name":"testdomain",
+ "namespace":"default",
+ "kubernetesversion":"1.12.3"
+ }`)),
+ expected: rb.Profile{
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ rbDefClient: &mockRBProfile{
+ //Items that will be returned by the mocked Client
+ Items: []rb.Profile{
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ },
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ vh := rbProfileHandler{client: testCase.rbDefClient}
+ req, err := http.NewRequest("POST", "/v1/rb/profile", testCase.reader)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(vh.createHandler)
+ hr.ServeHTTP(rr, req)
+
+ //Check returned code
+ if rr.Code != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, rr.Code)
+ }
+
+ //Check returned body only if statusCreated
+ if rr.Code == http.StatusCreated {
+ got := rb.Profile{}
+ json.NewDecoder(rr.Body).Decode(&got)
+
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("createHandler returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestRBProfileListHandler(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ expected []rb.Profile
+ expectedCode int
+ rbDefClient *mockRBProfile
+ }{
+ {
+ label: "List Bundle Profiles",
+ expectedCode: http.StatusOK,
+ expected: []rb.Profile{
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655441111",
+ RBDID: "abcde123-e89b-8888-a456-986655441111",
+ Name: "testresourcebundle2",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ },
+ rbDefClient: &mockRBProfile{
+ // list of Profiles that will be returned by the mockclient
+ Items: []rb.Profile{
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655441111",
+ RBDID: "abcde123-e89b-8888-a456-986655441111",
+ Name: "testresourcebundle2",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ },
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ vh := rbProfileHandler{client: testCase.rbDefClient}
+ req, err := http.NewRequest("GET", "/v1/rb/profile", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(vh.listHandler)
+
+ hr.ServeHTTP(rr, req)
+ //Check returned code
+ if rr.Code != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, rr.Code)
+ }
+
+ //Check returned body only if statusOK
+ if rr.Code == http.StatusOK {
+ got := []rb.Profile{}
+ json.NewDecoder(rr.Body).Decode(&got)
+
+ // Since the order of returned slice is not guaranteed
+ // Check both and return error if both don't match
+ sort.Slice(got, func(i, j int) bool {
+ return got[i].UUID < got[i].UUID
+ })
+ // Sort both as it is not expected that testCase.expected
+ // is sorted
+ sort.Slice(testCase.expected, func(i, j int) bool {
+ return testCase.expected[i].UUID < testCase.expected[i].UUID
+ })
+
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("listHandler returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestRBProfileGetHandler(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ expected rb.Profile
+ inpUUID string
+ expectedCode int
+ rbDefClient *mockRBProfile
+ }{
+ {
+ label: "Get Bundle Profile",
+ expectedCode: http.StatusOK,
+ expected: rb.Profile{
+ UUID: "123e4567-e89b-12d3-a456-426655441111",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle2",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ inpUUID: "123e4567-e89b-12d3-a456-426655441111",
+ rbDefClient: &mockRBProfile{
+ // list of Profiles that will be returned by the mockclient
+ Items: []rb.Profile{
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655441111",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle2",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ },
+ },
+ },
+ {
+ label: "Get Non-Exiting Bundle Profile",
+ expectedCode: http.StatusInternalServerError,
+ inpUUID: "123e4567-e89b-12d3-a456-426655440000",
+ rbDefClient: &mockRBProfile{
+ // list of Profiles that will be returned by the mockclient
+ Items: []rb.Profile{},
+ Err: pkgerrors.New("Internal Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ vh := rbProfileHandler{client: testCase.rbDefClient}
+ req, err := http.NewRequest("GET", "/v1/rb/profile/"+testCase.inpUUID, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(vh.getHandler)
+
+ hr.ServeHTTP(rr, req)
+ //Check returned code
+ if rr.Code != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, rr.Code)
+ }
+
+ //Check returned body only if statusOK
+ if rr.Code == http.StatusOK {
+ got := rb.Profile{}
+ json.NewDecoder(rr.Body).Decode(&got)
+
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("listHandler returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestRBProfileDeleteHandler(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ inpUUID string
+ expectedCode int
+ rbDefClient *mockRBProfile
+ }{
+ {
+ label: "Delete Bundle Profile",
+ expectedCode: http.StatusNoContent,
+ inpUUID: "123e4567-e89b-12d3-a456-426655441111",
+ rbDefClient: &mockRBProfile{},
+ },
+ {
+ label: "Delete Non-Exiting Bundle Profile",
+ expectedCode: http.StatusInternalServerError,
+ inpUUID: "123e4567-e89b-12d3-a456-426655440000",
+ rbDefClient: &mockRBProfile{
+ Err: pkgerrors.New("Internal Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ vh := rbProfileHandler{client: testCase.rbDefClient}
+ req, err := http.NewRequest("GET", "/v1/rb/profile/"+testCase.inpUUID, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(vh.deleteHandler)
+
+ hr.ServeHTTP(rr, req)
+ //Check returned code
+ if rr.Code != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, rr.Code)
+ }
+ })
+ }
+}
+
+func TestRBProfileUploadHandler(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ inpUUID string
+ body io.Reader
+ expectedCode int
+ rbDefClient *mockRBProfile
+ }{
+ {
+ label: "Upload Bundle Profile Content",
+ expectedCode: http.StatusOK,
+ inpUUID: "123e4567-e89b-12d3-a456-426655441111",
+ body: bytes.NewBuffer([]byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xf2, 0x48, 0xcd,
+ }),
+ rbDefClient: &mockRBProfile{},
+ },
+ {
+ label: "Upload Invalid Bundle Profile Content",
+ expectedCode: http.StatusInternalServerError,
+ inpUUID: "123e4567-e89b-12d3-a456-426655440000",
+ body: bytes.NewBuffer([]byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xf2, 0x48, 0xcd,
+ }),
+ rbDefClient: &mockRBProfile{
+ Err: pkgerrors.New("Internal Error"),
+ },
+ },
+ {
+ label: "Upload Empty Body Content",
+ expectedCode: http.StatusBadRequest,
+ inpUUID: "123e4567-e89b-12d3-a456-426655440000",
+ rbDefClient: &mockRBProfile{},
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ vh := rbProfileHandler{client: testCase.rbDefClient}
+ req, err := http.NewRequest("POST",
+ "/v1/rb/profile/"+testCase.inpUUID+"/content", testCase.body)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ hr := http.HandlerFunc(vh.uploadHandler)
+
+ hr.ServeHTTP(rr, req)
+ //Check returned code
+ if rr.Code != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, rr.Code)
+ }
+ })
+ }
+}
diff --git a/src/k8splugin/db/mongo.go b/src/k8splugin/db/mongo.go
index 311f044c..05976b12 100644
--- a/src/k8splugin/db/mongo.go
+++ b/src/k8splugin/db/mongo.go
@@ -183,7 +183,13 @@ func (m *MongoStore) Read(coll, key, tag string) ([]byte, error) {
}
//Return the data as a byte array
- return tagdata.Lookup(tag).Value, nil
+ //Convert string data to byte array using the built-in functions
+ switch tagdata.Lookup(tag).Type {
+ case bson.TypeString:
+ return []byte(tagdata.Lookup(tag).StringValue()), nil
+ default:
+ return tagdata.Lookup(tag).Value, nil
+ }
}
// Helper function that deletes an object by its ID
@@ -224,6 +230,11 @@ func (m *MongoStore) Delete(coll, key, tag string) error {
keydata, err := decodeBytes(c.FindOneAndUpdate(ctx, filter, update,
options.FindOneAndUpdate().SetReturnDocument(options.Before)))
if err != nil {
+ //No document was found. Return nil.
+ if err == mongo.ErrNoDocuments {
+ return nil
+ }
+ //Return any other error that was found.
return pkgerrors.Errorf("Error decoding master table after update: %s",
err.Error())
}
diff --git a/src/k8splugin/go.mod b/src/k8splugin/go.mod
index 2ac70782..c6d2ef23 100644
--- a/src/k8splugin/go.mod
+++ b/src/k8splugin/go.mod
@@ -27,7 +27,7 @@ require (
github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v0.0.0-20180228065516-1df9eeb2bb81 // indirect
- github.com/mongodb/mongo-go-driver v0.1.0
+ github.com/mongodb/mongo-go-driver v0.2.0
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.8.0
github.com/pmezard/go-difflib v1.0.0 // indirect
diff --git a/src/k8splugin/go.sum b/src/k8splugin/go.sum
index 18b85c91..dbc0a60a 100644
--- a/src/k8splugin/go.sum
+++ b/src/k8splugin/go.sum
@@ -52,8 +52,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180228065516-1df9eeb2bb81 h1:ImOHKpmdLPXWX5KSYquUWXKaopEPuY7TPPUo18u9aOI=
github.com/modern-go/reflect2 v0.0.0-20180228065516-1df9eeb2bb81/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/mongodb/mongo-go-driver v0.1.0 h1:LcpPFw0tNumIAakvNrkI9S9wdX0iOxvMLw/+hcAdHaU=
-github.com/mongodb/mongo-go-driver v0.1.0/go.mod h1:NK/HWDIIZkaYsnYa0hmtP443T5ELr0KDecmIioVuuyU=
+github.com/mongodb/mongo-go-driver v0.2.0 h1:MBI/hnb0LiACJRVAlT+nL5wdtV4EFKTjJEhQdapZFB0=
+github.com/mongodb/mongo-go-driver v0.2.0/go.mod h1:NK/HWDIIZkaYsnYa0hmtP443T5ELr0KDecmIioVuuyU=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
diff --git a/src/k8splugin/mock_files/mock_json/create_rbdefinition.json b/src/k8splugin/mock_files/mock_json/create_rbdefinition.json
new file mode 100644
index 00000000..994afdf8
--- /dev/null
+++ b/src/k8splugin/mock_files/mock_json/create_rbdefinition.json
@@ -0,0 +1,6 @@
+{
+ "name": "test-rbdef",
+ "description": "testing resource bundle definition api",
+ "uuid": "7eb09e38-4363-9942-1234-3beb2e95fd85",
+ "service-type": "firewall"
+} \ No newline at end of file
diff --git a/src/k8splugin/mock_files/mock_json/create_rbprofile.json b/src/k8splugin/mock_files/mock_json/create_rbprofile.json
new file mode 100644
index 00000000..5d439cf0
--- /dev/null
+++ b/src/k8splugin/mock_files/mock_json/create_rbprofile.json
@@ -0,0 +1,7 @@
+{
+ "name": "test-rbprofile",
+ "description": "testing resource bundle profile api",
+ "rbdid": "7eb09e38-4363-9942-1234-3beb2e95fd85",
+ "uuid": "12345678-8888-4578-3344-987654398731",
+ "service-type": "firewall"
+}
diff --git a/src/k8splugin/mock_files/mock_json/create_vnfd.json b/src/k8splugin/mock_files/mock_json/create_vnfd.json
deleted file mode 100644
index 64a186b2..00000000
--- a/src/k8splugin/mock_files/mock_json/create_vnfd.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "test-vnfd",
- "description": "testing vnfd creation api",
- "uuid": "",
- "service-type": "firewall"
-} \ No newline at end of file
diff --git a/src/k8splugin/rb/definition.go b/src/k8splugin/rb/definition.go
index 02ecc5ae..eb7a12fc 100644
--- a/src/k8splugin/rb/definition.go
+++ b/src/k8splugin/rb/definition.go
@@ -29,9 +29,9 @@ import (
// Definition contains the parameters needed for resource bundle (rb) definitions
// It implements the interface for managing the definitions
type Definition struct {
+ UUID string `json:"uuid,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
- UUID string `json:"uuid,omitempty"`
ServiceType string `json:"service-type"`
}
@@ -87,11 +87,12 @@ func (v *DefinitionClient) List() ([]Definition, error) {
var results []Definition
for key, value := range res {
+ //value is a byte array
if len(value) > 0 {
def := Definition{}
err = db.DBconn.Unmarshal(value, &def)
if err != nil {
- log.Printf("Error Unmarshaling value for: %s", key)
+ log.Printf("[Definition] Error Unmarshaling value for: %s", key)
continue
}
results = append(results, def)
@@ -108,6 +109,7 @@ func (v *DefinitionClient) Get(id string) (Definition, error) {
return Definition{}, pkgerrors.Wrap(err, "Get Resource Bundle definition")
}
+ //value is a byte array
if value != nil {
def := Definition{}
err = db.DBconn.Unmarshal(value, &def)
@@ -124,7 +126,7 @@ func (v *DefinitionClient) Get(id string) (Definition, error) {
func (v *DefinitionClient) Delete(id string) error {
err := db.DBconn.Delete(v.storeName, id, v.tagMeta)
if err != nil {
- return pkgerrors.Wrap(err, "Delete Resource Bundle Definitions")
+ return pkgerrors.Wrap(err, "Delete Resource Bundle Definition")
}
return nil
@@ -136,7 +138,7 @@ func (v *DefinitionClient) Upload(id string, inp []byte) error {
//ignore the returned data here
_, err := v.Get(id)
if err != nil {
- return pkgerrors.Errorf("Invalid ID provided: %s", err.Error())
+ return pkgerrors.Errorf("Invalid Definition ID provided: %s", err.Error())
}
err = isTarGz(bytes.NewBuffer(inp))
@@ -146,7 +148,7 @@ func (v *DefinitionClient) Upload(id string, inp []byte) error {
//Encode given byte stream to text for storage
encodedStr := base64.StdEncoding.EncodeToString(inp)
- err = db.DBconn.Create(v.storeName, id, encodedStr, v.tagContent)
+ err = db.DBconn.Create(v.storeName, id, v.tagContent, encodedStr)
if err != nil {
return pkgerrors.Errorf("Error uploading data to db: %s", err.Error())
}
diff --git a/src/k8splugin/rb/definition_test.go b/src/k8splugin/rb/definition_test.go
index 1e488678..6074f8b3 100644
--- a/src/k8splugin/rb/definition_test.go
+++ b/src/k8splugin/rb/definition_test.go
@@ -21,13 +21,14 @@ package rb
import (
"k8splugin/db"
"reflect"
+ "sort"
"strings"
"testing"
pkgerrors "github.com/pkg/errors"
)
-func TestCreate(t *testing.T) {
+func TestCreateDefinition(t *testing.T) {
testCases := []struct {
label string
inp Definition
@@ -83,7 +84,7 @@ func TestCreate(t *testing.T) {
}
}
-func TestList(t *testing.T) {
+func TestListDefinition(t *testing.T) {
testCases := []struct {
label string
@@ -145,6 +146,17 @@ func TestList(t *testing.T) {
t.Fatalf("List returned an unexpected error %s", err)
}
} else {
+ // Since the order of returned slice is not guaranteed
+ // Check both and return error if both don't match
+ sort.Slice(got, func(i, j int) bool {
+ return got[i].UUID < got[i].UUID
+ })
+ // Sort both as it is not expected that testCase.expected
+ // is sorted
+ sort.Slice(testCase.expected, func(i, j int) bool {
+ return testCase.expected[i].UUID < testCase.expected[i].UUID
+ })
+
if reflect.DeepEqual(testCase.expected, got) == false {
t.Errorf("List Resource Bundle returned unexpected body: got %v;"+
" expected %v", got, testCase.expected)
@@ -154,7 +166,7 @@ func TestList(t *testing.T) {
}
}
-func TestGet(t *testing.T) {
+func TestGetDefinition(t *testing.T) {
testCases := []struct {
label string
@@ -214,7 +226,7 @@ func TestGet(t *testing.T) {
}
}
-func TestDelete(t *testing.T) {
+func TestDeleteDefinition(t *testing.T) {
testCases := []struct {
label string
@@ -253,7 +265,7 @@ func TestDelete(t *testing.T) {
}
}
-func TestUpload(t *testing.T) {
+func TestUploadDefinition(t *testing.T) {
testCases := []struct {
label string
inp string
@@ -298,7 +310,7 @@ func TestUpload(t *testing.T) {
{
label: "Upload with an Invalid Resource Bundle Definition",
inp: "123e4567-e89b-12d3-a456-426655440000",
- expectedError: "Invalid ID provided",
+ expectedError: "Invalid Definition ID provided",
content: []byte{
0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b,
0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74,
@@ -325,7 +337,7 @@ func TestUpload(t *testing.T) {
"123e4567-e89b-12d3-a456-426655441111": []byte(
"{\"name\":\"testresourcebundle\"," +
"\"description\":\"testresourcebundle\"," +
- "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," +
+ "\"uuid\":\"123e4567-e89b-12d3-a456-426655441111\"," +
"\"service-type\":\"firewall\"}"),
},
},
diff --git a/src/k8splugin/rb/profile.go b/src/k8splugin/rb/profile.go
new file mode 100644
index 00000000..bbd43fea
--- /dev/null
+++ b/src/k8splugin/rb/profile.go
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rb
+
+import (
+ "bytes"
+ "encoding/base64"
+ "k8splugin/db"
+ "log"
+
+ uuid "github.com/hashicorp/go-uuid"
+ pkgerrors "github.com/pkg/errors"
+)
+
+// Profile contains the parameters needed for resource bundle (rb) profiles
+// It implements the interface for managing the profiles
+type Profile struct {
+ UUID string `json:"uuid,omitempty"`
+ RBDID string `json:"rbdid"`
+ Name string `json:"name"`
+ Namespace string `json:"namespace"`
+ KubernetesVersion string `json:"kubernetesversion"`
+}
+
+// ProfileManager is an interface exposes the resource bundle profile functionality
+type ProfileManager interface {
+ Create(def Profile) (Profile, error)
+ List() ([]Profile, error)
+ Get(resID string) (Profile, error)
+ Help() map[string]string
+ Delete(resID string) error
+ Upload(resID string, inp []byte) error
+}
+
+// ProfileClient implements the ProfileManager
+// It will also be used to maintain some localized state
+type ProfileClient struct {
+ storeName string
+ tagMeta, tagContent string
+}
+
+// NewProfileClient returns an instance of the ProfileClient
+// which implements the ProfileManager
+// Uses rb/def prefix
+func NewProfileClient() *ProfileClient {
+ return &ProfileClient{
+ storeName: "rbprofile",
+ tagMeta: "metadata",
+ tagContent: "content",
+ }
+}
+
+// Help returns some information on how to create the content
+// for the profile in the form of html formatted page
+func (v *ProfileClient) Help() map[string]string {
+ ret := make(map[string]string)
+
+ return ret
+}
+
+// Create an entry for the resource bundle profile in the database
+func (v *ProfileClient) Create(p Profile) (Profile, error) {
+
+ //Check if provided RBID is a valid resource bundle
+ _, err := NewDefinitionClient().Get(p.RBDID)
+ if err != nil {
+ return Profile{}, pkgerrors.Errorf("Invalid Resource Bundle ID provided: %s", err.Error())
+ }
+
+ // Name is required
+ if p.Name == "" {
+ return Profile{}, pkgerrors.New("Name is required for Resource Bundle Profile")
+ }
+
+ // If UUID is empty, we will generate one
+ if p.UUID == "" {
+ p.UUID, _ = uuid.GenerateUUID()
+ }
+ key := p.UUID
+
+ err = db.DBconn.Create(v.storeName, key, v.tagMeta, p)
+ if err != nil {
+ return Profile{}, pkgerrors.Wrap(err, "Creating Profile DB Entry")
+ }
+
+ return p, nil
+}
+
+// List all resource entries in the database
+func (v *ProfileClient) List() ([]Profile, error) {
+ res, err := db.DBconn.ReadAll(v.storeName, v.tagMeta)
+ if err != nil || len(res) == 0 {
+ return []Profile{}, pkgerrors.Wrap(err, "Listing Resource Bundle Profiles")
+ }
+
+ var retData []Profile
+
+ for key, value := range res {
+ //value is a byte array
+ if len(value) > 0 {
+ pr := Profile{}
+ err = db.DBconn.Unmarshal(value, &pr)
+ if err != nil {
+ log.Printf("[Profile] Error Unmarshaling value for: %s", key)
+ continue
+ }
+ retData = append(retData, pr)
+ }
+ }
+
+ return retData, nil
+}
+
+// Get returns the Resource Bundle Profile for corresponding ID
+func (v *ProfileClient) Get(id string) (Profile, error) {
+ value, err := db.DBconn.Read(v.storeName, id, v.tagMeta)
+ if err != nil {
+ return Profile{}, pkgerrors.Wrap(err, "Get Resource Bundle Profile")
+ }
+
+ //value is a byte array
+ if value != nil {
+ pr := Profile{}
+ err = db.DBconn.Unmarshal(value, &pr)
+ if err != nil {
+ return Profile{}, pkgerrors.Wrap(err, "Unmarshaling Profile Value")
+ }
+ return pr, nil
+ }
+
+ return Profile{}, pkgerrors.New("Error getting Resource Bundle Profile")
+}
+
+// Delete the Resource Bundle Profile from database
+func (v *ProfileClient) Delete(id string) error {
+ err := db.DBconn.Delete(v.storeName, id, v.tagMeta)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Delete Resource Bundle Profile")
+ }
+
+ err = db.DBconn.Delete(v.storeName, id, v.tagContent)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Delete Resource Bundle Profile Content")
+ }
+
+ return nil
+}
+
+// Upload the contents of resource bundle into database
+func (v *ProfileClient) Upload(id string, inp []byte) error {
+
+ //ignore the returned data here.
+ _, err := v.Get(id)
+ if err != nil {
+ return pkgerrors.Errorf("Invalid Profile ID provided %s", err.Error())
+ }
+
+ err = isTarGz(bytes.NewBuffer(inp))
+ if err != nil {
+ return pkgerrors.Errorf("Error in file format %s", err.Error())
+ }
+
+ //Encode given byte stream to text for storage
+ encodedStr := base64.StdEncoding.EncodeToString(inp)
+ err = db.DBconn.Create(v.storeName, id, v.tagContent, encodedStr)
+ if err != nil {
+ return pkgerrors.Errorf("Error uploading data to db %s", err.Error())
+ }
+
+ return nil
+}
diff --git a/src/k8splugin/rb/profile_test.go b/src/k8splugin/rb/profile_test.go
new file mode 100644
index 00000000..a760830b
--- /dev/null
+++ b/src/k8splugin/rb/profile_test.go
@@ -0,0 +1,414 @@
+// +build unit
+
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rb
+
+import (
+ "k8splugin/db"
+ "reflect"
+ "sort"
+ "strings"
+ "testing"
+
+ pkgerrors "github.com/pkg/errors"
+)
+
+func TestCreateProfile(t *testing.T) {
+ testCases := []struct {
+ label string
+ inp Profile
+ expectedError string
+ mockdb *db.MockDB
+ expected Profile
+ }{
+ {
+ label: "Create Resource Bundle Profile",
+ inp: Profile{
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ expected: Profile{
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ expectedError: "",
+ mockdb: &db.MockDB{
+ Items: map[string][]byte{
+ "abcde123-e89b-8888-a456-986655447236": []byte(
+ "{\"name\":\"testresourcebundle\"," +
+ "\"namespace\":\"default\"," +
+ "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," +
+ "\"kubernetesversion\":\"1.12.3\"}"),
+ },
+ },
+ },
+ {
+ label: "Failed Create Resource Bundle Profile",
+ expectedError: "Error Creating Profile",
+ mockdb: &db.MockDB{
+ Err: pkgerrors.New("Error Creating Profile"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ impl := NewProfileClient()
+ got, err := impl.Create(testCase.inp)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("Create returned an unexpected error %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("Create returned an unexpected error %s", err)
+ }
+ } else {
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("Create Resource Bundle returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestListProfiles(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ expectedError string
+ mockdb *db.MockDB
+ expected []Profile
+ }{
+ {
+ label: "List Resource Bundle Profile",
+ expected: []Profile{
+ {
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ },
+ expectedError: "",
+ mockdb: &db.MockDB{
+ Items: map[string][]byte{
+ "123e4567-e89b-12d3-a456-426655440000": []byte(
+ "{\"name\":\"testresourcebundle\"," +
+ "\"namespace\":\"default\"," +
+ "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," +
+ "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," +
+ "\"kubernetesversion\":\"1.12.3\"}"),
+ },
+ },
+ },
+ {
+ label: "List Error",
+ expectedError: "DB Error",
+ mockdb: &db.MockDB{
+ Err: pkgerrors.New("DB Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ impl := NewProfileClient()
+ got, err := impl.List()
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("List returned an unexpected error %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("List returned an unexpected error %s", err)
+ }
+ } else {
+ // Since the order of returned slice is not guaranteed
+ // Check both and return error if both don't match
+ sort.Slice(got, func(i, j int) bool {
+ return got[i].UUID < got[i].UUID
+ })
+ // Sort both as it is not expected that testCase.expected
+ // is sorted
+ sort.Slice(testCase.expected, func(i, j int) bool {
+ return testCase.expected[i].UUID < testCase.expected[i].UUID
+ })
+
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("List Resource Bundle returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestGetProfile(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ expectedError string
+ mockdb *db.MockDB
+ inp string
+ expected Profile
+ }{
+ {
+ label: "Get Resource Bundle Profile",
+ inp: "123e4567-e89b-12d3-a456-426655440000",
+ expected: Profile{
+ UUID: "123e4567-e89b-12d3-a456-426655440000",
+ RBDID: "abcde123-e89b-8888-a456-986655447236",
+ Name: "testresourcebundle",
+ Namespace: "default",
+ KubernetesVersion: "1.12.3",
+ },
+ expectedError: "",
+ mockdb: &db.MockDB{
+ Items: map[string][]byte{
+ "123e4567-e89b-12d3-a456-426655440000": []byte(
+ "{\"name\":\"testresourcebundle\"," +
+ "\"namespace\":\"default\"," +
+ "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," +
+ "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," +
+ "\"kubernetesversion\":\"1.12.3\"}"),
+ },
+ },
+ },
+ {
+ label: "Get Error",
+ expectedError: "DB Error",
+ mockdb: &db.MockDB{
+ Err: pkgerrors.New("DB Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ impl := NewProfileClient()
+ got, err := impl.Get(testCase.inp)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("Get returned an unexpected error %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("Get returned an unexpected error %s", err)
+ }
+ } else {
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("Get Resource Bundle returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestDeleteProfile(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ inp string
+ expectedError string
+ mockdb *db.MockDB
+ }{
+ {
+ label: "Delete Resource Bundle Profile",
+ inp: "123e4567-e89b-12d3-a456-426655440000",
+ mockdb: &db.MockDB{},
+ },
+ {
+ label: "Delete Error",
+ expectedError: "DB Error",
+ mockdb: &db.MockDB{
+ Err: pkgerrors.New("DB Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ impl := NewProfileClient()
+ err := impl.Delete(testCase.inp)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("Delete returned an unexpected error %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("Delete returned an unexpected error %s", err)
+ }
+ }
+ })
+ }
+}
+
+func TestUploadProfile(t *testing.T) {
+ testCases := []struct {
+ label string
+ inp string
+ content []byte
+ expectedError string
+ mockdb *db.MockDB
+ }{
+ {
+ label: "Upload Resource Bundle Profile",
+ inp: "123e4567-e89b-12d3-a456-426655440000",
+ content: []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b,
+ 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74,
+ 0x61, 0x72, 0x00, 0xed, 0xce, 0x41, 0x0a, 0xc2,
+ 0x30, 0x10, 0x85, 0xe1, 0xac, 0x3d, 0x45, 0x4e,
+ 0x50, 0x12, 0xd2, 0xc4, 0xe3, 0x48, 0xa0, 0x01,
+ 0x4b, 0x52, 0x0b, 0xed, 0x88, 0x1e, 0xdf, 0x48,
+ 0x11, 0x5c, 0x08, 0xa5, 0x8b, 0x52, 0x84, 0xff,
+ 0xdb, 0xbc, 0x61, 0x66, 0x16, 0x4f, 0xd2, 0x2c,
+ 0x8d, 0x3c, 0x45, 0xed, 0xc8, 0x54, 0x21, 0xb4,
+ 0xef, 0xb4, 0x67, 0x6f, 0xbe, 0x73, 0x61, 0x9d,
+ 0xb2, 0xce, 0xd5, 0x55, 0xf0, 0xde, 0xd7, 0x3f,
+ 0xdb, 0xd6, 0x49, 0x69, 0xb3, 0x67, 0xa9, 0x8f,
+ 0xfb, 0x2c, 0x71, 0xd2, 0x5a, 0xc5, 0xee, 0x92,
+ 0x73, 0x8e, 0x43, 0x7f, 0x4b, 0x3f, 0xff, 0xd6,
+ 0xee, 0x7f, 0xea, 0x9a, 0x4a, 0x19, 0x1f, 0xe3,
+ 0x54, 0xba, 0xd3, 0xd1, 0x55, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0xbc, 0x00, 0xb5, 0xe8,
+ 0x4a, 0xf9, 0x00, 0x28, 0x00, 0x00,
+ },
+ mockdb: &db.MockDB{
+ Items: map[string][]byte{
+ "123e4567-e89b-12d3-a456-426655440000": []byte(
+ "{\"name\":\"testresourcebundle\"," +
+ "\"namespace\":\"default\"," +
+ "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," +
+ "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," +
+ "\"kubernetesversion\":\"1.12.3\"}"),
+ },
+ },
+ },
+ {
+ label: "Upload with an Invalid Resource Bundle Profile",
+ inp: "123e4567-e89b-12d3-a456-426655440000",
+ expectedError: "Invalid Profile ID provided",
+ content: []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b,
+ 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74,
+ 0x61, 0x72, 0x00, 0xed, 0xce, 0x41, 0x0a, 0xc2,
+ 0x30, 0x10, 0x85, 0xe1, 0xac, 0x3d, 0x45, 0x4e,
+ 0x50, 0x12, 0xd2, 0xc4, 0xe3, 0x48, 0xa0, 0x01,
+ 0x4b, 0x52, 0x0b, 0xed, 0x88, 0x1e, 0xdf, 0x48,
+ 0x11, 0x5c, 0x08, 0xa5, 0x8b, 0x52, 0x84, 0xff,
+ 0xdb, 0xbc, 0x61, 0x66, 0x16, 0x4f, 0xd2, 0x2c,
+ 0x8d, 0x3c, 0x45, 0xed, 0xc8, 0x54, 0x21, 0xb4,
+ 0xef, 0xb4, 0x67, 0x6f, 0xbe, 0x73, 0x61, 0x9d,
+ 0xb2, 0xce, 0xd5, 0x55, 0xf0, 0xde, 0xd7, 0x3f,
+ 0xdb, 0xd6, 0x49, 0x69, 0xb3, 0x67, 0xa9, 0x8f,
+ 0xfb, 0x2c, 0x71, 0xd2, 0x5a, 0xc5, 0xee, 0x92,
+ 0x73, 0x8e, 0x43, 0x7f, 0x4b, 0x3f, 0xff, 0xd6,
+ 0xee, 0x7f, 0xea, 0x9a, 0x4a, 0x19, 0x1f, 0xe3,
+ 0x54, 0xba, 0xd3, 0xd1, 0x55, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0xbc, 0x00, 0xb5, 0xe8,
+ 0x4a, 0xf9, 0x00, 0x28, 0x00, 0x00,
+ },
+ mockdb: &db.MockDB{
+ Items: map[string][]byte{
+ "123e4567-e89b-12d3-a456-426655441111": []byte(
+ "{\"name\":\"testresourcebundle\"," +
+ "\"namespace\":\"default\"," +
+ "\"uuid\":\"123e4567-e89b-12d3-a456-426655441111\"," +
+ "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," +
+ "\"kubernetesversion\":\"1.12.3\"}"),
+ },
+ },
+ },
+ {
+ label: "Invalid File Format Error",
+ inp: "123e4567-e89b-12d3-a456-426655440000",
+ expectedError: "Error in file format",
+ content: []byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xf2, 0x48, 0xcd,
+ },
+ mockdb: &db.MockDB{
+ Items: map[string][]byte{
+ "123e4567-e89b-12d3-a456-426655440000": []byte(
+ "{\"name\":\"testresourcebundle\"," +
+ "\"namespace\":\"default\"," +
+ "\"uuid\":\"123e4567-e89b-12d3-a456-426655440000\"," +
+ "\"rbdid\":\"abcde123-e89b-8888-a456-986655447236\"," +
+ "\"kubernetesversion\":\"1.12.3\"}"),
+ },
+ },
+ },
+ {
+ label: "Upload Error",
+ expectedError: "DB Error",
+ content: []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b,
+ 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74,
+ 0x61, 0x72, 0x00, 0xed, 0xce, 0x41, 0x0a, 0xc2,
+ 0x30, 0x10, 0x85, 0xe1, 0xac, 0x3d, 0x45, 0x4e,
+ 0x50, 0x12, 0xd2, 0xc4, 0xe3, 0x48, 0xa0, 0x01,
+ 0x4b, 0x52, 0x0b, 0xed, 0x88, 0x1e, 0xdf, 0x48,
+ 0x11, 0x5c, 0x08, 0xa5, 0x8b, 0x52, 0x84, 0xff,
+ 0xdb, 0xbc, 0x61, 0x66, 0x16, 0x4f, 0xd2, 0x2c,
+ 0x8d, 0x3c, 0x45, 0xed, 0xc8, 0x54, 0x21, 0xb4,
+ 0xef, 0xb4, 0x67, 0x6f, 0xbe, 0x73, 0x61, 0x9d,
+ 0xb2, 0xce, 0xd5, 0x55, 0xf0, 0xde, 0xd7, 0x3f,
+ 0xdb, 0xd6, 0x49, 0x69, 0xb3, 0x67, 0xa9, 0x8f,
+ 0xfb, 0x2c, 0x71, 0xd2, 0x5a, 0xc5, 0xee, 0x92,
+ 0x73, 0x8e, 0x43, 0x7f, 0x4b, 0x3f, 0xff, 0xd6,
+ 0xee, 0x7f, 0xea, 0x9a, 0x4a, 0x19, 0x1f, 0xe3,
+ 0x54, 0xba, 0xd3, 0xd1, 0x55, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0xbc, 0x00, 0xb5, 0xe8,
+ 0x4a, 0xf9, 0x00, 0x28, 0x00, 0x00,
+ },
+ mockdb: &db.MockDB{
+ Err: pkgerrors.New("DB Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ impl := NewProfileClient()
+ err := impl.Upload(testCase.inp, testCase.content)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Errorf("Upload returned an unexpected error %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Errorf("Upload returned an unexpected error %s", err)
+ }
+ }
+ })
+ }
+}