113 lines
3.9 KiB
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")
|
|
}
|
|
}
|