Files
minstrel/internal/api/client_assets_test.go
T
bvandeusen 14d7678624 fix: CI lint errors after #397 commits
- flutter analyze: Riverpod 3 dropped StateProvider; replaced
  _dismissedVersionsProvider with a small Notifier<Set<String>>
  + NotifierProvider, mutating via an `add(version)` method.
  Public API (shouldShowUpdateBannerProvider, dismissUpdateProvider)
  unchanged.
- golangci errcheck: defer f.Close() now wrapped in func() { _ = f.Close() }();
  os.Setenv calls in test helper switched to t.Setenv (cleaner — auto-restores
  on test cleanup, no manual Unsetenv needed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 20:01:43 -04:00

116 lines
3.7 KiB
Go

package api
import (
"encoding/json"
"io"
"log/slog"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
)
// withClientAPKDir points the handlers at a fresh temp dir for each
// test and restores the env var on cleanup. Returns the dir.
func withClientAPKDir(t *testing.T) string {
t.Helper()
dir := t.TempDir()
prev, hadPrev := os.LookupEnv("MINSTREL_CLIENT_APK_DIR")
t.Setenv("MINSTREL_CLIENT_APK_DIR", dir)
t.Cleanup(func() {
if hadPrev {
t.Setenv("MINSTREL_CLIENT_APK_DIR", prev)
}
// t.Setenv auto-restores the prior empty/unset state at end of
// test, so the !hadPrev branch needs no explicit Unsetenv.
})
return dir
}
func TestClientVersion_404WhenNoAPK(t *testing.T) {
withClientAPKDir(t)
h := &handlers{logger: slog.New(slog.NewTextHandler(io.Discard, nil))}
rr := httptest.NewRecorder()
h.handleClientVersion(rr, httptest.NewRequest(http.MethodGet, "/api/client/version", nil))
if rr.Code != http.StatusNotFound {
t.Errorf("want 404, got %d", rr.Code)
}
}
func TestClientVersion_404WhenAPKButNoVersion(t *testing.T) {
dir := withClientAPKDir(t)
if err := os.WriteFile(filepath.Join(dir, clientAPKFilename), []byte("fake apk"), 0o644); err != nil {
t.Fatal(err)
}
h := &handlers{logger: slog.New(slog.NewTextHandler(io.Discard, nil))}
rr := httptest.NewRecorder()
h.handleClientVersion(rr, httptest.NewRequest(http.MethodGet, "/api/client/version", nil))
if rr.Code != http.StatusNotFound {
t.Errorf("want 404, got %d", rr.Code)
}
}
func TestClientVersion_200WithBothFiles(t *testing.T) {
dir := withClientAPKDir(t)
body := []byte("fake apk content")
if err := os.WriteFile(filepath.Join(dir, clientAPKFilename), body, 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, clientVersionFile), []byte("v2026.05.10\n"), 0o644); err != nil {
t.Fatal(err)
}
h := &handlers{logger: slog.New(slog.NewTextHandler(io.Discard, nil))}
rr := httptest.NewRecorder()
h.handleClientVersion(rr, httptest.NewRequest(http.MethodGet, "/api/client/version", nil))
if rr.Code != http.StatusOK {
t.Fatalf("want 200, got %d (body: %s)", rr.Code, rr.Body.String())
}
var resp clientVersionResponse
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
t.Fatal(err)
}
if resp.Version != "v2026.05.10" {
t.Errorf("version: want trimmed v2026.05.10, got %q", resp.Version)
}
if resp.APKURL != "/api/client/apk" {
t.Errorf("apk_url: want /api/client/apk, got %q", resp.APKURL)
}
if resp.SizeBytes != int64(len(body)) {
t.Errorf("size_bytes: want %d, got %d", len(body), resp.SizeBytes)
}
}
func TestClientAPK_404WhenMissing(t *testing.T) {
withClientAPKDir(t)
h := &handlers{logger: slog.New(slog.NewTextHandler(io.Discard, nil))}
rr := httptest.NewRecorder()
h.handleClientAPK(rr, httptest.NewRequest(http.MethodGet, "/api/client/apk", nil))
if rr.Code != http.StatusNotFound {
t.Errorf("want 404, got %d", rr.Code)
}
}
func TestClientAPK_StreamsWithCorrectContentType(t *testing.T) {
dir := withClientAPKDir(t)
body := []byte("PK\x03\x04 fake apk bytes")
if err := os.WriteFile(filepath.Join(dir, clientAPKFilename), body, 0o644); err != nil {
t.Fatal(err)
}
h := &handlers{logger: slog.New(slog.NewTextHandler(io.Discard, nil))}
rr := httptest.NewRecorder()
h.handleClientAPK(rr, httptest.NewRequest(http.MethodGet, "/api/client/apk", nil))
if rr.Code != http.StatusOK {
t.Fatalf("want 200, got %d", rr.Code)
}
if got := rr.Header().Get("Content-Type"); got != "application/vnd.android.package-archive" {
t.Errorf("Content-Type: want application/vnd.android.package-archive, got %q", got)
}
if rr.Body.Len() != len(body) {
t.Errorf("body length: want %d, got %d", len(body), rr.Body.Len())
}
if got := rr.Body.Bytes(); string(got) != string(body) {
t.Errorf("body bytes mismatch")
}
}