test(#4689): regression tests for MATCH (u:User) RETURN u NoSuchElementException - #4690
Conversation
|
Tick the box to add this pull request to the merge queue (same as
|
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Coverage variation | ✅ -8.13% coverage variation |
| Diff coverage | ✅ 96.67% diff coverage |
Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (2ba493d) 131866 99084 75.14% Head commit (881ba78) 163732 (+31866) 109710 (+10626) 67.01% (-8.13%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>
Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#4690) 30 29 96.67% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
There was a problem hiding this comment.
Code Review
This pull request adds documentation analyzing a reported NoSuchElementException when returning whole vertices in Cypher and SQL, along with a new regression test suite (Issue4689MatchReturnVertexIT) to verify these query paths. The review feedback highlights critical improvements for the tests: explicitly creating and populating vertex types in the SQL tests to ensure they actually exercise the serialization paths, and dynamically resolving the HTTP server URL and database name using base class helper methods to prevent test flakiness.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| void sqlSelectFromTypeShouldNotThrow() throws Exception { | ||
| // SQL: returning whole record should work (same issue with SQL as with Cypher) | ||
| final JSONObject response = executeCommand(0, "sql", "SELECT FROM V1"); | ||
|
|
||
| assertThat(response).isNotNull(); | ||
| assertThat(response.has("result")).as("SELECT FROM should not throw NoSuchElementException").isTrue(); | ||
| } |
There was a problem hiding this comment.
The test queries V1, but V1 is not created or populated within this test. If V1 is empty or does not exist, the query will either fail with a schema error or return an empty result set. If it returns an empty result set, the vertex serialization code path is never executed, meaning this regression test would pass vacuously without actually verifying that the NoSuchElementException is resolved.
To ensure the test is robust, self-contained, and actually exercises the serialization path, we should explicitly create a vertex type, insert a record, and query that type.
void sqlSelectFromTypeShouldNotThrow() throws Exception {
executeCommand(0, "sql", "CREATE VERTEX TYPE SqlUser");
executeCommand(0, "sql", "INSERT INTO SqlUser SET name = 'Alice', age = 30");
// SQL: returning whole record should work (same issue with SQL as with Cypher)
final JSONObject response = executeCommand(0, "sql", "SELECT FROM SqlUser");
assertThat(response).isNotNull();
assertThat(response.has("result")).as("SELECT FROM should not throw NoSuchElementException").isTrue();
}There was a problem hiding this comment.
Fixed in the current commit. sqlSelectFromTypeShouldNotThrow now creates its own SqlSelectAll vertex type and populates it with 2 records before querying - no dependency on V1.
| void sqlSelectFieldsShouldWork() throws Exception { | ||
| // Selecting individual fields should work (workaround for SQL) | ||
| final JSONObject response = executeCommand(0, "sql", "SELECT name FROM V1"); | ||
|
|
||
| assertThat(response).isNotNull(); | ||
| assertThat(response.has("result")).isTrue(); | ||
| } |
There was a problem hiding this comment.
Similar to the previous test, querying V1 without creating it or inserting records makes the test dependent on external state or run vacuously on an empty result set.
To ensure test isolation and correctness, explicitly create a vertex type, insert a record, and query it.
void sqlSelectFieldsShouldWork() throws Exception {
executeCommand(0, "sql", "CREATE VERTEX TYPE SqlUser2");
executeCommand(0, "sql", "INSERT INTO SqlUser2 SET name = 'Bob', age = 25");
// Selecting individual fields should work (workaround for SQL)
final JSONObject response = executeCommand(0, "sql", "SELECT name FROM SqlUser2");
assertThat(response).isNotNull();
assertThat(response.has("result")).isTrue();
}There was a problem hiding this comment.
Fixed in the current commit. sqlSelectFieldsShouldWork now creates its own SqlSelectFields vertex type with 1 record - no dependency on V1.
| final java.net.HttpURLConnection connection = (java.net.HttpURLConnection) new java.net.URI( | ||
| "http://127.0.0.1:2480/api/v1/command/graph").toURL().openConnection(); |
There was a problem hiding this comment.
Hardcoding the host, port (127.0.0.1:2480), and database name (graph) can lead to test flakiness or failures if the test server is configured to run on a dynamic port (e.g., in parallel execution environments or CI pipelines) or if the database name is different.
We should use the helper methods getHttpServerUrl(0) and getDatabase(0).getName() provided by BaseGraphServerTest to dynamically resolve the correct URL.
| final java.net.HttpURLConnection connection = (java.net.HttpURLConnection) new java.net.URI( | |
| "http://127.0.0.1:2480/api/v1/command/graph").toURL().openConnection(); | |
| final java.net.HttpURLConnection connection = (java.net.HttpURLConnection) new java.net.URI( | |
| getHttpServerUrl(0) + "/api/v1/command/" + getDatabase(0).getName()).toURL().openConnection(); |
There was a problem hiding this comment.
Updated to use getDatabaseName() for the database name portion. The port pattern "http://127.0.0.1:2480" matches the existing convention in BaseGraphServerTest.executeCommand() (which uses "http://127.0.0.1:248" + serverIndex). No getHttpServerUrl() helper exists in the base class.
Code ReviewOverviewThis PR adds regression tests for issue #4689 ( IssuesCriticalMisleading PR title and branch name Unaddressed structural inconsistency CorrectnessTest isolation: cross-test state dependency Weak assertions - empty results pass the tests // After executing the MATCH query that should return 2 vertices:
assertThat(response.getJSONArray("result").length()).isEqualTo(2);Style (per CLAUDE.md: "don't use fully qualified names if possible, always import the class")
// Current - violates project conventions
final java.net.HttpURLConnection connection = (java.net.HttpURLConnection) new java.net.URI(...)
.toURL().openConnection();
connection.setRequestProperty("Authorization",
"Basic " + java.util.Base64.getEncoder().encodeToString(...));
formatPayload(connection, "opencypher", ..., null, java.util.Collections.emptyMap());Should import Also note: this test duplicates the pattern already handled by Performance tagging (per CLAUDE.md)
@Test
@Tag("slow")
void cypherMatchReturnManyVerticesShouldWork() throws Exception {Required import: Committed documentation file
Summary
The test idea is sound and the coverage is valuable. With the assertion strength improved, isolation fixed, style corrected, and the doc file removed, this would be a clean regression safety net. |
Code Review: PR #4689 - Regression tests for
|
Code Review: PR #4689 Regression TestsOverviewThis PR adds 7 regression tests for issue #4689 ( Issues / Suggestions1. Missing
|
Code Review - Issue #4689 Regression TestsOverviewThis PR adds 7 regression tests for issue #4689 ( Test File -
|
| Area | Verdict |
|---|---|
| Test correctness | Pass - all 7 scenarios cover the stated issue |
| Test isolation | Pass - fresh DB per test via @BeforeEach in base class |
| Assertions | Good - descriptive messages, AssertJ throughout |
| Schema dependency | E1 coupling in edge test is fragile - easy to fix |
| Response format divergence | Needs a comment in test 7 |
| Docs file | Consider trimming or removing review-cycle section |
The tests themselves are solid and coverage is appropriate for the issue. The E1 schema coupling is the only change worth fixing before merge.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4690 +/- ##
============================================
- Coverage 66.02% 65.32% -0.70%
- Complexity 0 573 +573
============================================
Files 1673 1673
Lines 131866 131929 +63
Branches 28238 28244 +6
============================================
- Hits 87058 86179 -879
- Misses 32815 33849 +1034
+ Partials 11993 11901 -92 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Code ReviewOverviewThis PR adds regression tests for issue #4689 where IssuesMODERATE - Tracking doc belongs in the issue tracker, not the repo
MINOR - Each of the 5 test methods constructs a try (RemoteDatabase tx = new RemoteDatabase("127.0.0.1", 2480 + serverIndex, DATABASE_NAME, "root", ...)) {
...
}
MINOR - The sibling class Positive Observations
SummaryThe test logic itself is solid. The two actionable items before merge are: (1) add |
Code Review - PR #4690: Regression tests for MATCH (u:User) RETURN u NSEOverviewThis PR adds regression test coverage for issue #4689 across three test classes and a documentation file. The investigation work is thorough and well-described. Below are specific issues found in the test code. CRITICAL - Resource LeakFile: Every test method creates a final RemoteDatabase database = new RemoteDatabase("127.0.0.1", 2480, getDatabaseName(), "root", ...);If try (final RemoteDatabase database = new RemoteDatabase(...)) {
// test body
}Important IssuesHardcoded port 2480 in two places
The server port should be obtained dynamically (e.g.
for (int i = 0; i < 25; i++)
executeCommand(0, "opencypher", "CREATE (u:StudioSpoke {idx: " + i + "})");The PR description says Correctness / Test Quality
assertThat(row.isVertex()).as("SELECT FROM should produce a vertex element over RemoteDatabase").isTrue();
Minor / StyleDocumentation file includes review-process metadata
assertThat(result.getJSONArray("records").length()).as("Projection workaround should return 1 vertex").isEqualTo(1);One vertex ( Summary
The investigation and coverage strategy are solid. The resource leak and hardcoded port are the items that need fixing before merge. |
…ementException
Add Issue4689MatchReturnVertexIT covering the reported scenario:
MATCH (u:User) RETURN u (whole vertex) vs RETURN u{.*} as user (projection).
Also covers SQL SELECT FROM type, pagination with >100 vertices, vertices with
edges, and the default (non-studio) HTTP serializer path. All 7 tests pass on
the current codebase confirming the code path is correct.
…tions, @tag(slow) - Make sqlSelectFromTypeShouldNotThrow/sqlSelectFieldsShouldWork self-contained with own vertex types (SqlSelectAll, SqlSelectFields) per gemini review - cypherMatchReturnVertexProjectionWorkaround uses own isolated type (IssueUserProj) to eliminate cross-test ordering dependency per claude review - Assert on result record counts where data is explicitly created per claude review - Use getDatabaseName() in default-serializer test URL per gemini review - Import HttpURLConnection/URL/Base64/Collections instead of FQN per claude review - Add @tag("slow") to 110-vertex pagination test per claude review
…IND bulk create, javadoc - cypherMatchReturnManyVerticesShouldWork: use UNWIND range(0,109) for single-command bulk create instead of 110 HTTP round-trips; assert records.length()==110 to verify all vertices are returned across pagination batches - cypherMatchReturnVertexWithEdgesShouldWork: assert at least one vertex has non-zero @out or @in edge count to validate setMetadata() edge-counting code path - Trim class-level Javadoc to single line per CLAUDE.md convention - Remove @tag("slow") since UNWIND replaces the slow loop
Add Issue4689MatchReturnVertexRemoteIT exercising the issue scenarios through the RemoteDatabase client (HTTP "record" serializer parsed via json2Result/json2Record), the path a real remote driver uses - the most faithful reproduction of the reporter's setup. Covers MATCH RETURN whole vertex, projection workaround, SQL SELECT FROM, SQL field selection, and vertices with edges. All 5 tests pass.
… vertex Reporter clarified the error happens only in Studio (HTTP/Bolt work fine). Studio uses serializer=studio, the only path that builds the full graph and runs the "filter out not connected edges" loop iterating getEdges() on every returned vertex. Add Issue4689StudioSerializerIT stressing that studio-only path: edges between returned vertices, edges to vertices outside the result, self-loops, a 25-edge hub, SQL whole-record SELECT, and bidirectional edges. All 6 tests pass - bug still not reproducible over the studio serializer.
The untyped EdgeIterator (getEdges(DIRECTION) with no edge-type filter) violated the Iterator contract: hasNext() only checked the segment position while next() lazily loaded the edge record, caught RecordNotFoundException on a dangling pointer (edge record removed but the link still in the vertex edge segment), skipped it, then threw NoSuchElementException once the segment ended - although hasNext() had returned true. A standard for-each loop (the Studio "filter out not connected edges" pass) propagated the NSE as an HTTP 500. The record is force-loaded inside next() when the transaction isolation is REPEATABLE_READ or the edge's bucket/type no longer resolves. This is why the failure was Studio-only (the only serializer that iterates and loads each vertex's edges; HTTP/Bolt only count them), limited to collections with dangling edges, and only affected whole-vertex queries (scalar projections are not vertices, so never enter the loop). hasNext() now validates the non-lightweight edge RID and skips dangling pointers there, mirroring the already-robust EdgeIteratorFilter, so hasNext()/next() stay consistent. reset() clears the prefetch state; remove() semantics are preserved (its only production caller uses the EdgeVertexIterator/entryIterator path). Tests: - engine DanglingEdgeIteratorTest (fails NSE before fix, skips after) - server Issue4689StudioSerializerIT.matchReturnVertexWithDanglingEdgeDoesNotReturn500 (HTTP 500 -> 200)
a37ecfe to
881ba78
Compare
Review: PR #4690 - EdgeIterator NSE on dangling edgeThorough read of the core fix ( Correctness - looks good
1. Performance: doubled
|
…0 in /studio [skip ci] Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 6.0.1 to 7.0.0. Release notes *Sourced from [webpack-cli's releases](https://github.com/webpack/webpack-cli/releases).* > webpack-cli@7.0.0 > ----------------- > > ### Major Changes > > * The minimum supported version of Node.js is `20.9.0`. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Use dynamic import to load `webpack.config.js`, fallback to interpret only when configuration can't be load by dynamic import. Using dynamic imports allows you to take advantage of Node.js's built-in TypeScript support. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Removed the `--node-env` argument in favor of the `--config-node-env` argument. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * The `version` command only output versions right now. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Removed deprecated API, no action required unless you use `import cli from "webpack-cli";`/`const cli = require("webpack-cli");`. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > > ### Patch Changes > > * Allow configuration freezing. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Use graceful shutdown when file system cache is enabled. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Performance improved. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) Changelog *Sourced from [webpack-cli's changelog](https://github.com/webpack/webpack-cli/blob/main/CHANGELOG.md).* > 7.0.0 > ----- > > ### Major Changes > > * The minimum supported version of Node.js is `20.9.0`. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Use dynamic import to load `webpack.config.js`, fallback to interpret only when configuration can't be load by dynamic import. Using dynamic imports allows you to take advantage of Node.js's built-in TypeScript support. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Removed the `--node-env` argument in favor of the `--config-node-env` argument. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * The `version` command only output versions right now. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Removed deprecated API, no action required unless you use `import cli from "webpack-cli";`/`const cli = require("webpack-cli");`. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > > ### Patch Changes > > * Allow configuration freezing. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Use graceful shutdown when file system cache is enabled. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) > * Performance improved. (by [`@alexander-akait`](https://github.com/alexander-akait) in [ArcadeData#4677](https://redirect.github.com/webpack/webpack-cli/pull/4677)) Commits * [`0b116f7`](webpack/webpack-cli@0b116f7) chore(release): new release ([ArcadeData#4679](https://redirect.github.com/webpack/webpack-cli/issues/4679)) * [`e0b2f07`](webpack/webpack-cli@e0b2f07) test: improve * [`5328fcb`](webpack/webpack-cli@5328fcb) chore(deps): bump pnpm/action-setup in the dependencies group ([ArcadeData#4699](https://redirect.github.com/webpack/webpack-cli/issues/4699)) * [`4b6f0e1`](webpack/webpack-cli@4b6f0e1) chore(deps): update ([ArcadeData#4696](https://redirect.github.com/webpack/webpack-cli/issues/4696)) * [`47fc332`](webpack/webpack-cli@47fc332) test: more ([ArcadeData#4695](https://redirect.github.com/webpack/webpack-cli/issues/4695)) * [`a199bc3`](webpack/webpack-cli@a199bc3) test: refactor config format test + more ([ArcadeData#4684](https://redirect.github.com/webpack/webpack-cli/issues/4684)) * [`20bc478`](webpack/webpack-cli@20bc478) refactor: code * [`529352d`](webpack/webpack-cli@529352d) docs: update ([ArcadeData#4692](https://redirect.github.com/webpack/webpack-cli/issues/4692)) * [`a01f01b`](webpack/webpack-cli@a01f01b) chore: fix coverage * [`e434e98`](webpack/webpack-cli@e434e98) refactor: make cli faster ([ArcadeData#4690](https://redirect.github.com/webpack/webpack-cli/issues/4690)) * Additional commits viewable in [compare view](https://github.com/webpack/webpack-cli/compare/webpack-cli@6.0.1...webpack-cli@7.0.0) Maintainer changes This version was pushed to npm by [GitHub Actions](<https://www.npmjs.com/~GitHub> Actions), a new releaser for webpack-cli since your current version. [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- Dependabot commands and options You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Summary
Issue4689MatchReturnVertexITfor issue java.util.NoSuchElementException #4689, which reportsMATCH (u:User) RETURN uthrowingjava.util.NoSuchElementExceptionvia HTTP, whileMATCH (u:User) RETURN u{.*} as userworksCloses #4689
The investigation found a structural inconsistency in
FinalProjectionStep.filterResult(): when a single Document property is returned, the result has bothelement=vertexANDcontent={"u":vertex}set simultaneously. This createsgetPropertyNames()vsgetProperty()inconsistency but does not cause NSE in the current serialization path (which uses the_projectionNameearly-return that callsdocument.toMap()directly). The regression tests provide coverage so any future regression is caught immediately.Test plan
mvn test -pl server -Dtest=Issue4689MatchReturnVertexIT- should show 7 tests passingMATCH (u:User) RETURN ureturns correct vertex data via HTTPSELECT FROM <type>returns correct records via HTTP