Skip to content

IntegrationContext.StoreOptions leaves documents behind, so some tests only pass on a fresh database #398

Description

@jeremydmiller

What happens

Polecat.Tests/Harness/IntegrationContext.StoreOptions(...) builds a custom DocumentStore and calls ApplyAllConfiguredChangesToDatabaseAsync(), but never deletes existing data. Every test class that routes through it inherits whatever earlier runs left in its schema.

protected async Task<string> StoreOptions(Action<StoreOptions> configure)
{
    var options = new StoreOptions { ... };
    configure(options);

    _customStore = new DocumentStore(options);
    _database = _customStore.Database;
    await _database.ApplyAllConfiguredChangesToDatabaseAsync();   // schema only -- no data cleanup
    ...
}

Because the suite isolates by DatabaseSchemaName inside one shared master database rather than by database, that residue survives across runs indefinitely.

Concrete failure

Storage/single_tenant_has_no_tenant_id_column_tests.full_lifecycle_works_without_tenant_id_column (line 93):

Shouldly.ShouldAssertException : byLinq.Count
    should be
1
    but was
3

The class has two tests, both configured onto schema no_tenant_col, and both store a Widget. The lifecycle test then asserts Query<Widget>().Where(w => w.Name == "Original") returns exactly one row. On a second run that count is 2, then 3, and so on. Confirmed directly against the container:

1> SELECT COUNT(*) FROM master.no_tenant_col.pc_doc_widget;
7

Why CI never sees it

CI provisions a fresh SQL Server per run, so the table is always empty on the first pass. This is a local-only failure — and a confusing one, because it presents as a flaky assertion in an area the developer did not touch.

Suggested fix

Either is defensible; the second is the smaller blast radius:

  1. Have StoreOptions clean documents after applying schema changes (_customStore.Advanced.Clean.DeleteAllDocumentsAsync()), matching what a developer reasonably expects from a per-test store, or
  2. Fix the two tests to clean their own Widget rows — but note this pattern is not unique to that class, so (1) is likelier to be the real answer.

Worth auditing which other StoreOptions callers assert on absolute counts before choosing.

Found by

Compliance wave 2 (marten#5118 / marten#5123) — surfaced while establishing a trustworthy full-suite baseline. Not caused by that work.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions