Go-based FM stereo transmitter with RDS, Windows-first and cross-platform
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

124 行
4.2KB

  1. package control
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "net/http"
  7. "net/http/httptest"
  8. "testing"
  9. cfgpkg "github.com/jan/fm-rds-tx/internal/config"
  10. )
  11. func TestHealthz(t *testing.T) {
  12. srv := NewServer(cfgpkg.Default())
  13. rec := httptest.NewRecorder()
  14. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/healthz", nil))
  15. if rec.Code != 200 { t.Fatalf("status: %d", rec.Code) }
  16. }
  17. func TestStatus(t *testing.T) {
  18. srv := NewServer(cfgpkg.Default())
  19. rec := httptest.NewRecorder()
  20. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/status", nil))
  21. if rec.Code != 200 { t.Fatalf("status: %d", rec.Code) }
  22. var body map[string]any
  23. json.Unmarshal(rec.Body.Bytes(), &body)
  24. if body["service"] != "fm-rds-tx" { t.Fatal("missing service") }
  25. if _, ok := body["preEmphasisTauUS"]; !ok { t.Fatal("missing preEmphasisTauUS") }
  26. }
  27. func TestDryRunEndpoint(t *testing.T) {
  28. srv := NewServer(cfgpkg.Default())
  29. rec := httptest.NewRecorder()
  30. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/dry-run", nil))
  31. if rec.Code != 200 { t.Fatalf("status: %d", rec.Code) }
  32. var body map[string]any
  33. json.Unmarshal(rec.Body.Bytes(), &body)
  34. if body["mode"] != "dry-run" { t.Fatal("wrong mode") }
  35. }
  36. func TestConfigPatch(t *testing.T) {
  37. srv := NewServer(cfgpkg.Default())
  38. body := []byte(`{"toneLeftHz":900,"radioText":"hello world","preEmphasisTauUS":75}`)
  39. rec := httptest.NewRecorder()
  40. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/config", bytes.NewReader(body)))
  41. if rec.Code != 200 { t.Fatalf("status: %d body=%s", rec.Code, rec.Body.String()) }
  42. }
  43. func TestRuntimeWithoutDriver(t *testing.T) {
  44. srv := NewServer(cfgpkg.Default())
  45. rec := httptest.NewRecorder()
  46. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/runtime", nil))
  47. if rec.Code != 200 { t.Fatalf("status: %d", rec.Code) }
  48. }
  49. func TestTXStartWithoutController(t *testing.T) {
  50. srv := NewServer(cfgpkg.Default())
  51. rec := httptest.NewRecorder()
  52. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/tx/start", nil))
  53. if rec.Code != http.StatusServiceUnavailable { t.Fatalf("expected 503, got %d", rec.Code) }
  54. }
  55. func TestConfigPatchUpdatesSnapshot(t *testing.T) {
  56. srv := NewServer(cfgpkg.Default())
  57. srv.SetTXController(&fakeTXController{})
  58. rec := httptest.NewRecorder()
  59. body := []byte(`{"outputDrive":1.2}`)
  60. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/config", bytes.NewReader(body)))
  61. if rec.Code != 200 {
  62. t.Fatalf("status: %d", rec.Code)
  63. }
  64. var resp map[string]any
  65. if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
  66. t.Fatalf("unmarshal response: %v", err)
  67. }
  68. if live, ok := resp["live"].(bool); !ok || !live {
  69. t.Fatalf("expected live true, got %v", resp["live"])
  70. }
  71. rec = httptest.NewRecorder()
  72. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/config", nil))
  73. var cfg cfgpkg.Config
  74. if err := json.NewDecoder(rec.Body).Decode(&cfg); err != nil {
  75. t.Fatalf("decode config: %v", err)
  76. }
  77. if cfg.FM.OutputDrive != 1.2 {
  78. t.Fatalf("expected snapshot to reflect new drive, got %v", cfg.FM.OutputDrive)
  79. }
  80. }
  81. func TestConfigPatchEngineRejectsDoesNotUpdateSnapshot(t *testing.T) {
  82. srv := NewServer(cfgpkg.Default())
  83. srv.SetTXController(&fakeTXController{updateErr: errors.New("boom")})
  84. body := []byte(`{"outputDrive":2.2}`)
  85. rec := httptest.NewRecorder()
  86. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/config", bytes.NewReader(body)))
  87. if rec.Code != http.StatusBadRequest {
  88. t.Fatalf("expected 400, got %d", rec.Code)
  89. }
  90. rec = httptest.NewRecorder()
  91. srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/config", nil))
  92. var cfg cfgpkg.Config
  93. if err := json.NewDecoder(rec.Body).Decode(&cfg); err != nil {
  94. t.Fatalf("decode config: %v", err)
  95. }
  96. if cfg.FM.OutputDrive != cfgpkg.Default().FM.OutputDrive {
  97. t.Fatalf("expected snapshot untouched, got %v", cfg.FM.OutputDrive)
  98. }
  99. }
  100. type fakeTXController struct {
  101. updateErr error
  102. }
  103. func (f *fakeTXController) StartTX() error { return nil }
  104. func (f *fakeTXController) StopTX() error { return nil }
  105. func (f *fakeTXController) TXStats() map[string]any { return map[string]any{} }
  106. func (f *fakeTXController) UpdateConfig(_ LivePatch) error { return f.updateErr }