Skip to content

feat(AppHost): add WithShowStatsCommand for local dev stats#264

Merged
mpaulosky merged 2 commits into
devfrom
squad/261-add-withshowstatscommand
May 8, 2026
Merged

feat(AppHost): add WithShowStatsCommand for local dev stats#264
mpaulosky merged 2 commits into
devfrom
squad/261-add-withshowstatscommand

Conversation

@mpaulosky

Copy link
Copy Markdown
Owner

Closes #261

Working as Sam (Backend/.NET)

Changes

  • Added WithShowStatsCommand to MongoDbResourceBuilderExtensions
  • Command name: show-myblog-stats, display: 📊 Show MyBlog Stats
  • Returns Markdown table of collection document counts via CommandResultData with DisplayImmediately = true
  • Empty DB returns *(no collections found)* row with Success = true
  • Shared _clearMutex prevents concurrent operations (non-blocking WaitAsync(0))
  • Skips system.* collections consistent with clear command
  • UpdateState gates on HealthStatus.HealthyEnabled, else Disabled
  • Unit tests: MongoDbStatsCommandTests (5 tests)
  • Collection definition: Infrastructure/MongoStatsIntegrationCollection
  • Integration tests: MongoShowStatsIntegrationTests (3 tests)
  • All 16 prior unit tests continue to pass

- Add WithShowStatsCommand private method to MongoDbResourceBuilderExtensions
- Command name: 'show-myblog-stats', display: '📊 Show MyBlog Stats'
- Returns Markdown table of collection document counts via CommandResultData
  with Format = Markdown and DisplayImmediately = true
- Empty DB returns '*(no collections found)*' row with Success = true
- Shared _clearMutex prevents concurrent operations (non-blocking WaitAsync(0))
- Skips system.* collections consistent with clear command
- UpdateState gates on HealthStatus.Healthy → Enabled, else Disabled
- Wire builder.WithShowStatsCommand(databaseName) in WithMongoDbDevCommands
- Unit tests: MongoDbStatsCommandTests (5 tests)
- Collection definition: Infrastructure/MongoStatsIntegrationCollection
- Integration tests: MongoShowStatsIntegrationTests (3 tests)
- All 16 prior unit tests continue to pass

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 8, 2026 16:59
@mpaulosky mpaulosky added the squad Squad triage inbox — Lead will assign to a member label May 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Aspire dashboard operator command for local development to display MongoDB collection document counts (“show-myblog-stats”), along with unit and integration tests in AppHost.Tests.

Changes:

  • Registers WithShowStatsCommand in WithMongoDbDevCommands and returns Markdown output via CommandResultData (displayed immediately).
  • Implements non-blocking concurrency gating via the shared _clearMutex and skips system.* collections.
  • Adds new unit and integration test coverage scaffolding for the stats command.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/AppHost/MongoDbResourceBuilderExtensions.cs Adds WithShowStatsCommand and wires it into the existing MongoDB dev commands pipeline.
tests/AppHost.Tests/MongoDbStatsCommandTests.cs Adds model-level tests for stats command annotation/state behavior.
tests/AppHost.Tests/MongoShowStatsIntegrationTests.cs Adds integration tests invoking the new command against a real Aspire+MongoDB container.
tests/AppHost.Tests/Infrastructure/MongoStatsIntegrationCollection.cs Adds an xUnit collection definition for stats integration tests.

Comment on lines +51 to +54
result.Success.Should().BeTrue("the handler must succeed when MongoDB is reachable");
result.Message.Should().Contain("collection(s)",
"the success message must report the number of collections found");
}
// Assert
result.Success.Should().BeTrue("an empty database must still return success — no collections is not an error");
result.Message.Should().Contain("0 collection(s)",
"the message must indicate zero collections were found in the empty database");

// Assert
annotation.Should().NotBeNull(
"the mongodb resource must expose a 'show-myblog-stats' operator action per issue #261");
var client = new MongoClient(connectionString);
var database = client.GetDatabase(databaseName);

var namesCursor = await database.ListCollectionNamesAsync(cancellationToken: context.CancellationToken);
@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Test Results Summary

331 tests  +8   330 ✅ +8   19s ⏱️ ±0s
  6 suites ±0     1 💤 ±0 
  6 files   ±0     0 ❌ ±0 

Results for commit 2d0289e. ± Comparison against base commit 924edfc.

♻️ This comment has been updated with latest results.

@codecov

codecov Bot commented May 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.70115% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.57%. Comparing base (924edfc) to head (2d0289e).

Files with missing lines Patch % Lines
src/AppHost/MongoDbResourceBuilderExtensions.cs 97.70% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #264      +/-   ##
==========================================
+ Coverage   85.56%   86.57%   +1.01%     
==========================================
  Files          44       44              
  Lines         956     1043      +87     
  Branches      115      116       +1     
==========================================
+ Hits          818      903      +85     
- Misses         94       96       +2     
  Partials       44       44              
Files with missing lines Coverage Δ
src/AppHost/MongoDbResourceBuilderExtensions.cs 94.88% <97.70%> (+1.08%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mpaulosky

Copy link
Copy Markdown
Owner Author

❌ Aragorn Review — Changes Required (1 CI Failure)

Failing test: ShowMyBlogStats_Concurrent_Invocations_Allow_Only_One_Run

CI result: AppHost.Tests — 47 passed, 1 failed, 1 skipped.

Error from runner:

Expected results.Count(static r => r.Success) to be 1 because the semaphore
should allow only one stats operation to run at a time, but found 2.
  at MongoShowStatsIntegrationTests.cs:line 96

Root cause

The concurrent test calls PrepareAsync(blogPostCount: 0) — an empty database.
The stats handler for an empty DB is essentially instantaneous:

  1. Acquires mutex
  2. Resolves connection string (already cached in the fixture)
  3. ListCollectionNamesAsync → empty cursor, returns in microseconds
  4. Builds the one-row empty-table markdown
  5. Releases mutex — well before the second Task.WhenAll task has a chance to call WaitAsync(0)

Both tasks succeed → assertion fails.

Compare with ClearMyBlogData_Concurrent_Invocations_Allow_Only_One_Run (passing ✅): it seeds 50 posts + 50 comments + 50 tags = 150 docs before firing two concurrent tasks. That gives the first task real I/O work to do while holding the mutex, so the overlap window exists.


Required fix

In MongoShowStatsIntegrationTests.cs, change the concurrent test's arrange step:

// BEFORE — empty DB, first operation completes before second even starts
await PrepareAsync(blogPostCount: 0);

// AFTER — enough documents to hold the mutex open while the 2nd task races
await PrepareAsync(blogPostCount: 50);

One-line fix. The exact count isn't critical; anything that makes the handler do real DB work (network round-trip + document counting) is sufficient.


Everything else ✅

Checklist item Result
File headers on all 3 new .cs files
No .squad/ files in diff
Command name "show-myblog-stats" hardcoded
CommandResultData { Format = Markdown, DisplayImmediately = true }
Empty DB → *(no collections found)* row
system.* collections filtered out
_clearMutex.WaitAsync(0) non-blocking guard reused
IsHighlighted = false (default; unit test verifies)
WithShowStatsCommand wired into WithMongoDbDevCommands
xUnit collection definition follows existing pattern
[Collection("MongoStatsIntegration")] on integration test class
Code style matches existing file
Codecov patch ✅ project ✅ — no coverage decrease
All other 16 CI checks (CodeQL, build, Web/Domain/Arch/Bunit/Integration)

One fix needed, then this is ready to squash-merge. 🎯

— Aragorn, Lead Developer

…ndow

The empty-DB path completes in microseconds, so both concurrent
invocations succeed before either releases the semaphore. Seeding 50
documents gives the first task real I/O work, ensuring the second
task hits WaitAsync(0) while the semaphore is held.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mpaulosky
mpaulosky merged commit 002b5bb into dev May 8, 2026
18 checks passed
@mpaulosky
mpaulosky deleted the squad/261-add-withshowstatscommand branch May 8, 2026 17:16
mpaulosky added a commit that referenced this pull request May 8, 2026
## Sprint 18 — AppHost MongoDB Dev Commands Refactor

This release promotes all Sprint 18 work from `dev` to `main`.

### What's included

#### Feature work
- **#262** — `refactor(apphost): extract WithClearDatabaseCommand into
MongoDbResourceBuilderExtensions`
- **#263** — `feat(AppHost): add WithSeedDataCommand for local dev
seeding`
- **#264** — `feat(AppHost): add WithShowStatsCommand for local dev
stats`
- **#267** — `refactor: rename _clearMutex to _dbMutex in
MongoDbResourceBuilderExtensions`

#### CI fixes
- **#270** — `fix(ci): Blog → README Sync — push to dev instead of main`
- **#271** — `fix(ci): add pre-flight token validation and fix
permissions block in squad-mark-released`

### CI status

- ✅ **Squad CI** (`ci.yml`) — green on latest `dev` commit
- ⚠️ **Test Suite** — 1 flaky test failure: `SeedMyBlogData Concurrent
Invocations Allow Only One Run` (timing-sensitive concurrency test; race
condition in test harness, not production code). All other 47 tests
pass. Squad CI gate is the authoritative pass/fail gate.

### Notes

- Last release tag: `v1.5.0`
- `dev` is 55 commits ahead of `main`
- No open Sprint 18 issues, no open PRs
- Merge strategy: squash merge per playbook

---

## Release Checklist

- [ ] Latest `dev` Squad CI is green ✅
- [ ] Release scope reviewed (Sprint 18 milestone closed, all 4 issues
merged)
- [ ] Breaking changes documented (none — additive AppHost extension
methods only)
- [ ] Flaky test acknowledged (`SeedMyBlogData Concurrent` — timing race
in test, not prod)
- [ ] Release notes drafted (see sprint summary above)
- [ ] Aragorn approval received
- [ ] Boromir confirms branch state and workflow health
- [ ] PR CI passes before merge
- [ ] Merge to `main` with squash merge
- [ ] Tag `main` with appropriate `vX.Y.Z` after merge + CI green

Closes the Sprint 18 release gate.
Working as Boromir (DevOps)

---------

Co-authored-by: Boromir <boromir@squad.dev>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

squad Squad triage inbox — Lead will assign to a member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add WithShowStatsCommand with unit and integration tests

2 participants