diff --git a/.gitignore b/.gitignore
index f6d6b861ea9bea47efbaec7442ef2f133e6225e4..78c6e10062c15b5eb23543e4c43b585851060baa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,4 @@ documentation/design/*.pdf
 .idea/workspace.xml
 restconf/bin/bin
 test/.terraform.local/
+configs/gosdn.toml
\ No newline at end of file
diff --git a/cli/cli_test.go b/cli/cli_test.go
deleted file mode 100644
index 65bf6e6497dd747d4cbd951143cf4c56e2b46ea4..0000000000000000000000000000000000000000
--- a/cli/cli_test.go
+++ /dev/null
@@ -1,259 +0,0 @@
-package cli
-
-import (
-	"code.fbi.h-da.de/cocsn/gosdn/forks/google/gnmi"
-	"context"
-	gpb "github.com/openconfig/gnmi/proto/gnmi"
-	"github.com/openconfig/ygot/ygot"
-	"reflect"
-	"testing"
-)
-
-func TestCapabilities(t *testing.T) {
-	type args struct {
-		a string
-		u string
-		p string
-	}
-	tests := []struct {
-		name    string
-		args    args
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := Capabilities(tt.args.a, tt.args.u, tt.args.p); (err != nil) != tt.wantErr {
-				t.Errorf("Capabilities() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}
-
-func TestGet(t *testing.T) {
-	type args struct {
-		a    string
-		u    string
-		p    string
-		args []string
-	}
-	tests := []struct {
-		name    string
-		args    args
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := Get(tt.args.a, tt.args.u, tt.args.p, tt.args.args...); (err != nil) != tt.wantErr {
-				t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}
-
-func TestHttpGet(t *testing.T) {
-	type args struct {
-		apiEndpoint string
-		f           string
-		args        []string
-	}
-	tests := []struct {
-		name    string
-		args    args
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := HTTPGet(tt.args.apiEndpoint, tt.args.f, tt.args.args...); (err != nil) != tt.wantErr {
-				t.Errorf("HTTPGet() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}
-
-func TestLeafPaths(t *testing.T) {
-	tests := []struct {
-		name    string
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := LeafPaths(); (err != nil) != tt.wantErr {
-				t.Errorf("LeafPaths() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}
-
-func TestPathTraversal(t *testing.T) {
-	tests := []struct {
-		name    string
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := PathTraversal(); (err != nil) != tt.wantErr {
-				t.Errorf("PathTraversal() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}
-
-func TestSet(t *testing.T) {
-	type args struct {
-		a    string
-		u    string
-		p    string
-		typ  string
-		args []string
-	}
-	tests := []struct {
-		name    string
-		args    args
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := Set(tt.args.a, tt.args.u, tt.args.p, tt.args.typ, tt.args.args...); (err != nil) != tt.wantErr {
-				t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}
-
-func TestSubscribe(t *testing.T) {
-	type args struct {
-		a         string
-		u         string
-		p         string
-		sample    int64
-		heartbeat int64
-		args      []string
-	}
-	tests := []struct {
-		name    string
-		args    args
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := Subscribe(tt.args.a, tt.args.u, tt.args.p, tt.args.sample, tt.args.heartbeat, tt.args.args...); (err != nil) != tt.wantErr {
-				t.Errorf("Subscribe() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}
-
-func TestTarget(t *testing.T) {
-	type args struct {
-		bindAddr string
-	}
-	tests := []struct {
-		name    string
-		args    args
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := Target(tt.args.bindAddr); (err != nil) != tt.wantErr {
-				t.Errorf("Target() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}
-
-func Test_callback(t *testing.T) {
-	type args struct {
-		newConfig ygot.ValidatedGoStruct
-	}
-	tests := []struct {
-		name    string
-		args    args
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if err := callback(tt.args.newConfig); (err != nil) != tt.wantErr {
-				t.Errorf("callback() error = %v, wantErr %v", err, tt.wantErr)
-			}
-		})
-	}
-}
-
-func Test_newServer(t *testing.T) {
-	type args struct {
-		model  *gnmi.Model
-		config []byte
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *server
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got, err := newServer(tt.args.model, tt.args.config)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("newServer() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-			if !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("newServer() got = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func Test_server_Get(t *testing.T) {
-	type fields struct {
-		Server *gnmi.Server
-	}
-	type args struct {
-		ctx context.Context
-		req *gpb.GetRequest
-	}
-	tests := []struct {
-		name    string
-		fields  fields
-		args    args
-		want    *gpb.GetResponse
-		wantErr bool
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := &server{
-				Server: tt.fields.Server,
-			}
-			got, err := s.Get(tt.args.ctx, tt.args.req)
-			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)
-			}
-		})
-	}
-}
diff --git a/cli/get.go b/cli/get.go
index 36dec3a4b75b2c86c225ee7beb71634148c2da39..f2b2e6e80aff4e1e8a53b2d61e2d339524df0bdd 100644
--- a/cli/get.go
+++ b/cli/get.go
@@ -9,7 +9,7 @@ import (
 )
 
 // Get sends a gNMI Get request to the specified target and prints the response to stdout
-func Get(a, u, p string, args ...string) error {
+func Get(a, u, p string, args ...string) (*gpb.GetResponse,error) {
 	sbi := &nucleus.OpenConfig{}
 	opts := &nucleus.GnmiTransportOptions{
 		Config: gnmi.Config{
@@ -22,12 +22,16 @@ func Get(a, u, p string, args ...string) error {
 	}
 	t, err := nucleus.NewGnmiTransport(opts)
 	if err != nil {
-		return err
+		return nil,err
 	}
 	resp, err := t.Get(context.Background(), args...)
 	if err != nil {
-		return err
+		return nil, err
 	}
-	log.Info(resp)
-	return nil
+	log.Debug(resp)
+	r, ok := resp.(*gpb.GetResponse)
+	if !ok {
+		return nil, &nucleus.ErrInvalidTypeAssertion{}
+	}
+	return r, nil
 }
diff --git a/cli/http.go b/cli/http.go
index ba3b2f6765f1a5a5f2adc5137533e2cb95a420eb..91c4bb65c29971cc49a837d0a1bb30abd8690d01 100644
--- a/cli/http.go
+++ b/cli/http.go
@@ -1,6 +1,7 @@
 package cli
 
 import (
+	"errors"
 	"fmt"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/viper"
@@ -34,12 +35,15 @@ func HTTPGet(apiEndpoint, f string, args ...string) error {
 		if err != nil {
 			return err
 		}
-		if f == "init" {
+		switch f {
+		case "init":
 			pnd := string(bytes[:36])
 			sbi := string(bytes[36:])
 			viper.Set("CLI_PND", pnd)
 			viper.Set("CLI_SBI", sbi)
 			return viper.WriteConfig()
+		default:
+			fmt.Println(string(bytes))
 		}
 		fmt.Println(string(bytes))
 	case http.StatusCreated:
@@ -48,11 +52,14 @@ func HTTPGet(apiEndpoint, f string, args ...string) error {
 		if err != nil {
 			return err
 		}
+		uuid := string(bytes[19:55])
+		viper.Set("LAST_DEVICE_UUID", uuid)
 		fmt.Println(string(bytes))
 	default:
 		log.WithFields(log.Fields{
 			"status code": resp.StatusCode,
 		}).Error("operation unsuccessful")
+		return errors.New(resp.Status)
 	}
 	return nil
 }
diff --git a/cli/integration_test.go b/cli/integration_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..3e1a36808bd34c5a337a313a38cb0e2b4798cb70
--- /dev/null
+++ b/cli/integration_test.go
@@ -0,0 +1,240 @@
+package cli
+
+import (
+	"os"
+	"testing"
+)
+
+const unreachable = "203.0.113.10:6030"
+
+var address = "141.100.70.171:6030"
+var apiEndpoint = "http://141.100.70.171:8080"
+var username = "admin"
+var password = "arista"
+var defaultPath = []string{"/system/config/hostname"}
+
+func testSetupIntegration() {
+	a := os.Getenv("GOSDN_TEST_ENDPOINT")
+	if a != "" {
+		address = a
+	}
+	api := os.Getenv("GOSDN_TEST_API_ENDPOINT")
+	if api != "" {
+		apiEndpoint = api
+	}
+}
+
+func TestMain(m *testing.M) {
+	testSetupIntegration()
+	os.Exit(m.Run())
+}
+
+func TestCapabilities(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping integration test")
+	}
+	type args struct {
+		a string
+		u string
+		p string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "default",
+			args: args{
+				a: address,
+				u: username,
+				p: password,
+			},
+			wantErr: false,
+		},
+		{
+			name: "destination unreachable",
+			args: args{
+				a: unreachable,
+				u: username,
+				p: password,
+			},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if err := Capabilities(tt.args.a, tt.args.u, tt.args.p); (err != nil) != tt.wantErr {
+				t.Errorf("Capabilities() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestGet(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping integration test")
+	}
+	type args struct {
+		a    string
+		u    string
+		p    string
+		args []string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "default",
+			args: args{
+				a:    address,
+				u:    username,
+				p:    password,
+				args: defaultPath,
+			},
+			wantErr: false,
+		},
+		{
+			name: "destination unreachable",
+			args: args{
+				a:    unreachable,
+				u:    username,
+				p:    password,
+				args: defaultPath,
+			},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if _,err := Get(tt.args.a, tt.args.u, tt.args.p, tt.args.args...); (err != nil) != tt.wantErr {
+				t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestHttpGet(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping integration test")
+	}
+	type args struct {
+		apiEndpoint string
+		f           string
+		args        []string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "default",
+			args: args{
+				apiEndpoint: apiEndpoint,
+				f:           "init",
+				args:        nil,
+			},
+			wantErr: false,
+		},
+		{
+			name: "destination unreachable",
+			args: args{
+				apiEndpoint: "http://" + unreachable,
+				f:           "init",
+				args:        nil,
+			},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if err := HttpGet(tt.args.apiEndpoint, tt.args.f, tt.args.args...); (err != nil) != tt.wantErr {
+				t.Errorf("HttpGet() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestPathTraversal(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping integration test")
+	}
+	tests := []struct {
+		name    string
+		wantErr bool
+	}{
+		{
+			name:    "default",
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if err := PathTraversal(); (err != nil) != tt.wantErr {
+				t.Errorf("PathTraversal() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestSet(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping integration test")
+	}
+	type args struct {
+		a    string
+		u    string
+		p    string
+		typ  string
+		args []string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "default",
+			args: args{
+				a:    address,
+				u:    username,
+				p:    password,
+				typ:  "update",
+				args: []string{"/system/config/hostname", "ceos3000"},
+			},
+			wantErr: false,
+		},
+		{
+			name: "destination unreachable",
+			args: args{
+				a:    unreachable,
+				u:    username,
+				p:    password,
+				typ:  "update",
+				args: []string{"/system/config/hostname", "ceos3000"},
+			},
+			wantErr: true,
+		},
+		{
+			name: "invalid path",
+			args: args{
+				a:    address,
+				u:    username,
+				p:    password,
+				typ:  "update",
+				args: []string{"invalid/path", "ceos3000"},
+			},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if err := Set(tt.args.a, tt.args.u, tt.args.p, tt.args.typ, tt.args.args...); (err != nil) != tt.wantErr {
+				t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
diff --git a/cli/ygot.go b/cli/ygot.go
deleted file mode 100644
index 51b12852e6274d94279972793333ea3be3131657..0000000000000000000000000000000000000000
--- a/cli/ygot.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package cli
-
-import (
-	"github.com/openconfig/ygot/util"
-	log "github.com/sirupsen/logrus"
-)
-
-func LeafPaths() error {
-	for _, v := range testSchema.SchemaTree {
-		entry, err := util.FindLeafRefSchema(v, "/interface/")
-		if err != nil {
-			log.Error(err)
-		}
-		log.Info(entry)
-	}
-	return nil
-}
diff --git a/cmd/get.go b/cmd/get.go
index 055d6c6f9ee9fb4a94262bc43317336a26a9e6ec..46a709e6d1d87e7497942ab3a902ccdac029c1bb 100644
--- a/cmd/get.go
+++ b/cmd/get.go
@@ -42,7 +42,8 @@ var getCmd = &cobra.Command{
 	Short: "get request",
 	Long:  `Sends a gNMI Get request to the specified target and prints the response to stdout`,
 	RunE: func(cmd *cobra.Command, args []string) error {
-		return cli.Get(address, username, password, args...)
+		_,err := cli.Get(address, username, password, args...)
+		return err
 	},
 }
 
diff --git a/cmd/integration_test.go b/cmd/integration_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..3eda98ed9d98a5d558d4084e32a02bb2426d9198
--- /dev/null
+++ b/cmd/integration_test.go
@@ -0,0 +1,131 @@
+package cmd
+
+import (
+	"code.fbi.h-da.de/cocsn/gosdn/cli"
+	guuid "github.com/google/uuid"
+	"github.com/spf13/viper"
+	"os"
+	"testing"
+)
+
+var testAddress = "141.100.70.171:6030"
+var testApiEndpoint = "http://141.100.70.171:8080"
+var testUsername = "admin"
+var testPassword = "arista"
+
+func testSetupIntegration() {
+	a := os.Getenv("GOSDN_TEST_ENDPOINT")
+	if a != "" {
+		testAddress = a
+	}
+	api := os.Getenv("GOSDN_TEST_API_ENDPOINT")
+	if api != "" {
+		testApiEndpoint = api
+	}
+	u := os.Getenv("GOSDN_TEST_USER")
+	if u != "" {
+		testUsername = u
+	}
+	p := os.Getenv("GOSDN_TEST_PASSWORD")
+	if p != "" {
+		testPassword = p
+	}
+}
+
+func TestMain(m *testing.M) {
+	testSetupIntegration()
+	os.Exit(m.Run())
+}
+
+func TestCliIntegration(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping integration test")
+	}
+	tests := []struct {
+		name    string
+		wantErr bool
+	}{
+		{
+			name:    "default",
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			defer viper.Reset()
+			if err := cli.HttpGet(testApiEndpoint, "init"); (err != nil) != tt.wantErr {
+				switch err.(type) {
+				case viper.ConfigFileNotFoundError:
+				default:
+					t.Errorf("gosdn cli init error = %v, wantErr %v", err, tt.wantErr)
+					return
+				}
+			}
+			cliPnd = viper.GetString("CLI_PND")
+			cliSbi = viper.GetString("CLI_SBI")
+
+			if err := cli.HttpGet(
+				testApiEndpoint,
+				"addDevice",
+				"address="+testAddress,
+				"password="+testPassword,
+				"username="+testUsername,
+				"sbi="+cliSbi,
+				"pnd="+cliPnd,
+			); (err != nil) != tt.wantErr {
+				t.Errorf("gosdn cli add-device error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			did := viper.GetString("LAST_DEVICE_UUID")
+
+			if err := cli.HttpGet(
+				testApiEndpoint,
+				"request",
+				"uuid="+did,
+				"sbi="+cliSbi,
+				"pnd="+cliPnd,
+				"path=/system/config/hostname",
+			); (err != nil) != tt.wantErr {
+				t.Errorf("gosdn cli request error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if err := cli.HttpGet(
+				testApiEndpoint,
+				"getDevice",
+				"address="+testAddress,
+				"uuid="+did,
+				"sbi="+cliSbi,
+				"pnd="+cliPnd,
+			); (err != nil) != tt.wantErr {
+				t.Errorf("gosdn cli get-device error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			hostname := guuid.New().String()
+			if err := cli.HttpGet(
+				testApiEndpoint,
+				"set",
+				"address="+testAddress,
+				"uuid="+did,
+				"sbi="+cliSbi,
+				"pnd="+cliPnd,
+				"path=/system/config/hostname",
+				"value="+hostname,
+			); (err != nil) != tt.wantErr {
+				t.Errorf("gosdn cli set error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			resp, err := cli.Get(testAddress, testUsername, testPassword, "/system/config/hostname")
+			if (err != nil) != tt.wantErr {
+				t.Errorf("cli.Get() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			got := resp.Notification[0].Update[0].Val.GetStringVal()
+			if got != hostname {
+				t.Errorf("integration test failed = got: %v, want: %v", got, hostname)
+			}
+		})
+	}
+}
diff --git a/nucleus/controller.go b/nucleus/controller.go
index ae666ee9dfb07e40671869b0f0c8b45fd339df7d..f9e2b6dd968e54172a8a1db92fe5850f107dfa5d 100644
--- a/nucleus/controller.go
+++ b/nucleus/controller.go
@@ -5,6 +5,9 @@ import (
 	"context"
 	"github.com/google/uuid"
 	log "github.com/sirupsen/logrus"
+	"net/http"
+	"os"
+	"os/signal"
 	"time"
 )
 
@@ -13,19 +16,28 @@ type Core struct {
 	// deprecated
 	database database.Database
 
-	pndc pndStore
-	sbic sbiStore
+	pndc       pndStore
+	sbic       sbiStore
+	httpServer *http.Server
+	stopChan   chan os.Signal
 }
 
 var c *Core
 
-//Initialize does start-up housekeeping like reading controller config files
-func initialize() error {
+func init() {
 	c = &Core{
-		database: database.Database{},
-		pndc:     pndStore{},
-		sbic:     sbiStore{},
+		database:   database.Database{},
+		pndc:       pndStore{},
+		sbic:       sbiStore{},
+		stopChan:   make(chan os.Signal, 1),
 	}
+
+	// Setting up signal capturing
+	signal.Notify(c.stopChan, os.Interrupt)
+}
+
+// initialize does start-up housekeeping like reading controller config files
+func initialize() error {
 	c.sbic = sbiStore{
 		store{},
 	}
@@ -84,10 +96,17 @@ func Run(ctx context.Context) error {
 	log.WithFields(log.Fields{}).Info("initialisation finished")
 	for {
 		select {
+		case <-c.stopChan:
+			return shutdown()
 		case <-ctx.Done():
-			return nil
+			return shutdown()
 		case <-time.Tick(time.Minute):
 			log.Debug("up and running")
 		}
 	}
 }
+
+func shutdown()error{
+	log.Info("shutting down controller")
+	return stopHttpServer()
+}
\ No newline at end of file
diff --git a/nucleus/controller_test.go b/nucleus/controller_test.go
index 0fa4ffa903a1f894325aaf5211341e19a2df754a..8b59316492b90f54093c586d75eb800320dc68ef 100644
--- a/nucleus/controller_test.go
+++ b/nucleus/controller_test.go
@@ -1 +1,52 @@
 package nucleus
+
+import (
+	"context"
+	"net/http"
+	"testing"
+	"time"
+)
+
+func TestRun(t *testing.T) {
+	type args struct {
+		request string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    interface{}
+		wantErr bool
+	}{
+		{
+			name:    "liveliness indicator",
+			args:    args{request: apiEndpoint + "/livez"},
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "readyness indicator",
+			args:    args{request: apiEndpoint + "/readyz"},
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "init",
+			args:    args{request: apiEndpoint + "/api?q=init"},
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ctx, cancel := context.WithCancel(context.Background())
+			go func() {
+				if err := Run(ctx); (err != nil) != tt.wantErr {
+					t.Errorf("Run() error = %v, wantErr %v", err, tt.wantErr)
+				}
+			}()
+			time.Sleep(time.Second)
+			cancel()
+			time.Sleep(time.Second)
+		})
+	}
+}
diff --git a/nucleus/errors_test.go b/nucleus/errors_test.go
deleted file mode 100644
index 09d172db926b14465fb4e16f641017a4f6d430ae..0000000000000000000000000000000000000000
--- a/nucleus/errors_test.go
+++ /dev/null
@@ -1,196 +0,0 @@
-package nucleus
-
-import "testing"
-
-func TestErrAlreadyExists_Error(t *testing.T) {
-	type fields struct {
-		item interface{}
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   string
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := &ErrAlreadyExists{
-				item: tt.fields.item,
-			}
-			if got := e.Error(); got != tt.want {
-				t.Errorf("Error() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestErrInvalidParameters_Error(t *testing.T) {
-	type fields struct {
-		f interface{}
-		r interface{}
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   string
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := ErrInvalidParameters{
-				f: tt.fields.f,
-				r: tt.fields.r,
-			}
-			if got := e.Error(); got != tt.want {
-				t.Errorf("Error() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestErrInvalidTransportOptions_Error(t *testing.T) {
-	type fields struct {
-		t interface{}
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   string
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := ErrInvalidTransportOptions{
-				t: tt.fields.t,
-			}
-			if got := e.Error(); got != tt.want {
-				t.Errorf("Error() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestErrInvalidTypeAssertion_Error(t *testing.T) {
-	type fields struct {
-		v interface{}
-		t interface{}
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   string
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := ErrInvalidTypeAssertion{
-				v: tt.fields.v,
-				t: tt.fields.t,
-			}
-			if got := e.Error(); got != tt.want {
-				t.Errorf("Error() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestErrNilClient_Error(t *testing.T) {
-	tests := []struct {
-		name string
-		want string
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := &ErrNilClient{}
-			if got := e.Error(); got != tt.want {
-				t.Errorf("Error() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestErrNil_Error(t *testing.T) {
-	tests := []struct {
-		name string
-		want string
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := &ErrNil{}
-			if got := e.Error(); got != tt.want {
-				t.Errorf("Error() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestErrNotFound_Error(t *testing.T) {
-	type fields struct {
-		id interface{}
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   string
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := &ErrNotFound{
-				id: tt.fields.id,
-			}
-			if got := e.Error(); got != tt.want {
-				t.Errorf("Error() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestErrNotYetImplemented_Error(t *testing.T) {
-	tests := []struct {
-		name string
-		want string
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := ErrNotYetImplemented{}
-			if got := e.Error(); got != tt.want {
-				t.Errorf("Error() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestErrUnsupportedPath_Error(t *testing.T) {
-	type fields struct {
-		p interface{}
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   string
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := ErrUnsupportedPath{
-				p: tt.fields.p,
-			}
-			if got := e.Error(); got != tt.want {
-				t.Errorf("Error() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
diff --git a/nucleus/gnmi_transport_test.go b/nucleus/gnmi_transport_test.go
index 9bc9a4de923b8d29fa0ca9ba5481f9b8e3ff51ca..d77cbe0caef4de1daf8f373b0bb821724ba3a0e3 100644
--- a/nucleus/gnmi_transport_test.go
+++ b/nucleus/gnmi_transport_test.go
@@ -47,6 +47,7 @@ func TestMain(m *testing.M) {
 	testSetupPnd()
 	testSetupStore()
 	testSetupSbi()
+	testSetupHttp()
 	testSetupIntegration()
 	os.Exit(m.Run())
 }
diff --git a/nucleus/http.go b/nucleus/http.go
index 7463c4d78135b8aed2114e4a8d1cdf88d79fa619..57b94ade9e5bafc855c7dc285408565079df5b6f 100644
--- a/nucleus/http.go
+++ b/nucleus/http.go
@@ -2,24 +2,40 @@ package nucleus
 
 import (
 	"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
+	"context"
 	"fmt"
 	"github.com/google/uuid"
 	gpb "github.com/openconfig/gnmi/proto/gnmi"
 	log "github.com/sirupsen/logrus"
 	"net/http"
 	"net/url"
+	"time"
 )
 
-const basePath = "/api"
+func stopHttpServer() error {
+	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+	defer cancel()
+	log.Info("shutting down http server")
+	return c.httpServer.Shutdown(ctx)
+}
 
-// deprecated
-func httpAPI() (err error) {
-	http.HandleFunc(basePath, httpHandler)
+func registerHttpHandler(){
+	defer func() {
+		if r := recover(); r != nil {
+			fmt.Println("Recovered in f", r)
+		}
+	}()
+	http.HandleFunc("/api", httpHandler)
 	http.HandleFunc("/livez", healthCheck)
-	http.HandleFunc("/readyz", healthCheck)
+	http.HandleFunc("/readyz", readynessCheck)
+}
 
+// deprecated
+func httpAPI() (err error) {
+	registerHttpHandler()
+	c.httpServer = &http.Server{Addr: ":8080"}
 	go func() {
-		err = http.ListenAndServe(":8080", nil)
+		err = c.httpServer.ListenAndServe()
 		if err != nil {
 			return
 		}
@@ -31,6 +47,11 @@ func healthCheck(writer http.ResponseWriter, request *http.Request) {
 	writer.WriteHeader(http.StatusOK)
 }
 
+func readynessCheck(writer http.ResponseWriter, request *http.Request) {
+	writer.WriteHeader(http.StatusOK)
+}
+
+// nolint
 func httpHandler(writer http.ResponseWriter, request *http.Request) {
 	log.WithFields(log.Fields{
 		"request": request,
@@ -39,6 +60,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
 	query, err := url.ParseQuery(request.URL.RawQuery)
 	if err != nil {
 		log.Error(err)
+		writer.WriteHeader(http.StatusBadRequest)
 		return
 	}
 
@@ -63,9 +85,19 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
 		pnd, err = c.pndc.get(pid)
 		if err != nil {
 			log.Error(err)
+			writer.WriteHeader(http.StatusInternalServerError)
+			return
 		}
 		sbic := pnd.GetSBIs()
 		sbi, err = sbic.(*sbiStore).get(sid)
+		if err != nil {
+			log.WithFields(log.Fields{
+				"requested uuid": sid,
+				"available uuids": sbic.(*sbiStore).UUIDs(),
+			}).Error(err)
+			writer.WriteHeader(http.StatusInternalServerError)
+			return
+		}
 	}
 
 	switch query.Get("q") {
@@ -83,7 +115,7 @@ func httpHandler(writer http.ResponseWriter, request *http.Request) {
 		})
 		err = pnd.AddDevice(d)
 		if err != nil {
-			writer.WriteHeader(http.StatusBadRequest)
+			writer.WriteHeader(http.StatusInternalServerError)
 			log.Error(err)
 			return
 		}
diff --git a/nucleus/http_test.go b/nucleus/http_test.go
index b4210a6a84ba092b1680eeb2667b609b24bf4748..4658b16423a1b5261989b8508b98b38a7b842aa9 100644
--- a/nucleus/http_test.go
+++ b/nucleus/http_test.go
@@ -1,25 +1,179 @@
 package nucleus
 
 import (
-	"context"
+	"code.fbi.h-da.de/cocsn/gosdn/mocks"
+	"errors"
+	"github.com/google/uuid"
+	log "github.com/sirupsen/logrus"
+	"github.com/stretchr/testify/mock"
+	"net/http"
 	"testing"
 )
 
-func Test_httpApi(t *testing.T) {
-	type args struct {
-		ctx context.Context
+const apiEndpoint = "http://localhost:8080"
+
+var sbi SouthboundInterface
+var pnd PrincipalNetworkDomain
+var args string
+var argsNotFound string
+var d Device
+
+func testSetupHttp() {
+	testSetupPnd()
+	sbi = &OpenConfig{id: defaultSbiID}
+	sbi.Schema()
+	var err error
+	pnd, err = NewPND("test", "test pnd", defaultPndID, sbi)
+	if err != nil {
+		log.Fatal(err)
+	}
+	d = mockDevice()
+	tr := d.Transport.(*mocks.Transport)
+	mockError := errors.New("mock error")
+	tr.On("Get", mockContext, "/system/config/hostname").Return(mock.Anything, nil)
+	tr.On("Get", mockContext, "error").Return(mock.Anything, mockError)
+	tr.On("Set", mockContext, mock.Anything).Return(mock.Anything, nil)
+	tr.On("ProcessResponse", mock.Anything, mock.Anything, mock.Anything).Return(nil)
+	if err := pnd.AddDevice(&d); err != nil {
+		log.Fatal(err)
+	}
+	args = "&uuid=" + mdid.String() + "&pnd=" + defaultPndID.String() + "&sbi=" + defaultSbiID.String()
+	argsNotFound = "&uuid=" + uuid.New().String() + "&pnd=" + defaultPndID.String() + "&sbi=" + defaultSbiID.String()
+
+	c = &Core{
+		pndc: pndStore{store{}},
+		sbic: sbiStore{store{}},
+	}
+	if err := c.sbic.add(sbi); err != nil {
+		log.Fatal(err)
+	}
+	if err := c.pndc.add(pnd); err != nil {
+		log.Fatal(err)
 	}
+}
+
+func Test_httpApi(t *testing.T) {
 	tests := []struct {
 		name    string
-		args    args
+		request string
+		want    *http.Response
 		wantErr bool
 	}{
-		// TODO: Add test cases.
+		{
+			name:    "liveliness indicator",
+			request: apiEndpoint + "/livez",
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "readyness indicator",
+			request: apiEndpoint + "/readyz",
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "init",
+			request: apiEndpoint + "/api?q=init",
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "get-ids",
+			request: apiEndpoint + "/api?q=getIDs",
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "add-device",
+			request: apiEndpoint + "/api?q=addDevice" + args,
+			want:    &http.Response{StatusCode: http.StatusCreated},
+			wantErr: false,
+		},
+		{
+			name:    "request",
+			request: apiEndpoint + "/api?q=request" + args + "&path=/system/config/hostname",
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "request not found",
+			request: apiEndpoint + "/api?q=request" + argsNotFound + "&path=/system/config/hostname",
+			want:    &http.Response{StatusCode: http.StatusNotFound},
+			wantErr: false,
+		},
+		{
+			name:    "request internal server error",
+			request: apiEndpoint + "/api?q=request" + args + "&path=error",
+			want:    &http.Response{StatusCode: http.StatusInternalServerError},
+			wantErr: false,
+		},
+		{
+			name:    "request-all",
+			request: apiEndpoint + "/api?q=requestAll" + args + "&path=/system/config/hostname",
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "request-all internal server error",
+			request: apiEndpoint + "/api?q=requestAll" + args + "&path=error",
+			want:    &http.Response{StatusCode: http.StatusInternalServerError},
+			wantErr: false,
+		},
+
+		{
+			name:    "get-device",
+			request: apiEndpoint + "/api?q=getDevice" + args,
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "get-device not found",
+			request: apiEndpoint + "/api?q=getDevice" + argsNotFound,
+			want:    &http.Response{StatusCode: http.StatusNotFound},
+			wantErr: false,
+		},
+		{
+			name:    "set",
+			request: apiEndpoint + "/api?q=set" + args + "&path=/system/config/hostname&value=ceos3000",
+			want:    &http.Response{StatusCode: http.StatusOK},
+			wantErr: false,
+		},
+		{
+			name:    "internal server errror: wrong pnd",
+			request: apiEndpoint + "/api?pnd=" + uuid.New().String(),
+			want:    &http.Response{StatusCode: http.StatusInternalServerError},
+			wantErr: false,
+		},
+		{
+			name:    "internal server errror: wrong sbi",
+			request: apiEndpoint + "/api?sbi=" + uuid.New().String(),
+			want:    &http.Response{StatusCode: http.StatusInternalServerError},
+			wantErr: false,
+		},
+	}
+	if err := httpAPI(); err != nil {
+		t.Errorf("httpApi() error = %v", err)
+		return
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			if err := httpAPI(); (err != nil) != tt.wantErr {
-				t.Errorf("httpAPI() error = %v, wantErr %v", err, tt.wantErr)
+			got, err := http.Get(tt.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("httpApi() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if got.StatusCode != tt.want.StatusCode {
+				t.Errorf("httpApi() got: %v, want %v", got.StatusCode, tt.want.StatusCode)
+			}
+			if tt.name == "add-device" {
+				for k := range pnd.(*pndImplementation).devices.store{
+					if k != mdid {
+						if err := pnd.RemoveDevice(k); err != nil {
+							t.Error(err)
+							return
+						}
+					}
+				}
 			}
 		})
 	}
diff --git a/test/terraform/containers.tf b/test/terraform/containers.tf
index a6e381a9169eef45337aaf0b843bc1c89ddebef0..f9144a450c0691daef380b918ccbbb90f311a0c2 100644
--- a/test/terraform/containers.tf
+++ b/test/terraform/containers.tf
@@ -5,13 +5,22 @@ resource "docker_container" "gosdn" {
   image = docker_image.gosdn.name
   restart = "always"
 
+  networks_advanced {
+    name = "bridge"
+  }
+
   ports {
     internal = 55055
     external = 5555
   }
 
+  ports {
+    internal = 8080
+    external = 8080
+  }
+
   env = [
-    "GOSDN_DEBUG=",
+    "GOSDN_LOG=debug",
     ]
 }