//// End-to-end test for the browse handler's `?strategy=` param: HTTP wiring //// only, domain correctness lives in catalog_variants/stats/strategy_test. import crate_server/catalog/row.{BrowseRow} import crate_server/catalog/source.{type Source, Source} import crate_server/context.{type Context} import crate_server/handlers/browse.{browse} import crate_server/oauth/config import crate_server/oauth/session_store import crate_server/oauth/sessions import gleam/dynamic/decode import gleam/http import gleam/int import gleam/json import gleam/list import gleam/option.{None, Some} import gleam/string import support import wisp import wisp/simulate const session_cookie = "ar_oauth_sid" const far_future = 9_999_999_999 fn a_session() -> sessions.OauthSession { support.stub_session_with( access_token: "at", refresh_token: "rt", expires_at: far_future, ) } /// Same Discogs release: `a` has far more adoption, `b` is more recent. fn variant_source() -> Source { let more_adopted = BrowseRow( uri: "at://a/1", cid: "bafya", title: "Spiderland", artist_display: Some("Slint"), genres: [], styles: [], released: None, country: None, cover: None, thumb_url: None, discogs_id: Some("42"), created_at: "2020-01-01T00:00:00Z", publisher_did: "did:plc:pub", publisher_handle: "pub.test", publisher_pds: "https://pds.test", supersedes: None, based_on: None, format: Some("2×LP"), label: Some("Hyperdub"), master: Some( "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/master1", ), barcode: None, ) let more_recent = BrowseRow( ..more_adopted, uri: "at://b/1", cid: "bafyb", created_at: "2024-01-01T00:00:00Z", ) Source( releases: fn() { [more_adopted, more_recent] }, adoption_count: fn(uri) { case uri { "at://a/1" -> 10 "at://b/1" -> 1 _ -> 0 } }, ) } fn test_context() -> #(Context, config.Config) { let cfg = support.stub_config_with( support.unreachable_client(), "https://resolver.test", "http://localhost:8080", ) let ctx = support.stub_context_with_variant_source(cfg, variant_source()) #(ctx, cfg) } fn browse_body(query: String, ctx: Context, cfg: config.Config) -> String { let assert Ok(id) = session_store.create(cfg.sessions, a_session()) let req = simulate.request(http.Get, support.xrpc("catalog.listReleases") <> query) |> simulate.cookie(session_cookie, id, wisp.Signed) let resp = browse(req, ctx) assert resp.status == 200 simulate.read_body(resp) } pub fn strategy_query_param_selects_the_winner_test() { let #(ctx, cfg) = test_context() let cases = [ #("", "at://a/1", "at://b/1"), #("?strategy=most-recent", "at://b/1", "at://a/1"), #("?strategy=not-a-real-strategy", "at://a/1", "at://b/1"), ] cases |> list.each(fn(c) { let #(query, winner, loser) = c let body = browse_body(query, ctx, cfg) assert string.contains(body, "\"uri\":\"" <> winner <> "\"") assert !string.contains(body, "\"uri\":\"" <> loser <> "\"") }) } pub fn resolved_release_includes_variant_count_test() { let #(ctx, cfg) = test_context() let body = browse_body("", ctx, cfg) assert string.contains(body, "\"variantCount\":2") } pub fn resolved_release_includes_format_label_and_master_test() { let #(ctx, cfg) = test_context() let body = browse_body("", ctx, cfg) assert string.contains(body, "\"format\":\"2×LP\"") assert string.contains(body, "\"label\":\"Hyperdub\"") assert string.contains( body, "\"master\":\"at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/master1\"", ) } fn release_source(count: Int) -> Source { let rows = int.range(1, count + 1, [], fn(rows, n) { let id = int.to_string(n) let row = BrowseRow( uri: "at://did:plc:pub/dev.mokkenstorm.crate.catalog.release/" <> id, cid: "bafy" <> id, title: "Release " <> id, artist_display: None, genres: [], styles: [], released: None, country: None, cover: None, thumb_url: None, discogs_id: None, created_at: id, publisher_did: "did:plc:pub", publisher_handle: "pub.test", publisher_pds: "https://pds.test", supersedes: None, based_on: None, format: None, label: None, master: None, barcode: None, ) [row, ..rows] }) Source(releases: fn() { rows }, adoption_count: fn(_uri) { 0 }) } fn paginated_context(count: Int) -> #(Context, config.Config) { let cfg = support.stub_config_with( support.unreachable_client(), "https://resolver.test", "http://localhost:8080", ) let ctx = support.stub_context_with_variant_source(cfg, release_source(count)) #(ctx, cfg) } fn release_uris(body: String) -> List(String) { let decoder = decode.at(["releases"], decode.list(decode.at(["uri"], decode.string))) let assert Ok(uris) = json.parse(body, decoder) uris } fn next_cursor(body: String) -> String { let assert Ok(cursor) = json.parse(body, decode.at(["cursor"], decode.string)) cursor } pub fn browse_pages_through_the_full_catalog_with_an_opaque_cursor_test() { let #(ctx, cfg) = paginated_context(3) let first = browse_body("?limit=2", ctx, cfg) let second = browse_body("?limit=2&cursor=" <> next_cursor(first), ctx, cfg) assert list.length(release_uris(first)) == 2 assert list.length(release_uris(second)) == 1 assert list.all(release_uris(second), fn(uri) { !list.contains(release_uris(first), uri) }) } pub fn browse_omits_cursor_after_the_last_page_test() { let #(ctx, cfg) = paginated_context(1) let body = browse_body("?limit=2", ctx, cfg) assert !string.contains(body, "\"cursor\"") }