156 lines
5.1 KiB
Go
156 lines
5.1 KiB
Go
package latest
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"bookmarkmanager/backend/internal/store"
|
|
)
|
|
|
|
// TestSmokeKaganeImage is the live proof that the cover proxy's fetch actually
|
|
// clears Cloudflare and returns image bytes. It needs the real browser unit
|
|
// with outbound network, so it runs only when SMOKE_BROWSER_WS_URL is set:
|
|
//
|
|
// cd chrome && BROWSER_BIND_ADDR=127.0.0.1 docker compose up -d --build
|
|
// SMOKE_BROWSER_WS_URL=ws://127.0.0.1:9222 go test -run TestSmokeKaganeImage ./internal/latest
|
|
//
|
|
// Not chromedp/headless-shell: its challenge never clears (see chrome/Dockerfile),
|
|
// so a red run there proves nothing about kagane.
|
|
func TestSmokeKaganeImage(t *testing.T) {
|
|
ws := os.Getenv("SMOKE_BROWSER_WS_URL")
|
|
if ws == "" {
|
|
t.Skip("SMOKE_BROWSER_WS_URL unset")
|
|
}
|
|
const imageID = "019fe11a-84c3-7fc3-a84b-88787374b617" // SP Baby's cover
|
|
|
|
// The same URL through a plain client is what the web UI's <img> gets.
|
|
// Asserting on it keeps the test honest about why the browser is needed.
|
|
req, err := http.NewRequest(http.MethodGet,
|
|
"https://kagane.to/api/v2/image/"+imageID+"/compressed", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if res, err := (&http.Client{Timeout: 15 * time.Second}).Do(req); err == nil {
|
|
res.Body.Close()
|
|
if res.StatusCode == http.StatusOK {
|
|
t.Log("note: kagane answered a plain request 200 — the challenge is not up right now")
|
|
}
|
|
}
|
|
|
|
f, err := NewBrowserFetcher(ws)
|
|
if err != nil {
|
|
t.Fatalf("NewBrowserFetcher: %v", err)
|
|
}
|
|
defer f.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
|
|
defer cancel()
|
|
body, contentType, err := f.Image(ctx, imageID)
|
|
if err != nil {
|
|
t.Fatalf("Image: %v", err)
|
|
}
|
|
if len(body) < 1000 {
|
|
t.Fatalf("body is %d bytes, want a real image", len(body))
|
|
}
|
|
if contentType != "image/webp" {
|
|
t.Fatalf("content type = %q, want image/webp", contentType)
|
|
}
|
|
// WebP files start with "RIFF....WEBP".
|
|
if string(body[:4]) != "RIFF" || string(body[8:12]) != "WEBP" {
|
|
t.Fatalf("body is not a WebP: % x", body[:12])
|
|
}
|
|
t.Logf("fetched %d bytes of %s", len(body), contentType)
|
|
|
|
if _, _, err := f.Image(ctx, "not-a-uuid"); err == nil {
|
|
t.Fatal("Image accepted a non-uuid id")
|
|
}
|
|
}
|
|
|
|
// Control for the test above: the poller's own kagane path, same sidecar. If
|
|
// this fails too, the sidecar is not clearing the challenge at all and the
|
|
// image result says nothing about Image itself.
|
|
func TestSmokeKaganeGet(t *testing.T) {
|
|
ws := os.Getenv("SMOKE_BROWSER_WS_URL")
|
|
if ws == "" {
|
|
t.Skip("SMOKE_BROWSER_WS_URL unset")
|
|
}
|
|
f, err := NewBrowserFetcher(ws)
|
|
if err != nil {
|
|
t.Fatalf("NewBrowserFetcher: %v", err)
|
|
}
|
|
defer f.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
|
|
defer cancel()
|
|
body, status, err := f.Get(ctx, "https://kagane.to/series/019fe11a-8670-7cf3-8343-0b02057d3787")
|
|
if err != nil {
|
|
t.Fatalf("Get: %v", err)
|
|
}
|
|
t.Logf("status=%d bytes=%d head=%.80q", status, len(body), body)
|
|
if status != 200 {
|
|
t.Fatalf("status = %d, want 200 — the sidecar is not clearing the challenge", status)
|
|
}
|
|
}
|
|
|
|
// TestSmokeAcquireKaganeCover proves the #62 acquisition path end to end
|
|
// against the real browser: a kagane Series bookmarked at creation gets its
|
|
// Cover, bytes fetched through the sidecar into the content-addressed store.
|
|
// Same SMOKE_BROWSER_WS_URL gate as the tests above; a red run means the
|
|
// challenge is not clearing from this IP (a live fact to re-check), not
|
|
// necessarily a defect in the pipeline.
|
|
func TestSmokeAcquireKaganeCover(t *testing.T) {
|
|
ws := os.Getenv("SMOKE_BROWSER_WS_URL")
|
|
if ws == "" {
|
|
t.Skip("SMOKE_BROWSER_WS_URL unset")
|
|
}
|
|
const (
|
|
seriesID = "019fe11a-8670-7cf3-8343-0b02057d3787"
|
|
coverURL = "https://kagane.to/api/v2/image/019fe11a-84c3-7fc3-a84b-88787374b617/compressed"
|
|
)
|
|
s, _ := newTestStore(t)
|
|
bf, err := NewBrowserFetcher(ws)
|
|
if err != nil {
|
|
t.Fatalf("NewBrowserFetcher: %v", err)
|
|
}
|
|
defer bf.Close()
|
|
tlsF, err := NewTLSFetcher()
|
|
if err != nil {
|
|
t.Fatalf("NewTLSFetcher: %v", err)
|
|
}
|
|
acq := &Acquirer{
|
|
Store: s, Fetch: tlsF, BrowserFetch: bf,
|
|
BrowserCoverFetch: bf, Covers: NewCoverFetcher(),
|
|
}
|
|
s.OnSeriesCreated = acq.Acquire
|
|
|
|
if _, err := s.Upsert(s.OwnerID(), store.Bookmark{
|
|
Key: "kagane:" + seriesID, Site: "kagane", SeriesID: seriesID,
|
|
Title: "smoke", SeriesURL: "https://kagane.to/series/" + seriesID, UpdatedAt: 1000,
|
|
}); err != nil {
|
|
t.Fatalf("Upsert: %v", err)
|
|
}
|
|
acq.Wait()
|
|
|
|
got, found, err := s.Get(s.OwnerID(), "kagane:"+seriesID)
|
|
if err != nil || !found {
|
|
t.Fatalf("Get: %v found=%v", err, found)
|
|
}
|
|
if want := testCoverBaseURL + "/covers/" + store.CoverAddress(coverURL); got.Cover != want {
|
|
t.Fatalf("Cover = %q, want %q — the acquire path did not store the browser-fetched bytes", got.Cover, want)
|
|
}
|
|
body, contentType, ok, err := s.CoverByAddress(store.CoverAddress(coverURL))
|
|
if err != nil || !ok {
|
|
t.Fatalf("CoverByAddress: %v found=%v", err, ok)
|
|
}
|
|
if len(body) < 1000 {
|
|
t.Fatalf("stored cover is %d bytes, want a real image", len(body))
|
|
}
|
|
if contentType != "image/webp" {
|
|
t.Fatalf("content type = %q, want image/webp", contentType)
|
|
}
|
|
t.Logf("stored %d bytes of %s", len(body), contentType)
|
|
}
|