|
- package control
-
- import (
- "bytes"
- "encoding/json"
- "errors"
- "net/http"
- "net/http/httptest"
- "testing"
-
- cfgpkg "github.com/jan/fm-rds-tx/internal/config"
- )
-
- func TestHealthz(t *testing.T) {
- srv := NewServer(cfgpkg.Default())
- rec := httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/healthz", nil))
- if rec.Code != 200 {
- t.Fatalf("status: %d", rec.Code)
- }
- }
-
- func TestStatus(t *testing.T) {
- srv := NewServer(cfgpkg.Default())
- rec := httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/status", nil))
- if rec.Code != 200 {
- t.Fatalf("status: %d", rec.Code)
- }
- var body map[string]any
- json.Unmarshal(rec.Body.Bytes(), &body)
- if body["service"] != "fm-rds-tx" {
- t.Fatal("missing service")
- }
- if _, ok := body["preEmphasisTauUS"]; !ok {
- t.Fatal("missing preEmphasisTauUS")
- }
- }
-
- func TestStatusReportsRuntimeIndicator(t *testing.T) {
- srv := NewServer(cfgpkg.Default())
- srv.SetTXController(&fakeTXController{stats: map[string]any{"runtimeIndicator": "degraded", "runtimeAlert": "late buffers"}})
- rec := httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/status", nil))
- if rec.Code != 200 {
- t.Fatalf("status: %d", rec.Code)
- }
- var body map[string]any
- json.Unmarshal(rec.Body.Bytes(), &body)
- if body["runtimeIndicator"] != "degraded" {
- t.Fatalf("expected runtimeIndicator degraded, got %v", body["runtimeIndicator"])
- }
- if body["runtimeAlert"] != "late buffers" {
- t.Fatalf("expected runtimeAlert late buffers, got %v", body["runtimeAlert"])
- }
- }
-
- func TestDryRunEndpoint(t *testing.T) {
- srv := NewServer(cfgpkg.Default())
- rec := httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/dry-run", nil))
- if rec.Code != 200 {
- t.Fatalf("status: %d", rec.Code)
- }
- var body map[string]any
- json.Unmarshal(rec.Body.Bytes(), &body)
- if body["mode"] != "dry-run" {
- t.Fatal("wrong mode")
- }
- }
-
- func TestConfigPatch(t *testing.T) {
- srv := NewServer(cfgpkg.Default())
- body := []byte(`{"toneLeftHz":900,"radioText":"hello world","preEmphasisTauUS":75}`)
- rec := httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/config", bytes.NewReader(body)))
- if rec.Code != 200 {
- t.Fatalf("status: %d body=%s", rec.Code, rec.Body.String())
- }
- }
-
- func TestRuntimeWithoutDriver(t *testing.T) {
- srv := NewServer(cfgpkg.Default())
- rec := httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/runtime", nil))
- if rec.Code != 200 {
- t.Fatalf("status: %d", rec.Code)
- }
- }
-
- func TestTXStartWithoutController(t *testing.T) {
- srv := NewServer(cfgpkg.Default())
- rec := httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/tx/start", nil))
- if rec.Code != http.StatusServiceUnavailable {
- t.Fatalf("expected 503, got %d", rec.Code)
- }
- }
-
- func TestConfigPatchUpdatesSnapshot(t *testing.T) {
- srv := NewServer(cfgpkg.Default())
- srv.SetTXController(&fakeTXController{})
-
- rec := httptest.NewRecorder()
- body := []byte(`{"outputDrive":1.2}`)
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/config", bytes.NewReader(body)))
- if rec.Code != 200 {
- t.Fatalf("status: %d", rec.Code)
- }
- var resp map[string]any
- if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
- t.Fatalf("unmarshal response: %v", err)
- }
- if live, ok := resp["live"].(bool); !ok || !live {
- t.Fatalf("expected live true, got %v", resp["live"])
- }
-
- rec = httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/config", nil))
- var cfg cfgpkg.Config
- if err := json.NewDecoder(rec.Body).Decode(&cfg); err != nil {
- t.Fatalf("decode config: %v", err)
- }
- if cfg.FM.OutputDrive != 1.2 {
- t.Fatalf("expected snapshot to reflect new drive, got %v", cfg.FM.OutputDrive)
- }
- }
-
- func TestConfigPatchEngineRejectsDoesNotUpdateSnapshot(t *testing.T) {
- srv := NewServer(cfgpkg.Default())
- srv.SetTXController(&fakeTXController{updateErr: errors.New("boom")})
-
- body := []byte(`{"outputDrive":2.2}`)
- rec := httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodPost, "/config", bytes.NewReader(body)))
- if rec.Code != http.StatusBadRequest {
- t.Fatalf("expected 400, got %d", rec.Code)
- }
-
- rec = httptest.NewRecorder()
- srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/config", nil))
- var cfg cfgpkg.Config
- if err := json.NewDecoder(rec.Body).Decode(&cfg); err != nil {
- t.Fatalf("decode config: %v", err)
- }
- if cfg.FM.OutputDrive != cfgpkg.Default().FM.OutputDrive {
- t.Fatalf("expected snapshot untouched, got %v", cfg.FM.OutputDrive)
- }
- }
-
- type fakeTXController struct {
- updateErr error
- stats map[string]any
- }
-
- func (f *fakeTXController) StartTX() error { return nil }
- func (f *fakeTXController) StopTX() error { return nil }
- func (f *fakeTXController) TXStats() map[string]any {
- if f.stats != nil {
- return f.stats
- }
- return map[string]any{}
- }
- func (f *fakeTXController) UpdateConfig(_ LivePatch) error { return f.updateErr }
|