diff options
author | 2019-11-19 11:51:46 -0800 | |
---|---|---|
committer | 2019-11-19 16:10:31 -0800 | |
commit | 432cee9b36a87f63e787fe4465ec385aa750e172 (patch) | |
tree | 7ebcaa63f7e629e25602bccb041f26079c2f6f0b /src/orchestrator/internal/project | |
parent | c58a35989f731a0d1c8ec75e85480873da4b1c35 (diff) |
Add v2 with project API
Definiton, Profile and other APIs will
migrate to this area with support for Projects and v2.
This patch adds the Project API only along with
support for the Mongo database.
Migration of other APIs will happen in future patches
Issue-ID: MULTICLOUD-871
Change-Id: I2eb2d0db2384fd58d1ec874e24fa9125a1f5b288
Signed-off-by: Kiran Kamineni <kiran.k.kamineni@intel.com>
Diffstat (limited to 'src/orchestrator/internal/project')
-rw-r--r-- | src/orchestrator/internal/project/project.go | 133 | ||||
-rw-r--r-- | src/orchestrator/internal/project/project_test.go | 177 |
2 files changed, 310 insertions, 0 deletions
diff --git a/src/orchestrator/internal/project/project.go b/src/orchestrator/internal/project/project.go new file mode 100644 index 00000000..f0c50065 --- /dev/null +++ b/src/orchestrator/internal/project/project.go @@ -0,0 +1,133 @@ +/* + * Copyright 2019 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 project + +import ( + "encoding/json" + + "github.com/onap/multicloud-k8s/src/orchestrator/internal/db" + + pkgerrors "github.com/pkg/errors" +) + +// Project contains the parameters needed for Projects +// It implements the interface for managing the Projects +type Project struct { + ProjectName string `json:"project-name"` + Description string `json:"description"` +} + +// ProjectKey is the key structure that is used in the database +type ProjectKey struct { + ProjectName string `json:"rb-name"` +} + +// We will use json marshalling to convert to string to +// preserve the underlying structure. +func (pk ProjectKey) String() string { + out, err := json.Marshal(pk) + if err != nil { + return "" + } + + return string(out) +} + +// ProjectManager is an interface exposes the Project functionality +type ProjectManager interface { + Create(pr Project) (Project, error) + Get(name string) (Project, error) + Delete(name string) error +} + +// ProjectClient implements the ProjectManager +// It will also be used to maintain some localized state +type ProjectClient struct { + storeName string + tagMeta, tagContent string +} + +// NewProjectClient returns an instance of the ProjectClient +// which implements the ProjectManager +func NewProjectClient() *ProjectClient { + return &ProjectClient{ + tagMeta: "projectmetadata", + } +} + +// Create a new collection based on the project +func (v *ProjectClient) Create(p Project) (Project, error) { + + //Construct the composite key to select the entry + key := ProjectKey{ + ProjectName: p.ProjectName, + } + + //Check if this Project already exists + _, err := v.Get(p.ProjectName) + if err == nil { + return Project{}, pkgerrors.New("Project already exists") + } + + err = db.DBconn.Create(p.ProjectName, key, v.tagMeta, p) + if err != nil { + return Project{}, pkgerrors.Wrap(err, "Creating DB Entry") + } + + return p, nil +} + +// Get returns the Project for corresponding name +func (v *ProjectClient) Get(name string) (Project, error) { + + //Construct the composite key to select the entry + key := ProjectKey{ + ProjectName: name, + } + value, err := db.DBconn.Read(name, key, v.tagMeta) + if err != nil { + return Project{}, pkgerrors.Wrap(err, "Get Project") + } + + //value is a byte array + if value != nil { + proj := Project{} + err = db.DBconn.Unmarshal(value, &proj) + if err != nil { + return Project{}, pkgerrors.Wrap(err, "Unmarshaling Value") + } + return proj, nil + } + + return Project{}, pkgerrors.New("Error getting Project") +} + +// Delete the Project from database +func (v *ProjectClient) Delete(name string) error { + + //Construct the composite key to select the entry + key := ProjectKey{ + ProjectName: name, + } + err := db.DBconn.Delete(name, key, v.tagMeta) + if err != nil { + return pkgerrors.Wrap(err, "Delete Project Entry;") + } + + //TODO: Delete the collection when the project is deleted + return nil +} diff --git a/src/orchestrator/internal/project/project_test.go b/src/orchestrator/internal/project/project_test.go new file mode 100644 index 00000000..cc691e33 --- /dev/null +++ b/src/orchestrator/internal/project/project_test.go @@ -0,0 +1,177 @@ +/* + * 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 project + +import ( + "reflect" + "strings" + "testing" + + "github.com/onap/multicloud-k8s/src/orchestrator/internal/db" + + pkgerrors "github.com/pkg/errors" +) + +func TestCreateProject(t *testing.T) { + testCases := []struct { + label string + inp Project + expectedError string + mockdb *db.MockDB + expected Project + }{ + { + label: "Create Project", + inp: Project{ + ProjectName: "testProject", + Description: "A sample Project used for unit testing", + }, + expected: Project{ + ProjectName: "testProject", + Description: "A sample Project used for unit testing", + }, + expectedError: "", + mockdb: &db.MockDB{}, + }, + { + label: "Failed Create Project", + expectedError: "Error Creating Project", + mockdb: &db.MockDB{ + Err: pkgerrors.New("Error Creating Project"), + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + db.DBconn = testCase.mockdb + impl := NewProjectClient() + 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 returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestGetProject(t *testing.T) { + + testCases := []struct { + label string + name string + expectedError string + mockdb *db.MockDB + inp string + expected Project + }{ + { + label: "Get Project", + name: "testProject", + expected: Project{ + ProjectName: "testProject", + Description: "Test project for unit testing", + }, + expectedError: "", + mockdb: &db.MockDB{ + Items: map[string]map[string][]byte{ + ProjectKey{ProjectName: "testProject"}.String(): { + "projectmetadata": []byte( + "{\"project-name\":\"testProject\"," + + "\"description\":\"Test project for unit testing\"}"), + }, + }, + }, + }, + { + 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 := NewProjectClient() + got, err := impl.Get(testCase.name) + 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 returned unexpected body: got %v;"+ + " expected %v", got, testCase.expected) + } + } + }) + } +} + +func TestDeleteProject(t *testing.T) { + + testCases := []struct { + label string + name string + expectedError string + mockdb *db.MockDB + }{ + { + label: "Delete Project", + name: "testProject", + 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 := NewProjectClient() + err := impl.Delete(testCase.name) + 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) + } + } + }) + } +} |