File: credentials_resolver_test.go

package info (click to toggle)
gitlab-ci-multi-runner 14.10.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 31,248 kB
  • sloc: sh: 1,694; makefile: 384; asm: 79; ruby: 68
file content (163 lines) | stat: -rw-r--r-- 4,910 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//go:build !integration
// +build !integration

package gcs

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"gitlab.com/gitlab-org/gitlab-runner/common"
)

var accessID2 = "test-access-id-2@X.iam.gserviceaccount.com"

type credentialsResolverTestCase struct {
	config                         *common.CacheGCSConfig
	credentialsFileContent         *credentialsFile
	credentialsFileDoesNotExist    bool
	credentialsFileWithInvalidJSON bool
	errorExpectedOnInitialization  bool
	errorExpectedOnResolve         bool
	expectedCredentials            *common.CacheGCSCredentials
}

func prepareStubbedCredentialsFile(t *testing.T, testCase credentialsResolverTestCase) func() {
	cleanup := func() {}

	if testCase.credentialsFileContent != nil {
		file, err := ioutil.TempFile("", "gcp-credentials-file")
		require.NoError(t, err)

		cleanup = func() {
			os.Remove(file.Name())
		}

		testCase.config.CredentialsFile = file.Name()

		switch {
		case testCase.credentialsFileDoesNotExist:
			os.Remove(file.Name())
		case testCase.credentialsFileWithInvalidJSON:
			_, err = file.Write([]byte("a"))
			require.NoError(t, err)

			err = file.Close()
			require.NoError(t, err)
		default:
			data, err := json.Marshal(testCase.credentialsFileContent)
			require.NoError(t, err)

			_, err = file.Write(data)
			require.NoError(t, err)

			err = file.Close()
			require.NoError(t, err)
		}
	}

	return cleanup
}

func getCredentialsConfig(accessID string, privateKey string) *common.CacheGCSConfig {
	return &common.CacheGCSConfig{
		CacheGCSCredentials: common.CacheGCSCredentials{
			AccessID:   accessID,
			PrivateKey: privateKey,
		},
	}
}

func getCredentialsFileContent(fileType string, clientEmail string, privateKey string) *credentialsFile {
	return &credentialsFile{
		Type:        fileType,
		ClientEmail: clientEmail,
		PrivateKey:  privateKey,
	}
}

func getExpectedCredentials(accessID string, privateKey string) *common.CacheGCSCredentials {
	return &common.CacheGCSCredentials{
		AccessID:   accessID,
		PrivateKey: privateKey,
	}
}

func TestDefaultCredentialsResolver(t *testing.T) {
	cases := map[string]credentialsResolverTestCase{
		"config is nil": {
			config:                        nil,
			credentialsFileContent:        nil,
			errorExpectedOnInitialization: true,
		},
		"credentials not set": {
			config:                 &common.CacheGCSConfig{},
			errorExpectedOnResolve: true,
		},
		"credentials direct in config": {
			config:                 getCredentialsConfig(accessID, privateKey),
			errorExpectedOnResolve: false,
			expectedCredentials:    getExpectedCredentials(accessID, privateKey),
		},
		"credentials in credentials file - service account file": {
			config:                 &common.CacheGCSConfig{},
			credentialsFileContent: getCredentialsFileContent(TypeServiceAccount, accessID, privateKey),
			errorExpectedOnResolve: false,
			expectedCredentials:    getExpectedCredentials(accessID, privateKey),
		},
		"credentials in credentials file - unsupported type credentials file": {
			config:                 &common.CacheGCSConfig{},
			credentialsFileContent: getCredentialsFileContent("unknown_type", "", ""),
			errorExpectedOnResolve: true,
		},
		"credentials in both places - credentials file takes precedence": {
			config:                 getCredentialsConfig(accessID, privateKey),
			credentialsFileContent: getCredentialsFileContent(TypeServiceAccount, accessID2, privateKey),
			errorExpectedOnResolve: false,
			expectedCredentials:    getExpectedCredentials(accessID2, privateKey),
		},
		"credentials in non-existing credentials file": {
			config:                      &common.CacheGCSConfig{},
			credentialsFileContent:      getCredentialsFileContent(TypeServiceAccount, accessID, privateKey),
			credentialsFileDoesNotExist: true,
			errorExpectedOnResolve:      true,
		},
		"credentials in credentials file - invalid JSON": {
			config:                         &common.CacheGCSConfig{},
			credentialsFileContent:         getCredentialsFileContent(TypeServiceAccount, accessID, privateKey),
			credentialsFileWithInvalidJSON: true,
			errorExpectedOnResolve:         true,
		},
	}

	for name, testCase := range cases {
		t.Run(name, func(t *testing.T) {
			cleanupCredentialsFileMock := prepareStubbedCredentialsFile(t, testCase)
			defer cleanupCredentialsFileMock()

			cr, err := newDefaultCredentialsResolver(testCase.config)

			if testCase.errorExpectedOnInitialization {
				assert.Error(t, err)
				return
			}

			require.NoError(t, err, "Error on resolver initialization is not expected")

			err = cr.Resolve()

			if testCase.errorExpectedOnResolve {
				assert.Error(t, err)
				return
			}

			require.NoError(t, err, "Error on credentials resolving is not expected")
			assert.Equal(t, testCase.expectedCredentials, cr.Credentials())
		})
	}
}