diff --git a/cmd/gnmi-target/target.go b/cmd/gnmi-target/target.go
index 4239ea9faaa0bb556e3f122cba9441b0e9b352e5..e72ef7acb77d43cefb5770f79828f8cc6128cac0 100644
--- a/cmd/gnmi-target/target.go
+++ b/cmd/gnmi-target/target.go
@@ -6,7 +6,6 @@ import (
 	oc "code.fbi.h-da.de/cocsn/yang-models/generated/arista"
 	"context"
 	"flag"
-	"fmt"
 	"github.com/google/gnxi/utils/credentials"
 	pb "github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
@@ -16,7 +15,6 @@ import (
 	"google.golang.org/grpc/reflection"
 	"google.golang.org/grpc/status"
 	"net"
-	"os"
 	"reflect"
 )
 
@@ -76,19 +74,6 @@ func main() {
 		oc.Unmarshal,
 		oc.ΛEnum)
 
-	flag.Usage = func() {
-		fmt.Fprintf(os.Stderr, "Supported models:\n")
-		for _, m := range model.SupportedModels() {
-			fmt.Fprintf(os.Stderr, "  %s\n", m)
-		}
-		fmt.Fprintf(os.Stderr, "\n")
-		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
-		flag.PrintDefaults()
-	}
-
-	flag.Set("logtostderr", "true")
-	flag.Parse()
-
 	g := grpc.NewServer()
 
 	var configData []byte
diff --git a/forks/goarista/openconfig/client/client.go b/forks/goarista/openconfig/client/client.go
deleted file mode 100644
index 1d7d1992f375d06b747161dc4570124696202fac..0000000000000000000000000000000000000000
--- a/forks/goarista/openconfig/client/client.go
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (c) 2016 Arista Networks, Inc.
-// Use of this source code is governed by the Apache License 2.0
-// that can be found in the COPYING file.
-
-// Package ciena provides helper functions for OpenConfig CLI tools.
-package client
-
-import (
-	"io"
-	"strings"
-	"sync"
-
-	"github.com/golang/glog"
-	"github.com/golang/protobuf/proto"
-	"github.com/openconfig/reference/rpc/openconfig"
-	"golang.org/x/net/context"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/metadata"
-)
-
-const defaultPort = "6030"
-
-// PublishFunc is the method to publish responses
-type PublishFunc func(addr string, message proto.Message)
-
-// Client is a connected gRPC ciena
-type Client struct {
-	client openconfig.OpenConfigClient
-	ctx    context.Context
-	device string
-}
-
-// New creates a new gRPC ciena and connects it
-func New(username, password, addr string, opts []grpc.DialOption) *Client {
-	device := addr
-	if !strings.ContainsRune(addr, ':') {
-		addr += ":" + defaultPort
-	}
-	// Make sure we don't move past the grpc.Dial() call until we actually
-	// established an HTTP/2 connection successfully.
-	opts = append(opts, grpc.WithBlock())
-	conn, err := grpc.Dial(addr, opts...)
-	if err != nil {
-		glog.Fatalf("Failed to dial: %s", err)
-	}
-	glog.Infof("Connected to %s", addr)
-	client := openconfig.NewOpenConfigClient(conn)
-
-	ctx := context.Background()
-	if username != "" {
-		ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(
-			"username", username,
-			"password", password))
-	}
-	return &Client{
-		client: client,
-		device: device,
-		ctx:    ctx,
-	}
-}
-
-// Get sends a get request and returns the responses
-func (c *Client) Get(path string) []*openconfig.Notification {
-	req := &openconfig.GetRequest{
-		Path: []*openconfig.Path{
-			{
-				Element: strings.Split(path, "/"),
-			},
-		},
-	}
-	response, err := c.client.Get(c.ctx, req)
-	if err != nil {
-		glog.Fatalf("Get failed: %s", err)
-	}
-	return response.Notification
-}
-
-// Subscribe sends subscriptions, and consumes responses.
-// The given publish function is used to publish SubscribeResponses received
-// for the given subscriptions, when connected to the given host, with the
-// given user/pass pair, or the ciena-side cert specified in the gRPC opts.
-// This function does not normally return so it should probably be run in its
-// own goroutine.  When this function returns, the given WaitGroup is marked
-// as done.
-func (c *Client) Subscribe(wg *sync.WaitGroup, subscriptions []string,
-	publish PublishFunc) {
-	defer wg.Done()
-	stream, err := c.client.Subscribe(c.ctx)
-	if err != nil {
-		glog.Fatalf("Subscribe failed: %s", err)
-	}
-	defer stream.CloseSend()
-
-	for _, path := range subscriptions {
-		sub := &openconfig.SubscribeRequest{
-			Request: &openconfig.SubscribeRequest_Subscribe{
-				Subscribe: &openconfig.SubscriptionList{
-					Subscription: []*openconfig.Subscription{
-						{
-							Path: &openconfig.Path{Element: strings.Split(path, "/")},
-						},
-					},
-				},
-			},
-		}
-
-		glog.Infof("Sending subscribe request: %s", sub)
-		err = stream.Send(sub)
-		if err != nil {
-			glog.Fatalf("Failed to subscribe: %s", err)
-		}
-	}
-
-	for {
-		resp, err := stream.Recv()
-		if err != nil {
-			if err != io.EOF {
-				glog.Fatalf("Error received from the server: %s", err)
-			}
-			return
-		}
-		switch resp := resp.Response.(type) {
-		case *openconfig.SubscribeResponse_SyncResponse:
-			if !resp.SyncResponse {
-				panic("initial sync failed," +
-					" check that you're using a ciena compatible with the server")
-			}
-		}
-		glog.V(3).Info(resp)
-		publish(c.device, resp)
-	}
-}
diff --git a/forks/goarista/openconfig/client/flags.go b/forks/goarista/openconfig/client/flags.go
deleted file mode 100644
index fb91bba3715c286babedb3e58caf221b576d213b..0000000000000000000000000000000000000000
--- a/forks/goarista/openconfig/client/flags.go
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2016 Arista Networks, Inc.
-// Use of this source code is governed by the Apache License 2.0
-// that can be found in the COPYING file.
-
-package client
-
-import (
-	"crypto/tls"
-	"crypto/x509"
-	"flag"
-	"io/ioutil"
-	"os"
-	"strings"
-
-	"github.com/golang/glog"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/credentials"
-)
-
-const (
-	// HostnameArg is the value to be replaced by the actual hostname
-	HostnameArg = "HOSTNAME"
-)
-
-// ParseHostnames parses a comma-separated list of names and replaces HOSTNAME with the current
-// hostname in it
-func ParseHostnames(list string) ([]string, error) {
-	items := strings.Split(list, ",")
-	hostname, err := os.Hostname()
-	if err != nil {
-		return nil, err
-	}
-	names := make([]string, len(items))
-	for i, name := range items {
-		if name == HostnameArg {
-			name = hostname
-		}
-		names[i] = name
-	}
-	return names, nil
-}
-
-// ParseFlags registers some additional common flags,
-// parses the flags, and returns the resulting gRPC options,
-// and other settings to connect to the gRPC interface.
-func ParseFlags() (username string, password string, subscriptions, addrs []string,
-	opts []grpc.DialOption) {
-
-	var (
-		addrsFlag = flag.String("addrs", "localhost:6030",
-			"Comma-separated list of addresses of OpenConfig gRPC servers. The address 'HOSTNAME' "+
-				"is replaced by the current hostname.")
-
-		caFileFlag = flag.String("cafile", "",
-			"Path to server TLS certificate file")
-
-		certFileFlag = flag.String("certfile", "",
-			"Path to ciena TLS certificate file")
-
-		keyFileFlag = flag.String("keyfile", "",
-			"Path to ciena TLS private key file")
-
-		passwordFlag = flag.String("password", "",
-			"Password to authenticate with")
-
-		subscribeFlag = flag.String("subscribe", "",
-			"Comma-separated list of paths to subscribe to upon connecting to the server")
-
-		usernameFlag = flag.String("username", "",
-			"Username to authenticate with")
-
-		tlsFlag = flag.Bool("tls", false,
-			"Enable TLS")
-	)
-
-	flag.Parse()
-	if *tlsFlag || *caFileFlag != "" || *certFileFlag != "" {
-		config := &tls.Config{}
-		if *caFileFlag != "" {
-			b, err := ioutil.ReadFile(*caFileFlag)
-			if err != nil {
-				glog.Fatal(err)
-			}
-			cp := x509.NewCertPool()
-			if !cp.AppendCertsFromPEM(b) {
-				glog.Fatalf("credentials: failed to append certificates")
-			}
-			config.RootCAs = cp
-		} else {
-			config.InsecureSkipVerify = true
-		}
-		if *certFileFlag != "" {
-			if *keyFileFlag == "" {
-				glog.Fatalf("Please provide both -certfile and -keyfile")
-			}
-			cert, err := tls.LoadX509KeyPair(*certFileFlag, *keyFileFlag)
-			if err != nil {
-				glog.Fatal(err)
-			}
-			config.Certificates = []tls.Certificate{cert}
-		}
-		opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(config)))
-	} else {
-		opts = append(opts, grpc.WithInsecure())
-	}
-	var err error
-	addrs, err = ParseHostnames(*addrsFlag)
-	if err != nil {
-		glog.Fatal(err)
-	}
-	subscriptions = strings.Split(*subscribeFlag, ",")
-	return *usernameFlag, *passwordFlag, subscriptions, addrs, opts
-}
diff --git a/forks/goarista/openconfig/json.go b/forks/goarista/openconfig/json.go
deleted file mode 100644
index 8eba88baded76b426451ef862d332a3c712a1db2..0000000000000000000000000000000000000000
--- a/forks/goarista/openconfig/json.go
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright (c) 2016 Arista Networks, Inc.
-// Use of this source code is governed by the Apache License 2.0
-// that can be found in the COPYING file.
-
-package openconfig
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"strings"
-
-	"github.com/openconfig/reference/rpc/openconfig"
-)
-
-// joinPath builds a string out of an Element
-func joinPath(path *openconfig.Path) string {
-	if path == nil {
-		return ""
-	}
-	return strings.Join(path.Element, "/")
-}
-
-func convertUpdate(update *openconfig.Update) (interface{}, error) {
-	switch update.Value.Type {
-	case openconfig.Type_JSON:
-		var value interface{}
-		decoder := json.NewDecoder(bytes.NewReader(update.Value.Value))
-		decoder.UseNumber()
-		if err := decoder.Decode(&value); err != nil {
-			return nil, fmt.Errorf("Malformed JSON update %q in %s",
-				update.Value.Value, update)
-		}
-		return value, nil
-	case openconfig.Type_BYTES:
-		return update.Value.Value, nil
-	default:
-		return nil,
-			fmt.Errorf("Unhandled type of value %v in %s", update.Value.Type, update)
-	}
-}
-
-// NotificationToJSON converts a Notification into a JSON string
-func NotificationToJSON(notif *openconfig.Notification) (string, error) {
-	m := make(map[string]interface{}, 1)
-	m["timestamp"] = notif.Timestamp
-	m["path"] = "/" + joinPath(notif.Prefix)
-	if len(notif.Update) != 0 {
-		updates := make(map[string]interface{}, len(notif.Update))
-		var err error
-		for _, update := range notif.Update {
-			updates[joinPath(update.Path)], err = convertUpdate(update)
-			if err != nil {
-				return "", err
-			}
-		}
-		m["updates"] = updates
-	}
-	if len(notif.Delete) != 0 {
-		deletes := make([]string, len(notif.Delete))
-		for i, del := range notif.Delete {
-			deletes[i] = joinPath(del)
-		}
-		m["deletes"] = deletes
-	}
-	m = map[string]interface{}{"notification": m}
-	js, err := json.MarshalIndent(m, "", "  ")
-	if err != nil {
-		return "", err
-	}
-	return string(js), nil
-}
-
-// SubscribeResponseToJSON converts a SubscribeResponse into a JSON string
-func SubscribeResponseToJSON(resp *openconfig.SubscribeResponse) (string, error) {
-	m := make(map[string]interface{}, 1)
-	var err error
-	switch resp := resp.Response.(type) {
-	case *openconfig.SubscribeResponse_Update:
-		return NotificationToJSON(resp.Update)
-	case *openconfig.SubscribeResponse_Heartbeat:
-		m["heartbeat"] = resp.Heartbeat.Interval
-	case *openconfig.SubscribeResponse_SyncResponse:
-		m["syncResponse"] = resp.SyncResponse
-	default:
-		return "", fmt.Errorf("Unknown type of response: %T: %s", resp, resp)
-	}
-	js, err := json.MarshalIndent(m, "", "  ")
-	if err != nil {
-		return "", err
-	}
-	return string(js), nil
-}
-
-// EscapeFunc is the escaping method for attribute names
-type EscapeFunc func(k string) string
-
-// escapeValue looks for maps in an interface and escapes their keys
-func escapeValue(value interface{}, escape EscapeFunc) interface{} {
-	valueMap, ok := value.(map[string]interface{})
-	if !ok {
-		return value
-	}
-	escapedMap := make(map[string]interface{}, len(valueMap))
-	for k, v := range valueMap {
-		escapedKey := escape(k)
-		escapedMap[escapedKey] = escapeValue(v, escape)
-	}
-	return escapedMap
-}
-
-// addPathToMap creates a map[string]interface{} from a path. It returns the node in
-// the map corresponding to the last element in the path
-func addPathToMap(root map[string]interface{}, path []string, escape EscapeFunc) (
-	map[string]interface{}, error) {
-	parent := root
-	for _, element := range path {
-		k := escape(element)
-		node, found := parent[k]
-		if !found {
-			node = map[string]interface{}{}
-			parent[k] = node
-		}
-		var ok bool
-		parent, ok = node.(map[string]interface{})
-		if !ok {
-			return nil, fmt.Errorf(
-				"Node %s is of type %T (expected map[string]interface traversing %q)",
-				element, node, path)
-		}
-	}
-	return parent, nil
-}
-
-// NotificationToMap maps a Notification into a nested map of entities
-func NotificationToMap(addr string, notification *openconfig.Notification,
-	escape EscapeFunc) (map[string]interface{}, error) {
-	if escape == nil {
-		escape = func(name string) string {
-			return name
-		}
-	}
-	prefix := notification.GetPrefix()
-
-	// Convert deletes
-	var deletes map[string]interface{}
-	notificationDeletes := notification.GetDelete()
-	if notificationDeletes != nil {
-		deletes = make(map[string]interface{})
-		node := deletes
-		if prefix != nil {
-			var err error
-			node, err = addPathToMap(node, prefix.Element, escape)
-			if err != nil {
-				return nil, err
-			}
-		}
-		for _, delete := range notificationDeletes {
-			_, err := addPathToMap(node, delete.Element, escape)
-			if err != nil {
-				return nil, err
-			}
-		}
-	}
-
-	// Convert updates
-	var updates map[string]interface{}
-	notificationUpdates := notification.GetUpdate()
-	if notificationUpdates != nil {
-		updates = make(map[string]interface{})
-		node := updates
-		if prefix != nil {
-			var err error
-			node, err = addPathToMap(node, prefix.Element, escape)
-			if err != nil {
-				return nil, err
-			}
-		}
-		for _, update := range notificationUpdates {
-			updateNode := node
-			path := update.GetPath()
-			elementLen := len(path.Element)
-
-			// Convert all elements before the leaf
-			if elementLen > 1 {
-				parentElements := path.Element[:elementLen-1]
-				var err error
-				updateNode, err = addPathToMap(updateNode, parentElements, escape)
-				if err != nil {
-					return nil, err
-				}
-			}
-
-			// Convert the value in the leaf
-			value := update.GetValue()
-			var unmarshaledValue interface{}
-			switch value.Type {
-			case openconfig.Type_JSON:
-				if err := json.Unmarshal(value.Value, &unmarshaledValue); err != nil {
-					return nil, err
-				}
-			case openconfig.Type_BYTES:
-				unmarshaledValue = update.Value.Value
-			default:
-				return nil, fmt.Errorf("Unexpected value type %s for path %v",
-					value.Type, path)
-			}
-			updateNode[escape(path.Element[elementLen-1])] = escapeValue(
-				unmarshaledValue, escape)
-		}
-	}
-
-	// Build the complete map to return
-	root := map[string]interface{}{
-		"timestamp": notification.Timestamp,
-	}
-	if addr != "" {
-		root["dataset"] = addr
-	}
-	if deletes != nil {
-		root["delete"] = deletes
-	}
-	if updates != nil {
-		root["update"] = updates
-	}
-	return root, nil
-}
-
-// NotificationToJSONDocument maps a Notification into a single JSON document
-func NotificationToJSONDocument(addr string, notification *openconfig.Notification,
-	escape EscapeFunc) ([]byte, error) {
-	m, err := NotificationToMap(addr, notification, escape)
-	if err != nil {
-		return nil, err
-	}
-	return json.Marshal(m)
-}
diff --git a/forks/goarista/openconfig/json_test.go b/forks/goarista/openconfig/json_test.go
deleted file mode 100644
index 1dfc41d5789b9c8fcbb1a6a8b30918f77873a88a..0000000000000000000000000000000000000000
--- a/forks/goarista/openconfig/json_test.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2016 Arista Networks, Inc.
-// Use of this source code is governed by the Apache License 2.0
-// that can be found in the COPYING file.
-
-package openconfig
-
-import (
-	"encoding/json"
-	"testing"
-
-	"github.com/aristanetworks/goarista/test"
-
-	"github.com/openconfig/reference/rpc/openconfig"
-)
-
-func TestNotificationToMap(t *testing.T) {
-	value := map[string]interface{}{
-		"239.255.255.250_0.0.0.0": map[string]interface{}{
-			"creationTime": 4.567969230573434e+06,
-		},
-	}
-	valueJSON, err := json.Marshal(value)
-	if err != nil {
-		t.Fatal(err)
-	}
-	tests := []struct {
-		notification openconfig.Notification
-		json         map[string]interface{}
-	}{{
-		notification: openconfig.Notification{
-			Prefix: &openconfig.Path{
-				Element: []string{
-					"foo",
-				},
-			},
-			Update: []*openconfig.Update{
-				{
-					Path: &openconfig.Path{
-						Element: []string{
-							"route1",
-						},
-					},
-					Value: &openconfig.Value{
-						Value: valueJSON,
-					},
-				}, {
-					Path: &openconfig.Path{
-						Element: []string{
-							"route2",
-						},
-					},
-					Value: &openconfig.Value{
-						Value: valueJSON,
-					},
-				}},
-		},
-		json: map[string]interface{}{
-			"timestamp": int64(0),
-			"dataset":   "cairo",
-			"update": map[string]interface{}{
-				"foo": map[string]interface{}{
-					"route1": map[string]interface{}{
-						"239.255.255.250_0.0.0.0": map[string]interface{}{
-							"creationTime": 4.567969230573434e+06,
-						},
-					},
-					"route2": map[string]interface{}{
-						"239.255.255.250_0.0.0.0": map[string]interface{}{
-							"creationTime": 4.567969230573434e+06,
-						},
-					},
-				},
-			},
-		},
-	}, {
-		notification: openconfig.Notification{
-			Prefix: &openconfig.Path{
-				Element: []string{
-					"foo", "bar",
-				},
-			},
-			Delete: []*openconfig.Path{
-				{
-					Element: []string{
-						"route", "237.255.255.250_0.0.0.0",
-					}},
-				{
-					Element: []string{
-						"route", "238.255.255.250_0.0.0.0",
-					},
-				},
-			},
-			Update: []*openconfig.Update{{
-				Path: &openconfig.Path{
-					Element: []string{
-						"route",
-					},
-				},
-				Value: &openconfig.Value{
-					Value: valueJSON,
-				},
-			}},
-		},
-		json: map[string]interface{}{
-			"timestamp": int64(0),
-			"dataset":   "cairo",
-			"delete": map[string]interface{}{
-				"foo": map[string]interface{}{
-					"bar": map[string]interface{}{
-						"route": map[string]interface{}{
-							"237.255.255.250_0.0.0.0": map[string]interface{}{},
-							"238.255.255.250_0.0.0.0": map[string]interface{}{},
-						},
-					},
-				},
-			},
-			"update": map[string]interface{}{
-				"foo": map[string]interface{}{
-					"bar": map[string]interface{}{
-						"route": map[string]interface{}{
-							"239.255.255.250_0.0.0.0": map[string]interface{}{
-								"creationTime": 4.567969230573434e+06,
-							},
-						},
-					},
-				},
-			},
-		},
-	}}
-	for _, tcase := range tests {
-		actual, err := NotificationToMap("cairo", &tcase.notification, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		diff := test.Diff(tcase.json, actual)
-		if len(diff) > 0 {
-			expectedJSON, _ := json.Marshal(tcase.json)
-			actualJSON, _ := json.Marshal(actual)
-			t.Fatalf("Unexpected diff: %s\nExpected:\n%s\nGot:\n%s\n)", diff, expectedJSON,
-				actualJSON)
-		}
-	}
-}
diff --git a/forks/google/gnmi/server.go b/forks/google/gnmi/server.go
index 3af5d9b50e74aa79c77a87f116920349374fbdc9..0cc56f64d062544d2ab1d5db5b00924e58285c6c 100644
--- a/forks/google/gnmi/server.go
+++ b/forks/google/gnmi/server.go
@@ -47,7 +47,7 @@ type ConfigCallback func(ygot.ValidatedGoStruct) error
 
 var (
 	pbRootPath         = &pb.Path{}
-	supportedEncodings = []pb.Encoding{pb.Encoding_PROTO}
+	supportedEncodings = []pb.Encoding{pb.Encoding_PROTO, pb.Encoding_JSON_IETF, pb.Encoding_JSON}
 )
 
 // Server struct maintains the data structure for device config and implements the interface of gnmi server.
diff --git a/go.mod b/go.mod
index dd60fd272aab3c56c223acadd69ecda15a8b365d..2ee58ea728a76d130fa59bf80d99c4410a83c6b9 100644
--- a/go.mod
+++ b/go.mod
@@ -21,6 +21,7 @@ require (
 	github.com/rivo/tview v0.0.0-20201018122409-d551c850a743
 	github.com/sirupsen/logrus v1.4.2
 	github.com/spf13/viper v1.7.1
+	github.com/stretchr/testify v1.6.1
 	github.com/tidwall/gjson v1.6.3
 	golang.org/x/net v0.0.0-20201216054612-986b41b23924
 	google.golang.org/grpc v1.34.0
diff --git a/go.sum b/go.sum
index 969f8580799a31dd91384a2076fd0099e1f90d4b..a13eb5160fd2c4d42be432c818f1ac93d2137dba 100644
--- a/go.sum
+++ b/go.sum
@@ -516,6 +516,7 @@ github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
 github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
diff --git a/nucleus/cli-handling_test.go b/nucleus/cli-handling_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5fa897297a3cbdddc8b9156600d469cd7e168cd9
--- /dev/null
+++ b/nucleus/cli-handling_test.go
@@ -0,0 +1,61 @@
+package nucleus
+
+import (
+	"testing"
+)
+
+func Test_buf_Write(t *testing.T) {
+
+}
+
+func Test_getCLIGoing(t *testing.T) {
+
+}
+
+func Test_server_AddDevice(t *testing.T) {
+
+}
+
+func Test_server_BroadcastLog(t *testing.T) {
+
+}
+
+func Test_server_CreateLogStream(t *testing.T) {
+
+}
+
+func Test_server_CreatePND(t *testing.T) {
+
+}
+
+func Test_server_GetAllPNDs(t *testing.T) {
+
+}
+
+func Test_server_GetAllSBINames(t *testing.T) {
+
+}
+
+func Test_server_HandleDeviceGetRequest(t *testing.T) {
+
+}
+
+func Test_server_SayHello(t *testing.T) {
+
+}
+
+func Test_server_Shutdown(t *testing.T) {
+
+}
+
+func Test_server_TAPIGetEdge(t *testing.T) {
+
+}
+
+func Test_server_TAPIGetEdgeNode(t *testing.T) {
+
+}
+
+func Test_server_TAPIGetLink(t *testing.T) {
+
+}
diff --git a/nucleus/gnmi_transport.go b/nucleus/gnmi_transport.go
index 5d9dde72e3fc9a4beb7d9bcfdb18d079579aa058..964c22d89ccced928bc7fef7c0e923e4fb255f4a 100644
--- a/nucleus/gnmi_transport.go
+++ b/nucleus/gnmi_transport.go
@@ -102,7 +102,7 @@ func gnmiFullPath(prefix, path *gpb.Path) (*gpb.Path, error) {
 
 // Capabilities calls GNMI capabilities
 func (g *Gnmi) Capabilities(ctx context.Context) (interface{}, error) {
-	client, err := gnmi.Dial(ctx.Value("config").(*gnmi.Config))
+	client, err := gnmi.Dial(g.config)
 	if err != nil {
 		return nil, err
 	}
diff --git a/nucleus/gnmi_transport_test.go b/nucleus/gnmi_transport_test.go
index 0fa4ffa903a1f894325aaf5211341e19a2df754a..83471ce9e3c3ea0c4e0f55e68acf98f846cf1aa2 100644
--- a/nucleus/gnmi_transport_test.go
+++ b/nucleus/gnmi_transport_test.go
@@ -1 +1,535 @@
 package nucleus
+
+import (
+	"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
+	"code.fbi.h-da.de/cocsn/gosdn/test_resources"
+	"context"
+	log "github.com/golang/glog"
+	gpb "github.com/openconfig/gnmi/proto/gnmi"
+	"github.com/openconfig/gnmi/proto/gnmi_ext"
+	"github.com/openconfig/goyang/pkg/yang"
+	"github.com/openconfig/ygot/ytypes"
+	"os"
+	"reflect"
+	"testing"
+)
+
+// TestMain bootstraps all tests. Humongous best
+func TestMain(m *testing.M) {
+	testSetupGnmi()
+	os.Exit(m.Run())
+}
+
+// testSetupGnmi bootstraps tests for gnmi transport
+func testSetupGnmi() {
+	// TODO: Set sane defaults
+	gnmiConfig = &gnmi.Config{
+		Username: "test",
+		Password: "test",
+		Addr:     "localhost:13371",
+		Encoding: gpb.Encoding_PROTO,
+	}
+
+	transport = &Gnmi{
+		SetNode:  nil,
+		RespChan: make(chan *gpb.SubscribeResponse),
+		config:   gnmiConfig,
+	}
+
+	startGnmiTarget = make(chan string)
+	stopGnmiTarget = make(chan bool)
+	go targetRunner()
+}
+
+func targetRunner() {
+	for {
+		addr := <-startGnmiTarget
+		if err := test_resources.GnmiTarget(stopGnmiTarget, addr); err != nil {
+			log.Fatal(err)
+		}
+	}
+}
+
+var transport *Gnmi
+var gnmiConfig *gnmi.Config
+var startGnmiTarget chan string
+var stopGnmiTarget chan bool
+
+func TestGnmi_Capabilities(t *testing.T) {
+	type fields struct {
+		config *gnmi.Config
+	}
+	type args struct {
+		ctx      context.Context
+		endpoint string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    *gpb.CapabilityResponse
+		wantErr bool
+	}{
+		{
+			name:   "proto",
+			fields: fields{config: gnmiConfig},
+			args: args{
+				ctx:      context.Background(),
+				endpoint: gnmiConfig.Addr,
+			},
+			want:    &gpb.CapabilityResponse{},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			startGnmiTarget <- tt.args.endpoint
+			g := &Gnmi{
+				config: tt.fields.config,
+			}
+			got, err := g.Capabilities(tt.args.ctx)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Capabilities() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			_, ok := got.(*gpb.CapabilityResponse)
+			if !ok {
+				t.Errorf("Capabilities() got = %v, want %v", got, tt.want)
+			}
+			stopGnmiTarget <- true
+		})
+	}
+}
+
+func TestGnmi_Close(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			if err := g.Close(); (err != nil) != tt.wantErr {
+				t.Errorf("Close() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestGnmi_Get(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	type args struct {
+		ctx    context.Context
+		params []string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    interface{}
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			got, err := g.Get(tt.args.ctx, tt.args.params...)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("Get() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGnmi_GetConfig(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   *gnmi.Config
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			if got := g.GetConfig(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("GetConfig() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGnmi_ProcessResponse(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	type args struct {
+		resp interface{}
+		root interface{}
+		s    *ytypes.Schema
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			if err := g.ProcessResponse(tt.args.resp, tt.args.root, tt.args.s); (err != nil) != tt.wantErr {
+				t.Errorf("ProcessResponse() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestGnmi_Set(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	type args struct {
+		ctx    context.Context
+		params []string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    interface{}
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			got, err := g.Set(tt.args.ctx, tt.args.params...)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("Set() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGnmi_SetConfig(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	type args struct {
+		config *gnmi.Config
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+
+		})
+	}
+}
+
+func TestGnmi_Subscribe(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	type args struct {
+		ctx    context.Context
+		params []string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			if err := g.Subscribe(tt.args.ctx, tt.args.params...); (err != nil) != tt.wantErr {
+				t.Errorf("Subscribe() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestGnmi_Type(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   string
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			if got := g.Type(); got != tt.want {
+				t.Errorf("Type() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGnmi_get(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	type args struct {
+		ctx    context.Context
+		paths  [][]string
+		origin string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    interface{}
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			got, err := g.get(tt.args.ctx, tt.args.paths, tt.args.origin)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("get() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("get() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGnmi_getWithRequest(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	type args struct {
+		ctx context.Context
+		req *gpb.GetRequest
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    interface{}
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			got, err := g.getWithRequest(tt.args.ctx, tt.args.req)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("getWithRequest() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("getWithRequest() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGnmi_set(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	type args struct {
+		ctx    context.Context
+		setOps []*gnmi.Operation
+		exts   []*gnmi_ext.Extension
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			if err := g.set(tt.args.ctx, tt.args.setOps, tt.args.exts...); (err != nil) != tt.wantErr {
+				t.Errorf("set() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestGnmi_subscribe(t *testing.T) {
+	type fields struct {
+		SetNode  func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
+		RespChan chan *gpb.SubscribeResponse
+		config   *gnmi.Config
+	}
+	type args struct {
+		ctx context.Context
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			g := &Gnmi{
+				SetNode:  tt.fields.SetNode,
+				RespChan: tt.fields.RespChan,
+				config:   tt.fields.config,
+			}
+			if err := g.subscribe(tt.args.ctx); (err != nil) != tt.wantErr {
+				t.Errorf("subscribe() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func Test_extractModelKey(t *testing.T) {
+	type args struct {
+		path *gpb.Path
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := extractModelKey(tt.args.path); got != tt.want {
+				t.Errorf("extractModelKey() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func Test_gnmiFullPath(t *testing.T) {
+	type args struct {
+		prefix *gpb.Path
+		path   *gpb.Path
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *gpb.Path
+		wantErr bool
+	}{
+		// TODO: Add test cases.
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := gnmiFullPath(tt.args.prefix, tt.args.path)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("gnmiFullPath() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("gnmiFullPath() got = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/test_resources/targets.go b/test_resources/targets.go
new file mode 100644
index 0000000000000000000000000000000000000000..7aa3d84999e972ba0706641e048c40aa0c1f31c9
--- /dev/null
+++ b/test_resources/targets.go
@@ -0,0 +1,100 @@
+package test_resources
+
+import (
+	"code.fbi.h-da.de/cocsn/gosdn/forks/google/gnmi"
+	"code.fbi.h-da.de/cocsn/gosdn/forks/google/gnmi/modeldata"
+	oc "code.fbi.h-da.de/cocsn/yang-models/generated/arista"
+	pb "github.com/openconfig/gnmi/proto/gnmi"
+	"github.com/openconfig/ygot/ygot"
+	log "github.com/sirupsen/logrus"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/reflection"
+	"net"
+	"reflect"
+)
+
+type server struct {
+	*gnmi.Server
+}
+
+func callback(newConfig ygot.ValidatedGoStruct) error {
+	// Apply the config to your device and return nil if success. return error if fails.
+	//
+	// Do something ...
+	return nil
+}
+
+func newServer(model *gnmi.Model, config []byte) (*server, error) {
+	s, err := gnmi.NewServer(model, config, callback)
+	if err != nil {
+		return nil, err
+	}
+	return &server{Server: s}, nil
+}
+
+/*
+TODO: Implement multiple server configurations
+// Get overrides the Get func of gnmi.Target to provide user auth.
+func (s *server) Get(ctx context.Context, req *pb.GetRequest) (*pb.GetResponse, error) {
+	msg, ok := credentials.AuthorizeUser(ctx)
+	if !ok {
+		log.Infof("denied a Get request: %v", msg)
+		return nil, status.Error(codes.PermissionDenied, msg)
+	}
+	log.Infof("allowed a Get request: %v", msg)
+	return s.Server.Get(ctx, req)
+}
+
+// Set overrides the Set func of gnmi.Target to provide user auth.
+func (s *server) Set(ctx context.Context, req *pb.SetRequest) (*pb.SetResponse, error) {
+	msg, ok := credentials.AuthorizeUser(ctx)
+	if !ok {
+		log.Infof("denied a Set request: %v", msg)
+		return nil, status.Error(codes.PermissionDenied, msg)
+	}
+	log.Infof("allowed a Set request: %v", msg)
+	return s.Server.Set(ctx, req)
+}
+*/
+
+func GnmiTarget(stop chan bool, bindAddr string) error {
+	if bindAddr == "" {
+		bindAddr = "localhost:13371"
+	}
+
+	// Google stuff from here
+	model := gnmi.NewModel(modeldata.ModelData,
+		reflect.TypeOf((*oc.Device)(nil)),
+		oc.SchemaTree["Device"],
+		oc.Unmarshal,
+		oc.ΛEnum)
+
+	g := grpc.NewServer()
+
+	var configData []byte
+	s, err := newServer(model, configData)
+	if err != nil {
+		log.Errorf("error in creating gnmi target: %v", err)
+		return err
+	}
+	pb.RegisterGNMIServer(g, s)
+	reflection.Register(g)
+
+	log.Infof("starting to listen on %s", bindAddr)
+	listen, err := net.Listen("tcp", bindAddr)
+	if err != nil {
+		log.Errorf("failed to listen: %v", err)
+		return err
+	}
+
+	log.Info("starting to serve")
+	go func() {
+		<-stop
+		g.GracefulStop()
+	}()
+	if err := g.Serve(listen); err != nil {
+		log.Errorf("failed to serve: %v", err)
+		return err
+	}
+	return nil
+}