Wideband autonomous SDR analysis engine forked from sdr-visual-suite
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

88 líneas
3.2KB

  1. package pipeline
  2. import (
  3. "testing"
  4. "time"
  5. )
  6. func TestDecisionQueueDropsByBudget(t *testing.T) {
  7. arbiter := NewArbiter()
  8. decisions := []SignalDecision{
  9. {Candidate: Candidate{ID: 1, SNRDb: 12}, ShouldRecord: true, ShouldAutoDecode: true},
  10. {Candidate: Candidate{ID: 2, SNRDb: 10}, ShouldRecord: true, ShouldAutoDecode: true},
  11. }
  12. budget := BudgetModel{
  13. Record: BudgetQueue{Max: 1},
  14. Decode: BudgetQueue{Max: 1},
  15. }
  16. stats := arbiter.ApplyDecisions(decisions, budget, time.Now(), Policy{DecisionHoldMs: 250})
  17. if stats.RecordDropped == 0 || stats.DecodeDropped == 0 {
  18. t.Fatalf("expected drops by budget, got %+v", stats)
  19. }
  20. allowed := 0
  21. for _, d := range decisions {
  22. if d.ShouldRecord || d.ShouldAutoDecode {
  23. allowed++
  24. continue
  25. }
  26. if d.Reason != DecisionReasonQueueRecord && d.Reason != DecisionReasonQueueDecode {
  27. t.Fatalf("unexpected decision reason: %s", d.Reason)
  28. }
  29. }
  30. if allowed != 1 {
  31. t.Fatalf("expected 1 decision allowed, got %d", allowed)
  32. }
  33. }
  34. func TestDecisionQueueEnforcesBudgets(t *testing.T) {
  35. decisions := []SignalDecision{
  36. {Candidate: Candidate{ID: 1, SNRDb: 5}, ShouldRecord: true, ShouldAutoDecode: true},
  37. {Candidate: Candidate{ID: 2, SNRDb: 15}, ShouldRecord: true, ShouldAutoDecode: true},
  38. {Candidate: Candidate{ID: 3, SNRDb: 10}, ShouldRecord: true, ShouldAutoDecode: false},
  39. }
  40. arbiter := NewArbiter()
  41. policy := Policy{SignalPriorities: []string{"digital"}, MaxRecordingStreams: 1, MaxDecodeJobs: 1}
  42. budget := BudgetModelFromPolicy(policy)
  43. stats := arbiter.ApplyDecisions(decisions, budget, time.Now(), policy)
  44. if stats.RecordSelected != 1 || stats.DecodeSelected != 1 {
  45. t.Fatalf("unexpected counts: record=%d decode=%d", stats.RecordSelected, stats.DecodeSelected)
  46. }
  47. if !decisions[1].ShouldRecord || !decisions[1].ShouldAutoDecode {
  48. t.Fatalf("expected highest SNR decision to remain allowed")
  49. }
  50. if decisions[0].ShouldRecord || decisions[0].ShouldAutoDecode {
  51. t.Fatalf("expected lowest SNR decision to be budgeted off")
  52. }
  53. if decisions[2].ShouldRecord {
  54. t.Fatalf("expected mid SNR decision to be budgeted off by record budget")
  55. }
  56. }
  57. func TestDecisionQueueHoldKeepsSelection(t *testing.T) {
  58. arbiter := NewArbiter()
  59. policy := Policy{DecisionHoldMs: 500}
  60. budget := BudgetModel{Record: BudgetQueue{Max: 1}, Decode: BudgetQueue{Max: 1}}
  61. now := time.Now()
  62. decisions := []SignalDecision{
  63. {Candidate: Candidate{ID: 1, SNRDb: 5}, ShouldRecord: true, ShouldAutoDecode: true},
  64. {Candidate: Candidate{ID: 2, SNRDb: 15}, ShouldRecord: true, ShouldAutoDecode: true},
  65. }
  66. arbiter.ApplyDecisions(decisions, budget, now, policy)
  67. if !decisions[1].ShouldRecord || !decisions[1].ShouldAutoDecode {
  68. t.Fatalf("expected candidate 2 to be selected initially")
  69. }
  70. decisions = []SignalDecision{
  71. {Candidate: Candidate{ID: 1, SNRDb: 25}, ShouldRecord: true, ShouldAutoDecode: true},
  72. {Candidate: Candidate{ID: 2, SNRDb: 2}, ShouldRecord: true, ShouldAutoDecode: true},
  73. }
  74. arbiter.ApplyDecisions(decisions, budget, now.Add(100*time.Millisecond), policy)
  75. if !decisions[1].ShouldRecord || !decisions[1].ShouldAutoDecode {
  76. t.Fatalf("expected held candidate 2 to remain selected")
  77. }
  78. if decisions[0].ShouldRecord || decisions[0].ShouldAutoDecode {
  79. t.Fatalf("expected candidate 1 to remain queued behind hold")
  80. }
  81. }