Skip to content

feat(compat): Solr 10 support with metrics API migration#61

Open
adityamparikh wants to merge 19 commits intoapache:mainfrom
adityamparikh:metrics-api-migration
Open

feat(compat): Solr 10 support with metrics API migration#61
adityamparikh wants to merge 19 commits intoapache:mainfrom
adityamparikh:metrics-api-migration

Conversation

@adityamparikh
Copy link
Copy Markdown
Contributor

@adityamparikh adityamparikh commented Mar 8, 2026

Summary

Comprehensive Solr 10 compatibility PR that consolidates the metrics API migration,
create-collection tool, CI matrix expansion, and code review hardening into a single
reviewable changeset.

  • Metrics API migration: getCacheMetrics() and getHandlerMetrics() now use
    /admin/metrics (available since Solr 7.1+) instead of the removed /admin/mbeans
  • Create-collection MCP tool: New create-collection tool with authentication,
    configSet/numShards/replicationFactor defaults
  • CI matrix: Tests now run against Solr 8.11, 9.4, 9.9, 9.10, and 10
  • Code review fixes:
    • Fix ClassCastException risk in CollectionUtils.getFloat — added instanceof
      check and String fallback parsing
    • Add extractCollectionName() to checkHealth for shard name support
    • Populate collection field in SolrHealthStatus response
    • Eliminate 3 redundant listCollections() round-trips per getCollectionStats call
    • Return null instead of 0.0f from getFloat for missing values (consistent
      with getLong/getInteger)
  • Integration tests rewritten: Setup indexes 50 documents and runs 15 warm-up
    queries (with filter queries) against real Solr via Testcontainers. Tests assert
    actual non-zero metric values:
    • numDocs == 50, totalResults == 50, totalDocuments == 50
    • queryResultCache.lookups > 0, documentCache.lookups > 0, filterCache.lookups > 0
    • selectHandler.requests > 0, updateHandler.requests > 0
    • System.out.println replaced with SLF4J, @BeforeEach/static-boolean replaced
      with @BeforeAll/@TestInstance(PER_CLASS)

Supersedes #59.

Test plan

  • ./gradlew build passes (default Solr 9.9)
  • Integration tests index real data and assert on actual metric values
  • Unit tests updated with collection field assertions and String-based getFloat tests
  • Verify against solr:10-slim and solr:9.10-slim Docker images

🤖 Generated with Claude Code

adityamparikh and others added 17 commits February 28, 2026 23:38
Replace the default BinaryResponseParser (wt=javabin) with a custom
JsonResponseParser (wt=json) for future-proofing and improved
debuggability.

The JsonResponseParser converts Solr's JSON response envelope into the
NamedList<Object> tree that SolrJ typed response classes expect:
- JSON objects → SimpleOrderedMap (extends NamedList, implements Map,
  satisfying both QueryResponse's NamedList casts and SchemaResponse's
  Map cast)
- JSON objects with numFound+docs → SolrDocumentList
- Flat alternating arrays [String, non-String, ...] → SimpleOrderedMap
  (Solr's json.nl=flat encoding for facet counts)
- All other arrays → List
- Decimal numbers → Float (matching JavaBin's float type, required by
  SchemaResponse's (Float) version cast)
- Small integers → Integer, large integers → Long

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
Extract JsonResponseParser instantiation into a dedicated @bean method
so it can be injected as a dependency into solrClient(), making the
wiring explicit and enabling overriding in tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
Replace the static new ObjectMapper() with Spring's auto-configured
ObjectMapper bean injected via constructor. Use MediaType.APPLICATION_JSON_VALUE
for the content type constant instead of a raw string literal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
…'s ObjectMapper

Extract URL normalization tests from SolrConfigTest into a dedicated
SolrConfigUrlNormalizationTest annotated with @jsontest, so Spring's
auto-configured ObjectMapper is injected rather than using new ObjectMapper().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
… Solr 10

SolrInfoMBeanHandler (and thus the /admin/mbeans endpoint) was removed in
Solr 10. When getCacheMetrics() or getHandlerMetrics() call this endpoint on
a Solr 10 server, SolrJ throws RemoteSolrException (a RuntimeException) because
the server returns an HTML 404 page instead of JSON.

Widen the catch in both methods to include RuntimeException so the server
degrades gracefully (returning null for cache/handler stats) rather than
propagating the exception. The integration tests already handle null stats,
so all tests now pass with solr:10-slim.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
Add Solr 9.10 and 10 to the CI compatibility matrix, running integration
tests against all supported versions (8.11, 9.4, 9.9, 9.10, 10) on every
PR and push to main.

Also update AGENTS.md to document Solr 10 compatibility status: the
/admin/mbeans endpoint removal is handled gracefully, and all other
functionality is verified working with solr:10-slim.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
Move CollectionService, CollectionUtils, and Dtos from the metadata
package into a new dedicated collection package. This separates
collection management from schema introspection (SchemaService stays
in metadata).

Add create-collection MCP tool to CollectionService:
- Accepts name (required), configSet, numShards, replicationFactor
- Defaults: configSet=_default, numShards=1, replicationFactor=1
- Uses CollectionAdminRequest.createCollection() for both SolrCloud
  and standalone Solr via Http2SolrClient
- Returns CollectionCreationResult DTO with name, success, message,
  and createdAt timestamp

Add CollectionCreationResult record to Dtos.java.

Update unit tests with correct 2-arg Mockito stubs to match
CollectionAdminRequest.process() call signature.
Add integration test asserting the new collection appears in
listCollections() after creation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
116 session documents covering all tracks and days (March 4-6 2026)
for use with the create-collection and index-documents MCP tools.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
- Add isBlank() guard in createCollection() to throw
  IllegalArgumentException before calling SolrJ, ensuring consistent
  behavior regardless of SolrJ version
- Update README: add create-collection to feature list, fix all tool
  names to kebab-case, split into Search/Indexing/Collections/Schema
  sections, list all three indexing tools separately

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
Add @PreAuthorize("isAuthenticated()") to the createCollection method
to prevent unauthorized collection creation via the MCP tool, consistent
with the pattern used in SearchService and IndexingService.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
- Remove unnecessary local variable in validateCollectionExists (S1488)
- Add private constructor to CollectionUtils utility class (S1118)

Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Aditya Parikh <adityamparikh@gmail.com>
Merge upstream/main into solr-10 branch. Adopt consolidated parameterized
test with try-with-resources for URL normalization, removing duplicate
individual test methods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
Trivial conflict: unused exception variable naming (e vs _) in catch
blocks for getCacheMetrics and getHandlerMetrics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
…trics API

Replace the deprecated /admin/mbeans endpoint with the Solr Metrics API
(/admin/metrics) for cache and handler statistics. The Metrics API is
node-level, so fetchMetrics now searches for the matching core registry
by prefix. Cache metrics remain nested NamedList objects while handler
metrics use flat dotted keys (e.g. QUERY./select.requests), requiring
separate extraction logic.

Key changes:
- fetchMetrics uses /admin/metrics with group=core and prefix filtering
- Handler extraction refactored to read flat keys via extractFlatHandlerInfo
- Core registry matching uses trailing dot to prevent false prefix matches
- Remove unused AVG_TIME_PER_REQUEST_FIELD and AVG_REQUESTS_PER_SECOND_FIELD
- Add integration tests for cache and handler metrics against real Solr
- Remove dead test helper createCompleteMockCacheData

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
- Fix ClassCastException risk in CollectionUtils.getFloat by adding
  instanceof check and String fallback parsing, matching getLong/getInteger
- Add extractCollectionName() call to checkHealth for shard name support
- Populate collection field in SolrHealthStatus response
- Eliminate redundant validateCollectionExists calls when getCacheMetrics
  and getHandlerMetrics are invoked from getCollectionStats (saves 3
  extra listCollections() round-trips per call)
- Replace System.out.println debug statements with SLF4J logger
- Migrate integration test setup from fragile @BeforeEach/static-boolean
  to @BeforeAll with @testinstance(PER_CLASS)
- Add String-based getFloat tests and collection field assertions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
@adityamparikh adityamparikh force-pushed the metrics-api-migration branch from 2119774 to 8b94f1d Compare March 26, 2026 02:16
@adityamparikh adityamparikh changed the title refactor(metrics): migrate from /admin/mbeans to /admin/metrics API feat(compat): Solr 10 support with metrics API migration and code review fixes Mar 26, 2026
adityamparikh and others added 2 commits March 26, 2026 17:52
The integration tests previously created an empty collection and only
checked metrics were >= 0. Now @BeforeAll indexes 50 documents and
runs 15 warm-up queries (including filter queries) against real Solr
via Testcontainers. Tests assert on actual non-zero values:

- numDocs == 50 (matches indexed count)
- queryResultCache.lookups > 0 (from warm-up queries)
- documentCache.lookups > 0 (from reading documents)
- filterCache.lookups > 0 (from filter queries)
- selectHandler.requests > 0 (from queries)
- updateHandler.requests > 0 (from indexing)
- health check totalDocuments == 50

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
Replace direct SolrClient calls with the actual Spring service beans:
- CollectionService.createCollection() to create the test collection
- IndexingService.indexJsonDocuments() to index 50 test documents
- SearchService.search() for warm-up queries and verification

This exercises the real MCP tool code paths (JSON document creation,
batch indexing, query building) rather than bypassing them with raw
SolrJ. Also adds testSearchVerifiesIndexedDocuments() to confirm
SearchService returns correct results with filter queries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: adityamparikh <aditya.m.parikh@gmail.com>
@adityamparikh adityamparikh changed the title feat(compat): Solr 10 support with metrics API migration and code review fixes feat(compat): Solr 10 support with metrics API migration Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant