POST /paste: parse the video id, fetch metadata via the VideoFetcher port (Data API, ungated), upsert a subscription-less row scoped to the user (idempotent = dedup), and — unless already summarized — RequestSummarize + start immediate processing through the SAME globalFetchGate as the Summarize button. Explicit paste overrides the recency window; a captionless video degrades to the honest 'no transcript' terminal state via the engine (ADR-010). Invalid URL -> 400, not-found -> 404, both add nothing. Route mounts only when a Fetcher is wired. Moves the video-not-found sentinel to domain (shared by adapter + web, no cross-adapter coupling). Tests: valid add+queue, invalid, not-found, dedup. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
114 lines
3.4 KiB
Go
114 lines
3.4 KiB
Go
package web_test
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"gitea.d-ma.be/mathias/tapir/internal/domain"
|
|
)
|
|
|
|
// fakeFetcher is a web.VideoFetcher returning a fixed video (or an error),
|
|
// scoped to whatever (userID, videoID) the handler asks for.
|
|
type fakeFetcher struct {
|
|
title string
|
|
err error
|
|
calls int
|
|
}
|
|
|
|
func (f *fakeFetcher) FetchVideo(_ context.Context, userID, videoID string) (domain.Video, error) {
|
|
f.calls++
|
|
if f.err != nil {
|
|
return domain.Video{}, f.err
|
|
}
|
|
return domain.Video{
|
|
UserID: userID,
|
|
Provider: domain.ProviderYouTube,
|
|
ProviderVideoID: videoID,
|
|
Title: f.title,
|
|
URL: "https://www.youtube.com/watch?v=" + videoID,
|
|
}, nil
|
|
}
|
|
|
|
func pasteReq(rawURL string) *http.Request {
|
|
req := httptest.NewRequest(http.MethodPost, "/paste",
|
|
strings.NewReader("url="+url.QueryEscape(rawURL)))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
return req
|
|
}
|
|
|
|
func TestPasteValidURLAddsAndRequests(t *testing.T) {
|
|
ctx := context.Background()
|
|
app := newApp(t)
|
|
resetDB(t, rawPool(t))
|
|
app.Fetcher = &fakeFetcher{title: "Pasted Talk"}
|
|
p := rawPool(t)
|
|
|
|
rec := do(t, app, pasteReq("https://youtu.be/dQw4w9WgXcQ"))
|
|
require.Equal(t, http.StatusOK, rec.Code)
|
|
|
|
var (
|
|
count, requested int
|
|
title string
|
|
)
|
|
require.NoError(t, p.QueryRow(ctx,
|
|
`SELECT count(*), coalesce(max(title),'') FROM videos
|
|
WHERE user_id=$1 AND provider_video_id='dQw4w9WgXcQ'`, userID).Scan(&count, &title))
|
|
require.Equal(t, 1, count, "pasted video added once, scoped to the user")
|
|
require.Equal(t, "Pasted Talk", title)
|
|
|
|
require.NoError(t, p.QueryRow(ctx,
|
|
`SELECT count(*) FROM videos
|
|
WHERE user_id=$1 AND provider_video_id='dQw4w9WgXcQ' AND summarize_requested`,
|
|
userID).Scan(&requested))
|
|
require.Equal(t, 1, requested, "pasted video is queued for summarization (through the gate)")
|
|
}
|
|
|
|
func TestPasteInvalidURLRejected(t *testing.T) {
|
|
app := newApp(t)
|
|
resetDB(t, rawPool(t))
|
|
app.Fetcher = &fakeFetcher{title: "x"}
|
|
|
|
rec := do(t, app, pasteReq("definitely not a url"))
|
|
require.Equal(t, http.StatusBadRequest, rec.Code)
|
|
|
|
var count int
|
|
require.NoError(t, rawPool(t).QueryRow(context.Background(),
|
|
`SELECT count(*) FROM videos WHERE user_id=$1`, userID).Scan(&count))
|
|
require.Equal(t, 0, count, "invalid input adds nothing")
|
|
}
|
|
|
|
func TestPasteVideoNotFound(t *testing.T) {
|
|
app := newApp(t)
|
|
resetDB(t, rawPool(t))
|
|
app.Fetcher = &fakeFetcher{err: domain.ErrVideoNotFound}
|
|
|
|
rec := do(t, app, pasteReq("https://youtu.be/dQw4w9WgXcQ"))
|
|
require.Equal(t, http.StatusNotFound, rec.Code)
|
|
|
|
var count int
|
|
require.NoError(t, rawPool(t).QueryRow(context.Background(),
|
|
`SELECT count(*) FROM videos WHERE user_id=$1`, userID).Scan(&count))
|
|
require.Equal(t, 0, count, "a not-found video adds nothing")
|
|
}
|
|
|
|
func TestPasteDedupNoDuplicate(t *testing.T) {
|
|
app := newApp(t)
|
|
resetDB(t, rawPool(t))
|
|
app.Fetcher = &fakeFetcher{title: "Pasted Talk"}
|
|
|
|
require.Equal(t, http.StatusOK, do(t, app, pasteReq("https://youtu.be/dQw4w9WgXcQ")).Code)
|
|
require.Equal(t, http.StatusOK, do(t, app, pasteReq("https://www.youtube.com/watch?v=dQw4w9WgXcQ")).Code)
|
|
|
|
var count int
|
|
require.NoError(t, rawPool(t).QueryRow(context.Background(),
|
|
`SELECT count(*) FROM videos WHERE user_id=$1 AND provider_video_id='dQw4w9WgXcQ'`,
|
|
userID).Scan(&count))
|
|
require.Equal(t, 1, count, "pasting the same video twice must not duplicate the row")
|
|
}
|