Skip to content

Resolve test app names from app.json to prevent silent CI test skips#9059

Merged
aholstrup1 merged 3 commits into
mainfrom
aholstrup1-subcontracting-test-investigation
Jul 7, 2026
Merged

Resolve test app names from app.json to prevent silent CI test skips#9059
aholstrup1 merged 3 commits into
mainfrom
aholstrup1-subcontracting-test-investigation

Conversation

@aholstrup1

@aholstrup1 aholstrup1 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

What & why

BCApps CI was silently skipping entire test apps. The parallel test dispatcher decided which test apps to run by matching each project's projects.json key (surfaced as BuildMetadata.ApplicationName, and also its groups.json name) against the app name the container reports (app.json "name"). Those two strings are required to be identical, but when they drift the app is dropped from the dispatch set and all of its tests are silently skipped while the build stays green.

This is how WIPTransferRemainderCreatedWhenOpenLineQuantityReduced (and the rest of the Subcontracting suite) failed in another build system yet never even ran in GitHub CI: Subcontracting-Tests (projects.json key) vs Subcontracting Test (app.json name).

A full scan found 7 affected test apps with this drift: Subcontracting Test (~22 test codeunits), Subscription Billing Test (~30), OnPrem Permissions Test, Statistical Accounts Test, Dynamics SL Migration Tests, Tests for MX DIOT Extension, and Basic Experience Tests. All were installed in the container but never dispatched.

Approach

Rather than hand-editing the metadata for all 7 (which fixes the symptom but leaves the mechanism fragile), this makes the dispatcher robust by using the authoritative source of truth. Get-InstalledTestAppNames now resolves each test app's name from its app.json (via AppJsonPath) using a new Get-AppNameFromMetadata helper, instead of trusting the projects.json key. That is the same string the container reports, so both the installed-name intersection and the downstream name-to-extensionId dispatch map line up, and any future key/name drift self-heals.

When the projects.json key and app.json name disagree, it emits a ::warning:: naming the offending app so the drift is visible instead of silent, while still dispatching the tests correctly.

Verified safe: all 40 legacy-bucket apps and every other test app already have key == app.json name, so switching the source of truth changes behavior only for the 7 that were broken.

Linked work

Fixes #

Related to AB#641388 (Subcontracting WIPTransferRemainderCreatedWhenOpenLineQuantityReduced failure surfaced and disabled by this change)
Related to AB#641478 (Subscription Billing IT DeferralsReleaseSucceedsWhenGLAccountHasDefaultDeferralTemplateAndJournalTemplNotMandatory failure surfaced and disabled by this change)

How I validated this

  • I read the full diff and it contains only changes I intended.
  • I built the affected app(s) locally with no new analyzer warnings.
  • I ran the change in Business Central and confirmed it behaves as expected.
  • I added or updated tests for the new behavior, or explained below why none are needed.

What I tested and the outcome

  • This is a build-script (PowerShell) change, not an AL app change, so there is no BC app to build or run.
  • Added build/scripts/tests/ParallelTestExecution.Test.ps1 (Pester). 5 tests, all green locally with Pester 5.7.1, covering: name resolved from app.json when it differs from the projects.json key, the aligned case, and both fallbacks (missing app.json path, empty path). The drift test also asserts Get-InstalledTestAppNames dispatches the app under its real installed name.
  • Confirmed against the real failing run (28391219041): extensionId 32b0d4d1 (Subcontracting Test) was installed but never appeared in any Dispatching '...' line in the W1 or US IntegrationTests jobs; no codeunit 149911 header and no test-function output were present. This change makes that app resolve into the dispatch set.

Risk & compatibility

  • No metadata files (projects.json, groups.json, app.json) are changed; this is purely a resolution-logic change in ParallelTestExecution.psm1.
  • Once merged, the ~7 previously-skipped test suites will start running in CI. Some may surface pre-existing real failures (for example the Subcontracting WIP transfer test), which is the intended outcome. Reviewers should expect newly-executing tests, not regressions from this change itself.
  • Two such pre-existing failures found so far have been temporarily added to their apps' DisabledTests JSON and tracked by AB#641388 and AB#641478.
  • Fallback preserves today's behavior for any app whose app.json cannot be read.
  • Follow-up worth considering (not in this PR): a guard test asserting projects.json key == groups.json name == app.json "name" for every test project, so drift is caught at PR time.

BCApps CI dispatched test apps by matching the projects.json key
(BuildMetadata.ApplicationName) against the container's installed app
name (app.json "name"). When those drift, the app is dropped from the
dispatch set and all of its tests are silently skipped while the build
stays green. This affected 7 test apps, including Subcontracting Test
(~22 test codeunits never run in any CI job).

Get-InstalledTestAppNames now resolves each test app's name from its
app.json via the new Get-AppNameFromMetadata helper, with a safe
fallback to ApplicationName and a CI warning when the two disagree.
Adds Pester coverage for the drift, aligned, and fallback cases.
@aholstrup1 aholstrup1 requested review from a team July 3, 2026 07:03
@github-actions github-actions Bot added the Build: scripts & configs Build scripts and configuration files label Jul 3, 2026
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Copilot PR Review

Iteration 3 · Outcome: no-knowledge

The diff contains no AL, JavaScript, CSS, or HTML files — only PowerShell build scripts (ParallelTestExecution.psm1, a new Pester test) and DisabledTest.json entries. None of the six al-* leaf skills found any changed AL/UI objects to build a worklist from, so each rolled up as no-knowledge/not-applicable with zero findings. The super-skill self-review pass examined the PowerShell logic (Get-AppNameFromMetadata: AppJsonPath is always populated and validated to exist by Get-ApplicationGroup/BuildMetadataProvider, the fallback path is defensive-only and correctly exercised by the new Pester tests) and found the change correct and well-tested; no cross-cutting defect cleared the agent-finding precision bar.

Knowledge source: https://github.com/microsoft/BCQuality@822cae1b2771ac25f665f73369f69093bd4fd630

No findings were posted for this iteration.

Orchestrator pre-filter (13 file(s) excluded)

  • layer-disabled (knowledge) : 13 file(s)

Findings produced by the Copilot CLI agent against BCQuality at 822cae1b2771ac25f665f73369f69093bd4fd630. Reply 👎 on any inline comment to flag false positives.

…enLineQuantityReduced

Once the CI dispatch fix lets the Subcontracting Test app run, the test
WIPTransferRemainderCreatedWhenOpenLineQuantityReduced (codeunit 149911)
fails, as already seen in the internal build system. Disable it via the
DisabledTests JSON to unblock CI; tracked by AB#641388.
@aholstrup1 aholstrup1 requested a review from a team July 3, 2026 11:09
spetersenms
spetersenms previously approved these changes Jul 3, 2026
…nGLAccountHasDefaultDeferralTemplateAndJournalTemplNotMandatory

The CI dispatch fix lets the Subscription Billing Test app run; it fails
in the IT (Italy) build with 'The record in table Payment Lines already
exists' while posting the vendor contract purchase invoice (codeunit
139913 Vendor Deferrals Test). Disable it via the DisabledTests JSON to
unblock CI; tracked by AB#641478.
Comment thread build/scripts/ParallelTestExecution.psm1
@aholstrup1 aholstrup1 merged commit 26ec320 into main Jul 7, 2026
484 of 498 checks passed
@aholstrup1 aholstrup1 deleted the aholstrup1-subcontracting-test-investigation branch July 7, 2026 09:16
aholstrup1 added a commit that referenced this pull request Jul 7, 2026
…9176)

## What & why

The `Run PS Tests` job started failing with:

```
CommandNotFoundException: Could not find Command Get-BcContainerAppInfo
```

`build/scripts/tests/ParallelTestExecution.Test.ps1` (added alongside
the test-dispatch fix in #9059) mocks `Get-BcContainerAppInfo`, which is
a **BcContainerHelper** cmdlet. That module is loaded when the build
runs inside a BC container, but it is **not** present in the `Run PS
Tests` runner. Pester 5 cannot mock a command that does not exist, so
the mock setup threw and the job failed. This was not caught before
merge because locally BcContainerHelper is usually loaded, so the mock
resolved against the real cmdlet.

## Linked work

<!-- No approved product issue: this is a CI/test-only fix for a break
introduced by #9059. -->

Fixes #

Related to #9059 (introduced the test), supersedes #9174 (which fixed
the same failure via a production module wrapper).

## How I validated this

- [x] I read the full diff and it contains only changes I intended.
- [x] I built the affected app(s) locally with no new analyzer warnings.
- [ ] I ran the change in Business Central and confirmed it behaves as
expected.
- [x] I added or updated tests for the new behavior, or explained below
why none are needed.

**What I tested and the outcome**

- This is a PowerShell test-only change; there is no BC app to build or
run.
- Reproduced the exact CI condition locally by running Pester with
module autoloading disabled so `Get-BcContainerAppInfo` is absent
(`Get-Command` returns nothing). Before the fix the mock setup threw
`CommandNotFoundException`; after the fix all 5 tests pass.
- The stub body intentionally `throw`s to document that it must never
execute; the tests passing proves every module call is intercepted by
Pester's mock, not the stub.

## Risk & compatibility

- Change is confined to a single Pester test file; no production build
script or module is touched (this is the key difference from #9174,
which added a wrapper to the shipped `ParallelTestExecution.psm1`).
- The stub is only defined when the real cmdlet is absent (i.e. the PS
test runner) and is removed in `AfterAll`, so it never shadows the real
BcContainerHelper cmdlet in a container and does not leak into other
test files.
- No behavioral change to `ParallelTestExecution.psm1` or the
test-dispatch logic.

---------

Co-authored-by: aholstrup1 <aholstrup1@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Build: scripts & configs Build scripts and configuration files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants