4e64544aae
CI / benchmark-publish (pull_request) Has been skipped
CI / quality (pull_request) Successful in 48s
CI / build (pull_request) Successful in 31s
CI / helm (pull_request) Successful in 21s
CI / lint (pull_request) Successful in 3m15s
CI / typecheck (pull_request) Successful in 4m4s
CI / security (pull_request) Successful in 4m13s
CI / unit_tests (pull_request) Successful in 4m28s
CI / docker (pull_request) Successful in 1m52s
CI / integration_tests (pull_request) Successful in 7m14s
CI / coverage (pull_request) Successful in 12m49s
CI / e2e_tests (pull_request) Successful in 22m8s
CI / status-check (pull_request) Successful in 2s
CI / benchmark-regression (pull_request) Successful in 57m27s
Add explicit indexing timeout bounds and propagate timeout_seconds through the repo indexing service, utility walker, and CLI entrypoint so large repositories fail predictably instead of hanging. Add 10K-scale Behave/Robot verification and a dedicated benchmark path to validate that large-project indexing completes, persists status correctly, and remains measurable for regressions. Address review feedback by splitting oversized Behave and Robot support files into focused modules, trimming repo_indexing_service.py back under the 500-line limit, and rebasing the branch onto current master. ISSUES CLOSED: #851 # Conflicts: # CHANGELOG.md # robot/helper_m5_e2e_verification.py
280 lines
13 KiB
Gherkin
280 lines
13 KiB
Gherkin
# Repository indexing service tests targeting issue #195.
|
|
@feature195
|
|
Feature: Repository indexing with incremental refresh and language detection
|
|
As a CleverAgents user with a large project
|
|
I want the system to index my repository files with language detection
|
|
So that context assembly can efficiently retrieve relevant code fragments
|
|
|
|
# -- Full index ----------------------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Full index of a repository with mixed file types
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When I run repo-index full index on the sample directory
|
|
Then the repo-index result status should be "ready"
|
|
And the repo-index result file count should be 6
|
|
And the repo-index primary language should be "python"
|
|
And the repo-index token estimate should be positive
|
|
|
|
@feature195
|
|
Scenario: Indexed files have correct language detection
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When I run repo-index full index on the sample directory
|
|
Then the repo-index file "main.py" should have language "python"
|
|
And the repo-index file "index.ts" should have language "typescript"
|
|
And the repo-index file "README.md" should have language "markdown"
|
|
And the repo-index file "config.json" should have language "json"
|
|
And the repo-index file "Makefile" should have language "makefile"
|
|
|
|
@feature195
|
|
Scenario: Index is persisted and can be retrieved
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When I run repo-index full index on the sample directory
|
|
And I query repo-index for the indexed resource
|
|
Then the repo-index retrieved index should match the original
|
|
And the repo-index retrieved file hashes should match the original
|
|
|
|
# -- Incremental refresh -------------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Incremental refresh detects changed files
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
And I run repo-index full index on the sample directory
|
|
When I modify repo-index file "main.py" with new content
|
|
And I run repo-index incremental refresh
|
|
Then the repo-index file "main.py" content hash should differ from original
|
|
And the repo-index file "index.ts" content hash should match original
|
|
|
|
@feature195
|
|
Scenario: Refresh on non-existent index falls back to full index
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When I run repo-index incremental refresh
|
|
Then the repo-index result status should be "ready"
|
|
And the repo-index result file count should be 6
|
|
|
|
# -- Policy enforcement --------------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Max file size excludes large files
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files and a 2MB file
|
|
When I run repo-index full index with max file size 1000000 bytes
|
|
Then the repo-index result should not include file "big_file.dat"
|
|
And the repo-index result file count should be 6
|
|
|
|
@feature195
|
|
Scenario: Include globs filter to matching files only
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When I run repo-index full index with include globs "*.py"
|
|
Then the repo-index result file count should be 2
|
|
And the repo-index primary language should be "python"
|
|
|
|
@feature195
|
|
Scenario: Exclude globs remove matching files
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When I run repo-index full index with exclude globs "*.md,*.json"
|
|
Then the repo-index result should not include file "README.md"
|
|
And the repo-index result should not include file "config.json"
|
|
|
|
@feature195
|
|
Scenario: Max total size truncates indexing
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files and a 2MB file
|
|
When I run repo-index full index with max total size 100 bytes
|
|
Then the repo-index result file count should be less than 6
|
|
|
|
@feature195
|
|
Scenario: Indexing 10,000 files completes within timeout bound
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with 10000 python files
|
|
When I run repo-index full index with timeout of 120 seconds
|
|
Then the repo-index result status should be "ready"
|
|
And the repo-index result file count should be 10000
|
|
And the repo-index indexing elapsed seconds should be less than 120
|
|
|
|
# -- Removal -------------------------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Remove index cleans up all records
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
And I run repo-index full index on the sample directory
|
|
When I remove the repo-index for the resource
|
|
Then querying repo-index for the resource should return nothing
|
|
|
|
@feature195
|
|
Scenario: Remove non-existent index returns false
|
|
Given a repo-index fresh in-memory indexing service
|
|
When I remove the repo-index for a non-existent resource
|
|
Then the repo-index removal result should be false
|
|
|
|
# -- Error handling ------------------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Index with empty resource ID raises error
|
|
Given a repo-index fresh in-memory indexing service
|
|
When I attempt repo-index with empty resource ID
|
|
Then a repo-index ValueError should be raised mentioning "non-empty"
|
|
|
|
@feature195
|
|
Scenario: Index with non-existent path raises error
|
|
Given a repo-index fresh in-memory indexing service
|
|
When I attempt repo-index with non-existent path "/nonexistent/xyz"
|
|
Then a repo-index FileNotFoundError should be raised
|
|
|
|
@feature195
|
|
Scenario: Index with invalid ULID resource ID raises error
|
|
Given a repo-index fresh in-memory indexing service
|
|
When I attempt repo-index with invalid ULID resource ID
|
|
Then a repo-index ValueError should be raised mentioning "valid ULID"
|
|
|
|
# -- Status query ---------------------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Get index status returns metadata without file records
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
And I run repo-index full index on the sample directory
|
|
When I query repo-index status for the indexed resource
|
|
Then the repo-index status metadata should have status "ready"
|
|
And the repo-index status metadata file count should be 6
|
|
|
|
# -- Additional edge cases -----------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Index with file path as root raises error
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When I attempt repo-index with a file path as root
|
|
Then a repo-index ValueError should be raised mentioning "not a directory"
|
|
|
|
@feature195
|
|
Scenario: Index on empty directory returns zero files with ready status
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index empty temporary directory
|
|
When I run repo-index full index on the sample directory
|
|
Then the repo-index result status should be "ready"
|
|
And the repo-index result file count should be 0
|
|
And the repo-index primary language should be "unknown"
|
|
|
|
# -- Refresh error paths -------------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Refresh with non-existent path raises error
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
And I run repo-index full index on the sample directory
|
|
When I attempt repo-index refresh with non-existent path "/nonexistent/xyz"
|
|
Then a repo-index FileNotFoundError should be raised
|
|
|
|
@feature195
|
|
Scenario: Refresh with file path as root raises error
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
And I run repo-index full index on the sample directory
|
|
When I attempt repo-index refresh with a file path as root
|
|
Then a repo-index ValueError should be raised mentioning "not a directory"
|
|
|
|
# -- Fault tolerance paths -----------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Walk failure on fresh resource persists ERROR status
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When repo-index walk is mocked to fail and I index a fresh resource
|
|
Then a repo-index error should be raised
|
|
And querying repo-index status for the resource should show "error"
|
|
|
|
@feature195
|
|
Scenario: Walk failure on existing resource preserves previous index
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
And I run repo-index full index on the sample directory
|
|
When repo-index walk is mocked to fail and I re-index
|
|
Then a repo-index error should be raised
|
|
And the repo-index previous index should still be retrievable with 6 files
|
|
|
|
@feature195
|
|
Scenario: Refresh walk failure preserves previous good index
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
And I run repo-index full index on the sample directory
|
|
When repo-index walk is mocked to fail and I refresh
|
|
Then a repo-index error should be raised
|
|
And the repo-index previous index should still be retrievable with 6 files
|
|
|
|
# -- Stale indexing cleanup ------------------------------------------------
|
|
|
|
@feature195
|
|
Scenario: Cleanup stale indexing removes orphan INDEXING rows
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index stale INDEXING row is inserted for a resource
|
|
When I call repo-index cleanup stale indexing
|
|
Then the repo-index cleanup should report 1 stale row removed
|
|
And querying repo-index for the stale resource should return nothing
|
|
|
|
# -- Edge cases: unreadable files, naive datetimes -----------------------
|
|
|
|
@feature195
|
|
Scenario: Unreadable file is skipped without crashing index
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with a file that fails hashing
|
|
When I run repo-index full index with hash failure on "secret.dat"
|
|
Then the repo-index result status should be "ready"
|
|
And the repo-index result should not include file "secret.dat"
|
|
|
|
@feature195
|
|
Scenario: Re-index replaces existing index completely
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
And I run repo-index full index on the sample directory
|
|
When I add a new file "extra.py" and re-index
|
|
Then the repo-index result file count should be 7
|
|
And the repo-index result status should be "ready"
|
|
|
|
@feature195
|
|
Scenario: Naive datetime is coerced to UTC in FileRecord
|
|
Given a repo-index fresh in-memory indexing service
|
|
When I create a FileRecord with a naive datetime
|
|
Then the FileRecord last_modified should have UTC timezone
|
|
|
|
@feature195
|
|
Scenario: Naive datetime is coerced to UTC in IndexMetadata
|
|
Given a repo-index fresh in-memory indexing service
|
|
When I create an IndexMetadata with a naive datetime
|
|
Then the IndexMetadata indexed_at should have UTC timezone
|
|
|
|
# -- Domain model structural assertions ----------------------------------
|
|
|
|
@feature195
|
|
Scenario: IndexMetadata has all spec-required fields
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When I run repo-index full index on the sample directory
|
|
Then the repo-index metadata should have field "index_id"
|
|
And the repo-index metadata should have field "resource_id"
|
|
And the repo-index metadata should have field "indexed_at"
|
|
And the repo-index metadata should have field "file_count"
|
|
And the repo-index metadata should have field "token_estimate"
|
|
And the repo-index metadata should have field "primary_language"
|
|
And the repo-index metadata should have field "status"
|
|
|
|
@feature195
|
|
Scenario: FileRecord has all spec-required fields
|
|
Given a repo-index fresh in-memory indexing service
|
|
And a repo-index temporary directory with sample project files
|
|
When I run repo-index full index on the sample directory
|
|
Then each repo-index file record should have field "path"
|
|
And each repo-index file record should have field "content_hash"
|
|
And each repo-index file record should have field "token_count"
|
|
And each repo-index file record should have field "language"
|
|
And each repo-index file record should have field "size_bytes"
|
|
And each repo-index file record should have field "last_modified"
|