package httpapi import ( "net/http" "strings" "testing" "git.vakhrushev.me/av/jellybit/internal/store" "git.vakhrushev.me/av/jellybit/internal/worker" ) // TestFragProgressDownloading: активная задача → фрагмент с прогрессом, // значениями снимка и атрибутами htmx-поллинга. func TestFragProgressDownloading(t *testing.T) { dl := store.Download{ID: testULID, Infohashes: []store.Infohash{{DownloadID: testULID, Infohash: "ih5", Kind: store.HashV1}}, State: store.StateDownloading} lv := stubLive{m: map[string]worker.Live{"ih5": {Progress: 0.42, DlSpeed: 6400000, ETA: 720}}} h := testRouterLive(t, stubReader{one: &dl}, stubReviewer{}, lv) rr := get(t, h, "/fragments/downloads/"+testULID+"/progress") if rr.Code != http.StatusOK { t.Fatalf("status = %d, want 200", rr.Code) } body := rr.Body.String() for _, want := range []string{`hx-trigger="every 3s"`, "/fragments/downloads/" + testULID + "/progress", "width:42%", "42%"} { if !strings.Contains(body, want) { t.Errorf("фрагмент прогресса не содержит %q\n%s", want, body) } } } // TestFragProgressStopsWhenNotDownloading: когда задача покинула downloading, // фрагмент отдаётся без атрибутов поллинга (поллинг прекращается). func TestFragProgressStopsWhenNotDownloading(t *testing.T) { dl := store.Download{ID: testULID, Infohashes: []store.Infohash{{DownloadID: testULID, Infohash: "ih5", Kind: store.HashV1}}, State: store.StateDone} h := testRouterLive(t, stubReader{one: &dl}, stubReviewer{}, stubLive{}) rr := get(t, h, "/fragments/downloads/"+testULID+"/progress") if rr.Code != http.StatusOK { t.Fatalf("status = %d, want 200", rr.Code) } if body := rr.Body.String(); strings.Contains(body, "hx-trigger") { t.Errorf("завершённая задача всё ещё поллит:\n%s", body) } } // TestFragSeeding: сидирующая задача → секция «Раздача» со статистикой и // поллингом. func TestFragSeeding(t *testing.T) { dl := store.Download{ID: testULID, Infohashes: []store.Infohash{{DownloadID: testULID, Infohash: "ih9", Kind: store.HashV1}}, State: store.StateDone} lv := stubLive{m: map[string]worker.Live{"ih9": { Seeding: true, Progress: 1, Ratio: 2.41, Seeds: 38, Peers: 14, Uploaded: 1 << 30, UpSpeed: 1153433, }}} h := testRouterLive(t, stubReader{one: &dl}, stubReviewer{}, lv) rr := get(t, h, "/fragments/downloads/"+testULID+"/seeding") if rr.Code != http.StatusOK { t.Fatalf("status = %d, want 200", rr.Code) } body := rr.Body.String() for _, want := range []string{"Раздача", "2.41", "38 / 14", `hx-trigger="every 3s"`} { if !strings.Contains(body, want) { t.Errorf("фрагмент раздачи не содержит %q\n%s", want, body) } } } // TestFragSeedingDegrades: нет живых данных → секция отсутствует, поллинга нет. func TestFragSeedingDegrades(t *testing.T) { dl := store.Download{ID: testULID, Infohashes: []store.Infohash{{DownloadID: testULID, Infohash: "ih9", Kind: store.HashV1}}, State: store.StateDone} h := testRouterLive(t, stubReader{one: &dl}, stubReviewer{}, stubLive{}) rr := get(t, h, "/fragments/downloads/"+testULID+"/seeding") if rr.Code != http.StatusOK { t.Fatalf("status = %d, want 200", rr.Code) } body := rr.Body.String() if strings.Contains(body, "Раздача") || strings.Contains(body, "hx-trigger") { t.Errorf("секция раздачи не деградировала:\n%s", body) } } // TestIndexCardShowsLiveProgress: активная карточка в списке несёт прогресс уже // в первом кадре (значения снимка) и атрибуты поллинга. func TestIndexCardShowsLiveProgress(t *testing.T) { dl := store.Download{ID: testULID, SourceRef: "The.Bear.S03", Infohashes: []store.Infohash{{DownloadID: testULID, Infohash: "ih3", Kind: store.HashV1}}, State: store.StateDownloading} lv := stubLive{m: map[string]worker.Live{"ih3": {Progress: 0.46, DlSpeed: 6400000, ETA: 720}}} h := testRouterLive(t, stubReader{list: []store.Download{dl}}, stubReviewer{}, lv) rr := get(t, h, "/") if rr.Code != http.StatusOK { t.Fatalf("status = %d, want 200", rr.Code) } body := rr.Body.String() for _, want := range []string{`class="progress"`, "width:46%", "/fragments/downloads/" + testULID + "/progress"} { if !strings.Contains(body, want) { t.Errorf("карточка без живого прогресса: нет %q", want) } } } // TestFragNotFound: фрагмент несуществующей задачи → 404. func TestFragNotFound(t *testing.T) { h := testRouterLive(t, stubReader{}, stubReviewer{}, stubLive{}) if rr := get(t, h, "/fragments/downloads/01arz3ndektsv4rrffq69g5fff/progress"); rr.Code != http.StatusNotFound { t.Fatalf("status = %d, want 404", rr.Code) } // Невалидный id → 404 без похода в БД. if rr := get(t, h, "/fragments/downloads/404/progress"); rr.Code != http.StatusNotFound { t.Fatalf("status(invalid id) = %d, want 404", rr.Code) } }