Skip to content

SOLR-8474: Add Selenium-based JUnit tests for the Admin UI - #4738

Open
janhoy wants to merge 47 commits into
apache:mainfrom
janhoy:admin-ui-selenium-tests
Open

SOLR-8474: Add Selenium-based JUnit tests for the Admin UI#4738
janhoy wants to merge 47 commits into
apache:mainfrom
janhoy:admin-ui-selenium-tests

Conversation

@janhoy

@janhoy janhoy commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

https://issues.apache.org/jira/browse/SOLR-8474

The old (AngularJS) Admin UI has had no automated test coverage. This PR adds JUnit tests that drive the real UI in a headless Chrome browser via Selenium WebDriver — pure JVM dependencies, no Node.js toolchain.

What's included

  • UI serving in tests: new opt-in JettyConfig.Builder#enableAdminUi(boolean) makes JettySolrRunner (and thus MiniSolrCloudCluster) serve the Admin UI static files and LoadAdminUiServlet exactly as the production web.xml does — addressing the long-standing TODO in JettySolrRunner.
  • Test harness (solr/webapp/src/test): AdminUiTestBase starts a 2-node cloud cluster with the UI enabled and a headless Chrome; AdminUiStandaloneTestBase covers standalone (user-managed, no ZooKeeper) nodes — including a leader/follower pair — whose UI differs from cloud mode. Tests skip cleanly (JUnit Assume) on machines without Chrome — e.g. ASF Jenkins — and run wherever Chrome is installed (-Dtests.ui.chrome.binary= to override discovery). On failure a screenshot, the page source and the browser console log are saved. An optional security.json hook supports authenticated clusters, and a stub of the generated js-client bundle keeps the Collections screen alive from a source checkout.
  • Feature-based test classes — each screen's display and write tests live together (53 tests in the default run):
    • AdminUiSmokeTest — navigates every screen, asserting no severe console errors
    • AdminUiDashboardTest — versions/JVM/memory vs /admin/info/system
    • AdminUiNodeScreensTest — java properties, threads, cloud nodes/tree/graph/zkstatus, security, login
    • AdminUiCollectionsScreenTest — detail display; create/delete collection, create/delete alias, add/delete replica, reload — all verified via APIs
    • AdminUiQueryScreenTest — query execution, rows/fl, paramsets dropdown, dismax/edismax toggles, raw query parameters
    • AdminUiDocumentsScreenTest — indexing form; document indexed via UI becomes searchable
    • AdminUiSchemaScreenTest — field browsing, flags and term info vs schema API; add/delete field via the dialogs
    • AdminUiParamsetsScreenTest — create/delete paramset via the form
    • AdminUiLoggingScreenTest — level editor set/unset; events viewer
    • AdminUiCoreAdminScreenTest — core listing, reload core (cloud)
    • AdminUiCoreAdminStandaloneTest — add/rename/swap/unload core on a standalone node, plus standalone menu differences
    • AdminUiCollectionScreensTest — analysis, files, segments, plugins, overviews
    • AdminUiStreamScreenTest — streaming expression execution
    • AdminUiSqlScreenTest — SQL query via the form (sql module as a test-only dependency; its jars were already licensed)
    • AdminUiReplicationScreenTest — cloud-mode rendering
    • AdminUiReplicationStandaloneTest — leader/follower pair: disable polling, replicate-now, enable polling
    • AdminUiSecurityAuthTest — BasicAuth login flow, security screen, add user/role/permission
    • AdminUiSchemaDesignerTest (@AwaitsFix) — designer happy path; disabled until the designer's backend flakiness is addressed
  • Dependencies kept slim: only the 8 core selenium-* jars (Apache-2.0) plus a byte-buddy version alignment; opentelemetry comes from solr-core, selenium-support was avoided by a small poll-based wait helper.
  • Beasting supported: gradlew -p solr/webapp beast -Ptests.dups=N --tests <Class> works (the generated test tasks needed explicit sourceSet wiring in this war project); the full suite is stable across order-shuffled beast runs.
  • Found real UI issues: the tests surfaced several UI bugs/weaknesses. They are tracked separately in SOLR-18347
  • Test catalog / status doc: dev-docs/admin-ui-tests.md

This PR was developed almost fully AI-assisted (Claude Fable).

Coverage checklist

  • Smoke navigation of every screen (node-level, cloud views, per-collection, per-core)
  • Dashboard display vs system API
  • Java properties, thread dump, logging tree displays
  • Cloud nodes/tree/graph/zkstatus displays
  • Collections: detail, create/delete, aliases, replicas, reload
  • Query: execution, rows/fl, paramsets dropdown, dismax/edismax toggles, raw query parameters
  • Documents: form + indexing via UI
  • Schema: browse, flags, term info, add/delete field
  • Paramsets: create/delete via UI
  • Logging: level change + events viewer
  • Core Admin: listing + reload (cloud); add/rename/swap/unload (standalone)
  • Analysis, Files, Segments, Plugins, Overviews
  • Stream expression execution
  • SQL screen (sql module on the test classpath)
  • Replication: cloud-mode rendering; standalone leader/follower replicate-now and polling toggles
  • Security with BasicAuth: login flow, security screen, add user/role/permission
  • Schema Designer happy path (@AwaitsFix due to designer backend flakiness)

Remaining TODOs for full coverage

  • JWT/OAuth login flows (need an identity provider — BasicAuth covers the login mechanics)
  • Serve the real js-client bundle when built, instead of the test stub
  • GitHub Actions workflow to run these tests in CI (Chrome is preinstalled on ubuntu-latest)
  • File JIRAs for the issues under "Possible UI bugs to investigate" in dev-docs/admin-ui-tests.md, and re-enable AdminUiSchemaDesignerTest once the designer races are fixed

janhoy added 9 commits August 13, 2026 23:25
- New opt-in JettyConfig.enableAdminUi flag makes JettySolrRunner serve the
  Admin UI static files and LoadAdminUiServlet like production web.xml does
- New test sourceSet in solr/webapp with AdminUiTestBase: starts a 2-node
  cloud cluster with the UI enabled and drives it with headless Chrome via
  Selenium WebDriver; tests skip cleanly when no Chrome binary is found
- First test: AdminUiDashboardTest asserts the dashboard displays versions,
  JVM and system stats matching the /admin/info/system API
- Selenium 4.47.0 test-only dependency with license bookkeeping
Exclude opentelemetry (provided by solr-core), auto-service and jspecify
annotation jars, and drop selenium-support in favor of a small poll-based
wait helper. Only the 8 core selenium jars and a byte-buddy version bump
remain as new dependencies.
Navigates every node-level, cloud, collection and core screen, waiting for
each screen's main content element and asserting no severe browser console
errors. Runs the test cluster with metricsEnabled=true so metrics-backed
screens (Plugins) work.
Selenium requires 1.18.11 on the webapp test classpath; align the shared
version so only a single byte-buddy version remains in solr/licenses.
Java properties, thread dump, logging tree, cloud nodes/tree views,
collections detail, core admin, security and login screens, verified
against the corresponding admin APIs. Serves a minimal stub of the
generated js-client bundle so the Collections screen's CollectionsV2
service instantiates in tests.
Collection screens: query execution, analysis, schema browser, files,
segments, plugins, documents form, paramsets, overview. Write actions
through the UI: create and delete a collection, index a document, change
and revert a log level - all verified via the corresponding APIs.
@janhoy

janhoy commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Well, this was impressive. In under one hour, Fable 5 did all this without any hand-holding beyond the initial promt (except me asking it to slim down dependencies). It figured out what tests to write, how to write them, how to wire in adminUI in test framework etc. The doc dev-docs/admin-ui-tests.md has checkboxes for the remaining tests to write for full coverage. That is just one more prompt "implement the remaining tests we have planned", and then come back in an hour :)

We'll then be able to catch regressions from any V2 work or any other commits to the UI. I ran all current 27 tests in 33 seconds, so this thing is fast too.

Edit: I kicked off the next prompt, going warp speed here..

@janhoy
janhoy marked this pull request as draft August 13, 2026 22:20
@janhoy
janhoy requested a review from epugh August 13, 2026 22:20
janhoy added 7 commits August 14, 2026 00:27
…ole log capture

Adds createFixtureCollection/coreNameOnNode0/waitUntil helpers, an optional
security.json for the test cluster, browser console logs in failure
artifacts, a standard test log4j2 config so the log watcher sees events,
and filters for two benign UI console errors.
…tions

Groups the collections display and write tests in one feature class:
create/delete collection, create/delete alias, add/delete replica and
reload, each verified through the corresponding API.
Feature-grouped classes: query execution with rows/fl parameters, the
documents indexing form, and paramset create/delete via the UI.
…gner

Schema browser display, field flags and term info, add/delete field via
the dialogs. Nightly Schema Designer happy path: new schema from a sample
document.
Logging level editor and events viewer, core reload, streaming expression
execution, and replication screen rendering in cloud mode.
… depth

Removes AdminUiWriteActionsTest (its tests moved to the feature classes),
trims the node/collection display classes accordingly, and deepens the
cloud coverage: graph SVG replica circles and ZK status ensemble info.
Comment thread solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java Outdated
@epugh

epugh commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

I'd prefer that we run these on nightly. The odds of breading the UI is generally low, and these tests don't seem light.

I think the big reason we are pushing to have this now is that the odds of breaking the UI are actually GOING UP, becasue we are migrating to the V2 api and we've labeled them Experimental which allows us to modify them more casually.

I don't love the nightly because I don't think anyone sees them... Definitly no casual contributor is subscribed to that mailing list, and it new casual contributors who are doing much of the V2 migration work... Lastly, one of Jason's big concerns was flakyness in this new tooling. The best way to iron out any flakyness, or identify and decide TOO flaky is to mkae these tests part of our regular testing.

janhoy added 5 commits August 21, 2026 15:17
Stubbing the js-client only grows as more v2 API calls land in the Admin UI.
The tests now serve the generated bundle unconditionally and skip themselves
when it is unavailable (js-client build disabled).

See apache#4738 (comment)
…um=true

Addresses maturity/stability concerns raised in review: the Selenium suites
no longer run by default. A new @SeleniumTest test group annotation
(disabled by default, aligned with @Nightly/@monster mechanics but its own
group) gates them; enable with -Ptests.selenium=true. Since a run is now an
explicit choice, a missing Chrome or non-starting ChromeDriver fails the
tests instead of skipping them.
With the js-client bundle excluded from the build the Admin UI tests cannot
meaningfully run, and a stubbed client would only grow stale as the UI
adopts more of the v2 API. The build now disables :solr:webapp tests with a
warning when -PdisableJsClient=true is set, and fails with an error when
-Ptests.selenium=true explicitly requests them at the same time.

See apache#4738 (comment)
Runs on pull requests that touch the webapp (UI code, tests, build), the v2
API contract in solr/api, or the v2 API implementations in
solr/core/.../handler/admin/api — the places a UI regression can originate.
Uses the Chrome preinstalled on ubuntu-latest and archives screenshots, page
sources and browser logs on failure.
Pick up the bundle from the js-client build output when the Gradle-set
sysprop is absent, so the suites also run from an IDE after one Gradle
build. Point the two UI-bug bullets in the doc at SOLR-18347.
@dsmiley

dsmiley commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

We could both make these tests nightly, and add a GitHub Actions workflow that runs specific things like this as well.

janhoy added 2 commits August 21, 2026 15:56
Aligns the browser-binary override with the tests.selenium opt-in flag.
A blank value is now treated as unset rather than overriding discovery.
Only wire the js-client bundle (and thereby its node/npm toolchain) into
:solr:webapp test tasks when -Ptests.selenium=true enables the Admin UI
tests; a default test run no longer touches the js-client build at all.

See apache#4738 (comment)
@janhoy

janhoy commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

I've now made the whole suite opt-in, which I think addresses the stability/maturity concerns raised here:

  • The suites carry a new @SeleniumTest test group annotation (disabled by default, same mechanics as @Nightly/@Monster but its own group), enabled with -Ptests.selenium=true. Without the flag all 53 tests group-skip in a fraction of a second — no cluster, no browser, no node — so they can never block or slow down regular development.
  • A missing Chrome now fails the tests instead of skipping: if you explicitly opted in, a silent skip would be a false green.
  • A new GitHub Actions workflow (admin-ui-test.yml) runs them on PRs that touch the webapp, the v2 API contract (solr/api) or the v2 API implementations (handler/admin/api) — exactly the places a UI regression can originate, per Eric's point that v2 migration is what's raising the risk.

On nightly (@dsmiley): I deliberately didn't group them into @Nightly — per Eric few people watch the nightly results, and the targeted PR workflow gives faster and more visible feedback. (Correction: I earlier claimed ASF Jenkins has no Chrome — I haven't actually been able to verify what's installed on the lucene-solr-3/4 nodes, so treat that as unverified.) Nothing prevents adding -Ptests.selenium=true to a nightly Jenkins job later if the nodes do have a browser, and the two approaches compose fine.

Docs in dev-docs/admin-ui-tests.md and dev-docs/gradle-help/tests.txt (gradlew helpTests). Also renamed the browser override to -Dtests.selenium.chrome.binary to match the flag.

janhoy added 2 commits August 21, 2026 16:10
Navigating to a URL that only differs in the #-fragment does not reload the
page, so the Angular app instance — including in-flight refresh callbacks of
the previous test's screen — survived across tests. On a slow CI runner such
a stale callback chain interleaved with the new test's navigation and fired
the collections controller's "No collection or alias" alert spuriously,
failing testReloadCollectionViaUi. openPage now forces a reload when already
on index.html, giving each test a fresh app instance.

@dsmiley dsmiley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing my concerns Jan! Big effort here, thank you.

Comment thread solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java Outdated
Comment thread solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java
@janhoy
janhoy requested review from epugh and a balanced review from Copilot August 21, 2026 14:51
@janhoy janhoy added this to the 10.x milestone Aug 21, 2026

@epugh epugh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while I don't love YAGW: Yet Another Github Workflow, I'll take the progress to unblock things. This looks great, I can't wait to have it. And I look forward to saying "thank you to the Admin UI for all your hard work" and "Goodbye to the entire Admin UI" in the not too distant future ;-).

@epugh

epugh commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Btw, @gerlowskija is reviewing the improvments I made to schema designer v2 api, and i'm looking forward to getting that merged, getting the new v2 use in admin ui merged, and then being able to remove the @AwaitsFix annotation for that selenium test!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 54 out of 54 changed files in this pull request and generated 2 comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

solr/webapp/src/test/org/apache/solr/webapp/AdminUiNodeScreensTest.java:57

  • This test does not drain or assert the browser console, unlike the other methods in this class. Because the same ChromeDriver is reused and test order is randomized, any severe error from this page is instead consumed by whichever test runs next and is reported against the wrong screen.
    solr/webapp/src/test-files/log4j2.xml:30
  • Correct the spelling of “synchonous” to “synchronous.”

Comment thread solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java
Comment thread .github/workflows/admin-ui-test.yml
janhoy added 3 commits August 21, 2026 17:14
Fetching the browser log from ChromeDriver empties its buffer, so a failed
console assertion left an empty console.log artifact. The assertion now
accumulates what it drains and the failure watcher writes the accumulated
entries plus any remainder, cleared at test start.
Changes to the embedded-Jetty harness, the SeleniumTest annotation or the
test-group wiring can break the browser tests; include those paths in the
workflow filter.
A Chrome update surfaced timing races the harness previously got away with:

- waitFor(...).click() could hit a StaleElementReferenceException when the
  page re-rendered between lookup and click (reproducible on the logging
  screen's jstree). All click sites now go through a click(By) helper that
  retries the whole find-and-click, like the existing setText helper.
- Booting the app directly on a deep link races its initial data loading,
  intermittently leaving the target screen unresolved (empty collection in
  the per-collection menu, hidden action buttons). openPage now boots a
  fresh app instance on the default route and then navigates in-app via a
  hash change, like a user would.
- WAIT_TIMEOUT raised from 15s to 30s for loaded CI machines; successful
  waits still return as soon as their condition holds.
Comment thread solr/webapp/src/test/org/apache/solr/webapp/AdminUiTestBase.java
@janhoy

janhoy commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Heads-up on the latest commit (5df3e5d): a Chrome auto-update (151.0.7922.137 → .170) surfaced three timing races locally — a stale-element click on the logging screen's jstree, a data-loading race when the app boots directly on a deep link, and tight 15s waits under load. All clicks now retry via a click(By) helper, openPage boots the app on the default route and then navigates in-app like a user would, and the wait timeout is 30s. Validated with 5 consecutive full-suite runs plus beasting the worst classes — all green. The deep-link boot race itself is another Admin UI weakness for the SOLR-18347 list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants