aboutsummaryrefslogtreecommitdiff
path: root/weed/credential/credential_test.go
blob: dd1449fa5d21b7fbf7965a54433c3b37d3eeed39 (plain)
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
package credential

import (
	"context"
	"testing"

	"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
	"github.com/seaweedfs/seaweedfs/weed/util"
)

func TestCredentialStoreInterface(t *testing.T) {
	// Note: This test may fail if run without importing store packages
	// For full integration testing, see the test/ package
	if len(Stores) == 0 {
		t.Skip("No credential stores registered - this is expected when testing the base package without store imports")
	}

	// Check that expected stores are available
	storeNames := GetAvailableStores()
	expectedStores := []string{string(StoreTypeFilerEtc), string(StoreTypeMemory)}

	// Add PostgreSQL if it's available (build tags dependent)
	for _, storeName := range storeNames {
		found := false
		for _, expected := range append(expectedStores, string(StoreTypePostgres)) {
			if string(storeName) == expected {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("Unexpected store found: %s", storeName)
		}
	}

	// Test that filer_etc store is always available
	filerEtcStoreFound := false
	memoryStoreFound := false
	for _, storeName := range storeNames {
		if string(storeName) == string(StoreTypeFilerEtc) {
			filerEtcStoreFound = true
		}
		if string(storeName) == string(StoreTypeMemory) {
			memoryStoreFound = true
		}
	}
	if !filerEtcStoreFound {
		t.Error("FilerEtc store should always be available")
	}
	if !memoryStoreFound {
		t.Error("Memory store should always be available")
	}
}

func TestCredentialManagerCreation(t *testing.T) {
	config := util.GetViper()

	// Test creating credential manager with invalid store
	_, err := NewCredentialManager(CredentialStoreTypeName("nonexistent"), config, "test.")
	if err == nil {
		t.Error("Expected error for nonexistent store")
	}

	// Skip store-specific tests if no stores are registered
	if len(Stores) == 0 {
		t.Skip("No credential stores registered - skipping store-specific tests")
	}

	// Test creating credential manager with available stores
	availableStores := GetAvailableStores()
	if len(availableStores) == 0 {
		t.Skip("No stores available for testing")
	}

	// Test with the first available store
	storeName := availableStores[0]
	cm, err := NewCredentialManager(storeName, config, "test.")
	if err != nil {
		t.Fatalf("Failed to create credential manager with store %s: %v", storeName, err)
	}
	if cm == nil {
		t.Error("Credential manager should not be nil")
	}
	defer cm.Shutdown()

	// Test that the store is of the correct type
	if cm.GetStore().GetName() != storeName {
		t.Errorf("Expected %s store, got %s", storeName, cm.GetStore().GetName())
	}
}

func TestCredentialInterface(t *testing.T) {
	// Skip if no stores are registered
	if len(Stores) == 0 {
		t.Skip("No credential stores registered - for full testing see test/ package")
	}

	// Test the interface with the first available store
	availableStores := GetAvailableStores()
	if len(availableStores) == 0 {
		t.Skip("No stores available for testing")
	}

	testCredentialInterfaceWithStore(t, availableStores[0])
}

func testCredentialInterfaceWithStore(t *testing.T, storeName CredentialStoreTypeName) {
	// Create a test identity
	testIdentity := &iam_pb.Identity{
		Name:    "testuser",
		Actions: []string{"Read", "Write"},
		Account: &iam_pb.Account{
			Id:           "123456789012",
			DisplayName:  "Test User",
			EmailAddress: "test@example.com",
		},
		Credentials: []*iam_pb.Credential{
			{
				AccessKey: "AKIAIOSFODNN7EXAMPLE",
				SecretKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
			},
		},
	}

	// Test the interface methods exist (compile-time check)
	config := util.GetViper()
	cm, err := NewCredentialManager(storeName, config, "test.")
	if err != nil {
		t.Fatalf("Failed to create credential manager: %v", err)
	}
	defer cm.Shutdown()

	ctx := context.Background()

	// Test LoadConfiguration
	_, err = cm.LoadConfiguration(ctx)
	if err != nil {
		t.Fatalf("LoadConfiguration failed: %v", err)
	}

	// Test CreateUser
	err = cm.CreateUser(ctx, testIdentity)
	if err != nil {
		t.Fatalf("CreateUser failed: %v", err)
	}

	// Test GetUser
	user, err := cm.GetUser(ctx, "testuser")
	if err != nil {
		t.Fatalf("GetUser failed: %v", err)
	}
	if user.Name != "testuser" {
		t.Errorf("Expected user name 'testuser', got %s", user.Name)
	}

	// Test ListUsers
	users, err := cm.ListUsers(ctx)
	if err != nil {
		t.Fatalf("ListUsers failed: %v", err)
	}
	if len(users) != 1 || users[0] != "testuser" {
		t.Errorf("Expected ['testuser'], got %v", users)
	}

	// Test GetUserByAccessKey
	userByKey, err := cm.GetUserByAccessKey(ctx, "AKIAIOSFODNN7EXAMPLE")
	if err != nil {
		t.Fatalf("GetUserByAccessKey failed: %v", err)
	}
	if userByKey.Name != "testuser" {
		t.Errorf("Expected user name 'testuser', got %s", userByKey.Name)
	}
}

func TestCredentialManagerIntegration(t *testing.T) {
	// Skip if no stores are registered
	if len(Stores) == 0 {
		t.Skip("No credential stores registered - for full testing see test/ package")
	}

	// Test with the first available store
	availableStores := GetAvailableStores()
	if len(availableStores) == 0 {
		t.Skip("No stores available for testing")
	}

	storeName := availableStores[0]
	config := util.GetViper()
	cm, err := NewCredentialManager(storeName, config, "test.")
	if err != nil {
		t.Fatalf("Failed to create credential manager: %v", err)
	}
	defer cm.Shutdown()

	ctx := context.Background()

	// Test complete workflow
	user1 := &iam_pb.Identity{
		Name:    "user1",
		Actions: []string{"Read"},
		Account: &iam_pb.Account{
			Id:           "111111111111",
			DisplayName:  "User One",
			EmailAddress: "user1@example.com",
		},
		Credentials: []*iam_pb.Credential{
			{
				AccessKey: "AKIAUSER1",
				SecretKey: "secret1",
			},
		},
	}

	user2 := &iam_pb.Identity{
		Name:    "user2",
		Actions: []string{"Write"},
		Account: &iam_pb.Account{
			Id:           "222222222222",
			DisplayName:  "User Two",
			EmailAddress: "user2@example.com",
		},
		Credentials: []*iam_pb.Credential{
			{
				AccessKey: "AKIAUSER2",
				SecretKey: "secret2",
			},
		},
	}

	// Create users
	err = cm.CreateUser(ctx, user1)
	if err != nil {
		t.Fatalf("Failed to create user1: %v", err)
	}

	err = cm.CreateUser(ctx, user2)
	if err != nil {
		t.Fatalf("Failed to create user2: %v", err)
	}

	// List users
	users, err := cm.ListUsers(ctx)
	if err != nil {
		t.Fatalf("Failed to list users: %v", err)
	}

	if len(users) != 2 {
		t.Errorf("Expected 2 users, got %d", len(users))
	}

	// Test access key lookup
	foundUser, err := cm.GetUserByAccessKey(ctx, "AKIAUSER1")
	if err != nil {
		t.Fatalf("Failed to get user by access key: %v", err)
	}
	if foundUser.Name != "user1" {
		t.Errorf("Expected user1, got %s", foundUser.Name)
	}

	// Delete user
	err = cm.DeleteUser(ctx, "user1")
	if err != nil {
		t.Fatalf("Failed to delete user: %v", err)
	}

	// Verify user is deleted
	_, err = cm.GetUser(ctx, "user1")
	if err != ErrUserNotFound {
		t.Errorf("Expected ErrUserNotFound, got %v", err)
	}

	// Clean up
	err = cm.DeleteUser(ctx, "user2")
	if err != nil {
		t.Fatalf("Failed to delete user2: %v", err)
	}
}

// TestErrorTypes tests that the custom error types are defined correctly
func TestErrorTypes(t *testing.T) {
	// Test that error types are defined
	if ErrUserNotFound == nil {
		t.Error("ErrUserNotFound should be defined")
	}
	if ErrUserAlreadyExists == nil {
		t.Error("ErrUserAlreadyExists should be defined")
	}
	if ErrAccessKeyNotFound == nil {
		t.Error("ErrAccessKeyNotFound should be defined")
	}

	// Test error messages
	if ErrUserNotFound.Error() != "user not found" {
		t.Errorf("Expected 'user not found', got '%s'", ErrUserNotFound.Error())
	}
	if ErrUserAlreadyExists.Error() != "user already exists" {
		t.Errorf("Expected 'user already exists', got '%s'", ErrUserAlreadyExists.Error())
	}
	if ErrAccessKeyNotFound.Error() != "access key not found" {
		t.Errorf("Expected 'access key not found', got '%s'", ErrAccessKeyNotFound.Error())
	}
}

// TestGetAvailableStores tests the store discovery function
func TestGetAvailableStores(t *testing.T) {
	stores := GetAvailableStores()
	if len(stores) == 0 {
		t.Skip("No stores available for testing")
	}

	// Convert to strings for comparison
	storeNames := make([]string, len(stores))
	for i, store := range stores {
		storeNames[i] = string(store)
	}

	t.Logf("Available stores: %v (count: %d)", storeNames, len(storeNames))

	// We expect at least memory and filer_etc stores to be available
	expectedStores := []string{string(StoreTypeFilerEtc), string(StoreTypeMemory)}

	// Add PostgreSQL if it's available (build tags dependent)
	for _, storeName := range storeNames {
		found := false
		for _, expected := range append(expectedStores, string(StoreTypePostgres)) {
			if storeName == expected {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("Unexpected store found: %s", storeName)
		}
	}

	// Test that filer_etc store is always available
	filerEtcStoreFound := false
	memoryStoreFound := false
	for _, storeName := range storeNames {
		if storeName == string(StoreTypeFilerEtc) {
			filerEtcStoreFound = true
		}
		if storeName == string(StoreTypeMemory) {
			memoryStoreFound = true
		}
	}
	if !filerEtcStoreFound {
		t.Error("FilerEtc store should always be available")
	}
	if !memoryStoreFound {
		t.Error("Memory store should always be available")
	}
}