Files
pulse/internal/mock/platform_support_contract_test.go
T
rcourtman cd2be53725 mock: simulate offline Proxmox VE host pve5 and stopped workloads
Configure pve5 as offline, cascading to stopped status on all its guests and zeroing metrics to simulate a node outage. Also force standalone offline states on postgres-replica-01 and dev-portal-01 workloads. Update test helpers and platforms coverage checklist in platform_support_contract_test.go.
2026-05-19 19:51:23 +01:00

1138 lines
36 KiB
Go

package mock
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
"testing"
"time"
"github.com/rcourtman/pulse-go-rewrite/internal/platformsupport"
)
var (
numberedPlatformListRE = regexp.MustCompile("^\\d+\\.\\s+`([^`]+)`")
currentSupportMatrixRE = regexp.MustCompile("^\\|\\s+`([^`]+)`\\s+\\|")
currentSupportSetupRowRE = regexp.MustCompile("^\\|\\s+`([^`]+)`\\s+\\|\\s+([^|]+?)\\s+\\|")
agentHostProfileTableRowRE = regexp.MustCompile("^\\|\\s+`([^`]+)`\\s+\\|\\s+`([^`]+)`\\s+\\|\\s+`([^`]+)`\\s+\\|\\s+`([^`]+)`\\s+\\|\\s+(.+?)\\s+\\|\\s+`([^`]+)`\\s+\\|\\s+`([^`]+)`\\s+\\|")
)
type platformSupportManifest struct {
SchemaVersion int `json:"schema_version"`
DefaultInfrastructureSourceOrder []string `json:"default_infrastructure_source_order"`
AgentHostProfiles []agentHostProfileManifestEntry `json:"agent_host_profiles"`
Platforms []platformSupportManifestEntry `json:"platforms"`
}
type agentHostProfileManifestEntry struct {
ID string `json:"id"`
Family string `json:"family"`
GovernanceState string `json:"governance_state"`
ReadinessStage string `json:"readiness_stage"`
HostIdentityTokens []string `json:"host_identity_tokens"`
RuntimePlatform string `json:"runtime_platform"`
SupportFloor map[string]string `json:"support_floor"`
StorageFamily string `json:"storage_family"`
}
type platformSupportManifestEntry struct {
ID string `json:"id"`
GovernanceState string `json:"governance_state"`
ReadinessStage string `json:"readiness_stage"`
PrimaryMode string `json:"primary_mode"`
OnboardingPaths []string `json:"onboarding_paths"`
CanonicalProjections []string `json:"canonical_projections"`
SupportFloor map[string]string `json:"support_floor"`
UILabel string `json:"ui_label"`
UITone string `json:"ui_tone"`
Aliases []string `json:"aliases"`
DisplayTokens []string `json:"display_tokens"`
StorageFamily string `json:"storage_family"`
}
func TestPlatformSupportManifestMatchesSupportModel(t *testing.T) {
model := loadPlatformSupportModel(t)
manifest := loadPlatformSupportManifest(t)
classified := parsePlatformListSection(t, model, "### First-class platforms")
admitted := parsePlatformListSection(t, model, "### Admitted platforms (not yet supported)")
presentationOnly := parsePlatformListSection(t, model, "### Presentation-only platform vocabulary")
agentHostProfiles := parseAgentHostProfileSection(t, model, "### Agent Host Profiles")
matrix := parseCurrentSupportMatrixPlatforms(t, model)
if diff := diffPlatformSets(classified, matrix); diff != "" {
t.Fatalf("current supported platform definitions drifted between classification and support matrix:\n%s", diff)
}
if diff := diffPlatformSets(classified, manifestPlatformsByState(t, manifest, "supported")); diff != "" {
t.Fatalf("supported platform manifest drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformSets(admitted, manifestPlatformsByState(t, manifest, "admitted")); diff != "" {
t.Fatalf("admitted platform manifest drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformSets(
presentationOnly,
manifestPlatformsByState(t, manifest, "presentation-only"),
); diff != "" {
t.Fatalf("presentation-only platform manifest drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformFieldMap(
parseCurrentSupportMatrixOnboardingPaths(t, model),
manifestPlatformOnboardingPathsByState(t, manifest, "supported"),
); diff != "" {
t.Fatalf("supported onboarding-path manifest drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformSets(
sortedAgentHostProfileIDs(agentHostProfiles),
manifestAgentHostProfileIDsByState(t, manifest, "supported"),
); diff != "" {
t.Fatalf("agent host profile manifest drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformFieldMap(
agentHostProfileFieldMap(agentHostProfiles, func(profile agentHostProfileSectionEntry) []string {
return []string{profile.Family}
}),
manifestAgentHostProfileFamiliesByState(t, manifest, "supported"),
); diff != "" {
t.Fatalf("agent host profile family drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformFieldMap(
agentHostProfileFieldMap(agentHostProfiles, func(profile agentHostProfileSectionEntry) []string {
return []string{profile.GovernanceState}
}),
manifestAgentHostProfileGovernanceStatesByState(t, manifest, "supported"),
); diff != "" {
t.Fatalf("agent host profile governance drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformFieldMap(
agentHostProfileFieldMap(agentHostProfiles, func(profile agentHostProfileSectionEntry) []string {
return []string{profile.ReadinessStage}
}),
manifestAgentHostProfileReadinessStagesByState(t, manifest, "supported"),
); diff != "" {
t.Fatalf("agent host profile readiness drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformFieldMap(
agentHostProfileFieldMap(agentHostProfiles, func(profile agentHostProfileSectionEntry) []string {
return append([]string(nil), profile.HostIdentityTokens...)
}),
manifestAgentHostProfileHostIdentityTokensByState(t, manifest, "supported"),
); diff != "" {
t.Fatalf("agent host profile host-identity tokens drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformFieldMap(
agentHostProfileFieldMap(agentHostProfiles, func(profile agentHostProfileSectionEntry) []string {
return []string{profile.RuntimePlatform}
}),
manifestAgentHostProfileRuntimePlatformsByState(t, manifest, "supported"),
); diff != "" {
t.Fatalf("agent host profile runtime-platform fallback drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformFieldMap(
agentHostProfileFieldMap(agentHostProfiles, func(profile agentHostProfileSectionEntry) []string {
return []string{profile.StorageFamily}
}),
manifestAgentHostProfileStorageFamiliesByState(t, manifest, "supported"),
); diff != "" {
t.Fatalf("agent host profile storage-family drifted from the canonical support model:\n%s", diff)
}
if diff := diffPlatformSets(classified, manifest.DefaultInfrastructureSourceOrder); diff != "" {
t.Fatalf("default infrastructure source ordering drifted from the canonical supported platform set:\n%s", diff)
}
}
func TestMockCoverageMatchesCurrentSupportedPlatformSet(t *testing.T) {
manifest := loadPlatformSupportManifest(t)
supported := manifestPlatformsByState(t, manifest, "supported")
checkers := map[string]func(*testing.T, FixtureGraph){
"agent": assertAgentMockCoverage,
"docker": assertDockerMockCoverage,
"kubernetes": assertKubernetesMockCoverage,
"proxmox-pbs": assertProxmoxPBSMockCoverage,
"proxmox-pmg": assertProxmoxPMGMockCoverage,
"proxmox-pve": assertProxmoxPVEMockCoverage,
"truenas": assertTrueNASMockCoverage,
"vmware-vsphere": assertVMwareMockCoverage,
}
if diff := diffPlatformSets(supported, sortedPlatformKeys(checkers)); diff != "" {
t.Fatalf("supported platform coverage guardrail drifted from the canonical support model:\n%s", diff)
}
graph := buildFixtureGraph(DefaultConfig, time.Date(2026, time.April, 10, 12, 0, 0, 0, time.UTC))
for _, platform := range supported {
checker := checkers[platform]
checker(t, graph)
}
}
func TestVMwareFixturesRemainSupportedAtPhase1Floor(t *testing.T) {
model := loadPlatformSupportModel(t)
manifest := loadPlatformSupportManifest(t)
supported := manifestPlatformsByState(t, manifest, "supported")
admitted := manifestPlatformsByState(t, manifest, "admitted")
presentationOnly := manifestPlatformsByState(t, manifest, "presentation-only")
if !containsPlatform(supported, "vmware-vsphere") {
t.Fatal("vmware-vsphere must appear in the current supported platform set after promotion from first-lab-ready")
}
if containsPlatform(admitted, "vmware-vsphere") {
t.Fatal("vmware-vsphere must not remain in the admitted set after promotion to supported")
}
if containsPlatform(presentationOnly, "vmware-vsphere") {
t.Fatal("vmware-vsphere must not regress into presentation-only vocabulary once supported")
}
if !strings.Contains(model, "| `vmware-vsphere` |") {
t.Fatal("expected platform support model to keep the vmware-vsphere support row")
}
vmwareOnboardingPaths, ok := manifestPlatformOnboardingPaths(manifest)["vmware-vsphere"]
if !ok {
t.Fatal("expected vmware-vsphere onboarding-path manifest entry")
}
if diff := diffPlatformSets([]string{"platform-connections"}, vmwareOnboardingPaths); diff != "" {
t.Fatalf("vmware-vsphere onboarding path drifted from the support model:\n%s", diff)
}
vmwareManifest := requireManifestPlatform(t, manifest, "vmware-vsphere")
if vmwareManifest.ReadinessStage != "supported" {
t.Fatalf("vmware readiness stage = %q, want supported", vmwareManifest.ReadinessStage)
}
if vmwareManifest.PrimaryMode != "api-backed" {
t.Fatalf("vmware primary mode = %q, want api-backed", vmwareManifest.PrimaryMode)
}
if diff := diffPlatformSets([]string{"agent", "storage", "vm"}, vmwareManifest.CanonicalProjections); diff != "" {
t.Fatalf("vmware canonical projections drifted from the support model:\n%s", diff)
}
if got := vmwareManifest.SupportFloor["recovery"]; got != "n/a" {
t.Fatalf("vmware recovery support floor = %q, want n/a", got)
}
if got := vmwareManifest.SupportFloor["assistant_control"]; got != "read-only" {
t.Fatalf("vmware assistant control support floor = %q, want read-only", got)
}
graph := buildFixtureGraph(DefaultConfig, time.Date(2026, time.April, 10, 12, 0, 0, 0, time.UTC))
if len(graph.PlatformFixtures.VMware.Hosts) == 0 {
t.Fatal("expected VMware mock fixtures to include hosts")
}
if len(graph.PlatformFixtures.VMware.VMs) == 0 {
t.Fatal("expected VMware mock fixtures to include VMs")
}
if len(graph.PlatformFixtures.VMware.Datastores) == 0 {
t.Fatal("expected VMware mock fixtures to include datastores")
}
fixture := DefaultVMwareConnectionFixture()
if fixture.CollectedAt.IsZero() {
t.Fatal("expected VMware mock connection fixture freshness")
}
if fixture.Hosts == 0 || fixture.VMs == 0 || fixture.Datastores == 0 {
t.Fatalf("expected VMware mock connection fixture to describe canonical inventory, got %+v", fixture)
}
}
func TestUnraidRemainsInPresentationOnlyVocabularyAndAgentHostProfiles(t *testing.T) {
model := loadPlatformSupportModel(t)
manifest := loadPlatformSupportManifest(t)
supported := manifestPlatformsByState(t, manifest, "supported")
admitted := manifestPlatformsByState(t, manifest, "admitted")
presentationOnly := manifestPlatformsByState(t, manifest, "presentation-only")
profiles := parseAgentHostProfileSection(t, model, "### Agent Host Profiles")
if containsPlatform(supported, "unraid") {
t.Fatal("unraid must not appear in the current supported platform set")
}
if containsPlatform(admitted, "unraid") {
t.Fatal("unraid must not appear in the admitted platform set")
}
if !containsPlatform(presentationOnly, "unraid") {
t.Fatal("expected unraid to remain presentation-only platform vocabulary")
}
if !containsPlatform(sortedAgentHostProfileIDs(profiles), "unraid") {
t.Fatal("expected unraid to remain a supported agent host profile")
}
profile := requireAgentHostProfileManifestEntry(t, manifest, "unraid")
if profile.GovernanceState != "supported" {
t.Fatalf("unraid governance state = %q, want supported", profile.GovernanceState)
}
if profile.ReadinessStage != "supported" {
t.Fatalf("unraid readiness stage = %q, want supported", profile.ReadinessStage)
}
if diff := diffPlatformSets([]string{"unraid", "unraid-os", "unraid os"}, profile.HostIdentityTokens); diff != "" {
t.Fatalf("unraid host identity tokens drifted from the host-profile model:\n%s", diff)
}
if profile.RuntimePlatform != "linux" {
t.Fatalf("unraid runtime platform = %q, want linux", profile.RuntimePlatform)
}
if profile.StorageFamily != "onprem" {
t.Fatalf("unraid storage family = %q, want onprem", profile.StorageFamily)
}
if got := profile.SupportFloor["assistant_control"]; got != "read-only" {
t.Fatalf("unraid assistant control support floor = %q, want read-only", got)
}
if got := profile.SupportFloor["storage"]; got != "supported" {
t.Fatalf("unraid storage support floor = %q, want supported", got)
}
if !strings.Contains(model, "### Agent Host Profiles") {
t.Fatal("expected platform support model to keep an agent host profiles section")
}
if !strings.Contains(
model,
"| `unraid` | `Unraid` | `supported` | `supported` | `unraid`, `unraid-os`, `unraid os` | `linux` | `onprem` |",
) {
t.Fatal("expected platform support model to keep the unraid host-profile row")
}
}
func TestPlatformSupportBackendProjectionMatchesSupportManifest(t *testing.T) {
manifest := loadPlatformSupportManifest(t)
profiles := platformsupport.AgentHostProfiles()
gotIDs := make([]string, 0, len(profiles))
gotTokens := make(map[string][]string, len(profiles))
gotRuntimePlatforms := make(map[string][]string, len(profiles))
for _, profile := range profiles {
if profile.GovernanceState != "supported" {
continue
}
gotIDs = append(gotIDs, profile.ID)
gotTokens[profile.ID] = append([]string(nil), profile.HostIdentityTokens...)
gotRuntimePlatforms[profile.ID] = []string{profile.RuntimePlatform}
}
if diff := diffPlatformSets(manifestAgentHostProfileIDsByState(t, manifest, "supported"), gotIDs); diff != "" {
t.Fatalf("backend agent host profile ids drifted from manifest:\n%s", diff)
}
if diff := diffPlatformFieldMap(
manifestAgentHostProfileHostIdentityTokensByState(t, manifest, "supported"),
gotTokens,
); diff != "" {
t.Fatalf("backend agent host profile identity tokens drifted from manifest:\n%s", diff)
}
if diff := diffPlatformFieldMap(
manifestAgentHostProfileRuntimePlatformsByState(t, manifest, "supported"),
gotRuntimePlatforms,
); diff != "" {
t.Fatalf("backend agent host profile runtime platforms drifted from manifest:\n%s", diff)
}
profile, ok := platformsupport.AgentHostProfileForIdentity("Unraid")
if !ok {
t.Fatal("expected backend projection to resolve Unraid identity token")
}
if profile.ID != "unraid" || profile.RuntimePlatform != "linux" {
t.Fatalf("backend Unraid profile = %+v, want id=unraid runtime=linux", profile)
}
if got := platformsupport.NormalizeRuntimePlatformForAgentHostProfile("unraid", "unraid"); got != "linux" {
t.Fatalf("backend runtime normalization = %q, want linux", got)
}
}
func assertAgentMockCoverage(t *testing.T, graph FixtureGraph) {
t.Helper()
if len(graph.State.Hosts) == 0 {
t.Fatal("expected host-agent fixtures for the supported agent platform")
}
if len(graph.State.PhysicalDisks) == 0 {
t.Fatal("expected physical-disk fixtures for the supported agent platform")
}
}
func assertDockerMockCoverage(t *testing.T, graph FixtureGraph) {
t.Helper()
if len(graph.State.DockerHosts) == 0 {
t.Fatal("expected docker host fixtures for the supported docker platform")
}
containerCount := 0
for _, host := range graph.State.DockerHosts {
containerCount += len(host.Containers)
}
if containerCount == 0 {
t.Fatal("expected docker container fixtures for the supported docker platform")
}
}
func assertKubernetesMockCoverage(t *testing.T, graph FixtureGraph) {
t.Helper()
if len(graph.State.KubernetesClusters) == 0 {
t.Fatal("expected kubernetes cluster fixtures for the supported kubernetes platform")
}
nodeCount := 0
deploymentCount := 0
podCount := 0
for _, cluster := range graph.State.KubernetesClusters {
nodeCount += len(cluster.Nodes)
deploymentCount += len(cluster.Deployments)
podCount += len(cluster.Pods)
}
if nodeCount == 0 || deploymentCount == 0 || podCount == 0 {
t.Fatalf(
"expected kubernetes fixtures to include nodes, deployments, and pods; got nodes=%d deployments=%d pods=%d",
nodeCount,
deploymentCount,
podCount,
)
}
}
func assertProxmoxPVEMockCoverage(t *testing.T, graph FixtureGraph) {
t.Helper()
if len(graph.State.Nodes) == 0 {
t.Fatal("expected proxmox-pve node fixtures")
}
if len(graph.State.VMs) == 0 {
t.Fatal("expected proxmox-pve VM fixtures")
}
if len(graph.State.Containers) == 0 {
t.Fatal("expected proxmox-pve system-container fixtures")
}
if len(graph.State.Storage) == 0 {
t.Fatal("expected proxmox-pve storage fixtures")
}
if len(graph.State.PhysicalDisks) == 0 {
t.Fatal("expected proxmox-pve physical-disk fixtures")
}
if len(graph.State.PVEBackups.StorageBackups) == 0 {
t.Fatal("expected proxmox-pve recovery fixtures")
}
}
func assertProxmoxPBSMockCoverage(t *testing.T, graph FixtureGraph) {
t.Helper()
if len(graph.State.PBSInstances) == 0 {
t.Fatal("expected proxmox-pbs instance fixtures")
}
if len(graph.State.PBSBackups) == 0 {
t.Fatal("expected proxmox-pbs backup fixtures")
}
}
func assertProxmoxPMGMockCoverage(t *testing.T, graph FixtureGraph) {
t.Helper()
if len(graph.State.PMGInstances) == 0 {
t.Fatal("expected proxmox-pmg instance fixtures")
}
if len(graph.State.PMGBackups) == 0 {
t.Fatal("expected proxmox-pmg backup fixtures")
}
}
func assertTrueNASMockCoverage(t *testing.T, graph FixtureGraph) {
t.Helper()
snapshot := graph.PlatformFixtures.TrueNAS
if strings.TrimSpace(snapshot.System.Hostname) == "" {
t.Fatal("expected truenas system fixture")
}
if len(snapshot.Apps) == 0 {
t.Fatal("expected truenas app fixtures")
}
if len(snapshot.Pools) == 0 || len(snapshot.Datasets) == 0 {
t.Fatal("expected truenas storage fixtures")
}
if len(snapshot.Disks) == 0 {
t.Fatal("expected truenas disk fixtures")
}
if len(snapshot.ZFSSnapshots)+len(snapshot.ReplicationTasks) == 0 {
t.Fatal("expected truenas recovery fixtures")
}
fixture := DefaultTrueNASConnectionFixture()
if fixture.CollectedAt.IsZero() {
t.Fatal("expected truenas mock connection fixture freshness")
}
if fixture.Systems == 0 || fixture.StoragePools == 0 || fixture.Apps == 0 || fixture.Disks == 0 {
t.Fatalf("expected truenas mock connection fixture to describe canonical inventory, got %+v", fixture)
}
}
func assertVMwareMockCoverage(t *testing.T, graph FixtureGraph) {
t.Helper()
if len(graph.PlatformFixtures.VMware.Hosts) == 0 {
t.Fatal("expected VMware mock fixtures to include hosts")
}
if len(graph.PlatformFixtures.VMware.VMs) == 0 {
t.Fatal("expected VMware mock fixtures to include VMs")
}
if len(graph.PlatformFixtures.VMware.Datastores) == 0 {
t.Fatal("expected VMware mock fixtures to include datastores")
}
}
func loadPlatformSupportManifest(t *testing.T) platformSupportManifest {
t.Helper()
_, currentFile, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("failed to locate current test file for platform support manifest lookup")
}
manifestPath := filepath.Join(
filepath.Dir(currentFile),
"..",
"..",
"docs",
"release-control",
"v6",
"internal",
"PLATFORM_SUPPORT_MANIFEST.json",
)
manifestBytes, err := os.ReadFile(manifestPath)
if err != nil {
t.Fatalf("read platform support manifest: %v", err)
}
var manifest platformSupportManifest
if err := json.Unmarshal(manifestBytes, &manifest); err != nil {
t.Fatalf("unmarshal platform support manifest: %v", err)
}
if manifest.SchemaVersion < 1 {
t.Fatalf("expected positive platform support manifest schema version, got %d", manifest.SchemaVersion)
}
if len(manifest.Platforms) == 0 {
t.Fatal("expected platform support manifest to declare at least one platform")
}
if len(manifest.DefaultInfrastructureSourceOrder) == 0 {
t.Fatal("expected platform support manifest to declare a default infrastructure source order")
}
return manifest
}
func loadPlatformSupportModel(t *testing.T) string {
t.Helper()
_, currentFile, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("failed to locate current test file for platform support model lookup")
}
modelPath := filepath.Join(
filepath.Dir(currentFile),
"..",
"..",
"docs",
"release-control",
"v6",
"internal",
"PLATFORM_SUPPORT_MODEL.md",
)
modelBytes, err := os.ReadFile(modelPath)
if err != nil {
t.Fatalf("read platform support model: %v", err)
}
return string(modelBytes)
}
func parsePlatformListSection(t *testing.T, model string, heading string) []string {
t.Helper()
var platforms []string
inSection := false
// The admitted-platform section is allowed to be empty once the last
// admitted platform graduates to supported; every other section must
// declare at least one platform.
allowEmpty := strings.Contains(heading, "Admitted platforms")
for _, raw := range strings.Split(model, "\n") {
line := strings.TrimSpace(raw)
switch {
case line == heading:
inSection = true
continue
case !inSection:
continue
case strings.HasPrefix(line, "### ") || strings.HasPrefix(line, "## "):
if allowEmpty {
return allowEmptyPlatformList(platforms)
}
return requireNonEmptyPlatformList(t, platforms, heading)
}
matches := numberedPlatformListRE.FindStringSubmatch(line)
if len(matches) == 2 {
platforms = append(platforms, matches[1])
}
}
if allowEmpty {
return allowEmptyPlatformList(platforms)
}
return requireNonEmptyPlatformList(t, platforms, heading)
}
func parseCurrentSupportMatrixPlatforms(t *testing.T, model string) []string {
t.Helper()
var platforms []string
inSection := false
for _, raw := range strings.Split(model, "\n") {
line := strings.TrimSpace(raw)
switch {
case line == "## Current Support Matrix":
inSection = true
continue
case !inSection:
continue
case strings.HasPrefix(line, "## "):
return requireNonEmptyPlatformList(t, platforms, "current support matrix")
}
matches := currentSupportMatrixRE.FindStringSubmatch(line)
if len(matches) == 2 {
platforms = append(platforms, matches[1])
}
}
return requireNonEmptyPlatformList(t, platforms, "current support matrix")
}
func parseCurrentSupportMatrixOnboardingPaths(t *testing.T, model string) map[string][]string {
t.Helper()
rows := make(map[string][]string)
inSetupTable := false
for _, raw := range strings.Split(model, "\n") {
line := strings.TrimSpace(raw)
switch {
case strings.HasPrefix(line, "| Platform") && strings.Contains(line, "| Setup"):
inSetupTable = true
continue
case !inSetupTable:
continue
case strings.HasPrefix(line, "## "):
return requireNonEmptyPlatformFieldMap(t, rows, "current support matrix onboarding paths")
case line == "" || strings.HasPrefix(line, "| ---"):
continue
}
matches := currentSupportSetupRowRE.FindStringSubmatch(line)
if len(matches) != 3 {
continue
}
rows[matches[1]] = parseSetupCellOnboardingPaths(t, matches[2])
}
return requireNonEmptyPlatformFieldMap(t, rows, "current support matrix onboarding paths")
}
func manifestPlatformsByState(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
) []string {
t.Helper()
platforms := make([]string, 0)
for _, platform := range manifest.Platforms {
if strings.TrimSpace(platform.ID) == "" {
t.Fatal("expected platform support manifest platform ids to be non-empty")
}
if strings.TrimSpace(platform.GovernanceState) == "" {
t.Fatalf("expected platform support manifest to classify %s", platform.ID)
}
if platform.GovernanceState == governanceState {
platforms = append(platforms, platform.ID)
}
}
if governanceState == "admitted" {
return allowEmptyPlatformList(platforms)
}
return requireNonEmptyPlatformList(t, platforms, fmt.Sprintf("manifest platforms with state %s", governanceState))
}
func manifestPlatformOnboardingPathsByState(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
) map[string][]string {
t.Helper()
rows := make(map[string][]string)
for _, platform := range manifest.Platforms {
if platform.GovernanceState != governanceState {
continue
}
rows[platform.ID] = validateManifestOnboardingPaths(t, platform)
}
return requireNonEmptyPlatformFieldMap(
t,
rows,
fmt.Sprintf("manifest onboarding paths with state %s", governanceState),
)
}
func manifestPlatformOnboardingPaths(manifest platformSupportManifest) map[string][]string {
rows := make(map[string][]string, len(manifest.Platforms))
for _, platform := range manifest.Platforms {
rows[platform.ID] = append([]string(nil), platform.OnboardingPaths...)
}
return rows
}
type agentHostProfileSectionEntry struct {
Family string
GovernanceState string
ReadinessStage string
HostIdentityTokens []string
RuntimePlatform string
StorageFamily string
}
func parseAgentHostProfileSection(
t *testing.T,
model string,
heading string,
) map[string]agentHostProfileSectionEntry {
t.Helper()
entries := make(map[string]agentHostProfileSectionEntry)
inSection := false
for _, raw := range strings.Split(model, "\n") {
line := strings.TrimSpace(raw)
switch {
case line == heading:
inSection = true
continue
case !inSection:
continue
case strings.HasPrefix(line, "### ") || strings.HasPrefix(line, "## "):
return requireNonEmptyAgentHostProfileMap(t, entries, heading)
case line == "" || strings.HasPrefix(line, "| ---"):
continue
}
matches := agentHostProfileTableRowRE.FindStringSubmatch(line)
if len(matches) != 8 {
continue
}
entries[matches[1]] = agentHostProfileSectionEntry{
Family: matches[2],
GovernanceState: matches[3],
ReadinessStage: matches[4],
HostIdentityTokens: parseInlineTokenList(matches[5]),
RuntimePlatform: matches[6],
StorageFamily: matches[7],
}
}
return requireNonEmptyAgentHostProfileMap(t, entries, heading)
}
func parseInlineTokenList(value string) []string {
tokens := make([]string, 0, 1)
for _, token := range strings.Split(value, ",") {
token = strings.TrimSpace(token)
token = strings.Trim(token, "`")
if token == "" {
continue
}
tokens = append(tokens, token)
}
return tokens
}
func sortedAgentHostProfileIDs(profiles map[string]agentHostProfileSectionEntry) []string {
ids := make([]string, 0, len(profiles))
for id := range profiles {
ids = append(ids, id)
}
sort.Strings(ids)
return ids
}
func agentHostProfileFieldMap(
profiles map[string]agentHostProfileSectionEntry,
selector func(agentHostProfileSectionEntry) []string,
) map[string][]string {
rows := make(map[string][]string, len(profiles))
for id, profile := range profiles {
rows[id] = append([]string(nil), selector(profile)...)
}
return rows
}
func requireNonEmptyAgentHostProfileMap(
t *testing.T,
entries map[string]agentHostProfileSectionEntry,
heading string,
) map[string]agentHostProfileSectionEntry {
t.Helper()
if len(entries) == 0 {
t.Fatalf("expected %s to declare at least one agent host profile", heading)
}
return entries
}
func manifestAgentHostProfileIDsByState(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
) []string {
t.Helper()
ids := make([]string, 0)
for _, profile := range manifest.AgentHostProfiles {
if strings.TrimSpace(profile.ID) == "" {
t.Fatal("expected agent host profile ids to be non-empty")
}
if strings.TrimSpace(profile.GovernanceState) == "" {
t.Fatalf("expected agent host profile manifest to classify %s", profile.ID)
}
if profile.GovernanceState == governanceState {
ids = append(ids, profile.ID)
}
}
return requireNonEmptyPlatformList(
t,
ids,
fmt.Sprintf("manifest agent host profiles with state %s", governanceState),
)
}
func manifestAgentHostProfileFieldMap(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
selector func(agentHostProfileManifestEntry) []string,
label string,
) map[string][]string {
t.Helper()
rows := make(map[string][]string)
for _, profile := range manifest.AgentHostProfiles {
if profile.GovernanceState != governanceState {
continue
}
rows[profile.ID] = append([]string(nil), selector(profile)...)
}
return requireNonEmptyPlatformFieldMap(t, rows, label)
}
func manifestAgentHostProfileFamiliesByState(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
) map[string][]string {
return manifestAgentHostProfileFieldMap(
t,
manifest,
governanceState,
func(profile agentHostProfileManifestEntry) []string { return []string{profile.Family} },
fmt.Sprintf("manifest agent host profile families with state %s", governanceState),
)
}
func manifestAgentHostProfileGovernanceStatesByState(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
) map[string][]string {
return manifestAgentHostProfileFieldMap(
t,
manifest,
governanceState,
func(profile agentHostProfileManifestEntry) []string { return []string{profile.GovernanceState} },
fmt.Sprintf("manifest agent host profile governance with state %s", governanceState),
)
}
func manifestAgentHostProfileReadinessStagesByState(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
) map[string][]string {
return manifestAgentHostProfileFieldMap(
t,
manifest,
governanceState,
func(profile agentHostProfileManifestEntry) []string { return []string{profile.ReadinessStage} },
fmt.Sprintf("manifest agent host profile readiness with state %s", governanceState),
)
}
func manifestAgentHostProfileHostIdentityTokensByState(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
) map[string][]string {
return manifestAgentHostProfileFieldMap(
t,
manifest,
governanceState,
func(profile agentHostProfileManifestEntry) []string {
return append([]string(nil), profile.HostIdentityTokens...)
},
fmt.Sprintf("manifest agent host profile identity tokens with state %s", governanceState),
)
}
func manifestAgentHostProfileRuntimePlatformsByState(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
) map[string][]string {
return manifestAgentHostProfileFieldMap(
t,
manifest,
governanceState,
func(profile agentHostProfileManifestEntry) []string { return []string{profile.RuntimePlatform} },
fmt.Sprintf("manifest agent host profile runtime platforms with state %s", governanceState),
)
}
func manifestAgentHostProfileStorageFamiliesByState(
t *testing.T,
manifest platformSupportManifest,
governanceState string,
) map[string][]string {
return manifestAgentHostProfileFieldMap(
t,
manifest,
governanceState,
func(profile agentHostProfileManifestEntry) []string { return []string{profile.StorageFamily} },
fmt.Sprintf("manifest agent host profile storage families with state %s", governanceState),
)
}
func requireAgentHostProfileManifestEntry(
t *testing.T,
manifest platformSupportManifest,
profileID string,
) agentHostProfileManifestEntry {
t.Helper()
for _, profile := range manifest.AgentHostProfiles {
if profile.ID == profileID {
return profile
}
}
t.Fatalf("expected agent host profile manifest entry for %s", profileID)
return agentHostProfileManifestEntry{}
}
func requireManifestPlatform(t *testing.T, manifest platformSupportManifest, platformID string) platformSupportManifestEntry {
t.Helper()
for _, platform := range manifest.Platforms {
if platform.ID == platformID {
return platform
}
}
t.Fatalf("expected platform support manifest entry for %s", platformID)
return platformSupportManifestEntry{}
}
func requireNonEmptyPlatformList(t *testing.T, platforms []string, label string) []string {
t.Helper()
unique := uniqueSortedPlatforms(platforms)
if len(unique) == 0 {
t.Fatalf("expected %s to declare at least one platform", label)
}
return unique
}
// allowEmptyPlatformList mirrors requireNonEmptyPlatformList but tolerates an
// empty result. Used for governance sets that can legitimately be empty
// (e.g. the admitted-platform staging area after the last admitted platform
// has been promoted to supported).
func allowEmptyPlatformList(platforms []string) []string {
return uniqueSortedPlatforms(platforms)
}
func requireNonEmptyPlatformFieldMap(
t *testing.T,
values map[string][]string,
label string,
) map[string][]string {
t.Helper()
if len(values) == 0 {
t.Fatalf("expected %s to declare at least one platform", label)
}
return values
}
func uniqueSortedPlatforms(platforms []string) []string {
seen := make(map[string]struct{}, len(platforms))
for _, platform := range platforms {
platform = strings.TrimSpace(platform)
if platform == "" {
continue
}
seen[platform] = struct{}{}
}
out := make([]string, 0, len(seen))
for platform := range seen {
out = append(out, platform)
}
sort.Strings(out)
return out
}
func sortedPlatformKeys(checkers map[string]func(*testing.T, FixtureGraph)) []string {
keys := make([]string, 0, len(checkers))
for key := range checkers {
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}
func containsPlatform(platforms []string, want string) bool {
for _, platform := range platforms {
if platform == want {
return true
}
}
return false
}
func diffPlatformSets(want []string, got []string) string {
wantSet := make(map[string]struct{}, len(want))
for _, platform := range want {
wantSet[platform] = struct{}{}
}
gotSet := make(map[string]struct{}, len(got))
for _, platform := range got {
gotSet[platform] = struct{}{}
}
missing := make([]string, 0)
for _, platform := range want {
if _, ok := gotSet[platform]; !ok {
missing = append(missing, platform)
}
}
extra := make([]string, 0)
for _, platform := range got {
if _, ok := wantSet[platform]; !ok {
extra = append(extra, platform)
}
}
if len(missing) == 0 && len(extra) == 0 {
return ""
}
parts := make([]string, 0, 2)
if len(missing) > 0 {
parts = append(parts, fmt.Sprintf("missing: %s", strings.Join(missing, ", ")))
}
if len(extra) > 0 {
parts = append(parts, fmt.Sprintf("extra: %s", strings.Join(extra, ", ")))
}
return strings.Join(parts, "\n")
}
func diffPlatformFieldMap(want map[string][]string, got map[string][]string) string {
platforms := make(map[string]struct{}, len(want)+len(got))
for platform := range want {
platforms[platform] = struct{}{}
}
for platform := range got {
platforms[platform] = struct{}{}
}
keys := make([]string, 0, len(platforms))
for platform := range platforms {
keys = append(keys, platform)
}
sort.Strings(keys)
messages := make([]string, 0)
for _, platform := range keys {
wantValue, wantOK := want[platform]
gotValue, gotOK := got[platform]
switch {
case !wantOK:
messages = append(messages, fmt.Sprintf("unexpected platform %s", platform))
case !gotOK:
messages = append(messages, fmt.Sprintf("missing platform %s", platform))
default:
if diff := diffPlatformSets(wantValue, gotValue); diff != "" {
messages = append(
messages,
fmt.Sprintf("%s onboarding paths drifted:\n%s", platform, indentDiff(diff)),
)
}
}
}
return strings.Join(messages, "\n")
}
func parseSetupCellOnboardingPaths(t *testing.T, value string) []string {
t.Helper()
normalized := strings.ToLower(strings.TrimSpace(value))
paths := make([]string, 0, 2)
if strings.Contains(normalized, "install workspace") {
paths = append(paths, "install-workspace")
}
if strings.Contains(normalized, "platform connections") {
paths = append(paths, "platform-connections")
}
return requireNonEmptyPlatformList(t, paths, fmt.Sprintf("setup cell %q", value))
}
func validateManifestOnboardingPaths(t *testing.T, platform platformSupportManifestEntry) []string {
t.Helper()
switch platform.GovernanceState {
case "supported", "admitted":
return requireNonEmptyPlatformList(
t,
platform.OnboardingPaths,
fmt.Sprintf("manifest onboarding paths for %s", platform.ID),
)
case "presentation-only":
if len(platform.OnboardingPaths) != 0 {
t.Fatalf(
"presentation-only platform %s must not declare onboarding paths, got %v",
platform.ID,
platform.OnboardingPaths,
)
}
return []string{}
default:
t.Fatalf("unexpected governance state %s for %s", platform.GovernanceState, platform.ID)
return nil
}
}
func indentDiff(diff string) string {
lines := strings.Split(diff, "\n")
for i, line := range lines {
lines[i] = " " + line
}
return strings.Join(lines, "\n")
}