The kvm2 block reuses KVMConfig; validateKVM gains a block-name variant so messages say kvm2. The package skeleton has a non-dialing New, strict providerID parsing, the state table and a 34-row classify test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
184 lines
3.9 KiB
Go
184 lines
3.9 KiB
Go
package provider
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestLoadConfig_valid(t *testing.T) {
|
|
t.Parallel()
|
|
data := []byte(`
|
|
providers:
|
|
- name: kubernetes
|
|
type: kubernetes
|
|
kubernetes:
|
|
image: ubuntu/squid:6.6-24.04_edge
|
|
- name: gcp-eu
|
|
type: gcp
|
|
gcp:
|
|
project: my-project
|
|
network: custom-net
|
|
`)
|
|
cfg, err := LoadConfig(data)
|
|
if err != nil {
|
|
t.Fatalf("LoadConfig() error = %v, want nil", err)
|
|
}
|
|
if len(cfg.Providers) != 2 {
|
|
t.Fatalf("len(cfg.Providers) = %d, want 2", len(cfg.Providers))
|
|
}
|
|
if cfg.Providers[0].Kubernetes == nil || cfg.Providers[0].Kubernetes.Image != "ubuntu/squid:6.6-24.04_edge" {
|
|
t.Errorf("providers[0].kubernetes = %+v, want Image=ubuntu/squid:6.6-24.04_edge", cfg.Providers[0].Kubernetes)
|
|
}
|
|
if cfg.Providers[1].GCP == nil || cfg.Providers[1].GCP.Project != "my-project" {
|
|
t.Errorf("providers[1].gcp = %+v, want Project=my-project", cfg.Providers[1].GCP)
|
|
}
|
|
}
|
|
|
|
func TestLoadConfig_invalid(t *testing.T) {
|
|
t.Parallel()
|
|
tests := []struct {
|
|
name string
|
|
yaml string
|
|
wantErrSub string
|
|
}{
|
|
{
|
|
name: "empty providers list",
|
|
yaml: `providers: []`,
|
|
wantErrSub: "at least one provider",
|
|
},
|
|
{
|
|
name: "missing name",
|
|
yaml: `
|
|
providers:
|
|
- type: kubernetes`,
|
|
wantErrSub: "name is required",
|
|
},
|
|
{
|
|
name: "duplicate name",
|
|
yaml: `
|
|
providers:
|
|
- name: kubernetes
|
|
type: kubernetes
|
|
- name: kubernetes
|
|
type: kubernetes`,
|
|
wantErrSub: "duplicate provider name",
|
|
},
|
|
{
|
|
name: "unknown type",
|
|
yaml: `
|
|
providers:
|
|
- name: p1
|
|
type: azure`,
|
|
wantErrSub: `unknown provider type "azure"`,
|
|
},
|
|
{
|
|
name: "missing type",
|
|
yaml: `
|
|
providers:
|
|
- name: p1`,
|
|
wantErrSub: "type is required",
|
|
},
|
|
{
|
|
name: "gcp missing project",
|
|
yaml: `
|
|
providers:
|
|
- name: gcp-eu
|
|
type: gcp`,
|
|
wantErrSub: "gcp.project is required",
|
|
},
|
|
{
|
|
name: "gcp with empty project",
|
|
yaml: `
|
|
providers:
|
|
- name: gcp-eu
|
|
type: gcp
|
|
gcp:
|
|
project: ""`,
|
|
wantErrSub: "gcp.project is required",
|
|
},
|
|
{
|
|
name: "kubernetes type with gcp block",
|
|
yaml: `
|
|
providers:
|
|
- name: p1
|
|
type: kubernetes
|
|
gcp:
|
|
project: my-project`,
|
|
wantErrSub: "type is kubernetes but a gcp block is set",
|
|
},
|
|
{
|
|
name: "gcp type with kubernetes block",
|
|
yaml: `
|
|
providers:
|
|
- name: p1
|
|
type: gcp
|
|
gcp:
|
|
project: my-project
|
|
kubernetes:
|
|
image: custom-image`,
|
|
wantErrSub: "type is gcp but a kubernetes block is set",
|
|
},
|
|
{
|
|
name: "kvm type with kvm2 block",
|
|
yaml: `
|
|
providers:
|
|
- name: p1
|
|
type: kvm
|
|
kvm2:
|
|
sshKeyFile: /key`,
|
|
wantErrSub: "type is kvm but a kvm2 block is set",
|
|
},
|
|
{
|
|
name: "kvm2 type with kvm block",
|
|
yaml: `
|
|
providers:
|
|
- name: p1
|
|
type: kvm2
|
|
kvm:
|
|
sshKeyFile: /key`,
|
|
wantErrSub: "type is kvm2 but a kvm block is set",
|
|
},
|
|
{
|
|
name: "strict mode rejects unknown top-level key",
|
|
yaml: `
|
|
providers:
|
|
- name: p1
|
|
type: kubernetes
|
|
extraneous: true`,
|
|
wantErrSub: "parsing providers config",
|
|
},
|
|
{
|
|
name: "strict mode rejects unknown provider key",
|
|
yaml: `
|
|
providers:
|
|
- name: p1
|
|
type: kubernetes
|
|
bogus: true`,
|
|
wantErrSub: "parsing providers config",
|
|
},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := LoadConfig([]byte(tc.yaml))
|
|
if err == nil {
|
|
t.Fatalf("LoadConfig() error = nil, want error containing %q", tc.wantErrSub)
|
|
}
|
|
if !strings.Contains(err.Error(), tc.wantErrSub) {
|
|
t.Errorf("LoadConfig() error = %q, want substring %q", err.Error(), tc.wantErrSub)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadConfigFile_missingFile(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := LoadConfigFile("/nonexistent/providers.yaml")
|
|
if err == nil {
|
|
t.Fatal("LoadConfigFile() error = nil, want error")
|
|
}
|
|
if !strings.Contains(err.Error(), "reading providers config") {
|
|
t.Errorf("LoadConfigFile() error = %q, want substring %q", err.Error(), "reading providers config")
|
|
}
|
|
}
|