diff --git a/.gitignore b/.gitignore
index a5d5d1f33f4a7cf0809a9b8bc18afd6b0f048211..a8871530421887c909e04b8a5d1dea746bfdf868 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,5 @@ coverage.html
*.swp
*.swo
*~
+
+.vscode
\ No newline at end of file
diff --git a/Makefile b/Makefile
index b55cf447a2ff389232a029e27cee5f3c44bee03a..024413957dd05cfb05e42e8ec93d203b3a3c3741 100644
--- a/Makefile
+++ b/Makefile
@@ -49,6 +49,9 @@ fmt: ## Run go fmt against code.
vet: ## Run go vet against code.
go vet ./...
+lint: ## Run go lint against code
+ golint -set_exit_status ./...
+
ENVTEST_ASSETS_DIR=$(shell pwd)/testbin
test: # manifests generate ## Run tests.
mkdir -p ${ENVTEST_ASSETS_DIR}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..948202f62e298a2875b5cfb97818d2ad78aa3c22
--- /dev/null
+++ b/README.md
@@ -0,0 +1,44 @@
+##
Valkyrie Automated CICD Provisioning Tool
+
+### Golang Frameworks
+- rlog
+ - https://github.com/romana/rlog
+- go-gitlab
+ - https://github.com/xanzy/go-gitlab
+ - https://docs.gitlab.com/ee/api/api_resources.html
+ - https://pkg.go.dev/github.com/xanzy/go-gitlab?utm_source=godoc#section-documentation
+- http-mock
+ - https://github.com/jarcoal/httpmock
+
+### lint fmt vet
+- run linter
+ - `golint -set_exit_status ./... `
+- use make
+ - `make fmt vet lint`
+
+### Testing
+- run tests locally
+```
+make build
+make test
+```
+- generate coverage report
+ - run AFTER running `make test`
+```
+# AFTER running make test
+go tool cover -html=cover.out -o coverage.html
+open coverage.html
+```
+### Integration testing
+- integration tests may require setting environment variables
+- integration tests may require availability of service
+ - examples: gitlab, twistlock, fortify, sonarqube
+- place integration test files in the ./integration-tests/ folder
+- tag test files with a build tag at the beginning of the file
+```
+// +build integration
+
+package integration
+```
+- run integration tests as follows
+ - `go test -v -tags "integration" ./integration-tests/...`
\ No newline at end of file
diff --git a/apis/gitlab/v1alpha1/group_types_test.go b/apis/gitlab/v1alpha1/group_types_test.go
index 03871c4c34981df6a9c1808adb234c88aa8b6905..bf3d636c9f28893f3d15427ba5ae66363981d675 100644
--- a/apis/gitlab/v1alpha1/group_types_test.go
+++ b/apis/gitlab/v1alpha1/group_types_test.go
@@ -70,13 +70,13 @@ func initVarsGroup() testVarsGroup {
testVars.testObjectSpec1 = GroupSpec{
Name: "testGroup1",
GitlabCredentialsName: "nameOfTheCredentials",
- Description: "testDescription1",
+ Description: "testDescription1",
}
testVars.testObjectSpec2 = GroupSpec{
Name: "testGroup2",
GitlabCredentialsName: "nameOfCredentials2",
ProjectSpecs: nil,
- Description: "testDescription2",
+ Description: "testDescription2",
}
id1 := int64(1)
diff --git a/clients/gitlab/client.go b/clients/gitlab/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..c254baad24bcb9fc347573040504a1c20b430792
--- /dev/null
+++ b/clients/gitlab/client.go
@@ -0,0 +1,232 @@
+package gitlab
+
+// Facade built around go-gitlab
+// https://github.com/xanzy/go-gitlab
+// https://docs.gitlab.com/ee/api/api_resources.html
+// https://pkg.go.dev/github.com/xanzy/go-gitlab?utm_source=godoc#section-documentation
+
+import (
+ "fmt"
+ "github.com/romana/rlog"
+ gitlab "github.com/xanzy/go-gitlab"
+ "net/http"
+)
+
+const itemsPerPage = 50
+
+// Client -
+type Client struct {
+ client *gitlab.Client
+ token string
+ apiURL string
+}
+
+// NewClient - create new gitlab api client
+func NewClient(apiURL string, token string, httpClient *http.Client) Client {
+ // apiUrl https://code.il2.dso.mil/api/v4
+ // token gitlab user access token
+ // httpClient optional injection of http client object to be used by gitlab api
+
+ var gitlabClient *gitlab.Client
+ if httpClient == nil {
+ gitlabClient, _ = gitlab.NewClient(token, gitlab.WithBaseURL(apiURL))
+ } else {
+ gitlabClient, _ = gitlab.NewClient(token, gitlab.WithBaseURL(apiURL), gitlab.WithHTTPClient(httpClient))
+ }
+
+ rlog.Debug("Created new Client instance")
+ return Client{
+ client: gitlabClient,
+ token: token,
+ apiURL: apiURL,
+ }
+}
+
+// GetUsers -
+func (r Client) GetUsers(search *string) ([]*gitlab.User, error) {
+ listOptions := gitlab.ListOptions{
+ Page: 1,
+ PerPage: itemsPerPage,
+ }
+
+ // some valid values path, name
+ var orderBy = "name"
+ var opts = gitlab.ListUsersOptions{
+ ListOptions: listOptions,
+ OrderBy: &orderBy,
+ }
+ // if search defined add it to opts
+
+ if search != nil {
+ opts.Search = search
+ }
+
+ userList := []*gitlab.User{}
+ var more = true
+ for more {
+ users, res, err := r.client.Users.ListUsers(&opts)
+ if err != nil {
+ return nil, err
+ }
+ for x := 0; x < len(users); x++ {
+ userList = append(userList, users[x])
+ }
+
+ if res.NextPage > 0 {
+ opts.ListOptions.Page = opts.ListOptions.Page + 1
+ } else {
+ more = false
+ }
+
+ }
+ rlog.Debug(fmt.Sprintf("Completed call to GetUsers. Records returned: %d", len(userList)))
+ return userList, nil
+}
+
+// AddUser -
+func (r Client) AddUser(user *gitlab.User, password string) (*gitlab.User, int, error) {
+ var opts = gitlab.CreateUserOptions{
+ Username: &user.Username,
+ Email: &user.Email,
+ Name: &user.Name,
+ Password: &password,
+ }
+ newUser, res, err := r.client.Users.CreateUser(&opts)
+ if err != nil {
+ return nil, res.StatusCode, err
+ }
+ rlog.Debug(fmt.Sprintf("Completed call to AddUser. Status Code: %d", res.StatusCode))
+ return newUser, res.StatusCode, nil
+}
+
+// DeleteUser -
+func (r Client) DeleteUser(username string) (int, error) {
+ var opts = gitlab.ListUsersOptions{Username: &username}
+ users, lres, err := r.client.Users.ListUsers(&opts)
+ if err != nil {
+ return lres.StatusCode, err
+ }
+ res, err := r.client.Users.DeleteUser(users[0].ID)
+ if err != nil {
+ return res.StatusCode, err
+ }
+ rlog.Debug(fmt.Sprintf("Completed call to DeleteUser. Status Code: %d", res.StatusCode))
+ return res.StatusCode, nil
+}
+
+// GetGroups -
+func (r Client) GetGroups(search *string) ([]*gitlab.Group, error) {
+ listOptions := gitlab.ListOptions{
+ Page: 1,
+ PerPage: itemsPerPage,
+ }
+
+ // some valid values path, name
+ var orderBy = "path"
+ var opts = gitlab.ListGroupsOptions{
+ ListOptions: listOptions,
+ OrderBy: &orderBy,
+ }
+ // if search defined add it to opts
+
+ if search != nil {
+ opts.Search = search
+ }
+ groupList := []*gitlab.Group{}
+ var more = true
+ for more {
+ groups, res, err := r.client.Groups.ListGroups(&opts)
+ if err != nil {
+ return nil, err
+ }
+ for x := 0; x < len(groups); x++ {
+ groupList = append(groupList, groups[x])
+ }
+
+ if res.NextPage > 0 {
+ opts.ListOptions.Page = opts.ListOptions.Page + 1
+ } else {
+ more = false
+ }
+
+ }
+ rlog.Debug(fmt.Sprintf("Completed call to GetGroups. Records returned: %d", len(groupList)))
+ return groupList, nil
+}
+
+// AddGroup -
+func (r Client) AddGroup(group *gitlab.Group) (*gitlab.Group, int, error) {
+ // force visibility to private
+ var visibility = gitlab.PrivateVisibility
+ var opts = gitlab.CreateGroupOptions{Name: &group.Name,
+ Path: &group.Path, Description: &group.Description,
+ Visibility: &visibility}
+
+ newGroup, res, err := r.client.Groups.CreateGroup(&opts)
+ if err != nil {
+ return nil, res.StatusCode, err
+ }
+ return newGroup, res.StatusCode, nil
+}
+
+// DeleteGroup -
+func (r Client) DeleteGroup(groupID int) (int, error) {
+ res, err := r.client.Groups.DeleteGroup(groupID)
+ if err != nil {
+ return res.StatusCode, err
+ }
+ return res.StatusCode, nil
+}
+
+// GetProject -
+func (r Client) GetProject(projectID int) (*gitlab.Project, error) {
+ opts := gitlab.GetProjectOptions{}
+ project, res, err := r.client.Projects.GetProject(projectID, &opts)
+ if err != nil {
+ return nil, err
+ }
+
+ rlog.Debug(fmt.Sprintf("Completed call to GetProject. status Code: %d", res.StatusCode))
+ return project, nil
+}
+
+// GetProjects -
+func (r Client) GetProjects(search *string) ([]*gitlab.Project, error) {
+ listOptions := gitlab.ListOptions{
+ Page: 1,
+ PerPage: itemsPerPage,
+ }
+
+ // some valid values path, name
+ var orderBy = "path"
+ var opts = gitlab.ListProjectsOptions{
+ ListOptions: listOptions,
+ OrderBy: &orderBy,
+ }
+ // if search defined add it to opts
+
+ if search != nil {
+ opts.Search = search
+ }
+ projectList := []*gitlab.Project{}
+ var more = true
+ for more {
+ opts := gitlab.ListProjectsOptions{}
+ projects, res, err := r.client.Projects.ListProjects(&opts)
+ if err != nil {
+ return nil, err
+ }
+ for x := 0; x < len(projects); x++ {
+ projectList = append(projectList, projects[x])
+ }
+
+ if res.NextPage > 0 {
+ opts.ListOptions.Page = opts.ListOptions.Page + 1
+ } else {
+ more = false
+ }
+
+ }
+ rlog.Debug(fmt.Sprintf("Completed call to GetProjectss. Records returned: %d", len(projectList)))
+ return projectList, nil
+}
diff --git a/clients/gitlab/client_test.go b/clients/gitlab/client_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5185c4973aec571e52ad15a382392bd0c3d68523
--- /dev/null
+++ b/clients/gitlab/client_test.go
@@ -0,0 +1,551 @@
+package gitlab
+
+import (
+ "net/http"
+ "reflect"
+ "testing"
+
+ "github.com/jarcoal/httpmock"
+ gogitlab "github.com/xanzy/go-gitlab"
+)
+
+func TestNewClient(t *testing.T) {
+
+ testToken := "abcdef"
+ testURL := "https://test"
+ testWantURL := "https://test/api/v4/"
+ testHTTPClient := &http.Client{}
+
+ type args struct {
+ apiURL string
+ token string
+ httpClient *http.Client
+ }
+ tests := []struct {
+ name string
+ args args
+ wantBaseURL string
+ }{
+ {
+ name: "New Client",
+ args: args{testURL, testToken, nil},
+ wantBaseURL: testWantURL,
+ },
+ {
+ name: "New Client with httpClient injection",
+ args: args{testURL, testToken, testHTTPClient},
+ wantBaseURL: testWantURL,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := NewClient(tt.args.apiURL, tt.args.token, tt.args.httpClient)
+ t.Logf("baseUrl %s", got.client.BaseURL())
+ if got.client.BaseURL().String() != tt.wantBaseURL {
+ t.Errorf("NewClient() = %v, want %v", got.client.BaseURL().String(), tt.wantBaseURL)
+ }
+ })
+ }
+}
+
+func TestClient_GetUsers(t *testing.T) {
+ // setup a http client for use in mocking
+ testHTTPClient := &http.Client{}
+ httpmock.ActivateNonDefault(testHTTPClient)
+ defer httpmock.DeactivateAndReset()
+
+ // empty gitlab User array
+ testUserArray := []*gogitlab.User{}
+ testUser1 := gogitlab.User{ID: 1, Username: "joedirt"}
+ testUser2 := gogitlab.User{ID: 2, Username: "spongebob"}
+ testUserArray = append(testUserArray, &testUser1, &testUser2)
+
+ // use regex url matcher
+ httpmock.RegisterResponder("GET",
+ `=~^https://test/api/v4/users.*`,
+ httpmock.NewJsonResponderOrPanic(200, testUserArray),
+ )
+
+ // test objects
+ search := "searchstring"
+ testAPIUrl := "https://test/api/v4/"
+ testToken := "token"
+ // create a gitlab Client object, inject http client to allow for mocking using httpmock
+ testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient))
+
+ type fields struct {
+ client *gogitlab.Client
+ token string
+ apiURL string
+ }
+ type args struct {
+ search *string
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want []*gogitlab.User
+ wantErr bool
+ }{
+ {
+ name: "GetUsers 1",
+ fields: fields{client: testGitlabClient, token: testToken, apiURL: testAPIUrl},
+ args: args{search: nil},
+ want: testUserArray,
+ wantErr: false,
+ },
+ {
+ name: "GetUsers 2",
+ fields: fields{client: testGitlabClient, token: testToken, apiURL: testAPIUrl},
+ args: args{search: &search},
+ want: testUserArray,
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := Client{
+ client: tt.fields.client,
+ token: tt.fields.token,
+ apiURL: tt.fields.apiURL,
+ }
+
+ got, err := r.GetUsers(tt.args.search)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("Client.GetUsers() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ for _, user := range got {
+ t.Logf("user id %d, username %s", user.ID, user.Username)
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("Client.GetUsers() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestClient_AddUser(t *testing.T) {
+ // setup a http client for use in mocking
+ testHTTPClient := &http.Client{}
+ httpmock.ActivateNonDefault(testHTTPClient)
+ defer httpmock.DeactivateAndReset()
+
+ testUser1 := gogitlab.User{ID: 1, Username: "joedirt"}
+
+ httpmock.RegisterResponder("POST",
+ "https://test/api/v4/users",
+ httpmock.NewJsonResponderOrPanic(200, testUser1),
+ )
+
+ // test objects
+ testAPIUrl := "https://test/api/v4/"
+ testToken := "token"
+ // create a gitlab Client object, inject http client to allow for mocking using httpmock
+ testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient))
+
+ type fields struct {
+ client *gogitlab.Client
+ token string
+ apiURL string
+ }
+ type args struct {
+ user *gogitlab.User
+ password string
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want *gogitlab.User
+ want1 int
+ wantErr bool
+ }{
+ {
+ name: "AddUser 1",
+ fields: fields{client: testGitlabClient, token: testToken, apiURL: testAPIUrl},
+ args: args{user: &testUser1, password: "test"},
+ want: &testUser1,
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := Client{
+ client: tt.fields.client,
+ token: tt.fields.token,
+ apiURL: tt.fields.apiURL,
+ }
+ got, _, err := r.AddUser(tt.args.user, tt.args.password)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("Client.AddUser() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if got.ID != tt.want.ID {
+ t.Errorf("Client.AddUser() got = %d, want %d", got.ID, tt.want.ID)
+ return
+ }
+ t.Logf("Client.AddUser() got = %d, want %d", got.ID, tt.want.ID)
+ })
+ }
+}
+
+func TestClient_DeleteUser(t *testing.T) {
+ // setup a http client for use in mocking
+ testHTTPClient := &http.Client{}
+ httpmock.ActivateNonDefault(testHTTPClient)
+ defer httpmock.DeactivateAndReset()
+
+ testUser := gogitlab.User{ID: 1, Username: "joedirt"}
+ testUserArray := []*gogitlab.User{}
+ testUserArray = append(testUserArray, &testUser)
+
+ httpmock.RegisterResponder("DELETE",
+ `=~^https://test/api/v4/users.*`,
+ httpmock.NewJsonResponderOrPanic(202, testUser),
+ )
+ httpmock.RegisterResponder("GET",
+ `=~^https://test/api/v4/users.*`,
+ httpmock.NewJsonResponderOrPanic(200, testUserArray),
+ )
+
+ // test objects
+ testUsername := "testusername"
+ testAPIUrl := "https://test/api/v4/"
+ testToken := "token"
+ // create a gitlab Client object, inject http client to allow for mocking using httpmock
+ testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient))
+
+ type fields struct {
+ client *gogitlab.Client
+ token string
+ apiURL string
+ }
+ type args struct {
+ username string
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want int
+ wantErr bool
+ }{
+ {
+ name: "DeleteUser 1",
+ fields: fields{client: testGitlabClient, token: testToken, apiURL: testAPIUrl},
+ args: args{username: testUsername},
+ want: 202,
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := Client{
+ client: tt.fields.client,
+ token: tt.fields.token,
+ apiURL: tt.fields.apiURL,
+ }
+ got, err := r.DeleteUser(tt.args.username)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("Client.DeleteUser() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if got != tt.want {
+ t.Errorf("Client.DeleteUser() = %v, want %v", got, tt.want)
+ return
+ }
+ t.Logf("Client.DeleteUser() statusCode = %d ", got)
+ })
+ }
+}
+
+func TestClient_GetGroups(t *testing.T) {
+ // setup a http client for use in mocking
+ testHTTPClient := &http.Client{}
+ httpmock.ActivateNonDefault(testHTTPClient)
+ defer httpmock.DeactivateAndReset()
+
+ // empty gitlab User array
+ testGroupArray := []*gogitlab.Group{}
+ testGroup1 := gogitlab.Group{ID: 1, Name: "joedirt"}
+ testGroup2 := gogitlab.Group{ID: 2, Name: "spongebob"}
+ testGroupArray = append(testGroupArray, &testGroup1, &testGroup2)
+
+ // use regex url matcher
+ httpmock.RegisterResponder("GET",
+ `=~^https://test/api/v4/groups.*`,
+ httpmock.NewJsonResponderOrPanic(200, testGroupArray),
+ )
+
+ // test objects
+ search := "searchstring"
+ testAPIUrl := "https://test/api/v4/"
+ testToken := "token"
+ // create a gitlab Client object, inject http client to allow for mocking using httpmock
+ testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient))
+
+ type fields struct {
+ client *gogitlab.Client
+ token string
+ apiURL string
+ }
+ type args struct {
+ search *string
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want []*gogitlab.Group
+ wantErr bool
+ }{
+ {
+ name: "GetGroups 1",
+ fields: fields{client: testGitlabClient, token: testToken, apiURL: testAPIUrl},
+ args: args{search: nil},
+ want: testGroupArray,
+ wantErr: false,
+ },
+ {
+ name: "GetGroups 2",
+ fields: fields{client: testGitlabClient, token: testToken, apiURL: testAPIUrl},
+ args: args{search: &search},
+ want: testGroupArray,
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := Client{
+ client: tt.fields.client,
+ token: tt.fields.token,
+ apiURL: tt.fields.apiURL,
+ }
+
+ got, err := r.GetGroups(tt.args.search)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("Client.GetGroups() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ for _, group := range got {
+ t.Logf("user id %d, groupname %s", group.ID, group.Name)
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("Client.GetGroups() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestClient_AddGroup(t *testing.T) {
+ // setup a http client for use in mocking
+ testHTTPClient := &http.Client{}
+ httpmock.ActivateNonDefault(testHTTPClient)
+ defer httpmock.DeactivateAndReset()
+
+ // empty gitlab User array
+ testGroup := gogitlab.Group{ID: 1, Name: "joedirt"}
+
+ httpmock.RegisterResponder("POST",
+ "https://test/api/v4/groups",
+ httpmock.NewJsonResponderOrPanic(200, testGroup),
+ )
+
+ // test objects
+ testAPIUrl := "https://test/api/v4/"
+ testToken := "token"
+ // create a gitlab Client object, inject http client to allow for mocking using httpmock
+ testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient))
+
+ type fields struct {
+ client *gogitlab.Client
+ token string
+ apiURL string
+ }
+ type args struct {
+ group *gogitlab.Group
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want *gogitlab.Group
+ want1 int
+ wantErr bool
+ }{
+ {
+ name: "AddGroup 1",
+ fields: fields{client: testGitlabClient, token: testToken, apiURL: testAPIUrl},
+ args: args{group: &testGroup},
+ want: &testGroup,
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := Client{
+ client: tt.fields.client,
+ token: tt.fields.token,
+ apiURL: tt.fields.apiURL,
+ }
+ got, _, err := r.AddGroup(tt.args.group)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("Client.AddGroup() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if got.ID != tt.want.ID {
+ t.Errorf("Client.AddGroup() got = %d, want %d", got.ID, tt.want.ID)
+ return
+ }
+ t.Logf("Client.AddGroup() got = %d %s, want %d %s", got.ID, got.Name, tt.want.ID, tt.want.Name)
+ })
+ }
+}
+
+func TestClient_DeleteGroup(t *testing.T) {
+
+ // setup a http client for use in mocking
+ testHTTPClient := &http.Client{}
+ httpmock.ActivateNonDefault(testHTTPClient)
+ defer httpmock.DeactivateAndReset()
+ // empty gitlab User array
+ testGroupArray := []*gogitlab.Group{}
+ testGroup1 := gogitlab.Group{ID: 1, Name: "group joedirt"}
+ testGroup2 := gogitlab.Group{ID: 2, Name: "group spongebob"}
+ testGroupArray = append(testGroupArray, &testGroup1, &testGroup2)
+
+ httpmock.RegisterResponder("DELETE",
+ `=~^https://test/api/v4/groups.*`,
+ httpmock.NewJsonResponderOrPanic(202, testGroup1),
+ )
+ httpmock.RegisterResponder("GET",
+ `=~^https://test/api/v4/groups.*`,
+ httpmock.NewJsonResponderOrPanic(200, testGroupArray),
+ )
+
+ // test objects
+ testGroupID := 1
+ testAPIUrl := "https://test/api/v4/"
+ testToken := "token"
+ // create a gitlab Client object, inject http client to allow for mocking using httpmock
+ testGitlabClient, _ := gogitlab.NewClient(testToken, gogitlab.WithBaseURL(testAPIUrl), gogitlab.WithHTTPClient(testHTTPClient))
+
+ type fields struct {
+ client *gogitlab.Client
+ token string
+ apiURL string
+ }
+ type args struct {
+ groupID int
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want int
+ wantErr bool
+ }{
+ {
+ name: "DeleteGroup 1",
+ fields: fields{client: testGitlabClient, token: testToken, apiURL: testAPIUrl},
+ args: args{groupID: testGroupID},
+ want: 202,
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ r := Client{
+ client: tt.fields.client,
+ token: tt.fields.token,
+ apiURL: tt.fields.apiURL,
+ }
+ got, err := r.DeleteGroup(tt.args.groupID)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("Client.DeleteGroup() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if got != tt.want {
+ t.Errorf("Client.รง() = %v, want %v", got, tt.want)
+ return
+ }
+ t.Logf("Client.DeleteGroup() statusCode = %d ", got)
+ })
+ }
+}
+
+// func TestClient_GetProject(t *testing.T) {
+// type fields struct {
+// client *gitlab.Client
+// token string
+// apiURL string
+// }
+// type args struct {
+// projectID int
+// }
+// tests := []struct {
+// name string
+// fields fields
+// args args
+// want *gitlab.Project
+// wantErr bool
+// }{
+// // TODO: Add test cases.
+// }
+// for _, tt := range tests {
+// t.Run(tt.name, func(t *testing.T) {
+// r := Client{
+// client: tt.fields.client,
+// token: tt.fields.token,
+// apiURL: tt.fields.apiURL,
+// }
+// got, err := r.GetProject(tt.args.projectID)
+// if (err != nil) != tt.wantErr {
+// t.Errorf("Client.GetProject() error = %v, wantErr %v", err, tt.wantErr)
+// return
+// }
+// if !reflect.DeepEqual(got, tt.want) {
+// t.Errorf("Client.GetProject() = %v, want %v", got, tt.want)
+// }
+// })
+// }
+// }
+
+// func TestClient_GetProjects(t *testing.T) {
+// type fields struct {
+// client *gitlab.Client
+// token string
+// apiURL string
+// }
+// type args struct {
+// search *string
+// }
+// tests := []struct {
+// name string
+// fields fields
+// args args
+// want []*gitlab.Project
+// wantErr bool
+// }{
+// // TODO: Add test cases.
+// }
+// for _, tt := range tests {
+// t.Run(tt.name, func(t *testing.T) {
+// r := Client{
+// client: tt.fields.client,
+// token: tt.fields.token,
+// apiURL: tt.fields.apiURL,
+// }
+// got, err := r.GetProjects(tt.args.search)
+// if (err != nil) != tt.wantErr {
+// t.Errorf("Client.GetProjects() error = %v, wantErr %v", err, tt.wantErr)
+// return
+// }
+// if !reflect.DeepEqual(got, tt.want) {
+// t.Errorf("Client.GetProjects() = %v, want %v", got, tt.want)
+// }
+// })
+// }
+// }
diff --git a/controllers/gitlab/gitlab_client.go b/controllers/gitlab/gitlab_client.go
index abc9052a346e665283ef3e63abb58aeb30fa294e..57999a45219a1679388f6482a674d5e3463ecc11 100644
--- a/controllers/gitlab/gitlab_client.go
+++ b/controllers/gitlab/gitlab_client.go
@@ -1,56 +1,55 @@
-package gitlab
-
-import gitlab "github.com/xanzy/go-gitlab"
-
-// Client is a facade for go-gitlab
-type Client interface {
- NewClient(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error)
- ListGroups(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error)
- ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error)
- CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error)
- UpdateGroup(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error)
-
-}
-
-// ClientImpl is the Default implementation for the facade.
-type ClientImpl struct {
- client *gitlab.Client
-}
-
-// NewClient is a facade for the go-gitlab client NewClient call
-func (c ClientImpl) NewClient(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
- client, err := gitlab.NewClient(token, options...)
- c.client = client
- return client, err
-}
-
-// ListGroups is a facade for the go-gitlab client.Groups.ListGroups call.
-func (c ClientImpl) ListGroups(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error) {
- return c.client.Groups.ListGroups(opt, options...)
-}
-
-// ListGroupsByName is a facade for the go-gitlab client.Groups.ListGroups call, with the group name as a search option.
-func (c ClientImpl) ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- return c.client.Groups.ListGroups(
- &gitlab.ListGroupsOptions{
- Search: &name,
- })
-}
-
-// CreateGroup is a facade for the go-gitlab client.Groups.CreateGroup
-func (c ClientImpl) CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error) {
- opt := gitlab.CreateGroupOptions{
- Name: &name,
- Description: &description,
- }
- return c.client.Groups.CreateGroup(&opt)
-}
-
-// UpdateGroup is a facade for the go-gitlab client.Group.UpdateGroup
-func (c ClientImpl) UpdateGroup(id string, name string, descrption string) (*gitlab.Group, *gitlab.Response, error) {
- opt := gitlab.UpdateGroupOptions{
- Name: &name,
- Description: &descrption,
- }
- return c.client.Groups.UpdateGroup(id, &opt)
-}
+package gitlab
+
+import gitlab "github.com/xanzy/go-gitlab"
+
+// Client is a facade for go-gitlab
+type Client interface {
+ NewClient(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error)
+ ListGroups(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error)
+ ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error)
+ CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error)
+ UpdateGroup(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error)
+}
+
+// ClientImpl is the Default implementation for the facade.
+type ClientImpl struct {
+ client *gitlab.Client
+}
+
+// NewClient is a facade for the go-gitlab client NewClient call
+func (c ClientImpl) NewClient(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
+ client, err := gitlab.NewClient(token, options...)
+ c.client = client
+ return client, err
+}
+
+// ListGroups is a facade for the go-gitlab client.Groups.ListGroups call.
+func (c ClientImpl) ListGroups(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error) {
+ return c.client.Groups.ListGroups(opt, options...)
+}
+
+// ListGroupsByName is a facade for the go-gitlab client.Groups.ListGroups call, with the group name as a search option.
+func (c ClientImpl) ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ return c.client.Groups.ListGroups(
+ &gitlab.ListGroupsOptions{
+ Search: &name,
+ })
+}
+
+// CreateGroup is a facade for the go-gitlab client.Groups.CreateGroup
+func (c ClientImpl) CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error) {
+ opt := gitlab.CreateGroupOptions{
+ Name: &name,
+ Description: &description,
+ }
+ return c.client.Groups.CreateGroup(&opt)
+}
+
+// UpdateGroup is a facade for the go-gitlab client.Group.UpdateGroup
+func (c ClientImpl) UpdateGroup(id string, name string, descrption string) (*gitlab.Group, *gitlab.Response, error) {
+ opt := gitlab.UpdateGroupOptions{
+ Name: &name,
+ Description: &descrption,
+ }
+ return c.client.Groups.UpdateGroup(id, &opt)
+}
diff --git a/controllers/gitlab/group_controller.go b/controllers/gitlab/group_controller.go
index db8c208cfed76d2caf87eba338b621074818ea8f..46f433d50486e1d095819eec119f0a0eeef75ba6 100644
--- a/controllers/gitlab/group_controller.go
+++ b/controllers/gitlab/group_controller.go
@@ -1,316 +1,314 @@
-/*
-Copyright 2021.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package gitlab
-
-import (
- "context"
- "fmt"
- "github.com/go-logr/logr"
- "github.com/xanzy/go-gitlab"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/types"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "time"
- gitlabv1alpha1 "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1"
-)
-
-// Errors
-const (
- errorUnableToFetchGroup = "unable to fetch group"
- errorUnableToFetchGitlabCredentials = "unable to fetch gitlab credentials"
- errorUnableToFetchSecret = "unable to fetch secret from gitlab credentials"
- errorUnableToCreateGitlabClient = "unable to create gitlab client"
- errorWhileSearchingGroups = "Error while searching groups."
- errorWhileCreatingGitlabGroup = "Error while creating GitLab group."
- errorWhileUpdatingGitlabGroup = "Error while updating GitLab group."
- errorUnableToUpdateStatus = "Unable to update status."
- errorUnableToProcessProjects = "Unable to process projects"
- errorTryingToCreateProject = "Error trying to create project"
- errorLookingUpProject = "Error looking up project"
- errorUpdatingProject = "Error updating project"
-)
-
-// Group Status
-const (
- CredentialNotFound = "CredentialNotFound"
- CredentialSecretNotFound = "CredentialSecretNotFound"
- GroupCreated = "Created"
- GroupOK = "OK"
-)
-
-const valkyrie = "valkyrie"
-
-
-// GroupReconciler reconciles the state of a Gitlab Group, for each reconciliation loop it will log in to Gitlab
-// with credentials in the secret provided. It will then check the state of the Group, and create it if necessary.
-type GroupReconciler struct {
- client.Client
- Log logr.Logger
- Scheme *runtime.Scheme
- gitlabClient Client
-}
-
-//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=groups,verbs=get;list;watch;create;update;patch;delete
-//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=groups/status,verbs=get;update;patch
-//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=groups/finalizers,verbs=update
-//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=gitlabcredentials,verbs=get;list;watch
-//+kubebuilder:rbac:groups=core,resources=secretreference,verbs=get;list;watch
-//+kubebuilder:rbac:groups=core,resources=secret,verbs=get;list;watch
-//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=projects,verbs=get;list;watch;create;update;patch;delete
-
-// Reconcile is part of the main kubernetes reconciliation loop which aims to
-// move the current state of the cluster closer to the desired state.
-// The reconcile loop for the Gitlab Group will update the Group and any of the child Project API Objects.
-func (r *GroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
- log := r.Log.WithValues("group", req.NamespacedName)
-
- group := &gitlabv1alpha1.Group{}
-
- // Get the Group Object
- if err := r.Get(ctx, req.NamespacedName, group); err != nil {
- log.Error(err, errorUnableToFetchGroup, "group", req.NamespacedName.Name)
- // we'll ignore not-found errors, since they can't be fixed by an immediate
- // requeue (we'll need to wait for a new notification), and we can get them
- // on deleted requests.
- return ctrl.Result{}, client.IgnoreNotFound(err)
- }
-
- // Get the Gitlab Credentials
- var gitLabCredentialsName = types.NamespacedName{
- Namespace: req.Namespace,
- Name: group.Spec.GitlabCredentialsName,
- }
-
- var gitlabCredentials gitlabv1alpha1.GitlabCredentials
- if err := r.Get(ctx, gitLabCredentialsName, &gitlabCredentials); err != nil {
-
- log.Error(err, errorUnableToFetchGitlabCredentials)
- group.Status.State = CredentialNotFound
- _ = r.updateStatus(ctx, 0, group)
- return ctrl.Result{Requeue: true}, err
- }
-
- var secretName = types.NamespacedName{
- Namespace: gitlabCredentials.Spec.AccessToken.Namespace,
- Name: gitlabCredentials.Spec.AccessToken.Name,
- }
-
- var secret v1.Secret
- // Get the Secret
- if err := r.Get(ctx, secretName, &secret); err != nil {
-
- log.Error(err, errorUnableToFetchSecret)
- group.Status.State = CredentialSecretNotFound
- _ = r.updateStatus(ctx, 0, group)
-
- return ctrl.Result{Requeue: true}, err
- }
-
- // Login to Gitlab
- var accessToken = string(secret.Data[gitlabCredentials.Spec.AccessTokenKey])
-
- var err error
- if _, err = r.gitlabClient.NewClient(accessToken, gitlab.WithBaseURL(gitlabCredentials.Spec.URL)); err != nil {
- log.Error(err, errorUnableToCreateGitlabClient, "username", gitlabCredentials.Spec.Username, "url", gitlabCredentials.Spec.URL)
- return ctrl.Result{Requeue: true}, err
- }
-
- // See if the Group Exists
- var gitlabGroup *gitlab.Group
- found, _, gitlabGroup, err := r.groupExists(group)
- if err != nil {
- log.Error(err, errorWhileSearchingGroups, "status")
- return ctrl.Result{Requeue: true}, err
- }
-
- if !found {
- if gitlabGroup, _, err = r.createGroup(group); err != nil {
-
- log.Error(err, errorWhileCreatingGitlabGroup, "group", group)
- return ctrl.Result{Requeue: true}, err
- }
- } else {
- if gitlabGroup, _, err = r.updateGroup(group); err != nil {
- log.Error(err, errorWhileUpdatingGitlabGroup, "group", group)
- return ctrl.Result{Requeue: true}, err
- }
- }
-
- if err := r.updateStatus(ctx, gitlabGroup.ID, group); err != nil {
- log.Error(err, errorUnableToUpdateStatus, "group", group)
- return ctrl.Result{ Requeue: true }, err
- }
-
- if err := r.processProjects(ctx, group, group.Spec.ProjectSpecs); err != nil {
- log.Error(err, errorUnableToProcessProjects, "group", group)
- return ctrl.Result{Requeue: true}, err
- }
-
- return ctrl.Result{}, nil
-}
-
-func (r *GroupReconciler) groupExists(group *gitlabv1alpha1.Group) (bool, *gitlab.Response, *gitlab.Group, error) {
-
- var grouplist []*gitlab.Group
- var response *gitlab.Response
- var err error
- if grouplist, response, err = r.gitlabClient.ListGroupsByName(group.Spec.Name); err != nil {
- return false, response, nil, err
- }
-
- // TODO: (jvb) For work beyond the MVP we'll need to handle pagination. May be superceeded by adam's client work.
- found := false
- for _, groupInList := range grouplist {
- found = group.Spec.Name == groupInList.Name
- if found {
- return found, response, groupInList, nil
- }
- }
- return found, response, nil, nil
-}
-
-func (r *GroupReconciler) createGroup(group *gitlabv1alpha1.Group) (*gitlab.Group, *gitlab.Response, error) {
- gitlabGroup, response, err := r.gitlabClient.CreateGroup(group.Spec.Name, group.Spec.Description)
-
- if err == nil {
- group.Status.CreatedTime = metav1.Time{
- Time: time.Now(),
- }
- group.ObjectMeta.Annotations["ID"] = fmt.Sprint(gitlabGroup.ID)
- group.ObjectMeta.Annotations["Creator"] = valkyrie
- group.Status.State = GroupCreated
- }
-
- return gitlabGroup, response, err
-}
-
-func (r *GroupReconciler) updateGroup(group *gitlabv1alpha1.Group) (*gitlab.Group, *gitlab.Response, error) {
- gitlabGroup, response, err := r.gitlabClient.UpdateGroup(group.ObjectMeta.Annotations["ID"], group.Spec.Name, group.Spec.Description)
-
- if err == nil {
- group.Status.State = GroupOK
- group.Status.LastUpdatedTime = metav1.Time{
- Time: time.Now(),
- }
- }
-
- return gitlabGroup, response, err
-}
-
-
-func (r *GroupReconciler) processProjects(ctx context.Context, group *gitlabv1alpha1.Group, specs []gitlabv1alpha1.ProjectSpec) error {
- for _, projectSpec := range specs {
- if project, foundProject, err := r.getProject(ctx, group, projectSpec); err != nil {
- r.Log.Error(err, errorLookingUpProject, "name", projectSpec.Name)
- return err
- } else if foundProject {
- if _, err := r.updateProject(ctx, projectSpec, project); err != nil {
-
- r.Log.Error(err, errorUpdatingProject, "project", project)
- }
- } else {
- if err := r.createProject(ctx, group, projectSpec); err != nil {
-
- r.Log.Error(err, errorTryingToCreateProject, "project", projectSpec)
- return err
- }
- }
- }
- return nil
-}
-
-func (r *GroupReconciler) getProject(ctx context.Context, group *gitlabv1alpha1.Group, spec gitlabv1alpha1.ProjectSpec) (*gitlabv1alpha1.Project, bool, error) {
- var project gitlabv1alpha1.Project
- projectName := types.NamespacedName{
- Namespace: group.Namespace,
- Name: fmt.Sprintf("%s-%s", group.Name, spec.Name),
- }
- err := r.Get(ctx, projectName, &project)
-
- projectNotFound := client.IgnoreNotFound(err)
-
- if projectNotFound == nil {
- return nil, false, nil
- }
-
- return &project, true, err
-}
-
-func (r *GroupReconciler) createProject(ctx context.Context, group *gitlabv1alpha1.Group, spec gitlabv1alpha1.ProjectSpec) error {
- blockOwnerDeletion := true
- managingController := true
- return r.Create(ctx, &gitlabv1alpha1.Project{
- ObjectMeta: ctrl.ObjectMeta{
- OwnerReferences: []metav1.OwnerReference{
- {
- APIVersion: group.APIVersion,
- Kind: group.Kind,
- Name: group.Name,
- UID: group.UID,
- Controller: &managingController,
- BlockOwnerDeletion: &blockOwnerDeletion,
- },
- },
- },
- Spec: gitlabv1alpha1.ProjectSpec{
- Name: spec.Name,
- Path: spec.Path,
- ImpactLevel: spec.ImpactLevel,
- StorageTypes: spec.StorageTypes,
- VirtualService: spec.VirtualService,
- ServicePort: spec.ServicePort,
- Language: spec.Language,
- },
- })
-}
-
-func (r *GroupReconciler) updateProject(ctx context.Context, spec gitlabv1alpha1.ProjectSpec, project *gitlabv1alpha1.Project) (*gitlabv1alpha1.Project, error) {
- project.Spec.Name = spec.Name
- project.Spec.Path = spec.Path
- project.Spec.ImpactLevel = spec.ImpactLevel
- project.Spec.StorageTypes = spec.StorageTypes
- project.Spec.VirtualService = spec.VirtualService
- project.Spec.ServicePort = spec.ServicePort
- project.Spec.Language = spec.Language
- return project, r.Update(ctx, project)
-}
-
-func (r *GroupReconciler) updateStatus(ctx context.Context, id int, group *gitlabv1alpha1.Group) error {
- if id != 0 {
- id64 := int64(id)
- group.Status.GitlabID = &id64
- group.Status.LastUpdatedTime = metav1.Time{
- Time: time.Now(),
- }
- }
-
- return r.Status().Update(ctx, group)
-}
-
-// SetupWithManager sets up the controller with the Manager.
-func (r *GroupReconciler) SetupWithManager(mgr ctrl.Manager) error {
- // Setup a default GitlabClient implementation
- r.gitlabClient = &ClientImpl{}
-
- return ctrl.NewControllerManagedBy(mgr).
- For(&gitlabv1alpha1.Group{}).
- Owns(&gitlabv1alpha1.Project{}).
- Complete(r)
-}
\ No newline at end of file
+/*
+Copyright 2021.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package gitlab
+
+import (
+ "context"
+ "fmt"
+ "github.com/go-logr/logr"
+ "github.com/xanzy/go-gitlab"
+ v1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "time"
+ gitlabv1alpha1 "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1"
+)
+
+// Errors
+const (
+ errorUnableToFetchGroup = "unable to fetch group"
+ errorUnableToFetchGitlabCredentials = "unable to fetch gitlab credentials"
+ errorUnableToFetchSecret = "unable to fetch secret from gitlab credentials"
+ errorUnableToCreateGitlabClient = "unable to create gitlab client"
+ errorWhileSearchingGroups = "Error while searching groups."
+ errorWhileCreatingGitlabGroup = "Error while creating GitLab group."
+ errorWhileUpdatingGitlabGroup = "Error while updating GitLab group."
+ errorUnableToUpdateStatus = "Unable to update status."
+ errorUnableToProcessProjects = "Unable to process projects"
+ errorTryingToCreateProject = "Error trying to create project"
+ errorLookingUpProject = "Error looking up project"
+ errorUpdatingProject = "Error updating project"
+)
+
+// Group Status
+const (
+ CredentialNotFound = "CredentialNotFound"
+ CredentialSecretNotFound = "CredentialSecretNotFound"
+ GroupCreated = "Created"
+ GroupOK = "OK"
+)
+
+const valkyrie = "valkyrie"
+
+// GroupReconciler reconciles the state of a Gitlab Group, for each reconciliation loop it will log in to Gitlab
+// with credentials in the secret provided. It will then check the state of the Group, and create it if necessary.
+type GroupReconciler struct {
+ client.Client
+ Log logr.Logger
+ Scheme *runtime.Scheme
+ gitlabClient Client
+}
+
+//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=groups,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=groups/status,verbs=get;update;patch
+//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=groups/finalizers,verbs=update
+//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=gitlabcredentials,verbs=get;list;watch
+//+kubebuilder:rbac:groups=core,resources=secretreference,verbs=get;list;watch
+//+kubebuilder:rbac:groups=core,resources=secret,verbs=get;list;watch
+//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=projects,verbs=get;list;watch;create;update;patch;delete
+
+// Reconcile is part of the main kubernetes reconciliation loop which aims to
+// move the current state of the cluster closer to the desired state.
+// The reconcile loop for the Gitlab Group will update the Group and any of the child Project API Objects.
+func (r *GroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+ log := r.Log.WithValues("group", req.NamespacedName)
+
+ group := &gitlabv1alpha1.Group{}
+
+ // Get the Group Object
+ if err := r.Get(ctx, req.NamespacedName, group); err != nil {
+ log.Error(err, errorUnableToFetchGroup, "group", req.NamespacedName.Name)
+ // we'll ignore not-found errors, since they can't be fixed by an immediate
+ // requeue (we'll need to wait for a new notification), and we can get them
+ // on deleted requests.
+ return ctrl.Result{}, client.IgnoreNotFound(err)
+ }
+
+ // Get the Gitlab Credentials
+ var gitLabCredentialsName = types.NamespacedName{
+ Namespace: req.Namespace,
+ Name: group.Spec.GitlabCredentialsName,
+ }
+
+ var gitlabCredentials gitlabv1alpha1.GitlabCredentials
+ if err := r.Get(ctx, gitLabCredentialsName, &gitlabCredentials); err != nil {
+
+ log.Error(err, errorUnableToFetchGitlabCredentials)
+ group.Status.State = CredentialNotFound
+ _ = r.updateStatus(ctx, 0, group)
+ return ctrl.Result{Requeue: true}, err
+ }
+
+ var secretName = types.NamespacedName{
+ Namespace: gitlabCredentials.Spec.AccessToken.Namespace,
+ Name: gitlabCredentials.Spec.AccessToken.Name,
+ }
+
+ var secret v1.Secret
+ // Get the Secret
+ if err := r.Get(ctx, secretName, &secret); err != nil {
+
+ log.Error(err, errorUnableToFetchSecret)
+ group.Status.State = CredentialSecretNotFound
+ _ = r.updateStatus(ctx, 0, group)
+
+ return ctrl.Result{Requeue: true}, err
+ }
+
+ // Login to Gitlab
+ var accessToken = string(secret.Data[gitlabCredentials.Spec.AccessTokenKey])
+
+ var err error
+ if _, err = r.gitlabClient.NewClient(accessToken, gitlab.WithBaseURL(gitlabCredentials.Spec.URL)); err != nil {
+ log.Error(err, errorUnableToCreateGitlabClient, "username", gitlabCredentials.Spec.Username, "url", gitlabCredentials.Spec.URL)
+ return ctrl.Result{Requeue: true}, err
+ }
+
+ // See if the Group Exists
+ var gitlabGroup *gitlab.Group
+ found, _, gitlabGroup, err := r.groupExists(group)
+ if err != nil {
+ log.Error(err, errorWhileSearchingGroups, "status")
+ return ctrl.Result{Requeue: true}, err
+ }
+
+ if !found {
+ if gitlabGroup, _, err = r.createGroup(group); err != nil {
+
+ log.Error(err, errorWhileCreatingGitlabGroup, "group", group)
+ return ctrl.Result{Requeue: true}, err
+ }
+ } else {
+ if gitlabGroup, _, err = r.updateGroup(group); err != nil {
+ log.Error(err, errorWhileUpdatingGitlabGroup, "group", group)
+ return ctrl.Result{Requeue: true}, err
+ }
+ }
+
+ if err := r.updateStatus(ctx, gitlabGroup.ID, group); err != nil {
+ log.Error(err, errorUnableToUpdateStatus, "group", group)
+ return ctrl.Result{Requeue: true}, err
+ }
+
+ if err := r.processProjects(ctx, group, group.Spec.ProjectSpecs); err != nil {
+ log.Error(err, errorUnableToProcessProjects, "group", group)
+ return ctrl.Result{Requeue: true}, err
+ }
+
+ return ctrl.Result{}, nil
+}
+
+func (r *GroupReconciler) groupExists(group *gitlabv1alpha1.Group) (bool, *gitlab.Response, *gitlab.Group, error) {
+
+ var grouplist []*gitlab.Group
+ var response *gitlab.Response
+ var err error
+ if grouplist, response, err = r.gitlabClient.ListGroupsByName(group.Spec.Name); err != nil {
+ return false, response, nil, err
+ }
+
+ // TODO: (jvb) For work beyond the MVP we'll need to handle pagination. May be superceeded by adam's client work.
+ found := false
+ for _, groupInList := range grouplist {
+ found = group.Spec.Name == groupInList.Name
+ if found {
+ return found, response, groupInList, nil
+ }
+ }
+ return found, response, nil, nil
+}
+
+func (r *GroupReconciler) createGroup(group *gitlabv1alpha1.Group) (*gitlab.Group, *gitlab.Response, error) {
+ gitlabGroup, response, err := r.gitlabClient.CreateGroup(group.Spec.Name, group.Spec.Description)
+
+ if err == nil {
+ group.Status.CreatedTime = metav1.Time{
+ Time: time.Now(),
+ }
+ group.ObjectMeta.Annotations["ID"] = fmt.Sprint(gitlabGroup.ID)
+ group.ObjectMeta.Annotations["Creator"] = valkyrie
+ group.Status.State = GroupCreated
+ }
+
+ return gitlabGroup, response, err
+}
+
+func (r *GroupReconciler) updateGroup(group *gitlabv1alpha1.Group) (*gitlab.Group, *gitlab.Response, error) {
+ gitlabGroup, response, err := r.gitlabClient.UpdateGroup(group.ObjectMeta.Annotations["ID"], group.Spec.Name, group.Spec.Description)
+
+ if err == nil {
+ group.Status.State = GroupOK
+ group.Status.LastUpdatedTime = metav1.Time{
+ Time: time.Now(),
+ }
+ }
+
+ return gitlabGroup, response, err
+}
+
+func (r *GroupReconciler) processProjects(ctx context.Context, group *gitlabv1alpha1.Group, specs []gitlabv1alpha1.ProjectSpec) error {
+ for _, projectSpec := range specs {
+ if project, foundProject, err := r.getProject(ctx, group, projectSpec); err != nil {
+ r.Log.Error(err, errorLookingUpProject, "name", projectSpec.Name)
+ return err
+ } else if foundProject {
+ if _, err := r.updateProject(ctx, projectSpec, project); err != nil {
+
+ r.Log.Error(err, errorUpdatingProject, "project", project)
+ }
+ } else {
+ if err := r.createProject(ctx, group, projectSpec); err != nil {
+
+ r.Log.Error(err, errorTryingToCreateProject, "project", projectSpec)
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (r *GroupReconciler) getProject(ctx context.Context, group *gitlabv1alpha1.Group, spec gitlabv1alpha1.ProjectSpec) (*gitlabv1alpha1.Project, bool, error) {
+ var project gitlabv1alpha1.Project
+ projectName := types.NamespacedName{
+ Namespace: group.Namespace,
+ Name: fmt.Sprintf("%s-%s", group.Name, spec.Name),
+ }
+ err := r.Get(ctx, projectName, &project)
+
+ projectNotFound := client.IgnoreNotFound(err)
+
+ if projectNotFound == nil {
+ return nil, false, nil
+ }
+
+ return &project, true, err
+}
+
+func (r *GroupReconciler) createProject(ctx context.Context, group *gitlabv1alpha1.Group, spec gitlabv1alpha1.ProjectSpec) error {
+ blockOwnerDeletion := true
+ managingController := true
+ return r.Create(ctx, &gitlabv1alpha1.Project{
+ ObjectMeta: ctrl.ObjectMeta{
+ OwnerReferences: []metav1.OwnerReference{
+ {
+ APIVersion: group.APIVersion,
+ Kind: group.Kind,
+ Name: group.Name,
+ UID: group.UID,
+ Controller: &managingController,
+ BlockOwnerDeletion: &blockOwnerDeletion,
+ },
+ },
+ },
+ Spec: gitlabv1alpha1.ProjectSpec{
+ Name: spec.Name,
+ Path: spec.Path,
+ ImpactLevel: spec.ImpactLevel,
+ StorageTypes: spec.StorageTypes,
+ VirtualService: spec.VirtualService,
+ ServicePort: spec.ServicePort,
+ Language: spec.Language,
+ },
+ })
+}
+
+func (r *GroupReconciler) updateProject(ctx context.Context, spec gitlabv1alpha1.ProjectSpec, project *gitlabv1alpha1.Project) (*gitlabv1alpha1.Project, error) {
+ project.Spec.Name = spec.Name
+ project.Spec.Path = spec.Path
+ project.Spec.ImpactLevel = spec.ImpactLevel
+ project.Spec.StorageTypes = spec.StorageTypes
+ project.Spec.VirtualService = spec.VirtualService
+ project.Spec.ServicePort = spec.ServicePort
+ project.Spec.Language = spec.Language
+ return project, r.Update(ctx, project)
+}
+
+func (r *GroupReconciler) updateStatus(ctx context.Context, id int, group *gitlabv1alpha1.Group) error {
+ if id != 0 {
+ id64 := int64(id)
+ group.Status.GitlabID = &id64
+ group.Status.LastUpdatedTime = metav1.Time{
+ Time: time.Now(),
+ }
+ }
+
+ return r.Status().Update(ctx, group)
+}
+
+// SetupWithManager sets up the controller with the Manager.
+func (r *GroupReconciler) SetupWithManager(mgr ctrl.Manager) error {
+ // Setup a default GitlabClient implementation
+ r.gitlabClient = &ClientImpl{}
+
+ return ctrl.NewControllerManagedBy(mgr).
+ For(&gitlabv1alpha1.Group{}).
+ Owns(&gitlabv1alpha1.Project{}).
+ Complete(r)
+}
diff --git a/controllers/gitlab/group_controller_test.go b/controllers/gitlab/group_controller_test.go
index 3dd202447977976ce5207c650b1bbb24ac05935a..c97e08658e42cfa98a8350dfe8d056a157431456 100755
--- a/controllers/gitlab/group_controller_test.go
+++ b/controllers/gitlab/group_controller_test.go
@@ -1,1156 +1,1141 @@
-package gitlab
-
-import (
- "context"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
- "github.com/xanzy/go-gitlab"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- "net/http"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
- gitlabv1alpha1 "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1"
-)
-
-
-var _ =
- Describe("Reconcile", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- When("it looks up the API Object", func() {
- Context("the API Object isn't found", func() {
- loggerMock := MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- contextMock := context.TODO()
- clientMock := MockClient{ statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- }}}
- clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
- requestMock := ctrl.Request{}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: &loggerMock,
- Scheme: scheme,
- }
- result, err := sut.Reconcile(contextMock, requestMock)
- It("should log the error", func() {
- Expect(loggerMock.logLevelCalled).To(Equal("Error"))
- Expect(loggerMock.loggedMessage).To(Equal("unable to fetch group"))
- })
- It("should return an empty result, and ignore the error.", func() {
- Expect(result).Should(Equal(ctrl.Result{}))
- Expect(err).Should(BeNil())
- })
- })
- })
-})
-var _ =
- Describe("Reconcile", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- When("it looks up the GitlabCredentals", func() {
- Context("gitlab credentials are not found", func() {
- loggerMock := MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- contextMock := context.TODO()
- clientMock := MockClient{ statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- }}}
- requestMock := ctrl.Request{}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: &loggerMock,
- Scheme: scheme,
- }
- requestMock.NamespacedName = types.NamespacedName{
- Namespace: "default",
- Name: "testGroup",
- }
- clientMock.GetFunction = nil
- group := gitlabv1alpha1.Group{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GroupSpec{},
- Status: gitlabv1alpha1.GroupStatus{},
- }
- clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
- clientMock.expectedObjects[requestMock.NamespacedName] = &group
- result, err := sut.Reconcile(contextMock, requestMock)
- It("should log the error", func() {
- Expect(loggerMock.logLevelCalled).To(Equal("Error"))
- Expect(loggerMock.loggedMessage).To(Equal("unable to fetch gitlab credentials"))
- })
- It("should return a reconcile result, and the error.", func() {
- Expect(result).To(Equal(ctrl.Result{
- Requeue: true,
- }))
- Expect(err).ToNot(BeNil())
- })
- })
- })
- })
-var _ =
- Describe("Reconcile", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- When("getting the secret from the GitlabCredentials", func() {
- Context("Secret doesn't exist", func() {
- loggerMock := MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- contextMock := context.TODO()
- clientMock := MockClient{ statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- }}}
- requestMock := ctrl.Request{}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: &loggerMock,
- Scheme: scheme,
- }
- requestMock.NamespacedName = types.NamespacedName{
- Namespace: "default",
- Name: "testGroup",
- }
- gitlabCred := gitlabv1alpha1.GitlabCredentials{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GitlabCredentialsSpec{
- URL: "https://example.com",
- Username: "ausername",
- AccessToken: v1.SecretReference{
- Name: "asecret",
- Namespace: "default",
- },
- },
- Status: gitlabv1alpha1.GitlabCredentialsStatus{},
- }
- group := gitlabv1alpha1.Group{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GroupSpec{
- Name: "agroup",
- GitlabCredentialsName: "gitlab-credentials",
- ProjectSpecs: nil,
- },
- Status: gitlabv1alpha1.GroupStatus{},
- }
-
- clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
- clientMock.expectedObjects[requestMock.NamespacedName] = &group
- clientMock.expectedObjects[types.NamespacedName{
- Namespace: "default",
- Name: group.Spec.GitlabCredentialsName,
- }] = &gitlabCred
- result, err := sut.Reconcile(contextMock, requestMock)
- It("Should log an error regarding the missing credentials", func() {
- Expect(loggerMock.logLevelCalled).To(Equal("Error"))
- Expect(loggerMock.loggedMessage).To(Equal("unable to fetch secret from gitlab credentials"))
- })
- It("Should return a requeue result and an error", func() {
- Expect(result).To(Equal(ctrl.Result{Requeue: true}))
- Expect(err).ToNot(BeNil())
- })
- })
- })
- })
-var _ =
- Describe("Reconcile", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- When("logging in to GitLab", func() {
- Context("can't create client", func() {
- loggerMock := &MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- contextMock := context.TODO()
- clientMock := MockClient{ statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- }}}
- requestMock := ctrl.Request{}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: loggerMock,
- Scheme: scheme,
- }
- requestMock.NamespacedName = types.NamespacedName{
- Namespace: "default",
- Name: "testGroup",
- }
- gitlabCred := gitlabv1alpha1.GitlabCredentials{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GitlabCredentialsSpec{
- URL: "https://example.com",
- Username: "ausername",
- AccessToken: v1.SecretReference{
- Name: "asecret",
- Namespace: "default",
- },
- },
- Status: gitlabv1alpha1.GitlabCredentialsStatus{},
- }
- group := gitlabv1alpha1.Group{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GroupSpec{
- Name: "agroup",
- GitlabCredentialsName: "gitlab-credentials",
- ProjectSpecs: nil,
- },
- Status: gitlabv1alpha1.GroupStatus{},
- }
- secretNamespacedName := types.NamespacedName{
- Namespace: gitlabCred.Spec.AccessToken.Namespace,
- Name: gitlabCred.Spec.AccessToken.Name,
- }
- stringData := map[string]string { "accessToken" : "password"}
- secret := v1.Secret{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- StringData: stringData,
- Type: "opaque",
- }
- clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
- clientMock.expectedObjects[requestMock.NamespacedName] = &group
- clientMock.expectedObjects[types.NamespacedName{
- Namespace: "default",
- Name: group.Spec.GitlabCredentialsName,
- }] = &gitlabCred
- clientMock.expectedObjects[secretNamespacedName] = &secret
- sut.gitlabClient = &MockGitlabClient{
- newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
- return nil, &MockError{
- message: "mocked error",
- }
- },
- }
- result, err := sut.Reconcile(contextMock, requestMock)
- It("Should log the failure", func() {
- Expect(loggerMock.logLevelCalled).To(Equal("Error"))
- Expect(loggerMock.loggedMessage).To(Equal(errorUnableToCreateGitlabClient))
- })
- It("Should return an error", func() {
- Expect(err).ToNot(BeNil())
- })
- It("should requeue the group", func() {
- Expect(result).To(Equal(ctrl.Result{Requeue: true}))
- })
- })
- })
- })
-
-var _ =
- Describe("Reconcile", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- When("groupExists fails", func() {
- loggerMock := &MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- contextMock := context.TODO()
- clientMock := MockClient{ statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- }}}
- requestMock := ctrl.Request{}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: loggerMock,
- Scheme: scheme,
- }
- requestMock.NamespacedName = types.NamespacedName{
- Namespace: "default",
- Name: "testGroup",
- }
- gitlabCred := gitlabv1alpha1.GitlabCredentials{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GitlabCredentialsSpec{
- URL: "https://example.com",
- Username: "ausername",
- AccessToken: v1.SecretReference{
- Name: "asecret",
- Namespace: "default",
- },
- },
- Status: gitlabv1alpha1.GitlabCredentialsStatus{},
- }
- group := gitlabv1alpha1.Group{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GroupSpec{
- Name: "agroup",
- GitlabCredentialsName: "gitlab-credentials",
- ProjectSpecs: nil,
- },
- Status: gitlabv1alpha1.GroupStatus{},
- }
- secretNamespacedName := types.NamespacedName{
- Namespace: gitlabCred.Spec.AccessToken.Namespace,
- Name: gitlabCred.Spec.AccessToken.Name,
- }
- stringData := map[string]string { "accessToken" : "password"}
- secret := v1.Secret{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- StringData: stringData,
- Type: "opaque",
- }
- clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
- clientMock.expectedObjects[requestMock.NamespacedName] = &group
- clientMock.expectedObjects[types.NamespacedName{
- Namespace: "default",
- Name: group.Spec.GitlabCredentialsName,
- }] = &gitlabCred
- clientMock.expectedObjects[secretNamespacedName] = &secret
- sut.gitlabClient = &MockGitlabClient{
- newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
- return &gitlab.Client{}, nil
- },
- listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- return nil, &gitlab.Response{
- Response: &http.Response{
- Status: "",
- StatusCode: 0,
- Proto: "",
- ProtoMajor: 0,
- ProtoMinor: 0,
- Header: nil,
- Body: nil,
- ContentLength: 0,
- TransferEncoding: nil,
- Close: false,
- Uncompressed: false,
- Trailer: nil,
- Request: nil,
- TLS: nil,
- },
- TotalItems: 0,
- TotalPages: 0,
- ItemsPerPage: 0,
- CurrentPage: 0,
- NextPage: 0,
- PreviousPage: 0,
- }, &MockError{
- message: "Error",
- }
- },
- }
- result, err := sut.Reconcile(contextMock, requestMock)
- It("should requeue the object", func() {
- Expect(result).To(Equal(ctrl.Result{Requeue: true}))
- })
- It("should log the error", func() {
- Expect(loggerMock.logLevelCalled).To(Equal("Error"))
- Expect(loggerMock.loggedMessage).To(Equal(errorWhileSearchingGroups))
- })
- It("should return an error", func() {
- Expect(err).NotTo(BeNil())
- })
- })
- })
-
-var _ =
- Describe("Reconcile", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- When("createGroup fails", func() {
- loggerMock := &MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- contextMock := context.TODO()
- clientMock := MockClient{ statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- }}}
- requestMock := ctrl.Request{}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: loggerMock,
- Scheme: scheme,
- }
- requestMock.NamespacedName = types.NamespacedName{
- Namespace: "default",
- Name: "testGroup",
- }
- gitlabCred := gitlabv1alpha1.GitlabCredentials{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GitlabCredentialsSpec{
- URL: "https://example.com",
- Username: "ausername",
- AccessToken: v1.SecretReference{
- Name: "asecret",
- Namespace: "default",
- },
- },
- Status: gitlabv1alpha1.GitlabCredentialsStatus{},
- }
- group := gitlabv1alpha1.Group{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GroupSpec{
- Name: "agroup",
- GitlabCredentialsName: "gitlab-credentials",
- ProjectSpecs: nil,
- },
- Status: gitlabv1alpha1.GroupStatus{},
- }
- secretNamespacedName := types.NamespacedName{
- Namespace: gitlabCred.Spec.AccessToken.Namespace,
- Name: gitlabCred.Spec.AccessToken.Name,
- }
- stringData := map[string]string { "accessToken" : "password"}
- secret := v1.Secret{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- StringData: stringData,
- Type: "opaque",
- }
- clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
- clientMock.expectedObjects[requestMock.NamespacedName] = &group
- clientMock.expectedObjects[types.NamespacedName{
- Namespace: "default",
- Name: group.Spec.GitlabCredentialsName,
- }] = &gitlabCred
- clientMock.expectedObjects[secretNamespacedName] = &secret
- sut.gitlabClient = &MockGitlabClient{
- newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
- return &gitlab.Client{}, nil
- },
- listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- groups := []*gitlab.Group{ &gitlab.Group{
- ID: 0,
- Name: "",
- Path: "",
- Description: "",
- MembershipLock: false,
- Visibility: "",
- LFSEnabled: false,
- AvatarURL: "",
- WebURL: "",
- RequestAccessEnabled: false,
- FullName: "",
- FullPath: "",
- ParentID: 0,
- Projects: nil,
- Statistics: nil,
- CustomAttributes: nil,
- ShareWithGroupLock: false,
- RequireTwoFactorAuth: false,
- TwoFactorGracePeriod: 0,
- ProjectCreationLevel: "",
- AutoDevopsEnabled: false,
- SubGroupCreationLevel: "",
- EmailsDisabled: false,
- MentionsDisabled: false,
- RunnersToken: "",
- SharedProjects: nil,
- SharedWithGroups: nil,
- LDAPCN: "",
- LDAPAccess: 0,
- LDAPGroupLinks: nil,
- SharedRunnersMinutesLimit: 0,
- ExtraSharedRunnersMinutesLimit: 0,
- MarkedForDeletionOn: nil,
- CreatedAt: nil,
- } }
- return groups, &gitlab.Response{
- Response: &http.Response{
- Status: "",
- StatusCode: 0,
- Proto: "",
- ProtoMajor: 0,
- ProtoMinor: 0,
- Header: nil,
- Body: nil,
- ContentLength: 0,
- TransferEncoding: nil,
- Close: false,
- Uncompressed: false,
- Trailer: nil,
- Request: nil,
- TLS: nil,
- },
- TotalItems: 0,
- TotalPages: 0,
- ItemsPerPage: 0,
- CurrentPage: 0,
- NextPage: 0,
- PreviousPage: 0,
- }, nil
- },
- createGroupFunction: func(name string, description string) (*gitlab.Group, *gitlab.Response, error) {
- return nil, &gitlab.Response{}, &MockError{
- message: "Error",
- }
- },
- }
- result, err := sut.Reconcile(contextMock, requestMock)
- It("should requeue the object", func() {
- Expect(result).To(Equal(ctrl.Result{Requeue: true}))
- })
- It("should log the error", func() {
- Expect(loggerMock.logLevelCalled).To(Equal("Error"))
- Expect(loggerMock.loggedMessage).To(Equal(errorWhileCreatingGitlabGroup))
- })
- It("should return an error", func() {
- Expect(err).NotTo(BeNil())
- })
- })
- })
-var _ =
- Describe("Reconcile", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- When("updateGroup fails", func() {
- loggerMock := &MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- contextMock := context.TODO()
- clientMock := MockClient{ statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- }}}
- requestMock := ctrl.Request{}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: loggerMock,
- Scheme: scheme,
- }
- requestMock.NamespacedName = types.NamespacedName{
- Namespace: "default",
- Name: "testGroup",
- }
- gitlabCred := gitlabv1alpha1.GitlabCredentials{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GitlabCredentialsSpec{
- URL: "https://example.com",
- Username: "ausername",
- AccessToken: v1.SecretReference{
- Name: "asecret",
- Namespace: "default",
- },
- },
- Status: gitlabv1alpha1.GitlabCredentialsStatus{},
- }
- group := gitlabv1alpha1.Group{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GroupSpec{
- Name: "agroup",
- GitlabCredentialsName: "gitlab-credentials",
- ProjectSpecs: nil,
- },
- Status: gitlabv1alpha1.GroupStatus{},
- }
- secretNamespacedName := types.NamespacedName{
- Namespace: gitlabCred.Spec.AccessToken.Namespace,
- Name: gitlabCred.Spec.AccessToken.Name,
- }
- stringData := map[string]string { "accessToken" : "password"}
- secret := v1.Secret{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- StringData: stringData,
- Type: "opaque",
- }
- clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
- clientMock.expectedObjects[requestMock.NamespacedName] = &group
- clientMock.expectedObjects[types.NamespacedName{
- Namespace: "default",
- Name: group.Spec.GitlabCredentialsName,
- }] = &gitlabCred
- clientMock.expectedObjects[secretNamespacedName] = &secret
- sut.gitlabClient = &MockGitlabClient{
- newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
- return &gitlab.Client{}, nil
- },
- listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- groups := []*gitlab.Group{ {Name: "agroup"} }
- return groups, &gitlab.Response{
- Response: &http.Response{
- Status: "",
- StatusCode: 0,
- Proto: "",
- ProtoMajor: 0,
- ProtoMinor: 0,
- Header: nil,
- Body: nil,
- ContentLength: 0,
- TransferEncoding: nil,
- Close: false,
- Uncompressed: false,
- Trailer: nil,
- Request: nil,
- TLS: nil,
- },
- TotalItems: 0,
- TotalPages: 0,
- ItemsPerPage: 0,
- CurrentPage: 0,
- NextPage: 0,
- PreviousPage: 0,
- }, nil
- },
- updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
- return nil, &gitlab.Response{}, &MockError{
- message: "Error",
- }
- },
- }
- result, err := sut.Reconcile(contextMock, requestMock)
- It("should requeue the object", func() {
- Expect(result).To(Equal(ctrl.Result{Requeue: true}))
- })
- It("should log the error", func() {
- Expect(loggerMock.logLevelCalled).To(Equal("Error"))
- Expect(loggerMock.loggedMessage).To(Equal(errorWhileUpdatingGitlabGroup))
- })
- It("should return an error", func() {
- Expect(err).NotTo(BeNil())
- })
- })
- })
-
-var _ =
- Describe("Reconcile", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- When("updateStatus fails", func() {
- loggerMock := &MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- contextMock := context.TODO()
- clientMock := MockClient{
- statusWriter: &MockStatusWriter{
- updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return &MockError{ "error"}
- },
- },
- }
- requestMock := ctrl.Request{}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: loggerMock,
- Scheme: scheme,
- }
- requestMock.NamespacedName = types.NamespacedName{
- Namespace: "default",
- Name: "testGroup",
- }
- gitlabCred := gitlabv1alpha1.GitlabCredentials{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GitlabCredentialsSpec{
- URL: "https://example.com",
- Username: "ausername",
- AccessToken: v1.SecretReference{
- Name: "asecret",
- Namespace: "default",
- },
- },
- Status: gitlabv1alpha1.GitlabCredentialsStatus{},
- }
- group := gitlabv1alpha1.Group{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GroupSpec{
- Name: "agroup",
- GitlabCredentialsName: "gitlab-credentials",
- ProjectSpecs: nil,
- },
- Status: gitlabv1alpha1.GroupStatus{},
- }
- secretNamespacedName := types.NamespacedName{
- Namespace: gitlabCred.Spec.AccessToken.Namespace,
- Name: gitlabCred.Spec.AccessToken.Name,
- }
- stringData := map[string]string { "accessToken" : "password"}
- secret := v1.Secret{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- StringData: stringData,
- Type: "opaque",
- }
- clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
- clientMock.expectedObjects[requestMock.NamespacedName] = &group
- clientMock.expectedObjects[types.NamespacedName{
- Namespace: "default",
- Name: group.Spec.GitlabCredentialsName,
- }] = &gitlabCred
- clientMock.expectedObjects[secretNamespacedName] = &secret
- sut.gitlabClient = &MockGitlabClient{
- newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
- return &gitlab.Client{}, nil
- },
- listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- groups := []*gitlab.Group{ {Name: "agroup"} }
- return groups, &gitlab.Response{
- Response: &http.Response{
- Status: "",
- StatusCode: 0,
- Proto: "",
- ProtoMajor: 0,
- ProtoMinor: 0,
- Header: nil,
- Body: nil,
- ContentLength: 0,
- TransferEncoding: nil,
- Close: false,
- Uncompressed: false,
- Trailer: nil,
- Request: nil,
- TLS: nil,
- },
- TotalItems: 0,
- TotalPages: 0,
- ItemsPerPage: 0,
- CurrentPage: 0,
- NextPage: 0,
- PreviousPage: 0,
- }, nil
- },
- updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
- return &gitlab.Group{ Name: "agroup" }, &gitlab.Response{}, nil
- },
- }
- result, err := sut.Reconcile(contextMock, requestMock)
- It("should requeue the object", func() {
- Expect(result).To(Equal(ctrl.Result{Requeue: true}))
- })
- It("should log the error", func() {
- Expect(loggerMock.logLevelCalled).To(Equal("Error"))
- Expect(loggerMock.loggedMessage).To(Equal(errorUnableToUpdateStatus))
- })
- It("should return an error", func() {
- Expect(err).NotTo(BeNil())
- })
- })
- })
-
-var _ =
- Describe("Reconcile", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- When("processProjects fails", func() {
- loggerMock := &MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- contextMock := context.TODO()
- clientMock := MockClient{
- statusWriter: &MockStatusWriter{
- updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- },
- },
- createFunction: func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error{
- return &MockError{message: "error"}
- },
- }
- requestMock := ctrl.Request{}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: loggerMock,
- Scheme: scheme,
- }
- requestMock.NamespacedName = types.NamespacedName{
- Namespace: "default",
- Name: "testGroup",
- }
- gitlabCred := gitlabv1alpha1.GitlabCredentials{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GitlabCredentialsSpec{
- URL: "https://example.com",
- Username: "ausername",
- AccessToken: v1.SecretReference{
- Name: "asecret",
- Namespace: "default",
- },
- },
- Status: gitlabv1alpha1.GitlabCredentialsStatus{},
- }
- group := gitlabv1alpha1.Group{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- Spec: gitlabv1alpha1.GroupSpec{
- Name: "agroup",
- GitlabCredentialsName: "gitlab-credentials",
- ProjectSpecs: []gitlabv1alpha1.ProjectSpec{ { Name: "ProjectSpec"} },
- },
- Status: gitlabv1alpha1.GroupStatus{},
- }
- secretNamespacedName := types.NamespacedName{
- Namespace: gitlabCred.Spec.AccessToken.Namespace,
- Name: gitlabCred.Spec.AccessToken.Name,
- }
- stringData := map[string]string { "accessToken" : "password"}
- secret := v1.Secret{
- TypeMeta: metav1.TypeMeta{},
- ObjectMeta: metav1.ObjectMeta{},
- StringData: stringData,
- Type: "opaque",
- }
- clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
- clientMock.expectedObjects[requestMock.NamespacedName] = &group
- clientMock.expectedObjects[types.NamespacedName{
- Namespace: "default",
- Name: group.Spec.GitlabCredentialsName,
- }] = &gitlabCred
- clientMock.expectedObjects[secretNamespacedName] = &secret
- sut.gitlabClient = &MockGitlabClient{
- newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
- return &gitlab.Client{}, nil
- },
- listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- groups := []*gitlab.Group{ {Name: "agroup"} }
- return groups, &gitlab.Response{
- Response: &http.Response{
- Status: "",
- StatusCode: 0,
- Proto: "",
- ProtoMajor: 0,
- ProtoMinor: 0,
- Header: nil,
- Body: nil,
- ContentLength: 0,
- TransferEncoding: nil,
- Close: false,
- Uncompressed: false,
- Trailer: nil,
- Request: nil,
- TLS: nil,
- },
- TotalItems: 0,
- TotalPages: 0,
- ItemsPerPage: 0,
- CurrentPage: 0,
- NextPage: 0,
- PreviousPage: 0,
- }, nil
- },
- updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
- return &gitlab.Group{ Name: "agroup" }, &gitlab.Response{}, nil
- },
- }
- result, err := sut.Reconcile(contextMock, requestMock)
- It("should requeue the object", func() {
- Expect(result).To(Equal(ctrl.Result{Requeue: true}))
- })
- It("should log the error", func() {
- Expect(loggerMock.logLevelCalled).To(Equal("Error"))
- Expect(loggerMock.loggedMessage).To(Equal(errorUnableToProcessProjects))
- })
- It("should return an error", func() {
- Expect(err).NotTo(BeNil())
- })
- })
- })
-
-var _ =
- Describe("groupExists", func() {
- When("the gitlab client fails", func() {
- sut := GroupReconciler{
- gitlabClient: &MockGitlabClient{
- listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- return nil, &gitlab.Response{}, &MockError{
- message: "mockedError",
- }
- },
- },
- }
- found, response, groups, err := sut.groupExists(&gitlabv1alpha1.Group{ Spec: gitlabv1alpha1.GroupSpec{Name: "An error"}})
- It("should return that it didn't find the group", func() {
- Expect(found).To(Equal(false))
- })
- It("should return the gitlab response", func() {
- Expect(response).ToNot(BeNil())
- })
- It("should return a nil group", func() {
- Expect(groups).To(BeNil())
- })
- It("should return an error", func() {
- Expect(err).ToNot(BeNil())
- })
- })
- When("the group is in the list", func() {
- group := &gitlab.Group{ Name: "A group" }
- returnGroups := []*gitlab.Group{ group }
- sut := GroupReconciler{
- gitlabClient: &MockGitlabClient{
- listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- return returnGroups, &gitlab.Response{}, nil
- },
- },
- }
-
- found, response, returnedGroup, err := sut.groupExists(&gitlabv1alpha1.Group{ Spec: gitlabv1alpha1.GroupSpec{Name: "A group"}})
- It("should return that it found the group", func() {
- Expect(found).To(Equal(true))
- })
- It("should return the gitlab response", func() {
- Expect(response).ToNot(BeNil())
- })
- It("should return list with the group", func() {
- Expect(returnedGroup).To(Equal(group))
- })
- It("should not return an error", func() {
- Expect(err).To(BeNil())
- })
- })
- When("the group is not in the list", func() {
- sut := GroupReconciler{
- gitlabClient: &MockGitlabClient{
- listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- return nil, &gitlab.Response{}, nil
- },
- },
- }
-
- found, response, groups, err := sut.groupExists(&gitlabv1alpha1.Group{ Spec: gitlabv1alpha1.GroupSpec{Name: "A group"}})
- It("should return that it did not find the group", func() {
- Expect(found).To(Equal(false))
- })
- It("should return the gitlab response", func() {
- Expect(response).ToNot(BeNil())
- })
- It("should return nil for the group list", func() {
- Expect(groups).To(BeNil())
- })
- It("should not return an error", func() {
- Expect(err).To(BeNil())
- })
- })
- })
-var _ =
- Describe("createGroup", func() {
- expectedGroup := &gitlab.Group{ ID: 1, Name: "A test group"}
- expectedResponse := &gitlab.Response{
- Response: &http.Response{},
- TotalItems: 1,
- TotalPages: 1,
- ItemsPerPage: 10,
- CurrentPage: 1,
- NextPage: 0,
- PreviousPage: 0,
- }
- sut := GroupReconciler{
- gitlabClient: &MockGitlabClient{
- createGroupFunction: func(name string, description string) (*gitlab.Group, *gitlab.Response, error) {
- return expectedGroup, expectedResponse, nil
- },
- },
- }
- group, response, err := sut.createGroup(
- &gitlabv1alpha1.Group{
- ObjectMeta: ctrl.ObjectMeta{Annotations: make(map[string]string)},
- Spec: gitlabv1alpha1.GroupSpec{Name: "a group"},
- })
- It("should return the gitlab group created", func() {
- Expect(group).To(Equal(expectedGroup))
- })
- It("should return the gitlab response", func(){
- Expect(response).To(Equal(expectedResponse))
- })
- It("should return the error created by the call, or nil", func() {
- Expect(err).To(BeNil())
- })
- })
-
-var _ =
- Describe("updateGroup", func() {
- expectedGroup := &gitlab.Group{ID: 2, Name: "A test group"}
- expectedResponse := &gitlab.Response{
- Response: &http.Response{},
- TotalItems: 1,
- TotalPages: 1,
- ItemsPerPage: 10,
- CurrentPage: 1,
- NextPage: 0,
- PreviousPage: 0,
- }
- sut := GroupReconciler{
- gitlabClient: &MockGitlabClient{
- updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
- return expectedGroup, expectedResponse, nil
- },
- listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- return []*gitlab.Group{{Name: "a group"}}, &gitlab.Response{}, nil
- },
- },
- }
- group, response, err := sut.updateGroup(
- &gitlabv1alpha1.Group{
- ObjectMeta: ctrl.ObjectMeta{Annotations: make(map[string]string)},
- Spec: gitlabv1alpha1.GroupSpec{Name: "a group"},
- Status: gitlabv1alpha1.GroupStatus{
- GitlabID: nil,
- CreatedTime: metav1.Time{},
- LastUpdatedTime: metav1.Time{},
- State: "",
- },
- })
- It("should return the gitlab group created", func() {
- Expect(group).To(Equal(expectedGroup))
- })
- It("should return the gitlab response", func(){
- Expect(response).To(Equal(expectedResponse))
- })
- It("should return the error created by the call, or nil", func() {
- Expect(err).To(BeNil())
- })
- })
-
-var _ =
- Describe("SetupWithManager", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- loggerMock := MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- clientMock := MockClient{ statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- }}}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: &loggerMock,
- Scheme: scheme,
- }
- err := sut.SetupWithManager(&MockManager{
- Log: &loggerMock,
- builder: builder,
- })
- It("should setup the default gitlab client", func() {
- Expect(sut.gitlabClient).To(BeAssignableToTypeOf(&ClientImpl{}))
- })
- It("should return no error", func() {
- Expect(err).To(BeNil())
- })
- })
-
-var _ = Describe("updateStatus", func() {
- When("group id is not 0", func() {
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- loggerMock := MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- clientMock := MockClient{ statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- }}}
- sut := GroupReconciler{
- Client: &clientMock,
- Log: &loggerMock,
- Scheme: scheme,
- }
- group := gitlabv1alpha1.Group{Status: gitlabv1alpha1.GroupStatus{
- GitlabID: nil,
- CreatedTime: metav1.Time{},
- LastUpdatedTime: metav1.Time{},
- State: "",
- }}
- sut.updateStatus(&MockContext{}, 1, &group)
-
- It("should update the gitlab id", func() {
- Expect(*group.Status.GitlabID).To(Equal(int64(1)))
- })
- It("should update the last updated time", func() {
- Expect(group.Status.LastUpdatedTime.Time).To(Not(BeNil()))
- })
- })
-})
-
-var _ =
- Describe("updateProject", func() {
- spec := gitlabv1alpha1.ProjectSpec{
- Name: "a project",
- Path: "https://example.com.path",
- ImpactLevel: "2",
- StorageTypes: nil,
- VirtualService: "default",
- ServicePort: 8081,
- Language: "golang",
- }
- project := gitlabv1alpha1.Project{Spec: gitlabv1alpha1.ProjectSpec{}}
- builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
- scheme, _ := builder.Build()
- loggerMock := MockLogger{
- WithValuesKeysAndValues: nil,
- WithValuesCalled: false,
- WithNameValue: "",
- WithNameCalled: false,
- }
- mockError := &MockError{"true"}
- clientMock := MockClient{
- statusWriter: MockStatusWriter{
- updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return nil
- },
- },
- updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return mockError
- },
- }
- sut := GroupReconciler{
- Client: &clientMock,
- Log: &loggerMock,
- Scheme: scheme,
- }
-
- returnedProject, err := sut.updateProject(context.TODO(), spec, &project)
- It("should update the project from the project specification", func() {
- Expect(project.Spec.Name).To(Equal(spec.Name))
- Expect(project.Spec.ServicePort).To(Equal(spec.ServicePort))
- Expect(project.Spec.Language).To(Equal(spec.Language))
- Expect(project.Spec.Path).To(Equal(spec.Path))
- Expect(project.Spec.VirtualService).To(Equal(spec.VirtualService))
- Expect(project.Spec.StorageTypes).To(Equal(spec.StorageTypes))
- Expect(project.Spec.ImpactLevel).To(Equal(spec.ImpactLevel))
- })
- It("should call the kubernetes client update function", func() {
- Expect(clientMock.updateFunctionCalled).To(BeTrue())
- })
- It("should return the result of the update function", func() {
- Expect(err).To(Equal(mockError))
- })
- It("should return the updated project", func() {
- Expect(project).To(Equal(*returnedProject))
- })
- })
\ No newline at end of file
+package gitlab
+
+import (
+ "context"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "github.com/xanzy/go-gitlab"
+ v1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/types"
+ "net/http"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ gitlabv1alpha1 "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1"
+)
+
+var _ = Describe("Reconcile", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ When("it looks up the API Object", func() {
+ Context("the API Object isn't found", func() {
+ loggerMock := MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ contextMock := context.TODO()
+ clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ }}}
+ clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
+ requestMock := ctrl.Request{}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: &loggerMock,
+ Scheme: scheme,
+ }
+ result, err := sut.Reconcile(contextMock, requestMock)
+ It("should log the error", func() {
+ Expect(loggerMock.logLevelCalled).To(Equal("Error"))
+ Expect(loggerMock.loggedMessage).To(Equal("unable to fetch group"))
+ })
+ It("should return an empty result, and ignore the error.", func() {
+ Expect(result).Should(Equal(ctrl.Result{}))
+ Expect(err).Should(BeNil())
+ })
+ })
+ })
+})
+var _ = Describe("Reconcile", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ When("it looks up the GitlabCredentals", func() {
+ Context("gitlab credentials are not found", func() {
+ loggerMock := MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ contextMock := context.TODO()
+ clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ }}}
+ requestMock := ctrl.Request{}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: &loggerMock,
+ Scheme: scheme,
+ }
+ requestMock.NamespacedName = types.NamespacedName{
+ Namespace: "default",
+ Name: "testGroup",
+ }
+ clientMock.GetFunction = nil
+ group := gitlabv1alpha1.Group{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GroupSpec{},
+ Status: gitlabv1alpha1.GroupStatus{},
+ }
+ clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
+ clientMock.expectedObjects[requestMock.NamespacedName] = &group
+ result, err := sut.Reconcile(contextMock, requestMock)
+ It("should log the error", func() {
+ Expect(loggerMock.logLevelCalled).To(Equal("Error"))
+ Expect(loggerMock.loggedMessage).To(Equal("unable to fetch gitlab credentials"))
+ })
+ It("should return a reconcile result, and the error.", func() {
+ Expect(result).To(Equal(ctrl.Result{
+ Requeue: true,
+ }))
+ Expect(err).ToNot(BeNil())
+ })
+ })
+ })
+})
+var _ = Describe("Reconcile", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ When("getting the secret from the GitlabCredentials", func() {
+ Context("Secret doesn't exist", func() {
+ loggerMock := MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ contextMock := context.TODO()
+ clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ }}}
+ requestMock := ctrl.Request{}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: &loggerMock,
+ Scheme: scheme,
+ }
+ requestMock.NamespacedName = types.NamespacedName{
+ Namespace: "default",
+ Name: "testGroup",
+ }
+ gitlabCred := gitlabv1alpha1.GitlabCredentials{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GitlabCredentialsSpec{
+ URL: "https://example.com",
+ Username: "ausername",
+ AccessToken: v1.SecretReference{
+ Name: "asecret",
+ Namespace: "default",
+ },
+ },
+ Status: gitlabv1alpha1.GitlabCredentialsStatus{},
+ }
+ group := gitlabv1alpha1.Group{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GroupSpec{
+ Name: "agroup",
+ GitlabCredentialsName: "gitlab-credentials",
+ ProjectSpecs: nil,
+ },
+ Status: gitlabv1alpha1.GroupStatus{},
+ }
+
+ clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
+ clientMock.expectedObjects[requestMock.NamespacedName] = &group
+ clientMock.expectedObjects[types.NamespacedName{
+ Namespace: "default",
+ Name: group.Spec.GitlabCredentialsName,
+ }] = &gitlabCred
+ result, err := sut.Reconcile(contextMock, requestMock)
+ It("Should log an error regarding the missing credentials", func() {
+ Expect(loggerMock.logLevelCalled).To(Equal("Error"))
+ Expect(loggerMock.loggedMessage).To(Equal("unable to fetch secret from gitlab credentials"))
+ })
+ It("Should return a requeue result and an error", func() {
+ Expect(result).To(Equal(ctrl.Result{Requeue: true}))
+ Expect(err).ToNot(BeNil())
+ })
+ })
+ })
+})
+var _ = Describe("Reconcile", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ When("logging in to GitLab", func() {
+ Context("can't create client", func() {
+ loggerMock := &MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ contextMock := context.TODO()
+ clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ }}}
+ requestMock := ctrl.Request{}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: loggerMock,
+ Scheme: scheme,
+ }
+ requestMock.NamespacedName = types.NamespacedName{
+ Namespace: "default",
+ Name: "testGroup",
+ }
+ gitlabCred := gitlabv1alpha1.GitlabCredentials{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GitlabCredentialsSpec{
+ URL: "https://example.com",
+ Username: "ausername",
+ AccessToken: v1.SecretReference{
+ Name: "asecret",
+ Namespace: "default",
+ },
+ },
+ Status: gitlabv1alpha1.GitlabCredentialsStatus{},
+ }
+ group := gitlabv1alpha1.Group{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GroupSpec{
+ Name: "agroup",
+ GitlabCredentialsName: "gitlab-credentials",
+ ProjectSpecs: nil,
+ },
+ Status: gitlabv1alpha1.GroupStatus{},
+ }
+ secretNamespacedName := types.NamespacedName{
+ Namespace: gitlabCred.Spec.AccessToken.Namespace,
+ Name: gitlabCred.Spec.AccessToken.Name,
+ }
+ stringData := map[string]string{"accessToken": "password"}
+ secret := v1.Secret{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ StringData: stringData,
+ Type: "opaque",
+ }
+ clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
+ clientMock.expectedObjects[requestMock.NamespacedName] = &group
+ clientMock.expectedObjects[types.NamespacedName{
+ Namespace: "default",
+ Name: group.Spec.GitlabCredentialsName,
+ }] = &gitlabCred
+ clientMock.expectedObjects[secretNamespacedName] = &secret
+ sut.gitlabClient = &MockGitlabClient{
+ newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
+ return nil, &MockError{
+ message: "mocked error",
+ }
+ },
+ }
+ result, err := sut.Reconcile(contextMock, requestMock)
+ It("Should log the failure", func() {
+ Expect(loggerMock.logLevelCalled).To(Equal("Error"))
+ Expect(loggerMock.loggedMessage).To(Equal(errorUnableToCreateGitlabClient))
+ })
+ It("Should return an error", func() {
+ Expect(err).ToNot(BeNil())
+ })
+ It("should requeue the group", func() {
+ Expect(result).To(Equal(ctrl.Result{Requeue: true}))
+ })
+ })
+ })
+})
+
+var _ = Describe("Reconcile", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ When("groupExists fails", func() {
+ loggerMock := &MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ contextMock := context.TODO()
+ clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ }}}
+ requestMock := ctrl.Request{}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: loggerMock,
+ Scheme: scheme,
+ }
+ requestMock.NamespacedName = types.NamespacedName{
+ Namespace: "default",
+ Name: "testGroup",
+ }
+ gitlabCred := gitlabv1alpha1.GitlabCredentials{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GitlabCredentialsSpec{
+ URL: "https://example.com",
+ Username: "ausername",
+ AccessToken: v1.SecretReference{
+ Name: "asecret",
+ Namespace: "default",
+ },
+ },
+ Status: gitlabv1alpha1.GitlabCredentialsStatus{},
+ }
+ group := gitlabv1alpha1.Group{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GroupSpec{
+ Name: "agroup",
+ GitlabCredentialsName: "gitlab-credentials",
+ ProjectSpecs: nil,
+ },
+ Status: gitlabv1alpha1.GroupStatus{},
+ }
+ secretNamespacedName := types.NamespacedName{
+ Namespace: gitlabCred.Spec.AccessToken.Namespace,
+ Name: gitlabCred.Spec.AccessToken.Name,
+ }
+ stringData := map[string]string{"accessToken": "password"}
+ secret := v1.Secret{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ StringData: stringData,
+ Type: "opaque",
+ }
+ clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
+ clientMock.expectedObjects[requestMock.NamespacedName] = &group
+ clientMock.expectedObjects[types.NamespacedName{
+ Namespace: "default",
+ Name: group.Spec.GitlabCredentialsName,
+ }] = &gitlabCred
+ clientMock.expectedObjects[secretNamespacedName] = &secret
+ sut.gitlabClient = &MockGitlabClient{
+ newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
+ return &gitlab.Client{}, nil
+ },
+ listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ return nil, &gitlab.Response{
+ Response: &http.Response{
+ Status: "",
+ StatusCode: 0,
+ Proto: "",
+ ProtoMajor: 0,
+ ProtoMinor: 0,
+ Header: nil,
+ Body: nil,
+ ContentLength: 0,
+ TransferEncoding: nil,
+ Close: false,
+ Uncompressed: false,
+ Trailer: nil,
+ Request: nil,
+ TLS: nil,
+ },
+ TotalItems: 0,
+ TotalPages: 0,
+ ItemsPerPage: 0,
+ CurrentPage: 0,
+ NextPage: 0,
+ PreviousPage: 0,
+ }, &MockError{
+ message: "Error",
+ }
+ },
+ }
+ result, err := sut.Reconcile(contextMock, requestMock)
+ It("should requeue the object", func() {
+ Expect(result).To(Equal(ctrl.Result{Requeue: true}))
+ })
+ It("should log the error", func() {
+ Expect(loggerMock.logLevelCalled).To(Equal("Error"))
+ Expect(loggerMock.loggedMessage).To(Equal(errorWhileSearchingGroups))
+ })
+ It("should return an error", func() {
+ Expect(err).NotTo(BeNil())
+ })
+ })
+})
+
+var _ = Describe("Reconcile", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ When("createGroup fails", func() {
+ loggerMock := &MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ contextMock := context.TODO()
+ clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ }}}
+ requestMock := ctrl.Request{}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: loggerMock,
+ Scheme: scheme,
+ }
+ requestMock.NamespacedName = types.NamespacedName{
+ Namespace: "default",
+ Name: "testGroup",
+ }
+ gitlabCred := gitlabv1alpha1.GitlabCredentials{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GitlabCredentialsSpec{
+ URL: "https://example.com",
+ Username: "ausername",
+ AccessToken: v1.SecretReference{
+ Name: "asecret",
+ Namespace: "default",
+ },
+ },
+ Status: gitlabv1alpha1.GitlabCredentialsStatus{},
+ }
+ group := gitlabv1alpha1.Group{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GroupSpec{
+ Name: "agroup",
+ GitlabCredentialsName: "gitlab-credentials",
+ ProjectSpecs: nil,
+ },
+ Status: gitlabv1alpha1.GroupStatus{},
+ }
+ secretNamespacedName := types.NamespacedName{
+ Namespace: gitlabCred.Spec.AccessToken.Namespace,
+ Name: gitlabCred.Spec.AccessToken.Name,
+ }
+ stringData := map[string]string{"accessToken": "password"}
+ secret := v1.Secret{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ StringData: stringData,
+ Type: "opaque",
+ }
+ clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
+ clientMock.expectedObjects[requestMock.NamespacedName] = &group
+ clientMock.expectedObjects[types.NamespacedName{
+ Namespace: "default",
+ Name: group.Spec.GitlabCredentialsName,
+ }] = &gitlabCred
+ clientMock.expectedObjects[secretNamespacedName] = &secret
+ sut.gitlabClient = &MockGitlabClient{
+ newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
+ return &gitlab.Client{}, nil
+ },
+ listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ groups := []*gitlab.Group{&gitlab.Group{
+ ID: 0,
+ Name: "",
+ Path: "",
+ Description: "",
+ MembershipLock: false,
+ Visibility: "",
+ LFSEnabled: false,
+ AvatarURL: "",
+ WebURL: "",
+ RequestAccessEnabled: false,
+ FullName: "",
+ FullPath: "",
+ ParentID: 0,
+ Projects: nil,
+ Statistics: nil,
+ CustomAttributes: nil,
+ ShareWithGroupLock: false,
+ RequireTwoFactorAuth: false,
+ TwoFactorGracePeriod: 0,
+ ProjectCreationLevel: "",
+ AutoDevopsEnabled: false,
+ SubGroupCreationLevel: "",
+ EmailsDisabled: false,
+ MentionsDisabled: false,
+ RunnersToken: "",
+ SharedProjects: nil,
+ SharedWithGroups: nil,
+ LDAPCN: "",
+ LDAPAccess: 0,
+ LDAPGroupLinks: nil,
+ SharedRunnersMinutesLimit: 0,
+ ExtraSharedRunnersMinutesLimit: 0,
+ MarkedForDeletionOn: nil,
+ CreatedAt: nil,
+ }}
+ return groups, &gitlab.Response{
+ Response: &http.Response{
+ Status: "",
+ StatusCode: 0,
+ Proto: "",
+ ProtoMajor: 0,
+ ProtoMinor: 0,
+ Header: nil,
+ Body: nil,
+ ContentLength: 0,
+ TransferEncoding: nil,
+ Close: false,
+ Uncompressed: false,
+ Trailer: nil,
+ Request: nil,
+ TLS: nil,
+ },
+ TotalItems: 0,
+ TotalPages: 0,
+ ItemsPerPage: 0,
+ CurrentPage: 0,
+ NextPage: 0,
+ PreviousPage: 0,
+ }, nil
+ },
+ createGroupFunction: func(name string, description string) (*gitlab.Group, *gitlab.Response, error) {
+ return nil, &gitlab.Response{}, &MockError{
+ message: "Error",
+ }
+ },
+ }
+ result, err := sut.Reconcile(contextMock, requestMock)
+ It("should requeue the object", func() {
+ Expect(result).To(Equal(ctrl.Result{Requeue: true}))
+ })
+ It("should log the error", func() {
+ Expect(loggerMock.logLevelCalled).To(Equal("Error"))
+ Expect(loggerMock.loggedMessage).To(Equal(errorWhileCreatingGitlabGroup))
+ })
+ It("should return an error", func() {
+ Expect(err).NotTo(BeNil())
+ })
+ })
+})
+var _ = Describe("Reconcile", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ When("updateGroup fails", func() {
+ loggerMock := &MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ contextMock := context.TODO()
+ clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ }}}
+ requestMock := ctrl.Request{}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: loggerMock,
+ Scheme: scheme,
+ }
+ requestMock.NamespacedName = types.NamespacedName{
+ Namespace: "default",
+ Name: "testGroup",
+ }
+ gitlabCred := gitlabv1alpha1.GitlabCredentials{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GitlabCredentialsSpec{
+ URL: "https://example.com",
+ Username: "ausername",
+ AccessToken: v1.SecretReference{
+ Name: "asecret",
+ Namespace: "default",
+ },
+ },
+ Status: gitlabv1alpha1.GitlabCredentialsStatus{},
+ }
+ group := gitlabv1alpha1.Group{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GroupSpec{
+ Name: "agroup",
+ GitlabCredentialsName: "gitlab-credentials",
+ ProjectSpecs: nil,
+ },
+ Status: gitlabv1alpha1.GroupStatus{},
+ }
+ secretNamespacedName := types.NamespacedName{
+ Namespace: gitlabCred.Spec.AccessToken.Namespace,
+ Name: gitlabCred.Spec.AccessToken.Name,
+ }
+ stringData := map[string]string{"accessToken": "password"}
+ secret := v1.Secret{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ StringData: stringData,
+ Type: "opaque",
+ }
+ clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
+ clientMock.expectedObjects[requestMock.NamespacedName] = &group
+ clientMock.expectedObjects[types.NamespacedName{
+ Namespace: "default",
+ Name: group.Spec.GitlabCredentialsName,
+ }] = &gitlabCred
+ clientMock.expectedObjects[secretNamespacedName] = &secret
+ sut.gitlabClient = &MockGitlabClient{
+ newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
+ return &gitlab.Client{}, nil
+ },
+ listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ groups := []*gitlab.Group{{Name: "agroup"}}
+ return groups, &gitlab.Response{
+ Response: &http.Response{
+ Status: "",
+ StatusCode: 0,
+ Proto: "",
+ ProtoMajor: 0,
+ ProtoMinor: 0,
+ Header: nil,
+ Body: nil,
+ ContentLength: 0,
+ TransferEncoding: nil,
+ Close: false,
+ Uncompressed: false,
+ Trailer: nil,
+ Request: nil,
+ TLS: nil,
+ },
+ TotalItems: 0,
+ TotalPages: 0,
+ ItemsPerPage: 0,
+ CurrentPage: 0,
+ NextPage: 0,
+ PreviousPage: 0,
+ }, nil
+ },
+ updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
+ return nil, &gitlab.Response{}, &MockError{
+ message: "Error",
+ }
+ },
+ }
+ result, err := sut.Reconcile(contextMock, requestMock)
+ It("should requeue the object", func() {
+ Expect(result).To(Equal(ctrl.Result{Requeue: true}))
+ })
+ It("should log the error", func() {
+ Expect(loggerMock.logLevelCalled).To(Equal("Error"))
+ Expect(loggerMock.loggedMessage).To(Equal(errorWhileUpdatingGitlabGroup))
+ })
+ It("should return an error", func() {
+ Expect(err).NotTo(BeNil())
+ })
+ })
+})
+
+var _ = Describe("Reconcile", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ When("updateStatus fails", func() {
+ loggerMock := &MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ contextMock := context.TODO()
+ clientMock := MockClient{
+ statusWriter: &MockStatusWriter{
+ updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return &MockError{"error"}
+ },
+ },
+ }
+ requestMock := ctrl.Request{}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: loggerMock,
+ Scheme: scheme,
+ }
+ requestMock.NamespacedName = types.NamespacedName{
+ Namespace: "default",
+ Name: "testGroup",
+ }
+ gitlabCred := gitlabv1alpha1.GitlabCredentials{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GitlabCredentialsSpec{
+ URL: "https://example.com",
+ Username: "ausername",
+ AccessToken: v1.SecretReference{
+ Name: "asecret",
+ Namespace: "default",
+ },
+ },
+ Status: gitlabv1alpha1.GitlabCredentialsStatus{},
+ }
+ group := gitlabv1alpha1.Group{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GroupSpec{
+ Name: "agroup",
+ GitlabCredentialsName: "gitlab-credentials",
+ ProjectSpecs: nil,
+ },
+ Status: gitlabv1alpha1.GroupStatus{},
+ }
+ secretNamespacedName := types.NamespacedName{
+ Namespace: gitlabCred.Spec.AccessToken.Namespace,
+ Name: gitlabCred.Spec.AccessToken.Name,
+ }
+ stringData := map[string]string{"accessToken": "password"}
+ secret := v1.Secret{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ StringData: stringData,
+ Type: "opaque",
+ }
+ clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
+ clientMock.expectedObjects[requestMock.NamespacedName] = &group
+ clientMock.expectedObjects[types.NamespacedName{
+ Namespace: "default",
+ Name: group.Spec.GitlabCredentialsName,
+ }] = &gitlabCred
+ clientMock.expectedObjects[secretNamespacedName] = &secret
+ sut.gitlabClient = &MockGitlabClient{
+ newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
+ return &gitlab.Client{}, nil
+ },
+ listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ groups := []*gitlab.Group{{Name: "agroup"}}
+ return groups, &gitlab.Response{
+ Response: &http.Response{
+ Status: "",
+ StatusCode: 0,
+ Proto: "",
+ ProtoMajor: 0,
+ ProtoMinor: 0,
+ Header: nil,
+ Body: nil,
+ ContentLength: 0,
+ TransferEncoding: nil,
+ Close: false,
+ Uncompressed: false,
+ Trailer: nil,
+ Request: nil,
+ TLS: nil,
+ },
+ TotalItems: 0,
+ TotalPages: 0,
+ ItemsPerPage: 0,
+ CurrentPage: 0,
+ NextPage: 0,
+ PreviousPage: 0,
+ }, nil
+ },
+ updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
+ return &gitlab.Group{Name: "agroup"}, &gitlab.Response{}, nil
+ },
+ }
+ result, err := sut.Reconcile(contextMock, requestMock)
+ It("should requeue the object", func() {
+ Expect(result).To(Equal(ctrl.Result{Requeue: true}))
+ })
+ It("should log the error", func() {
+ Expect(loggerMock.logLevelCalled).To(Equal("Error"))
+ Expect(loggerMock.loggedMessage).To(Equal(errorUnableToUpdateStatus))
+ })
+ It("should return an error", func() {
+ Expect(err).NotTo(BeNil())
+ })
+ })
+})
+
+var _ = Describe("Reconcile", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ When("processProjects fails", func() {
+ loggerMock := &MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ contextMock := context.TODO()
+ clientMock := MockClient{
+ statusWriter: &MockStatusWriter{
+ updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ },
+ },
+ createFunction: func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
+ return &MockError{message: "error"}
+ },
+ }
+ requestMock := ctrl.Request{}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: loggerMock,
+ Scheme: scheme,
+ }
+ requestMock.NamespacedName = types.NamespacedName{
+ Namespace: "default",
+ Name: "testGroup",
+ }
+ gitlabCred := gitlabv1alpha1.GitlabCredentials{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GitlabCredentialsSpec{
+ URL: "https://example.com",
+ Username: "ausername",
+ AccessToken: v1.SecretReference{
+ Name: "asecret",
+ Namespace: "default",
+ },
+ },
+ Status: gitlabv1alpha1.GitlabCredentialsStatus{},
+ }
+ group := gitlabv1alpha1.Group{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ Spec: gitlabv1alpha1.GroupSpec{
+ Name: "agroup",
+ GitlabCredentialsName: "gitlab-credentials",
+ ProjectSpecs: []gitlabv1alpha1.ProjectSpec{{Name: "ProjectSpec"}},
+ },
+ Status: gitlabv1alpha1.GroupStatus{},
+ }
+ secretNamespacedName := types.NamespacedName{
+ Namespace: gitlabCred.Spec.AccessToken.Namespace,
+ Name: gitlabCred.Spec.AccessToken.Name,
+ }
+ stringData := map[string]string{"accessToken": "password"}
+ secret := v1.Secret{
+ TypeMeta: metav1.TypeMeta{},
+ ObjectMeta: metav1.ObjectMeta{},
+ StringData: stringData,
+ Type: "opaque",
+ }
+ clientMock.expectedObjects = make(map[client.ObjectKey]client.Object)
+ clientMock.expectedObjects[requestMock.NamespacedName] = &group
+ clientMock.expectedObjects[types.NamespacedName{
+ Namespace: "default",
+ Name: group.Spec.GitlabCredentialsName,
+ }] = &gitlabCred
+ clientMock.expectedObjects[secretNamespacedName] = &secret
+ sut.gitlabClient = &MockGitlabClient{
+ newClientFunction: func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
+ return &gitlab.Client{}, nil
+ },
+ listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ groups := []*gitlab.Group{{Name: "agroup"}}
+ return groups, &gitlab.Response{
+ Response: &http.Response{
+ Status: "",
+ StatusCode: 0,
+ Proto: "",
+ ProtoMajor: 0,
+ ProtoMinor: 0,
+ Header: nil,
+ Body: nil,
+ ContentLength: 0,
+ TransferEncoding: nil,
+ Close: false,
+ Uncompressed: false,
+ Trailer: nil,
+ Request: nil,
+ TLS: nil,
+ },
+ TotalItems: 0,
+ TotalPages: 0,
+ ItemsPerPage: 0,
+ CurrentPage: 0,
+ NextPage: 0,
+ PreviousPage: 0,
+ }, nil
+ },
+ updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
+ return &gitlab.Group{Name: "agroup"}, &gitlab.Response{}, nil
+ },
+ }
+ result, err := sut.Reconcile(contextMock, requestMock)
+ It("should requeue the object", func() {
+ Expect(result).To(Equal(ctrl.Result{Requeue: true}))
+ })
+ It("should log the error", func() {
+ Expect(loggerMock.logLevelCalled).To(Equal("Error"))
+ Expect(loggerMock.loggedMessage).To(Equal(errorUnableToProcessProjects))
+ })
+ It("should return an error", func() {
+ Expect(err).NotTo(BeNil())
+ })
+ })
+})
+
+var _ = Describe("groupExists", func() {
+ When("the gitlab client fails", func() {
+ sut := GroupReconciler{
+ gitlabClient: &MockGitlabClient{
+ listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ return nil, &gitlab.Response{}, &MockError{
+ message: "mockedError",
+ }
+ },
+ },
+ }
+ found, response, groups, err := sut.groupExists(&gitlabv1alpha1.Group{Spec: gitlabv1alpha1.GroupSpec{Name: "An error"}})
+ It("should return that it didn't find the group", func() {
+ Expect(found).To(Equal(false))
+ })
+ It("should return the gitlab response", func() {
+ Expect(response).ToNot(BeNil())
+ })
+ It("should return a nil group", func() {
+ Expect(groups).To(BeNil())
+ })
+ It("should return an error", func() {
+ Expect(err).ToNot(BeNil())
+ })
+ })
+ When("the group is in the list", func() {
+ group := &gitlab.Group{Name: "A group"}
+ returnGroups := []*gitlab.Group{group}
+ sut := GroupReconciler{
+ gitlabClient: &MockGitlabClient{
+ listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ return returnGroups, &gitlab.Response{}, nil
+ },
+ },
+ }
+
+ found, response, returnedGroup, err := sut.groupExists(&gitlabv1alpha1.Group{Spec: gitlabv1alpha1.GroupSpec{Name: "A group"}})
+ It("should return that it found the group", func() {
+ Expect(found).To(Equal(true))
+ })
+ It("should return the gitlab response", func() {
+ Expect(response).ToNot(BeNil())
+ })
+ It("should return list with the group", func() {
+ Expect(returnedGroup).To(Equal(group))
+ })
+ It("should not return an error", func() {
+ Expect(err).To(BeNil())
+ })
+ })
+ When("the group is not in the list", func() {
+ sut := GroupReconciler{
+ gitlabClient: &MockGitlabClient{
+ listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ return nil, &gitlab.Response{}, nil
+ },
+ },
+ }
+
+ found, response, groups, err := sut.groupExists(&gitlabv1alpha1.Group{Spec: gitlabv1alpha1.GroupSpec{Name: "A group"}})
+ It("should return that it did not find the group", func() {
+ Expect(found).To(Equal(false))
+ })
+ It("should return the gitlab response", func() {
+ Expect(response).ToNot(BeNil())
+ })
+ It("should return nil for the group list", func() {
+ Expect(groups).To(BeNil())
+ })
+ It("should not return an error", func() {
+ Expect(err).To(BeNil())
+ })
+ })
+})
+var _ = Describe("createGroup", func() {
+ expectedGroup := &gitlab.Group{ID: 1, Name: "A test group"}
+ expectedResponse := &gitlab.Response{
+ Response: &http.Response{},
+ TotalItems: 1,
+ TotalPages: 1,
+ ItemsPerPage: 10,
+ CurrentPage: 1,
+ NextPage: 0,
+ PreviousPage: 0,
+ }
+ sut := GroupReconciler{
+ gitlabClient: &MockGitlabClient{
+ createGroupFunction: func(name string, description string) (*gitlab.Group, *gitlab.Response, error) {
+ return expectedGroup, expectedResponse, nil
+ },
+ },
+ }
+ group, response, err := sut.createGroup(
+ &gitlabv1alpha1.Group{
+ ObjectMeta: ctrl.ObjectMeta{Annotations: make(map[string]string)},
+ Spec: gitlabv1alpha1.GroupSpec{Name: "a group"},
+ })
+ It("should return the gitlab group created", func() {
+ Expect(group).To(Equal(expectedGroup))
+ })
+ It("should return the gitlab response", func() {
+ Expect(response).To(Equal(expectedResponse))
+ })
+ It("should return the error created by the call, or nil", func() {
+ Expect(err).To(BeNil())
+ })
+})
+
+var _ = Describe("updateGroup", func() {
+ expectedGroup := &gitlab.Group{ID: 2, Name: "A test group"}
+ expectedResponse := &gitlab.Response{
+ Response: &http.Response{},
+ TotalItems: 1,
+ TotalPages: 1,
+ ItemsPerPage: 10,
+ CurrentPage: 1,
+ NextPage: 0,
+ PreviousPage: 0,
+ }
+ sut := GroupReconciler{
+ gitlabClient: &MockGitlabClient{
+ updateGroupFunction: func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
+ return expectedGroup, expectedResponse, nil
+ },
+ listGroupsByNameFunction: func(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ return []*gitlab.Group{{Name: "a group"}}, &gitlab.Response{}, nil
+ },
+ },
+ }
+ group, response, err := sut.updateGroup(
+ &gitlabv1alpha1.Group{
+ ObjectMeta: ctrl.ObjectMeta{Annotations: make(map[string]string)},
+ Spec: gitlabv1alpha1.GroupSpec{Name: "a group"},
+ Status: gitlabv1alpha1.GroupStatus{
+ GitlabID: nil,
+ CreatedTime: metav1.Time{},
+ LastUpdatedTime: metav1.Time{},
+ State: "",
+ },
+ })
+ It("should return the gitlab group created", func() {
+ Expect(group).To(Equal(expectedGroup))
+ })
+ It("should return the gitlab response", func() {
+ Expect(response).To(Equal(expectedResponse))
+ })
+ It("should return the error created by the call, or nil", func() {
+ Expect(err).To(BeNil())
+ })
+})
+
+var _ = Describe("SetupWithManager", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ loggerMock := MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ }}}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: &loggerMock,
+ Scheme: scheme,
+ }
+ err := sut.SetupWithManager(&MockManager{
+ Log: &loggerMock,
+ builder: builder,
+ })
+ It("should setup the default gitlab client", func() {
+ Expect(sut.gitlabClient).To(BeAssignableToTypeOf(&ClientImpl{}))
+ })
+ It("should return no error", func() {
+ Expect(err).To(BeNil())
+ })
+})
+
+var _ = Describe("updateStatus", func() {
+ When("group id is not 0", func() {
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ loggerMock := MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ }}}
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: &loggerMock,
+ Scheme: scheme,
+ }
+ group := gitlabv1alpha1.Group{Status: gitlabv1alpha1.GroupStatus{
+ GitlabID: nil,
+ CreatedTime: metav1.Time{},
+ LastUpdatedTime: metav1.Time{},
+ State: "",
+ }}
+ sut.updateStatus(&MockContext{}, 1, &group)
+
+ It("should update the gitlab id", func() {
+ Expect(*group.Status.GitlabID).To(Equal(int64(1)))
+ })
+ It("should update the last updated time", func() {
+ Expect(group.Status.LastUpdatedTime.Time).To(Not(BeNil()))
+ })
+ })
+})
+
+var _ = Describe("updateProject", func() {
+ spec := gitlabv1alpha1.ProjectSpec{
+ Name: "a project",
+ Path: "https://example.com.path",
+ ImpactLevel: "2",
+ StorageTypes: nil,
+ VirtualService: "default",
+ ServicePort: 8081,
+ Language: "golang",
+ }
+ project := gitlabv1alpha1.Project{Spec: gitlabv1alpha1.ProjectSpec{}}
+ builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{})
+ scheme, _ := builder.Build()
+ loggerMock := MockLogger{
+ WithValuesKeysAndValues: nil,
+ WithValuesCalled: false,
+ WithNameValue: "",
+ WithNameCalled: false,
+ }
+ mockError := &MockError{"true"}
+ clientMock := MockClient{
+ statusWriter: MockStatusWriter{
+ updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return nil
+ },
+ },
+ updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return mockError
+ },
+ }
+ sut := GroupReconciler{
+ Client: &clientMock,
+ Log: &loggerMock,
+ Scheme: scheme,
+ }
+
+ returnedProject, err := sut.updateProject(context.TODO(), spec, &project)
+ It("should update the project from the project specification", func() {
+ Expect(project.Spec.Name).To(Equal(spec.Name))
+ Expect(project.Spec.ServicePort).To(Equal(spec.ServicePort))
+ Expect(project.Spec.Language).To(Equal(spec.Language))
+ Expect(project.Spec.Path).To(Equal(spec.Path))
+ Expect(project.Spec.VirtualService).To(Equal(spec.VirtualService))
+ Expect(project.Spec.StorageTypes).To(Equal(spec.StorageTypes))
+ Expect(project.Spec.ImpactLevel).To(Equal(spec.ImpactLevel))
+ })
+ It("should call the kubernetes client update function", func() {
+ Expect(clientMock.updateFunctionCalled).To(BeTrue())
+ })
+ It("should return the result of the update function", func() {
+ Expect(err).To(Equal(mockError))
+ })
+ It("should return the updated project", func() {
+ Expect(project).To(Equal(*returnedProject))
+ })
+})
diff --git a/controllers/gitlab/mocks_test.go b/controllers/gitlab/mocks_test.go
index ecca40c9d36b295f6b2d2546b9c4c31fde1a9d62..1716f5dd15337006e9907a76d7d0dcd57707e41e 100755
--- a/controllers/gitlab/mocks_test.go
+++ b/controllers/gitlab/mocks_test.go
@@ -1,424 +1,423 @@
-package gitlab
-
-import (
- "context"
- "github.com/go-logr/logr"
- "github.com/jinzhu/copier"
- "github.com/xanzy/go-gitlab"
- "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/api/meta"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/client-go/rest"
- "k8s.io/client-go/tools/record"
- "net/http"
- "sigs.k8s.io/controller-runtime/pkg/cache"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/healthz"
- "sigs.k8s.io/controller-runtime/pkg/log/zap"
- "sigs.k8s.io/controller-runtime/pkg/manager"
- "sigs.k8s.io/controller-runtime/pkg/scheme"
- "sigs.k8s.io/controller-runtime/pkg/webhook"
- "time"
- "valkyrie.dso.mil/valkyrie-api/controllers"
-)
-
-type MockClient struct {
- GetFunction func(ctx context.Context, key client.ObjectKey, obj client.Object) error
- GetCalled bool
- expectedObjects map[client.ObjectKey]client.Object
- NotFoundError error
- statusWriter client.StatusWriter
- createFunction func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error
- updateFunction func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error
- updateFunctionCalled bool
-}
-
-func (m *MockClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
- m.GetCalled = true
- if m.GetFunction != nil {
- return m.GetFunction(ctx, key, obj)
- }
-
- if m.expectedObjects == nil {
- return nil
- }
-
- if m.expectedObjects[key] == nil {
- return &errors.StatusError{
- ErrStatus: metav1.Status{
- TypeMeta: metav1.TypeMeta{},
- ListMeta: metav1.ListMeta{},
- Status: string(metav1.StatusReasonNotFound),
- Message: "NotFound",
- Reason: metav1.StatusReasonNotFound,
- Details: nil,
- Code: 0,
- },
- }
- }
-
- foundObject := m.expectedObjects[key]
-
- copier.Copy(obj, foundObject)
-
- return nil
-}
-
-func (m *MockClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
- panic("implement me")
-}
-
-func (m *MockClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
- if m.createFunction == nil {
- return nil
- }
- return m.createFunction(ctx, obj, opts...)
-}
-
-func (m *MockClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
- panic("implement me")
-}
-
-func (m *MockClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- m.updateFunctionCalled = true
- if m.updateFunction == nil {
- return nil
- }
- return m.updateFunction(ctx, obj, opts...)
-}
-
-func (m *MockClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
- panic("implement me")
-}
-
-func (m *MockClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
- panic("implement me")
-}
-
-type MockStatusWriter struct {
- updateFunction func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error
-}
-
-func (m MockStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return m.updateFunction(ctx, obj, opts...)
-}
-
-func (m MockStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
- panic("implement me")
-}
-
-func (m *MockClient) Status() client.StatusWriter {
- return m.statusWriter
-}
-
-func (m *MockClient) Scheme() *runtime.Scheme {
- panic("implement me")
-}
-
-func (m *MockClient) RESTMapper() meta.RESTMapper {
- panic("implement me")
-}
-
-type MockContext struct {
-}
-
-func (m *MockContext) Deadline() (deadline time.Time, ok bool) {
- panic("implement me")
-}
-
-func (m *MockContext) Done() <-chan struct{} {
- panic("implement me")
-}
-
-func (m *MockContext) Err() error {
- panic("implement me")
-}
-
-func (m *MockContext) Value(key interface{}) interface{} {
- panic("implement me")
-}
-
-type MockLogger struct {
- WithValuesKeysAndValues []interface{}
- WithValuesCalled bool
- WithNameValue string
- WithNameCalled bool
- loggedMessage string
- keysAndValues []interface{}
- logFunction func(msg string, keysAndValues ...interface{})
- logLevelCalled string
- level int
-}
-
-func (m *MockLogger) Enabled() bool {
- return true
-}
-
-func (m *MockLogger) Info(msg string, keysAndValues ...interface{}) {
- m.loggedMessage = msg
- m.keysAndValues = keysAndValues
- m.logLevelCalled = "Info"
- if m.logFunction != nil {
- m.logFunction(msg, keysAndValues)
- return
- }
-}
-
-func (m *MockLogger) Error(err error, msg string, keysAndValues ...interface{}) {
- m.loggedMessage = msg
- m.keysAndValues = keysAndValues
- m.logLevelCalled = "Error"
- if m.logFunction != nil {
- m.logFunction(msg, keysAndValues)
- return
- }
-}
-
-func (m *MockLogger) V(level int) logr.Logger {
- m.level = level
- return m
-}
-
-func (m *MockLogger) WithValues(keysAndValues ...interface{}) logr.Logger {
- m.WithValuesCalled = true
- for i := 0; i < len(keysAndValues); i++ {
- m.WithValuesKeysAndValues = append(m.WithValuesKeysAndValues, keysAndValues[i])
- }
- m.WithValuesKeysAndValues = append(m.WithValuesKeysAndValues, keysAndValues)
-
- return m
-}
-
-func (m *MockLogger) WithName(name string) logr.Logger {
- m.WithNameCalled = true
- m.WithNameValue = name
- return m
-}
-
-type MockController struct {
- setupWithManagerWasCalled bool
-}
-
-func (m *MockController) SetupWithManager(manager manager.Manager) error {
- m.setupWithManagerWasCalled = true
- return nil
-}
-
-type MockManager struct {
- Log logr.Logger
- addHealthzCheckFunction func(name string, check healthz.Checker) error
- addHealthzCheckWasCalled bool
- addReadyzCheckFunction func(name string, check healthz.Checker) error
- addReadyzCheckWasCalled bool
- startFunction func(ctx context.Context) error
- startWasCalled bool
- builder *scheme.Builder
- Fields []interface{}
- runnable manager.Runnable
-}
-
-func (m *MockManager) Add(runnable manager.Runnable) error {
- m.runnable = runnable
-
- return nil
-}
-
-func (m *MockManager) Elected() <-chan struct{} {
- panic("implement me")
-}
-
-func (m *MockManager) SetFields(i interface{}) error {
- if m.Fields == nil {
- m.Fields = make([]interface{}, 0)
- }
- m.Fields = append(m.Fields, i)
-
- return nil
-}
-
-func (m *MockManager) AddMetricsExtraHandler(path string, handler http.Handler) error {
- panic("implement me")
-}
-
-func (m *MockManager) AddHealthzCheck(name string, check healthz.Checker) error {
- m.addHealthzCheckWasCalled = true
- if m.addHealthzCheckFunction == nil {
- return nil
- }
- return m.addHealthzCheckFunction(name, check)
-}
-
-func (m *MockManager) AddReadyzCheck(name string, check healthz.Checker) error {
- m.addReadyzCheckWasCalled = true
- if m.addReadyzCheckFunction == nil {
- return nil
- }
-
- return m.addReadyzCheckFunction(name, check)
-}
-
-func (m *MockManager) Start(ctx context.Context) error {
- m.startWasCalled = true
- if m.startFunction == nil {
- return nil
- }
- return m.startFunction(ctx)
-}
-
-func (m *MockManager) GetConfig() *rest.Config {
- return &rest.Config{}
-}
-
-func (m *MockManager) GetScheme() *runtime.Scheme {
- scheme, _ := m.builder.Build()
- return scheme
-}
-
-func (m *MockManager) GetClient() client.Client {
- return nil
-}
-
-func (m *MockManager) GetFieldIndexer() client.FieldIndexer {
- panic("implement me")
-}
-
-func (m *MockManager) GetCache() cache.Cache {
- panic("implement me")
-}
-
-func (m *MockManager) GetEventRecorderFor(name string) record.EventRecorder {
- panic("implement me")
-}
-
-func (m *MockManager) GetRESTMapper() meta.RESTMapper {
- panic("implement me")
-}
-
-func (m *MockManager) GetAPIReader() client.Reader {
- panic("implement me")
-}
-
-func (m *MockManager) GetWebhookServer() *webhook.Server {
- panic("implement me")
-}
-
-func (m *MockManager) GetLogger() logr.Logger {
- return m.Log
-}
-
-type MockRunFunctionParameters struct {
- options zap.Options
- metricsAddress string
- healthProbeAddress string
- enableLeaderElection bool
-}
-
-type MockDriver struct {
- parseCommandLineCalled bool
- parseCommandLineFunction func() (string, bool, string, zap.Options, error)
- runCalled bool
- runFunction func(opts zap.Options, metricsAddress string, healthProbeAddress string, enableLeaderElection bool) (int, error)
- runFunctionParameters MockRunFunctionParameters
- newManagerCalled bool
- newManagerFunction func(metricsAddress string, healthProbeAddress string, enableLeaderElection bool) (manager.Manager, error)
- instantiateControllersCalled bool
- instantiateControllersFunction func(mgr manager.Manager) []controllers.ManagedController
- setupControllerWithManagerCalled bool
- setupControllersFunction func(controller controllers.ManagedController, manager manager.Manager) error
-}
-
-func (m *MockDriver) parseCommandLine() (string, bool, string, zap.Options, error) {
- m.parseCommandLineCalled = true
- if m.parseCommandLineFunction == nil {
- return "", true, "", zap.Options{}, nil
- }
-
- return m.parseCommandLineFunction()
-}
-
-func (m *MockDriver) run(opts zap.Options, metricsAddress string, healthProbeAddress string, enableLeaderElection bool) (int, error) {
- m.runCalled = true
- m.runFunctionParameters = MockRunFunctionParameters{
- options: opts,
- metricsAddress: metricsAddress,
- healthProbeAddress: healthProbeAddress,
- enableLeaderElection: enableLeaderElection,
- }
- if m.runFunction == nil {
- return 0, nil
- }
-
- return m.runFunction(opts, metricsAddress, healthProbeAddress, enableLeaderElection)
-}
-
-func (m *MockDriver) newManager(metricsAddress string, healthProbeAddress string, enableLeaderElection bool) (manager.Manager, error) {
- m.newManagerCalled = true
- if m.newManagerFunction == nil {
- return &MockManager{}, nil
- }
-
- return m.newManagerFunction(metricsAddress, healthProbeAddress, enableLeaderElection)
-}
-
-func (m *MockDriver) instantiateControllers(mgr manager.Manager) []controllers.ManagedController {
- m.instantiateControllersCalled = true
-
- if m.instantiateControllersFunction == nil {
- return []controllers.ManagedController{
- &MockController{},
- }
- }
-
- return m.instantiateControllersFunction(mgr)
-}
-
-func (m *MockDriver) setupControllerWithManager(controller controllers.ManagedController, manager manager.Manager) error {
- m.setupControllerWithManagerCalled = true
-
- if m.setupControllersFunction == nil {
- return nil
- }
-
- return m.setupControllersFunction(controller, manager)
-}
-
-type MockError struct {
- message string
-}
-
-func (m *MockError) Error() string {
- if m.message == "" {
- m.message = "mock Error"
- }
- return m.message
-}
-
-type MockGitlabClient struct {
- newClientFunction func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error)
- listGroupsFunction func(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error)
- listGroupsByNameFunction func(name string) ([]*gitlab.Group, *gitlab.Response, error)
- createGroupFunction func(name string, description string) (*gitlab.Group, *gitlab.Response, error)
- updateGroupFunction func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error)
-
-}
-
-func (m *MockGitlabClient) CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error) {
- return m.createGroupFunction(name, description)
-}
-
-func (m *MockGitlabClient) UpdateGroup(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
- return m.updateGroupFunction(id, name, description)
-}
-
-func (m *MockGitlabClient) ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error) {
- return m.listGroupsByNameFunction(name)
-}
-
-func (m *MockGitlabClient) NewClient(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
- return m.newClientFunction(token, options...)
-}
-
-func (m *MockGitlabClient) ListGroups(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error) {
- return m.listGroupsFunction(opt, options...)
-}
+package gitlab
+
+import (
+ "context"
+ "github.com/go-logr/logr"
+ "github.com/jinzhu/copier"
+ "github.com/xanzy/go-gitlab"
+ "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/record"
+ "net/http"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/healthz"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+ "time"
+ "valkyrie.dso.mil/valkyrie-api/controllers"
+)
+
+type MockClient struct {
+ GetFunction func(ctx context.Context, key client.ObjectKey, obj client.Object) error
+ GetCalled bool
+ expectedObjects map[client.ObjectKey]client.Object
+ NotFoundError error
+ statusWriter client.StatusWriter
+ createFunction func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error
+ updateFunction func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error
+ updateFunctionCalled bool
+}
+
+func (m *MockClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
+ m.GetCalled = true
+ if m.GetFunction != nil {
+ return m.GetFunction(ctx, key, obj)
+ }
+
+ if m.expectedObjects == nil {
+ return nil
+ }
+
+ if m.expectedObjects[key] == nil {
+ return &errors.StatusError{
+ ErrStatus: metav1.Status{
+ TypeMeta: metav1.TypeMeta{},
+ ListMeta: metav1.ListMeta{},
+ Status: string(metav1.StatusReasonNotFound),
+ Message: "NotFound",
+ Reason: metav1.StatusReasonNotFound,
+ Details: nil,
+ Code: 0,
+ },
+ }
+ }
+
+ foundObject := m.expectedObjects[key]
+
+ copier.Copy(obj, foundObject)
+
+ return nil
+}
+
+func (m *MockClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
+ panic("implement me")
+}
+
+func (m *MockClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
+ if m.createFunction == nil {
+ return nil
+ }
+ return m.createFunction(ctx, obj, opts...)
+}
+
+func (m *MockClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
+ panic("implement me")
+}
+
+func (m *MockClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ m.updateFunctionCalled = true
+ if m.updateFunction == nil {
+ return nil
+ }
+ return m.updateFunction(ctx, obj, opts...)
+}
+
+func (m *MockClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+ panic("implement me")
+}
+
+func (m *MockClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
+ panic("implement me")
+}
+
+type MockStatusWriter struct {
+ updateFunction func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error
+}
+
+func (m MockStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
+ return m.updateFunction(ctx, obj, opts...)
+}
+
+func (m MockStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
+ panic("implement me")
+}
+
+func (m *MockClient) Status() client.StatusWriter {
+ return m.statusWriter
+}
+
+func (m *MockClient) Scheme() *runtime.Scheme {
+ panic("implement me")
+}
+
+func (m *MockClient) RESTMapper() meta.RESTMapper {
+ panic("implement me")
+}
+
+type MockContext struct {
+}
+
+func (m *MockContext) Deadline() (deadline time.Time, ok bool) {
+ panic("implement me")
+}
+
+func (m *MockContext) Done() <-chan struct{} {
+ panic("implement me")
+}
+
+func (m *MockContext) Err() error {
+ panic("implement me")
+}
+
+func (m *MockContext) Value(key interface{}) interface{} {
+ panic("implement me")
+}
+
+type MockLogger struct {
+ WithValuesKeysAndValues []interface{}
+ WithValuesCalled bool
+ WithNameValue string
+ WithNameCalled bool
+ loggedMessage string
+ keysAndValues []interface{}
+ logFunction func(msg string, keysAndValues ...interface{})
+ logLevelCalled string
+ level int
+}
+
+func (m *MockLogger) Enabled() bool {
+ return true
+}
+
+func (m *MockLogger) Info(msg string, keysAndValues ...interface{}) {
+ m.loggedMessage = msg
+ m.keysAndValues = keysAndValues
+ m.logLevelCalled = "Info"
+ if m.logFunction != nil {
+ m.logFunction(msg, keysAndValues)
+ return
+ }
+}
+
+func (m *MockLogger) Error(err error, msg string, keysAndValues ...interface{}) {
+ m.loggedMessage = msg
+ m.keysAndValues = keysAndValues
+ m.logLevelCalled = "Error"
+ if m.logFunction != nil {
+ m.logFunction(msg, keysAndValues)
+ return
+ }
+}
+
+func (m *MockLogger) V(level int) logr.Logger {
+ m.level = level
+ return m
+}
+
+func (m *MockLogger) WithValues(keysAndValues ...interface{}) logr.Logger {
+ m.WithValuesCalled = true
+ for i := 0; i < len(keysAndValues); i++ {
+ m.WithValuesKeysAndValues = append(m.WithValuesKeysAndValues, keysAndValues[i])
+ }
+ m.WithValuesKeysAndValues = append(m.WithValuesKeysAndValues, keysAndValues)
+
+ return m
+}
+
+func (m *MockLogger) WithName(name string) logr.Logger {
+ m.WithNameCalled = true
+ m.WithNameValue = name
+ return m
+}
+
+type MockController struct {
+ setupWithManagerWasCalled bool
+}
+
+func (m *MockController) SetupWithManager(manager manager.Manager) error {
+ m.setupWithManagerWasCalled = true
+ return nil
+}
+
+type MockManager struct {
+ Log logr.Logger
+ addHealthzCheckFunction func(name string, check healthz.Checker) error
+ addHealthzCheckWasCalled bool
+ addReadyzCheckFunction func(name string, check healthz.Checker) error
+ addReadyzCheckWasCalled bool
+ startFunction func(ctx context.Context) error
+ startWasCalled bool
+ builder *scheme.Builder
+ Fields []interface{}
+ runnable manager.Runnable
+}
+
+func (m *MockManager) Add(runnable manager.Runnable) error {
+ m.runnable = runnable
+
+ return nil
+}
+
+func (m *MockManager) Elected() <-chan struct{} {
+ panic("implement me")
+}
+
+func (m *MockManager) SetFields(i interface{}) error {
+ if m.Fields == nil {
+ m.Fields = make([]interface{}, 0)
+ }
+ m.Fields = append(m.Fields, i)
+
+ return nil
+}
+
+func (m *MockManager) AddMetricsExtraHandler(path string, handler http.Handler) error {
+ panic("implement me")
+}
+
+func (m *MockManager) AddHealthzCheck(name string, check healthz.Checker) error {
+ m.addHealthzCheckWasCalled = true
+ if m.addHealthzCheckFunction == nil {
+ return nil
+ }
+ return m.addHealthzCheckFunction(name, check)
+}
+
+func (m *MockManager) AddReadyzCheck(name string, check healthz.Checker) error {
+ m.addReadyzCheckWasCalled = true
+ if m.addReadyzCheckFunction == nil {
+ return nil
+ }
+
+ return m.addReadyzCheckFunction(name, check)
+}
+
+func (m *MockManager) Start(ctx context.Context) error {
+ m.startWasCalled = true
+ if m.startFunction == nil {
+ return nil
+ }
+ return m.startFunction(ctx)
+}
+
+func (m *MockManager) GetConfig() *rest.Config {
+ return &rest.Config{}
+}
+
+func (m *MockManager) GetScheme() *runtime.Scheme {
+ scheme, _ := m.builder.Build()
+ return scheme
+}
+
+func (m *MockManager) GetClient() client.Client {
+ return nil
+}
+
+func (m *MockManager) GetFieldIndexer() client.FieldIndexer {
+ panic("implement me")
+}
+
+func (m *MockManager) GetCache() cache.Cache {
+ panic("implement me")
+}
+
+func (m *MockManager) GetEventRecorderFor(name string) record.EventRecorder {
+ panic("implement me")
+}
+
+func (m *MockManager) GetRESTMapper() meta.RESTMapper {
+ panic("implement me")
+}
+
+func (m *MockManager) GetAPIReader() client.Reader {
+ panic("implement me")
+}
+
+func (m *MockManager) GetWebhookServer() *webhook.Server {
+ panic("implement me")
+}
+
+func (m *MockManager) GetLogger() logr.Logger {
+ return m.Log
+}
+
+type MockRunFunctionParameters struct {
+ options zap.Options
+ metricsAddress string
+ healthProbeAddress string
+ enableLeaderElection bool
+}
+
+type MockDriver struct {
+ parseCommandLineCalled bool
+ parseCommandLineFunction func() (string, bool, string, zap.Options, error)
+ runCalled bool
+ runFunction func(opts zap.Options, metricsAddress string, healthProbeAddress string, enableLeaderElection bool) (int, error)
+ runFunctionParameters MockRunFunctionParameters
+ newManagerCalled bool
+ newManagerFunction func(metricsAddress string, healthProbeAddress string, enableLeaderElection bool) (manager.Manager, error)
+ instantiateControllersCalled bool
+ instantiateControllersFunction func(mgr manager.Manager) []controllers.ManagedController
+ setupControllerWithManagerCalled bool
+ setupControllersFunction func(controller controllers.ManagedController, manager manager.Manager) error
+}
+
+func (m *MockDriver) parseCommandLine() (string, bool, string, zap.Options, error) {
+ m.parseCommandLineCalled = true
+ if m.parseCommandLineFunction == nil {
+ return "", true, "", zap.Options{}, nil
+ }
+
+ return m.parseCommandLineFunction()
+}
+
+func (m *MockDriver) run(opts zap.Options, metricsAddress string, healthProbeAddress string, enableLeaderElection bool) (int, error) {
+ m.runCalled = true
+ m.runFunctionParameters = MockRunFunctionParameters{
+ options: opts,
+ metricsAddress: metricsAddress,
+ healthProbeAddress: healthProbeAddress,
+ enableLeaderElection: enableLeaderElection,
+ }
+ if m.runFunction == nil {
+ return 0, nil
+ }
+
+ return m.runFunction(opts, metricsAddress, healthProbeAddress, enableLeaderElection)
+}
+
+func (m *MockDriver) newManager(metricsAddress string, healthProbeAddress string, enableLeaderElection bool) (manager.Manager, error) {
+ m.newManagerCalled = true
+ if m.newManagerFunction == nil {
+ return &MockManager{}, nil
+ }
+
+ return m.newManagerFunction(metricsAddress, healthProbeAddress, enableLeaderElection)
+}
+
+func (m *MockDriver) instantiateControllers(mgr manager.Manager) []controllers.ManagedController {
+ m.instantiateControllersCalled = true
+
+ if m.instantiateControllersFunction == nil {
+ return []controllers.ManagedController{
+ &MockController{},
+ }
+ }
+
+ return m.instantiateControllersFunction(mgr)
+}
+
+func (m *MockDriver) setupControllerWithManager(controller controllers.ManagedController, manager manager.Manager) error {
+ m.setupControllerWithManagerCalled = true
+
+ if m.setupControllersFunction == nil {
+ return nil
+ }
+
+ return m.setupControllersFunction(controller, manager)
+}
+
+type MockError struct {
+ message string
+}
+
+func (m *MockError) Error() string {
+ if m.message == "" {
+ m.message = "mock Error"
+ }
+ return m.message
+}
+
+type MockGitlabClient struct {
+ newClientFunction func(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error)
+ listGroupsFunction func(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error)
+ listGroupsByNameFunction func(name string) ([]*gitlab.Group, *gitlab.Response, error)
+ createGroupFunction func(name string, description string) (*gitlab.Group, *gitlab.Response, error)
+ updateGroupFunction func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error)
+}
+
+func (m *MockGitlabClient) CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error) {
+ return m.createGroupFunction(name, description)
+}
+
+func (m *MockGitlabClient) UpdateGroup(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) {
+ return m.updateGroupFunction(id, name, description)
+}
+
+func (m *MockGitlabClient) ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error) {
+ return m.listGroupsByNameFunction(name)
+}
+
+func (m *MockGitlabClient) NewClient(token string, options ...gitlab.ClientOptionFunc) (*gitlab.Client, error) {
+ return m.newClientFunction(token, options...)
+}
+
+func (m *MockGitlabClient) ListGroups(opt *gitlab.ListGroupsOptions, options ...gitlab.RequestOptionFunc) ([]*gitlab.Group, *gitlab.Response, error) {
+ return m.listGroupsFunction(opt, options...)
+}
diff --git a/go.mod b/go.mod
index 57c0834aa0436795d35c9b55671ed58b3b2d6b40..3f509c0d0d6bb38d43179bea8f3de710e066a3ca 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,7 @@ require (
github.com/jinzhu/copier v0.3.2
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.13.0
+ github.com/romana/rlog v0.0.0-20171115192701-f018bc92e7d7
github.com/xanzy/go-gitlab v0.50.0
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
diff --git a/go.sum b/go.sum
index 47ea8a2f47d1435fb74ed2d37e160316db763cca..f0aca23368a0a780adb73faa50bb2e598062fe22 100644
--- a/go.sum
+++ b/go.sum
@@ -42,10 +42,8 @@ github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdko
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
@@ -161,6 +159,7 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@@ -345,6 +344,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/romana/rlog v0.0.0-20171115192701-f018bc92e7d7 h1:jkvpcEatpwuMF5O5LVxTnehj6YZ/aEZN4NWD/Xml4pI=
+github.com/romana/rlog v0.0.0-20171115192701-f018bc92e7d7/go.mod h1:KTrHyWpO1sevuXPZwyeZc72ddWRFqNSKDFl7uVWKpg0=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
diff --git a/integration-tests/gitlab/api/gitlab_api_adhoc_test.go b/integration-tests/gitlab/api/gitlab_api_adhoc_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..c3f4cca5041e28fecce8ae197588668bafbdb46a
--- /dev/null
+++ b/integration-tests/gitlab/api/gitlab_api_adhoc_test.go
@@ -0,0 +1,139 @@
+// +build integration
+
+package integration
+
+import (
+ "testing"
+ "errors"
+ "os"
+ gitlab "valkyrie.dso.mil/valkyrie-api/clients/gitlab"
+)
+
+// getClient_AdHoc -
+func getClient_AdHoc() (gitlab.Client, error) {
+ gitlabAPIURL, ok := os.LookupEnv("GITLAB_API_URL")
+ if !ok {
+ return gitlab.Client{}, errors.New("env variable GITLAB_API_URL undefinded")
+ }
+ gitlabAPIToken, ok := os.LookupEnv("GITLAB_API_TOKEN")
+ if !ok {
+ return gitlab.Client{}, errors.New("env variable GITLAB_API_TOKEN undefinded")
+ }
+ var client = gitlab.NewClient(gitlabAPIURL, gitlabAPIToken,nil)
+ return client, nil
+}
+func TestClient_AdHoc_getUsers(t *testing.T) {
+ t.Run("test", func(t *testing.T) {
+ c, err := getClient_AdHoc()
+ if err != nil {
+ t.Errorf("Client.GetUsers() error = %v", err)
+ return
+ }
+ got, err := c.GetUsers(nil)
+ if err != nil {
+ t.Errorf("Client.GetUsers() error = %v", err)
+ return
+ }
+ t.Logf("GetUsers %d", len(got))
+ for x:=0;x