Go-based FM stereo transmitter with RDS, Windows-first and cross-platform
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
2.8KB

  1. package output
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. )
  7. func TestFrameQueuePushPop(t *testing.T) {
  8. q := NewFrameQueue(2)
  9. ctx := context.Background()
  10. frame := &CompositeFrame{Sequence: 1}
  11. if err := q.Push(ctx, frame); err != nil {
  12. t.Fatalf("push failed: %v", err)
  13. }
  14. if got := q.Depth(); got != 1 {
  15. t.Fatalf("expected depth 1, got %d", got)
  16. }
  17. if got := q.FillLevel(); got <= 0 || got >= 1 {
  18. t.Fatalf("unexpected fill level: %f", got)
  19. }
  20. popped, err := q.Pop(ctx)
  21. if err != nil {
  22. t.Fatalf("pop failed: %v", err)
  23. }
  24. if popped != frame {
  25. t.Fatal("popped frame differs from pushed frame")
  26. }
  27. if q.Depth() != 0 {
  28. t.Fatalf("expected depth 0 after pop, got %d", q.Depth())
  29. }
  30. stats := q.Stats()
  31. if stats.HighWaterMark == 0 {
  32. t.Fatal("expected high water mark to track push")
  33. }
  34. if stats.LowWaterMark != 0 {
  35. t.Fatalf("expected low water mark 0, got %d", stats.LowWaterMark)
  36. }
  37. }
  38. func TestFrameQueuePushTimeout(t *testing.T) {
  39. q := NewFrameQueue(1)
  40. ctx := context.Background()
  41. frame := &CompositeFrame{Sequence: 42}
  42. if err := q.Push(ctx, frame); err != nil {
  43. t.Fatalf("initial push: %v", err)
  44. }
  45. shortCtx, cancel := context.WithTimeout(ctx, 5*time.Millisecond)
  46. defer cancel()
  47. if err := q.Push(shortCtx, frame); err == nil {
  48. t.Fatalf("expected timeout when pushing into full queue")
  49. }
  50. stats := q.Stats()
  51. if stats.PushTimeouts == 0 {
  52. t.Fatalf("expected push timeout counter to increment, got %d", stats.PushTimeouts)
  53. }
  54. _, _ = q.Pop(ctx)
  55. }
  56. func TestFrameQueueCounters(t *testing.T) {
  57. q := NewFrameQueue(1)
  58. q.RecordDrop()
  59. q.RecordRepeat()
  60. q.RecordMute()
  61. stats := q.Stats()
  62. if stats.DroppedFrames != 1 {
  63. t.Fatalf("expected 1 drop, got %d", stats.DroppedFrames)
  64. }
  65. if stats.RepeatedFrames != 1 {
  66. t.Fatalf("expected 1 repeat, got %d", stats.RepeatedFrames)
  67. }
  68. if stats.MutedFrames != 1 {
  69. t.Fatalf("expected 1 mute, got %d", stats.MutedFrames)
  70. }
  71. }
  72. func TestFrameQueueHealthIndicator(t *testing.T) {
  73. q := NewFrameQueue(4)
  74. ctx := context.Background()
  75. stats := q.Stats()
  76. if stats.Health != QueueHealthCritical {
  77. t.Fatalf("expected initial health critical, got %s", stats.Health)
  78. }
  79. push := func(seq int) {
  80. frame := &CompositeFrame{Sequence: seq}
  81. if err := q.Push(ctx, frame); err != nil {
  82. t.Fatalf("push %d failed: %v", seq, err)
  83. }
  84. }
  85. push(1)
  86. stats = q.Stats()
  87. if stats.Health != QueueHealthLow {
  88. t.Fatalf("expected low after one frame, got %s", stats.Health)
  89. }
  90. push(2)
  91. stats = q.Stats()
  92. if stats.Health != QueueHealthLow {
  93. t.Fatalf("expected low at 50%% fill, got %s", stats.Health)
  94. }
  95. push(3)
  96. stats = q.Stats()
  97. if stats.Health != QueueHealthNormal {
  98. t.Fatalf("expected normal once queue has ~75%% fill, got %s", stats.Health)
  99. }
  100. for q.Depth() > 0 {
  101. if _, err := q.Pop(ctx); err != nil {
  102. t.Fatalf("cleanup pop failed: %v", err)
  103. }
  104. }
  105. }