package web_test // The language of a recording is chosen on the upload form (tapir#61). These drive the real // Router, Intake and Postgres store; the submitter is the process boundary and records the // job the worker would receive. import ( "bytes" "context" "mime/multipart" "net/http" "net/http/httptest" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "git.d-ma.be/mathias/tapir/internal/domain" ) // langReq builds an upload whose parts come in the order given: "title", "language" and // "file" (the file part always carries the same synthetic bytes). func langReq(t *testing.T, order []string, language string) *http.Request { t.Helper() var buf bytes.Buffer mw := multipart.NewWriter(&buf) for _, part := range order { switch part { case "title": require.NoError(t, mw.WriteField("title", "m")) case "language": require.NoError(t, mw.WriteField("language", language)) case "file": fw, err := mw.CreateFormFile("file", "m.wav") require.NoError(t, err) _, err = fw.Write([]byte("RIFF....WAVE")) require.NoError(t, err) } } require.NoError(t, mw.Close()) req := httptest.NewRequest(http.MethodPost, "/uploads", &buf) req.Header.Set("Content-Type", mw.FormDataContentType()) return req } func rowLanguage(t *testing.T, location string) domain.Language { t.Helper() id := strings.TrimPrefix(location, "/uploads/") got, err := newStore(t).GetUpload(context.Background(), userID, id) require.NoError(t, err) return got.Language } func TestUploadPost_TheLanguageFieldReachesTheJobAndTheRow(t *testing.T) { for _, tt := range []struct { name string language string want domain.Language }{ {"other", "auto", domain.LangAuto}, {"swedish", "sv", domain.LangSwedish}, } { t.Run(tt.name, func(t *testing.T) { app, sub := newUploadApp(t, audioOK, 200<<20) rec := do(t, app, langReq(t, []string{"title", "language", "file"}, tt.language)) require.Equal(t, http.StatusSeeOther, rec.Code) require.Len(t, sub.jobs, 1) assert.Equal(t, tt.want, sub.jobs[0].Language) assert.Equal(t, tt.want, rowLanguage(t, rec.Header().Get("Location"))) }) } } func TestUploadPost_NoLanguageFieldIsSwedishAsBefore(t *testing.T) { app, sub := newUploadApp(t, audioOK, 200<<20) rec := do(t, app, langReq(t, []string{"title", "file"}, "")) require.Equal(t, http.StatusSeeOther, rec.Code) require.Len(t, sub.jobs, 1) assert.Equal(t, domain.LangSwedish, sub.jobs[0].Language) assert.Equal(t, domain.LangSwedish, rowLanguage(t, rec.Header().Get("Location"))) } // A part after the file is never read (the file part ends the stream), so a client that // orders its fields wrongly gets Swedish, the old behaviour, not a guess. func TestUploadPost_ALanguageFieldAfterTheFileIsNotReadAndTheUploadIsSwedish(t *testing.T) { app, sub := newUploadApp(t, audioOK, 200<<20) rec := do(t, app, langReq(t, []string{"title", "file", "language"}, "auto")) require.Equal(t, http.StatusSeeOther, rec.Code) require.Len(t, sub.jobs, 1) assert.Equal(t, domain.LangSwedish, sub.jobs[0].Language) } func TestUploadPost_ALanguageOutsideTheClosedSetIsRefusedBeforeAnythingIsSpooledOrStored(t *testing.T) { for _, bad := range []string{"en", "SV", " sv", "sv,auto", "../auto", strings.Repeat("a", 5000)} { t.Run(bad[:min(len(bad), 12)], func(t *testing.T) { app, sub := newUploadApp(t, audioOK, 200<<20) rec := do(t, app, langReq(t, []string{"title", "language", "file"}, bad)) assert.Equal(t, http.StatusBadRequest, rec.Code) assert.Empty(t, sub.jobs, "a refused post must not enqueue transcription") rows, err := newStore(t).ListUploads(context.Background(), userID) require.NoError(t, err) assert.Empty(t, rows, "and must leave no row") assert.Contains(t, body(t, rec), "Choose a language from the list.") }) } } func TestUploadPage_TheFormOffersSwedishPreselectedAndOtherBeforeTheFilePart(t *testing.T) { app, _ := newUploadApp(t, audioOK, 200<<20) b := body(t, do(t, app, get("/uploads"))) sel := strings.Index(b, `name="language"`) file := strings.Index(b, `name="file"`) require.True(t, sel >= 0, "the form has a language field") assert.True(t, sel < file, "the field must come before the file part: the stream ends at the file") assert.Regexp(t, `