tests: an in-process JUnit slice runs an intent application's custom/ Java against H2 in milliseconds (#7643) - #7694
Open
NicoleNG18 wants to merge 1 commit into
Conversation
… Java against H2 in milliseconds (eclipse-dirigible#7643) custom/*.java of a generated application could only be exercised by booting the whole platform, so the money paths it carries had no unit tests at all. dirigible-sdk-test (tests/tests-sdk) adds @IntentSlice: the project's gen/ and custom/ classes, taken from the test classpath, run on a private in-memory H2 behind the platform's own entity store, bean container and numbering, with no web server, synchronizer, broker or IDE. Fixtures: given(Entity).with(field, value).saved(), Slice.expectRefused(...), the messages a write sent, and any application component as a test parameter. The application starts once per JVM and is reset before each test. The tests live in custom/test/, which the module's build compiles together with gen/ and custom/ as one test source root - so the test and the slice share one Class per type. JavaSynchronizer now skips custom/test/**: the platform has no JUnit to compile those sources against. sample-intent-money is the reference: a VAT computed by a custom/ action, its unit tests (red at 0.14 with double rounding, green at 0.15 with BigDecimal) as this module's test suite, and IntentSliceSampleIT publishing it to assert the platform leaves custom/test/ out. Not covered: event reactions/notify (events are recorded, not delivered), a fake clock (generated rules read the system clock directly), and the AOT packaging gate (no packaging step exists in this repository). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| if (entity.Description == null) { | ||
| throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The 'Description' property is required"); | ||
| } | ||
| if (entity.Description != null && entity.Description.length() > 200) { |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cause
A generated application keeps its hand-written logic (calculated-field actions, delegates, check predicates) in
custom/*.java. The only way to run that code was to boot the whole platform. The money paths it carries therefore had no unit tests at all.There were two obstacles. First, everything the generated code reaches goes through the static
BeanProvider/Beanslookup: the entity store, the client bean container, numbering. Second, the platform compiled every.javain a project, so acustom/test/*Test.javaimporting JUnit ended up in the live client codebase as a page of javac errors. You can see this on master by publishing the sample below:JavaSourceCompiler - javac error at /custom/test/LineVatActionTest.java ....Change
dirigible-sdk-test(tests/tests-sdk):@IntentSlice, a JUnit 5 extension.gen/+custom/classes run on a private in-memory H2 behind the platform's own code:JavaEntityManager/JavaEntityStore(generated repositories with their calculated fields, validations, checks,UnitOfWorkand outbox), engine-java'sComponentContainer,DocumentNumberService(series from the project's.numbersfiles) and a single-tenant context. All of it sits in a small context behindBeanProvider. There is no web server, synchronizer, broker or IDE.gen/,custom/andcustom/test/build together and the test and the slice share oneClassper type. A slice compiling into its ownClientClassLoaderwould hand the test a differentInvoiceLineEntityfrom the one it imports.slice.given(Entity.class).with("Field", value).saved(); values convert, e.g."2.90"becomes aBigDecimal..entity()gives the record unsaved, to call an action directly.Slice.expectRefused(() -> ...)asserts the refusal and returns it with its message.slice.sent()/slice.sentTo(topic)list the events a write published. A stand-in producer records them, so nothing is logged as an undelivered message.engine-java:
JavaSynchronizer.isAcceptedskipscustom/test/**. The rule lives in one place,ClientTestSources.isTestSource, which the slice uses too.Reference sample
sample-intent-money:InvoiceLine.vatAmountis computed bycustom/LineVatActioninBigDecimal.custom/test/LineVatActionTestis the slice's test suite.gen/Java is checked in, regenerated on this base. A nested.gitignoreun-ignores it against the repo-wide**/genrule.IntentSliceSampleIT(HTTP-level, untagged) publishes the sample. It asserts that only the four application sources are registered and the VAT over REST is 0.15.Docs:
tests/tests-sdk/README.md(setup, API, what is not covered), the sample's README, the AOT recipe inengine-java/README.md, and.claude/docs/client-java.md.Verified
LineVatActionTest: 6 green in 1.6 s withmvn testintests/tests-sdk.LineVatActionfor adoublecomputation and ran the suite:roundsTheVatHalfUpToTheCentfailed withexpected: <0.15> but was: <0.14>, and so did the event test. WithBigDecimalit is green.dirigible-parentimported for versions), ran the sample's suite: 6 green.IntentSliceSampleITgreen (19 s). With theisAcceptedchange reverted it fails, the registered artefacts then includingcustom/test/LineVatActionTest.java.JavaSynchronizerTestSourcesTest).mvn -T 1C formatter:validateafter wiping the formatter cache:BUILD SUCCESS.engine-javaandtests-sdk:BUILD SUCCESS.gen/regenerated, and the slice suite and IT re-run green.Not verified
Pathiteration and surefire'sworkingDirectory.license:check. It cannot run in a git worktree ("Bare Repository has neither a working tree, nor an index"), so I checked the EPL headers on every new Java file by hand.Not covered (each is its own piece of work)
MailAsserter. The slice records an event and stops; dispatching to the generated listeners is the next step.LocalDate.now()/Instant.now()directly in many emitted places, so a clock the slice could fix needs a generator-wide seam first.custom/*.javawithoutcustom/testunlessaot.tests: none"). This repo has no packaging step to put it in: AOT modules are built by the README recipe. That recipe now points at the module'smvn test._HISTORY/_LANGside tables from the generated.schemaare not created. In the slice, a write to ahistory: trueentity logs that the trail could not be recorded, and a read of amultilingual: trueentity warns.Fixes #7643
🤖 Generated with Claude Code