Files
djk/internal/app/ui_library_sources_test.go

113 lines
3.9 KiB
Go

package app
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"sync/atomic"
"testing"
"time"
)
func TestLibraryUpdateTargetsIndividualHuangguoEntrypoints(t *testing.T) {
for _, source := range []string{"cloudfront", sourceHuangguoAI, sourceHuangguoVideo} {
t.Run(source, func(t *testing.T) {
started := make(chan struct{}, 8)
downloader := rankingTestDownloader(t, func(request *http.Request) (*http.Response, error) {
if request.Context().Err() == nil {
select {
case started <- struct{}{}:
default:
}
}
<-request.Context().Done()
return nil, request.Context().Err()
})
app := &UIApp{downloader: downloader, cfg: downloader.cfg, libraryAttempted: true, librarySources: map[string]librarySourceState{}}
for _, provider := range []string{"cloudfront", sourceHuangguoAI, sourceHuangguoVideo, sourceHuangdou, sourceHongguo} {
app.librarySources[provider] = librarySourceState{Status: "cached", Count: 7}
}
t.Cleanup(func() {
app.mu.Lock()
done, cancel := app.libraryLoading, app.libraryCancel
app.mu.Unlock()
if cancel != nil {
cancel()
}
if done != nil {
select {
case <-done:
case <-time.After(3 * time.Second):
t.Error("source update did not stop")
}
}
app.stopSortMetadata()
})
read := func() struct {
Accepted bool `json:"updateAccepted"`
Loading bool `json:"loading"`
Source string `json:"loadingSource"`
} {
t.Helper()
request := httptest.NewRequest(http.MethodGet, "/api/ui/dramas?update=1&source="+source, nil)
request = request.WithContext(withSourceScope(context.Background(), accountRecord{Sources: []string{"huangguo"}}))
writer := httptest.NewRecorder()
app.handleDramas(writer, request)
var result struct {
Accepted bool `json:"updateAccepted"`
Loading bool `json:"loading"`
Source string `json:"loadingSource"`
}
if writer.Code != http.StatusOK || json.Unmarshal(writer.Body.Bytes(), &result) != nil {
t.Fatalf("individual source update rejected: %d %s", writer.Code, writer.Body.String())
}
return result
}
if result := read(); !result.Accepted || !result.Loading || result.Source != source {
t.Fatalf("update was not scoped to the requested entrypoint: %+v", result)
}
select {
case <-started:
case <-time.After(2 * time.Second):
t.Fatal("source update never dispatched a textual request")
}
if result := read(); result.Accepted || !result.Loading || result.Source != source {
t.Fatalf("busy update was reported as newly accepted: %+v", result)
}
app.mu.Lock()
defer app.mu.Unlock()
for provider, state := range app.librarySources {
want := "cached"
if provider == source {
want = "loading"
}
if state.Status != want || state.Count != 7 {
t.Errorf("update changed another entrypoint: %s %+v", provider, state)
}
}
})
}
}
func TestIndividualSourceUpdatesRequireSourcePermission(t *testing.T) {
var calls atomic.Int32
downloader := rankingTestDownloader(t, func(request *http.Request) (*http.Response, error) {
calls.Add(1)
return rankingHTTPResponse(request, http.StatusServiceUnavailable, "text fixture"), nil
})
app := &UIApp{downloader: downloader, cfg: downloader.cfg, libraryAttempted: true}
for _, source := range []string{"cloudfront", sourceHuangguoAI, sourceHuangguoVideo, sourceHuangdou} {
request := httptest.NewRequest(http.MethodGet, "/api/ui/dramas?update=1&source="+source, nil)
request = request.WithContext(withSourceScope(context.Background(), accountRecord{Sources: []string{sourceHongguo}}))
writer := httptest.NewRecorder()
app.handleDramas(writer, request)
if writer.Code != http.StatusForbidden {
t.Errorf("restricted source %s returned %d instead of 403", source, writer.Code)
}
}
if calls.Load() != 0 || app.libraryLoading != nil {
t.Fatal("unauthorized source update triggered background work")
}
}