aglinxinyuan opened a new pull request, #8403:
URL: https://github.com/apache/texera/pull/8403
### What changes were proposed in this PR?
`DatasetResourceSpec.beforeAll` set the JVM-global
`FulltextSearchQueryUtils.usePgroonga` to `false`
and never put it back. The write did nothing for this suite and everything
to the suites after it.
**Why it does nothing here.** `usePgroonga` is read at exactly one place in
`src/main`:
`FulltextSearchQueryUtils.scala:52`. That read is inside
`getFullTextSearchFilter`, which is called
from exactly two places in `src/main` —
`VersionedResourceSearchQueryBuilder.scala:128` and
`WorkflowSearchQueryBuilder.scala:120`. `DatasetResourceSpec` reaches
neither with a keyword:
| step | what it does |
| --- | --- |
| the four tests | two use only `UserDao`; two call
`DatasetSearchQueryBuilder.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 (`constructFromClause`
only builds jOOQ joins, `getGroupByFields` is `Seq.empty`) |
| `constructWhereClause` | reaches `getFullTextSearchFilter(splitKeywords,
List(DATASET.NAME, DATASET.DESCRIPTION))` |
| `splitKeywords` | derived from `params.keywords`, which the tests leave at
its `new util.ArrayList[String]()` default (`DashboardResource.scala:72`), so
it is empty |
| `getFullTextSearchFilter` | `fields` is non-empty so the `:39` guard does
not fire, but `trimmedKeywords.isEmpty` returns `noCondition()` at `:46` —
**before** the `:52` read |
**Why it does something to everyone else.** amber has no `Test / fork` and
serialises its suites in
one JVM, so `false` stayed set for every suite scheduled after this one,
moving their full-text
rendering onto the `to_tsvector`/`to_tsquery` arm.
```
before: beforeAll: usePgroonga = false -> suite's own 4 tests: never read
it
-> every later suite in the JVM:
reads false
after: flag untouched at its production default true
```
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 only `getKeywordsArray`
in the repository is `WorkflowResourceSpec`'s own `private` copy
(definition at `:201`, 16 call
sites, all in that file). Being `private`, this file's copy could only
ever have been called from
this file, and was not.
- `import
org.apache.texera.web.resource.dashboard.{FulltextSearchQueryUtils}` and
`import 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
(`MockTexeraDB` strips the full-text index block out of the DDL, so the
embedded Postgres has no
pgroonga extension — such a test would need the `to_tsvector` arm, and would
have to put the flag
back). 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 a
standing instruction — every keyword assertion in that spec must stay
branch-independent — and
justified it by asserting this leak as fact: that `DatasetResourceSpec` and
`WorkflowResourceSpec`
"both set it and neither restores it", and that an assertion on
`pgroonga_condition` "would pass solo
and fail in a full-module run". This PR falsifies the first half for
`DatasetResourceSpec` and the
second 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 the `if`, and embedded
verbatim by either arm) and
each 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 the
`false` arm (it runs real keyword searches against the embedded Postgres)
and still leaks it; that is
a separate change. It does not touch `src/main` — `usePgroonga` remains a
public mutable `var`. It
does 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 console
summary. Local, Windows, Java 17, module `WorkflowExecutionService`.
`1cbe857007` is 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:
| suite | XML | meaning |
| --- | --- | --- |
| `DatasetResourceSpec` | `tests="4" failures="0"` | none of its four tests
reaches the read |
| `FulltextSearchQueryUtilsSpec` | `tests="14" failures="3"` | the probe is
armed; exactly its three flag-reading tests died |
**3. The leak is real and the deletion removes it — same invocation, pinned
order.** sbt gives
separate `testOnly` invocations fresh classloaders, so the probe puts both
suites in one invocation
and pins their order with a `Suites` subclass that overrides
`runNestedSuites` to construct each
nested suite immediately before running it (sbt's own ScalaTest-framework
semantics; `Suites(a, b)`
would evaluate both constructors up front).
| tree | printed before / after `DatasetResourceSpec` ran | observer suite |
| --- | --- | --- |
| `1cbe857007` | `true` / `false` | FAILURE, `false was not equal to true` |
| this branch | `true` / `true` | `tests="5" failures="0"` |
Control, so the observer is not vacuously red on base: run alone in its own
invocation on
`1cbe857007` it is `tests="1" failures="0"` — the default really is `true`,
and the `false` came from
`DatasetResourceSpec`.
**4. The downstream arm switch, and that it turns nothing red.** Same pinned
order
(`DatasetResourceSpec` then `DatasetSearchQueryBuilderSpec`, one
invocation), the only variable being
this file:
| tree | flag observed after the subject | arm that selects (test 5) |
downstream result |
| --- | --- | --- | --- |
| `1cbe857007` | `false` | `to_tsvector`/`to_tsquery` | `tests="28"
failures="0"` |
| this branch | `true` | `pgroonga_condition` | `tests="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
`getFullTextSearchFilter` on both arms and dumped the SQL
(`DSL.using(POSTGRES).renderInlined`, no DB
needed):
| keywords | `usePgroonga = true` | `usePgroonga = false` |
| --- | --- | --- |
| `["alpha"]` | `... &@~ pgroonga_condition('alpha', ...)` |
`to_tsvector('english', ...) @@ to_tsquery('english', 'alpha')` |
| `["alpha", "beta"]` | `... pgroonga_condition('alpha beta', ...)` | two
predicates AND-ed, `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 token
appear on both arms; the joined string `alpha beta` appears only on the
`true` arm. Asserted as such
(`tests="4" failures="0"`), which is what licenses the wording in
`DatasetSearchQueryBuilderSpec`'s
paragraph. 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.
> Correction, so nobody carries the old sentence forward: an earlier
revision of that paragraph (and
> of this PR body) said the tokens "render identically on either arm".
Review caught it and the table
> above is why it was wrong — only *individual* tokens and the `coalesce`
expression survive both
> arms, not a joined multi-token string. The shipped paragraph now says
exactly that. Nothing in the
> spec asserted on a joined string, so no test changed.
**6. No regression.** `AMBER_TEST_FILTER=skip-integration
WorkflowExecutionService/test`, run on the
base 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:
| | report files | tests | `<failure>` | `<error>` | `<skipped>` |
| --- | --- | --- | --- | --- | --- |
| `1cbe857007` | 195 | 2303 | 84 | 1 | 1 |
| this branch | 195 | 2303 | 84 | 1 | 1 |
The two non-pass identity lists are byte-identical (`diff` is empty). The 85
failures/errors are all
pre-existing local-environment failures — `ResultExportServiceSpec` 17,
`DataProcessingSpec` 16,
`ExecutionStatsServiceSpec` 12, `ExecutionResultServiceSpec` 11,
`SyncExecutionResourceSpec` 8,
`InputPortMaterializationReaderThreadSpec` 8, `PveResourceSpec` 6,
`ReconfigurationSpec` 2,
`PauseSpec` 2, and one each in `WorkflowExecutionServiceSpec`,
`GitVersionControlLocalFileStorageSpec` and `DefaultCostEstimatorSpec` (that
last is a
construction-time abort) — none of them in the dashboard search path this PR
touches. The single
`<skipped>` is `NetworkOutputBufferSpec`'s `pendingUntilFixed` test, which
is not a failure at all.
> Correction: an earlier revision of this body reported "86 non-pass
identities" with a tail of "8
> singletons/pairs". Review could not reproduce 86 and measured 85. Both
measurements were right about
> the XML — 86 was 85 failures/errors plus that one `pendingUntilFixed`
`<skipped>` row, silently
> lumped in with the failures. The table above separates them. It was a bad
count, not a flake.
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
`DatasetSearchQueryBuilderSpec` ran 1st of 195 and `DatasetResourceSpec`
54th — so the downstream
spec happened to run *before* the leak and saw `true` anyway; in the branch
run they were 141st and
102nd. Tests 3-5 are the ordered evidence; the module runs only show that
nothing else moved.
**7. Lint.** `WorkflowExecutionService/scalafmtCheck`,
`WorkflowExecutionService/Test/scalafmtCheck`
and `WorkflowExecutionService/scalafixAll --check` all exit 0, the last with
its cache cleared so it
really re-scanned both changed files (`Running scalafix on 274 Scala
sources` / `on 209 Scala
sources`; the one warning it prints is pre-existing, in
`OutputManagerSpec`). scalafix is the gate
that matters here: each deletion orphans an import.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 5)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]