VOL-1243: Added logic for thread safety

- Thread safety was added at the proxy level
- Refactored the test init in a base_test structure
- Fixed issue with writing to kv
- Added profiling for locking period

Amendments:

- Comment out a cleanup statement causing KV corruption (as per VOL-1293)
- Added missing license

Change-Id: Id6658270dbb8b738abeef9e9e1d349dce36501bc
diff --git a/db/model/base_test.go b/db/model/base_test.go
new file mode 100644
index 0000000..1be34f6
--- /dev/null
+++ b/db/model/base_test.go
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2018-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 model
+
+import (
+	"github.com/opencord/voltha-go/common/log"
+	"github.com/opencord/voltha-go/protos/common"
+	"github.com/opencord/voltha-go/protos/openflow_13"
+	"github.com/opencord/voltha-go/protos/voltha"
+)
+
+type ModelTestConfig struct {
+	Root      *root
+	Backend   *Backend
+	RootProxy *Proxy
+	DbPrefix  string
+	DbType    string
+	DbHost    string
+	DbPort    int
+	DbTimeout int
+}
+
+var (
+	modelTestConfig = &ModelTestConfig{
+		DbPrefix:  "service/voltha/data/core/0001",
+		DbType:    "etcd",
+		DbHost:    "localhost",
+		//DbHost:    "10.106.153.44",
+		DbPort:    2379,
+		DbTimeout: 5,
+	}
+
+	ports = []*voltha.Port{
+		{
+			PortNo:     123,
+			Label:      "test-port-0",
+			Type:       voltha.Port_PON_OLT,
+			AdminState: common.AdminState_ENABLED,
+			OperStatus: common.OperStatus_ACTIVE,
+			DeviceId:   "etcd_port-0-device-id",
+			Peers:      []*voltha.Port_PeerPort{},
+		},
+	}
+
+	stats = &openflow_13.OfpFlowStats{
+		Id: 1111,
+	}
+	flows = &openflow_13.Flows{
+		Items: []*openflow_13.OfpFlowStats{stats},
+	}
+	device = &voltha.Device{
+		Id:         devId,
+		Type:       "simulated_olt",
+		Address:    &voltha.Device_HostAndPort{HostAndPort: "1.2.3.4:5555"},
+		AdminState: voltha.AdminState_PREPROVISIONED,
+		Flows:      flows,
+		Ports:      ports,
+	}
+	devId          string
+	targetDeviceId string
+)
+
+func init() {
+	log.AddPackage(log.JSON, log.WarnLevel, nil)
+	log.UpdateAllLoggers(log.Fields{"instanceId": "MODEL_TEST"})
+
+	defer log.CleanUp()
+
+	modelTestConfig.Backend = NewBackend(
+		modelTestConfig.DbType,
+		modelTestConfig.DbHost,
+		modelTestConfig.DbPort,
+		modelTestConfig.DbTimeout,
+		modelTestConfig.DbPrefix,
+	)
+
+	msgClass := &voltha.Voltha{}
+	root := NewRoot(msgClass, modelTestConfig.Backend)
+
+	if modelTestConfig.Backend != nil {
+		modelTestConfig.Root = root.Load(msgClass)
+	} else {
+		modelTestConfig.Root = root
+	}
+
+	GetProfiling().Report()
+
+	modelTestConfig.RootProxy = modelTestConfig.Root.GetProxy("/", false)
+}
+
+func commonCallback(args ...interface{}) interface{} {
+	log.Infof("Running common callback - arg count: %s", len(args))
+
+	for i := 0; i < len(args); i++ {
+		log.Infof("ARG %d : %+v", i, args[i])
+	}
+	execStatus := args[1].(*bool)
+
+	// Inform the caller that the callback was executed
+	*execStatus = true
+
+	return nil
+}
+
+func firstCallback(args ...interface{}) interface{} {
+	name := args[0]
+	id := args[1]
+	log.Infof("Running first callback - name: %s, id: %s\n", name, id)
+	return nil
+}
+func secondCallback(args ...interface{}) interface{} {
+	name := args[0].(map[string]string)
+	id := args[1]
+	log.Infof("Running second callback - name: %s, id: %f\n", name["name"], id)
+	// FIXME: the panic call seem to interfere with the logging mechanism
+	//panic("Generating a panic in second callback")
+	return nil
+}
+func thirdCallback(args ...interface{}) interface{} {
+	name := args[0]
+	id := args[1].(*voltha.Device)
+	log.Infof("Running third callback - name: %+v, id: %s\n", name, id.Id)
+	return nil
+}
diff --git a/db/model/model.go b/db/model/model.go
index 1312a41..18ff905 100644
--- a/db/model/model.go
+++ b/db/model/model.go
@@ -20,6 +20,6 @@
 )
 
 func init() {
-	log.AddPackage(log.JSON, log.DebugLevel, log.Fields{"instanceId": "DB_MODEL"})
+	log.AddPackage(log.JSON, log.InfoLevel, log.Fields{"instanceId": "DB_MODEL"})
 	defer log.CleanUp()
 }
diff --git a/db/model/node.go b/db/model/node.go
index 4a92208..a3e6ea7 100644
--- a/db/model/node.go
+++ b/db/model/node.go
@@ -331,10 +331,13 @@
 
 func (n *node) getData(rev Revision, depth int) interface{} {
 	msg := rev.Get(depth)
+	var modifiedMsg interface{}
 
 	if n.Proxy != nil {
 		log.Debug("invoking proxy GET Callbacks")
-		msg = n.Proxy.InvokeCallbacks(GET, false, msg)
+		if modifiedMsg = n.Proxy.InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
+			msg = modifiedMsg
+		}
 
 	}
 	return msg
@@ -398,6 +401,7 @@
 			idx, childRev := n.findRevByKey(children, field.Key, keyValue)
 			childNode := childRev.GetNode()
 			childNode.Proxy = n.Proxy
+
 			newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
 
 			if newChildRev.GetHash() == childRev.GetHash() {
@@ -418,19 +422,20 @@
 			children[idx] = newChildRev
 			rev = rev.UpdateChildren(name, children, branch)
 			branch.Latest.Drop(txid, false)
-			n.MakeLatest(branch, rev, nil)
-			return rev
+			n.Root.MakeLatest(branch, rev, nil)
+			return newChildRev
 		} else {
 			log.Errorf("cannot index into container with no keys")
 		}
 	} else {
 		childRev := rev.GetChildren()[name][0]
 		childNode := childRev.GetNode()
+		childNode.Proxy = n.Proxy
 		newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
 		rev = rev.UpdateChildren(name, []Revision{newChildRev}, branch)
 		branch.Latest.Drop(txid, false)
-		n.MakeLatest(branch, rev, nil)
-		return rev
+		n.Root.MakeLatest(branch, rev, nil)
+		return newChildRev
 	}
 	return nil
 }
@@ -460,8 +465,13 @@
 		}
 		rev := branch.Latest.UpdateData(data, branch)
 		changes := []ChangeTuple{{POST_UPDATE, branch.Latest.GetData(), rev.GetData()}}
-		branch.Latest.Drop(branch.Txid, true)
-		n.MakeLatest(branch, rev, changes)
+
+		// FIXME VOL-1293: the following statement corrupts the kv when using a subproxy (commenting for now)
+		// FIXME VOL-1293 cont'd: need to figure out the required conditions otherwise we are not cleaning up entries
+		//branch.Latest.Drop(branch.Txid, true)
+
+		n.Root.Proxy = n.Proxy
+		n.Root.MakeLatest(branch, rev, changes)
 		return rev
 	} else {
 		return branch.Latest
@@ -524,7 +534,7 @@
 					rev := rev.UpdateChildren(name, children, branch)
 					changes := []ChangeTuple{{POST_ADD, nil, rev.GetData()}}
 					branch.Latest.Drop(txid, false)
-					n.MakeLatest(branch, rev, changes)
+					n.Root.MakeLatest(branch, rev, changes)
 					return rev
 				}
 
@@ -547,7 +557,7 @@
 			children[idx] = newChildRev
 			rev := rev.UpdateChildren(name, children, branch)
 			branch.Latest.Drop(txid, false)
-			n.MakeLatest(branch, rev, nil)
+			n.Root.MakeLatest(branch, rev, nil)
 			return rev
 		} else {
 			log.Errorf("cannot add to non-keyed container")
@@ -614,7 +624,7 @@
 				children[idx] = newChildRev
 				rev := rev.UpdateChildren(name, children, branch)
 				branch.Latest.Drop(txid, false)
-				n.MakeLatest(branch, rev, nil)
+				n.Root.MakeLatest(branch, rev, nil)
 				return rev
 			} else {
 				for _, v := range rev.GetChildren()[name] {
@@ -633,7 +643,7 @@
 				children = append(children[:idx], children[idx+1:]...)
 				rev := rev.UpdateChildren(name, children, branch)
 				branch.Latest.Drop(txid, false)
-				n.MakeLatest(branch, rev, postAnnouncement)
+				n.Root.MakeLatest(branch, rev, postAnnouncement)
 				return rev
 			}
 		} else {
@@ -685,7 +695,7 @@
 	rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
 
 	if !dryRun {
-		n.MakeLatest(dstBranch, rev, changes)
+		n.Root.MakeLatest(dstBranch, rev, changes)
 		delete(n.Branches, txid)
 	}
 
@@ -742,7 +752,7 @@
 		path = path[1:]
 	}
 	if path == "" {
-		return n.makeProxy(path, exclusive)
+		return n.makeProxy(path, fullPath, exclusive)
 	}
 
 	rev := n.Branches[NONE].Latest
@@ -788,7 +798,7 @@
 	return nil
 }
 
-func (n *node) makeProxy(fullPath string, exclusive bool) *Proxy {
+func (n *node) makeProxy(path string, fullPath string, exclusive bool) *Proxy {
 	r := &root{
 		node:                  n,
 		Callbacks:             n.Root.Callbacks,
@@ -800,7 +810,7 @@
 	}
 
 	if n.Proxy == nil {
-		n.Proxy = NewProxy(r, fullPath, exclusive)
+		n.Proxy = NewProxy(r, path, fullPath, exclusive)
 	} else {
 		if n.Proxy.Exclusive {
 			log.Error("node is already owned exclusively")
diff --git a/db/model/profiling.go b/db/model/profiling.go
index 1f97839..b93d2fc 100644
--- a/db/model/profiling.go
+++ b/db/model/profiling.go
@@ -27,6 +27,8 @@
 	InMemoryModelCount    int
 	InMemoryProcessTime   float64
 	DatabaseStoreTime     float64
+	InMemoryLockTime      float64
+	InMemoryLockCount     int
 }
 
 var profiling_instance *profiling
@@ -54,6 +56,22 @@
 	p.DatabaseStoreTime += period
 }
 
+func (p *profiling) AddToInMemoryLockTime(period float64) {
+	p.InMemoryLockTime += period
+	p.InMemoryLockCount += 1
+}
+
+func (p *profiling) Reset() {
+	p.DatabaseRetrieveTime = 0
+	p.DatabaseRetrieveCount = 0
+	p.InMemoryModelTime = 0
+	p.InMemoryModelCount = 0
+	p.InMemoryProcessTime = 0
+	p.DatabaseStoreTime = 0
+	p.InMemoryLockTime = 0
+	p.InMemoryLockCount = 0
+}
+
 func (p *profiling) Report() {
 	log.Infof("[ Profiling Report ]")
 	log.Infof("Database Retrieval : %f", p.DatabaseRetrieveTime)
@@ -62,5 +80,8 @@
 	log.Infof("In-Memory Modeling : %f", p.InMemoryModelTime)
 	log.Infof("In-Memory Modeling Count: %d", p.InMemoryModelCount)
 	log.Infof("Avg In-Memory Modeling : %f", p.InMemoryModelTime/float64(p.InMemoryModelCount))
+	log.Infof("In-Memory Locking : %f", p.InMemoryLockTime)
+	log.Infof("In-Memory Locking Count: %d", p.InMemoryLockCount)
+	log.Infof("Avg In-Memory Locking : %f", p.InMemoryLockTime/float64(p.InMemoryLockCount))
 
 }
diff --git a/db/model/proxy.go b/db/model/proxy.go
index decbf9b..3827ff3 100644
--- a/db/model/proxy.go
+++ b/db/model/proxy.go
@@ -23,6 +23,7 @@
 	"reflect"
 	"runtime"
 	"strings"
+	"sync"
 )
 
 type OperationContext struct {
@@ -48,25 +49,68 @@
 }
 
 type Proxy struct {
+	sync.Mutex
 	Root      *root
 	Path      string
+	FullPath  string
 	Exclusive bool
 	Callbacks map[CallbackType]map[string]CallbackTuple
 }
 
-func NewProxy(root *root, path string, exclusive bool) *Proxy {
+func NewProxy(root *root, path string, fullPath string, exclusive bool) *Proxy {
 	callbacks := make(map[CallbackType]map[string]CallbackTuple)
+	if fullPath == "/" {
+		fullPath = ""
+	}
 	p := &Proxy{
 		Root:      root,
 		Exclusive: exclusive,
 		Path:      path,
+		FullPath:  fullPath,
 		Callbacks: callbacks,
 	}
 	return p
 }
 
+func (p *Proxy) parseForControlledPath(path string) (pathLock string, controlled bool) {
+	// TODO: Add other path prefixes they may need control
+	if strings.HasPrefix(path, "/devices") {
+		split := strings.SplitN(path, "/", -1)
+		switch len(split) {
+		case 2:
+			controlled = false
+			pathLock = ""
+			break
+		case 3:
+			fallthrough
+		default:
+			pathLock = fmt.Sprintf("%s/%s", split[1], split[2])
+			controlled = true
+		}
+	}
+	return pathLock, controlled
+}
+
 func (p *Proxy) Get(path string, depth int, deep bool, txid string) interface{} {
-	return p.Root.Get(path, "", depth, deep, txid)
+	var effectivePath string
+	if path == "/" {
+		effectivePath = p.FullPath
+	} else {
+		effectivePath = p.FullPath + path
+	}
+
+	pathLock, controlled := p.parseForControlledPath(effectivePath)
+
+	var pac interface{}
+	var exists bool
+
+	p.Lock()
+	if pac, exists = GetProxyAccessControl().Cache.LoadOrStore(path, NewProxyAccessControl(p, pathLock)); !exists {
+		defer GetProxyAccessControl().Cache.Delete(pathLock)
+	}
+	p.Unlock()
+
+	return pac.(ProxyAccessControl).Get(path, depth, deep, txid, controlled)
 }
 
 func (p *Proxy) Update(path string, data interface{}, strict bool, txid string) interface{} {
@@ -75,13 +119,27 @@
 		return nil
 	}
 	var fullPath string
+	var effectivePath string
 	if path == "/" {
 		fullPath = p.Path
+		effectivePath = p.FullPath
 	} else {
 		fullPath = p.Path + path
+		effectivePath = p.FullPath + path
 	}
 
-	return p.Root.Update(fullPath, data, strict, txid, nil)
+	pathLock, controlled := p.parseForControlledPath(effectivePath)
+
+	var pac interface{}
+	var exists bool
+
+	p.Lock()
+	if pac, exists = GetProxyAccessControl().Cache.LoadOrStore(path, NewProxyAccessControl(p, pathLock)); !exists {
+		defer GetProxyAccessControl().Cache.Delete(pathLock)
+	}
+	p.Unlock()
+
+	return pac.(ProxyAccessControl).Update(fullPath, data, strict, txid, controlled)
 }
 
 func (p *Proxy) Add(path string, data interface{}, txid string) interface{} {
@@ -90,12 +148,27 @@
 		return nil
 	}
 	var fullPath string
+	var effectivePath string
 	if path == "/" {
 		fullPath = p.Path
+		effectivePath = p.FullPath
 	} else {
 		fullPath = p.Path + path
+		effectivePath = p.FullPath + path
 	}
-	return p.Root.Add(fullPath, data, txid, nil)
+
+	pathLock, controlled := p.parseForControlledPath(effectivePath)
+
+	var pac interface{}
+	var exists bool
+
+	p.Lock()
+	if pac, exists = GetProxyAccessControl().Cache.LoadOrStore(path, NewProxyAccessControl(p, pathLock)); !exists {
+		defer GetProxyAccessControl().Cache.Delete(pathLock)
+	}
+	p.Unlock()
+
+	return pac.(ProxyAccessControl).Add(fullPath, data, txid, controlled)
 }
 
 func (p *Proxy) Remove(path string, txid string) interface{} {
@@ -104,12 +177,27 @@
 		return nil
 	}
 	var fullPath string
+	var effectivePath string
 	if path == "/" {
 		fullPath = p.Path
+		effectivePath = p.FullPath
 	} else {
 		fullPath = p.Path + path
+		effectivePath = p.FullPath + path
 	}
-	return p.Root.Remove(fullPath, txid, nil)
+
+	pathLock, controlled := p.parseForControlledPath(effectivePath)
+
+	var pac interface{}
+	var exists bool
+
+	p.Lock()
+	if pac, exists = GetProxyAccessControl().Cache.LoadOrStore(path, NewProxyAccessControl(p, pathLock)); !exists {
+		defer GetProxyAccessControl().Cache.Delete(pathLock)
+	}
+	p.Unlock()
+
+	return pac.(ProxyAccessControl).Remove(fullPath, txid, controlled)
 }
 
 func (p *Proxy) OpenTransaction() *Transaction {
@@ -199,5 +287,5 @@
 			}
 		}
 	}
-	return context
+	return result
 }
diff --git a/db/model/proxy_access_control.go b/db/model/proxy_access_control.go
new file mode 100644
index 0000000..7f4fad5
--- /dev/null
+++ b/db/model/proxy_access_control.go
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2018-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 model
+
+import (
+	"github.com/opencord/voltha-go/common/log"
+	"runtime/debug"
+	"sync"
+	"time"
+)
+
+type _singletonProxyAccessControl struct {
+	Cache sync.Map
+}
+
+var _instanceProxyAccessControl *_singletonProxyAccessControl
+var _onceProxyAccessControl sync.Once
+
+func GetProxyAccessControl() *_singletonProxyAccessControl {
+	_onceProxyAccessControl.Do(func() {
+		_instanceProxyAccessControl = &_singletonProxyAccessControl{}
+	})
+	return _instanceProxyAccessControl
+}
+
+type ProxyAccessControl interface {
+	Get(path string, depth int, deep bool, txid string, control bool) interface{}
+	Update(path string, data interface{}, strict bool, txid string, control bool) interface{}
+	Add(path string, data interface{}, txid string, control bool) interface{}
+	Remove(path string, txid string, control bool) interface{}
+}
+
+type proxyAccessControl struct {
+	//sync.Mutex
+	Proxy    *Proxy
+	PathLock chan struct{}
+	Path     string
+
+	start time.Time
+	stop  time.Time
+}
+
+func NewProxyAccessControl(proxy *Proxy, path string) ProxyAccessControl {
+	return &proxyAccessControl{
+		Proxy:    proxy,
+		Path:     path,
+		PathLock: make(chan struct{}, 1),
+	}
+}
+
+func (pac *proxyAccessControl) lock() {
+	log.CleanUp()
+	log.Debugf("Before lock ... pac: %+v, stack = %s", pac, string(debug.Stack()))
+	pac.PathLock <- struct{}{}
+	pac.start = time.Now()
+	log.Debugf("Got lock ... pac: %+v, stack = %s", pac, string(debug.Stack()))
+	//time.Sleep(1 * time.Second)
+	log.Debugf("<<<<< %s >>>>>> locked, stack=%s", pac.Path, string(debug.Stack()))
+}
+func (pac *proxyAccessControl) unlock() {
+	log.CleanUp()
+	log.Debugf("Before unlock ... pac: %+v, stack = %s", pac, string(debug.Stack()))
+	<-pac.PathLock
+	pac.stop = time.Now()
+	GetProfiling().AddToInMemoryLockTime(pac.stop.Sub(pac.start).Seconds())
+	log.Debugf("Got unlock ... pac: %+v, stack = %s", pac, string(debug.Stack()))
+	log.Debugf("<<<<< %s >>>>>> unlocked, stack=%s", pac.Path, string(debug.Stack()))
+}
+
+func (pac *proxyAccessControl) Get(path string, depth int, deep bool, txid string, control bool) interface{} {
+	if control {
+		pac.lock()
+		defer pac.unlock()
+		log.Debugf("controlling get, stack = %s", string(debug.Stack()))
+	}
+	pac.Proxy.Root.Proxy = pac.Proxy
+	return pac.Proxy.Root.Get(path, "", depth, deep, txid)
+}
+func (pac *proxyAccessControl) Update(path string, data interface{}, strict bool, txid string, control bool) interface{} {
+	if control {
+		pac.lock()
+		defer pac.unlock()
+		log.Debugf("controlling update, stack = %s", string(debug.Stack()))
+	}
+	pac.Proxy.Root.Proxy = pac.Proxy
+	return pac.Proxy.Root.Update(path, data, strict, txid, nil)
+}
+func (pac *proxyAccessControl) Add(path string, data interface{}, txid string, control bool) interface{} {
+	if control {
+		pac.lock()
+		defer pac.unlock()
+		log.Debugf("controlling add, stack = %s", string(debug.Stack()))
+	}
+	pac.Proxy.Root.Proxy = pac.Proxy
+	return pac.Proxy.Root.Add(path, data, txid, nil)
+}
+func (pac *proxyAccessControl) Remove(path string, txid string, control bool) interface{} {
+	if control {
+		pac.lock()
+		defer pac.unlock()
+		log.Debugf("controlling remove, stack = %s", string(debug.Stack()))
+	}
+	pac.Proxy.Root.Proxy = pac.Proxy
+	return pac.Proxy.Root.Remove(path, txid, nil)
+}
diff --git a/db/model/proxy_concurrency_test.go b/db/model/proxy_concurrency_test.go
new file mode 100644
index 0000000..85d385a
--- /dev/null
+++ b/db/model/proxy_concurrency_test.go
@@ -0,0 +1,456 @@
+/*
+ * Copyright 2018-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 model
+
+import (
+	"encoding/hex"
+	"encoding/json"
+	"github.com/google/uuid"
+	"github.com/opencord/voltha-go/protos/voltha"
+	"reflect"
+	"strconv"
+	"testing"
+)
+
+/*
+
+1. Add device
+2. Do parallel updates of that device
+3. Do parallel gets of that device
+4. Remove device
+
+ */
+
+var (
+	//pctTargetDeviceId string
+	target *voltha.Device
+)
+
+func Test_ConcurrentProxy_1_1_Add_NewDevice(t *testing.T) {
+	devIdBin, _ := uuid.New().MarshalBinary()
+	devId = "0001" + hex.EncodeToString(devIdBin)[:12]
+
+	preAddExecuted := false
+	postAddExecuted := false
+
+	modelTestConfig.RootProxy.RegisterCallback(PRE_ADD, commonCallback, "PRE_ADD instructions", &preAddExecuted)
+	modelTestConfig.RootProxy.RegisterCallback(POST_ADD, commonCallback, "POST_ADD instructions", &postAddExecuted)
+
+	device.Id = devId
+	if added := modelTestConfig.RootProxy.Add("/devices", device, ""); added == nil {
+		t.Error("Failed to add device")
+	} else {
+		t.Logf("Added device : %+v", added)
+	}
+
+	if d := modelTestConfig.RootProxy.Get("/devices/"+devId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+		t.Error("Failed to find added device")
+	} else {
+		djson, _ := json.Marshal(d)
+		t.Logf("Found device: %s", string(djson))
+	}
+
+	//if !preAddExecuted {
+	//	t.Error("PRE_ADD callback was not executed")
+	//}
+	//if !postAddExecuted {
+	//	t.Error("POST_ADD callback was not executed")
+	//}
+}
+
+func Test_ConcurrentProxy_1_Add_ExistingDevice(t *testing.T) {
+	t.Parallel()
+
+	device.Id = devId
+	if added := modelTestConfig.RootProxy.Add("/devices", device, ""); added == nil {
+		t.Logf("Successfully detected that the device already exists: %s", devId)
+	} else {
+		t.Errorf("A new device should not have been created : %+v", added)
+	}
+
+}
+
+func Test_ConcurrentProxy_Get_AllDevices(t *testing.T) {
+	t.Parallel()
+
+	devices := modelTestConfig.RootProxy.Get("/devices", 1, false, "")
+
+	if len(devices.([]interface{})) == 0 {
+		t.Error("there are no available devices to retrieve")
+	} else {
+		t.Logf("retrieved all devices: %+v", devices)
+	}
+}
+
+func Test_ConcurrentProxy_Get_Update_DeviceAdminState(t *testing.T) {
+	t.Parallel()
+	if retrieved := modelTestConfig.RootProxy.Get("/devices/"+devId, 1, false, ""); retrieved == nil {
+		t.Error("Failed to get device")
+	} else {
+		retrieved.(*voltha.Device).AdminState = voltha.AdminState_DISABLED
+
+		preUpdateExecuted := false
+		postUpdateExecuted := false
+
+		modelTestConfig.RootProxy.RegisterCallback(
+			PRE_UPDATE,
+			commonCallback,
+			"PRE_UPDATE instructions (root proxy)", &preUpdateExecuted,
+		)
+		modelTestConfig.RootProxy.RegisterCallback(
+			POST_UPDATE,
+			commonCallback,
+			"POST_UPDATE instructions (root proxy)", &postUpdateExecuted,
+		)
+
+		if afterUpdate := modelTestConfig.RootProxy.Update("/devices/"+devId, retrieved, false, ""); afterUpdate == nil {
+			t.Error("Failed to update device")
+		} else {
+			t.Logf("Updated device : %+v", afterUpdate.(Revision).GetData())
+		}
+		if d := modelTestConfig.RootProxy.Get("/devices/"+devId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+			t.Error("Failed to find updated device (root proxy)")
+		} else {
+			djson, _ := json.Marshal(d)
+			t.Logf("Found device (root proxy): %s", string(djson))
+		}
+
+		//if !preUpdateExecuted {
+		//	t.Error("PRE_UPDATE callback was not executed")
+		//}
+		//if !postUpdateExecuted {
+		//	t.Error("POST_UPDATE callback was not executed")
+		//}
+	}
+}
+
+func Test_ConcurrentProxy_Get_SingleDevice(t *testing.T) {
+	//t.Parallel()
+
+	if d := modelTestConfig.RootProxy.Get("/devices/"+devId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+		t.Errorf("Failed to find device : %s", devId)
+	} else {
+		djson, _ := json.Marshal(d)
+		t.Logf("Found device: %s", string(djson))
+	}
+
+}
+
+func Test_ConcurrentProxy_Get_SingleDeviceFlows(t *testing.T) {
+	t.Parallel()
+
+	if d := modelTestConfig.RootProxy.Get("/devices/"+devId+"/flows", 0, false, ""); !reflect.ValueOf(d).IsValid() {
+		t.Errorf("Failed to find device : %s", devId)
+	} else {
+		djson, _ := json.Marshal(d)
+		t.Logf("Found device: %s", string(djson))
+	}
+
+}
+
+func Test_ConcurrentProxy_Get_SingleDevicePorts(t *testing.T) {
+	t.Parallel()
+	if d := modelTestConfig.RootProxy.Get("/devices/"+devId+"/ports", 0, false, ""); !reflect.ValueOf(d).IsValid() {
+		t.Errorf("Failed to find device : %s", devId)
+	} else {
+		djson, _ := json.Marshal(d)
+		t.Logf("Found device: %s", string(djson))
+	}
+
+}
+
+func Test_ConcurrentProxy_Get_Update_DeviceFirmware(t *testing.T) {
+	t.Parallel()
+
+	if retrieved := modelTestConfig.RootProxy.Get("/devices/"+devId, 1, false, ""); retrieved == nil {
+		t.Error("Failed to get device")
+	} else {
+		var fwVersion int
+		if retrieved.(*voltha.Device).FirmwareVersion == "n/a" {
+			fwVersion = 0
+		} else {
+			fwVersion, _ = strconv.Atoi(retrieved.(*voltha.Device).FirmwareVersion)
+			fwVersion += 1
+		}
+
+		preUpdateExecuted := false
+		postUpdateExecuted := false
+
+		modelTestConfig.RootProxy.RegisterCallback(
+			PRE_UPDATE,
+			commonCallback,
+			"PRE_UPDATE instructions (root proxy)", &preUpdateExecuted,
+		)
+		modelTestConfig.RootProxy.RegisterCallback(
+			POST_UPDATE,
+			commonCallback,
+			"POST_UPDATE instructions (root proxy)", &postUpdateExecuted,
+		)
+
+		retrieved.(*voltha.Device).FirmwareVersion = strconv.Itoa(fwVersion)
+
+		if afterUpdate := modelTestConfig.RootProxy.Update("/devices/"+devId, retrieved, false, ""); afterUpdate == nil {
+			t.Error("Failed to update device")
+		} else {
+			t.Logf("Updated device : %+v", afterUpdate.(Revision).GetData())
+		}
+		if d := modelTestConfig.RootProxy.Get("/devices/"+devId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+			t.Error("Failed to find updated device (root proxy)")
+		} else {
+			djson, _ := json.Marshal(d)
+			t.Logf("Found device (root proxy): %s", string(djson))
+		}
+
+		//if !preUpdateExecuted {
+		//	t.Error("PRE_UPDATE callback was not executed")
+		//}
+		//if !postUpdateExecuted {
+		//	t.Error("POST_UPDATE callback was not executed")
+		//}
+	}
+}
+
+//func Test_ConcurrentProxy_Get_Update_DeviceFlows(t *testing.T) {
+//	t.Parallel()
+//
+//	// Get a device proxy and update a specific port
+//	//devflowsProxy := modelTestConfig.Root.GetProxy("/devices/"+devId+"/flows", false)
+//	flows := modelTestConfig.RootProxy.Get("/", 0, false, "")
+//	flows.([]interface{})[0].(*openflow_13.Flows).Items[0].TableId = 2244
+//
+//	preUpdateExecuted := false
+//	postUpdateExecuted := false
+//
+//	modelTestConfig.RootProxy.RegisterCallback(
+//		PRE_UPDATE,
+//		commonCallback,
+//		"PRE_UPDATE instructions (flows proxy)", &preUpdateExecuted,
+//	)
+//	modelTestConfig.RootProxy.RegisterCallback(
+//		POST_UPDATE,
+//		commonCallback,
+//		"POST_UPDATE instructions (flows proxy)", &postUpdateExecuted,
+//	)
+//
+//	kvFlows := modelTestConfig.RootProxy.Get("/devices/"+devId+"/flows", 0, false, "")
+//
+//	if reflect.DeepEqual(flows, kvFlows) {
+//		t.Errorf("Local changes have changed the KV store contents -  local:%+v, kv: %+v", flows, kvFlows)
+//	}
+//
+//	if updated := modelTestConfig.RootProxy.Update("/devices/"+devId+"/flows", flows.([]interface{})[0], false, ""); updated == nil {
+//		t.Error("Failed to update flow")
+//	} else {
+//		t.Logf("Updated flows : %+v", updated)
+//	}
+//
+//	if d := modelTestConfig.RootProxy.Get("/devices/"+devId+"/flows", 0, false, ""); d == nil {
+//		t.Error("Failed to find updated flows (flows proxy)")
+//	} else {
+//		djson, _ := json.Marshal(d)
+//		t.Logf("Found flows (flows proxy): %s", string(djson))
+//	}
+//
+//	if d := modelTestConfig.RootProxy.Get("/devices/"+devId+"/flows", 0, false, ""); !reflect.ValueOf(d).IsValid() {
+//		t.Error("Failed to find updated flows (root proxy)")
+//	} else {
+//		djson, _ := json.Marshal(d)
+//		t.Logf("Found flows (root proxy): %s", string(djson))
+//	}
+//
+//	//if !preUpdateExecuted {
+//	//	t.Error("PRE_UPDATE callback was not executed")
+//	//}
+//	//if !postUpdateExecuted {
+//	//	t.Error("POST_UPDATE callback was not executed")
+//	//}
+//}
+
+//func Test_ConcurrentProxy_4_1_Remove_Device(t *testing.T) {
+//	preRemoveExecuted := false
+//	postRemoveExecuted := false
+//
+//	modelTestConfig.RootProxy.RegisterCallback(
+//		PRE_REMOVE,
+//		commonCallback,
+//		"PRE_REMOVE instructions (root proxy)", &preRemoveExecuted,
+//	)
+//	modelTestConfig.RootProxy.RegisterCallback(
+//		POST_REMOVE,
+//		commonCallback,
+//		"POST_REMOVE instructions (root proxy)", &postRemoveExecuted,
+//	)
+//
+//	if removed := modelTestConfig.RootProxy.Remove("/devices/"+devId, ""); removed == nil {
+//		t.Error("Failed to remove device")
+//	} else {
+//		t.Logf("Removed device : %+v", removed)
+//	}
+//	if d := modelTestConfig.RootProxy.Get("/devices/"+devId, 0, false, ""); reflect.ValueOf(d).IsValid() {
+//		djson, _ := json.Marshal(d)
+//		t.Errorf("Device was not removed - %s", djson)
+//	} else {
+//		t.Logf("Device was removed: %s", devId)
+//	}
+//
+//	if !preRemoveExecuted {
+//		t.Error("PRE_UPDATE callback was not executed")
+//	}
+//	if !postRemoveExecuted {
+//		t.Error("POST_UPDATE callback was not executed")
+//	}
+//}
+
+//func Benchmark_ConcurrentProxy_UpdateFirmware(b *testing.B) {
+//	//var target *voltha.Device
+//	if target == nil {
+//		devices := modelTestConfig.RootProxy.Get("/devices", 1, false, "")
+//		if len(devices.([]interface{})) == 0 {
+//			b.Error("there are no available devices to retrieve")
+//		} else {
+//			// Save the target device id for later tests
+//			target = devices.([]interface{})[0].(*voltha.Device)
+//			//b.Logf("retrieved all devices: %+v", devices)
+//		}
+//	}
+//
+//	for n := 0; n < b.N; n++ {
+//		var fwVersion int
+//
+//		if target.FirmwareVersion == "n/a" {
+//			fwVersion = 0
+//		} else {
+//			fwVersion, _ = strconv.Atoi(target.FirmwareVersion)
+//			fwVersion += 1
+//		}
+//
+//		target.FirmwareVersion = strconv.Itoa(fwVersion)
+//
+//		if afterUpdate := modelTestConfig.RootProxy.Update("/devices/"+target.Id, target, false,
+//			""); afterUpdate == nil {
+//			b.Error("Failed to update device")
+//		} else {
+//			if d := modelTestConfig.RootProxy.Get("/devices/"+target.Id, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+//				b.Errorf("Failed to find device : %s", devId)
+//			} else {
+//				//djson, _ := json.Marshal(d)
+//				//b.Logf("Checking updated device device: %s", string(djson))
+//			}
+//		}
+//	}
+//
+//}
+//
+//func Benchmark_ConcurrentProxy_GetDevice(b *testing.B) {
+//	if target == nil {
+//		//var target *voltha.Device
+//		devices := modelTestConfig.RootProxy.Get("/devices", 1, false, "")
+//		if len(devices.([]interface{})) == 0 {
+//			b.Error("there are no available devices to retrieve")
+//		} else {
+//			// Save the target device id for later tests
+//			target = devices.([]interface{})[0].(*voltha.Device)
+//			//b.Logf("retrieved all devices: %+v", devices)
+//		}
+//	}
+//
+//	for n := 0; n < b.N; n++ {
+//		if d := modelTestConfig.RootProxy.Get("/devices/"+target.Id, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+//			b.Errorf("Failed to find device : %s", devId)
+//		} else {
+//			//djson, _ := json.Marshal(d)
+//			//b.Logf("Found device: %s", string(djson))
+//		}
+//	}
+//
+//}
+
+func Benchmark_ConcurrentProxy_UpdateFirmware(b *testing.B) {
+	//GetProfiling().Reset()
+	defer GetProfiling().Report()
+	//b.SetParallelism(100)
+	if target == nil {
+		devices := modelTestConfig.RootProxy.Get("/devices", 1, false, "")
+		if len(devices.([]interface{})) == 0 {
+			b.Error("there are no available devices to retrieve")
+		} else {
+			// Save the target device id for later tests
+			target = devices.([]interface{})[0].(*voltha.Device)
+			//b.Logf("retrieved all devices: %+v", devices)
+		}
+	}
+
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			var fwVersion int
+
+			if target.FirmwareVersion == "n/a" {
+				fwVersion = 0
+			} else {
+				fwVersion, _ = strconv.Atoi(target.FirmwareVersion)
+				fwVersion += 1
+			}
+
+			target.FirmwareVersion = strconv.Itoa(fwVersion)
+
+			if afterUpdate := modelTestConfig.RootProxy.Update("/devices/"+target.Id, target, false,
+				""); afterUpdate == nil {
+				b.Error("Failed to update device")
+			} else {
+				if d := modelTestConfig.RootProxy.Get("/devices/"+target.Id, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+					b.Errorf("Failed to find device : %s", devId)
+				} else if d.(*voltha.Device).FirmwareVersion != target.FirmwareVersion {
+					b.Errorf("Firmware was not uptaded - expected: %s, actual: %s",
+						target.FirmwareVersion,
+						d.(*voltha.Device).FirmwareVersion,
+					)
+				} else {
+					b.Logf("Firmware is now : %s", d.(*voltha.Device).FirmwareVersion)
+					//djson, _ := json.Marshal(d)
+					//b.Logf("Checking updated device device: %s", string(djson))
+				}
+			}
+		}
+	})
+}
+
+func Benchmark_ConcurrentProxy_GetDevice(b *testing.B) {
+	//GetProfiling().Reset()
+	defer GetProfiling().Report()
+	//b.SetParallelism(5)
+	if target == nil {
+		//var target *voltha.Device
+		devices := modelTestConfig.RootProxy.Get("/devices", 1, false, "")
+		if len(devices.([]interface{})) == 0 {
+			b.Error("there are no available devices to retrieve")
+		} else {
+			// Save the target device id for later tests
+			target = devices.([]interface{})[0].(*voltha.Device)
+			//b.Logf("retrieved all devices: %+v", devices)
+		}
+	}
+
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			if d := modelTestConfig.RootProxy.Get("/devices/"+target.Id, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+				b.Errorf("Failed to find device : %s", devId)
+			} else {
+				//djson, _ := json.Marshal(d)
+				//b.Logf("Found device: %s", string(djson))
+			}
+		}
+	})
+}
diff --git a/db/model/proxy_test.go b/db/model/proxy_test.go
index 6226caa..2d831c1 100644
--- a/db/model/proxy_test.go
+++ b/db/model/proxy_test.go
@@ -19,118 +19,34 @@
 	"encoding/hex"
 	"encoding/json"
 	"github.com/google/uuid"
-	"github.com/opencord/voltha-go/common/log"
-	"github.com/opencord/voltha-go/protos/common"
-	"github.com/opencord/voltha-go/protos/openflow_13"
 	"github.com/opencord/voltha-go/protos/voltha"
+	"github.com/opencord/voltha-go/protos/openflow_13"
 	"reflect"
 	"strconv"
 	"testing"
 )
 
-type proxyTest struct {
-	Root      *root
-	Backend   *Backend
-	Proxy     *Proxy
-	DbPrefix  string
-	DbType    string
-	DbHost    string
-	DbPort    int
-	DbTimeout int
-}
-
 var (
-	pt = &proxyTest{
-		DbPrefix: "service/voltha/data/core/0001",
-		DbType:   "etcd",
-		//DbHost:    "10.102.58.0",
-		DbHost:    "localhost",
-		DbPort:    2379,
-		DbTimeout: 5,
-	}
-	ports = []*voltha.Port{
-		{
-			PortNo:     123,
-			Label:      "test-port-0",
-			Type:       voltha.Port_PON_OLT,
-			AdminState: common.AdminState_ENABLED,
-			OperStatus: common.OperStatus_ACTIVE,
-			DeviceId:   "etcd_port-0-device-id",
-			Peers:      []*voltha.Port_PeerPort{},
-		},
-	}
-
-	stats = &openflow_13.OfpFlowStats{
-		Id: 1111,
-	}
-	flows = &openflow_13.Flows{
-		Items: []*openflow_13.OfpFlowStats{stats},
-	}
-	device = &voltha.Device{
-		Id:         devId,
-		Type:       "simulated_olt",
-		Address:    &voltha.Device_HostAndPort{HostAndPort: "1.2.3.4:5555"},
-		AdminState: voltha.AdminState_PREPROVISIONED,
-		Flows:      flows,
-		Ports:      ports,
-	}
-	devId          string
-	targetDeviceId string
-
-	preAddExecuted      = false
-	postAddExecuted     = false
-	preUpdateExecuted   = false
-	postUpdateExecuted  = false
-	preRemoveExecuted   = false
-	postRemoveExecuted = false
 )
 
-func init() {
-	log.AddPackage(log.JSON, log.DebugLevel, nil)
-	log.UpdateAllLoggers(log.Fields{"instanceId": "proxy_test"})
-
-	defer log.CleanUp()
-
-	pt.Backend = NewBackend(pt.DbType, pt.DbHost, pt.DbPort, pt.DbTimeout, pt.DbPrefix)
-
-	msgClass := &voltha.Voltha{}
-	root := NewRoot(msgClass, pt.Backend)
-	pt.Root = root.Load(msgClass)
-
-	GetProfiling().Report()
-
-	pt.Proxy = pt.Root.GetProxy("/", false)
-}
-
-func commonCallback(args ...interface{}) interface{} {
-	log.Infof("Running common callback - arg count: %s", len(args))
-
-	for i := 0; i < len(args); i++ {
-		log.Infof("ARG %d : %+v", i, args[i])
-	}
-	execStatus := args[1].(*bool)
-
-	// Inform the caller that the callback was executed
-	*execStatus = true
-
-	return nil
-}
-
 func Test_Proxy_1_1_Add_NewDevice(t *testing.T) {
 	devIdBin, _ := uuid.New().MarshalBinary()
 	devId = "0001" + hex.EncodeToString(devIdBin)[:12]
 
-	pt.Proxy.RegisterCallback(PRE_ADD, commonCallback, "PRE_ADD instructions", &preAddExecuted)
-	pt.Proxy.RegisterCallback(POST_ADD, commonCallback, "POST_ADD instructions", &postAddExecuted)
+	preAddExecuted := false
+	postAddExecuted := false
+
+	modelTestConfig.RootProxy.RegisterCallback(PRE_ADD, commonCallback, "PRE_ADD instructions", &preAddExecuted)
+	modelTestConfig.RootProxy.RegisterCallback(POST_ADD, commonCallback, "POST_ADD instructions", &postAddExecuted)
 
 	device.Id = devId
-	if added := pt.Proxy.Add("/devices", device, ""); added == nil {
+	if added := modelTestConfig.RootProxy.Add("/devices", device, ""); added == nil {
 		t.Error("Failed to add device")
 	} else {
 		t.Logf("Added device : %+v", added)
 	}
 
-	if d := pt.Proxy.Get("/devices/"+devId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+	if d := modelTestConfig.RootProxy.Get("/devices/"+devId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
 		t.Error("Failed to find added device")
 	} else {
 		djson, _ := json.Marshal(d)
@@ -147,7 +63,7 @@
 
 func Test_Proxy_1_2_Add_ExistingDevice(t *testing.T) {
 	device.Id = devId
-	if added := pt.Proxy.Add("/devices", device, ""); added == nil {
+	if added := modelTestConfig.RootProxy.Add("/devices", device, ""); added == nil {
 		t.Logf("Successfully detected that the device already exists: %s", devId)
 	} else {
 		t.Errorf("A new device should not have been created : %+v", added)
@@ -156,7 +72,7 @@
 }
 
 func Test_Proxy_2_1_Get_AllDevices(t *testing.T) {
-	devices := pt.Proxy.Get("/devices", 1, false, "")
+	devices := modelTestConfig.RootProxy.Get("/devices", 1, false, "")
 
 	if len(devices.([]interface{})) == 0 {
 		t.Error("there are no available devices to retrieve")
@@ -168,7 +84,7 @@
 }
 
 func Test_Proxy_2_2_Get_SingleDevice(t *testing.T) {
-	if d := pt.Proxy.Get("/devices/"+targetDeviceId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+	if d := modelTestConfig.RootProxy.Get("/devices/"+targetDeviceId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
 		t.Errorf("Failed to find device : %s", targetDeviceId)
 	} else {
 		djson, _ := json.Marshal(d)
@@ -178,9 +94,11 @@
 }
 
 func Test_Proxy_3_1_Update_Device_WithRootProxy(t *testing.T) {
-	if retrieved := pt.Proxy.Get("/devices/"+targetDeviceId, 1, false, ""); retrieved == nil {
+	if retrieved := modelTestConfig.RootProxy.Get("/devices/"+targetDeviceId, 1, false, ""); retrieved == nil {
 		t.Error("Failed to get device")
 	} else {
+		t.Logf("Found raw device (root proxy): %+v", retrieved)
+
 		var fwVersion int
 		if retrieved.(*voltha.Device).FirmwareVersion == "n/a" {
 			fwVersion = 0
@@ -189,15 +107,15 @@
 			fwVersion += 1
 		}
 
-		preUpdateExecuted = false
-		postUpdateExecuted = false
+		preUpdateExecuted := false
+		postUpdateExecuted := false
 
-		pt.Proxy.RegisterCallback(
+		modelTestConfig.RootProxy.RegisterCallback(
 			PRE_UPDATE,
 			commonCallback,
 			"PRE_UPDATE instructions (root proxy)", &preUpdateExecuted,
 		)
-		pt.Proxy.RegisterCallback(
+		modelTestConfig.RootProxy.RegisterCallback(
 			POST_UPDATE,
 			commonCallback,
 			"POST_UPDATE instructions (root proxy)", &postUpdateExecuted,
@@ -208,16 +126,17 @@
 		retrieved.(*voltha.Device).FirmwareVersion = strconv.Itoa(fwVersion)
 		//t.Logf("Before update : %+v", cloned)
 
-		if afterUpdate := pt.Proxy.Update("/devices/"+targetDeviceId, retrieved, false, ""); afterUpdate == nil {
+		if afterUpdate := modelTestConfig.RootProxy.Update("/devices/"+targetDeviceId, retrieved, false, ""); afterUpdate == nil {
 			t.Error("Failed to update device")
 		} else {
 			t.Logf("Updated device : %+v", afterUpdate.(Revision).GetData())
 		}
-		if d := pt.Proxy.Get("/devices/"+targetDeviceId, 0, false, ""); !reflect.ValueOf(d).IsValid() {
+		if d := modelTestConfig.RootProxy.Get("/devices/"+targetDeviceId, 1, false, ""); !reflect.ValueOf(d).IsValid() {
 			t.Error("Failed to find updated device (root proxy)")
 		} else {
 			djson, _ := json.Marshal(d)
-			t.Logf("Found device (root proxy): %s", string(djson))
+
+			t.Logf("Found device (root proxy): %s raw: %+v", string(djson), d)
 		}
 
 		if !preUpdateExecuted {
@@ -231,20 +150,20 @@
 
 func Test_Proxy_3_2_Update_Flow_WithSubProxy(t *testing.T) {
 	// Get a device proxy and update a specific port
-	devflowsProxy := pt.Root.GetProxy("/devices/"+devId+"/flows", false)
+	devflowsProxy := modelTestConfig.Root.GetProxy("/devices/"+devId+"/flows", false)
 	flows := devflowsProxy.Get("/", 0, false, "")
 	//flows.([]interface{})[0].(*openflow_13.Flows).Items[0].TableId = 2222
-	flows.([]interface{})[0].(*openflow_13.Flows).Items[0].TableId = 2244
-	//flows.(*openflow_13.Flows).Items[0].TableId = 2244
+	//flows.([]interface{})[0].(*openflow_13.Flows).Items[0].TableId = 2244
+	flows.(*openflow_13.Flows).Items[0].TableId = 2244
 	t.Logf("before updated flows: %+v", flows)
 
-	//devPortsProxy := pt.Root.node.GetProxy("/devices/"+devId+"/ports", false)
+	//devPortsProxy := modelTestConfig.RootProxy.node.GetProxy("/devices/"+devId+"/ports", false)
 	//port123 := devPortsProxy.Get("/123", 0, false, "")
 	//t.Logf("got ports: %+v", port123)
 	//port123.(*voltha.Port).OperStatus = common.OperStatus_DISCOVERED
 
-	preUpdateExecuted = false
-	postUpdateExecuted = false
+	preUpdateExecuted := false
+	postUpdateExecuted := false
 
 	devflowsProxy.RegisterCallback(
 		PRE_UPDATE,
@@ -263,7 +182,7 @@
 		t.Errorf("Local changes have changed the KV store contents -  local:%+v, kv: %+v", flows, kvFlows)
 	}
 
-	if updated := devflowsProxy.Update("/", flows.([]interface{})[0], false, ""); updated == nil {
+	if updated := devflowsProxy.Update("/", flows.(*openflow_13.Flows), false, ""); updated == nil {
 		t.Error("Failed to update flow")
 	} else {
 		t.Logf("Updated flows : %+v", updated)
@@ -276,7 +195,7 @@
 		t.Logf("Found flows (flows proxy): %s", string(djson))
 	}
 
-	if d := pt.Proxy.Get("/devices/"+devId+"/flows", 0, false, ""); !reflect.ValueOf(d).IsValid() {
+	if d := modelTestConfig.RootProxy.Get("/devices/"+devId+"/flows", 0, false, ""); !reflect.ValueOf(d).IsValid() {
 		t.Error("Failed to find updated flows (root proxy)")
 	} else {
 		djson, _ := json.Marshal(d)
@@ -289,11 +208,11 @@
 	if !postUpdateExecuted {
 		t.Error("POST_UPDATE callback was not executed")
 	}
-	//
-	// Get a device proxy and update all its ports
-	//
 
-	//devProxy := pt.Root.GetProxy("/devices/"+devId, false)
+	//Get a device proxy and update all its ports
+
+
+	//devProxy := modelTestConfig.RootProxy.GetProxy("/devices/"+devId, false)
 	//ports := devProxy.Get("/ports", 0, false, "")
 	//t.Logf("got ports: %+v", ports)
 	//devProxy.RegisterCallback(POST_UPDATE, commonCallback, nil)
@@ -308,7 +227,7 @@
 	// Get a device proxy, retrieve all the ports and update a specific one
 	//
 
-	//devProxy := pt.Root.GetProxy("/devices/"+devId, false)
+	//devProxy := modelTestConfig.RootProxy.GetProxy("/devices/"+devId, false)
 	//ports := devProxy.Get("/ports", 0, false, "")
 	//t.Logf("got ports: %+v", ports)
 	//devProxy.RegisterCallback(POST_UPDATE, commonCallback, nil)
@@ -321,26 +240,26 @@
 }
 
 func Test_Proxy_4_1_Remove_Device(t *testing.T) {
-	preRemoveExecuted = false
-	postRemoveExecuted = false
+	preRemoveExecuted := false
+	postRemoveExecuted := false
 
-	pt.Proxy.RegisterCallback(
+	modelTestConfig.RootProxy.RegisterCallback(
 		PRE_REMOVE,
 		commonCallback,
 		"PRE_REMOVE instructions (root proxy)", &preRemoveExecuted,
 	)
-	pt.Proxy.RegisterCallback(
+	modelTestConfig.RootProxy.RegisterCallback(
 		POST_REMOVE,
 		commonCallback,
 		"POST_REMOVE instructions (root proxy)", &postRemoveExecuted,
 	)
 
-	if removed := pt.Proxy.Remove("/devices/"+devId, ""); removed == nil {
+	if removed := modelTestConfig.RootProxy.Remove("/devices/"+devId, ""); removed == nil {
 		t.Error("Failed to remove device")
 	} else {
 		t.Logf("Removed device : %+v", removed)
 	}
-	if d := pt.Proxy.Get("/devices/"+devId, 0, false, ""); reflect.ValueOf(d).IsValid() {
+	if d := modelTestConfig.RootProxy.Get("/devices/"+devId, 0, false, ""); reflect.ValueOf(d).IsValid() {
 		djson, _ := json.Marshal(d)
 		t.Errorf("Device was not removed - %s", djson)
 	} else {
@@ -359,56 +278,35 @@
 // Callback tests
 // -----------------------------
 
-func firstCallback(args ...interface{}) interface{} {
-	name := args[0]
-	id := args[1]
-	log.Infof("Running first callback - name: %s, id: %s\n", name, id)
-	return nil
-}
-func secondCallback(args ...interface{}) interface{} {
-	name := args[0].(map[string]string)
-	id := args[1]
-	log.Infof("Running second callback - name: %s, id: %f\n", name["name"], id)
-	// FIXME: the panic call seem to interfere with the logging mechanism
-	//panic("Generating a panic in second callback")
-	return nil
-}
-func thirdCallback(args ...interface{}) interface{} {
-	name := args[0]
-	id := args[1].(*voltha.Device)
-	log.Infof("Running third callback - name: %+v, id: %s\n", name, id.Id)
-	return nil
-}
-
 func Test_Proxy_Callbacks_1_Register(t *testing.T) {
-	pt.Proxy.RegisterCallback(PRE_ADD, firstCallback, "abcde", "12345")
+	modelTestConfig.RootProxy.RegisterCallback(PRE_ADD, firstCallback, "abcde", "12345")
 
 	m := make(map[string]string)
 	m["name"] = "fghij"
-	pt.Proxy.RegisterCallback(PRE_ADD, secondCallback, m, 1.2345)
+	modelTestConfig.RootProxy.RegisterCallback(PRE_ADD, secondCallback, m, 1.2345)
 
 	d := &voltha.Device{Id: "12345"}
-	pt.Proxy.RegisterCallback(PRE_ADD, thirdCallback, "klmno", d)
+	modelTestConfig.RootProxy.RegisterCallback(PRE_ADD, thirdCallback, "klmno", d)
 }
 
 func Test_Proxy_Callbacks_2_Invoke_WithNoInterruption(t *testing.T) {
-	pt.Proxy.InvokeCallbacks(PRE_ADD, false, nil)
+	modelTestConfig.RootProxy.InvokeCallbacks(PRE_ADD, false, nil)
 }
 
 func Test_Proxy_Callbacks_3_Invoke_WithInterruption(t *testing.T) {
-	pt.Proxy.InvokeCallbacks(PRE_ADD, true, nil)
+	modelTestConfig.RootProxy.InvokeCallbacks(PRE_ADD, true, nil)
 }
 
 func Test_Proxy_Callbacks_4_Unregister(t *testing.T) {
-	pt.Proxy.UnregisterCallback(PRE_ADD, firstCallback)
-	pt.Proxy.UnregisterCallback(PRE_ADD, secondCallback)
-	pt.Proxy.UnregisterCallback(PRE_ADD, thirdCallback)
+	modelTestConfig.RootProxy.UnregisterCallback(PRE_ADD, firstCallback)
+	modelTestConfig.RootProxy.UnregisterCallback(PRE_ADD, secondCallback)
+	modelTestConfig.RootProxy.UnregisterCallback(PRE_ADD, thirdCallback)
 }
 
 //func Test_Proxy_Callbacks_5_Add(t *testing.T) {
-//	pt.Proxy.Root.AddCallback(pt.Proxy.InvokeCallbacks, POST_UPDATE, false, "some data", "some new data")
+//	modelTestConfig.RootProxy.Root.AddCallback(modelTestConfig.RootProxy.InvokeCallbacks, POST_UPDATE, false, "some data", "some new data")
 //}
 //
 //func Test_Proxy_Callbacks_6_Execute(t *testing.T) {
-//	pt.Proxy.Root.ExecuteCallbacks()
+//	modelTestConfig.RootProxy.Root.ExecuteCallbacks()
 //}
diff --git a/db/model/transaction_test.go b/db/model/transaction_test.go
index a490acd..7b438b2 100644
--- a/db/model/transaction_test.go
+++ b/db/model/transaction_test.go
@@ -18,7 +18,6 @@
 import (
 	"encoding/hex"
 	"github.com/google/uuid"
-	"github.com/opencord/voltha-go/common/log"
 	"github.com/opencord/voltha-go/protos/common"
 	"github.com/opencord/voltha-go/protos/voltha"
 	"reflect"
@@ -26,54 +25,13 @@
 	"testing"
 )
 
-type transactionTest struct {
-	Root      *root
-	Backend   *Backend
-	Proxy     *Proxy
-	DbPrefix  string
-	DbType    string
-	DbHost    string
-	DbPort    int
-	DbTimeout int
-}
-
 var (
-	tx = &transactionTest{
-		DbPrefix: "service/voltha/data/core/0001",
-		DbType:   "etcd",
-		//DbHost:    "10.102.58.0",
-		DbHost:    "localhost",
-		DbPort:    2379,
-		DbTimeout: 5,
-	}
 	txTargetDevId string
 	txDevId       string
 )
 
-func init() {
-	log.AddPackage(log.JSON, log.DebugLevel, nil)
-	log.UpdateAllLoggers(log.Fields{"instanceId": "transaction_test"})
-
-	defer log.CleanUp()
-
-	tx.Backend = NewBackend(tx.DbType, tx.DbHost, tx.DbPort, tx.DbTimeout, tx.DbPrefix)
-
-	msgClass := &voltha.Voltha{}
-	root := NewRoot(msgClass, tx.Backend)
-
-	if tx.Backend != nil {
-		tx.Root = root.Load(msgClass)
-	} else {
-		tx.Root = root
-	}
-
-	GetProfiling().Report()
-
-	tx.Proxy = tx.Root.GetProxy("/", false)
-}
-
 func Test_Transaction_1_GetDevices(t *testing.T) {
-	getTx := tx.Proxy.OpenTransaction()
+	getTx := modelTestConfig.RootProxy.OpenTransaction()
 
 	devices := getTx.Get("/devices", 1, false)
 
@@ -112,7 +70,7 @@
 		Ports:      ports,
 	}
 
-	addTx := tx.Proxy.OpenTransaction()
+	addTx := modelTestConfig.RootProxy.OpenTransaction()
 
 	if added := addTx.Add("/devices", device); added == nil {
 		t.Error("Failed to add device")
@@ -126,12 +84,12 @@
 
 	basePath := "/devices/" + txDevId
 
-	getDevWithPortsTx := tx.Proxy.OpenTransaction()
+	getDevWithPortsTx := modelTestConfig.RootProxy.OpenTransaction()
 	device1 := getDevWithPortsTx.Get(basePath+"/ports", 1, false)
 	t.Logf("retrieved device with ports: %+v", device1)
 	getDevWithPortsTx.Commit()
 
-	getDevTx := tx.Proxy.OpenTransaction()
+	getDevTx := modelTestConfig.RootProxy.OpenTransaction()
 	device2 := getDevTx.Get(basePath, 0, false)
 	t.Logf("retrieved device: %+v", device2)
 
@@ -139,7 +97,7 @@
 }
 
 func Test_Transaction_4_UpdateDevice(t *testing.T) {
-	updateTx := tx.Proxy.OpenTransaction()
+	updateTx := modelTestConfig.RootProxy.OpenTransaction()
 	if retrieved := updateTx.Get("/devices/"+txTargetDevId, 1, false); retrieved == nil {
 		t.Error("Failed to get device")
 	} else {
@@ -169,12 +127,12 @@
 
 	basePath := "/devices/" + txDevId
 
-	getDevWithPortsTx := tx.Proxy.OpenTransaction()
+	getDevWithPortsTx := modelTestConfig.RootProxy.OpenTransaction()
 	device1 := getDevWithPortsTx.Get(basePath+"/ports", 1, false)
 	t.Logf("retrieved device with ports: %+v", device1)
 	getDevWithPortsTx.Commit()
 
-	getDevTx := tx.Proxy.OpenTransaction()
+	getDevTx := modelTestConfig.RootProxy.OpenTransaction()
 	device2 := getDevTx.Get(basePath, 0, false)
 	t.Logf("retrieved device: %+v", device2)
 
@@ -182,7 +140,7 @@
 }
 
 func Test_Transaction_6_RemoveDevice(t *testing.T) {
-	removeTx := tx.Proxy.OpenTransaction()
+	removeTx := modelTestConfig.RootProxy.OpenTransaction()
 	if removed := removeTx.Remove("/devices/" + txDevId); removed == nil {
 		t.Error("Failed to remove device")
 	} else {
@@ -195,8 +153,8 @@
 
 	basePath := "/devices/" + txDevId
 
-	getDevTx := tx.Proxy.OpenTransaction()
-	device := tx.Proxy.Get(basePath, 0, false, "")
+	getDevTx := modelTestConfig.RootProxy.OpenTransaction()
+	device := modelTestConfig.RootProxy.Get(basePath, 0, false, "")
 	t.Logf("retrieved device: %+v", device)
 
 	getDevTx.Commit()