Implement the full architectural plan: unified ingest.Service entry point for archive and Redfish payloads, modular redfishprofile package with composable profiles (generic, ami-family, msi, supermicro, dell, hgx-topology), score-based profile matching with fallback expansion mode, and profile-driven acquisition/analysis plans. Vendor-specific logic moved out of common executors and into profile hooks. GPU chassis lookup strategies and known storage recovery collections (IntelVROC/HA-RAID/MRVL) now live in ResolvedAnalysisPlan, populated by profiles at analysis time. Replay helpers read from the plan; no hardcoded path lists remain in generic code. Also splits redfish_replay.go into domain modules (gpu, storage, inventory, fru, profiles) and adds full fixture/matcher/directive test coverage including Dell, AMI, unknown-vendor fallback, and deterministic ordering. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
391 lines
15 KiB
Go
391 lines
15 KiB
Go
package redfishprofile
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestMatchProfiles_UnknownVendorFallsBackToAggregateProfiles(t *testing.T) {
|
|
match := MatchProfiles(MatchSignals{
|
|
ServiceRootProduct: "Redfish Server",
|
|
})
|
|
if match.Mode != ModeFallback {
|
|
t.Fatalf("expected fallback mode, got %q", match.Mode)
|
|
}
|
|
if len(match.Profiles) < 2 {
|
|
t.Fatalf("expected aggregated fallback profiles, got %d", len(match.Profiles))
|
|
}
|
|
}
|
|
|
|
func TestMatchProfiles_MSISelectsMatchedMode(t *testing.T) {
|
|
match := MatchProfiles(MatchSignals{
|
|
SystemManufacturer: "Micro-Star International Co., Ltd.",
|
|
ResourceHints: []string{"/redfish/v1/Chassis/GPU1"},
|
|
})
|
|
if match.Mode != ModeMatched {
|
|
t.Fatalf("expected matched mode, got %q", match.Mode)
|
|
}
|
|
found := false
|
|
for _, profile := range match.Profiles {
|
|
if profile.Name() == "msi" {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatal("expected msi profile to be selected")
|
|
}
|
|
}
|
|
|
|
func TestBuildAcquisitionPlan_FallbackIncludesProfileNotes(t *testing.T) {
|
|
plan := BuildAcquisitionPlan(MatchSignals{
|
|
ServiceRootVendor: "AMI",
|
|
})
|
|
if len(plan.Profiles) == 0 {
|
|
t.Fatal("expected acquisition plan profiles")
|
|
}
|
|
if len(plan.Notes) == 0 {
|
|
t.Fatal("expected acquisition plan notes")
|
|
}
|
|
}
|
|
|
|
func TestBuildAcquisitionPlan_FallbackAddsBroadCrawlTuning(t *testing.T) {
|
|
plan := BuildAcquisitionPlan(MatchSignals{
|
|
ServiceRootProduct: "Unknown Redfish",
|
|
})
|
|
if plan.Mode != ModeFallback {
|
|
t.Fatalf("expected fallback mode, got %q", plan.Mode)
|
|
}
|
|
if plan.Tuning.SnapshotMaxDocuments < 180000 {
|
|
t.Fatalf("expected widened snapshot cap, got %d", plan.Tuning.SnapshotMaxDocuments)
|
|
}
|
|
if plan.Tuning.PrefetchEnabled == nil || !*plan.Tuning.PrefetchEnabled {
|
|
t.Fatal("expected fallback to force prefetch enabled")
|
|
}
|
|
if !plan.Tuning.RecoveryPolicy.EnableCriticalCollectionMemberRetry {
|
|
t.Fatal("expected fallback to inherit critical member retry recovery")
|
|
}
|
|
if !plan.Tuning.RecoveryPolicy.EnableCriticalSlowProbe {
|
|
t.Fatal("expected fallback to inherit critical slow probe recovery")
|
|
}
|
|
}
|
|
|
|
func TestBuildAcquisitionPlan_HGXDisablesNVMePostProbe(t *testing.T) {
|
|
plan := BuildAcquisitionPlan(MatchSignals{
|
|
SystemModel: "HGX B200",
|
|
ResourceHints: []string{"/redfish/v1/Systems/HGX_Baseboard_0"},
|
|
})
|
|
if plan.Mode != ModeMatched {
|
|
t.Fatalf("expected matched mode, got %q", plan.Mode)
|
|
}
|
|
if plan.Tuning.NVMePostProbeEnabled == nil || *plan.Tuning.NVMePostProbeEnabled {
|
|
t.Fatal("expected hgx profile to disable NVMe post-probe")
|
|
}
|
|
}
|
|
|
|
func TestResolveAcquisitionPlan_ExpandsScopedPaths(t *testing.T) {
|
|
signals := MatchSignals{}
|
|
match := MatchProfiles(signals)
|
|
plan := BuildAcquisitionPlan(signals)
|
|
resolved := ResolveAcquisitionPlan(match, plan, DiscoveredResources{
|
|
SystemPaths: []string{"/redfish/v1/Systems/1", "/redfish/v1/Systems/2"},
|
|
}, signals)
|
|
joined := joinResolvedPaths(resolved.SeedPaths)
|
|
for _, wanted := range []string{
|
|
"/redfish/v1/Systems/1/SimpleStorage",
|
|
"/redfish/v1/Systems/1/Storage/IntelVROC",
|
|
"/redfish/v1/Systems/2/SimpleStorage",
|
|
"/redfish/v1/Systems/2/Storage/IntelVROC",
|
|
} {
|
|
if !containsJoinedPath(joined, wanted) {
|
|
t.Fatalf("expected resolved seed path %q", wanted)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResolveAcquisitionPlan_CriticalBaselineIsShapedByProfiles(t *testing.T) {
|
|
signals := MatchSignals{}
|
|
match := MatchProfiles(signals)
|
|
plan := BuildAcquisitionPlan(signals)
|
|
resolved := ResolveAcquisitionPlan(match, plan, DiscoveredResources{
|
|
SystemPaths: []string{"/redfish/v1/Systems/1"},
|
|
ChassisPaths: []string{"/redfish/v1/Chassis/1"},
|
|
ManagerPaths: []string{"/redfish/v1/Managers/1"},
|
|
}, signals)
|
|
joined := joinResolvedPaths(resolved.CriticalPaths)
|
|
for _, wanted := range []string{
|
|
"/redfish/v1",
|
|
"/redfish/v1/Systems/1",
|
|
"/redfish/v1/Systems/1/Memory",
|
|
"/redfish/v1/Chassis/1/Assembly",
|
|
"/redfish/v1/Managers/1/NetworkProtocol",
|
|
"/redfish/v1/UpdateService",
|
|
} {
|
|
if !containsJoinedPath(joined, wanted) {
|
|
t.Fatalf("expected resolved critical path %q", wanted)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResolveAcquisitionPlan_FallbackAppendsPlanBToSeeds(t *testing.T) {
|
|
signals := MatchSignals{ServiceRootProduct: "Unknown Redfish"}
|
|
match := MatchProfiles(signals)
|
|
plan := BuildAcquisitionPlan(signals)
|
|
if plan.Mode != ModeFallback {
|
|
t.Fatalf("expected fallback mode, got %q", plan.Mode)
|
|
}
|
|
plan.PlanBPaths = append(plan.PlanBPaths, "/redfish/v1/Systems/1/Oem/TestPlanB")
|
|
resolved := ResolveAcquisitionPlan(match, plan, DiscoveredResources{
|
|
SystemPaths: []string{"/redfish/v1/Systems/1"},
|
|
}, signals)
|
|
if !containsJoinedPath(joinResolvedPaths(resolved.SeedPaths), "/redfish/v1/Systems/1/Oem/TestPlanB") {
|
|
t.Fatal("expected fallback resolved seeds to include plan-b path")
|
|
}
|
|
}
|
|
|
|
func TestResolveAcquisitionPlan_MSIRefinesDiscoveredGPUChassis(t *testing.T) {
|
|
signals := MatchSignals{
|
|
SystemManufacturer: "Micro-Star International Co., Ltd.",
|
|
ResourceHints: []string{"/redfish/v1/Chassis/GPU1", "/redfish/v1/Chassis/GPU4/Sensors"},
|
|
}
|
|
match := MatchProfiles(signals)
|
|
plan := BuildAcquisitionPlan(signals)
|
|
resolved := ResolveAcquisitionPlan(match, plan, DiscoveredResources{
|
|
ChassisPaths: []string{"/redfish/v1/Chassis/1", "/redfish/v1/Chassis/GPU1", "/redfish/v1/Chassis/GPU4"},
|
|
}, signals)
|
|
joinedSeeds := joinResolvedPaths(resolved.SeedPaths)
|
|
joinedCritical := joinResolvedPaths(resolved.CriticalPaths)
|
|
if !containsJoinedPath(joinedSeeds, "/redfish/v1/Chassis/GPU1") || !containsJoinedPath(joinedSeeds, "/redfish/v1/Chassis/GPU4") {
|
|
t.Fatal("expected MSI refinement to add discovered GPU chassis seed paths")
|
|
}
|
|
if containsJoinedPath(joinedSeeds, "/redfish/v1/Chassis/GPU2") {
|
|
t.Fatal("did not expect undiscovered MSI GPU chassis in resolved seeds")
|
|
}
|
|
if !containsJoinedPath(joinedCritical, "/redfish/v1/Chassis/GPU1/Sensors") || !containsJoinedPath(joinedCritical, "/redfish/v1/Chassis/GPU4/Sensors") {
|
|
t.Fatal("expected MSI refinement to add discovered GPU sensor critical paths")
|
|
}
|
|
if containsJoinedPath(joinedCritical, "/redfish/v1/Chassis/GPU3/Sensors") {
|
|
t.Fatal("did not expect undiscovered MSI GPU sensor critical path")
|
|
}
|
|
}
|
|
|
|
func TestResolveAcquisitionPlan_HGXRefinesDiscoveredBaseboardSystems(t *testing.T) {
|
|
signals := MatchSignals{
|
|
SystemManufacturer: "Supermicro",
|
|
SystemModel: "SYS-821GE-TNHR",
|
|
ChassisModel: "HGX B200",
|
|
ResourceHints: []string{
|
|
"/redfish/v1/Systems/HGX_Baseboard_0",
|
|
"/redfish/v1/Systems/HGX_Baseboard_0/Processors",
|
|
"/redfish/v1/Systems/1",
|
|
},
|
|
}
|
|
match := MatchProfiles(signals)
|
|
plan := BuildAcquisitionPlan(signals)
|
|
resolved := ResolveAcquisitionPlan(match, plan, DiscoveredResources{
|
|
SystemPaths: []string{"/redfish/v1/Systems/1", "/redfish/v1/Systems/HGX_Baseboard_0"},
|
|
}, signals)
|
|
joinedSeeds := joinResolvedPaths(resolved.SeedPaths)
|
|
joinedCritical := joinResolvedPaths(resolved.CriticalPaths)
|
|
if !containsJoinedPath(joinedSeeds, "/redfish/v1/Systems/HGX_Baseboard_0") || !containsJoinedPath(joinedSeeds, "/redfish/v1/Systems/HGX_Baseboard_0/Processors") {
|
|
t.Fatal("expected HGX refinement to add discovered baseboard system paths")
|
|
}
|
|
if !containsJoinedPath(joinedCritical, "/redfish/v1/Systems/HGX_Baseboard_0") || !containsJoinedPath(joinedCritical, "/redfish/v1/Systems/HGX_Baseboard_0/Processors") {
|
|
t.Fatal("expected HGX refinement to add discovered baseboard critical paths")
|
|
}
|
|
if containsJoinedPath(joinedSeeds, "/redfish/v1/Systems/HGX_Baseboard_1") {
|
|
t.Fatal("did not expect undiscovered HGX baseboard system path")
|
|
}
|
|
}
|
|
|
|
func TestResolveAcquisitionPlan_SupermicroRefinesFirmwareInventoryFromHint(t *testing.T) {
|
|
signals := MatchSignals{
|
|
SystemManufacturer: "Supermicro",
|
|
ResourceHints: []string{
|
|
"/redfish/v1/UpdateService/Oem/Supermicro/FirmwareInventory",
|
|
"/redfish/v1/Managers/1/Oem/Supermicro/FanMode",
|
|
},
|
|
}
|
|
match := MatchProfiles(signals)
|
|
plan := BuildAcquisitionPlan(signals)
|
|
resolved := ResolveAcquisitionPlan(match, plan, DiscoveredResources{
|
|
ManagerPaths: []string{"/redfish/v1/Managers/1"},
|
|
}, signals)
|
|
joinedCritical := joinResolvedPaths(resolved.CriticalPaths)
|
|
if !containsJoinedPath(joinedCritical, "/redfish/v1/UpdateService/Oem/Supermicro/FirmwareInventory") {
|
|
t.Fatal("expected Supermicro refinement to add firmware inventory critical path")
|
|
}
|
|
if !containsJoinedPath(joinResolvedPaths(resolved.Plan.PlanBPaths), "/redfish/v1/UpdateService/Oem/Supermicro/FirmwareInventory") {
|
|
t.Fatal("expected Supermicro refinement to add firmware inventory plan-b path")
|
|
}
|
|
}
|
|
|
|
func TestResolveAcquisitionPlan_DellRefinesDiscoveredIDRACManager(t *testing.T) {
|
|
signals := MatchSignals{
|
|
SystemManufacturer: "Dell Inc.",
|
|
ServiceRootProduct: "iDRAC Redfish Service",
|
|
}
|
|
match := MatchProfiles(signals)
|
|
plan := BuildAcquisitionPlan(signals)
|
|
resolved := ResolveAcquisitionPlan(match, plan, DiscoveredResources{
|
|
ManagerPaths: []string{"/redfish/v1/Managers/1", "/redfish/v1/Managers/iDRAC.Embedded.1"},
|
|
}, signals)
|
|
joinedSeeds := joinResolvedPaths(resolved.SeedPaths)
|
|
joinedCritical := joinResolvedPaths(resolved.CriticalPaths)
|
|
if !containsJoinedPath(joinedSeeds, "/redfish/v1/Managers/iDRAC.Embedded.1") {
|
|
t.Fatal("expected Dell refinement to add discovered iDRAC manager seed path")
|
|
}
|
|
if !containsJoinedPath(joinedCritical, "/redfish/v1/Managers/iDRAC.Embedded.1") {
|
|
t.Fatal("expected Dell refinement to add discovered iDRAC manager critical path")
|
|
}
|
|
}
|
|
|
|
func TestBuildAnalysisDirectives_SupermicroEnablesVendorStorageFallbacks(t *testing.T) {
|
|
signals := MatchSignals{
|
|
SystemManufacturer: "Supermicro",
|
|
SystemModel: "SYS-821GE",
|
|
}
|
|
match := MatchProfiles(signals)
|
|
plan := ResolveAnalysisPlan(match, map[string]interface{}{
|
|
"/redfish/v1/Chassis/NVMeSSD.1.StorageBackplane/Drives": map[string]interface{}{},
|
|
}, DiscoveredResources{}, signals)
|
|
directives := plan.Directives
|
|
if !directives.EnableSupermicroNVMeBackplane {
|
|
t.Fatal("expected supermicro nvme backplane fallback")
|
|
}
|
|
}
|
|
|
|
func joinResolvedPaths(paths []string) string {
|
|
return "\n" + strings.Join(paths, "\n") + "\n"
|
|
}
|
|
|
|
func containsJoinedPath(joined, want string) bool {
|
|
return strings.Contains(joined, "\n"+want+"\n")
|
|
}
|
|
|
|
func TestBuildAnalysisDirectives_HGXEnablesGPUFallbacks(t *testing.T) {
|
|
signals := MatchSignals{
|
|
SystemManufacturer: "Supermicro",
|
|
SystemModel: "SYS-821GE-TNHR",
|
|
ChassisModel: "HGX B200",
|
|
ResourceHints: []string{"/redfish/v1/Systems/HGX_Baseboard_0", "/redfish/v1/Chassis/HGX_Chassis_0/PCIeDevices/GPU_SXM_1"},
|
|
}
|
|
match := MatchProfiles(signals)
|
|
plan := ResolveAnalysisPlan(match, map[string]interface{}{
|
|
"/redfish/v1/Systems/HGX_Baseboard_0/Processors/GPU_SXM_1": map[string]interface{}{"ProcessorType": "GPU"},
|
|
"/redfish/v1/Chassis/HGX_Chassis_0/PCIeDevices/GPU_SXM_1": map[string]interface{}{},
|
|
}, DiscoveredResources{
|
|
SystemPaths: []string{"/redfish/v1/Systems/HGX_Baseboard_0"},
|
|
}, signals)
|
|
directives := plan.Directives
|
|
if !directives.EnableProcessorGPUFallback {
|
|
t.Fatal("expected processor GPU fallback for hgx profile")
|
|
}
|
|
if !directives.EnableProcessorGPUChassisAlias {
|
|
t.Fatal("expected processor GPU chassis alias resolution for hgx profile")
|
|
}
|
|
if !directives.EnableGenericGraphicsControllerDedup {
|
|
t.Fatal("expected graphics-controller dedup for hgx profile")
|
|
}
|
|
}
|
|
|
|
func TestBuildAnalysisDirectives_MSIEnablesMSIChassisLookup(t *testing.T) {
|
|
signals := MatchSignals{
|
|
SystemManufacturer: "Micro-Star International Co., Ltd.",
|
|
}
|
|
match := MatchProfiles(signals)
|
|
plan := ResolveAnalysisPlan(match, map[string]interface{}{
|
|
"/redfish/v1/Systems/1/Processors/GPU1": map[string]interface{}{"ProcessorType": "GPU"},
|
|
"/redfish/v1/Chassis/GPU1": map[string]interface{}{},
|
|
}, DiscoveredResources{
|
|
SystemPaths: []string{"/redfish/v1/Systems/1"},
|
|
ChassisPaths: []string{"/redfish/v1/Chassis/GPU1"},
|
|
}, signals)
|
|
directives := plan.Directives
|
|
if !directives.EnableMSIProcessorGPUChassisLookup {
|
|
t.Fatal("expected MSI processor GPU chassis lookup")
|
|
}
|
|
}
|
|
|
|
func TestBuildAnalysisDirectives_SupermicroEnablesStorageRecovery(t *testing.T) {
|
|
signals := MatchSignals{
|
|
SystemManufacturer: "Supermicro",
|
|
}
|
|
match := MatchProfiles(signals)
|
|
plan := ResolveAnalysisPlan(match, map[string]interface{}{
|
|
"/redfish/v1/Chassis/1/Drives": map[string]interface{}{},
|
|
"/redfish/v1/Systems/1/Storage/IntelVROC": map[string]interface{}{},
|
|
"/redfish/v1/Systems/1/Storage/IntelVROC/Drives": map[string]interface{}{},
|
|
}, DiscoveredResources{}, signals)
|
|
directives := plan.Directives
|
|
if !directives.EnableStorageEnclosureRecovery {
|
|
t.Fatal("expected storage enclosure recovery for supermicro")
|
|
}
|
|
if !directives.EnableKnownStorageControllerRecovery {
|
|
t.Fatal("expected known storage controller recovery for supermicro")
|
|
}
|
|
}
|
|
|
|
func TestMatchProfiles_OrderingIsDeterministic(t *testing.T) {
|
|
signals := MatchSignals{
|
|
SystemManufacturer: "Micro-Star International Co., Ltd.",
|
|
ResourceHints: []string{"/redfish/v1/Chassis/GPU1"},
|
|
}
|
|
first := MatchProfiles(signals)
|
|
second := MatchProfiles(signals)
|
|
if len(first.Profiles) != len(second.Profiles) {
|
|
t.Fatalf("profile stack size differs across calls: %d vs %d", len(first.Profiles), len(second.Profiles))
|
|
}
|
|
for i := range first.Profiles {
|
|
if first.Profiles[i].Name() != second.Profiles[i].Name() {
|
|
t.Fatalf("profile ordering differs at index %d: %q vs %q", i, first.Profiles[i].Name(), second.Profiles[i].Name())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMatchProfiles_FallbackOrderingIsDeterministic(t *testing.T) {
|
|
signals := MatchSignals{ServiceRootProduct: "Unknown Redfish"}
|
|
first := MatchProfiles(signals)
|
|
second := MatchProfiles(signals)
|
|
if first.Mode != ModeFallback || second.Mode != ModeFallback {
|
|
t.Fatalf("expected fallback mode in both calls")
|
|
}
|
|
if len(first.Profiles) != len(second.Profiles) {
|
|
t.Fatalf("fallback profile stack size differs: %d vs %d", len(first.Profiles), len(second.Profiles))
|
|
}
|
|
for i := range first.Profiles {
|
|
if first.Profiles[i].Name() != second.Profiles[i].Name() {
|
|
t.Fatalf("fallback profile ordering differs at index %d: %q vs %q", i, first.Profiles[i].Name(), second.Profiles[i].Name())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMatchProfiles_FallbackOnlySelectsSafeProfiles(t *testing.T) {
|
|
match := MatchProfiles(MatchSignals{ServiceRootProduct: "Unknown Generic Redfish Server"})
|
|
if match.Mode != ModeFallback {
|
|
t.Fatalf("expected fallback mode, got %q", match.Mode)
|
|
}
|
|
for _, profile := range match.Profiles {
|
|
if !profile.SafeForFallback() {
|
|
t.Fatalf("fallback mode included non-safe profile %q", profile.Name())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuildAnalysisDirectives_GenericMatchedKeepsFallbacksDisabled(t *testing.T) {
|
|
match := MatchResult{
|
|
Mode: ModeMatched,
|
|
Profiles: []Profile{genericProfile()},
|
|
}
|
|
directives := ResolveAnalysisPlan(match, nil, DiscoveredResources{}, MatchSignals{}).Directives
|
|
if directives.EnableProcessorGPUFallback {
|
|
t.Fatal("did not expect processor GPU fallback for generic matched profile")
|
|
}
|
|
if directives.EnableSupermicroNVMeBackplane {
|
|
t.Fatal("did not expect supermicro nvme fallback for generic matched profile")
|
|
}
|
|
if directives.EnableGenericGraphicsControllerDedup {
|
|
t.Fatal("did not expect generic graphics-controller dedup for generic matched profile")
|
|
}
|
|
}
|