Notes on the test suite added during development of glean-code-cli. See Running tests for the user-facing instructions on how to run the tests.
All 834 tests pass. Here's what was added across the development passes:
tests/test_commands_extended.py (155 new tests) — covers all previously untested commands:
/status,/clear,/help/datasources.list(all flag combinations),/datasources.status,/indexing.rotate-token/autocomplete,/recommendations,/feedback,/entities.list/pins.delete,/collections.delete/shortcuts.list,/shortcuts.get,/shortcuts.create,/shortcuts.update,/shortcuts.delete(full flag coverage)/answers.list,/answers.get,/answers.create,/answers.update,/answers.delete(int ID validation, arg passing)/summarize(by URL, by ID, query flag)/verification.list,/verification.verify,/verification.remind(flag passthrough, defaults)/messages.get,/activity.report,/insights(CSV export, all flags)/scaffoldwith--outputflag, cancellation paths_fmt_ts,_render_insights,_export_insights_csv,_print_datasource_status,Session.refresh_client
tests/test_client_extended.py (31 new tests) — covers all new client methods and mock responses:
- Mock responses for all 19 new endpoints (
/unpin,/listshortcuts,/listanswers,/summarize,/insights, etc.) GleanClientmethod bodies: correct paths, partial updates, optional fields, body construction
tests/test_indexing_walk.py (25 new tests) — covers the --path indexing helpers and command flow:
path_to_id,filename_to_title,mime_for_path— slug, title, and extension detectionwalk_files— default include/exclude behaviour,node_modules/.git/.DS_Storefiltering,--max-bytesskip, single-file root, missing-path errors, custom--includeoverridesfile_to_document— Markdown/HTML body shape, view-URL prefix override, unsupported-extension rejection/index.document --path— synthesizes aDocumentDefinition, dry-run skips the API, directory-passed errors, missing-permissions errors, mutex with--from-file, mutex of--publicand--acl-from-file/index.bulk-documents --path— folder walk produces a pagedBulkIndexDocumentsRequest,--includefiltering, dry-run, backward compat with--from-file
tests/test_commands_extended.py and tests/test_client_extended.py (33 new tests) — covers the Custom Metadata API surface:
GleanClientmethodsset_metadata_schema,get_metadata_schema,delete_metadata_schema,attach_metadata,detach_metadata— correct HTTP methods (PUT/GET/DELETE), correct paths under/rest/api/index, body shape, indexing-token requirement_mock_indexing_responsefor/custom-metadata/schema/{group}(schema-shaped GET, ack-style PUT/DELETE) and/document/{docId}/custom-metadata/{group}(ack-style PUT/DELETE)/metadata.set-schema— required--group, mutual exclusion of--from-fileand--keys, inline-key parsing (name:TYPE[:skip]), invalid-type rejection,--dry-runskip, no-token error, file-list-form parsing/metadata.get-schema,/metadata.delete-schema— required--group, no-token error, correct client-method invocation/metadata.attach— required--doc-idand--group, mutual exclusion of--from-fileand--values, inline-value parsing, malformed-value rejection,--dry-runskip, no-token error/metadata.detach— required flags, no-token error, correct client-method invocation
tests/test_mock_corpus.py (35 new tests) — covers the fake corpus behind mock mode:
- Ranking — relevant document first, distinct top hits for distinct queries, match-all ordered by freshness,
--datasourcefiltering, page padding when nothing matches, page-size cap - Snippets and metadata — snippet drawn from the sentence matching the query, author and relative freshness on every result
- Placeholders —
{Q}/{Q+1}/{FY}expansion, next quarter differs from current, no raw placeholders leak into results - Cross-endpoint coherence — a
/searchresult URL resolves through/getdocumentsand/summarizeto the same document,/chatcitations track the question,/getdocumentpermissionsowner is the document author,/peoplereads the roster - Custom corpus files —
mock_corpus_pathandGLEAN_MOCK_CORPUSoverrides (config wins), bare-array form, andCorpusErroron a missing file, invalid JSON, a document with no title, or an empty document list
tests/test_install.py (10 new tests) — covers app-bundle ownership in the installer:
bundle_identifier/owns_bundle— readsCFBundleIdentifierout ofInfo.plist; a missing bundle counts as ours (nothing to clobber), a foreign identifier and an unreadable or binary plist do not- Refusal —
install_macos_appexits rather than writing into a bundle it did not create, leaving that bundle'sInfo.plistbyte-identical and creating noContents/Resources - Legacy cleanup — an old
Glean.appis removed on install when we own it, and left alone when it belongs to another app - Uninstall — removes our own bundle, and never deletes a foreign one (the regression that would have deleted a user's Glean Desktop install)
- The default
APP_DIRis asserted not to beGlean.app
tests/test_mcp.py (9 new tests) — covers mock mode on the MCP server:
_build_client— forces live mode whatevermodethe config file carries (includingauto), and switches to mock only whenGLEAN_MOCKis set; truthy spellings (1,true,yes,on) accepted, everything else ignored- Labelling — all four tools (
search,chat,list_agents,run_agent) prefix their response with the[MOCK MODE]banner when serving fake data, including empty-result responses, and never in live mode - Tool descriptions — every tool docstring names
GLEAN_MOCK, so the warning reaches the agent before it calls anything
tests/test_mcp_control.py (36 new tests) — covers /mcp server control:
- Package diagnostics — reports the installed
mcpversion and whether it can actually run the server (v1 providesmcp.server.fastmcp; v2 does not) - State file — roundtrip, unreadable-file tolerance, and clearing a stale entry when the recorded pid is dead or has been reused by another process
startrefusals — stdio (which needs a client on the other end), unknown transports, missing package, an incompatible v2 install named by version, and a second start while one is runningstop— signals and clears state; a no-op when nothing is running- Client config — the stdio command form and the URL form, both JSON-serialisable
- Defaults — loopback-only bind, non-stdio default transport, and tool names checked against
glean_mcp.pyitself - Command dispatch — bare
/mcpshows status, unknown subcommands and clients error,--urlwithout a server errors, a non-numeric--porterrors
Every test redirects the state and log paths at a temp directory, so ~/.gleancode/ is never touched.
tests/test_flow.py (58 new tests) — covers the flow mapper:
- Capture gating — the
flow_capturekey defaults tomock, so live tenant content is never recorded by accident;onrecords both modes andoffrecords nothing - Capture — chat turns, citations, and search snippets land in SQLite; a shared
chatIdis one session and a new one starts another; every row is tagged with instance and mode; a capture failure cannot break the API call - Enrichment — document text is fetched, and comes from
/getdocumentsnow that the mock returns a body - Linking — identifier links are exact and score 1.0; two sessions with no shared wording connect through a document that mentions the other's subject in passing; link evidence is asserted to be specific rather than generic; links never cross an instance or mode partition
- Title anchoring — the scorer prefers a word from the other document's title over a rarer word that appears nowhere meaningful, which is what stops "across" and "percent" being offered as evidence
- Queries and purge — summary, collapsed, and single-session views are JSON-serialisable; purge is scoped to a partition or clears everything
- Rendering — the timeline is self-contained (no external references), well-formed HTML, badges mock data, renders connections with their evidence, and handles an empty database
- Command dispatch — bare
/flowshows status, unknown subcommands error, and bad--min-score/--limit/--docsvalues are rejected - Schema migration — a database written before
session_linkscarriedto_docgains the column on open, keeps its existing rows, and can be reopened repeatedly without the migration running twice /flow showrendering — sessions hang off a vertical rail, documents are labelled with their datasource, and a connection branches off with both document titles, the shared evidence, and the session number it reaches- Colour is decoration — with colour disabled the output contains no escape sequences and every structural glyph (
●─,│,├──◆,↓,▪) is still present, so the shape survives being piped - Width — no line exceeds the terminal width at 40, 58, 84, or 120 columns, with colour on and off. Measured on visible width, since ANSI escapes have zero display width and
len()would pass a broken layout - Ordering — informative links (
linked-document) come before trivial ones (shared-citation) regardless of score, verified against a database built by running the same investigation twice; documents a thread returned to lead the list, and singly-cited ones keep citation order rather than being interleaved by rank - Overflow —
--linkscaps connections per session and counts the remainder, and both--docsand--linksreject non-integers - Datasource colours — known sources each get a distinct colour, lookup ignores case and padding, and an unknown source falls back to grey rather than borrowing a familiar source's colour
The module patches out the mock client's simulated 0.25s network latency; without that these 58 tests take 31 seconds instead of 2.