| @@ -3,24 +3,28 @@ package main | |||
| import "sdr-wideband-suite/internal/pipeline" | |||
| type compactDecision struct { | |||
| ID int64 `json:"id"` | |||
| Class string `json:"class,omitempty"` | |||
| Record bool `json:"record"` | |||
| Decode bool `json:"decode"` | |||
| Reason string `json:"reason,omitempty"` | |||
| Candidate pipeline.Candidate `json:"candidate"` | |||
| ID int64 `json:"id"` | |||
| Class string `json:"class,omitempty"` | |||
| Record bool `json:"record"` | |||
| Decode bool `json:"decode"` | |||
| Reason string `json:"reason,omitempty"` | |||
| RecordAdmission *pipeline.PriorityAdmission `json:"record_admission,omitempty"` | |||
| DecodeAdmission *pipeline.PriorityAdmission `json:"decode_admission,omitempty"` | |||
| Candidate pipeline.Candidate `json:"candidate"` | |||
| } | |||
| func compactDecisions(decisions []pipeline.SignalDecision) []compactDecision { | |||
| out := make([]compactDecision, 0, len(decisions)) | |||
| for _, d := range decisions { | |||
| out = append(out, compactDecision{ | |||
| ID: d.Candidate.ID, | |||
| Class: d.Class, | |||
| Record: d.ShouldRecord, | |||
| Decode: d.ShouldAutoDecode, | |||
| Reason: d.Reason, | |||
| Candidate: d.Candidate, | |||
| ID: d.Candidate.ID, | |||
| Class: d.Class, | |||
| Record: d.ShouldRecord, | |||
| Decode: d.ShouldAutoDecode, | |||
| Reason: d.Reason, | |||
| RecordAdmission: d.RecordAdmission, | |||
| DecodeAdmission: d.DecodeAdmission, | |||
| Candidate: d.Candidate, | |||
| }) | |||
| } | |||
| return out | |||
| @@ -1,6 +1,7 @@ | |||
| package pipeline | |||
| import ( | |||
| "strings" | |||
| "testing" | |||
| "time" | |||
| ) | |||
| @@ -25,7 +26,7 @@ func TestDecisionQueueDropsByBudget(t *testing.T) { | |||
| allowed++ | |||
| continue | |||
| } | |||
| if d.Reason != DecisionReasonQueueRecord && d.Reason != DecisionReasonQueueDecode { | |||
| if !strings.HasPrefix(d.Reason, DecisionReasonQueueRecord) && !strings.HasPrefix(d.Reason, DecisionReasonQueueDecode) { | |||
| t.Fatalf("unexpected decision reason: %s", d.Reason) | |||
| } | |||
| } | |||
| @@ -56,6 +57,12 @@ func TestDecisionQueueEnforcesBudgets(t *testing.T) { | |||
| if decisions[2].ShouldRecord { | |||
| t.Fatalf("expected mid SNR decision to be budgeted off by record budget") | |||
| } | |||
| if decisions[1].RecordAdmission == nil || decisions[1].RecordAdmission.Class != AdmissionClassAdmit { | |||
| t.Fatalf("expected admitted record admission, got %+v", decisions[1].RecordAdmission) | |||
| } | |||
| if decisions[0].RecordAdmission == nil || decisions[0].RecordAdmission.Class != AdmissionClassDefer { | |||
| t.Fatalf("expected deferred record admission, got %+v", decisions[0].RecordAdmission) | |||
| } | |||
| } | |||
| func TestDecisionQueueHoldKeepsSelection(t *testing.T) { | |||
| @@ -84,4 +91,7 @@ func TestDecisionQueueHoldKeepsSelection(t *testing.T) { | |||
| if decisions[0].ShouldRecord || decisions[0].ShouldAutoDecode { | |||
| t.Fatalf("expected candidate 1 to remain queued behind hold") | |||
| } | |||
| if decisions[1].RecordAdmission == nil || decisions[1].RecordAdmission.Class != AdmissionClassHold { | |||
| t.Fatalf("expected record admission hold class, got %+v", decisions[1].RecordAdmission) | |||
| } | |||
| } | |||
| @@ -287,10 +287,16 @@ func TestAdmitRefinementPlanAppliesBudget(t *testing.T) { | |||
| if item2 == nil || item2.Status != RefinementStatusAdmitted { | |||
| t.Fatalf("expected candidate 2 admitted, got %+v", item2) | |||
| } | |||
| if item2.Admission == nil || item2.Admission.Class != AdmissionClassAdmit || item2.Admission.Tier == "" { | |||
| t.Fatalf("expected admission class/tier on admitted item, got %+v", item2.Admission) | |||
| } | |||
| item3 := findWorkItem(res.WorkItems, 3) | |||
| if item3 == nil || item3.Status != RefinementStatusSkipped { | |||
| t.Fatalf("expected candidate 3 skipped, got %+v", item3) | |||
| } | |||
| if item3.Admission == nil || item3.Admission.Class != AdmissionClassDefer { | |||
| t.Fatalf("expected deferred admission class on skipped item, got %+v", item3.Admission) | |||
| } | |||
| } | |||
| func TestAdmitRefinementPlanDisplacedByHold(t *testing.T) { | |||
| @@ -309,6 +315,9 @@ func TestAdmitRefinementPlanDisplacedByHold(t *testing.T) { | |||
| if item2 == nil || item2.Status != RefinementStatusDisplaced { | |||
| t.Fatalf("expected higher priority candidate displaced, got %+v", item2) | |||
| } | |||
| if item2.Admission == nil || item2.Admission.Class != AdmissionClassDisplace { | |||
| t.Fatalf("expected displaced admission class, got %+v", item2.Admission) | |||
| } | |||
| } | |||
| func TestRefinementStrategyUsesProfile(t *testing.T) { | |||