Some checks failed
CI/CD Pipeline / Docker Build (push) Blocked by required conditions
Security Scan / Security Analysis (push) Waiting to run
Security Scan / Native Library Security (push) Waiting to run
Checkout test / test (push) Successful in 4s
CI/CD Pipeline / Test (push) Failing after 1s
CI/CD Pipeline / Dev Compose Smoke Test (push) Has been skipped
CI/CD Pipeline / Build (push) Has been skipped
CI/CD Pipeline / Test Scripts (push) Has been skipped
CI/CD Pipeline / Test Native Libraries (push) Has been skipped
Documentation / build-and-publish (push) Has been cancelled
176 lines
4.2 KiB
Go
176 lines
4.2 KiB
Go
package auth
|
|
|
|
import (
|
|
"os/exec"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/jfraeys/fetch_ml/internal/auth"
|
|
)
|
|
|
|
// isKeyringAvailable checks if dbus is available for keyring operations
|
|
func isKeyringAvailable() bool {
|
|
// Check if dbus-launch is available (Linux keyring requirement)
|
|
if _, err := exec.LookPath("dbus-launch"); err != nil {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func TestNewKeychainManager(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
km := auth.NewKeychainManager()
|
|
if km == nil {
|
|
t.Fatal("NewKeychainManager returned nil")
|
|
}
|
|
|
|
methods := km.ListAvailableMethods()
|
|
if len(methods) == 0 {
|
|
t.Error("Expected at least one available method")
|
|
}
|
|
}
|
|
|
|
func TestKeychainIsAvailable(t *testing.T) {
|
|
t.Parallel() // Enable parallel execution
|
|
|
|
km := auth.NewKeychainManager()
|
|
|
|
// IsAvailable should return a boolean without error
|
|
available := km.IsAvailable()
|
|
|
|
// We can't predict the result since it depends on the test environment,
|
|
// but it should not panic
|
|
t.Logf("Keychain availability: %v", available)
|
|
}
|
|
|
|
func TestKeychainBasicOperations(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if !isKeyringAvailable() {
|
|
t.Skip("Skipping: dbus-launch not available for keyring operations")
|
|
}
|
|
|
|
km := auth.NewKeychainManager()
|
|
|
|
service := "test-service"
|
|
account := "test-account"
|
|
secret := "test-secret"
|
|
|
|
// Test storing API key
|
|
if err := km.StoreAPIKey(service, account, secret); err != nil {
|
|
t.Fatalf("StoreAPIKey failed: %v", err)
|
|
}
|
|
|
|
// Test retrieving API key
|
|
retrieved, err := km.GetAPIKey(service, account)
|
|
if err != nil {
|
|
t.Fatalf("GetAPIKey failed: %v", err)
|
|
}
|
|
if retrieved != secret {
|
|
t.Errorf("Expected secret %s, got %s", secret, retrieved)
|
|
}
|
|
|
|
// Test deleting API key
|
|
if err := km.DeleteAPIKey(service, account); err != nil {
|
|
t.Fatalf("DeleteAPIKey failed: %v", err)
|
|
}
|
|
|
|
// Verify deletion - should fail to retrieve
|
|
_, err = km.GetAPIKey(service, account)
|
|
if err == nil {
|
|
t.Error("Expected error when retrieving deleted key")
|
|
}
|
|
}
|
|
|
|
func TestKeychainListMethods(t *testing.T) {
|
|
t.Parallel() // Enable parallel execution
|
|
|
|
km := auth.NewKeychainManager()
|
|
methods := km.ListAvailableMethods()
|
|
|
|
if len(methods) == 0 {
|
|
t.Error("Expected at least one available method")
|
|
}
|
|
|
|
// Check that fallback method is always included
|
|
hasFallback := false
|
|
for _, method := range methods {
|
|
if method == "OS keyring" {
|
|
// OS keyring might be available
|
|
continue
|
|
}
|
|
if len(method) > 0 {
|
|
hasFallback = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !hasFallback {
|
|
t.Error("Expected fallback method to be available")
|
|
}
|
|
|
|
t.Logf("Available methods: %v", methods)
|
|
}
|
|
|
|
func TestKeychainErrorHandling(t *testing.T) {
|
|
t.Parallel() // Enable parallel execution
|
|
|
|
km := auth.NewKeychainManager()
|
|
|
|
// Test getting non-existent key
|
|
_, err := km.GetAPIKey("non-existent", "non-existent")
|
|
if err == nil {
|
|
t.Error("Expected error when getting non-existent key")
|
|
}
|
|
|
|
// Test deleting non-existent key (should not error)
|
|
if err := km.DeleteAPIKey("non-existent", "non-existent"); err != nil {
|
|
t.Errorf("DeleteAPIKey should not error for non-existent key: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestKeychainMultipleKeys(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if !isKeyringAvailable() {
|
|
t.Skip("Skipping: dbus-launch not available for keyring operations")
|
|
}
|
|
|
|
km := auth.NewKeychainManager()
|
|
|
|
keys := map[string]string{
|
|
"service1:account1": "secret1",
|
|
"service1:account2": "secret2",
|
|
"service2:account1": "secret3",
|
|
}
|
|
|
|
// Store multiple keys
|
|
for serviceAccount, secret := range keys {
|
|
parts := strings.SplitN(serviceAccount, ":", 2)
|
|
service, account := parts[0], parts[1]
|
|
|
|
if err := km.StoreAPIKey(service, account, secret); err != nil {
|
|
t.Fatalf("StoreAPIKey failed for %s: %v", serviceAccount, err)
|
|
}
|
|
}
|
|
|
|
// Retrieve and verify all keys
|
|
for serviceAccount, expectedSecret := range keys {
|
|
parts := strings.SplitN(serviceAccount, ":", 2)
|
|
service, account := parts[0], parts[1]
|
|
|
|
retrieved, err := km.GetAPIKey(service, account)
|
|
if err != nil {
|
|
t.Fatalf("GetAPIKey failed for %s: %v", serviceAccount, err)
|
|
}
|
|
if retrieved != expectedSecret {
|
|
t.Errorf("Expected secret %s for %s, got %s", expectedSecret, serviceAccount, retrieved)
|
|
}
|
|
|
|
// Clean up each key
|
|
if err := km.DeleteAPIKey(service, account); err != nil {
|
|
t.Fatalf("DeleteAPIKey failed for %s: %v", serviceAccount, err)
|
|
}
|
|
}
|
|
}
|