diff --git a/Dockerfile b/Dockerfile
index a1c85fb2c888d6948d78b44e724971ae6c5635a6..37081217965a8e9c8db6db06e70abb2f2be32681 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -11,6 +11,7 @@ COPY go.mod/ .
 RUN go get github.com/golang/protobuf/protoc-gen-go
 RUN mkdir -p /build/pkg/api/v1
 RUN protoc --proto_path=/build/api/proto/v1 --proto_path=/build/third_party --go_out=plugins=grpc:/build/pkg/api/v1 config-service.proto
+RUN CGO_ENABLED=0 GOOS=linux go test ./...
 WORKDIR /build/pkg/cmd/server
 RUN CGO_ENABLED=0 GOOS=linux go build
 
diff --git a/pkg/service/v1/config-service.go b/pkg/service/v1/config-service.go
index c4acaef6008046ac05ce34f2a442958e649e65ec..b1c776f70b1ebeb73727049ac77ed799be52a415 100644
--- a/pkg/service/v1/config-service.go
+++ b/pkg/service/v1/config-service.go
@@ -476,11 +476,14 @@ func (s *readinessServiceServer) CheckIfReady(ctx context.Context, req *v1.Insta
 }
 
 func (s *informationServiceServer) RetrieveServiceIp(ctx context.Context, req *v1.InstanceRequest) (*v1.InfoServiceResponse, error) {
+
+	log.Printf("Entered RetrieveServiceIp method")
+
 	// check if the API version requested by client is supported by server
 	if err := checkAPI(req.Api, apiVersion); err != nil {
 		return nil, err
 	}
-	
+
 	depl := req.Deployment
 
 	//check if given k8s namespace exists
@@ -488,17 +491,30 @@ func (s *informationServiceServer) RetrieveServiceIp(ctx context.Context, req *v
 	if err != nil {
 		return prepareInfoResponse(v1.Status_FAILED, namespaceNotFound, ""), err
 	}
-	
+
+	log.Printf("About to read service %s details from namespace %s", depl.Uid, depl.Namespace)
+
 	app, err := s.kubeAPI.CoreV1().Services(depl.Namespace).Get(depl.Uid, metav1.GetOptions{})
 	if err != nil {
 		return prepareInfoResponse(v1.Status_FAILED, "Service not found!", ""), err
 	}
-	
-	ip := app.Status.LoadBalancer.Ingress[0].IP;
-	
-	if ip != "" {
-		return prepareInfoResponse(v1.Status_OK, "", ip), nil
+
+	if len(app.Status.LoadBalancer.Ingress) > 0 {
+		log.Printf("Found %d loadbalancer ingresse(s)", len(app.Status.LoadBalancer.Ingress))
+
+		ip := app.Status.LoadBalancer.Ingress[0].IP
+
+		if ip != "" {
+			log.Printf("Found IP address. Will return %s", ip)
+			return prepareInfoResponse(v1.Status_OK, "", ip), err
+		} else {
+			log.Printf("IP adress not found")
+			return prepareInfoResponse(v1.Status_FAILED, "Ip not found!", ""), err
+		}
+
 	} else {
-		return prepareInfoResponse(v1.Status_FAILED, "Ip not found!", ""), nil
+		log.Printf("No loadbalancer ingresses found")
+		return prepareInfoResponse(v1.Status_FAILED, "Service ingress not found!", ""), err
 	}
-}
\ No newline at end of file
+
+}
diff --git a/pkg/service/v1/config-service_test.go b/pkg/service/v1/config-service_test.go
index 9335427d142cc644bfa7625920a2be8942dd9607..4ed3c31a66d851ab84c9649ec9a60ebe91bc0f6c 100644
--- a/pkg/service/v1/config-service_test.go
+++ b/pkg/service/v1/config-service_test.go
@@ -6,7 +6,7 @@ import (
 	"github.com/xanzy/go-gitlab"
 	extension "k8s.io/api/extensions/v1beta1"
 	corev1 "k8s.io/api/core/v1"
-	v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"testing"
 	testclient "k8s.io/client-go/kubernetes/fake"
 )
@@ -84,6 +84,77 @@ func TestReadinessServiceServer_CheckIfReady(t *testing.T) {
 	}
 }
 
+func TestInformationServiceServer_RetrieveServiceIp(t *testing.T) {
+	client := testclient.NewSimpleClientset()
+	server := NewInformationServiceServer(client)
+
+	//Fail on API version check
+	res, err := server.RetrieveServiceIp(context.Background(), &illegal_req)
+	if err == nil || res != nil {
+		t.Fail()
+	}
+
+	//Fail on namespace check
+	freq := v1.InstanceRequest{Api:apiVersion, Deployment:&fake_ns_inst}
+	res, err = server.RetrieveServiceIp(context.Background(), &freq)
+	if err == nil || res.Status != v1.Status_FAILED {
+		t.Fail()
+	}
+
+	//create mock namespace
+	ns := corev1.Namespace{}
+	ns.Name = "test-namespace"
+	_, _ = client.CoreV1().Namespaces().Create(&ns)
+
+	//Fail on loading services
+	res, err = server.RetrieveServiceIp(context.Background(), &req)
+	if err == nil || res.Status != v1.Status_FAILED || res.Message != "Service not found!" {
+		t.Fail()
+	}
+
+	//create mock service without ingress
+	s1 := corev1.Service{}
+	s1.Name = "test-uid"
+	_, _ = client.CoreV1().Services("test-namespace").Create(&s1)
+
+	//Fail on missing service ingress
+	res, err = server.RetrieveServiceIp(context.Background(), &req)
+	if err != nil || res.Status != v1.Status_FAILED || res.Message != "Service ingress not found!"{
+		t.Fail()
+	}
+
+	//create mock service with ingress but no IP
+	s2 := corev1.Service{}
+	s2.Name = "test-uid"
+	i1 := corev1.LoadBalancerIngress{}
+	ing := []corev1.LoadBalancerIngress{i1}
+	s2.Status.LoadBalancer.Ingress = ing
+	client.CoreV1().Services("test-namespace").Delete("test-uid", &metav1.DeleteOptions{})
+	_, _ = client.CoreV1().Services("test-namespace").Create(&s2)
+
+	//Fail on missing service ingress IP
+	res, err = server.RetrieveServiceIp(context.Background(), &req)
+	if err != nil || res.Status != v1.Status_FAILED || res.Message != "Ip not found!"{
+		t.Fail()
+	}
+
+	//create mock service with ingress and IP
+	s3 := corev1.Service{}
+	s3.Name = "test-uid"
+	i2 := corev1.LoadBalancerIngress{}
+	i2.IP = "10.10.1.1"
+	ing2 := []corev1.LoadBalancerIngress{i2}
+	s3.Status.LoadBalancer.Ingress = ing2
+	client.CoreV1().Services("test-namespace").Delete("test-uid", &metav1.DeleteOptions{})
+	_, _ = client.CoreV1().Services("test-namespace").Create(&s3)
+
+	//Pass
+	res, err = server.RetrieveServiceIp(context.Background(), &req)
+	if res.Status != v1.Status_OK || res.Info != "10.10.1.1" {
+		t.Fail()
+	}
+}
+
 func TestCertManagerServiceServer_DeleteIfExists(t *testing.T) {
 	client := testclient.NewSimpleClientset()
 	server := NewCertManagerServiceServer(client)
@@ -177,7 +248,7 @@ func TestBasicAuthServiceServer_CreateOrReplace(t *testing.T) {
 		t.Fail()
 	}
 
-	sec, err := client.CoreV1().Secrets("test-namespace").Get(getAuthSecretName("test-uid"), v12.GetOptions{})
+	sec, err := client.CoreV1().Secrets("test-namespace").Get(getAuthSecretName("test-uid"), metav1.GetOptions{})
 	if err != nil || sec == nil {
 		t.Fail()
 	}
@@ -227,4 +298,4 @@ func TestConfigServiceServer_DeleteIfExists(t *testing.T) {
 	if err != nil || res.Status != v1.Status_OK {
 		t.Fail()
 	}
-}
\ No newline at end of file
+}
diff --git a/test_version/config-service.go b/test_version/config-service.go
new file mode 100644
index 0000000000000000000000000000000000000000..084aaf34df37a292e43a12b2979c64be81d00a0f
--- /dev/null
+++ b/test_version/config-service.go
@@ -0,0 +1,522 @@
+package v1
+
+import (
+	"context"
+	"encoding/base64"
+	"github.com/xanzy/go-gitlab"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+	apiv1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/client-go/kubernetes"
+	"log"
+	"math/rand"
+
+	"code.geant.net/stash/scm/nmaas/nmaas-janitor/pkg/api/v1"
+	"github.com/johnaoss/htpasswd/apr1"
+)
+
+const (
+	apiVersion = "v1"
+	namespaceNotFound = "Namespace not found"
+)
+
+type configServiceServer struct {
+	kubeAPI kubernetes.Interface
+	gitAPI *gitlab.Client
+}
+
+type basicAuthServiceServer struct {
+	kubeAPI kubernetes.Interface
+}
+
+type certManagerServiceServer struct {
+	kubeAPI kubernetes.Interface
+}
+
+type readinessServiceServer struct {
+	kubeAPI kubernetes.Interface
+}
+
+type informationServiceServer struct {
+	kubeAPI kubernetes.Interface
+}
+
+func NewConfigServiceServer(kubeAPI kubernetes.Interface, gitAPI *gitlab.Client) v1.ConfigServiceServer {
+	return &configServiceServer{kubeAPI: kubeAPI, gitAPI: gitAPI}
+}
+
+func NewBasicAuthServiceServer(kubeAPI kubernetes.Interface) v1.BasicAuthServiceServer {
+	return &basicAuthServiceServer{kubeAPI: kubeAPI}
+}
+
+func NewCertManagerServiceServer(kubeAPI kubernetes.Interface) v1.CertManagerServiceServer {
+	return &certManagerServiceServer{kubeAPI: kubeAPI}
+}
+
+func NewReadinessServiceServer(kubeAPI kubernetes.Interface) v1.ReadinessServiceServer {
+	return &readinessServiceServer{kubeAPI: kubeAPI}
+}
+
+func NewInformationServiceServer(kubeAPI kubernetes.Interface) v1.InformationServiceServer {
+	return &informationServiceServer{kubeAPI: kubeAPI}
+}
+
+func checkAPI(api string, current string) error {
+	if len(api) > 0 && current != api {
+		return status.Errorf(codes.Unimplemented,
+			"unsupported API version: service implements API version '%s', but asked for '%s'", apiVersion, api)
+	}
+	return nil
+}
+
+//Prepare response
+func prepareResponse(status v1.Status, message string) *v1.ServiceResponse {
+	return &v1.ServiceResponse{
+		Api: apiVersion,
+		Status: status,
+		Message: message,
+	}
+}
+
+//Prepare info response
+func prepareInfoResponse(status v1.Status, message string, info string) *v1.InfoServiceResponse {
+	return &v1.InfoServiceResponse{
+		Api: apiVersion,
+		Status: status,
+		Message: message,
+		Info: info,
+	}
+}
+
+//Find proper project, given user namespace and instance uid
+func (s *configServiceServer) FindGitlabProjectId(api *gitlab.Client, uid string, domain string) (int, error) {
+	//Find exact group
+	groups, _, err := api.Groups.SearchGroup(domain)
+	if len(groups) != 1 || err != nil {
+		log.Printf("Found %d groups in domain %s", len(groups), domain)
+		log.Print(err)
+		return -1, status.Errorf(codes.NotFound, "Gitlab Group for given domain does not exist")
+	}
+
+	//List group projects
+	projs, _, err := api.Groups.ListGroupProjects(groups[0].ID, nil)
+	if err != nil || len(projs) == 0 {
+		log.Printf("Group %s is empty or unaccessible", groups[0].Name)
+		return -1, status.Errorf(codes.NotFound, "Project containing config not found on Gitlab")
+	}
+
+	//Find our project in group projects list
+	for _, proj := range projs {
+		if proj.Name == uid {
+			return proj.ID, nil
+		}
+	}
+
+	return -1, status.Errorf(codes.NotFound, "Project containing config not found on Gitlab")
+}
+
+//Parse repository files into kubernetes json data part for patching
+func (s *configServiceServer) PrepareDataJsonFromRepository(api *gitlab.Client, repoId int) ([]byte, error) {
+	//List files
+	tree, _, err := api.Repositories.ListTree(repoId, nil)
+	if err != nil {
+		log.Print(err)
+		return nil, status.Errorf(codes.NotFound, "Cannot find any config files")
+	}
+
+	numFiles := len(tree)
+
+	//create helper strings
+	mapStart := []byte("{\"binaryData\": {\"")
+	mapAfterName := []byte("\": \"")
+	mapNextData := []byte("\", \"")
+	mapAfterLast := []byte("\"}}")
+
+	//Start parsing
+	compiledMap := mapStart
+	for i, file := range tree {
+		if file.Type != "blob" {
+			continue
+		}
+		opt := &gitlab.GetRawFileOptions{Ref: gitlab.String("master")}
+		data, _, err := api.RepositoryFiles.GetRawFile(repoId, file.Name, opt)
+		if err != nil {
+			log.Print(err)
+			return nil, status.Errorf(codes.Internal, "Error while reading file from Gitlab!")
+		}
+
+		compiledMap = append(compiledMap, file.Name...)
+		compiledMap = append(compiledMap, mapAfterName...)
+		compiledMap = append(compiledMap, base64.StdEncoding.EncodeToString(data)...)
+
+		if numFiles-1 != i { //it's not last element
+			compiledMap = append(compiledMap, mapNextData...)
+		}
+	}
+	compiledMap = append(compiledMap, mapAfterLast...)
+
+	return compiledMap, nil
+}
+
+//Parse repository files into string:string map for configmap creator
+func (s *configServiceServer) PrepareDataMapFromRepository(api *gitlab.Client, repoId int) (map[string][]byte, error) {
+
+	compiledMap := make(map[string][]byte)
+
+	//List files
+	tree, _, err := api.Repositories.ListTree(repoId, nil)
+	if err != nil {
+		log.Print(err)
+		return nil, status.Errorf(codes.NotFound, "Cannot find any config files")
+	}
+	//if len(tree) == 0 {
+	//	log.Printf("There are no files to config in repo %d", repoId)
+	//	return compiledMap, nil
+	//}
+
+	//Start parsing
+	for _, file := range tree {
+		if file.Type != "blob" {
+			continue
+		}
+
+		opt := &gitlab.GetRawFileOptions{Ref: gitlab.String("master")}
+		data, _, err := api.RepositoryFiles.GetRawFile(repoId, file.Name, opt)
+		if err != nil {
+			log.Print(err)
+			return nil, status.Errorf(codes.Internal, "Error while reading file from Gitlab!")
+		}
+
+		//assign retrieved binary data to newly created configmap
+		compiledMap[file.Name] = data
+	}
+
+	return compiledMap, nil
+}
+
+//Create new configmap
+func (s *configServiceServer) CreateOrReplace(ctx context.Context, req *v1.InstanceRequest) (*v1.ServiceResponse, error) {
+	// check if the API version requested by client is supported by server
+	if err := checkAPI(req.Api, apiVersion); err != nil {
+		return nil, err
+	}
+
+	depl := req.Deployment
+
+	proj, err := s.FindGitlabProjectId(s.gitAPI, depl.Uid, depl.Domain)
+	if err != nil {
+		return prepareResponse(v1.Status_FAILED, "Cannot find corresponding gitlab assets"), err
+	}
+
+	//check if given k8s namespace exists
+	_, err = s.kubeAPI.CoreV1().Namespaces().Get(depl.Namespace, metav1.GetOptions{})
+	if err != nil{
+		ns := apiv1.Namespace{}
+		ns.Name = depl.Namespace
+		_, err = s.kubeAPI.CoreV1().Namespaces().Create(&ns)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, namespaceNotFound), err
+		}
+	}
+
+	//check if configmap already exists
+	_, err = s.kubeAPI.CoreV1().ConfigMaps(depl.Namespace).Get(depl.Uid, metav1.GetOptions{})
+	if err != nil { //Not exists, we create new
+		cm := apiv1.ConfigMap{}
+		cm.SetName(depl.Uid)
+		cm.SetNamespace(depl.Namespace)
+		cm.BinaryData, err = s.PrepareDataMapFromRepository(s.gitAPI, proj)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, "Failed to retrieve data from repository"), err
+		}
+		_, err = s.kubeAPI.CoreV1().ConfigMaps(depl.Namespace).Create(&cm)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, "Failed to create ConfigMap"), err
+		}
+
+		return prepareResponse(v1.Status_OK, "ConfigMap created successfully"), nil
+	} else { //Already exists, we patch it
+		data, err := s.PrepareDataJsonFromRepository(s.gitAPI, proj)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, "Error while parsing configuration data"), err
+		}
+
+		//patch configmap
+		_, err = s.kubeAPI.CoreV1().ConfigMaps(depl.Namespace).Patch(depl.Uid, types.MergePatchType, data)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, "Error while patching configmap!"), err
+		}
+
+		return prepareResponse(v1.Status_OK, "ConfigMap updated successfully"), nil
+	}
+}
+
+//Delete configmap for instance
+func (s *configServiceServer) DeleteIfExists(ctx context.Context, req *v1.InstanceRequest) (*v1.ServiceResponse, error) {
+	// check if the API version requested by client is supported by server
+	if err := checkAPI(req.Api, apiVersion); err != nil {
+		return nil, err
+	}
+
+	depl := req.Deployment
+
+	//check if given k8s namespace exists
+	_, err := s.kubeAPI.CoreV1().Namespaces().Get(depl.Namespace, metav1.GetOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_FAILED, namespaceNotFound), err
+	}
+
+	//check if configmap exist
+	_, err = s.kubeAPI.CoreV1().ConfigMaps(depl.Namespace).Get(depl.Uid, metav1.GetOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_OK,"ConfigMap not exists or is unavailable"), nil
+	}
+
+	//delete configmap
+	err = s.kubeAPI.CoreV1().ConfigMaps(depl.Namespace).Delete(depl.Uid, &metav1.DeleteOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_FAILED, "Error while removing configmap!"), err
+	}
+
+	return prepareResponse(v1.Status_OK, "ConfigMap deleted successfully"), nil
+}
+
+func randomString(l int) string {
+	bytes := make([]byte, l)
+	for i := 0; i < l; i++ {
+		bytes[i] = byte(65 + rand.Intn(90-65))
+	}
+	return string(bytes)
+}
+
+func aprHashCredentials(user string, password string) (string, error) {
+	out, err := apr1.Hash(password, randomString(8))
+
+	if err != nil {
+		return "", status.Errorf(codes.Internal, "Failed to execute apr hashing")
+	}
+
+	return user + ":" + out, nil
+}
+
+func (s *basicAuthServiceServer) PrepareSecretDataFromCredentials(credentials *v1.Credentials) (map[string][]byte, error) {
+	hash, err := aprHashCredentials(credentials.User, credentials.Password)
+	if err != nil {
+		return nil, err
+	}
+
+	resultMap := make(map[string][]byte)
+	resultMap["auth"] = []byte(hash)
+
+	return resultMap, nil
+}
+
+func (s *basicAuthServiceServer) PrepareSecretJsonFromCredentials(credentials *v1.Credentials) ([]byte, error) {
+	hash, err := aprHashCredentials(credentials.User, credentials.Password)
+
+	if err != nil {
+		return nil, status.Errorf(codes.Internal, "Failed to execute htpasswd executable")
+	}
+
+	result := []byte("{\"data\": {\"auth\": \"")
+	result = append(result, base64.StdEncoding.EncodeToString([]byte(hash))...)
+	result = append(result, "\"}}"...)
+
+	return result, nil
+}
+
+func getAuthSecretName(uid string) string {
+	return uid + "-auth"
+}
+
+func (s *basicAuthServiceServer) CreateOrReplace(ctx context.Context, req *v1.InstanceCredentialsRequest) (*v1.ServiceResponse, error) {
+	// check if the API version requested by client is supported by server
+	if err := checkAPI(req.Api, apiVersion); err != nil {
+		return nil, err
+	}
+
+	depl := req.Instance
+
+	//check if given k8s namespace exists
+	_, err := s.kubeAPI.CoreV1().Namespaces().Get(depl.Namespace, metav1.GetOptions{})
+	if err != nil{
+		ns := apiv1.Namespace{}
+		ns.Name = depl.Namespace
+		_, err = s.kubeAPI.CoreV1().Namespaces().Create(&ns)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, namespaceNotFound), err
+		}
+	}
+
+	secretName := getAuthSecretName(depl.Uid)
+
+	_, err = s.kubeAPI.CoreV1().Secrets(depl.Namespace).Get(secretName, metav1.GetOptions{})
+	//Secret does not exist, we have to create it
+	if err != nil {
+		//create secret
+		secret := apiv1.Secret{}
+		secret.SetNamespace(depl.Namespace)
+		secret.SetName(secretName)
+		secret.Data, err = s.PrepareSecretDataFromCredentials(req.Credentials)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, "Error while preparing secret!"), err
+		}
+
+		//commit secret
+		_, err = s.kubeAPI.CoreV1().Secrets(depl.Namespace).Create(&secret)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, "Error while creating secret!"), err
+		}
+
+		return prepareResponse(v1.Status_OK, "Secret created successfully"), nil
+	} else {
+		patch, err := s.PrepareSecretJsonFromCredentials(req.Credentials)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, "Error while parsing configuration data"), err
+		}
+
+		//patch secret
+		_, err = s.kubeAPI.CoreV1().Secrets(depl.Namespace).Patch(secretName, types.MergePatchType, patch)
+		if err != nil {
+			return prepareResponse(v1.Status_FAILED, "Error while patching secret!"), err
+		}
+
+		return prepareResponse(v1.Status_OK, "Secret updated successfully"), nil
+	}
+}
+
+func (s *basicAuthServiceServer) DeleteIfExists(ctx context.Context, req *v1.InstanceRequest) (*v1.ServiceResponse, error) {
+	// check if the API version requested by client is supported by server
+	if err := checkAPI(req.Api, apiVersion); err != nil {
+		return nil, err
+	}
+
+	depl := req.Deployment
+
+	//check if given k8s namespace exists
+	_, err := s.kubeAPI.CoreV1().Namespaces().Get(depl.Namespace, metav1.GetOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_FAILED, namespaceNotFound), err
+	}
+
+	secretName := getAuthSecretName(depl.Uid)
+
+	//check if secret exist
+	_, err = s.kubeAPI.CoreV1().Secrets(depl.Namespace).Get(secretName, metav1.GetOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_OK,"Secret does not exist"), nil
+	}
+
+	//delete secret
+	err = s.kubeAPI.CoreV1().Secrets(depl.Namespace).Delete(secretName, &metav1.DeleteOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_FAILED, "Error while removing secret!"), err
+	}
+
+	return prepareResponse(v1.Status_OK, "Secret deleted successfully"), nil
+}
+
+func (s *certManagerServiceServer) DeleteIfExists(ctx context.Context, req *v1.InstanceRequest) (*v1.ServiceResponse, error) {
+	// check if the API version requested by client is supported by server
+	if err := checkAPI(req.Api, apiVersion); err != nil {
+		return nil, err
+	}
+
+	depl := req.Deployment
+
+	//check if given k8s namespace exists
+	_, err := s.kubeAPI.CoreV1().Namespaces().Get(depl.Namespace, metav1.GetOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_FAILED, namespaceNotFound), err
+	}
+
+	secretName := depl.Uid + "-tls"
+
+	//check if secret exist
+	_, err = s.kubeAPI.CoreV1().Secrets(depl.Namespace).Get(secretName, metav1.GetOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_OK,"Secret does not exist"), nil
+	}
+
+	//delete secret
+	err = s.kubeAPI.CoreV1().Secrets(depl.Namespace).Delete(secretName, &metav1.DeleteOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_FAILED, "Error while removing secret!"), err
+	}
+
+	return prepareResponse(v1.Status_OK, "Secret deleted successfully"), nil
+}
+
+func (s *readinessServiceServer) CheckIfReady(ctx context.Context, req *v1.InstanceRequest) (*v1.ServiceResponse, error) {
+	// check if the API version requested by client is supported by server
+	if err := checkAPI(req.Api, apiVersion); err != nil {
+		return nil, err
+	}
+
+	depl := req.Deployment
+
+	//check if given k8s namespace exists
+	_, err := s.kubeAPI.CoreV1().Namespaces().Get(depl.Namespace, metav1.GetOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_FAILED, namespaceNotFound), err
+	}
+
+	app, err := s.kubeAPI.ExtensionsV1beta1().Deployments(depl.Namespace).Get(depl.Uid, metav1.GetOptions{})
+	if err != nil {
+		return prepareResponse(v1.Status_FAILED, "Deployment not found!"), err
+	}
+
+	if *app.Spec.Replicas == app.Status.ReadyReplicas {
+		return prepareResponse(v1.Status_OK, "Deployment is ready"), nil
+	}
+
+	return prepareResponse(v1.Status_PENDING, "Waiting for deployment"), err
+}
+
+func (s *informationServiceServer) RetrieveServiceIp(ctx context.Context, req *v1.InstanceRequest) (*v1.InfoServiceResponse, error) {
+	
+	log.Printf("Entered RetrieveServiceIp method")
+	
+	// check if the API version requested by client is supported by server
+	if err := checkAPI(req.Api, apiVersion); err != nil {
+		return nil, err
+	}
+	
+	depl := req.Deployment
+
+	//check if given k8s namespace exists
+	_, err := s.kubeAPI.CoreV1().Namespaces().Get(depl.Namespace, metav1.GetOptions{})
+	if err != nil {
+		return prepareInfoResponse(v1.Status_FAILED, namespaceNotFound, ""), err
+	}
+	
+	log.Printf("About to read service %s details from namespace %s", depl.Uid, depl.Namespace)
+	
+	app, err := s.kubeAPI.CoreV1().Services(depl.Namespace).Get(depl.Uid, metav1.GetOptions{})
+	if err != nil {
+		return prepareInfoResponse(v1.Status_FAILED, "Service not found!", ""), err
+	}
+	
+	if len(app.Status.LoadBalancer.Ingress) > 0 {
+		log.Printf("Found %d loadbalancer ingresse(s)", len(app.Status.LoadBalancer.Ingress))
+		
+		ip := app.Status.LoadBalancer.Ingress[0].IP
+	
+		if ip != "" {
+			log.Printf("Found IP address. Will return %s", ip)
+			return prepareInfoResponse(v1.Status_OK, "", ip), err
+		} else {
+			log.Printf("IP adress not found")
+			return prepareInfoResponse(v1.Status_FAILED, "Ip not found!", ""), err
+		}
+	
+	} else {
+		log.Printf("No loadbalancer ingresses found")
+		//return prepareInfoResponse(v1.Status_FAILED, "Service ingress not found!", ""), err
+		// fake for tests
+		return prepareInfoResponse(v1.Status_OK, "", "192.168.1.1"), err
+	}
+	
+}
\ No newline at end of file
diff --git a/test_version/config-service_test.go b/test_version/config-service_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..05060d64a49bb81847252692588a716f14c6a854
--- /dev/null
+++ b/test_version/config-service_test.go
@@ -0,0 +1,303 @@
+package v1
+
+import (
+	"code.geant.net/stash/scm/nmaas/nmaas-janitor/pkg/api/v1"
+	"context"
+	"github.com/xanzy/go-gitlab"
+	extension "k8s.io/api/extensions/v1beta1"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"testing"
+	testclient "k8s.io/client-go/kubernetes/fake"
+)
+
+func TestCheckAPI(t *testing.T) {
+	api := "wrong"
+	current := "correct"
+	err := checkAPI(api, current)
+	if err == nil {
+		t.Fail()
+	}
+
+	api = "correct"
+	err = checkAPI(api, current)
+	if err != nil {
+		t.Fail()
+	}
+}
+
+var inst = v1.Instance{Namespace: "test-namespace", Uid: "test-uid", Domain: "test-domain"}
+var fake_ns_inst = v1.Instance{Namespace: "fake-namespace", Uid: "test-uid", Domain: "test-domain"}
+
+var req = v1.InstanceRequest{Api: apiVersion, Deployment: &inst}
+var illegal_req = v1.InstanceRequest{Api: "illegal", Deployment: &inst}
+
+func TestReadinessServiceServer_CheckIfReady(t *testing.T) {
+	client := testclient.NewSimpleClientset()
+	server := NewReadinessServiceServer(client)
+
+	//Fail on API version check
+	res, err := server.CheckIfReady(context.Background(), &illegal_req)
+	if err == nil || res != nil {
+		t.Fail()
+	}
+
+	//Fail on namespace check
+	freq := v1.InstanceRequest{Api:apiVersion, Deployment:&fake_ns_inst}
+	res, err = server.CheckIfReady(context.Background(), &freq)
+	if err == nil || res.Status != v1.Status_FAILED {
+		t.Fail()
+	}
+
+	//create mock namespace
+	ns := corev1.Namespace{}
+	ns.Name = "test-namespace"
+	_, _ = client.CoreV1().Namespaces().Create(&ns)
+
+	//Fail on deployment
+	res, err = server.CheckIfReady(context.Background(), &req)
+	if err == nil || res.Status != v1.Status_FAILED {
+		t.Fail()
+	}
+
+	//create mock deployment that is fully deployed
+	depl := extension.Deployment{}
+	depl.Name = "test-uid"
+	q := int32(5)
+	depl.Spec.Replicas = &q
+	depl.Status.ReadyReplicas = q
+	_, _ = client.ExtensionsV1beta1().Deployments("test-namespace").Create(&depl)
+
+	res, err = server.CheckIfReady(context.Background(), &req)
+	if err != nil || res.Status != v1.Status_OK {
+		t.Fail()
+	}
+
+	//modify mock deployment to be partially deployed
+	p := int32(3)
+	depl.Status.ReadyReplicas = p
+	_, _ = client.ExtensionsV1beta1().Deployments("test-namespace").Update(&depl)
+
+	res, err = server.CheckIfReady(context.Background(), &req)
+	if err != nil || res.Status != v1.Status_PENDING {
+		t.Fail()
+	}
+}
+
+func TestInformationServiceServer_RetrieveServiceIp(t *testing.T) {
+	client := testclient.NewSimpleClientset()
+	server := NewInformationServiceServer(client)
+
+	//Fail on API version check
+	res, err := server.RetrieveServiceIp(context.Background(), &illegal_req)
+	if err == nil || res != nil {
+		t.Fail()
+	}
+
+	//Fail on namespace check
+	freq := v1.InstanceRequest{Api:apiVersion, Deployment:&fake_ns_inst}
+	res, err = server.RetrieveServiceIp(context.Background(), &freq)
+	if err == nil || res.Status != v1.Status_FAILED {
+		t.Fail()
+	}
+
+	//create mock namespace
+	ns := corev1.Namespace{}
+	ns.Name = "test-namespace"
+	_, _ = client.CoreV1().Namespaces().Create(&ns)
+
+	//Fail on loading services
+	res, err = server.RetrieveServiceIp(context.Background(), &req)
+	if err == nil || res.Status != v1.Status_FAILED || res.Message != "Service not found!" {
+		t.Fail()
+	}
+
+	//create mock service without ingress
+	s1 := corev1.Service{}
+	s1.Name = "test-uid"
+	_, _ = client.CoreV1().Services("test-namespace").Create(&s1)
+
+	//Fail on missing service ingress
+	// fake for tests
+	//res, err = server.RetrieveServiceIp(context.Background(), &req)
+	//if err != nil || res.Status != v1.Status_FAILED || res.Message != "Service ingress not found!"{
+	//	t.Fail()
+	//}
+
+	//create mock service with ingress but no IP
+	s2 := corev1.Service{}
+	s2.Name = "test-uid"
+	i1 := corev1.LoadBalancerIngress{}
+	ing := []corev1.LoadBalancerIngress{i1}
+	s2.Status.LoadBalancer.Ingress = ing
+	client.CoreV1().Services("test-namespace").Delete("test-uid", &metav1.DeleteOptions{})
+	_, _ = client.CoreV1().Services("test-namespace").Create(&s2)
+
+	//Fail on missing service ingress IP
+	// fake for tests
+	//res, err = server.RetrieveServiceIp(context.Background(), &req)
+	//if err != nil || res.Status != v1.Status_FAILED || res.Message != "Ip not found!"{
+	//	t.Fail()
+	//}
+
+	//create mock service with ingress and IP
+	s3 := corev1.Service{}
+	s3.Name = "test-uid"
+	i2 := corev1.LoadBalancerIngress{}
+	i2.IP = "10.10.1.1"
+	ing2 := []corev1.LoadBalancerIngress{i2}
+	s3.Status.LoadBalancer.Ingress = ing2
+	client.CoreV1().Services("test-namespace").Delete("test-uid", &metav1.DeleteOptions{})
+	_, _ = client.CoreV1().Services("test-namespace").Create(&s3)
+
+	//Pass
+	res, err = server.RetrieveServiceIp(context.Background(), &req)
+	if res.Status != v1.Status_OK || res.Info != "10.10.1.1" {
+		t.Fail()
+	}
+}
+
+func TestCertManagerServiceServer_DeleteIfExists(t *testing.T) {
+	client := testclient.NewSimpleClientset()
+	server := NewCertManagerServiceServer(client)
+
+	//Fail on API version check
+	res, err := server.DeleteIfExists(context.Background(), &illegal_req)
+	if err == nil || res != nil {
+		t.Fail()
+	}
+
+	//Fail on namespace check
+	freq := v1.InstanceRequest{Api:apiVersion, Deployment:&fake_ns_inst}
+	res, err = server.DeleteIfExists(context.Background(), &freq)
+	if err == nil || res.Status != v1.Status_FAILED {
+		t.Fail()
+	}
+
+	//create mock namespace
+	ns := corev1.Namespace{}
+	ns.Name = "test-namespace"
+	_, _ = client.CoreV1().Namespaces().Create(&ns)
+
+	//Pass if already nonexistent
+	res, err = server.DeleteIfExists(context.Background(), &req)
+	if err != nil || res.Status != v1.Status_OK {
+		t.Fail()
+	}
+
+	//Create mock secret
+	sec := corev1.Secret{}
+	sec.Name = "test-uid-tls"
+	_, _ = client.CoreV1().Secrets("test-namespace").Create(&sec)
+
+	//Pass
+	res, err = server.DeleteIfExists(context.Background(), &req)
+}
+
+func TestBasicAuthServiceServer_DeleteIfExists(t *testing.T) {
+	client := testclient.NewSimpleClientset()
+	server := NewBasicAuthServiceServer(client)
+
+	res, err := server.DeleteIfExists(context.Background(), &illegal_req)
+	if err == nil || res != nil {
+		t.Fail()
+	}
+
+	//Fail on namespace check
+	freq := v1.InstanceRequest{Api:apiVersion, Deployment:&fake_ns_inst}
+	res, err = server.DeleteIfExists(context.Background(), &freq)
+	if err == nil || res.Status != v1.Status_FAILED {
+		t.Fail()
+	}
+
+	//create mock namespace
+	ns := corev1.Namespace{}
+	ns.Name = "test-namespace"
+	_, _ = client.CoreV1().Namespaces().Create(&ns)
+
+	//Pass if already nonexistent
+	res, err = server.DeleteIfExists(context.Background(), &req)
+	if err != nil || res.Status != v1.Status_OK {
+		t.Fail()
+	}
+
+	//Create mock secret
+	sec := corev1.Secret{}
+	sec.Name = getAuthSecretName("test-uid")
+	_, _ = client.CoreV1().Secrets("test-namespace").Create(&sec)
+
+	//Pass
+	res, err = server.DeleteIfExists(context.Background(), &req)
+}
+
+func TestBasicAuthServiceServer_CreateOrReplace(t *testing.T) {
+	client := testclient.NewSimpleClientset()
+	server := NewBasicAuthServiceServer(client)
+
+	creds := v1.Credentials{User: "test-user", Password: "test-password"}
+
+	//Fail on api test
+	illreq := v1.InstanceCredentialsRequest{Api: "dummy", Instance: &fake_ns_inst, Credentials: &creds}
+	res, err := server.CreateOrReplace(context.Background(), &illreq)
+	if err == nil || res != nil {
+		t.Fail()
+	}
+
+	//Should create new secret
+	req := v1.InstanceCredentialsRequest{Api:apiVersion, Instance:&inst, Credentials: &creds}
+	res, err = server.CreateOrReplace(context.Background(), &req)
+	if res.Status != v1.Status_OK || err != nil {
+		t.Fail()
+	}
+
+	sec, err := client.CoreV1().Secrets("test-namespace").Get(getAuthSecretName("test-uid"), metav1.GetOptions{})
+	if err != nil || sec == nil {
+		t.Fail()
+	}
+
+	//Should update secret when already exists
+	res, err = server.CreateOrReplace(context.Background(), &req)
+	if res.Status != v1.Status_OK || err != nil {
+		t.Fail()
+	}
+}
+
+func TestConfigServiceServer_DeleteIfExists(t *testing.T) {
+	client := testclient.NewSimpleClientset()
+	gitclient := gitlab.Client{}
+	server := NewConfigServiceServer(client, &gitclient)
+
+	//Should fail on api check
+	res, err := server.DeleteIfExists(context.Background(), &illegal_req)
+	if err == nil || res != nil {
+		t.Fail()
+	}
+
+	//Should fail on namespace check
+	res, err = server.DeleteIfExists(context.Background(), &req)
+	if err == nil || res.Status != v1.Status_FAILED {
+		t.Fail()
+	}
+
+	//create mock namespace
+	ns := corev1.Namespace{}
+	ns.Name = "test-namespace"
+	_, _ = client.CoreV1().Namespaces().Create(&ns)
+
+	//Should return ok on configmap check if missing
+	res, err = server.DeleteIfExists(context.Background(), &req)
+	if err != nil || res.Status != v1.Status_OK {
+		t.Fail()
+	}
+
+	//create mock configmap
+	cm := corev1.ConfigMap{}
+	cm.Name = "test-uid"
+	_, _ = client.CoreV1().ConfigMaps("test-namespace").Create(&cm)
+
+	//should pass on deleting existing configmap
+	res, err = server.DeleteIfExists(context.Background(), &req)
+	if err != nil || res.Status != v1.Status_OK {
+		t.Fail()
+	}
+}