128 lines
4.0 KiB
Go
128 lines
4.0 KiB
Go
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")
|
|
}
|
|
|
|
func TestBuildUploads_RemovesAudioLeftBehindByACrash(t *testing.T) {
|
|
cfg := uploadCfg(t, true)
|
|
require.NoError(t, os.MkdirAll(cfg.UploadTmpDir, 0o700))
|
|
leftovers := []string{"upload-123", "wav-456"}
|
|
for _, n := range leftovers {
|
|
require.NoError(t, os.WriteFile(filepath.Join(cfg.UploadTmpDir, n), []byte("audio"), 0o600))
|
|
}
|
|
unrelated := filepath.Join(cfg.UploadTmpDir, "someone-elses-file")
|
|
require.NoError(t, os.WriteFile(unrelated, []byte("keep"), 0o600))
|
|
|
|
_, _, err := buildUploads(context.Background(), cfg, &fakeUploadsStore{}, quietLog())
|
|
|
|
require.NoError(t, err)
|
|
for _, n := range leftovers {
|
|
_, err := os.Stat(filepath.Join(cfg.UploadTmpDir, n))
|
|
assert.True(t, os.IsNotExist(err), "%s: audio is never retained, so a spooled file from a crashed run must not survive start-up", n)
|
|
}
|
|
_, err = os.Stat(unrelated)
|
|
assert.NoError(t, err, "only our own spool files are removed")
|
|
}
|