release: 1.2.0 - #4
Merged
Merged
Conversation
`Load Document` reads a fixture document from a JSON file, and `Insert Document
From File` reads one and inserts it in a single step. A document written into a
suite is fine until a second test needs it, and then it is copied and the copies
drift.
The file is read as MongoDB Extended JSON, so `$oid`, `$date`, `$numberInt` and
`$numberDouble` arrive as the BSON types MongoDB compares against rather than as
text that silently matches nothing. Update operators are `$`-prefixed too and
are passed through untouched, so a file can hold an update as readily as a
document.
Two kinds of hole, written differently because they are filled from different
places: `${name}` is a Robot Framework variable resolved from the calling
suite, and `{name}` is a template placeholder filled from the keyword's named
arguments. Any field the file already fills can be overridden by its dotted
path, which is the part a suite cannot do for itself, since `&{dict}` expansion
merges only one level deep. Either kind of hole left unfilled fails the keyword,
because the literal text is a perfectly insertable string that would seed a
document looking almost right.
The new `document_path` import argument names the directory that documents given
by file name are looked up in. It only removes the repetition: a path given to
the keyword works with or without it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A query that matches nothing and reports no error is this library's most common failure, and only one cause of it — a string `_id` against an ObjectId — was documented. `Explain Query` covers the rest: it asks the server how it answered the query and returns a flat summary of the plan, the most valuable field being `index_bounds`, the values the server actually searched for. Comparing those with what the suite passed is usually the whole diagnosis. It takes the query either way the find keywords take it, as free arguments or as a `query` document, so it drops in beside a failing call without rewriting it. The summary is logged at INFO a field to a line, since Robot Framework keeps newlines and indentation in `log.html` and a summary on one line is readable by nobody; the whole explain document is logged at DEBUG, indented, and returned under `raw`. The summary is derived rather than copied, because the explain document's shape differs by server version and topology while the questions do not: a slot-based plan nests its stages under `queryPlan`, a sharded cluster reports per shard, and the `_id` fast path is `EXPRESS_IXSCAN` on MongoDB 8 and `IDHACK` before it. A collection scan is therefore detected by the presence of a `COLLSCAN` rather than by an allowlist of index stage names, so no version check is involved. The keyword is a diagnostic and asserts nothing, `collection_scan` included: MongoDB rightly chooses a scan on a small collection, where reading it beats an index lookup plus a fetch, so an assertion that no scan happens would pass against production-sized data and fail against a freshly seeded test collection with nothing wrong. Where a suite needs an index, `Collection Should Have Index` says so directly and cannot flake, reading the collection's index definitions rather than a plan. It asks by fields rather than by name — the name is derived from the fields, and the fields are what the queries depend on — and compares their order, because a compound index serves its fields left to right. Both are read-only. The unit tests feed the keyword canned explain documents, mongomock having no `explain` at all; the new acceptance suite covers a real server answering a real query against a collection keyed by a compound `_id`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Documents read from Extended JSON files, and the two keywords for a query that returns nothing without erroring: `Explain Query` and `Collection Should Have Index`. Regenerates the keyword documentation so the version stamp GitHub Pages serves matches the release; CI only builds libdoc as a check, so the committed file is what is published. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three keywords could describe something that never happened, which is the
failure mode a test library can least afford.
Explain Query walked the whole explain document, so a rejected candidate plan
could report a collection scan for a query the server answered with an index,
or lend its index name and bounds to a query that scanned. _explain_stages now
skips rejectedPlans and allPlansExecution, which fixes the summary and the
per-shard summaries at once.
Load Document filled placeholders after ${...} substitution, so a variable
whose value contained braces was re-read as a template and failed on a hole the
file never declared. The placeholders a file declares are now read before
substitution: a variable's value is data.
Collection Should Have Index ended its message with a dangling "It has: ." when
the collection did not exist, which hid the likeliest cause of the failure.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Python 3.13 rewrote the decoder's messages, and a trailing comma is now reported at the comma rather than at the token after it, so the test failed on 3.13 and 3.14 while the library was doing exactly what it should. What matters is that the failure names the file and carries a position, which is what is asserted now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two features, then the release commit.
Load DocumentandInsert Document From FileA fixture document read from an Extended JSON file rather than written into a suite, so
$oidand$datearrive as the BSON types MongoDB compares against. Two kinds of hole —${name}from the calling suite,{name}from the keyword's arguments — plus dotted-pathoverrides of fields the file already fills. A new
document_pathimport argument names thelookup directory and does nothing else.
Explain QueryandCollection Should Have IndexA query that matches nothing and reports no error was documented for exactly one cause, a
string
_idagainst an ObjectId.Explain Querycovers the rest: it reports the plan theserver chose and, most usefully,
index_bounds— the values it actually searched for.Design notes worth reviewing:
the questions do not: SBE nests stages under
queryPlan, sharded clusters report pershard, and the
_idfast path isEXPRESS_IXSCANon MongoDB 8 butIDHACKbefore it.A scan is detected by the presence of a
COLLSCAN, so there is no version check.database.commandrather thancursor.explain(), which pymongo pins toallPlansExecution; that is what makesexecutionStatsthe default andqueryPlanneravailable.
collection_scanincluded — MongoDB rightlyscans small collections, so such an assertion would pass on production-shaped data and
fail on a freshly seeded test collection with nothing wrong.
Collection Should Have Indexis the assertion, reading index definitions rather than a plan so it cannot flake,and asking by fields rather than by the derived name.
Verification
MongoDBLibrary/keywords.pyat 100% coverage; mypy, ruff androbocop check atestclean.atest/explain_tests.robot, 11/11 against MongoDB 8, seeding 200 documents keyed bya compound
_id. One test reproduces the field-order trap end to end: the same_idwith its fields reversed explains as
returned: 0whileFind Document With Queryreturns
None.implements no
explainat all.🤖 Generated with Claude Code