Skip to content

chore: reorg tests to mirror module structure, scope CI to changed files - #110

Merged
mikemadeja merged 2 commits into
developfrom
chore/reorg-tests-and-changed-file-ci
Sep 25, 2026
Merged

mikemadeja merged 2 commits into
developfrom
chore/reorg-tests-and-changed-file-ci

Conversation

@mikemadeja

Copy link
Copy Markdown
Owner

Summary

Two related changes, as requested:

1. Test folder reorg. Every per-function test file moves from a flat tests/ directory into tests/<Category>/, mirroring PiHoleShell/Public/<Category>/ exactly - e.g. PiHoleShell/Public/Actions/Invoke-PiHoleFlushNetwork.ps1 now pairs with tests/Actions/Invoke-PiHoleFlushNetwork.Integration.Tests.ps1. Shared support files (IntegrationConfig.example.ps1, IntegrationConfig.local.ps1, Initialize-PiHoleTestData.ps1) stay at tests/ root since they don't belong to any single function. Git tracked all 33 moves as renames. Updated every moved file's $PSScriptRoot-relative lookups for those shared files accordingly - Pester discovers tests recursively by default, so no change was needed on the Pester/pipeline path side for this part.

2. CI scoped to changed files. This mirroring is what makes this straightforward: the Azure DevOps pipeline now scopes PR builds to only the test file(s) matching whatever PiHoleShell/Public/<Category>/<Function>.ps1 files actually changed, instead of always running the entire suite (which includes many real-server integration tests individually taking 10-40+ seconds).

Direct pushes to develop/main still always run the full suite unchanged. On a PR build, anything that isn't a clean 1:1 function-to-test-file match falls back to the full suite rather than risk silently skipping coverage:

  • Changes to PiHoleShell/Private/*, PiHoleShell.psm1/.psd1, or the shared Request-PiHoleAuth helper (used by every function)
  • Changes to the shared test helpers (Initialize-PiHoleTestData.ps1, IntegrationConfig.example.ps1)
  • Any failure computing the diff itself (git fetch/diff error)
  • No test-relevant files changed at all (e.g. a docs-only PR)

Changed test files run directly; non-code changes (README, workflows, tools/) are ignored/have no effect on scope.

Test plan

  • Validated the scoping logic in isolation against 10 scenarios (single function change, multi-category change, function with no test file, shared/private file changes, docs-only change, direct test-file change) - all behaved as designed
  • Ran the actual dry-run script against this PR's real git diff vs develop - correctly resolved to exactly the 33 moved test files (this PR itself only touches tests, so that's the right scope)
  • Invoke-ScriptAnalyzer -Path .\PiHoleShell -Recurse - clean
  • Full non-integration suite passes with the new nested discovery (113 tests found, same as before the move)
  • Re-ran a representative slice of the moved integration tests (History, Config, Authentication - 20 tests) against the real Pi-hole server to confirm the $PSScriptRoot path fixes work end-to-end, not just in isolation

🤖 Generated with Claude Code

mikemadeja and others added 2 commits September 24, 2026 17:57
Moves every per-function test file from a flat tests/ directory into
tests/<Category>/, mirroring PiHoleShell/Public/<Category>/ exactly (e.g.
PiHoleShell/Public/Actions/Invoke-PiHoleFlushNetwork.ps1 now pairs with
tests/Actions/Invoke-PiHoleFlushNetwork.Integration.Tests.ps1). Shared
support files (IntegrationConfig.example.ps1, IntegrationConfig.local.ps1,
Initialize-PiHoleTestData.ps1) stay at tests/ root since they don't belong
to any single function. Updated every moved file's $PSScriptRoot-relative
path lookups for those shared files accordingly (Pester still discovers
tests recursively by default, so no path change was needed on the Pester
side).

This mirroring is what makes the second change straightforward: the Azure
DevOps pipeline now scopes PR builds to only the test file(s) matching
whatever PiHoleShell/Public/<Category>/<Function>.ps1 files actually
changed, instead of always running the entire suite (which includes many
real-server integration tests that individually take 10-40+ seconds).

Direct pushes to develop/main still always run the full suite. On a PR
build, anything that isn't a clean 1:1 function-to-test-file match falls
back to the full suite rather than risk silently skipping coverage:
changes to Private/ files, PiHoleShell.psm1/.psd1, the shared
Request-PiHoleAuth helper (used by every function), the shared test
helpers, or a failure computing the diff itself. Changed test files run
directly; non-code changes (README, workflows, tools/) are ignored.

Verified the scoping logic locally against real git diffs before trusting
it in CI, and re-ran a representative slice of the moved integration tests
against the real Pi-hole server to confirm the path fixes work end-to-end.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… windows

The changed-file scoping added in the previous commit failed on its first
real run: the default Azure Pipelines checkout is shallow, so there's no
common ancestor with the target branch to diff against ("no merge base"/
"unknown revision"). Fixed by unshallowing first when the repo is shallow,
and fetching the target branch with an explicit refspec so origin/<branch>
gets created even under a checkout whose default fetch refspec is
restricted to a single branch. Verified both fixes end-to-end against a
real shallow, single-branch clone before trusting them in CI again.

Because the scoping fallback ran the full suite on that failed attempt, it
also surfaced a real, pre-existing bug (unrelated to this PR, already
broken on main): Get-PiHoleHistoryDatabase/Get-PiHoleHistoryDatabaseClient
asserted `Should -Not -BeNullOrEmpty` on their history array, but an empty
array is a legitimate response when nothing was logged in the queried
window - unlike the Stats(database) summary endpoints, which always return
a populated object shape even with zero matching rows. Changed those
assertions to verify the call succeeds (and, when data is present, that
its shape is correct) instead of requiring non-empty results.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@mikemadeja
mikemadeja merged commit c61f505 into develop Sep 25, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant