package certbot import ( "os" "path/filepath" "testing" ) func TestBuildHAProxyCert_EmptyCert(t *testing.T) { // BuildHAProxyCert requires sudo + real cert paths, // so we test the validation logic directly. combined := append([]byte{}, []byte{}...) if len(combined) != 0 { t.Fatal("test setup: expected empty combined") } // The check we added: len(combined) == 0 → error } func TestHAProxyCertPath(t *testing.T) { tests := []struct { domain string want string }{ {"example.com", "/etc/haproxy/certs/example.com.pem"}, {"*.example.com", "/etc/haproxy/certs/*.example.com.pem"}, {"sub.example.com", "/etc/haproxy/certs/sub.example.com.pem"}, } for _, tt := range tests { got := HAProxyCertPath(tt.domain) if got != tt.want { t.Errorf("HAProxyCertPath(%q) = %q, want %q", tt.domain, got, tt.want) } } } func TestCertPaths(t *testing.T) { domain := "example.com" certPath := CertPath(domain) keyPath := KeyPath(domain) if certPath != "/etc/letsencrypt/live/example.com/fullchain.pem" { t.Errorf("CertPath = %q", certPath) } if keyPath != "/etc/letsencrypt/live/example.com/privkey.pem" { t.Errorf("KeyPath = %q", keyPath) } } func TestEnsureCredentials(t *testing.T) { tmp := t.TempDir() credsPath := filepath.Join(tmp, "subdir", "cloudflare.ini") m := NewManager(credsPath) if err := m.EnsureCredentials("test-token"); err != nil { t.Fatalf("EnsureCredentials: %v", err) } data, err := os.ReadFile(credsPath) if err != nil { t.Fatalf("read credentials: %v", err) } if string(data) != "dns_cloudflare_api_token = test-token\n" { t.Errorf("credentials content = %q", string(data)) } } func TestEnsureCredentials_EmptyToken(t *testing.T) { m := NewManager(filepath.Join(t.TempDir(), "test.ini")) if err := m.EnsureCredentials(""); err == nil { t.Error("expected error for empty token") } } func TestParseCertOutput(t *testing.T) { tests := []struct { name string output string wildcard bool issuer string }{ { name: "wildcard cert (no spaces around =)", output: "subject=CN=*.cloud.payne.io\nnotAfter=Sep 4 23:22:30 2026 GMT\nissuer=C=US, O=Let's Encrypt, CN=YR1\n", wildcard: true, issuer: "C=US, O=Let's Encrypt, CN=YR1", }, { name: "wildcard cert (spaces around =)", output: "subject=CN = *.example.com\nnotAfter=Jan 15 12:00:00 2027 GMT\nissuer=CN=R3\n", wildcard: true, issuer: "CN=R3", }, { name: "single domain cert", output: "subject=CN=example.com\nnotAfter=Jan 15 12:00:00 2027 GMT\nissuer=CN=R3\n", wildcard: false, issuer: "CN=R3", }, { name: "single domain with subdomain", output: "subject=CN=app.example.com\nnotAfter=Jan 15 12:00:00 2027 GMT\nissuer=CN=R3\n", wildcard: false, issuer: "CN=R3", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { status := &CertStatus{} parseCertOutput(tt.output, status) if status.Wildcard != tt.wildcard { t.Errorf("Wildcard = %v, want %v", status.Wildcard, tt.wildcard) } if status.IssuerCN != tt.issuer { t.Errorf("IssuerCN = %q, want %q", status.IssuerCN, tt.issuer) } if status.Expiry.IsZero() { t.Error("Expiry should be parsed") } }) } }