Repository navigation
Upgrade to support OpenMRS Platform 3.0 - #126
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fp7T1pGYEMrMVp1M7AW9Fg
|
|
||
| @RunWith(MockitoJUnitRunner.class) | ||
| @ExtendWith(MockitoExtension.class) | ||
| @MockitoSettings(strictness = Strictness.LENIENT) |
There was a problem hiding this comment.
Could this be narrowed to the one stub that needs it? Without the class-level setting, every failure comes from the shared getConceptByUuid stub in setupMocks(): five of the tests never call it, and the three invalid-GP tests call it with "invalid". Dropping this annotation and marking just that stub lenient keeps all 11 passing (I ran it):
lenient().when(conceptService.getConceptByUuid(conceptSet1.getUuid())).thenReturn(conceptSet1);That leaves strict stubs on for the per-test global property stubs. With the class-wide LENIENT, a test that stubs the wrong property passes on the mock's null default. For example, stubbing QUEUE_PRIORITY instead of QUEUE_SERVICE in getAllowedServices_shouldThrowErrorIfNoGpConfigured still gives 11/11 as it stands, but fails with a PotentialStubbingProblem once only the setup stub is lenient. Not blocking.
…up stub Only the getConceptByUuid stub in setupMocks() trips strict stubs: most tests never call it, and the invalid-GP tests call it with "invalid". Marking that one stub lenient() keeps strict stubs on for the per-test global property stubs, so a test that stubs the wrong property fails instead of passing on the mock's null default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dkayiwa
left a comment
There was a problem hiding this comment.
This needs a rebase onto main before it can go in, and the rebase is a port as well as a conflict fix: main picked up #119 (O3-5765) after this branch was cut, and none of that code has been built or run on Platform 3.
- Besides the seven conflicting files, four more merge cleanly with #119's changes and then fail test-compile here.
AutoCloseQueueEntryTaskTest,QueueModuleActivatorTestandAutoCloseQueueEntryTaskIntegrationTestare JUnit 4, and junit:junit isn't on this branch's test classpath. The last two also extend the JUnit 4org.openmrs.test.BaseModuleContextSensitiveTest, and the integration test builds its task withTaskFactory; core master has dropped both. The two tests #119 added toQueueServicesWrapperTestuse@Test(expected = ...), which Jupiter's@Testdoesn't have. I compiled each of these against this branch's classpath to confirm. QueueModuleActivatorregisters both tasks throughSchedulerService'sTaskDefinitionmethods. They still compile, but core 3.0 deprecates them and runs them onJobRunrSchedulerServicerather than the timer scheduler #119 was tested against on 2.7.4, and the test counts and server checks in the description all come from a branch without #119.
So what I'd hold the merge on is porting #119's tests in the rebase, then checking on a 3.0 server that both queue tasks register and fire.
| <activator>${project.parent.groupId}.${project.parent.artifactId}.QueueModuleActivator</activator> | ||
|
|
||
| <require_version>${openmrsPlatformVersion}</require_version> | ||
| <require_version>3.0.0</require_version> |
There was a problem hiding this comment.
Could the README's Prerequisites be updated in this PR too? It still says "OpenMRS Platform ≥ 2.3.x" and "Java 8 or higher", and with this line and maven.compiler.release set to 21, a 4.x build needs Platform 3.0.0 and Java 21.
| http://www.springframework.org/schema/beans/spring-beans.xsd | ||
| http://www.springframework.org/schema/context | ||
| http://www.springframework.org/schema/context/spring-context-3.0.xsd"> | ||
| http://www.springframework.org/schema/context/spring-context.xsd"> |
There was a problem hiding this comment.
Spring 7 doesn't need this change: spring-beans and spring-context 7.0.9 still map the versioned -3.0.xsd locations to their bundled schemas in META-INF/spring.schemas, and omod's webModuleApplicationContext.xml keeps the 3.0 ones. I'd drop these two lines so the diff stays on what the upgrade needs; if you'd rather have the versionless form, change omod's file too so the two don't disagree.
| http://www.springframework.org/schema/beans/spring-beans.xsd | |
| http://www.springframework.org/schema/context | |
| http://www.springframework.org/schema/context/spring-context-3.0.xsd"> | |
| http://www.springframework.org/schema/context/spring-context.xsd"> | |
| http://www.springframework.org/schema/beans/spring-beans-3.0.xsd | |
| http://www.springframework.org/schema/context | |
| http://www.springframework.org/schema/context/spring-context-3.0.xsd"> |
Brings in openmrs#119 (O3-5765) and the 3.1.0 release, and ports openmrs#119 to Platform 3: - updateIfUnmodified keeps openmrs#119's CriteriaUpdate, on jakarta.persistence and createMutationQuery. - openmrs#119's tests move to JUnit 5. QueueModuleActivatorTest and AutoCloseQueueEntryTaskIntegrationTest extend the Jupiter BaseModuleContextSensitiveTest, and the integration test runs the task through core's LegacyTask, which is how the JobRunr scheduler runs a task definition now that TaskFactory is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t.xml Spring 7 still maps the -3.0.xsd locations to its bundled schemas, which webModuleApplicationContext.xml already relies on, so the change was not needed for the upgrade. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dkayiwa
left a comment
There was a problem hiding this comment.
Before this merges I'd like the core side tracked, and there's more of it than the Depends on list names.
The server check was a fresh install. A site that ran queue 3.1.0 or later on 2.x already has both task definitions when it moves to Platform 3, so started() finds them and returns, and scheduling them is left to core's onStartup(). On core master that goes wrong in two places:
- The upgraded rows have no
creator(TRUNK-6391 added the column without copyingcreated_by), soonStartup()throws the NPE that openmrs/openmrs-core#6629 fixes, and startup fails. #6629 is still open. - With #6629 in,
onStartup()enqueues each task's startup run under the task's uuid, then looks for a job with that uuid to decide whether to callscheduleTask, finds that run, and skips it. Each task gets one run at startup and no recurring job.
I reproduced both in an integration test against snapshot 434, with the definitions as 2.x leaves them:
schedulerService.saveTaskDefinition(definition); // each task: startOnStartup, no JobRunr jobs
new QueueModuleActivator().started(); // finds them registered and returns
schedulerService.onStartup(); // what Listener.startOpenmrs calls
schedulerService.getRecurringTask(definition.getUuid()); // empty
schedulerService.getTask(definition.getUuid()); // present, the startup runThe same call does create the recurring job for a definition that isn't startOnStartup. A stop and start of the queue module ends the same way, since WebModuleUtil.stopModule still shuts the module's tasks down and TRUNK-6558 took SchedulerUtil.startup() out of refreshApplicationContext. So the Javadoc on QueueModuleActivator.registerTask, which says the scheduler starts the task at server startup and restores it across a module stop and start, now describes 2.x. I'd reword it here to say what 3.0 does.
None of these has a TRUNK ticket, and neither do the three in the description, so right now this description is the only record of them. Could you file them and list them, with #6629, under Depends on before this goes in? If 3.0.0 ships with #6629 but without the onStartup fix, a site upgrading from queue 3.1.0 or later gets one auto-close run at its first startup and none after.
On 2.x the scheduler rescheduled every start-on-startup task at server startup and whenever a module started. On 3.0 onStartup() does not recreate a task's missing recurring job, and starting a module no longer reschedules the tasks that stopping it shut down, since TRUNK-6558 took SchedulerUtil.startup() out of refreshApplicationContext. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|



Updates queue so it builds against, and runs on, openmrs-core master (Platform 3.0.0-SNAPSHOT: Java 21, Jakarta EE, Spring 7, Hibernate 7). Same approach as the platform 3 upgrades of calculation (openmrs/openmrs-module-calculation#19), legacyui and webservices.rest.
Changes
openmrs-bomimported) and webservices.rest 5.0.0-SNAPSHOT.-parameters.openmrs-test.config.xmlnow setsrequire_versionto 3.0.0, and the README's prerequisites say Platform 3.0.0 and Java 21. CI (release workflow and Bamboo) uses JDK 21.CriteriaBuilder.AbstractBaseQueueDaoImplkeeps its helper names.QueueEntryDaoImplfollows the predicate-builder shape from **refactor: migrate QueueEntryDaoImpl from deprecated Hibernate Criteria API to JPA CriteriaBuilder** #101, but without **refactor: migrate QueueEntryDaoImpl from deprecated Hibernate Criteria API to JPA CriteriaBuilder** #101's fetch joins /distinct, and keeps the newer "exclude entries of voided patients" join.saveOrUpdate/deletebecomeHibernateUtil.saveOrUpdate/remove, andupdateIfUnmodifiedruns O3-5765: Automatically clear queue entries on a schedule #119'sCriteriaUpdatethroughcreateMutationQuery.GenerationType.IDENTITY.QueueEntry.queueComingFrombecomes@ManyToOne. Many entries can come from the same queue, and Hibernate 7 adds a UNIQUE constraint for@OneToOne.QueueServicesWrapperTestmarks its sharedgetConceptByUuidsetup stublenient(), since not every test uses it; the rest of its stubs stay strict.AutoCloseQueueEntryTaskIntegrationTestruns the task through core'sLegacyTask, which is how the JobRunr scheduler runs a task definition now thatTaskFactoryis gone.TaskDefinitionAPI.scheduler_task_configis still what core restores scheduled tasks from at startup, which is why TRUNK-6752 was closed without removing that API.Depends on
queue.QueueEntryServiceis aTransactionProxyFactoryBeanwhose target referencesvisitServiceandadminService, which could leave those core services without core's advisors (Core service advisors are skipped when modules declare TransactionProxyFactoryBean services openmrs-core#6630).TaskDefinitionto annotations, which writescheduler_task_config.creator, but the oldcreated_bycolumn keepsDEFAULT 0and its FK tousers, so the insert fails onscheduler_creator.QueueModuleActivatorthen logs "Unable to register task" for both tasks.daemonrun without privileges.Daemon.executeScheduledTaskAsUserbecomes the scheduling user and then drops daemon status, and tasks registered at startup are scheduled bydaemon, which has no roles. The visit task fails withAPIAuthenticationException: Privileges required: Get Queue Entries, and the close-time task makes the samegetQueueEntriescall once its time is set. Core's own Auto Close Visits Task is scheduled asdaemontoo, since itscreatorcolumn is null.JobRunrSchedulerService.scheduleTaskgives it a placeholder recurring job with an interval of a day plus the wait to its first run, and the helper that later sets the real interval leaves the occurrence the placeholder already scheduled.creator, because TRUNK-6391 added the column without copyingcreated_byinto it.onStartup()then throws an NPE and startup fails.onStartup()never recreates the recurring job of a start-on-startup task. It enqueues the task's startup run under the task's uuid, and that run then makes the task look scheduled. On a site that ran queue 3.1.0 or later on 2.x, each task gets one run at startup and no recurring job.SchedulerUtil.startup()out ofrefreshApplicationContext. After the queue module is stopped and started, both tasks stay unscheduled.Verification
mvn clean verifyagainst core 3.0.0-SNAPSHOT as published on 2026-10-07 (with #6631): 92 api, 73 omod and 127 integration tests pass, locally and in CI on Java 21 and 25.queue.autoCloseQueueEntriesAtTimeis set, the close-time task ends the entries started before that time at that time and leaves one started after it alone.queue.QueueEntryServicewas restored to aTransactionProxyFactoryBean, I deployed the omod on plain openmrs-core master (mvn jetty:run, MySQL 8) with legacyui, webservices.rest 5.0.0-SNAPSHOT, fhir2 6.0.0-SNAPSHOT, calculation, htmlwidgets, serialization.xstream, metadatamapping, event, idgen, emrapi and authentication:queue,queue-entryandqueue-roomreturn 200.mvn jetty:run, MySQL 8): every module starts, logging in through the UI works, and core message codes resolve.queueandqueue-entryreturn 200, and anonymous calls to core services are rejected with 401.🤖 Generated with Claude Code
https://claude.ai/code/session_01Fp7T1pGYEMrMVp1M7AW9Fg