Go-based FM stereo transmitter with RDS, Windows-first and cross-platform
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

121 Zeilen
3.4KB

  1. package app
  2. import (
  3. "context"
  4. "errors"
  5. "testing"
  6. "time"
  7. cfgpkg "github.com/jan/fm-rds-tx/internal/config"
  8. "github.com/jan/fm-rds-tx/internal/output"
  9. "github.com/jan/fm-rds-tx/internal/platform"
  10. )
  11. func TestFaultSeverityString(t *testing.T) {
  12. cases := []struct {
  13. severity FaultSeverity
  14. want string
  15. }{
  16. {FaultSeverityWarn, "warn"},
  17. {FaultSeverityDegraded, "degraded"},
  18. {FaultSeverityMuted, "muted"},
  19. {FaultSeverityFaulted, "faulted"},
  20. {FaultSeverity(99), "unknown"},
  21. }
  22. for _, tc := range cases {
  23. t.Run(tc.want, func(t *testing.T) {
  24. if got := tc.severity.String(); got != tc.want {
  25. t.Fatalf("expected %s, got %s", tc.want, got)
  26. }
  27. if txt, _ := tc.severity.MarshalText(); string(txt) != tc.want {
  28. t.Fatalf("MarshalText mismatch: want %s, got %s", tc.want, txt)
  29. }
  30. })
  31. }
  32. }
  33. func TestEngineRecordsQueueCriticalFault(t *testing.T) {
  34. e := NewEngine(cfgpkg.Default(), platform.NewSimulatedDriver(nil))
  35. e.setRuntimeState(RuntimeStateRunning)
  36. queue := output.QueueStats{Depth: 3, Health: output.QueueHealthCritical}
  37. for i := 0; i < queueCriticalStreakThreshold; i++ {
  38. e.evaluateRuntimeState(queue, false)
  39. }
  40. last := e.LastFault()
  41. if last == nil {
  42. t.Fatal("expected fault recorded, got nil")
  43. }
  44. if last.Reason != FaultReasonQueueCritical {
  45. t.Fatalf("expected queue critical reason, got %s", last.Reason)
  46. }
  47. if last.Severity != FaultSeverityDegraded {
  48. t.Fatalf("expected degraded severity, got %s", last.Severity)
  49. }
  50. }
  51. func TestEngineRecordsLateBufferFault(t *testing.T) {
  52. e := NewEngine(cfgpkg.Default(), platform.NewSimulatedDriver(nil))
  53. e.setRuntimeState(RuntimeStateRunning)
  54. queue := output.QueueStats{Depth: 5, Health: output.QueueHealthNormal}
  55. e.evaluateRuntimeState(queue, true)
  56. last := e.LastFault()
  57. if last == nil {
  58. t.Fatal("expected fault recorded for late buffers")
  59. }
  60. if last.Reason != FaultReasonLateBuffers {
  61. t.Fatalf("expected late buffer reason, got %s", last.Reason)
  62. }
  63. if last.Severity != FaultSeverityWarn {
  64. t.Fatalf("expected warn severity, got %s", last.Severity)
  65. }
  66. }
  67. func TestEngineRecordsWriteTimeoutFault(t *testing.T) {
  68. cfg := cfgpkg.Default()
  69. driver := platform.NewSimulatedDriver(&writeErrorBackend{})
  70. eng := NewEngine(cfg, driver)
  71. eng.SetChunkDuration(10 * time.Millisecond)
  72. ctx := context.Background()
  73. if err := eng.Start(ctx); err != nil {
  74. t.Fatalf("start: %v", err)
  75. }
  76. time.Sleep(120 * time.Millisecond)
  77. if err := eng.Stop(ctx); err != nil {
  78. t.Fatalf("stop: %v", err)
  79. }
  80. last := eng.LastFault()
  81. if last == nil {
  82. t.Fatal("expected write timeout fault")
  83. }
  84. if last.Reason != FaultReasonWriteTimeout {
  85. t.Fatalf("expected writeTimeout reason, got %s", last.Reason)
  86. }
  87. if last.Severity != FaultSeverityWarn {
  88. t.Fatalf("expected warn severity, got %s", last.Severity)
  89. }
  90. }
  91. type writeErrorBackend struct{}
  92. func (writeErrorBackend) Configure(context.Context, output.BackendConfig) error { return nil }
  93. func (writeErrorBackend) Write(context.Context, *output.CompositeFrame) (int, error) {
  94. return 0, errors.New("write timeout")
  95. }
  96. func (writeErrorBackend) Flush(context.Context) error { return nil }
  97. func (writeErrorBackend) Close(context.Context) error { return nil }
  98. func (writeErrorBackend) Info() output.BackendInfo {
  99. return output.BackendInfo{
  100. Name: "write-error",
  101. Description: "backend that rejects writes",
  102. Capabilities: output.BackendCapabilities{
  103. SupportsComposite: true,
  104. },
  105. }
  106. }