obm/internal/provider/provider_test.go
MermaidMan 33d9a2cb2e deploy walkthrough, API validation, inference client, Hetzner provider
- Interactive deploy command with 8-step walkthrough:
  framework → provider → token → SSH → server → inference → tailscale → discord
- .env file generation from walkthrough config
- DeploymentConfig struct with framework-aware defaults
- Inference API client with validation for Venice, OpenRouter, OpenAI, Anthropic
- Hetzner Cloud provider: token validation, SSH key listing
- DotEnv parser/writer with schema validation
- Destroy command with confirmation prompt
- Validation subcommand for checking existing .env files
- All tests passing, go vet clean
2026-05-22 15:29:27 +00:00

198 lines
No EOL
4.7 KiB
Go

package provider
import (
"context"
"testing"
"github.com/openboatmobile/obm/internal/validation"
)
// mockProvider implements Provider for testing.
type mockProvider struct {
BaseProvider
checks []validation.Check
}
func newMockProvider() *mockProvider {
return &mockProvider{
BaseProvider: BaseProvider{
DisplayName: "Mock Provider",
Identifier: "mock",
TokenKey: "MOCK_TOKEN",
},
}
}
func (m *mockProvider) Checks(ctx context.Context) []validation.Check {
return m.checks
}
func TestBaseProviderMethods(t *testing.T) {
p := newMockProvider()
if p.Name() != "mock" {
t.Errorf("Name() = %q, want %q", p.Name(), "mock")
}
if p.ProviderName() != "Mock Provider" {
t.Errorf("ProviderName() = %q, want %q", p.ProviderName(), "Mock Provider")
}
if p.TokenEnvKey() != "MOCK_TOKEN" {
t.Errorf("TokenEnvKey() = %q, want %q", p.TokenEnvKey(), "MOCK_TOKEN")
}
if p.GetToken() != "" {
t.Errorf("GetToken() = %q, want empty", p.GetToken())
}
p.SetToken("test-token")
if p.GetToken() != "test-token" {
t.Errorf("GetToken() = %q, want %q", p.GetToken(), "test-token")
}
}
func TestBaseProviderValidate(t *testing.T) {
ctx := context.Background()
t.Run("no_token", func(t *testing.T) {
p := newMockProvider()
err := p.Validate(ctx)
if err == nil {
t.Error("Validate() should fail when no token is set")
}
})
t.Run("has_token", func(t *testing.T) {
p := newMockProvider()
p.SetToken("test-token")
err := p.Validate(ctx)
// BaseProvider.Validate only checks for token presence
if err != nil {
t.Errorf("Validate() = %v, want nil", err)
}
})
}
func TestRegistry(t *testing.T) {
// Register a mock provider
Register("mock-test", func() Provider {
return newMockProvider()
})
// Verify it's registered
if _, ok := Registry["mock-test"]; !ok {
t.Error("mock-test provider not registered")
}
// Verify Get works
p, err := Get("mock-test")
if err != nil {
t.Errorf("Get(mock-test) = %v, want nil", err)
}
if p.Name() != "mock" {
t.Errorf("Get(mock-test).Name() = %q, want %q", p.Name(), "mock")
}
}
func TestGetUnknownProvider(t *testing.T) {
_, err := Get("nonexistent")
if err == nil {
t.Error("Get(nonexistent) should return error")
}
}
func TestNames(t *testing.T) {
// Names() should return all registered provider names
names := Names()
if len(names) == 0 {
t.Error("Names() returned empty slice, want at least one provider")
}
// Check that our registered provider is in the list
found := false
for _, n := range names {
if n == "mock-test" {
found = true
break
}
}
if !found {
t.Error("Names() missing mock-test provider")
}
}
func TestValidateAll(t *testing.T) {
ctx := context.Background()
t.Run("with_tokens", func(t *testing.T) {
p1 := newMockProvider()
p1.SetToken("token1")
p1.checks = []validation.Check{
validation.CheckFunc{
NameField: "token-auth",
CategoryField: validation.CategoryCredentials,
RunFunc: func(ctx context.Context) validation.CheckResult {
return validation.CheckResult{Status: validation.Pass, Message: "Token valid"}
},
},
}
p2 := newMockProvider()
p2.DisplayName = "Second Provider"
p2.Identifier = "mock2"
p2.TokenKey = "MOCK2_TOKEN"
p2.SetToken("token2")
p2.checks = []validation.Check{
validation.CheckFunc{
NameField: "token-auth",
CategoryField: validation.CategoryCredentials,
RunFunc: func(ctx context.Context) validation.CheckResult {
return validation.CheckResult{Status: validation.Pass, Message: "Token valid"}
},
},
}
reports, allPassed := ValidateAll(ctx, []Provider{p1, p2})
if len(reports) != 2 {
t.Errorf("ValidateAll() returned %d reports, want 2", len(reports))
}
if !allPassed {
t.Error("ValidateAll() should report all passed")
}
})
t.Run("with_failures", func(t *testing.T) {
p := newMockProvider()
p.SetToken("bad-token")
p.checks = []validation.Check{
validation.CheckFunc{
NameField: "token-auth",
CategoryField: validation.CategoryCredentials,
RunFunc: func(ctx context.Context) validation.CheckResult {
return validation.CheckResult{Status: validation.Fail, Message: "Token rejected by API"}
},
},
}
reports, allPassed := ValidateAll(ctx, []Provider{p})
if len(reports) != 1 {
t.Errorf("ValidateAll() returned %d reports, want 1", len(reports))
}
if allPassed {
t.Error("ValidateAll() should report failures")
}
if !reports[0].HasFailures() {
t.Error("Report should have failures")
}
})
t.Run("skip_no_token", func(t *testing.T) {
p := newMockProvider()
// No token set
reports, _ := ValidateAll(ctx, []Provider{p})
if len(reports) != 0 {
t.Errorf("ValidateAll() returned %d reports, want 0 (provider has no token)", len(reports))
}
})
}