kvm2: domain and volume XML, metadata element and NoCloud seed builders
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
package kvm2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.home.hrajfrisbee.cz/kacerr/egress-proxies-operator/internal/provider"
|
||||
)
|
||||
|
||||
func TestMarshalInstanceMetadata_namespacedElement(t *testing.T) {
|
||||
t.Parallel()
|
||||
created := time.Date(2026, 9, 16, 10, 30, 0, 0, time.FixedZone("CEST", 2*3600))
|
||||
got, err := marshalInstanceMetadata(newInstanceMetadata("uid-1", created))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []string{
|
||||
`<instance xmlns="` + metadataURI + `">`,
|
||||
"<managed>true</managed>",
|
||||
"<uid>uid-1</uid>",
|
||||
"<createdAt>2026-09-16T08:30:00Z</createdAt>",
|
||||
"</instance>",
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Errorf("marshalled metadata %q lacks %q", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMetadata_withNamespace(t *testing.T) {
|
||||
t.Parallel()
|
||||
in := `<instance xmlns="` + metadataURI + `"><managed>true</managed><uid>abc</uid><createdAt>2026-09-16T08:30:00Z</createdAt></instance>`
|
||||
m, err := parseInstanceMetadata(in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !m.managed() {
|
||||
t.Error("managed() = false, want true")
|
||||
}
|
||||
if m.UID != "abc" {
|
||||
t.Errorf("UID = %q, want abc", m.UID)
|
||||
}
|
||||
if want := time.Date(2026, 9, 16, 8, 30, 0, 0, time.UTC); !m.createdAt().Equal(want) {
|
||||
t.Errorf("createdAt() = %v, want %v", m.createdAt(), want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMetadata_withoutNamespaceDeclaration(t *testing.T) {
|
||||
t.Parallel()
|
||||
in := "<instance>\n <managed>true</managed>\n <uid>abc</uid>\n <createdAt>2026-09-16T08:30:00Z</createdAt>\n</instance>"
|
||||
m, err := parseInstanceMetadata(in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !m.managed() || m.UID != "abc" {
|
||||
t.Errorf("got managed=%v uid=%q, want true/abc", m.managed(), m.UID)
|
||||
}
|
||||
if m.createdAt().IsZero() {
|
||||
t.Error("createdAt() is zero, want parsed timestamp")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMetadata_absentGivesEmptyUID(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
}{
|
||||
{name: "empty element", in: "<instance/>"},
|
||||
{name: "empty element with namespace", in: `<instance xmlns="` + metadataURI + `"></instance>`},
|
||||
{name: "empty children", in: "<instance><managed></managed><uid></uid><createdAt></createdAt></instance>"},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m, err := parseInstanceMetadata(tc.in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m.managed() {
|
||||
t.Error("managed() = true, want false")
|
||||
}
|
||||
if m.UID != "" {
|
||||
t.Errorf("UID = %q, want empty", m.UID)
|
||||
}
|
||||
if !m.createdAt().IsZero() {
|
||||
t.Errorf("createdAt() = %v, want zero", m.createdAt())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMetadata_badCreatedAtIsZeroTime(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
}{
|
||||
{name: "garbage", in: "<instance><managed>true</managed><uid>u</uid><createdAt>yesterday</createdAt></instance>"},
|
||||
{name: "date only", in: "<instance><managed>true</managed><uid>u</uid><createdAt>2026-09-16</createdAt></instance>"},
|
||||
{name: "missing", in: "<instance><managed>true</managed><uid>u</uid></instance>"},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m, err := parseInstanceMetadata(tc.in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !m.createdAt().IsZero() {
|
||||
t.Errorf("createdAt() = %v, want zero", m.createdAt())
|
||||
}
|
||||
if !m.managed() || m.UID != "u" {
|
||||
t.Errorf("other fields lost: managed=%v uid=%q", m.managed(), m.UID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMetadata_notXMLIsPermanent(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
}{
|
||||
{name: "empty string", in: ""},
|
||||
{name: "whitespace", in: " \n"},
|
||||
{name: "plain text", in: "managed: true"},
|
||||
{name: "unclosed element", in: "<instance><managed>true"},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := parseInstanceMetadata(tc.in)
|
||||
if !errors.Is(err, provider.ErrPermanent) {
|
||||
t.Errorf("err = %v, want ErrPermanent", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMetadata_wrongRootIsPermanent(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
}{
|
||||
{name: "other local name", in: "<proxy><managed>true</managed></proxy>"},
|
||||
{name: "other local name with our namespace", in: `<vm xmlns="` + metadataURI + `"><uid>x</uid></vm>`},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := parseInstanceMetadata(tc.in)
|
||||
if !errors.Is(err, provider.ErrPermanent) {
|
||||
t.Errorf("err = %v, want ErrPermanent", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user