Ver código fonte

testing for gorm service accounts and projects'

Alexander Belanger 5 anos atrás
pai
commit
8124553b00

+ 1 - 1
cmd/app/main.go

@@ -10,7 +10,7 @@ import (
 
 	"github.com/porter-dev/porter/server/api"
 
-	adapter "github.com/porter-dev/porter/internal/adapter"
+	"github.com/porter-dev/porter/internal/adapter"
 	sessionstore "github.com/porter-dev/porter/internal/auth"
 	"github.com/porter-dev/porter/internal/config"
 	lr "github.com/porter-dev/porter/internal/logger"

+ 6 - 2
internal/adapter/gorm.go

@@ -1,4 +1,4 @@
-package gorm
+package adapter
 
 import (
 	"fmt"
@@ -13,7 +13,11 @@ import (
 // New returns a new gorm database instance
 func New(conf *config.DBConf) (*gorm.DB, error) {
 	if conf.SQLLite {
-		return gorm.Open(sqlite.Open(conf.SQLLitePath), &gorm.Config{})
+		// we add DisableForeignKeyConstraintWhenMigrating since our sqlite does
+		// not support foreign key constraints
+		return gorm.Open(sqlite.Open(conf.SQLLitePath), &gorm.Config{
+			DisableForeignKeyConstraintWhenMigrating: true,
+		})
 	}
 
 	dsn := fmt.Sprintf(

+ 2 - 0
internal/models/action.go

@@ -18,6 +18,8 @@ const (
 type ServiceAccountAction struct {
 	gorm.Model
 
+	ServiceAccountCandidateID uint
+
 	// One of the constant action names
 	Name     string `json:"name"`
 	Resolved bool   `json:"resolved"`

+ 4 - 2
internal/models/project.go

@@ -8,8 +8,10 @@ import (
 type Project struct {
 	gorm.Model
 
-	Name  string `json:"name"`
-	Roles []Role `json:"roles"`
+	Name                     string                    `json:"name"`
+	Roles                    []Role                    `json:"roles"`
+	ServiceAccountCandidates []ServiceAccountCandidate `json:"sa_candidates"`
+	ServiceAccounts          []ServiceAccount          `json:"serviceaccounts"`
 }
 
 // ProjectExternal represents the Project type that is sent over REST

+ 3 - 3
internal/models/serviceaccount.go

@@ -80,9 +80,9 @@ type ServiceAccount struct {
 	AuthMechanism string `json:"auth_mechanism"`
 
 	// These fields are used by all auth mechanisms
-	LocationOfOrigin  string
-	Impersonate       string   `json:"act-as,omitempty"`
-	ImpersonateGroups []string `json:"act-as-groups,omitempty"`
+	LocationOfOrigin string
+	Impersonate      string `json:"act-as,omitempty"`
+	// ImpersonateGroups []string `json:"act-as-groups,omitempty"`
 
 	// ------------------------------------------------------------------
 	// All fields below this line are encrypted before storage

+ 10 - 2
internal/repository/gorm/project.go

@@ -28,7 +28,13 @@ func (repo *ProjectRepository) CreateProject(project *models.Project) (*models.P
 
 // CreateProjectRole appends a role to the existing array of roles
 func (repo *ProjectRepository) CreateProjectRole(project *models.Project, role *models.Role) (*models.Role, error) {
-	if err := repo.db.Model(&project).Association("Roles").Append([]models.Role{*role}); err != nil {
+	assoc := repo.db.Model(&project).Association("Roles")
+
+	if assoc.Error != nil {
+		return nil, assoc.Error
+	}
+
+	if err := assoc.Append(role); err != nil {
 		return nil, err
 	}
 
@@ -38,8 +44,10 @@ func (repo *ProjectRepository) CreateProjectRole(project *models.Project, role *
 // ReadProject gets a projects specified by a unique id
 func (repo *ProjectRepository) ReadProject(id uint) (*models.Project, error) {
 	project := &models.Project{}
-	if err := repo.db.Where("id = ?", id).First(&project).Error; err != nil {
+
+	if err := repo.db.Preload("Roles").Where("id = ?", id).First(&project).Error; err != nil {
 		return nil, err
 	}
+
 	return project, nil
 }

+ 176 - 0
internal/repository/gorm/project_test.go

@@ -0,0 +1,176 @@
+package gorm_test
+
+import (
+	"os"
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/porter-dev/porter/internal/models"
+
+	"github.com/porter-dev/porter/internal/adapter"
+	"github.com/porter-dev/porter/internal/config"
+	"github.com/porter-dev/porter/internal/repository"
+	"github.com/porter-dev/porter/internal/repository/gorm"
+
+	orm "gorm.io/gorm"
+)
+
+type tester struct {
+	repo             *repository.Repository
+	dbFileName       string
+	initProjects     []*models.Project
+	initSACandidates []*models.ServiceAccountCandidate
+	initSAs          []*models.ServiceAccount
+}
+
+func setupTestEnv(tester *tester, t *testing.T) {
+	t.Helper()
+
+	db, err := adapter.New(&config.DBConf{
+		EncryptionKey: "__random_strong_encryption_key__",
+		SQLLite:       true,
+		SQLLitePath:   tester.dbFileName,
+	})
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	err = db.AutoMigrate(
+		&models.Project{},
+		&models.Role{},
+		&models.ServiceAccount{},
+		&models.ServiceAccountAction{},
+		&models.ServiceAccountCandidate{},
+		&models.Cluster{},
+		&models.User{},
+		&models.Session{},
+	)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.repo = gorm.NewRepository(db)
+}
+
+func cleanup(tester *tester, t *testing.T) {
+	t.Helper()
+
+	// remove the created file file
+	os.Remove(tester.dbFileName)
+}
+
+func initProject(tester *tester, t *testing.T) {
+	t.Helper()
+
+	proj := &models.Project{
+		Name: "project-test",
+	}
+
+	proj, err := tester.repo.Project.CreateProject(proj)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initProjects = append(tester.initProjects, proj)
+}
+
+func TestCreateProject(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_create_proj.db",
+	}
+
+	setupTestEnv(tester, t)
+	defer cleanup(tester, t)
+
+	proj := &models.Project{
+		Name: "project-test",
+	}
+
+	proj, err := tester.repo.Project.CreateProject(proj)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	proj, err = tester.repo.Project.ReadProject(proj.Model.ID)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	// make sure id is 1 and name is "project-test"
+	if proj.Model.ID != 1 {
+		t.Errorf("incorrect project ID: expected %d, got %d\n", 1, proj.Model.ID)
+	}
+
+	if proj.Name != "project-test" {
+		t.Errorf("incorrect project name: expected %s, got %s\n", "project-test", proj.Name)
+	}
+}
+
+func TestCreateProjectRole(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_create_proj_role.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	defer cleanup(tester, t)
+
+	role := &models.Role{
+		Kind:      models.RoleAdmin,
+		UserID:    0,
+		ProjectID: tester.initProjects[0].Model.ID,
+	}
+
+	role, err := tester.repo.Project.CreateProjectRole(tester.initProjects[0], role)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	proj, err := tester.repo.Project.ReadProject(tester.initProjects[0].Model.ID)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	// make sure IDs are correct
+	if proj.Model.ID != 1 {
+		t.Errorf("incorrect project ID: expected %d, got %d\n", 1, proj.Model.ID)
+	}
+
+	if len(proj.Roles) != 1 {
+		t.Fatalf("project roles incorrect length: expected %d, got %d\n", 1, len(proj.Roles))
+	}
+
+	if proj.Roles[0].Model.ID != 1 {
+		t.Fatalf("incorrect role ID: expected %d, got %d\n", 1, proj.Roles[0].Model.ID)
+	}
+
+	// make sure data is correct
+	expProj := &models.Project{
+		Name: "project-test",
+		Roles: []models.Role{
+			models.Role{
+				Kind:      models.RoleAdmin,
+				UserID:    0,
+				ProjectID: 1,
+			},
+		},
+	}
+
+	copyProj := proj
+
+	// reset fields for reflect.DeepEqual
+	copyProj.Model = orm.Model{}
+	copyProj.Roles[0].Model = orm.Model{}
+
+	if diff := deep.Equal(copyProj, expProj); diff != nil {
+		t.Errorf("incorrect project")
+		t.Error(diff)
+	}
+}

+ 4 - 3
internal/repository/gorm/repository.go

@@ -9,8 +9,9 @@ import (
 // gorm.DB for querying the database
 func NewRepository(db *gorm.DB) *repository.Repository {
 	return &repository.Repository{
-		User:    NewUserRepository(db),
-		Session: NewSessionRepository(db),
-		Project: NewProjectRepository(db),
+		User:           NewUserRepository(db),
+		Session:        NewSessionRepository(db),
+		Project:        NewProjectRepository(db),
+		ServiceAccount: NewServiceAccountRepository(db),
 	}
 }

+ 119 - 0
internal/repository/gorm/serviceaccount.go

@@ -0,0 +1,119 @@
+package gorm
+
+import (
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
+)
+
+// ServiceAccountRepository uses gorm.DB for querying the database
+type ServiceAccountRepository struct {
+	db *gorm.DB
+}
+
+// NewServiceAccountRepository returns a ServiceAccountRepository which uses
+// gorm.DB for querying the database
+func NewServiceAccountRepository(db *gorm.DB) repository.ServiceAccountRepository {
+	return &ServiceAccountRepository{db}
+}
+
+// CreateServiceAccountCandidate creates a new service account candidate
+func (repo *ServiceAccountRepository) CreateServiceAccountCandidate(
+	saCandidate *models.ServiceAccountCandidate,
+) (*models.ServiceAccountCandidate, error) {
+	project := &models.Project{}
+
+	if err := repo.db.Where("id = ?", saCandidate.ProjectID).First(&project).Error; err != nil {
+		return nil, err
+	}
+
+	assoc := repo.db.Model(&project).Association("ServiceAccountCandidates")
+
+	if assoc.Error != nil {
+		return nil, assoc.Error
+	}
+
+	if err := assoc.Append(saCandidate); err != nil {
+		return nil, err
+	}
+
+	return saCandidate, nil
+}
+
+// ReadServiceAccountCandidate finds a service account candidate by id
+func (repo *ServiceAccountRepository) ReadServiceAccountCandidate(
+	id uint,
+) (*models.ServiceAccountCandidate, error) {
+	saCandidate := &models.ServiceAccountCandidate{}
+
+	if err := repo.db.Preload("Actions").Where("id = ?", id).First(&saCandidate).Error; err != nil {
+		return nil, err
+	}
+
+	return saCandidate, nil
+}
+
+// ListServiceAccountCandidatesByProjectID finds all service account candidates
+// for a given project id
+func (repo *ServiceAccountRepository) ListServiceAccountCandidatesByProjectID(
+	projectID uint,
+) ([]*models.ServiceAccountCandidate, error) {
+	saCandidates := []*models.ServiceAccountCandidate{}
+
+	if err := repo.db.Preload("Actions").Where("project_id = ?", projectID).Find(&saCandidates).Error; err != nil {
+		return nil, err
+	}
+
+	return saCandidates, nil
+}
+
+// CreateServiceAccount creates a new servicea account
+func (repo *ServiceAccountRepository) CreateServiceAccount(
+	sa *models.ServiceAccount,
+) (*models.ServiceAccount, error) {
+	project := &models.Project{}
+
+	if err := repo.db.Where("id = ?", sa.ProjectID).First(&project).Error; err != nil {
+		return nil, err
+	}
+
+	assoc := repo.db.Model(&project).Association("ServiceAccounts")
+
+	if assoc.Error != nil {
+		return nil, assoc.Error
+	}
+
+	if err := assoc.Append(sa); err != nil {
+		return nil, err
+	}
+
+	return sa, nil
+}
+
+// ReadServiceAccount finds a service account by id
+func (repo *ServiceAccountRepository) ReadServiceAccount(
+	id uint,
+) (*models.ServiceAccount, error) {
+	sa := &models.ServiceAccount{}
+
+	// preload Clusters association
+	if err := repo.db.Preload("Clusters").Where("id = ?", id).First(&sa).Error; err != nil {
+		return nil, err
+	}
+
+	return sa, nil
+}
+
+// ListServiceAccountsByProjectID finds all service accounts
+// for a given project id
+func (repo *ServiceAccountRepository) ListServiceAccountsByProjectID(
+	projectID uint,
+) ([]*models.ServiceAccount, error) {
+	sas := []*models.ServiceAccount{}
+
+	if err := repo.db.Preload("Clusters").Where("project_id = ?", projectID).Find(&sas).Error; err != nil {
+		return nil, err
+	}
+
+	return sas, nil
+}

+ 389 - 0
internal/repository/gorm/serviceaccount_test.go

@@ -0,0 +1,389 @@
+package gorm_test
+
+import (
+	"testing"
+
+	"github.com/go-test/deep"
+	"github.com/porter-dev/porter/internal/models"
+	orm "gorm.io/gorm"
+)
+
+func initServiceAccountCandidate(tester *tester, t *testing.T) {
+	t.Helper()
+
+	saCandidate := &models.ServiceAccountCandidate{
+		ProjectID:       1,
+		Kind:            "connector",
+		ClusterName:     "cluster-test",
+		ClusterEndpoint: "https://localhost",
+		AuthMechanism:   models.X509,
+		Actions: []models.ServiceAccountAction{
+			models.ServiceAccountAction{
+				Name:     models.TokenDataAction,
+				Resolved: false,
+			},
+		},
+	}
+
+	saCandidate, err := tester.repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initSACandidates = append(tester.initSACandidates, saCandidate)
+}
+
+func initServiceAccount(tester *tester, t *testing.T) {
+	t.Helper()
+
+	sa := &models.ServiceAccount{
+		ProjectID:             1,
+		Kind:                  "connector",
+		AuthMechanism:         models.X509,
+		ClientCertificateData: []byte("-----BEGIN"),
+		ClientKeyData:         []byte("-----BEGIN"),
+		Clusters: []models.Cluster{
+			models.Cluster{
+				Name:   "cluster-test",
+				Server: "https://localhost",
+			},
+		},
+	}
+
+	sa, err := tester.repo.ServiceAccount.CreateServiceAccount(sa)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	tester.initSAs = append(tester.initSAs, sa)
+}
+
+func TestCreateServiceAccountCandidate(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_create_sa_candidate.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	defer cleanup(tester, t)
+
+	saCandidate := &models.ServiceAccountCandidate{
+		ProjectID:       1,
+		Kind:            "connector",
+		ClusterName:     "cluster-test",
+		ClusterEndpoint: "https://localhost",
+		AuthMechanism:   models.X509,
+	}
+
+	saCandidate, err := tester.repo.ServiceAccount.CreateServiceAccountCandidate(saCandidate)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	saCandidate, err = tester.repo.ServiceAccount.ReadServiceAccountCandidate(saCandidate.Model.ID)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	// make sure id is 1
+	if saCandidate.Model.ID != 1 {
+		t.Errorf("incorrect service accound candidate ID: expected %d, got %d\n", 1, saCandidate.Model.ID)
+	}
+
+	// make sure data is correct
+	expSACandidate := &models.ServiceAccountCandidate{
+		ProjectID:       1,
+		Kind:            "connector",
+		ClusterName:     "cluster-test",
+		ClusterEndpoint: "https://localhost",
+		AuthMechanism:   models.X509,
+		Actions:         []models.ServiceAccountAction{},
+	}
+
+	copySACandidate := saCandidate
+
+	// reset fields for reflect.DeepEqual
+	copySACandidate.Model = orm.Model{}
+
+	if diff := deep.Equal(copySACandidate, expSACandidate); diff != nil {
+		t.Errorf("incorrect sa candidate")
+		t.Error(diff)
+	}
+}
+
+func TestCreateServiceAccountCandidateWithAction(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_create_sa_candidate_w_action.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	initServiceAccountCandidate(tester, t)
+	defer cleanup(tester, t)
+
+	saCandidate := tester.initSACandidates[0]
+
+	saCandidate, err := tester.repo.ServiceAccount.ReadServiceAccountCandidate(saCandidate.Model.ID)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	// make sure IDs are correct
+	if saCandidate.Model.ID != 1 {
+		t.Errorf("incorrect service account candidate ID: expected %d, got %d\n", 1, saCandidate.Model.ID)
+	}
+
+	if len(saCandidate.Actions) != 1 {
+		t.Errorf("incorrect actions length: expected %d, got %d\n", 1, len(saCandidate.Actions))
+	}
+
+	if saCandidate.Actions[0].Model.ID != 1 {
+		t.Errorf("incorrect actions ID: expected %d, got %d\n", 1, saCandidate.Actions[0].Model.ID)
+	}
+
+	// make sure data is correct
+	expSACandidate := &models.ServiceAccountCandidate{
+		ProjectID:       1,
+		Kind:            "connector",
+		ClusterName:     "cluster-test",
+		ClusterEndpoint: "https://localhost",
+		AuthMechanism:   models.X509,
+		Actions: []models.ServiceAccountAction{
+			models.ServiceAccountAction{
+				ServiceAccountCandidateID: 1,
+				Name:                      models.TokenDataAction,
+				Resolved:                  false,
+			},
+		},
+	}
+
+	copySACandidate := saCandidate
+
+	// reset fields for reflect.DeepEqual
+	copySACandidate.Model = orm.Model{}
+	copySACandidate.Actions[0].Model = orm.Model{}
+
+	if diff := deep.Equal(copySACandidate, expSACandidate); diff != nil {
+		t.Errorf("incorrect sa candidate")
+		t.Error(diff)
+	}
+}
+
+func TestListServiceAccountCandidatesByProjectID(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_list_sa_candidates.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	initServiceAccountCandidate(tester, t)
+	defer cleanup(tester, t)
+
+	saCandidates, err := tester.repo.ServiceAccount.ListServiceAccountCandidatesByProjectID(
+		tester.initProjects[0].Model.ID,
+	)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	if len(saCandidates) != 1 {
+		t.Fatalf("length of sa candidates incorrect: expected %d, got %d\n", 1, len(saCandidates))
+	}
+
+	// make sure data is correct
+	expSACandidate := &models.ServiceAccountCandidate{
+		ProjectID:       1,
+		Kind:            "connector",
+		ClusterName:     "cluster-test",
+		ClusterEndpoint: "https://localhost",
+		AuthMechanism:   models.X509,
+		Actions: []models.ServiceAccountAction{
+			models.ServiceAccountAction{
+				ServiceAccountCandidateID: 1,
+				Name:                      models.TokenDataAction,
+				Resolved:                  false,
+			},
+		},
+	}
+
+	copySACandidate := saCandidates[0]
+
+	// reset fields for reflect.DeepEqual
+	copySACandidate.Model = orm.Model{}
+	copySACandidate.Actions[0].Model = orm.Model{}
+
+	if diff := deep.Equal(copySACandidate, expSACandidate); diff != nil {
+		t.Errorf("incorrect sa candidate")
+		t.Error(diff)
+	}
+}
+
+func TestCreateServiceAccount(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_create_sa.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	defer cleanup(tester, t)
+
+	sa := &models.ServiceAccount{
+		ProjectID:             1,
+		Kind:                  "connector",
+		AuthMechanism:         models.X509,
+		ClientCertificateData: []byte("-----BEGIN"),
+		ClientKeyData:         []byte("-----BEGIN"),
+	}
+
+	sa, err := tester.repo.ServiceAccount.CreateServiceAccount(sa)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	sa, err = tester.repo.ServiceAccount.ReadServiceAccount(sa.Model.ID)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	// make sure id is 1
+	if sa.Model.ID != 1 {
+		t.Errorf("incorrect service account ID: expected %d, got %d\n", 1, sa.Model.ID)
+	}
+
+	// make sure data is correct
+	expSA := &models.ServiceAccount{
+		ProjectID:             1,
+		Kind:                  "connector",
+		AuthMechanism:         models.X509,
+		ClientCertificateData: []byte("-----BEGIN"),
+		ClientKeyData:         []byte("-----BEGIN"),
+		Clusters:              []models.Cluster{},
+	}
+
+	copySA := sa
+
+	// reset fields for reflect.DeepEqual
+	copySA.Model = orm.Model{}
+
+	if diff := deep.Equal(copySA, expSA); diff != nil {
+		t.Errorf("incorrect service account")
+		t.Error(diff)
+	}
+}
+
+func TestCreateServiceAccountWithCluster(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_create_sa_w_cluster.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	initServiceAccount(tester, t)
+	defer cleanup(tester, t)
+
+	sa := tester.initSAs[0]
+
+	sa, err := tester.repo.ServiceAccount.ReadServiceAccount(sa.Model.ID)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	// make sure id is 1
+	if sa.Model.ID != 1 {
+		t.Errorf("incorrect service account ID: expected %d, got %d\n", 1, sa.Model.ID)
+	}
+
+	if len(sa.Clusters) != 1 {
+		t.Errorf("incorrect clusters length: expected %d, got %d\n", 1, len(sa.Clusters))
+	}
+
+	if sa.Clusters[0].Model.ID != 1 {
+		t.Errorf("incorrect clusters ID: expected %d, got %d\n", 1, sa.Clusters[0].Model.ID)
+	}
+
+	// make sure data is correct
+	expSA := &models.ServiceAccount{
+		ProjectID:             1,
+		Kind:                  "connector",
+		AuthMechanism:         models.X509,
+		ClientCertificateData: []byte("-----BEGIN"),
+		ClientKeyData:         []byte("-----BEGIN"),
+		Clusters: []models.Cluster{
+			models.Cluster{
+				ServiceAccountID: 1,
+				Name:             "cluster-test",
+				Server:           "https://localhost",
+			},
+		},
+	}
+
+	copySA := sa
+
+	// reset fields for reflect.DeepEqual
+	copySA.Model = orm.Model{}
+	copySA.Clusters[0].Model = orm.Model{}
+
+	if diff := deep.Equal(copySA, expSA); diff != nil {
+		t.Errorf("incorrect service account")
+		t.Error(diff)
+	}
+}
+
+func TestListServiceAccountsByProjectID(t *testing.T) {
+	tester := &tester{
+		dbFileName: "./porter_list_sas.db",
+	}
+
+	setupTestEnv(tester, t)
+	initProject(tester, t)
+	initServiceAccount(tester, t)
+	defer cleanup(tester, t)
+
+	sas, err := tester.repo.ServiceAccount.ListServiceAccountsByProjectID(
+		tester.initProjects[0].Model.ID,
+	)
+
+	if err != nil {
+		t.Fatalf("%v\n", err)
+	}
+
+	if len(sas) != 1 {
+		t.Fatalf("length of sas incorrect: expected %d, got %d\n", 1, len(sas))
+	}
+
+	// make sure data is correct
+	expSA := &models.ServiceAccount{
+		ProjectID:             1,
+		Kind:                  "connector",
+		AuthMechanism:         models.X509,
+		ClientCertificateData: []byte("-----BEGIN"),
+		ClientKeyData:         []byte("-----BEGIN"),
+		Clusters: []models.Cluster{
+			models.Cluster{
+				ServiceAccountID: 1,
+				Name:             "cluster-test",
+				Server:           "https://localhost",
+			},
+		},
+	}
+
+	copySA := sas[0]
+
+	// reset fields for reflect.DeepEqual
+	copySA.Model = orm.Model{}
+	copySA.Clusters[0].Model = orm.Model{}
+
+	if diff := deep.Equal(copySA, expSA); diff != nil {
+		t.Errorf("incorrect service account")
+		t.Error(diff)
+	}
+}

+ 0 - 2
internal/repository/serviceaccount.go

@@ -10,9 +10,7 @@ type ServiceAccountRepository interface {
 	CreateServiceAccountCandidate(saCandidate *models.ServiceAccountCandidate) (*models.ServiceAccountCandidate, error)
 	ReadServiceAccountCandidate(id uint) (*models.ServiceAccountCandidate, error)
 	ListServiceAccountCandidatesByProjectID(projectID uint) ([]*models.ServiceAccountCandidate, error)
-	DeleteServiceAccountCandidate(saCandidate *models.ServiceAccountCandidate) (*models.ServiceAccountCandidate, error)
 	CreateServiceAccount(sa *models.ServiceAccount) (*models.ServiceAccount, error)
 	ReadServiceAccount(id uint) (*models.ServiceAccount, error)
 	ListServiceAccountsByProjectID(projectID uint) ([]*models.ServiceAccount, error)
-	DeleteServiceAccount(sa *models.ServiceAccount) (*models.ServiceAccount, error)
 }

+ 0 - 36
internal/repository/test/serviceaccount.go

@@ -76,24 +76,6 @@ func (repo *ServiceAccountRepository) ListServiceAccountCandidatesByProjectID(
 	return res, nil
 }
 
-// DeleteServiceAccountCandidate deletes a service account candidate
-func (repo *ServiceAccountRepository) DeleteServiceAccountCandidate(
-	saCandidate *models.ServiceAccountCandidate,
-) (*models.ServiceAccountCandidate, error) {
-	if !repo.canQuery {
-		return nil, errors.New("Cannot write database")
-	}
-
-	if int(saCandidate.ID-1) >= len(repo.serviceAccountCandidates) || repo.serviceAccountCandidates[saCandidate.ID-1] == nil {
-		return nil, gorm.ErrRecordNotFound
-	}
-
-	index := int(saCandidate.ID - 1)
-	repo.serviceAccountCandidates[index] = nil
-
-	return saCandidate, nil
-}
-
 // CreateServiceAccount creates a new servicea account
 func (repo *ServiceAccountRepository) CreateServiceAccount(
 	sa *models.ServiceAccount,
@@ -154,24 +136,6 @@ func (repo *ServiceAccountRepository) ListServiceAccountsByProjectID(
 	return res, nil
 }
 
-// DeleteServiceAccount deletes a service account
-func (repo *ServiceAccountRepository) DeleteServiceAccount(
-	sa *models.ServiceAccount,
-) (*models.ServiceAccount, error) {
-	if !repo.canQuery {
-		return nil, errors.New("Cannot write database")
-	}
-
-	if int(sa.ID-1) >= len(repo.serviceAccounts) || repo.serviceAccounts[sa.ID-1] == nil {
-		return nil, gorm.ErrRecordNotFound
-	}
-
-	index := int(sa.ID - 1)
-	repo.serviceAccounts[index] = nil
-
-	return sa, nil
-}
-
 func (repo *ServiceAccountRepository) createCluster(
 	cluster *models.Cluster,
 ) (*models.Cluster, error) {