Skip to content

Commit 4e6488d

Browse files
committed
test(graphql): pin case ordering and test documented max page limit
Permute insertion order and seed mixed-case repo to ensure folded and recency orderings cannot satisfy pagination tests, and verify limit:200 distinguishes a terminal page from row 201. Refs #408
1 parent ac6c134 commit 4e6488d

1 file changed

Lines changed: 47 additions & 13 deletions

File tree

‎crates/gitlawb-node/src/graphql/query.rs‎

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -326,27 +326,28 @@ mod tests {
326326
// sorts past the first cursor, so an unqualified OR name predicate
327327
// would incorrectly serve it again on the next page.
328328
//
329-
// Rows are inserted out of order and assigned IDs that invert name order
330-
// within each owner, so neither insertion order / created_at nor d.id can
331-
// satisfy the asserted (owner, name) ordering. Sized to 6 entries so the
332-
// last page is full-sized (limit 2), proving hasNextPage distinguishes a
333-
// full terminal page from a page with remaining rows.
334-
db.create_repo(&repo("r1", owner2, "d-repo", true))
329+
// Rows are inserted out of order and not in reverse asserted order.
330+
// Assigned IDs do not track name order, and owner2 contains both
331+
// "B-repo" and "a-repo" whose byte order (B < a) differs from their
332+
// case-folded order (a < b), ensuring lower(d.name) cannot satisfy
333+
// the keyset query. Sized to 6 entries so the last page is full-sized
334+
// (limit 2), proving hasNextPage distinguishes a full terminal page.
335+
db.create_repo(&repo("r5", owner2, "c-repo", true))
335336
.await
336337
.unwrap();
337-
db.create_repo(&repo("r6", owner2, "c-repo", true))
338+
db.create_repo(&repo("r9", earlier_owner, "zz-repo", true))
338339
.await
339340
.unwrap();
340-
db.create_repo(&repo("r7", owner2, "a-repo", true))
341+
db.create_repo(&repo("r3", owner2, "B-repo", true))
341342
.await
342343
.unwrap();
343-
db.create_repo(&repo("r2", owner1, "z-repo", true))
344+
db.create_repo(&repo("r8", owner1, "z-repo", true))
344345
.await
345346
.unwrap();
346-
db.create_repo(&repo("r8", owner1, "b-repo", true))
347+
db.create_repo(&repo("r2", owner1, "b-repo", true))
347348
.await
348349
.unwrap();
349-
db.create_repo(&repo("r9", earlier_owner, "zz-repo", true))
350+
db.create_repo(&repo("r1", owner2, "a-repo", true))
350351
.await
351352
.unwrap();
352353

@@ -379,7 +380,7 @@ mod tests {
379380
p2["nodes"],
380381
serde_json::json!([
381382
{"name": "z-repo", "ownerDid": owner1},
382-
{"name": "a-repo", "ownerDid": owner2},
383+
{"name": "B-repo", "ownerDid": owner2},
383384
])
384385
);
385386
let cursor = p2["endCursor"].as_str().unwrap();
@@ -393,12 +394,45 @@ mod tests {
393394
assert_eq!(
394395
p3["nodes"],
395396
serde_json::json!([
397+
{"name": "a-repo", "ownerDid": owner2},
396398
{"name": "c-repo", "ownerDid": owner2},
397-
{"name": "d-repo", "ownerDid": owner2},
398399
])
399400
);
400401
}
401402

403+
#[sqlx::test]
404+
async fn repos_page_at_documented_maximum_distinguishes_terminal_page(pool: PgPool) {
405+
let db = db(pool).await;
406+
let total = crate::db::MAX_VISIBLE_REPO_PAGE_SIZE;
407+
for index in 0..total {
408+
let name = format!("repo-{index:03}");
409+
db.create_repo(&repo(&name, OWNER, &name, true))
410+
.await
411+
.unwrap();
412+
}
413+
let schema = schema(db.clone());
414+
let query =
415+
format!("{{ reposPage(limit: {total}) {{ nodes {{ name }} hasNextPage endCursor }} }}");
416+
let resp200 = anon(&schema, &query).await;
417+
assert!(resp200.errors.is_empty(), "{:?}", resp200.errors);
418+
let p200 = resp200.data.into_json().unwrap()["reposPage"].clone();
419+
assert_eq!(p200["hasNextPage"], false);
420+
let nodes200 = p200["nodes"].as_array().unwrap().clone();
421+
assert_eq!(nodes200.len(), total);
422+
423+
// Adding row 201 keeps page 1 content identical while flipping hasNextPage to true.
424+
let name201 = format!("repo-{total:03}");
425+
db.create_repo(&repo(&name201, OWNER, &name201, true))
426+
.await
427+
.unwrap();
428+
let resp201 = anon(&schema, &query).await;
429+
assert!(resp201.errors.is_empty(), "{:?}", resp201.errors);
430+
let p201 = resp201.data.into_json().unwrap()["reposPage"].clone();
431+
assert_eq!(p201["hasNextPage"], true);
432+
assert_eq!(p201["nodes"], p200["nodes"]);
433+
assert_eq!(p201["endCursor"], p200["endCursor"]);
434+
}
435+
402436
#[sqlx::test]
403437
async fn repos_page_visibility_matches_the_shared_gate(pool: PgPool) {
404438
use crate::db::VisibilityMode;

0 commit comments

Comments
 (0)