Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBHF4R9EAejDJUMdwr6C68
133 lines
3.8 KiB
Go
133 lines
3.8 KiB
Go
//go:build integration
|
|
|
|
// Diese Tests laufen nur mit `go test -tags integration ./internal/opnsense/`
|
|
// gegen eine echte OPNsense-Testinstanz. Sie bestätigen die in
|
|
// docs/opnsense-api.md dokumentierten Annahmen über Feldnamen und Formate.
|
|
package opnsense
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func integrationClient(t *testing.T) *Client {
|
|
t.Helper()
|
|
base, key, secret := os.Getenv("OPNSENSE_URL"), os.Getenv("OPNSENSE_KEY"), os.Getenv("OPNSENSE_SECRET")
|
|
if base == "" || key == "" || secret == "" {
|
|
t.Skip("OPNSENSE_URL/OPNSENSE_KEY/OPNSENSE_SECRET nicht gesetzt")
|
|
}
|
|
c, err := New(Options{BaseURL: base, APIKey: key, APISecret: secret,
|
|
CAFile: os.Getenv("OPNSENSE_CA"), Timeout: 20 * time.Second})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return c
|
|
}
|
|
|
|
// TestIntegrationProviders bestätigt Feldnamen und Map-Form der Provider-Antwort.
|
|
func TestIntegrationProviders(t *testing.T) {
|
|
ps, err := integrationClient(t).Providers(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("Providers: %v", err)
|
|
}
|
|
if len(ps) == 0 {
|
|
t.Fatal("keine Provider — mindestens eine OpenVPN-Instanz muss exportierbar sein")
|
|
}
|
|
for _, p := range ps {
|
|
if p.VPNID == "" || p.Name == "" {
|
|
t.Errorf("unvollständiger Provider: %+v", p)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestIntegrationAccountsExpiryIsParsed bestätigt, dass das Ablaufdatum in
|
|
// einem der unterstützten Formate ankommt und nicht stillschweigend leer bleibt.
|
|
func TestIntegrationAccountsExpiryIsParsed(t *testing.T) {
|
|
c := integrationClient(t)
|
|
ps, err := c.Providers(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var seen, withDate int
|
|
for _, p := range ps {
|
|
accs, err := c.Accounts(context.Background(), p.VPNID)
|
|
if err != nil {
|
|
t.Fatalf("Accounts(%s): %v", p.VPNID, err)
|
|
}
|
|
for _, a := range accs {
|
|
seen++
|
|
if a.CommonName == "" {
|
|
t.Errorf("Zertifikat %s ohne CommonName — Feldname prüfen: %+v", a.RefID, a)
|
|
}
|
|
if !a.ValidTo.IsZero() {
|
|
withDate++
|
|
}
|
|
}
|
|
}
|
|
if seen == 0 {
|
|
t.Skip("keine Zertifikate auf der Testinstanz")
|
|
}
|
|
if withDate == 0 {
|
|
t.Fatalf("kein einziges der %d Zertifikate hat ein auswertbares Ablaufdatum — "+
|
|
"flexTimeLayouts bzw. die Feldnamen in rawAccount müssen ergänzt werden", seen)
|
|
}
|
|
}
|
|
|
|
// TestIntegrationAccountsRevokedField bestätigt, dass revozierte Zertifikate
|
|
// als solche erkennbar sind. Voraussetzung: auf der Testinstanz existiert ein
|
|
// revoziertes Zertifikat mit CN aus OPNSENSE_REVOKED_CN.
|
|
func TestIntegrationAccountsRevokedField(t *testing.T) {
|
|
wantCN := os.Getenv("OPNSENSE_REVOKED_CN")
|
|
if wantCN == "" {
|
|
t.Skip("OPNSENSE_REVOKED_CN nicht gesetzt")
|
|
}
|
|
c := integrationClient(t)
|
|
ps, err := c.Providers(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, p := range ps {
|
|
accs, err := c.Accounts(context.Background(), p.VPNID)
|
|
if err != nil {
|
|
t.Fatalf("Accounts(%s): %v", p.VPNID, err)
|
|
}
|
|
for _, a := range accs {
|
|
if a.CommonName == wantCN {
|
|
if !a.Revoked {
|
|
t.Fatalf("Zertifikat %q wird nicht als revoziert gemeldet: %+v", wantCN, a)
|
|
}
|
|
if a.IsUsable(time.Now()) {
|
|
t.Fatalf("revoziertes Zertifikat %q gilt als nutzbar", wantCN)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
t.Fatalf("CN %q auf keiner Instanz gefunden", wantCN)
|
|
}
|
|
|
|
// TestIntegrationExportFormats bestätigt, dass beide angebotenen Formate
|
|
// nicht-leere Konfigurationen liefern.
|
|
func TestIntegrationExportFormats(t *testing.T) {
|
|
refID := os.Getenv("OPNSENSE_CERT_REF")
|
|
vpnID := os.Getenv("OPNSENSE_VPNID")
|
|
if refID == "" || vpnID == "" {
|
|
t.Skip("OPNSENSE_CERT_REF/OPNSENSE_VPNID nicht gesetzt")
|
|
}
|
|
c := integrationClient(t)
|
|
for _, format := range []string{FormatOVPN, FormatViscosity} {
|
|
res, err := c.Export(context.Background(), vpnID, refID, format)
|
|
if err != nil {
|
|
t.Errorf("Export(%s): %v", format, err)
|
|
continue
|
|
}
|
|
n, _ := io.Copy(io.Discard, res.Body)
|
|
res.Body.Close()
|
|
if n == 0 {
|
|
t.Errorf("Export(%s) lieferte 0 Bytes", format)
|
|
}
|
|
}
|
|
}
|