[tests] Isolate JNI reference leak tests#12038
Conversation
Move JNI reference and peer leak checks into a dedicated serial MSTest/MTP app and run it under CoreCLR and Mono in CI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7be7d34c-aff3-4338-b15b-6061bc7a3ba9
There was a problem hiding this comment.
Pull request overview
This PR isolates JNI reference/peer leak checks into a dedicated on-device MSTest/Microsoft Testing Platform (MTP) test app (tests/JniReferenceLeakTests) to avoid flaky process-wide assertions caused by unrelated background activity in shared device test processes.
Changes:
- Added a dedicated
JniReferenceLeakTestsAndroid test app with serialized MSTest execution ([assembly: DoNotParallelize]) and focused leak/peer assertions. - Migrated/removed flaky or process-global JNI reference/peer-count assertions from shared device test suites; narrowed remaining assertions to object-specific checks or restricted them to non-Android runs.
- Wired the new test app into solution/test documentation and into CI (package tests for CoreCLR + Mono; nightly emulator coverage).
Show a summary per file
| File | Description |
|---|---|
| Xamarin.Android-Tests.slnx | Adds the new JniReferenceLeakTests project to the tests solution structure. |
| tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs | Removes the weak-peer surfaced-object drift test from the shared device suite. |
| tests/Mono.Android-Tests/Mono.Android-Tests/Android.Widget/CustomWidgetTests.cs | Removes the previously ignored/flaky custom-widget GREF leak test from the shared suite. |
| tests/JniReferenceLeakTests/JniReferenceLeakTests.csproj | New dedicated Android MSTest/MTP app project for leak/peer accounting tests. |
| tests/JniReferenceLeakTests/TestInstrumentation.cs | Implements an MTP-based Android Instrumentation runner for MSTest with TRX reporting. |
| tests/JniReferenceLeakTests/AssemblyInfo.cs | Disables MSTest parallelism at the assembly level to stabilize process-wide accounting. |
| tests/JniReferenceLeakTests/ReferenceTestHelpers.cs | Adds helpers to amplify leak detection and synchronize GC/peer collection. |
| tests/JniReferenceLeakTests/GlobalReferenceTests.cs | Adds amplified GREF leak checks (TryFindClass, activation, object arrays). |
| tests/JniReferenceLeakTests/LocalReferenceTests.cs | Adds thread-local LREF accounting checks in an isolated process. |
| tests/JniReferenceLeakTests/PeerReferenceTests.cs | Adds object-specific surfaced-peer assertions + weak-peer collection check in isolation. |
| tests/JniReferenceLeakTests/WidgetReferenceTests.cs | Reintroduces the custom-view inflate leak check in the isolated harness. |
| tests/JniReferenceLeakTests/Resources/layout/leak_test_widget.axml | Layout used to inflate a custom managed widget for the leak test. |
| tests/JniReferenceLeakTests/java/net/dot/jni/referenceleaktests/ActivationProbeFactory.java | Java-side factory to exercise Java-side activation paths. |
| tests/JniReferenceLeakTests/AndroidManifest.xml | Manifest for the new test app. |
| tests/JniReferenceLeakTests/global.json | Forces Microsoft Testing Platform runner behavior when invoking dotnet test. |
| tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/BindingTests.cs | Removes process-global GREF equality assertion from Java-side activation test. |
| external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniTypeUtf8Test.cs | Restricts process-global GREF leak assertions to non-Android runs. |
| external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniRuntimeJniValueManagerContract.cs | Changes peer assertions from total-count based to peer-specific checks; restricts GREF leak test to non-Android runs. |
| external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JniEnvironmentTests.cs | Restricts process-global reference-count assertions to non-Android runs. |
| external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectTest.cs | Restricts runtime-global surfaced-peer count assertion to non-Android runs. |
| external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaObjectArrayTest.cs | Restricts fixture-wide process-global GREF baseline checks to non-Android runs. |
| external/Java.Interop/tests/Java.Interop-Tests/Java.Interop/JavaArrayContract.cs | Restricts fixture-wide LREF baseline checks to non-Android runs (covered in new isolated app). |
| build-tools/automation/yaml-templates/stage-package-tests.yaml | Adds CI legs to run the new app under CoreCLR and Mono in package tests. |
| build-tools/automation/azure-pipelines-nightly.yaml | Adds nightly emulator coverage for the new isolated leak test app. |
| .github/skills/tests/references/test-catalog.md | Documents how to build/run the new dedicated leak test app locally. |
Copilot's findings
- Files reviewed: 25/25 changed files
- Comments generated: 0
Keep the dedicated on-device JNI reference leak checks on CoreCLR only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7be7d34c-aff3-4338-b15b-6061bc7a3ba9
Treat warnings as errors in the leak-test project locally so unavailable package versions fail before CI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7be7d34c-aff3-4338-b15b-6061bc7a3ba9
Track the stable TestFX release centrally and keep the leak-test project on MSTestPackageVersion with local warnings treated as errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7be7d34c-aff3-4338-b15b-6061bc7a3ba9
✅ New
|
Summary
[assembly: DoNotParallelize]Why
GREF and surfaced-peer counts are process-wide. The existing Android test apps load many unrelated fixtures into one process, and runtime or test-infrastructure work on background threads can change those totals while a test is taking before/after snapshots. Serializing NUnit workers did not prevent these failures.
The new app contains only reference-accounting tests and disables MSTest parallelism at the assembly level. Process-wide checks execute equal 100-operation warmup and measurement batches, allowing only a small fixed amount of ambient drift, so a per-operation leak is strongly amplified. Thread-local LREF checks retain exact accounting, while registry tests count only the specific peer under test.
Functional coverage remains in the original suites, and JVM-only accounting tests continue to run there. The custom-widget test previously quarantined under #11201 now passes reliably in the isolated process.
Validation
make prepare && make allwith serialized MSBuildTreatWarningsAsErrors=true: 0 warningsJniReferenceLeakTests: 12 passed, 0 failed, 0 skipped under CoreCLRJava.Interop-Tests: 672 passed, 4 existing skipsMono.Android.NET-Tests.csprojbuildgit diff --checkFixes #12031.
Supersedes #12037.