|
|
|
@ -1816,3 +1816,205 @@ func TestHeaders(t *testing.T) { |
|
|
|
|
|
|
|
|
|
|
|
require.Equal(t, "max-age=31536000; includeSubDomains", resp.Header.Get("Strict-Transport-Security")) |
|
|
|
require.Equal(t, "max-age=31536000; includeSubDomains", resp.Header.Get("Strict-Transport-Security")) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func TestConnectorFailureHandling(t *testing.T) { |
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background()) |
|
|
|
|
|
|
|
defer cancel() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tests := []struct { |
|
|
|
|
|
|
|
name string |
|
|
|
|
|
|
|
connectors []storage.Connector |
|
|
|
|
|
|
|
continueOnConnectorFailure bool |
|
|
|
|
|
|
|
wantErr bool |
|
|
|
|
|
|
|
wantErrContains string |
|
|
|
|
|
|
|
expectConnectors []string // IDs of connectors that should be loaded successfully
|
|
|
|
|
|
|
|
}{ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "all connectors succeed with flag enabled", |
|
|
|
|
|
|
|
connectors: []storage.Connector{ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "mock1", |
|
|
|
|
|
|
|
Type: "mockCallback", |
|
|
|
|
|
|
|
Name: "Mock1", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "mock2", |
|
|
|
|
|
|
|
Type: "mockCallback", |
|
|
|
|
|
|
|
Name: "Mock2", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
continueOnConnectorFailure: true, |
|
|
|
|
|
|
|
wantErr: false, |
|
|
|
|
|
|
|
expectConnectors: []string{"mock1", "mock2"}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "all connectors succeed with flag disabled", |
|
|
|
|
|
|
|
connectors: []storage.Connector{ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "mock1", |
|
|
|
|
|
|
|
Type: "mockCallback", |
|
|
|
|
|
|
|
Name: "Mock1", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "mock2", |
|
|
|
|
|
|
|
Type: "mockCallback", |
|
|
|
|
|
|
|
Name: "Mock2", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
continueOnConnectorFailure: false, |
|
|
|
|
|
|
|
wantErr: false, |
|
|
|
|
|
|
|
expectConnectors: []string{"mock1", "mock2"}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "partial connector failure with flag enabled", |
|
|
|
|
|
|
|
connectors: []storage.Connector{ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "mock-good", |
|
|
|
|
|
|
|
Type: "mockCallback", |
|
|
|
|
|
|
|
Name: "Good Mock", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "bad-connector", |
|
|
|
|
|
|
|
Type: "nonexistent", |
|
|
|
|
|
|
|
Name: "Bad Connector", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "mock-good2", |
|
|
|
|
|
|
|
Type: "mockCallback", |
|
|
|
|
|
|
|
Name: "Good Mock 2", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
continueOnConnectorFailure: true, |
|
|
|
|
|
|
|
wantErr: false, |
|
|
|
|
|
|
|
expectConnectors: []string{"mock-good", "mock-good2"}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "partial connector failure with flag disabled", |
|
|
|
|
|
|
|
connectors: []storage.Connector{ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "mock-good", |
|
|
|
|
|
|
|
Type: "mockCallback", |
|
|
|
|
|
|
|
Name: "Good Mock", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "bad-connector", |
|
|
|
|
|
|
|
Type: "nonexistent", |
|
|
|
|
|
|
|
Name: "Bad Connector", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "mock-good2", |
|
|
|
|
|
|
|
Type: "mockCallback", |
|
|
|
|
|
|
|
Name: "Good Mock 2", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
continueOnConnectorFailure: false, |
|
|
|
|
|
|
|
wantErr: true, |
|
|
|
|
|
|
|
wantErrContains: "Failed to open connector bad-connector", |
|
|
|
|
|
|
|
expectConnectors: []string{}, // Server creation should fail
|
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "all connectors fail with flag enabled", |
|
|
|
|
|
|
|
connectors: []storage.Connector{ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "bad1", |
|
|
|
|
|
|
|
Type: "nonexistent1", |
|
|
|
|
|
|
|
Name: "Bad 1", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "bad2", |
|
|
|
|
|
|
|
Type: "nonexistent2", |
|
|
|
|
|
|
|
Name: "Bad 2", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
continueOnConnectorFailure: true, |
|
|
|
|
|
|
|
wantErr: true, |
|
|
|
|
|
|
|
wantErrContains: "failed to open all connectors (2/2)", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "all connectors fail with flag disabled", |
|
|
|
|
|
|
|
connectors: []storage.Connector{ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "bad1", |
|
|
|
|
|
|
|
Type: "nonexistent1", |
|
|
|
|
|
|
|
Name: "Bad 1", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ID: "bad2", |
|
|
|
|
|
|
|
Type: "nonexistent2", |
|
|
|
|
|
|
|
Name: "Bad 2", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
continueOnConnectorFailure: false, |
|
|
|
|
|
|
|
wantErr: true, |
|
|
|
|
|
|
|
wantErrContains: "Failed to open connector", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
name: "no connectors", |
|
|
|
|
|
|
|
connectors: []storage.Connector{}, |
|
|
|
|
|
|
|
continueOnConnectorFailure: true, |
|
|
|
|
|
|
|
wantErr: true, |
|
|
|
|
|
|
|
wantErrContains: "no connectors specified", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _, tc := range tests { |
|
|
|
|
|
|
|
t.Run(tc.name, func(t *testing.T) { |
|
|
|
|
|
|
|
config := Config{ |
|
|
|
|
|
|
|
Issuer: "http://localhost", |
|
|
|
|
|
|
|
Storage: memory.New(logger), |
|
|
|
|
|
|
|
Web: WebConfig{ |
|
|
|
|
|
|
|
Dir: "../web", |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Logger: logger, |
|
|
|
|
|
|
|
PrometheusRegistry: prometheus.NewRegistry(), |
|
|
|
|
|
|
|
HealthChecker: gosundheit.New(), |
|
|
|
|
|
|
|
ContinueOnConnectorFailure: tc.continueOnConnectorFailure, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create connectors in storage
|
|
|
|
|
|
|
|
for _, conn := range tc.connectors { |
|
|
|
|
|
|
|
if err := config.Storage.CreateConnector(ctx, conn); err != nil { |
|
|
|
|
|
|
|
t.Fatalf("failed to create connector: %v", err) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
server, err := newServer(ctx, config, staticRotationStrategy(testKey)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if tc.wantErr { |
|
|
|
|
|
|
|
if err == nil { |
|
|
|
|
|
|
|
t.Errorf("expected error but got none") |
|
|
|
|
|
|
|
} else if tc.wantErrContains != "" && !strings.Contains(err.Error(), tc.wantErrContains) { |
|
|
|
|
|
|
|
t.Errorf("expected error containing %q, got %q", tc.wantErrContains, err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
t.Errorf("unexpected error: %v", err) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Verify expected connectors are loaded
|
|
|
|
|
|
|
|
for _, id := range tc.expectConnectors { |
|
|
|
|
|
|
|
if _, exists := server.connectors[id]; !exists { |
|
|
|
|
|
|
|
t.Errorf("expected connector %q to be loaded", id) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Verify failed connectors are not loaded
|
|
|
|
|
|
|
|
for _, conn := range tc.connectors { |
|
|
|
|
|
|
|
_, shouldExist := false, false |
|
|
|
|
|
|
|
for _, expectedID := range tc.expectConnectors { |
|
|
|
|
|
|
|
if conn.ID == expectedID { |
|
|
|
|
|
|
|
shouldExist = true |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_, exists := server.connectors[conn.ID] |
|
|
|
|
|
|
|
if shouldExist && !exists { |
|
|
|
|
|
|
|
t.Errorf("connector %q should have been loaded but wasn't", conn.ID) |
|
|
|
|
|
|
|
} else if !shouldExist && exists { |
|
|
|
|
|
|
|
t.Errorf("connector %q should not have been loaded but was", conn.ID) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|