diff options
Diffstat (limited to 'src/orchestrator/internal/db/mongo_test.go')
-rw-r--r-- | src/orchestrator/internal/db/mongo_test.go | 597 |
1 files changed, 597 insertions, 0 deletions
diff --git a/src/orchestrator/internal/db/mongo_test.go b/src/orchestrator/internal/db/mongo_test.go new file mode 100644 index 00000000..171c908f --- /dev/null +++ b/src/orchestrator/internal/db/mongo_test.go @@ -0,0 +1,597 @@ +/* + * 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 db + +import ( + "bytes" + "context" + "reflect" + "strings" + "testing" + + pkgerrors "github.com/pkg/errors" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +//Implements the functions used currently in mongo.go +type mockCollection struct { + Err error + mCursor *mongo.Cursor + mCursorCount int +} + +func (c *mockCollection) InsertOne(ctx context.Context, document interface{}, + opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error) { + + if c.Err != nil { + return nil, c.Err + } + + return &mongo.InsertOneResult{InsertedID: "_id1234"}, nil +} + +func (c *mockCollection) FindOne(ctx context.Context, filter interface{}, + opts ...*options.FindOneOptions) *mongo.SingleResult { + + return &mongo.SingleResult{} +} + +func (c *mockCollection) FindOneAndUpdate(ctx context.Context, filter interface{}, + update interface{}, opts ...*options.FindOneAndUpdateOptions) *mongo.SingleResult { + + return &mongo.SingleResult{} +} + +func (c *mockCollection) DeleteOne(ctx context.Context, filter interface{}, + opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) { + + return nil, c.Err +} + +func (c *mockCollection) Find(ctx context.Context, filter interface{}, + opts ...*options.FindOptions) (*mongo.Cursor, error) { + + return c.mCursor, c.Err +} + +func TestCreate(t *testing.T) { + testCases := []struct { + label string + input map[string]interface{} + mockColl *mockCollection + bson bson.Raw + expectedError string + }{ + { + label: "Successfull creation of entry", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "tagName", + "data": "Data In String Format", + }, + bson: bson.Raw{'\x08', '\x00', '\x00', '\x00', '\x0A', 'x', '\x00', '\x00'}, + mockColl: &mockCollection{}, + }, + { + label: "UnSuccessfull creation of entry", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "tagName", + "data": "Data In String Format", + }, + mockColl: &mockCollection{ + Err: pkgerrors.New("DB Error"), + }, + expectedError: "DB Error", + }, + { + label: "Missing input fields", + input: map[string]interface{}{ + "coll": "", + "key": MockKey{Key: ""}, + "tag": "", + "data": "", + }, + expectedError: "No Data to store", + mockColl: &mockCollection{}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + m, _ := NewMongoStore("name", &mongo.Database{}) + // Override the getCollection function with our mocked version + getCollection = func(coll string, m *MongoStore) MongoCollection { + return testCase.mockColl + } + + decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) { + return testCase.bson, testCase.mockColl.Err + } + + err := m.Create(testCase.input["coll"].(string), testCase.input["key"].(Key), + testCase.input["tag"].(string), testCase.input["data"]) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("Create method returned an un-expected (%s)", err) + } + if !strings.Contains(string(err.Error()), testCase.expectedError) { + t.Fatalf("Create method returned an error (%s)", err) + } + } + }) + } +} + +func TestUpdate(t *testing.T) { + testCases := []struct { + label string + input map[string]interface{} + mockColl *mockCollection + bson bson.Raw + expectedError string + }{ + { + label: "Successfull update of entry", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "metadata", + "data": "Data In String Format", + }, + // Binary form of + // { + // "_id" : ObjectId("5c115156777ff85654248ae1"), + // "key" : bson.D{{"name","testdef"},{"version","v1"}}, + // "metadata" : ObjectId("5c115156c9755047e318bbfd") + // } + bson: bson.Raw{ + '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', + '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', + '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', + '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', + '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', + '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', + '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', + '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', + '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', + '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', + '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', + }, + mockColl: &mockCollection{}, + }, + { + label: "Entry does not exist", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "tagName", + "data": "Data In String Format", + }, + mockColl: &mockCollection{ + Err: pkgerrors.New("DB Error"), + }, + expectedError: "DB Error", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + m, _ := NewMongoStore("name", &mongo.Database{}) + // Override the getCollection function with our mocked version + getCollection = func(coll string, m *MongoStore) MongoCollection { + return testCase.mockColl + } + + decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) { + return testCase.bson, testCase.mockColl.Err + } + + err := m.Update(testCase.input["coll"].(string), testCase.input["key"].(Key), + testCase.input["tag"].(string), testCase.input["data"]) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("Create method returned an un-expected (%s)", err) + } + if !strings.Contains(string(err.Error()), testCase.expectedError) { + t.Fatalf("Create method returned an error (%s)", err) + } + } + }) + } +} + +func TestRead(t *testing.T) { + testCases := []struct { + label string + input map[string]interface{} + mockColl *mockCollection + bson bson.Raw + expectedError string + expected []byte + }{ + { + label: "Successfull Read of entry", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "metadata", + }, + // Binary form of + // { + // "_id" : ObjectId("5c115156777ff85654248ae1"), + // "key" : bson.D{{"name","testdef"},{"version","v1"}}, + // "metadata" : ObjectId("5c115156c9755047e318bbfd") + // } + bson: bson.Raw{ + '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', + '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', + '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', + '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', + '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', + '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', + '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', + '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', + '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', + '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', + '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', + }, + mockColl: &mockCollection{}, + // This is not the document because we are mocking decodeBytes + expected: []byte{92, 17, 81, 86, 119, 127, 248, 86, 84, 36, 138, 225}, + }, + { + label: "UnSuccessfull Read of entry: object not found", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "badtag", + }, + // Binary form of + // { + // "_id" : ObjectId("5c115156777ff85654248ae1"), + // "key" : bson.D{{"name","testdef"},{"version","v1"}}, + // "metadata" : ObjectId("5c115156c9755047e318bbfd") + // } + bson: bson.Raw{ + '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', + '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', + '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', + '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', + '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', + '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', + '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', + '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', + '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', + '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', + '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', + }, + mockColl: &mockCollection{}, + expectedError: "Error finding objectID", + }, + { + label: "UnSuccessfull Read of entry", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "tagName", + }, + mockColl: &mockCollection{ + Err: pkgerrors.New("DB Error"), + }, + expectedError: "DB Error", + }, + { + label: "Missing input fields", + input: map[string]interface{}{ + "coll": "", + "key": MockKey{Key: ""}, + "tag": "", + }, + expectedError: "Mandatory fields are missing", + mockColl: &mockCollection{}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + m, _ := NewMongoStore("name", &mongo.Database{}) + // Override the getCollection function with our mocked version + getCollection = func(coll string, m *MongoStore) MongoCollection { + return testCase.mockColl + } + + decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) { + return testCase.bson, testCase.mockColl.Err + } + got, err := m.Read(testCase.input["coll"].(string), testCase.input["key"].(Key), + testCase.input["tag"].(string)) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("Read method returned an un-expected (%s)", err) + } + if !strings.Contains(string(err.Error()), testCase.expectedError) { + t.Fatalf("Read method returned an error (%s)", err) + } + } else { + if bytes.Compare(got, testCase.expected) != 0 { + t.Fatalf("Read returned unexpected data: %v, expected: %v", + string(got), testCase.expected) + } + } + }) + } +} + +func TestDelete(t *testing.T) { + testCases := []struct { + label string + input map[string]interface{} + mockColl *mockCollection + bson bson.Raw + expectedError string + }{ + { + label: "Successfull Delete of entry", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "metadata", + }, + // Binary form of + // { + // "_id" : ObjectId("5c115156777ff85654248ae1"), + // "key" : bson.D{{"name","testdef"},{"version","v1"}}, + // "metadata" : ObjectId("5c115156c9755047e318bbfd") + // } + bson: bson.Raw{ + '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', + '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', + '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', + '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', + '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', + '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', + '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', + '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', + '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', + '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', + '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', + }, + mockColl: &mockCollection{}, + }, + { + label: "UnSuccessfull Delete of entry", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "tagName", + }, + mockColl: &mockCollection{ + Err: pkgerrors.New("DB Error"), + }, + expectedError: "DB Error", + }, + { + label: "UnSuccessfull Delete, key not found", + input: map[string]interface{}{ + "coll": "collname", + "key": MockKey{Key: "keyvalue"}, + "tag": "tagName", + }, + // Binary form of + // { + // "_id" : ObjectId("5c115156777ff85654248ae1"), + // "key" : bson.D{{"name","testdef"},{"version","v1"}}, + // "metadata" : ObjectId("5c115156c9755047e318bbfd") + // } + bson: bson.Raw{ + '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', + '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', + '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', + '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', + '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', + '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', + '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', + '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', + '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', + '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', + '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', + }, + mockColl: &mockCollection{}, + expectedError: "Error finding objectID", + }, + { + label: "Missing input fields", + input: map[string]interface{}{ + "coll": "", + "key": MockKey{Key: ""}, + "tag": "", + }, + expectedError: "Mandatory fields are missing", + mockColl: &mockCollection{}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + m, _ := NewMongoStore("name", &mongo.Database{}) + // Override the getCollection function with our mocked version + getCollection = func(coll string, m *MongoStore) MongoCollection { + return testCase.mockColl + } + + decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) { + return testCase.bson, testCase.mockColl.Err + } + err := m.Delete(testCase.input["coll"].(string), testCase.input["key"].(Key), + testCase.input["tag"].(string)) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("Delete method returned an un-expected (%s)", err) + } + if !strings.Contains(string(err.Error()), testCase.expectedError) { + t.Fatalf("Delete method returned an error (%s)", err) + } + } + }) + } +} + +func TestReadAll(t *testing.T) { + testCases := []struct { + label string + input map[string]interface{} + mockColl *mockCollection + bson bson.Raw + expectedError string + expected map[string][]byte + }{ + { + label: "Successfully Read all entries", + input: map[string]interface{}{ + "coll": "collname", + "tag": "metadata", + }, + mockColl: &mockCollection{ + mCursor: &mongo.Cursor{ + // Binary form of + // { + // "_id" : ObjectId("5c115156777ff85654248ae1"), + // "key" : bson.D{{"name","testdef"},{"version","v1"}}, + // "metadata" : ObjectId("5c115156c9755047e318bbfd") + // } + + Current: bson.Raw{ + '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', + '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', + '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', + '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', + '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', + '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', + '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', + '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', + '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', + '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', + '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', + }, + }, + mCursorCount: 1, + }, + expected: map[string][]byte{ + `{"name": "testdef","version": "v1"}`: []byte{ + 92, 17, 81, 86, 119, 127, 248, 86, 84, 36, 138, 225}, + }, + }, + { + label: "UnSuccessfully Read of all entries", + input: map[string]interface{}{ + "coll": "collname", + "tag": "tagName", + }, + mockColl: &mockCollection{ + Err: pkgerrors.New("DB Error"), + }, + expectedError: "DB Error", + }, + { + label: "UnSuccessfull Readall, tag not found", + input: map[string]interface{}{ + "coll": "collname", + "tag": "tagName", + }, + mockColl: &mockCollection{ + mCursor: &mongo.Cursor{ + // Binary form of + // { + // "_id" : ObjectId("5c115156777ff85654248ae1"), + // "key" : bson.D{{"name","testdef"},{"version","v1"}}, + // "metadata" : ObjectId("5c115156c9755047e318bbfd") + // } + Current: bson.Raw{ + '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79', + '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61', + '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74', + '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02', + '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00', + '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00', + '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74', + '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', + '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f', + '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', + '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00', + }, + }, + mCursorCount: 1, + }, + expectedError: "Did not find any objects with tag", + }, + { + label: "Missing input fields", + input: map[string]interface{}{ + "coll": "", + "tag": "", + }, + expectedError: "Missing collection or tag name", + mockColl: &mockCollection{}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.label, func(t *testing.T) { + m, _ := NewMongoStore("name", &mongo.Database{}) + // Override the getCollection function with our mocked version + getCollection = func(coll string, m *MongoStore) MongoCollection { + return testCase.mockColl + } + + decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) { + return testCase.mockColl.mCursor.Current, testCase.mockColl.Err + } + + cursorNext = func(ctx context.Context, cursor *mongo.Cursor) bool { + if testCase.mockColl.mCursorCount > 0 { + testCase.mockColl.mCursorCount -= 1 + return true + } + return false + } + + cursorClose = func(ctx context.Context, cursor *mongo.Cursor) error { + return nil + } + + got, err := m.ReadAll(testCase.input["coll"].(string), testCase.input["tag"].(string)) + if err != nil { + if testCase.expectedError == "" { + t.Fatalf("Readall method returned an un-expected (%s)", err) + } + if !strings.Contains(string(err.Error()), testCase.expectedError) { + t.Fatalf("Readall method returned an error (%s)", err) + } + } else { + if reflect.DeepEqual(got, testCase.expected) == false { + t.Fatalf("Readall returned unexpected data: %v, expected: %v", + got, testCase.expected) + } + } + }) + } +} |