From 7aec2538be62c858b4923d0f973e0acbefae57cc Mon Sep 17 00:00:00 2001 From: Mathias Date: Thu, 1 Oct 2026 18:42:33 +0200 Subject: [PATCH] test(web): a video file is accepted and the user is told the video was ignored (red) Video with no audio is rejected for having none. A file with a video track is accepted and marked had_video; every state of its page (queued, transcribing, done, failed) says only its audio was used and the video was discarded, and a plain audio file shows no such notice. Red: the had_video column does not exist. Co-Authored-By: Claude Sonnet 5.5 --- internal/web/uploads_handler_test.go | 67 ++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/internal/web/uploads_handler_test.go b/internal/web/uploads_handler_test.go index c43e982..9b342a6 100644 --- a/internal/web/uploads_handler_test.go +++ b/internal/web/uploads_handler_test.go @@ -158,12 +158,12 @@ func TestUploadPost_RejectionsAreSynchronousWithAMessageAndNoRow(t *testing.T) { wantInBody []string }{ { - name: "video names issue 28", - probe: uploads.Probe{Duration: time.Minute, HasAudio: true, HasVideo: true}, + name: "video with no audio is rejected for having no audio", + probe: uploads.Probe{Duration: time.Minute, HasVideo: true}, maxBytes: 1 << 20, content: "x", wantStatus: http.StatusUnprocessableEntity, - wantInBody: []string{"video", "#28"}, + wantInBody: []string{"no audio"}, }, { name: "too long states both lengths", @@ -275,3 +275,64 @@ func TestUploadStatus_DoneNamesTheEndpointThatServedIt(t *testing.T) { "which backend served a transcript is a quality fact, and berget means the audio left the homelab") assert.True(t, strings.Contains(b, "45 min"), "the audio length is shown") } + +func markHadVideo(t *testing.T, id string) { + t.Helper() + _, err := rawPool(t).Exec(context.Background(), `UPDATE uploaded_transcripts SET had_video = TRUE WHERE id = $1`, id) + require.NoError(t, err) +} + +func TestUploadPost_AFileWithAVideoTrackIsAcceptedAndTheRowRemembersIt(t *testing.T) { + // A Teams meeting with the camera off is still an .mp4 with a video track. + app, sub := newUploadApp(t, uploads.Probe{Duration: 62 * time.Minute, HasAudio: true, HasVideo: true}, 200<<20) + + rec := do(t, app, uploadReq(t, "Project notes", "Teams meeting.mp4", []byte("synthetic bytes"))) + + require.Equal(t, http.StatusSeeOther, rec.Code, "it must be accepted, not rejected as video") + var hadVideo bool + require.NoError(t, rawPool(t).QueryRow(context.Background(), + `SELECT had_video FROM uploaded_transcripts WHERE user_id = $1`, userID).Scan(&hadVideo)) + assert.True(t, hadVideo) + assert.Len(t, sub.jobs, 1) +} + +func TestUploadPost_AudioOnlyIsNotMarkedAsHavingHadVideo(t *testing.T) { + app, _ := newUploadApp(t, audioOK, 200<<20) + + do(t, app, uploadReq(t, "Voice memo", "memo.m4a", []byte("x"))) + + var hadVideo bool + require.NoError(t, rawPool(t).QueryRow(context.Background(), + `SELECT had_video FROM uploaded_transcripts WHERE user_id = $1`, userID).Scan(&hadVideo)) + assert.False(t, hadVideo) +} + +func TestUploadStatus_TellsTheUserTheVideoWasIgnoredInEveryStateAndOnlyWhenItWas(t *testing.T) { + app, _ := newUploadApp(t, audioOK, 200<<20) + states := []struct{ status, content string }{ + {"queued", ""}, {"transcribing", ""}, {"done", "Synthetic transcript."}, {"failed", "interrupted"}, + } + for _, st := range states { + t.Run(st.status, func(t *testing.T) { + withVideo := seedUpload(t, userID, "camera off "+st.status, st.status, st.content) + markHadVideo(t, withVideo) + audioOnly := seedUpload(t, userID, "voice only "+st.status, st.status, st.content) + + notice := body(t, do(t, app, get("/uploads/"+withVideo+"/status"))) + plain := body(t, do(t, app, get("/uploads/"+audioOnly+"/status"))) + + assert.Contains(t, notice, "video track") + assert.Contains(t, notice, "only its audio was used", "say what happened, not just that something did") + assert.Contains(t, notice, "discarded") + assert.NotContains(t, plain, "video track", "no notice when there was no video") + }) + } +} + +func TestUploadPage_AlsoCarriesTheVideoNotice(t *testing.T) { + app, _ := newUploadApp(t, audioOK, 200<<20) + id := seedUpload(t, userID, "camera off", "done", "Synthetic transcript.") + markHadVideo(t, id) + + assert.Contains(t, body(t, do(t, app, get("/uploads/"+id))), "only its audio was used") +}