From 3e802adade640be4ed5ea600a3328eec61c74f09 Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 1 Oct 2026 16:55:51 +0200 Subject: [PATCH] test(cmd): buildUploads wiring -- off by default, sweep first, private spool (red) Red: buildUploads is undefined. Co-Authored-By: Claude Sonnet 5.5 --- cmd/tapir/uploads_test.go | 106 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 cmd/tapir/uploads_test.go diff --git a/cmd/tapir/uploads_test.go b/cmd/tapir/uploads_test.go new file mode 100644 index 0000000..6d33f92 --- /dev/null +++ b/cmd/tapir/uploads_test.go @@ -0,0 +1,106 @@ +package main + +import ( + "context" + "errors" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "git.d-ma.be/mathias/tapir/internal/config" + "git.d-ma.be/mathias/tapir/internal/domain" +) + +// fakeUploadsStore satisfies the store surface buildUploads needs, and counts the +// start-up sweep. +type fakeUploadsStore struct { + sweeps int + sweepErr error +} + +func (f *fakeUploadsStore) CreateUpload(context.Context, string, string) (string, error) { + return "id", nil +} + +func (f *fakeUploadsStore) FailUpload(context.Context, string, string, domain.UploadErrorKind) error { + return nil +} + +func (f *fakeUploadsStore) StartTranscribing(context.Context, string, string) error { return nil } + +func (f *fakeUploadsStore) CompleteUpload(context.Context, string, string, domain.Transcription) error { + return nil +} + +func (f *fakeUploadsStore) FailInterruptedUploads(context.Context) (int, error) { + f.sweeps++ + return 2, f.sweepErr +} + +func uploadCfg(t *testing.T, enabled bool) config.Config { + t.Helper() + var cfg config.Config + cfg.GatewayURL = "http://gateway.invalid/v1" + cfg.UploadsEnabled = enabled + cfg.UploadMaxBytes = 200 << 20 + cfg.UploadTmpDir = filepath.Join(t.TempDir(), "spool") + cfg.TranscribeModel = "iguana/kb-whisper" + cfg.TranscribeFallbackModel = "berget/kb-whisper" + return cfg +} + +func TestBuildUploads_DisabledMountsNothingAndSweepsNothing(t *testing.T) { + st := &fakeUploadsStore{} + + in, w, err := buildUploads(context.Background(), uploadCfg(t, false), st, quietLog()) + + require.NoError(t, err) + assert.Nil(t, in, "a typed-nil Intake must never reach web.App.Uploads: it would mount the routes over nothing") + assert.Nil(t, w) + assert.Zero(t, st.sweeps) +} + +func TestBuildUploads_EnabledFailsInterruptedRowsBeforeAnythingElseStarts(t *testing.T) { + st := &fakeUploadsStore{} + + in, w, err := buildUploads(context.Background(), uploadCfg(t, true), st, quietLog()) + + require.NoError(t, err) + require.NotNil(t, in) + require.NotNil(t, w) + assert.Equal(t, 1, st.sweeps, + "audio is not retained, so rows left queued/transcribing by a restart can never resume: fail them at start-up, not never") +} + +func TestBuildUploads_SweepFailureStopsStartup(t *testing.T) { + st := &fakeUploadsStore{sweepErr: errors.New("db down")} + + _, _, err := buildUploads(context.Background(), uploadCfg(t, true), st, quietLog()) + + require.Error(t, err) + assert.Contains(t, err.Error(), "db down") +} + +func TestBuildUploads_CreatesTheSpoolDirectoryPrivately(t *testing.T) { + cfg := uploadCfg(t, true) + + _, _, err := buildUploads(context.Background(), cfg, &fakeUploadsStore{}, quietLog()) + + require.NoError(t, err) + info, err := os.Stat(cfg.UploadTmpDir) + require.NoError(t, err) + assert.True(t, info.IsDir()) + assert.Equal(t, os.FileMode(0o700), info.Mode().Perm(), "spooled audio is private third-party content") +} + +func TestBuildUploads_EnabledWithoutAGatewayIsAnError(t *testing.T) { + cfg := uploadCfg(t, true) + cfg.GatewayURL = "" + + _, _, err := buildUploads(context.Background(), cfg, &fakeUploadsStore{}, quietLog()) + + assert.Error(t, err, "uploads on with nowhere to transcribe must fail loudly at start-up, not at the first upload") +}