Skip to content

Conversation

@Leo-Fish
Copy link

@Leo-Fish Leo-Fish commented Oct 29, 2025

Hi! I ran NonDex Tool created by the researchers of UIUC on the test suite and found several tests with nondeterministic behavior. They're passing in normal CI but have dependencies on environment factors like hashmap iteration order and JVM version, which could potentially cause issues in different environments.

Nondeterministic tests identified:

  • org.mitre.synthea.export.flexporter.CustomFHIRPathResourceGeneratorR4Test.testArray1
  • org.mitre.synthea.world.agents.PersonTest.testPersonRecreationSerialDifferentGenerator
  • org.mitre.synthea.world.agents.PersonTest.testPersonFhirSTU3Recreation
  • org.mitre.synthea.world.agents.PersonTest.testPersonRecreationParallel
  • org.mitre.synthea.world.agents.PersonTest.testPersonFhirDSTU2Recreation
  • org.mitre.synthea.world.agents.PersonTest.testPersonFhirR4Recreation
  • org.mitre.synthea.world.agents.PersonTest.testPersonCcdaRecreation

Reproduce

1 build the project
./gradlew build -x test
2. Add the following to the plugins block in your build.gradle file:
plugins { id 'edu.illinois.nondex' version '2.1.7' }

3.Run NonDex on the specific test:
./gradlew nondexTest --tests=org.mitre.synthea.export.flexporter.CustomFHIRPathResourceGeneratorR4Test.testArray1 --nondexRuns=50
(You can replace the test method/class with the other affected tests listed above)

Happy to provide more details on any of these if helpful!

* Add sorting to ensure HashMap iteration order is deterministic
@Leo-Fish
Copy link
Author

Fixed: CustomFHIRPathResourceGeneratorR4Test.testArray1

Cause of nondeterminism: HashMap's non-deterministic iteration order in the sortedPaths() method caused inconsistent test results.

Proposed fix: Added explicit sorting with Collections.sort() to all three path categories (whereEquals, whereUnequals, withoutWhere) before combining them. This ensures deterministic ordering regardless of HashMap iteration order.

Note: Production code (Actions.java:422, createFhirPathMapping) already uses LinkedHashMap to address this issue in commit: 47fc1a9, but test code not being updated. I could apply the same LinkedHashMap approach here, but explicit sorting is more robust and prevents this in the future development. Happy to change to LinkedHashMap if you'd prefer to keep the approaches consistent :)

Changes:

  • Added Collections.sort() calls for all three path categories in sortedPaths()

Commit: c3da5c6

@Leo-Fish
Copy link
Author

Fixed: PayerTest.receiveMedicaidPregnancyEligible

Cause of nondeterminism: HashMap's non-deterministic iteration order in CSVEligibility constructor. While SimpleCSV.parseLineByLine() correctly returns LinkedHashMap, removeBlankMapStringValues() converted it back to HashMap, destroying insertion order and making the process non-deterministic.

Proposed fix: Modified removeBlankMapStringValues() to preserve LinkedHashMap type by specifying LinkedHashMap::new as the map supplier in Collectors.toMap(). This maintains the original CSV column order throughout the eligibility processing pipeline.

Changes:

  • Updated PlanEligibilityFinder.removeBlankMapStringValues() to use LinkedHashMap::new collector

Commit: c3da5c6

@codecov
Copy link

codecov bot commented Oct 29, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77%. Comparing base (0da3b77) to head (c3da5c6).
⚠️ Report is 4 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff            @@
##             master   #1627   +/-   ##
========================================
- Coverage        77%     77%   -1%     
+ Complexity     4066    4062    -4     
========================================
  Files           180     180           
  Lines         25333   25340    +7     
  Branches       3615    3615           
========================================
- Hits          19678   19663   -15     
- Misses         4522    4545   +23     
+ Partials       1133    1132    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 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.

Leo-Fish and others added 2 commits October 29, 2025 17:12
…PersonTest

- Use LinkedHashSet in ClinicalNoteExporter for deterministic clinical note ordering
- Use ConcurrentSkipListMap for Person.chronicMedications
- Use LinkedHashMap in HealthRecord and Demographics
@Leo-Fish
Copy link
Author

Leo-Fish commented Dec 4, 2025

Fixed: Remaining indeterministic PersonTest. All issues stemmed from HashMap/Set iteration order.

Summary of Changes:

Fix for CCDA/FHIR Recreation: Updated ClinicalNoteExporter to use LinkedHashSet instead of HashSet for active condition sets.
Fix for Parallel/Serial Recreation: Updated Person.chronicMedications to use ConcurrentSkipListMap instead of ConcurrentHashMap.
HealthRecord: Updated HealthRecord.present to use LinkedHashMap to fix condition-reason matching order.
Demographics: Updated Demographics to use LinkedHashMap for CSV data parsing to ensure consistent person generation.

@Leo-Fish Leo-Fish changed the title [WIP] Fix nondeterministic tests Fix non-deterministic tests caused by iteration order Dec 4, 2025
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