Commit VOL-4124. Testcases for device package.

Change-Id: I2fe37621e373f57d9f90da14a0bf0600b8328362
diff --git a/Makefile b/Makefile
index 218db5e..4db8dfb 100644
--- a/Makefile
+++ b/Makefile
@@ -118,6 +118,12 @@
 
 test: ## Run unit tests
 	@echo "Call unit test case suite"
+	@mkdir -p ./tests/results
+	@${GO} test -mod=vendor -v -coverprofile ./tests/results/go-test-coverage.out -covermode count ./... 2>&1 | tee ./tests/results/go-test-results.out ;\
+	RETURN=$$? ;\
+	${GO_JUNIT_REPORT} < ./tests/results/go-test-results.out > ./tests/results/go-test-results.xml ;\
+	${GOCOVER_COBERTURA} < ./tests/results/go-test-coverage.out > ./tests/results/go-test-coverage.xml ;\
+	exit $$RETURN
 
 sca: ## Runs static code analysis with the golangci-lint tool
 	@rm -rf ./sca-report
diff --git a/pkg/config/config_mock.go b/pkg/config/config_mock.go
new file mode 100644
index 0000000..f29e968
--- /dev/null
+++ b/pkg/config/config_mock.go
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * 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 config Common Logger initialization
+package config
+
+import (
+	"context"
+)
+
+const (
+	FailedPattern = "error"
+)
+
+// MockConfig function will be used to set some default values for config variables
+func MockConfig(ctx context.Context) {
+	ctxGlobal = ctx
+}
diff --git a/pkg/db/connection.go b/pkg/db/connection.go
index 52cf88b..26cdba3 100644
--- a/pkg/db/connection.go
+++ b/pkg/db/connection.go
@@ -34,12 +34,7 @@
 	"github.com/opencord/voltha-lib-go/v4/pkg/log"
 )
 
-var kvClient *KvStoreClient
-
-// KvStoreClient holds the KVStore info
-type KvStoreClient struct {
-	client kvstore.Client
-}
+var kvClient kvstore.Client
 
 // logger represents the log object
 var logger log.CLogger
@@ -61,8 +56,7 @@
 			logger.Errorw(ctx, "etcd-server-unreachable", log.Fields{"address": address})
 			return nil, errors.New("etcd client unreachable")
 		}
-		kvClient = new(KvStoreClient)
-		kvClient.client = etcdClient
+		kvClient = etcdClient
 		return etcdClient, err
 	}
 	return nil, errors.New("unsupported-kv-store")
diff --git a/pkg/db/kvclient_mock.go b/pkg/db/kvclient_mock.go
new file mode 100644
index 0000000..0f292d4
--- /dev/null
+++ b/pkg/db/kvclient_mock.go
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * 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 holds utils for datastore implementation
+package db
+
+import (
+	"context"
+	"errors"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/opencord/voltha-lib-go/v4/pkg/db/kvstore"
+
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+)
+
+type mockKVClient struct {
+}
+
+var testKvPairCache *sync.Map
+
+// MockKVClient function mimics the kvclient
+func MockKVClient() {
+	kvClient = new(mockKVClient)
+	testKvPairCache = new(sync.Map)
+}
+
+// ClearCache function clears the kvclient cache
+func ClearCache() {
+	testKvPairCache = new(sync.Map)
+}
+
+// List function implemented for KVClient.
+func (kvclient *mockKVClient) List(ctx context.Context, prefix string) (map[string]*kvstore.KVPair, error) {
+	kvPairMap := make(map[string]*kvstore.KVPair)
+	testKvPairCache.Range(func(key, value interface{}) bool {
+		if strings.Contains(key.(string), prefix) {
+			kvPair := new(kvstore.KVPair)
+			kvPair.Key = key.(string)
+			kvPair.Value = value.([]byte)
+			kvPairMap[kvPair.Key] = kvPair
+		}
+		return true
+	})
+
+	if len(kvPairMap) != 0 {
+		logger.Debugw(ctx, "List of MockKVClient called", log.Fields{"kvPairMap": kvPairMap})
+		return kvPairMap, nil
+	}
+
+	return nil, errors.New("key didn't find")
+}
+
+// Get mock function implementation for KVClient
+func (kvclient *mockKVClient) Get(ctx context.Context, key string) (*kvstore.KVPair, error) {
+	logger.Debugw(ctx, "Warning Warning Warning: Get of MockKVClient called", log.Fields{"key": key})
+
+	if val, ok := testKvPairCache.Load(key); ok {
+		kvPair := new(kvstore.KVPair)
+		kvPair.Key = key
+		kvPair.Value = val
+		return kvPair, nil
+	}
+
+	return nil, errors.New("key didn't find")
+}
+
+// Put mock function implementation for KVClient
+func (kvclient *mockKVClient) Put(ctx context.Context, key string, value interface{}) error {
+	if key != "" {
+		value = []byte(value.(string))
+		testKvPairCache.Store(key, value)
+		return nil
+	}
+	return errors.New("key didn't find")
+}
+
+// Delete mock function implementation for KVClient
+func (kvclient *mockKVClient) Delete(ctx context.Context, key string) error {
+	logger.Infow(ctx, "Error Error Error Key:", log.Fields{})
+	if key != "" {
+		testKvPairCache.Delete(key)
+		return nil
+	}
+	return errors.New("key didn't find")
+}
+
+// DeleteWithPrefix mock function implementation for KVClient
+func (kvclient *mockKVClient) DeleteWithPrefix(ctx context.Context, prefix string) error {
+	testKvPairCache.Range(func(key, value interface{}) bool {
+		if strings.Contains(key.(string), prefix) {
+			testKvPairCache.Delete(key)
+		}
+		return true
+	})
+	return nil
+}
+
+// Reserve mock function implementation for KVClient
+func (kvclient *mockKVClient) Reserve(ctx context.Context, key string, value interface{}, ttl time.Duration) (interface{}, error) {
+	return nil, errors.New("key didn't find")
+}
+
+// ReleaseReservation mock function implementation for KVClient
+func (kvclient *mockKVClient) ReleaseReservation(ctx context.Context, key string) error {
+	return nil
+}
+
+// ReleaseAllReservations mock function implementation for KVClient
+func (kvclient *mockKVClient) ReleaseAllReservations(ctx context.Context) error {
+	return nil
+}
+
+// RenewReservation mock function implementation for KVClient
+func (kvclient *mockKVClient) RenewReservation(ctx context.Context, key string) error {
+	return nil
+}
+
+// Watch mock function implementation for KVClient
+func (kvclient *mockKVClient) Watch(ctx context.Context, key string, withPrefix bool) chan *kvstore.Event {
+	return nil
+}
+
+// AcquireLock mock function implementation for KVClient
+func (kvclient *mockKVClient) AcquireLock(ctx context.Context, lockName string, timeout time.Duration) error {
+	return nil
+}
+
+// ReleaseLock mock function implementation for KVClient
+func (kvclient *mockKVClient) ReleaseLock(lockName string) error {
+	return nil
+}
+
+// IsConnectionUp mock function implementation for KVClient
+func (kvclient *mockKVClient) IsConnectionUp(ctx context.Context) bool { // timeout in second
+	return true
+}
+
+// CloseWatch mock function implementation for KVClient
+func (kvclient *mockKVClient) CloseWatch(ctx context.Context, key string, ch chan *kvstore.Event) {
+}
+
+// Close mock function implementation for KVClient
+func (kvclient *mockKVClient) Close(ctx context.Context) {
+}
diff --git a/pkg/db/operations.go b/pkg/db/operations.go
index ea63050..1d6097d 100644
--- a/pkg/db/operations.go
+++ b/pkg/db/operations.go
@@ -28,7 +28,7 @@
 func Read(ctx context.Context, key string) (string, error) {
 	if kvClient != nil {
 		logger.Debugw(ctx, "Reading-key-value-pair-from-kv-store", log.Fields{"key": key})
-		kvPair, err := kvClient.client.Get(ctx, key)
+		kvPair, err := kvClient.Get(ctx, key)
 		if err != nil {
 			return "", err
 		}
@@ -47,7 +47,7 @@
 	keyValues := make(map[string]string)
 	if kvClient != nil {
 		logger.Debugw(ctx, "Reading-all-key-value-pairs-from-kv-store", log.Fields{"key-prefix": keyPrefix})
-		kvPairs, err := kvClient.client.List(ctx, keyPrefix)
+		kvPairs, err := kvClient.List(ctx, keyPrefix)
 		if err != nil {
 			return keyValues, err
 		}
@@ -68,7 +68,7 @@
 func Del(ctx context.Context, key string) error {
 	if kvClient != nil {
 		logger.Debugw(ctx, "Deleting-key-value-pair-from-kv-store", log.Fields{"key": key})
-		return kvClient.client.Delete(ctx, key)
+		return kvClient.Delete(ctx, key)
 	}
 	logger.Errorw(ctx, "Deleting-key-value-pair-in-kv-store-failed-because-kvstore-not-initialised", log.Fields{"key": key})
 	return errors.New("kvstore not initialised")
@@ -78,7 +78,7 @@
 func DelAll(ctx context.Context, keyPrefix string) error {
 	if kvClient != nil {
 		logger.Debugw(ctx, "Deleting-all-key-value-pair-from-kv-store-with-prefix", log.Fields{"key-prefix": keyPrefix})
-		return kvClient.client.DeleteWithPrefix(ctx, keyPrefix)
+		return kvClient.DeleteWithPrefix(ctx, keyPrefix)
 	}
 	logger.Errorw(ctx, "Deleting-all-key-value-pair-in-kv-store-with-prefix-failed-because-kvstore-not-initialised", log.Fields{"key-prefix": keyPrefix})
 	return errors.New("kvstore not initialised")
@@ -88,7 +88,7 @@
 func Put(ctx context.Context, key string, val string) error {
 	if kvClient != nil {
 		logger.Debugw(ctx, "Storing-key-value-pair-in-kv-store", log.Fields{"key": key, "value": val})
-		return kvClient.client.Put(ctx, key, val)
+		return kvClient.Put(ctx, key, val)
 	}
 	logger.Errorw(ctx, "Storing-key-value-pair-in-kv-store-failed-because-kvstore-not-initialised", log.Fields{"key": key, "value": val})
 	return errors.New("kvstore not initialised")
diff --git a/pkg/models/device/db_test.go b/pkg/models/device/db_test.go
new file mode 100644
index 0000000..b59d08b
--- /dev/null
+++ b/pkg/models/device/db_test.go
@@ -0,0 +1,382 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * 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 modifiablecomponent stores ModifiableComponent methods and functions
+package device
+
+import (
+	"context"
+	"fmt"
+	"strings"
+	"testing"
+
+	timestamp "github.com/golang/protobuf/ptypes/timestamp"
+	"github.com/opencord/device-management-interface/go/dmi"
+	"github.com/opencord/opendevice-manager/pkg/db"
+)
+
+// mockModifiableComp refers to mocking of modifiable component req
+func mockModifiableComp(id string) *dmi.ModifiableComponent {
+	req := new(dmi.ModifiableComponent)
+	req.Name = "olt-name-" + id
+	req.Alias = "olt-1-alias-" + id
+	req.AssetId = "olt-1-assetid-" + id
+	req.Uri = new(dmi.Uri)
+	req.Uri.Uri = "127.0.0." + id
+	req.Parent = new(dmi.Component)
+	req.AdminState = dmi.ComponentAdminState_COMP_ADMIN_STATE_UNLOCKED
+	return req
+}
+
+func mockHardware(id string) *dmi.Hardware {
+	hw := new(dmi.Hardware)
+	hw.LastChange = new(timestamp.Timestamp)
+	hw.LastBooted = new(timestamp.Timestamp)
+	hw.Root = new(dmi.Component)
+	hw.Root.ModelName = "model-name-" + id
+	return hw
+}
+
+func runTcase(tcaseName string, t *testing.T, tcaseFunc func() (bool, error)) (string, bool) {
+	fmt.Println("\n#======= TESTCASE STARTED : " + tcaseName + " ========#")
+	if ok, err := tcaseFunc(); !ok {
+		fmt.Println("#======= TESTCASE FAILED : "+tcaseName+"  ========#", err)
+		return tcaseName, false
+	}
+	fmt.Println("#======= TESTCASE PASSED : " + tcaseName + " ========#")
+	return tcaseName, true
+}
+
+// _Test_PositiveTcaseNewDeviceRecord refers to the positive tcase defined for testing func NewDeviceRecord
+func Test_PositiveTcaseNewDeviceRecord(t *testing.T) {
+	req := mockModifiableComp("1")
+	var rec *DeviceRecord
+
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Positive Testcase for NewDeviceRecord
+	tcase1 := func() (bool, error) {
+		var err error
+		if rec, err = NewDeviceRecord(ctx, req); rec == nil || err != nil {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Positive Testcase for NewDeviceRecord-1", t, tcase1); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+}
+
+// _Test_NegativeTcaseDBGetByName refers to the negative tcase defined for testing func DBGetByName
+func Test_NegativeTcaseDBGetByName(t *testing.T) {
+	req := mockModifiableComp("1")
+
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Negative Testcase for DBGetByName
+	tcase2 := func() (bool, error) {
+		if rec, err := DBGetByName(ctx, req.Name); rec != nil {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Negative Testcase for DBGetByName-1", t, tcase2); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+}
+
+// _Test_Suite refers to all component testcases belongs to all packages
+func Test_Suite(t *testing.T) {
+}
+
+// _Test_NegativeTcaseDBAddByName refers to the negative tcase defined for testing func DBAddByName
+func Test_NegativeTcaseDBAddByName(t *testing.T) {
+
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Negative Testcase for DBAddByName
+	tcase3 := func() (bool, error) {
+		emptyDevRec := new(DeviceRecord)
+		if err := emptyDevRec.DBAddByName(ctx); err == nil {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Negative Testcase for DBAddByName-1", t, tcase3); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+
+}
+
+// _Test_PositiveTcaseDBAddByName refers to the positive tcase defined for testing func DBAddByName
+func Test_PositiveTcaseDBAddByName(t *testing.T) {
+	req := mockModifiableComp("1")
+	var rec *DeviceRecord
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Positive Testcase for DBAddByName
+	tcase4 := func() (bool, error) {
+		var err error
+		if rec, err = NewDeviceRecord(ctx, req); rec == nil || err != nil {
+			return false, err
+		}
+		if err = rec.DBAddByName(ctx); err != nil {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Positive Testcase for DBAddByName-1", t, tcase4); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+
+}
+
+// _Test_PositiveTcaseDBGetByName refers to the positive tcase defined for testing func DBGetByName
+func Test_PositiveTcaseDBGetByName(t *testing.T) {
+	req := mockModifiableComp("1")
+	var rec *DeviceRecord
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Positive Testcase for DBGetByName
+	tcase5 := func() (bool, error) {
+		var err error
+		if rec, err = NewDeviceRecord(ctx, req); rec == nil || err != nil {
+			return false, err
+		}
+		if err = rec.DBAddByName(ctx); err != nil {
+			return false, err
+		}
+		if rec, err := DBGetByName(ctx, rec.Name); rec == nil || err != nil {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Positive Testcase for DBGetByName-1", t, tcase5); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+
+}
+
+// _Test_PositiveTcaseDBGetByNameWithCacheMiss refers to the positive tcase defined for testing func DBGetByName with cache miss
+func Test_PositiveTcaseDBGetByNameWithCacheMiss(t *testing.T) {
+	req := mockModifiableComp("1")
+	var rec *DeviceRecord
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Positive Testcase for DBGetByName with cache miss
+	tcase5 := func() (bool, error) {
+		var err error
+		if rec, err = NewDeviceRecord(ctx, req); rec == nil || err != nil {
+			return false, err
+		}
+		if err = rec.DBAddByName(ctx); err != nil {
+			return false, err
+		}
+		if rec, err := DBGetByName(ctx, rec.Name); rec == nil || err != nil {
+			return false, err
+		}
+		ClearCacheEntry(ctx, rec.Name, "")
+		if rec, err := DBGetByName(ctx, rec.Name); rec == nil || err != nil {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Positive Testcase for DBGetByName-2 with cache miss", t, tcase5); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+
+}
+
+// _Test_PositiveTcaseDBAddUuidLookup refers to the positive tcase defined for testing func DBAddUuidLookup
+func Test_PositiveTcaseDBAddUuidLookup(t *testing.T) {
+	req := mockModifiableComp("1")
+	var rec *DeviceRecord
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Positive Testcase for DBAddUuidLookup
+	tcase6 := func() (bool, error) {
+		var err error
+		if rec, err = NewDeviceRecord(ctx, req); rec == nil || err != nil {
+			return false, err
+		}
+		if err = rec.DBAddByName(ctx); err != nil {
+			return false, err
+		}
+		rec.Uuid = strings.Replace(rec.Name, "name", "uuid", 1)
+		if err := rec.DBAddUuidLookup(ctx); err != nil {
+			return false, err
+		}
+		if err := rec.DBAddByName(ctx); err != nil {
+			return false, err
+		}
+		if rec, err := DBGetByName(ctx, rec.Name); rec == nil || err != nil || rec.Uuid == "" {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Positive Testcase for DBAddUuidLookup-1", t, tcase6); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+
+}
+
+// _Test_PositiveTcaseDBGetAll refers to the positive tcase defined for testing func DBGetAll
+func Test_PositiveTcaseDBGetAll(t *testing.T) {
+	req := mockModifiableComp("1")
+	var rec *DeviceRecord
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Positive Testcase for DBGetAll
+	tcase8 := func() (bool, error) {
+		var err error
+		if rec, err = NewDeviceRecord(ctx, req); rec == nil || err != nil {
+			return false, err
+		}
+		if err = rec.DBAddByName(ctx); err != nil {
+			return false, err
+		}
+		if list, err := DBGetAll(ctx); list == nil || err != nil || len(list) != 1 {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Positive Testcase for DBGetAll-1", t, tcase8); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+
+}
+
+// _Test_NegativeTcaseDBGetByUuid refers to the negative tcase defined for testing func DBGetByUuid
+func Test_NegativeTcaseDBGetByUuid(t *testing.T) {
+
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Negative Testcase for DBGetByUuid
+	tcase10 := func() (bool, error) {
+		if rec, err := DBGetByUuid(ctx, "invalid-uuid-1"); rec != nil || err == nil {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Negative Testcase for DBGetByUuid-1", t, tcase10); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+
+}
+
+// _Test_PositiveTcaseDBDelRecord refers to the positive tcase defined for testing func DBDelRecord
+func Test_PositiveTcaseDBDelRecord(t *testing.T) {
+	req := mockModifiableComp("1")
+	var rec *DeviceRecord
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Positive Testcase for DBDelRecord
+	tcase11 := func() (bool, error) {
+		var err error
+		if rec, err = NewDeviceRecord(ctx, req); rec == nil || err != nil {
+			return false, err
+		}
+		if err = rec.DBAddByName(ctx); err != nil {
+			return false, err
+		}
+		if err := rec.DBDelRecord(ctx); err != nil {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Positive Testcase for DBDelRecord-1", t, tcase11); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+
+}
+
+// _Test_PositiveTcaseDBSaveHwInfo refers to the positive tcase defined for testing func DBSaveHwInfo
+func Test_PositiveTcaseDBSaveHwInfo(t *testing.T) {
+	req := mockModifiableComp("1")
+	var rec *DeviceRecord
+	db.MockKVClient()
+	ctx := context.Background()
+	defer db.ClearCache()
+
+	// Positive Testcase for DBSaveHwInfo
+	tcase := func() (bool, error) {
+		var err error
+		if rec, err = NewDeviceRecord(ctx, req); rec == nil || err != nil {
+			return false, err
+		}
+		if err = rec.DBAddByName(ctx); err != nil {
+			return false, err
+		}
+		rec.Uuid = strings.Replace(rec.Name, "name", "uuid", 1)
+		if err := rec.DBAddUuidLookup(ctx); err != nil {
+			return false, err
+		}
+		hwInfo := mockHardware("1")
+		if err := rec.DBSaveHwInfo(ctx, hwInfo); rec == nil || err != nil {
+			return false, err
+		}
+		if rec, err := DBGetByName(ctx, rec.Name); rec == nil || err != nil || rec.ModelName != hwInfo.Root.ModelName {
+			return false, err
+		}
+		return true, nil
+	}
+
+	if name, ok := runTcase("Positive Testcase for DBSaveHwInfo-1", t, tcase); !ok {
+		t.Errorf("#======= FAILED :  Testcase " + name + "  ========#")
+		return
+	}
+
+}