Run 3 on the real host got past Create and failed in Get: libvirt 11.6 selects the <instance> element by our URI in DomainGetMetadata but hands it back with no namespace declaration, and the parser required the URI on the element. The lookup already guarantees the namespace, so match on the local name only. The fake now strips the declaration the way libvirt does, and a new test pins the bare form. Execution log updated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
95 lines
2.8 KiB
Go
95 lines
2.8 KiB
Go
package kvm
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestInstanceMetadata_roundTrip(t *testing.T) {
|
|
t.Parallel()
|
|
created := time.Date(2026, 9, 4, 12, 30, 0, 0, time.FixedZone("CEST", 2*3600))
|
|
raw, err := xml.Marshal(newInstanceMetadata("uid-1", created))
|
|
if err != nil {
|
|
t.Fatalf("Marshal() error = %v", err)
|
|
}
|
|
if !strings.Contains(string(raw), `xmlns="`+metadataURI+`"`) {
|
|
t.Errorf("marshalled metadata lacks the namespace declaration: %s", raw)
|
|
}
|
|
m, err := parseInstanceMetadata(string(raw))
|
|
if err != nil {
|
|
t.Fatalf("parseInstanceMetadata() error = %v", err)
|
|
}
|
|
if !m.managed() || m.UID != "uid-1" {
|
|
t.Errorf("parsed = %+v, want managed with uid-1", m)
|
|
}
|
|
if got := m.createdAt(); !got.Equal(created) || got.Location() != time.UTC {
|
|
t.Errorf("createdAt() = %v, want %v in UTC", got, created)
|
|
}
|
|
}
|
|
|
|
func TestParseInstanceMetadata_libvirtPrefixedForm(t *testing.T) {
|
|
t.Parallel()
|
|
// libvirt re-serialises the stored element with whatever prefix it
|
|
// chooses; only the namespace URI is contractual.
|
|
in := `<op:instance xmlns:op="` + metadataURI + `">` +
|
|
`<op:managed>true</op:managed><op:uid>uid-2</op:uid>` +
|
|
`<op:createdAt>2026-09-04T10:00:00Z</op:createdAt></op:instance>`
|
|
m, err := parseInstanceMetadata(in)
|
|
if err != nil {
|
|
t.Fatalf("parseInstanceMetadata() error = %v", err)
|
|
}
|
|
if !m.managed() || m.UID != "uid-2" || m.createdAt().Hour() != 10 {
|
|
t.Errorf("parsed = %+v", m)
|
|
}
|
|
}
|
|
|
|
func TestParseInstanceMetadata_libvirtBareForm(t *testing.T) {
|
|
t.Parallel()
|
|
// What libvirt 11.6 actually returns from DomainGetMetadata: the element
|
|
// selected by our URI, serialised without any namespace declaration.
|
|
in := `<instance><managed>true</managed><uid>uid-3</uid>` +
|
|
`<createdAt>2026-09-10T07:30:00Z</createdAt></instance>`
|
|
m, err := parseInstanceMetadata(in)
|
|
if err != nil {
|
|
t.Fatalf("parseInstanceMetadata() error = %v", err)
|
|
}
|
|
if !m.managed() || m.UID != "uid-3" || m.createdAt().Minute() != 30 {
|
|
t.Errorf("parsed = %+v", m)
|
|
}
|
|
}
|
|
|
|
func TestParseInstanceMetadata_notManaged(t *testing.T) {
|
|
t.Parallel()
|
|
tests := []struct {
|
|
name string
|
|
in string
|
|
wantErr bool
|
|
}{
|
|
{"managed false", `<instance xmlns="` + metadataURI + `"><managed>false</managed><uid>u</uid></instance>`, false},
|
|
{"foreign element", `<foo xmlns="urn:other"><managed>true</managed></foo>`, true},
|
|
{"garbage", `not xml`, true},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
m, err := parseInstanceMetadata(tc.in)
|
|
if (err != nil) != tc.wantErr {
|
|
t.Fatalf("error = %v, wantErr %v", err, tc.wantErr)
|
|
}
|
|
if m.managed() {
|
|
t.Errorf("managed() = true for %q", tc.in)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInstanceMetadata_createdAtMalformedIsZero(t *testing.T) {
|
|
t.Parallel()
|
|
m := instanceMetadata{CreatedAt: "yesterday"}
|
|
if !m.createdAt().IsZero() {
|
|
t.Errorf("createdAt() = %v, want zero time", m.createdAt())
|
|
}
|
|
}
|