libhive,hiveview: Track per-test client log ranges for better reporting#1402
Conversation
| } | ||
| for _, test := range s.TestCases { | ||
| if test.MultiTestContext { | ||
| continue |
There was a problem hiding this comment.
I think this thing should be reverted.
There was a problem hiding this comment.
I've removed the filtering of test cases with this field in hiveview.
The backend additions for the field remain:
- The
MultiTestContextfield, SetMultiTestContextmethod, and,- the
SetMultiTestContextcall inregisterMultiTestNode.
I can easily remove these if need be by dropping 319ebe5.
There was a problem hiding this comment.
Btw, the motivation behind keeping the field is to potentially enable special handling of these "client lifecycle" tests in https://github.com/ethpandaops/hive-ui.
| for (var k in data.testCases) { | ||
| let tc = data.testCases[k]; | ||
| if (tc.multiTestContext) { | ||
| continue; |
08fc98f to
440e643
Compare
440e643 to
cfacc48
Compare
|
From the description:
@fjl, this understates the change in hiveview behavior. All clients get log byte offsets, even clients whose register endpoint is never called (i.e, single-test clients). So this behavior effects all tests and upon opening the client log it will always jump to the log portion corresponding to the test, not line 0 as before. This is because |
enginex and enable log reporting for multi-test clientsenginex and enable log reporting for multi-test clients
enginex and enable log reporting for multi-test clients| ) | ||
|
|
||
| // noopBackend is a minimal ContainerBackend for testing. | ||
| type noopBackend struct{} |
There was a problem hiding this comment.
We don't need to define this backend here, there is already a mock backend in package internal/fakes.
There was a problem hiding this comment.
The test accessed libhive internals, so couldn't use fakes as-is. I re-wrote it to test via the public API; now it's declared as package libhive_test and uses fakes, see ec9d4cb
Add LogOffsets field to ClientInfo to track byte offsets into the client log file for the portion relevant to each test case. This enables log filtering when a single client container serves multiple tests (e.g., in the enginex simulator with many-test-to-single-client mapping). - Add LogOffsets *TestLogOffsets to ClientInfo struct - Add LogFileSize helper function to get current log size - Set LogOffsets.Begin when client container starts (api.go) - Set LogOffsets.End when test ends (testmanager.go)
- `StartTest` and `EndTest` write to `suite.TestCases` under `testCaseMutex`. - `IsTestInSuite` read from the same map without holding `testCaseMutex`. - Acquire `testCaseMutex.RLock()` before the map read to fix the race.
Use `package libhive_test` with `fakes.NewContainerBackend` to avoid the import cycle that `noopBackend` worked around. Client start and multi-test node registration now go through the HTTP API via `httptest.NewServer` so the `wait` callback is set by real code paths. Container lifecycle is verified through a `DeleteContainer` hook and log offsets through `tm.Results()`. `TestLogFileSize` moves to its own internal-package file since it tests an unexported function and has no external dependencies.
cfacc48 to
ec9d4cb
Compare
|
Heavier testing with a larger fixture release and higher |
| for _, v := range testCase.ClientInfo { | ||
| if v.LogOffsets != nil && manager.config.LogDir != "" { | ||
| logFilePath := filepath.Join(manager.config.LogDir, filepath.FromSlash(v.LogFile)) | ||
| v.LogOffsets.End = logFileSize(logFilePath) |
There was a problem hiding this comment.
I wouldn't have another method handy, but just want to note that this way of getting the offsets might be unreliable. The way logs are handled is that hive attaches to the docker output stream and writes the output to the file in a background goroutine. This process is not at all synchronized with the running of tests. So depending on machine load, docker latency, etc., the collected offsets can be way behind. Basically what's happening here is, we are taking the current size of the output file, as reported by the OS, and recording that.
We could improve this by adding more API surface in the docker backend to allow reading the current output size of the container. This would remove the OS filesystem from the equation at least.
Nothing further can be done though, since we fundamentally rely on docker to provide us with the output from the client container.
There is also the fundamental issue that client logs may not always be emitted in time with the tests.
* feat: display per-test client log sections via TestLogOffsets Hive can now reuse client containers across many tests (ethereum/hive#1402) and reports the byte range of the client log belonging to each test in clientInfo[].logOffsets. Surface those ranges in the UI: - types: TestLogOffsets, clientInfo[].logOffsets, multiTestContext, optional summaryResult fields - hide multi-test context pseudo-tests from the results table and stats - per-test Logs links anchor the viewer on the test's byte range - expanded rows show a client-log excerpt (Range request, capped at 128 KB) next to the existing test-details excerpt - LogViewer: ?begin&end now loads the full file, maps byte offsets to lines (byte-accurate), highlights the section and scrolls to it - byteRange utils defend against servers that ignore Range headers * fix: clamp byte offsets to buffer length in line mapping * feat: windowed log viewer for byte-range anchored views When anchored on a test's byte range (?begin&end), fetch only the range plus 64 KB of context via HTTP Range requests instead of the whole file, so shared client logs of any size render instantly: - expand-up/expand-down buttons load more context in 64 KB steps, preserving the scroll position when prepending - absolute line numbers resolve in the background by streaming the window prefix and counting newlines (window-relative until then) - 'Load full file' escape hatch switches to the full view - servers without Range support fall back to the full view for free * feat: log-to-test navigation for shared client logs Adds the inverse mapping of per-test log offsets — from a shared client log back to the tests it contains: - LogViewer sidebar listing every test section of the current log in log order, with pass/fail dots, a failures filter, and per-segment links to the test details; clicking a segment re-anchors the viewer - suite page 'Shared Client Sessions' panel summarising the client instances owned by multi-test context entries (tests served, log size, lifecycle status), replacing the hidden pseudo test case * fix: use instant scroll for programmatic jumps in virtualized log tanstack-virtual smooth scrolling does not reliably complete over long distances on a freshly mounted virtualizer, leaving anchored views at the top of the window instead of on the highlighted section. * feat: show absolute line numbers in log excerpt headers Counted directly when the server returned the whole file, otherwise by streaming the prefix in the background; skipped for excerpts starting beyond 8 MB so expanding a row never triggers huge downloads. * refactor: apply review cleanups to log-offset code - share one isRealTestCase predicate (5 inline multiTestContext filters) and one logViewerUrl builder (3 inline route constructions) - move window chunk helpers (EOF detection, partial-line trims) into byteRange.ts, shared by initial load and both expand directions - replace per-request prefix streaming with checkpoint-cached, bounded line-number resolution (resolveLineNumber); navigating between tests in the same log now only streams the gap since the last count - drop the HEAD pre-flight (Content-Range already carries the size), LogViewer's duplicate byte formatter, derivable lineCount/truncated state, dead resets, and the stale-result ref machinery - VirtualizedLogContent takes prependedLines (its own units) instead of a pixel scroll adjustment; line-height knowledge stays internal - suite JSON query marked immutable (staleTime: Infinity); themed CSS variables replace hardcoded border/text colors in the new components * fix: handle empty log ranges and stale scroll timeouts Production results record logOffsets with begin == end when a client produced no output during a test; requesting that range can even yield 416 at EOF. fetchByteRange now short-circuits empty ranges and expanded rows say so instead of rendering an empty excerpt. Scroll-to-index timeouts in the virtualized views are cleared on re-run so a pending scroll never fires against an outdated index, and sidebar rows guard against virtual items that momentarily outlive a shrinking filtered list.
Summary
Edit: The simulator Dockerfile has been removed from this PR and added in #1403.
This PR
adds theimplements per-test client log isolation for multi-test client reuse.eels/consume-enginexsimulator andIt adds:blockchain_test_engine_xfixtures by running multiple tests against a single client instance, avoiding client startup time.And, to enable client log file handling for this simulator/"multi-test" clients, it implements:
These last changes are required because although simulators can already reuse a client across multiple tests, the results lack per-test client log isolation. All tests point to the same full client log file with no way to see which portion is relevant.
Backend (
internal/libhive)registerMultiTestNodeAPI endpoint (POST /testsuite/{suite}/test/{test}/node/{node}/register/{target}) that registers a target test for use with an existing client, capturing the current log file offset as the new test's starting byte position.TestLogOffsetsonClientInfo; capture end offset inEndTest.MultiTestContextand filter them from result summaries and test counts. Without this, the client lifecycle test case inflates the test count by one.(edit: filtering removed).testmanager_test.gocovering registration, lifecycle ownership, and log offset correctness.Frontend (
cmd/hiveview)Testing
To test, cherry-pick the commit that adds the enginex simulator in #1403 and use experiments/enginex-fix-test-reporting from ethereum/execution-specs#2476 that uses the new
registerendpoint:./hive --sim ethereum/eels/consume-enginex \ --client go-ethereum \ --sim.buildarg "branch=experiments/enginex-fix-test-reporting" \ --sim.buildarg "fixtures=https://github.com/danceratopz/execution-specs/releases/download/v0.1.0a2/fixtures.tar.gz" \ --client-file client.yaml \ --sim.loglevel=5 --docker.nocache enginexwhere
client.yaml, is, for example:and the specified "release" contains an example set of 222 benchmark tests split across 4 pre-alloc groups:
Screengrab
hiveview-multi-client-log-reporting-demo-small.mp4