package download import ( "context" "os" "path/filepath" "slices" "testing" "time" ) // TestSlskdLive runs the provider against a real slskd daemon. It is // skipped unless YJ_SLSKD_URL, YJ_SLSKD_API_KEY and YJ_SLSKD_DOWNLOADS // are set, and it downloads something only when YJ_SLSKD_GRAB=1 — then // the smallest candidate the search returns, from whichever stranger // is sharing it. // // Everything else here tests the provider against a stub written from // reading slskd's source. This is where those readings are checked: // the search options, the responses endpoint, the batch destination, // the cancel. // // YJ_SLSKD_URL=http://localhost:5030 YJ_SLSKD_API_KEY=… \ // YJ_SLSKD_DOWNLOADS=/path/to/slskd/downloads YJ_SLSKD_GRAB=1 \ // go test -run TestSlskdLive -v ./backend/download/ func TestSlskdLive(t *testing.T) { base, key, downloads := os.Getenv("YJ_SLSKD_URL"), os.Getenv("YJ_SLSKD_API_KEY"), os.Getenv("YJ_SLSKD_DOWNLOADS") if base == "" || key == "" || downloads == "" { t.Skip( "set YJ_SLSKD_URL, YJ_SLSKD_API_KEY and YJ_SLSKD_DOWNLOADS to run against a real slskd", ) } query := os.Getenv("YJ_SLSKD_QUERY") if query == "" { query = "Radiohead OK Computer" } p, err := newSlskd( Config{ ID: 1, Kind: KindSlskd, Name: "live", Enabled: true, Settings: map[string]string{"url": base, "downloadsPath": downloads}, }, func(string) (string, error) { return key, nil }, slogDiscard(), ) if err != nil { t.Fatalf("newSlskd: %v", err) } s, ok := p.(*slskd) if !ok { t.Fatalf("provider is %T", p) } ctx := context.Background() if err := s.Check(ctx); err != nil { t.Fatalf("Check: %v", err) } started := time.Now() got, err := s.Search(ctx, Download{Query: query}) if err != nil { t.Fatalf("Search: %v", err) } t.Logf( "search %q: %d candidates in %s", query, len(got), time.Since(started).Round(time.Millisecond), ) if len(got) == 0 { t.Fatal("no candidates; try a more common YJ_SLSKD_QUERY") } timed := 0 for _, c := range got { for _, f := range c.Files { if f.LengthMillis > 0 { timed++ } } } t.Logf("%d files carry a length", timed) if os.Getenv("YJ_SLSKD_GRAB") != "1" { return } smallest := slices.MinFunc(got, func(a, b Candidate) int { return int(a.TotalSize - b.TotalSize) }) t.Logf("grabbing %q from %s (%d files, %d bytes)", smallest.Title, smallest.Origin, len(smallest.Files), smallest.TotalSize) s.stallAfter = 3 * time.Minute gctx, cancel := context.WithTimeout(ctx, 15*time.Minute) defer cancel() res, err := s.Grab(gctx, smallest, t.TempDir(), func(p Progress) { t.Logf("%s: %d/%d bytes", p.Phase, p.Current, p.Total) }) if err != nil { // A stranger going offline is not a defect; what matters is // that the transfers were cancelled, which slskd's UI shows. t.Fatalf("Grab: %v", err) } t.Logf("batches: %v", s.batches.Load() == batchesSupported) for _, f := range res.Files { info, err := os.Stat(f) if err != nil || info.Size() == 0 { t.Errorf("collected %s is missing or empty: %v", f, err) } } if entries, _ := os.ReadDir(filepath.Join(downloads, slskdDestRoot)); len(entries) != 0 { t.Errorf("%d batch folders left in slskd's downloads", len(entries)) } }