test(amber): drop the unused pgroonga override from DatasetResourceSpec - #8403
Conversation
`DatasetResourceSpec.beforeAll` set the JVM-global `FulltextSearchQueryUtils.usePgroonga` to `false` and never put it back. The write had no effect on this suite: both of its `constructQuery` calls pass no keywords, so `getFullTextSearchFilter` returns at its empty-keyword guard before it ever reads the flag. Its only effect was to leave `false` behind for whichever suites sbt schedules after it in the same JVM (amber has no `Test / fork`), silently moving their full-text rendering onto the `to_tsvector`/`to_tsquery` arm. Delete the write rather than capture-and-restore it: with nothing here reading the flag, leaving it at its production default removes the leak outright, with no dependence on when the suite object is constructed or on how sbt orders the run. The `getKeywordsArray` helper that came along with the write is deleted too -- it has no caller (`WorkflowResourceSpec` has its own private copy) -- and the two imports that only those two members needed go with it. `DatasetSearchQueryBuilderSpec`'s header paragraph asserted this leak as fact while explaining why its keyword assertions must stay branch-independent. The instruction stands, so the paragraph now justifies it by the flag being JVM-global mutable state rather than by any particular suite's behaviour, and states precisely what survives onto both arms -- the concatenated `coalesce` expression and each individual keyword token, but not their joining, which the two arms render differently.
Automated Reviewer SuggestionsBased on the
|
There was a problem hiding this comment.
🟢 Approval recommended
The changes are a low-risk cleanup confined to tests/comments and remove a confirmed JVM-global state leak without altering production code paths.
Pull request overview
This PR removes an unnecessary JVM-global test override (FulltextSearchQueryUtils.usePgroonga = false) from DatasetResourceSpec that was not exercised by that suite but could leak into subsequently executed suites (amber tests run in a shared JVM). It also updates nearby test documentation to reflect that the flag is shared mutable state and to clarify what parts of the rendered full-text predicate are stable across both rendering arms.
Changes:
- Remove the
usePgroonga = falsewrite fromDatasetResourceSpec.beforeAlland replace it with an explanatory comment about why the suite leaves the flag at its production default. - Delete an unused local helper (
getKeywordsArray) and the imports that only existed to support it. - Update
DatasetSearchQueryBuilderSpec’s header documentation to justify arm-independent assertions without relying on a specific suite’s leak behavior.
File summaries
| File | Description |
|---|---|
| amber/src/test/scala/org/apache/texera/web/resource/dashboard/file/DatasetResourceSpec.scala | Removes a leaking JVM-global flag override and deletes an unused helper/imports; adds an explanatory comment to prevent reintroducing the leak. |
| amber/src/test/scala/org/apache/texera/web/resource/dashboard/DatasetSearchQueryBuilderSpec.scala | Updates scaladoc to describe usePgroonga as shared mutable state and clarifies which predicate substrings are arm-independent. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🔴 | bs=10 sw=10 sl=64 | 365 | 0.223 | 26,418/35,395/35,395 us | 🔴 +14.2% / 🔴 +116.8% |
| ⚪ | bs=100 sw=10 sl=64 | 804 | 0.491 | 120,288/151,947/151,947 us | ⚪ within ±5% / 🔴 +37.8% |
| 🔴 | bs=1000 sw=10 sl=64 | 918 | 0.56 | 1,080,343/1,251,006/1,251,006 us | 🔴 +11.5% / 🔴 +18.8% |
Baseline details
Latest main 1cbe857 from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 365 tuples/sec | 422 tuples/sec | 749.39 tuples/sec | -13.5% | -51.3% |
| bs=10 sw=10 sl=64 | MB/s | 0.223 MB/s | 0.258 MB/s | 0.457 MB/s | -13.6% | -51.2% |
| bs=10 sw=10 sl=64 | p50 | 26,418 us | 23,129 us | 13,045 us | +14.2% | +102.5% |
| bs=10 sw=10 sl=64 | p95 | 35,395 us | 33,888 us | 16,328 us | +4.4% | +116.8% |
| bs=10 sw=10 sl=64 | p99 | 35,395 us | 33,888 us | 19,518 us | +4.4% | +81.3% |
| bs=100 sw=10 sl=64 | throughput | 804 tuples/sec | 843 tuples/sec | 968.07 tuples/sec | -4.6% | -16.9% |
| bs=100 sw=10 sl=64 | MB/s | 0.491 MB/s | 0.515 MB/s | 0.591 MB/s | -4.7% | -16.9% |
| bs=100 sw=10 sl=64 | p50 | 120,288 us | 117,586 us | 103,330 us | +2.3% | +16.4% |
| bs=100 sw=10 sl=64 | p95 | 151,947 us | 145,032 us | 110,305 us | +4.8% | +37.8% |
| bs=100 sw=10 sl=64 | p99 | 151,947 us | 145,032 us | 121,264 us | +4.8% | +25.3% |
| bs=1000 sw=10 sl=64 | throughput | 918 tuples/sec | 936 tuples/sec | 998 tuples/sec | -1.9% | -8.0% |
| bs=1000 sw=10 sl=64 | MB/s | 0.56 MB/s | 0.571 MB/s | 0.609 MB/s | -1.9% | -8.1% |
| bs=1000 sw=10 sl=64 | p50 | 1,080,343 us | 1,068,701 us | 1,009,354 us | +1.1% | +7.0% |
| bs=1000 sw=10 sl=64 | p95 | 1,251,006 us | 1,122,293 us | 1,052,748 us | +11.5% | +18.8% |
| bs=1000 sw=10 sl=64 | p99 | 1,251,006 us | 1,122,293 us | 1,081,982 us | +11.5% | +15.6% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,548.12,200,128000,365,0.223,26417.82,35395.47,35395.47
1,100,10,64,20,2487.29,2000,1280000,804,0.491,120288.41,151946.71,151946.71
2,1000,10,64,20,21780.74,20000,12800000,918,0.560,1080342.54,1251006.00,1251006.00
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8403 +/- ##
============================================
- Coverage 94.03% 94.01% -0.02%
+ Complexity 4821 4818 -3
============================================
Files 1204 1204
Lines 48991 48992 +1
Branches 5956 5957 +1
============================================
- Hits 46067 46062 -5
- Misses 1458 1461 +3
- Partials 1466 1469 +3
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🟢 Approval recommended
The change is a low-risk test-hygiene cleanup that removes cross-suite global-state leakage without altering test assertions or production behavior.
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Xinyuan Lin <xinyual3@uci.edu>
apache#8404) ### What changes were proposed in this PR? `FulltextSearchQueryUtils.usePgroonga` (`amber/src/main/scala/org/apache/texera/web/resource/dashboard/FulltextSearchQueryUtils.scala:32`) is a JVM-global `var` whose production default is `true`. It is read at exactly one site, `FulltextSearchQueryUtils.scala:52`, to choose between the pgroonga arm and the `to_tsvector`/`to_tsquery` fallback. `WorkflowResourceSpec.beforeAll` forces it `false` and never puts it back. amber declares no `Test / fork` — the two `Test / fork := true` settings a grep finds in `build.sbt` belong to `ComputingUnitManagingService` (`build.sbt:191`) and `FileService` (`build.sbt:227`), while the amber project (`WorkflowExecutionService`, `build.sbt:252`) declares neither `fork` nor `parallelExecution` — and suites are serialized by `Tags.limit(Tags.Test, 1)` (`amber/build.sbt:48`). One `WorkflowExecutionService/test` run is therefore a single JVM sharing a single flag: 193 completed suites in the run measured here. ``` one WorkflowExecutionService/test JVM -- unforked, suites serialized ... -> WorkflowResourceSpec -> ... beforeAll: usePgroonga = false afterAll : (before) nothing every later suite (after) usePgroonga = <captured> renders the fallback arm, not production's ``` This suite genuinely needs the `false` arm, so the write is restored rather than deleted: the embedded Postgres it runs against has no pgroonga extension, and with the flag left `true` 11 of its 78 tests fail with `ERROR: function pgroonga_condition(unknown, fuzzy_max_distance_ratio => numeric) does not exist`. The 11 are named under *How was this PR tested?*. The capture is taken **in `beforeAll`, immediately before the write**, and written back as the **first** statement of `afterAll`, ahead of `closeConnectionPool()`. That ordering is hygiene, not a fix for a live hazard: `MockTexeraDB.closeConnectionPool` (`common/dao/src/test/scala/org/apache/texera/dao/MockTexeraDB.scala:183-192`) already swallows any `Exception` itself (`catch { case e: Exception => e.printStackTrace() } finally { ... }`), so only an `Error` could escape it today. Putting the restore first means the ordering does not depend on that staying true. The alternative — capturing into a `val` at construction time — restores whatever the flag held when sbt happened to instantiate the class, which is a property of sbt's scheduling rather than of what the suite clobbered. Both forms were run against the same scenario: an earlier suite leaves the flag `false`, then this suite runs, then a third suite reads it. | capture site | value restored | scenario outcome | | --- | --- | --- | | construction time (`private val`) | `true` — the value at instantiation | 79/80, `true was not equal to false` | | write time (`private var`, this PR) | `false` — the value it clobbered | 80/80 | Honest qualification, since it cuts against this change: that scenario is built with a nested `org.scalatest.Suites`, which evaluates its nested suites as **constructor arguments** and therefore instantiates all of them before any of their tests run. Measured separately, sbt/ScalaTest does *not* do that for discovered suites — it constructs each one immediately before running it (order log: `ctor:Bb, beforeAll:Bb, test:Bb, afterAll:Bb, ctor:Aa, ...`). Nothing touches the flag between this suite's construction and its `beforeAll`, and there are zero `extends Suites` classes in `amber/src/test/scala`, so **the two forms restore the same value in a real `test` run today and are behaviourally indistinguishable there**. The write-time form is preferred only because its correctness does not depend on that measurement continuing to hold: a future `Test / fork`, a `OneInstancePerTest` mixin, or any nesting suite would each change the answer. The in-code comment carries that same qualification, so the file does not overstate the case either. The field is also initialised from the live value at its declaration. That is not decoration — `afterAll` was measured to run even when `beforeAll` throws, so the restore can execute on a path where the capture line never did, and the initialiser keeps it from writing back an invented default. **The restore is unpinned: nothing in the repo would go red if it were deleted again.** Pinning the arm `false` for an entire module run — a conservative superset of the leak's effect — leaves the failing-test identities byte-identical to baseline, so no suite in `WorkflowExecutionService` currently reads the flag in an arm-sensitive way. This PR removes latent cross-suite state leakage; it does not fix a currently-failing test, and no fragile ordering-dependent guard suite was added to manufacture a pin. **A comment elsewhere that this change falsifies.** `DatasetSearchQueryBuilderSpec`'s header comment (`:114-123`) explains why that suite's keyword assertions are deliberately arm-independent, and its parenthetical names both writers of the global: "`DatasetResourceSpec` or `WorkflowResourceSpec` ran earlier in this JVM and left the global `false` (both set it and neither restores it...)". After this commit that sentence is false — this suite does restore it. This PR deliberately does **not** edit that comment. Any narrowing written here ("only `DatasetResourceSpec` leaks") would itself become false the moment the sibling PR lands, so the correction belongs in exactly one place: the sibling (apache#8403) rewrites that paragraph into a form that names no suite at all and is therefore true whichever of the two merges first. If this PR merges first, the comment is stale until the sibling lands — and the guardrail it states, "anything added here must keep that property", stays valid in every one of the four states, so nothing that reads it is misled about what to do. Writers of the global today: | writer | restores? | | --- | --- | | `FulltextSearchQueryUtilsSpec:64,71,87` | yes — `after { ... }`, per test | | `WorkflowResourceSpec:179` | this PR | | `DatasetResourceSpec:99` | no — deleted outright by apache#8403, since that suite never reaches the flag read | Once both land, this spec is the only writer of the global outside `FulltextSearchQueryUtilsSpec`. With only **one** of the two applied the flag's end state differs — with only this PR, `DatasetResourceSpec` still writes `false` without restoring; with only the sibling, this suite still leaks `false` — and whichever of the two sbt schedules last decides it (sbt's order was measured to be neither alphabetical nor command-line order). *Inference, not a measurement:* since nothing in the module was found to be arm-sensitive, the failing-test identity set should not move in either partial state. The sibling-only tree was never built or run, so that half is reasoning from the arm-sensitivity measurement rather than an observation. **Scope.** One test file, +17 lines: the capture, the restore, and the comment explaining why the capture sits where it does. No `src/main` file is touched and no other test file is touched. No test is added, renamed or deleted; the suite's own 78 tests are unchanged and so are their outcomes. ### Any related issues, documentation, discussions? Closes apache#8400 ### How was this PR tested? Everything below is read out of `amber/target/test-reports/TEST-*.xml`, not the sbt console summary. All probe suites were deleted before committing; the branch is one commit. **1. The suite really does need the `false` write.** With `beforeAll` changed to leave the flag `true`, `WorkflowResourceSpec` alone reports 78 tests and **11 failures**, every one an `org.jooq.exception.DataAccessException` caused by `ERROR: function pgroonga_condition(unknown, fuzzy_max_distance_ratio => numeric) does not exist`. The suite passes keywords through a `getKeywordsArray` helper at 16 call sites (`:331-751`), one of them with the reserved-character string `"+-@()<>~*\""`, so it reaches the flag read for real instead of taking the empty-keywords early return at `FulltextSearchQueryUtils.scala:45-47`. ``` /search API should be able to search for resources by keyword /search API should be able to search for workflows in different columns in Workflow table /search API should be able to search text phrases /search API should be able to search with arbitrary number of keywords in different combinations /search API should filter results by different resourceType /search API should handle multiple keywords correctly /search API should handle reserved characters in the keywords /search API should not be able to search workflows from different user accounts /search API should not return resources that belong to a different user /search API should return multiple matching resources from a single resource type /search API should return resources that match any of all provided keywords ``` So the right fix here is a restore, not the deletion the sibling PR makes. **2. Red before / green after,** with an explicitly-ordered throwaway probe — `Suites(new WorkflowResourceSpec, new PgroongaProbeTailSpec)`, where the tail asserts the global still holds production's default. The nesting pins the ordering because a plain `testOnly` of two classes does not order them. Both suites in the **same** invocation, since separate invocations get fresh classloaders and reset the static: | tree | result | non-passing identity in the XML | | --- | --- | --- | | baseline `1cbe857007` | 78 passed, **1 failed** | `the JVM-global usePgroonga, after the preceding suite finished should still hold production's default` | | with this PR | **79 passed, 0 failed** | none | | control: probe alone, baseline | 1 passed | none | The control matters: the tail assertion is not unconditionally red, so its red above is caused by the leak. **3. Write-time vs construction-time capture** — the table in the first section. Same probe shape, with an added first nested suite that leaves the flag `false`. Both arms were measured on the committed content: the write-time arm as committed, the construction-time arm by changing only `var` to `val` and dropping the capture line from `beforeAll`. The construction-time form restores `true` and clobbers it (XML: `true was not equal to false` on `usePgroonga after WorkflowResourceSpec should still be the false the earlier suite left`); the write-time form restores `false` and the run is 80/80. As stated above, this reflects the eager instantiation that `Suites` nesting creates rather than sbt's own (measured lazy) behaviour, so it is a design argument, not a live bug. **4. Instantiation and lifecycle semantics,** measured with an append-only order log from two suites plus one whose `beforeAll` throws: ``` ctor:Bb flag=true <- Bb fully constructed, run and torn down beforeAll:Bb flag=true test:Bb flag=true afterAll:Bb ctor:Aa flag=true <- only now is Aa constructed beforeAll:Aa flag=true test:Aa sets flag=false afterAll:Aa throwspec:beforeAll entered, about to throw throwspec:afterAll RAN <- afterAll runs even when beforeAll throws ``` Four findings: construction is lazy, per suite, immediately before that suite runs; suites do not interleave; `afterAll` still runs when `beforeAll` throws (sbt reported `Suites: completed 2, aborted 1` and the throwing suite's test never logged a line, so the restore can execute on a path where the capture never did); and `Bb` ran before `Aa` although `Aa` was listed first on the `testOnly` command line and sorts first alphabetically. **5. Arm sensitivity, i.e. why the restore is unpinned.** Production default mutated `true` -> `false` in `src/main` for one whole module run, then reverted: 195 report files and **86 non-passing identities, byte-identical to the baseline list** (`diff` empty). That is a superset of the leak's effect — every one of the 193 suites ran on the fallback arm, not just the ones scheduled after this spec — so no suite outcome in this module depends on the arm. The mutation was reverted and verified: `git diff --name-only 1cbe857 -- '*/src/main/*'` is empty and line 32 reads `var usePgroonga: Boolean = true` again. **6. Regression,** widest scope that runs locally — `AMBER_TEST_FILTER=skip-integration sbt WorkflowExecutionService/test`, baseline (both touched files at their `1cbe857007` content) measured first. *Counting rule:* a non-passing identity is a `<testcase>` element in `amber/target/test-reports/TEST-*.xml` carrying a `<failure>`, `<error>` or `<skipped>` child, printed as `KIND \t suite \t test name` and sorted; the same rule is applied to both runs. | run | report files | sbt summary | non-passing identities | | --- | --- | --- | --- | | baseline `1cbe857007` | 195 | 2297 tests: 2214 succeeded, 83 failed, 1 canceled, 1 pending; 193 suites completed, 1 aborted | 86 | | with this PR | 195 | identical, line for line | 86 | `diff` of the two sorted identity lists is **empty**. The 86 break down as 84 `<failure>` + 1 `<error>` (the aborted suite's `SuiteSelector` pseudo-testcase) + 1 `<skipped>`, and the run's own reporter tally agrees: `Total 2301, Failed 84, Errors 1, Passed 2216, Canceled 1, Pending 1`. Excluding `<skipped>` the same runs read as 85 rows — the absolute number is method-dependent, which is why the rule is stated; the load-bearing fact is that the two lists are byte-identical, not the count. All 86 are pre-existing on this box, in 13 suites, none of them touched by this PR: | suite | rows | why it is red here | | --- | --- | --- | | ResultExportServiceSpec | 17 | `org.apache.iceberg.exceptions.RESTException` — REST catalog GET to `localhost:8181`, no Docker on this box | | DataProcessingSpec | 16 | same catalog GET, wrapped in `java.lang.Throwable` | | ExecutionStatsServiceSpec | 12 | same | | ExecutionResultServiceSpec | 11 | same | | SyncExecutionResourceSpec | 8 | same | | InputPortMaterializationReaderThreadSpec | 8 | same (an engine worker-manager suite, not a dashboard one) | | PveResourceSpec | 6 | python virtual environment: `Python executable not found for PVE` | | ReconfigurationSpec, PauseSpec | 2 + 2 | same catalog GET | | WorkflowExecutionServiceSpec | 1 | same | | DefaultCostEstimatorSpec | 1 | the aborted suite: `RESTException` from the same catalog GET at construction | | GitVersionControlLocalFileStorageSpec | 1 | local file-tree assertion, `testFileTreeRetrieval` | | NetworkOutputBufferSpec | 1 | the `<skipped>` row — a `pendingUntilFixed` test, not a failure | `WorkflowResourceSpec`, the only file this PR touches, is green in both wide runs at `tests="78" errors="0" failures="0"`; so is `DatasetSearchQueryBuilderSpec` (`tests="24"`), the spec whose header comment describes this leak. The change alters what the suite leaves behind, not what it asserts. **7. Lint** (CI gates): `WorkflowExecutionService/scalafmtCheck`, `WorkflowExecutionService/Test/scalafmtCheck` and `WorkflowExecutionService/scalafixAll --check` all report `[success]` on the committed tree. **Corrections made after review.** Four claims in an earlier draft of this description were wrong or unstated, and are corrected above rather than quietly dropped: (a) the restore-before-teardown ordering was justified as protecting against a teardown throw, but `closeConnectionPool` catches `Exception` itself, so the justification is hygiene only; (b) the non-passing identity count is counting-method dependent (the same runs read as 85 rows if `<skipped>` is excluded), so the rule is now stated; (c) the pre-existing local failures were described as Iceberg/Docker dashboard suites, which under-describes them — see the table above; and (d) this PR falsifies a sentence in `DatasetSearchQueryBuilderSpec`'s header comment, which the earlier draft cited as supporting evidence without disclosing that it goes stale; An earlier revision of this branch corrected that comment here; the edit has been reverted, because the narrowing it wrote would go false as soon as the sibling landed. The correction now lives only in the sibling PR, in an order-neutral form, and this PR discloses the staleness instead. ### Was this PR authored or co-authored using generative AI tooling? Generated-by: Claude Code (Opus 5)
What changes were proposed in this PR?
DatasetResourceSpec.beforeAllset the JVM-globalFulltextSearchQueryUtils.usePgroongatofalseand never put it back. The write did nothing for this suite and everything to the suites after it.
Why it does nothing here.
usePgroongais read at exactly one place insrc/main:FulltextSearchQueryUtils.scala:52. That read is insidegetFullTextSearchFilter, which is calledfrom exactly two places in
src/main—VersionedResourceSearchQueryBuilder.scala:128andWorkflowSearchQueryBuilder.scala:120.DatasetResourceSpecreaches neither with a keyword:UserDao; two callDatasetSearchQueryBuilder.constructQuery(uid, SearchQueryParams(resourceType = DATASET_RESOURCE_TYPE), includePublic = true)SearchQueryBuilder.constructQuery(final)constructFromClause+constructWhereClause+mappedResourceSchema.allFields+getGroupByFields; none of the first, third or fourth touches full-text (constructFromClauseonly builds jOOQ joins,getGroupByFieldsisSeq.empty)constructWhereClausegetFullTextSearchFilter(splitKeywords, List(DATASET.NAME, DATASET.DESCRIPTION))splitKeywordsparams.keywords, which the tests leave at itsnew util.ArrayList[String]()default (DashboardResource.scala:72), so it is emptygetFullTextSearchFilterfieldsis non-empty so the:39guard does not fire, buttrimmedKeywords.isEmptyreturnsnoCondition()at:46— before the:52readWhy it does something to everyone else. amber has no
Test / forkand serialises its suites inone JVM, so
falsestayed set for every suite scheduled after this one, moving their full-textrendering onto the
to_tsvector/to_tsqueryarm.So the write is deleted rather than captured and restored. A capture-and-restore would still leave
the value wrong during this suite and would depend on when the suite object is constructed and on
where sbt happens to schedule it; deleting the write removes the leak unconditionally.
Also removed, from the same copy-paste block:
private def getKeywordsArray, which has no caller. After the deletion the onlygetKeywordsArrayin the repository is
WorkflowResourceSpec's ownprivatecopy (definition at:201, 16 callsites, all in that file). Being
private, this file's copy could only ever have been called fromthis file, and was not.
import org.apache.texera.web.resource.dashboard.{FulltextSearchQueryUtils}andimport java.util,which were the only imports those two members needed.
A short comment replaces the write, recording that the flag is left at its production default because
no test here reaches the read, and what a keyword test added here would have to do instead
(
MockTexeraDBstrips the full-text index block out of the DDL, so the embedded Postgres has nopgroonga extension — such a test would need the
to_tsvectorarm, and would have to put the flagback). Without it the next author copying
WorkflowResourceSpec's pattern re-adds the leak.Why a second file is in the diff.
DatasetSearchQueryBuilderSpec's header paragraph carried astanding instruction — every keyword assertion in that spec must stay branch-independent — and
justified it by asserting this leak as fact: that
DatasetResourceSpecandWorkflowResourceSpec"both set it and neither restores it", and that an assertion on
pgroonga_condition"would pass soloand fail in a full-module run". This PR falsifies the first half for
DatasetResourceSpecand thesecond half outright. The instruction is still right, so the paragraph now justifies it by the flag
being JVM-global mutable state that any suite in the run may write, and states precisely which parts
of a rendered predicate survive onto both arms: the
coalesce(...) || ' ' || coalesce(...)expression(built at
FulltextSearchQueryUtils:49-51, before theif, and embedded verbatim by either arm) andeach individual keyword token — but not their joining, which the two arms render differently (test
5 below). Nothing else in that file changed — no assertion, no other comment, no reformatting.
What this PR does not do. It does not touch
WorkflowResourceSpec, which genuinely needs thefalsearm (it runs real keyword searches against the embedded Postgres) and still leaks it; that isa separate change, #8404, which restores the flag there rather than deleting the write. It does not touch
src/main—usePgroongaremains a public mutablevar. Itdoes not add or rename a test, and it does not change any assertion anywhere.
Any related issues, documentation, discussions?
Closes #8399
How was this PR tested?
Every number below was read out of
amber/target/test-reports/TEST-*.xml, not from sbt's consolesummary. Local, Windows, Java 17, module
WorkflowExecutionService.1cbe857007is the base commit.1. The suite stays green.
testOnly ...file.DatasetResourceSpec:tests="4" failures="0" errors="0".2. The flag read is unreachable from this suite — measured, not just argued. Temporarily armed
the read site in
src/main(if ({ sys.error("READ REACHED"); usePgroonga }), reverted afterwards)and ran the suite together with a control that does reach the read:
DatasetResourceSpectests="4" failures="0"FulltextSearchQueryUtilsSpectests="14" failures="3"3. The leak is real and the deletion removes it — same invocation, pinned order. sbt gives
separate
testOnlyinvocations fresh classloaders, so the probe puts both suites in one invocationand pins their order with a
Suitessubclass that overridesrunNestedSuitesto construct eachnested suite immediately before running it (sbt's own ScalaTest-framework semantics;
Suites(a, b)would evaluate both constructors up front).
DatasetResourceSpecran1cbe857007true/falsefalse was not equal to truetrue/truetests="5" failures="0"Control, so the observer is not vacuously red on base: run alone in its own invocation on
1cbe857007it istests="1" failures="0"— the default really istrue, and thefalsecame fromDatasetResourceSpec.4. The downstream arm switch, and that it turns nothing red. Same pinned order
(
DatasetResourceSpecthenDatasetSearchQueryBuilderSpec, one invocation), the only variable beingthis file:
1cbe857007falseto_tsvector/to_tsquerytests="28" failures="0"truepgroonga_conditiontests="28" failures="0"That is the point of the change — downstream suites move back onto the production arm — and it costs
nothing, because those assertions are branch-independent.
5. Which parts of a rendered predicate are actually arm-independent. A throwaway spec rendered
getFullTextSearchFilteron both arms and dumped the SQL (DSL.using(POSTGRES).renderInlined, no DBneeded):
usePgroonga = trueusePgroonga = false["alpha"]... &@~ pgroonga_condition('alpha', ...)to_tsvector('english', ...) @@ to_tsquery('english', 'alpha')["alpha", "beta"]... pgroonga_condition('alpha beta', ...)to_tsquery('english', 'alpha')and... 'beta'["alpha beta"]... pgroonga_condition('alpha beta', ...)... @@ to_tsquery('english', 'alpha & beta')The
COALESCE(name, '') || ' ' || COALESCE(description, '')expression and each individual tokenappear on both arms; the joined string
alpha betaappears only on thetruearm. Asserted as such(
tests="4" failures="0"), which is what licenses the wording inDatasetSearchQueryBuilderSpec'sparagraph. And the spec's existing assertions really are arm-independent: pinning the flag to each
arm and running it gives
tests="24" failures="0"both ways.6. No regression.
AMBER_TEST_FILTER=skip-integration WorkflowExecutionService/test, run on thebase commit first and then on this branch in the same worktree. Counting
<failure>,<error>and<skipped>children of<testcase>separately, because the distinction matters here:<failure><error><skipped>1cbe857007The two non-pass identity lists are byte-identical (
diffis empty). The 85 failures/errors are allpre-existing local-environment failures —
ResultExportServiceSpec17,DataProcessingSpec16,ExecutionStatsServiceSpec12,ExecutionResultServiceSpec11,SyncExecutionResourceSpec8,InputPortMaterializationReaderThreadSpec8,PveResourceSpec6,ReconfigurationSpec2,PauseSpec2, and one each inWorkflowExecutionServiceSpec,GitVersionControlLocalFileStorageSpecandDefaultCostEstimatorSpec(that last is aconstruction-time abort) — none of them in the dashboard search path this PR touches. The single
<skipped>isNetworkOutputBufferSpec'spendingUntilFixedtest, which is not a failure at all.Worth recording, because it is why the identity diff alone is not sufficient evidence: sbt's suite
order is not stable across invocations of the same command. In the base run
DatasetSearchQueryBuilderSpecran 1st of 195 andDatasetResourceSpec54th — so the downstreamspec happened to run before the leak and saw
trueanyway; in the branch run they were 141st and102nd. Tests 3-5 are the ordered evidence; the module runs only show that nothing else moved.
7. Lint.
WorkflowExecutionService/scalafmtCheck,WorkflowExecutionService/Test/scalafmtCheckand
WorkflowExecutionService/scalafixAll --checkall exit 0, the last with its cache cleared so itreally re-scanned both changed files (
Running scalafix on 274 Scala sources/on 209 Scala sources; the one warning it prints is pre-existing, inOutputManagerSpec). scalafix is the gatethat matters here: each deletion orphans an import.
Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 5)