[VOL-2254] Fix for unit test failing

Change-Id: I646fc9865c096c65b7d0660b1654955d55ba3951
diff --git a/VERSION b/VERSION
index ed1fc35..2653fe5 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.2.16
+2.2.16-dev
diff --git a/go.mod b/go.mod
index 9d74066..47305f7 100644
--- a/go.mod
+++ b/go.mod
@@ -26,6 +26,7 @@
 	github.com/jcmturner/gofork v1.0.0 // indirect
 	github.com/onsi/gomega v1.4.2 // indirect
 	github.com/opencord/voltha-protos/v2 v2.0.1
+	github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
 	github.com/pierrec/lz4 v2.3.0+incompatible // indirect
 	github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 // indirect
 	github.com/spf13/pflag v1.0.3 // indirect
diff --git a/go.sum b/go.sum
index 87fec72..79e5afb 100644
--- a/go.sum
+++ b/go.sum
@@ -193,6 +193,8 @@
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
+github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
 github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
 github.com/pierrec/lz4 v2.3.0+incompatible h1:CZzRn4Ut9GbUkHlQ7jqBXeZQV41ZSKWFc302ZU6lUTk=
 github.com/pierrec/lz4 v2.3.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
diff --git a/pkg/db/backend_test.go b/pkg/db/backend_test.go
index 3e1dce3..5629355 100644
--- a/pkg/db/backend_test.go
+++ b/pkg/db/backend_test.go
@@ -20,6 +20,7 @@
 	"context"
 	"github.com/opencord/voltha-lib-go/v2/pkg/log"
 	"github.com/opencord/voltha-lib-go/v2/pkg/mocks"
+	"github.com/phayes/freeport"
 	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
@@ -34,15 +35,30 @@
 
 const (
 	embedEtcdServerHost = "localhost"
-	embedEtcdServerPort = 2379
-	dummyEtcdServerPort = 12379
 	defaultTimeout      = 1
 	defaultPathPrefix   = "Prefix"
 )
 
-func TestMain(m *testing.M) {
-	etcdServer := mocks.StartEtcdServer(nil)
+var (
+	embedEtcdServerPort int
+	dummyEtcdServerPort int
+)
 
+func TestMain(m *testing.M) {
+	var err error
+	embedEtcdServerPort, err = freeport.GetFreePort()
+	if err != nil {
+		log.Fatal(err)
+	}
+	dummyEtcdServerPort, err = freeport.GetFreePort()
+	if err != nil {
+		log.Fatal(err)
+	}
+	peerPort, err := freeport.GetFreePort()
+	if err != nil {
+		log.Fatal(err)
+	}
+	etcdServer := mocks.StartEtcdServer(mocks.MKConfig("voltha.db.test", embedEtcdServerPort, peerPort, "voltha.lib.db", "error"))
 	res := m.Run()
 
 	etcdServer.Stop()
diff --git a/pkg/mocks/etcd_server.go b/pkg/mocks/etcd_server.go
index 9b9dec4..3246ca0 100644
--- a/pkg/mocks/etcd_server.go
+++ b/pkg/mocks/etcd_server.go
@@ -16,15 +16,17 @@
 package mocks
 
 import (
+	"fmt"
 	"go.etcd.io/etcd/embed"
 	"log"
+	"net/url"
 	"os"
 	"time"
 )
 
 const (
-	serverStartUpTimeout   = 10 * time.Second // Maximum time allowed to wait for the Etcd server to be ready
-	localPersistentStorage = "voltha.embed.etcd"
+	serverStartUpTimeout          = 10 * time.Second // Maximum time allowed to wait for the Etcd server to be ready
+	defaultLocalPersistentStorage = "voltha.test.embed.etcd"
 )
 
 //EtcdServer represents an embedded Etcd server.  It is used for testing only.
@@ -32,10 +34,57 @@
 	server *embed.Etcd
 }
 
+func islogLevelValid(logLevel string) bool {
+	valid := []string{"debug", "info", "warn", "error", "panic", "fatal"}
+	for _, l := range valid {
+		if l == logLevel {
+			return true
+		}
+	}
+	return false
+}
+
+/*
+* MKConfig creates an embedded Etcd config
+* :param configName: A name for this config
+* :param clientPort:  The port the etcd client will connect to (do not use 2379 for unit test)
+* :param peerPort:  The port the etcd server will listen for its peers (do not use 2380 for unit test)
+* :param localPersistentStorageDir: The name of a local directory which will hold the Etcd server data
+* :param logLevel: One of debug, info, warn, error, panic, or fatal. Default 'info'.
+ */
+func MKConfig(configName string, clientPort, peerPort int, localPersistentStorageDir string, logLevel string) *embed.Config {
+	cfg := embed.NewConfig()
+	cfg.Name = configName
+	cfg.Dir = localPersistentStorageDir
+	cfg.Logger = "zap"
+	if !islogLevelValid(logLevel) {
+		log.Fatalf("Invalid log level -%s", logLevel)
+	}
+	cfg.LogLevel = logLevel
+	acurl, err := url.Parse(fmt.Sprintf("http://localhost:%d", clientPort))
+	if err != nil {
+		log.Fatalf("Invalid client port -%d", clientPort)
+	}
+	cfg.ACUrls = []url.URL{*acurl}
+	cfg.LCUrls = []url.URL{*acurl}
+
+	apurl, err := url.Parse(fmt.Sprintf("http://localhost:%d", peerPort))
+	if err != nil {
+		log.Fatalf("Invalid peer port -%d", peerPort)
+	}
+	cfg.LPUrls = []url.URL{*apurl}
+	cfg.APUrls = []url.URL{*apurl}
+
+	cfg.ClusterState = embed.ClusterStateFlagNew
+	cfg.InitialCluster = cfg.Name + "=" + apurl.String()
+
+	return cfg
+}
+
 //getDefaultCfg specifies the default config
 func getDefaultCfg() *embed.Config {
 	cfg := embed.NewConfig()
-	cfg.Dir = localPersistentStorage
+	cfg.Dir = defaultLocalPersistentStorage
 	cfg.Logger = "zap"
 	cfg.LogLevel = "error"
 	return cfg
@@ -50,8 +99,8 @@
 	}
 	// Remove the local directory as
 	// a safeguard for the case where a prior test failed
-	if err := os.RemoveAll(localPersistentStorage); err != nil {
-		log.Fatalf("Failure removing local directory %s", localPersistentStorage)
+	if err := os.RemoveAll(cfg.Dir); err != nil {
+		log.Fatalf("Failure removing local directory %s", cfg.Dir)
 	}
 	e, err := embed.StartEtcd(cfg)
 	if err != nil {
@@ -75,9 +124,10 @@
 //Stop closes the embedded Etcd server and removes the local data directory as well
 func (es *EtcdServer) Stop() {
 	if es != nil {
+		storage := es.server.Config().Dir
 		es.server.Server.HardStop()
 		es.server.Close()
-		if err := os.RemoveAll(localPersistentStorage); err != nil {
+		if err := os.RemoveAll(storage); err != nil {
 			log.Fatalf("Failure removing local directory %s", es.server.Config().Dir)
 		}
 	}
diff --git a/pkg/mocks/etcd_server_test.go b/pkg/mocks/etcd_server_test.go
index 8230869..0463daa 100644
--- a/pkg/mocks/etcd_server_test.go
+++ b/pkg/mocks/etcd_server_test.go
@@ -17,7 +17,9 @@
 package mocks
 
 import (
+	"fmt"
 	"github.com/opencord/voltha-lib-go/v2/pkg/db/kvstore"
+	"github.com/phayes/freeport"
 	"github.com/stretchr/testify/assert"
 	"log"
 	"os"
@@ -28,12 +30,20 @@
 var client *kvstore.EtcdClient
 
 func setup() {
-	etcdServer = StartEtcdServer(nil)
+	clientPort, err := freeport.GetFreePort()
+	if err != nil {
+		log.Fatal(err)
+	}
+	peerPort, err := freeport.GetFreePort()
+	if err != nil {
+		log.Fatal(err)
+	}
+	etcdServer = StartEtcdServer(MKConfig("voltha.mock.test", clientPort, peerPort, "voltha.lib.mocks.etcd", "error"))
 	if etcdServer == nil {
 		log.Fatal("Embedded server failed to start")
 	}
-	var err error
-	client, err = kvstore.NewEtcdClient("localhost:2379", 10)
+	clientAddr := fmt.Sprintf("localhost:%d", clientPort)
+	client, err = kvstore.NewEtcdClient(clientAddr, 10)
 	if err != nil || client == nil {
 		etcdServer.Stop()
 		log.Fatal("Failed to create an Etcd client")
diff --git a/vendor/github.com/phayes/freeport/.gitignore b/vendor/github.com/phayes/freeport/.gitignore
new file mode 100644
index 0000000..1521c8b
--- /dev/null
+++ b/vendor/github.com/phayes/freeport/.gitignore
@@ -0,0 +1 @@
+dist
diff --git a/vendor/github.com/phayes/freeport/.goreleaser.yml b/vendor/github.com/phayes/freeport/.goreleaser.yml
new file mode 100644
index 0000000..48044ea
--- /dev/null
+++ b/vendor/github.com/phayes/freeport/.goreleaser.yml
@@ -0,0 +1,134 @@
+project_name: freeport
+
+release:
+  github:
+    owner: phayes
+    name: freeport
+
+builds:
+  - binary: freeport
+    goos:
+      - linux
+      - darwin
+    goarch:
+      - amd64
+      - "386"
+    goarm:
+      - "6"
+    main: ./cmd/freeport
+    ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
+
+archive:
+  format: tar.gz
+  name_template: '{{ .Binary }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{
+    .Arm }}{{ end }}'
+  files:
+  - licence*
+  - LICENCE*
+  - license*
+  - LICENSE*
+  - readme*
+  - README*
+  - changelog*
+  - CHANGELOG*
+
+snapshot:
+  name_template: SNAPSHOT-{{ .Commit }}
+
+checksum:
+  name_template: '{{ .ProjectName }}_{{ .Version }}_checksums.txt'
+
+# Create RPM and .DEB files
+fpm:
+  vendor: Patrick Hayes
+
+  # Your app's homepage.
+  #homepage: https://example.com/
+
+  # Your app's maintainer
+  maintainer: Patrick Hayes <patrick.d.hayes@gmail.com>
+
+  # Your app's description.
+  description: Get a free open TCP port that is ready to use.
+
+  # Your app's license.
+  # Default is empty.
+  license: BSD
+
+  # Formats to be generated.
+  formats:
+    - deb
+    - rpm
+
+  # Packages your package depends on.
+  #dependencies:
+  #  - git
+  #  - zsh
+
+  # Packages that conflict with your package.
+  #conflicts:
+  #  - svn
+  #  - bash
+
+  # Files or directories to add to your package (beyond the binary).
+  # Keys are source paths to get the files from.
+  # Values are the destination locations of the files in the package.
+  #files:
+  #  "scripts/etc/init.d/": "/etc/init.d"
+
+# Homebrew repos
+brew:
+  # Reporitory to push the tap to.
+  github:
+    owner: phayes
+    name: homebrew-repo
+
+  # Git author used to commit to the repository.
+  # Defaults are shown.
+  commit_author:
+    name: goreleaserbot
+    email: goreleaser@carlosbecker.com
+
+  # Folder inside the repository to put the formula.
+  # Default is the root folder.
+  # folder: .
+
+  # Caveats for the user of your binary.
+  # Default is empty.
+  # caveats: "How to use this binary"
+
+  # Your app's homepage.
+  # Default is empty.
+  # homepage: "https://example.com/"
+
+  # Your app's description.
+  # Default is empty.
+  description: "Get a free open TCP port that is ready to use."
+
+  # Packages your package depends on.
+  #dependencies:
+  #  - git
+  #  - zsh
+
+  # Packages that conflict with your package.
+  #conflicts:
+  #  - svn
+  #  - bash
+
+  # Specify for packages that run as a service.
+  # Default is empty.
+  #plist: |
+  #  <?xml version="1.0" encoding="UTF-8"?>
+  #  ...
+
+  # So you can `brew test` your formula.
+  # Default is empty.
+  #test: |
+  #  system "#{bin}/program --version"
+  #  ...
+
+  # Custom install script for brew.
+  # Default is 'bin.install "program"'.
+  #install: |
+  #  bin.install "program"
+  #  ...
\ No newline at end of file
diff --git a/vendor/github.com/phayes/freeport/LICENSE.md b/vendor/github.com/phayes/freeport/LICENSE.md
new file mode 100644
index 0000000..d9882e5
--- /dev/null
+++ b/vendor/github.com/phayes/freeport/LICENSE.md
@@ -0,0 +1,15 @@
+Open Source License (BSD 3-Clause)
+----------------------------------
+
+Copyright (c) 2014, Patrick Hayes / HighWire Press
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/phayes/freeport/README.md b/vendor/github.com/phayes/freeport/README.md
new file mode 100644
index 0000000..1665ccf
--- /dev/null
+++ b/vendor/github.com/phayes/freeport/README.md
@@ -0,0 +1,58 @@
+FreePort
+========
+
+Get a free open TCP port that is ready to use.
+
+## Command Line Example:
+```bash
+# Ask the kernel to give us an open port.
+export port=$(freeport)
+
+# Start standalone httpd server for testing
+httpd -X -c "Listen $port" &
+
+# Curl local server on the selected port
+curl localhost:$port
+```
+
+## Golang example:
+```go
+package main
+
+import "github.com/phayes/freeport"
+
+func main() {
+	port, err := freeport.GetFreePort()
+	if err != nil {
+		log.Fatal(err)
+	}
+	// port is ready to listen on
+}
+
+```
+
+## Installation
+
+#### Mac OSX
+```bash
+brew install phayes/repo/freeport
+```
+
+
+#### CentOS and other RPM based systems
+```bash
+wget https://github.com/phayes/freeport/releases/download/1.0.2/freeport_1.0.2_linux_386.rpm
+rpm -Uvh freeport_1.0.2_linux_386.rpm
+```
+
+#### Ubuntu and other DEB based systems
+```bash
+wget wget https://github.com/phayes/freeport/releases/download/1.0.2/freeport_1.0.2_linux_amd64.deb
+dpkg -i freeport_1.0.2_linux_amd64.deb
+```
+
+#### Building From Source
+```bash
+sudo apt-get install golang                    # Download go. Alternativly build from source: https://golang.org/doc/install/source
+go get github.com/phayes/freeport
+```
diff --git a/vendor/github.com/phayes/freeport/freeport.go b/vendor/github.com/phayes/freeport/freeport.go
new file mode 100644
index 0000000..fcfb6ba
--- /dev/null
+++ b/vendor/github.com/phayes/freeport/freeport.go
@@ -0,0 +1,49 @@
+package freeport
+
+import (
+	"net"
+)
+
+// GetFreePort asks the kernel for a free open port that is ready to use.
+func GetFreePort() (int, error) {
+	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
+	if err != nil {
+		return 0, err
+	}
+
+	l, err := net.ListenTCP("tcp", addr)
+	if err != nil {
+		return 0, err
+	}
+	defer l.Close()
+	return l.Addr().(*net.TCPAddr).Port, nil
+}
+
+// GetPort is deprecated, use GetFreePort instead
+// Ask the kernel for a free open port that is ready to use
+func GetPort() int {
+	port, err := GetFreePort()
+	if err != nil {
+		panic(err)
+	}
+	return port
+}
+
+// GetFreePort asks the kernel for free open ports that are ready to use.
+func GetFreePorts(count int) ([]int, error) {
+	var ports []int
+	for i := 0; i < count; i++ {
+		addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
+		if err != nil {
+			return nil, err
+		}
+
+		l, err := net.ListenTCP("tcp", addr)
+		if err != nil {
+			return nil, err
+		}
+		defer l.Close()
+		ports = append(ports, l.Addr().(*net.TCPAddr).Port)
+	}
+	return ports, nil
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index a6b0745..4927336 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -104,6 +104,8 @@
 github.com/opencord/voltha-protos/v2/go/tech_profile
 github.com/opencord/voltha-protos/v2/go/common
 github.com/opencord/voltha-protos/v2/go/omci
+# github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
+github.com/phayes/freeport
 # github.com/pierrec/lz4 v2.3.0+incompatible
 github.com/pierrec/lz4
 github.com/pierrec/lz4/internal/xxh32