You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ep...@apache.org on 2026/04/23 18:50:55 UTC

(solr-mcp) branch main updated: test: add MCP client integration test and reorganize test structure (#91)

This is an automated email from the ASF dual-hosted git repository.

epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-mcp.git


The following commit(s) were added to refs/heads/main by this push:
     new 6ccade5  test: add MCP client integration test and reorganize test structure (#91)
6ccade5 is described below

commit 6ccade5e3a9354a3dae5d3f18c1804b08762fa87
Author: Aditya Parikh <ad...@gmail.com>
AuthorDate: Thu Apr 23 14:50:49 2026 -0400

    test: add MCP client integration test and reorganize test structure (#91)
    
    * docs: update Spring AI version reference in AGENTS.md
    
    https://claude.ai/code/session_018sFVmRBfFQ3aaU8yyPDvCG
    
    * test: add MCP client integration test
    
    Add McpClientIntegrationTest that exercises the MCP server through a real
    MCP client over HTTP. Boots the app in HTTP mode on a random port with
    Solr via Testcontainers, connects an McpSyncClient, and tests the full
    create-collection → index → search workflow via MCP tool calls.
    
    Tests cover: ping, tool discovery, collection creation, listing,
    JSON/CSV indexing, search (all docs, filter query, keyword, pagination,
    facets), health check, collection stats, and schema introspection.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <no...@anthropic.com>
    Signed-off-by: adityamparikh <ad...@gmail.com>
    
    * refactor(test): reorganize tests into unit and integration classes
    
    Establish consistent test naming convention:
    - *ServiceTest.java = unit tests (mocked dependencies, fast)
    - *ServiceIntegrationTest.java = integration tests (Testcontainers, real Solr)
    
    Search tests:
    - SearchServiceTest: unit tests with mocked SolrClient (replaces SearchServiceDirectTest)
    - SearchServiceIntegrationTest: real Solr via Testcontainers (new)
    
    Indexing tests:
    - IndexingServiceTest: unit tests with mocked SolrClient (replaces nested UnitTests + DirectTest)
    - IndexingServiceIntegrationTest: real Solr via Testcontainers (new)
    
    Also:
    - Delete redundant *DirectTest.java files
    - Fix TestcontainersConfiguration default Solr image to "solr:9.9-slim"
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <no...@anthropic.com>
    Signed-off-by: adityamparikh <ad...@gmail.com>
    
    ---------
    
    Signed-off-by: adityamparikh <ad...@gmail.com>
    Co-authored-by: Claude <no...@anthropic.com>
---
 AGENTS.md                                          |   2 +-
 .../solr/mcp/server/McpClientIntegrationTest.java  | 325 +++++++++
 .../mcp/server/TestcontainersConfiguration.java    |   2 +-
 .../server/indexing/IndexingServiceDirectTest.java | 212 ------
 ...st.java => IndexingServiceIntegrationTest.java} | 305 +--------
 .../mcp/server/indexing/IndexingServiceTest.java   | 732 +--------------------
 .../mcp/server/search/SearchServiceDirectTest.java | 288 --------
 ...Test.java => SearchServiceIntegrationTest.java} | 292 +-------
 .../solr/mcp/server/search/SearchServiceTest.java  | 434 +-----------
 9 files changed, 362 insertions(+), 2230 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index 10f6aa5..b2236c7 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -8,7 +8,7 @@ Solr MCP Server is a Spring AI Model Context Protocol (MCP) server that enables
 
 - **Status:** Apache incubating project (v0.0.2-SNAPSHOT)
 - **Java:** 25+ (centralized in build.gradle.kts)
-- **Framework:** Spring Boot 3.5.8, Spring AI 1.1.2
+- **Framework:** Spring Boot 3.5.13, Spring AI 1.1.4
 - **License:** Apache 2.0
 
 ## Common Commands
diff --git a/src/test/java/org/apache/solr/mcp/server/McpClientIntegrationTest.java b/src/test/java/org/apache/solr/mcp/server/McpClientIntegrationTest.java
new file mode 100644
index 0000000..3eed6f8
--- /dev/null
+++ b/src/test/java/org/apache/solr/mcp/server/McpClientIntegrationTest.java
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.mcp.server;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.modelcontextprotocol.client.McpClient;
+import io.modelcontextprotocol.client.McpSyncClient;
+import io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport;
+import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
+import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
+import io.modelcontextprotocol.spec.McpSchema.TextContent;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.ActiveProfiles;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+/**
+ * Integration test that exercises the MCP server through a real MCP client.
+ *
+ * <p>
+ * Boots the application in HTTP mode, connects an MCP client, and tests the
+ * full create-collection → index → search workflow via MCP tool calls.
+ */
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {"http.security.enabled=false",
+		"spring.docker.compose.enabled=false"})
+@ActiveProfiles("http")
+@Import(TestcontainersConfiguration.class)
+@Testcontainers(disabledWithoutDocker = true)
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+class McpClientIntegrationTest {
+
+	private static final String COLLECTION = "mcp-client-test";
+
+	private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+	@LocalServerPort
+	private int port;
+
+	private McpSyncClient mcpClient;
+
+	@BeforeAll
+	void setupClient() {
+		var transport = HttpClientStreamableHttpTransport.builder("http://localhost:" + port).build();
+		mcpClient = McpClient.sync(transport).build();
+		mcpClient.initialize();
+	}
+
+	@AfterAll
+	void tearDown() {
+		if (mcpClient != null) {
+			mcpClient.close();
+		}
+	}
+
+	@Test
+	@Order(1)
+	void pingServer() {
+		assertDoesNotThrow(() -> mcpClient.ping(), "MCP ping should succeed");
+	}
+
+	@Test
+	@Order(2)
+	void listToolsReturnsExpectedTools() {
+		var toolsResult = mcpClient.listTools();
+		assertNotNull(toolsResult);
+		List<String> toolNames = toolsResult.tools().stream().map(t -> t.name()).toList();
+
+		assertTrue(toolNames.contains("create-collection"), "Should have create-collection tool");
+		assertTrue(toolNames.contains("index-json-documents"), "Should have index-json-documents tool");
+		assertTrue(toolNames.contains("search"), "Should have search tool");
+		assertTrue(toolNames.contains("list-collections"), "Should have list-collections tool");
+		assertTrue(toolNames.contains("check-health"), "Should have check-health tool");
+		assertTrue(toolNames.contains("get-collection-stats"), "Should have get-collection-stats tool");
+		assertTrue(toolNames.contains("get-schema"), "Should have get-schema tool");
+	}
+
+	@Test
+	@Order(3)
+	void createCollection() {
+		CallToolResult result = mcpClient
+				.callTool(new CallToolRequest("create-collection", Map.of("name", COLLECTION)));
+
+		assertNotNull(result);
+		assertNotError(result);
+		String text = extractText(result);
+		assertTrue(text.contains("success") || text.contains("true"), "Collection creation should succeed: " + text);
+	}
+
+	@Test
+	@Order(4)
+	void listCollectionsContainsCreatedCollection() {
+		CallToolResult result = mcpClient.callTool(new CallToolRequest("list-collections", Map.of()));
+
+		assertNotNull(result);
+		assertNotError(result);
+		String text = extractText(result);
+		assertTrue(text.contains(COLLECTION), "Created collection should appear in list: " + text);
+	}
+
+	@Test
+	@Order(5)
+	void indexJsonDocuments() {
+		String json = """
+				[
+				  {"id": "1", "title": "Introduction to Solr", "author": "Alice", "category": "search"},
+				  {"id": "2", "title": "MCP Protocol Guide", "author": "Bob", "category": "protocol"},
+				  {"id": "3", "title": "Spring Boot in Action", "author": "Charlie", "category": "framework"},
+				  {"id": "4", "title": "Advanced Solr Techniques", "author": "Alice", "category": "search"},
+				  {"id": "5", "title": "Building MCP Servers", "author": "Diana", "category": "protocol"}
+				]
+				""";
+
+		CallToolResult result = mcpClient
+				.callTool(new CallToolRequest("index-json-documents", Map.of("collection", COLLECTION, "json", json)));
+
+		assertNotNull(result);
+		assertNotError(result);
+	}
+
+	@Test
+	@Order(6)
+	void checkHealthShowsIndexedDocuments() {
+		CallToolResult result = mcpClient
+				.callTool(new CallToolRequest("check-health", Map.of("collection", COLLECTION)));
+
+		assertNotNull(result);
+		assertNotError(result);
+		String text = extractText(result);
+		assertTrue(text.contains("true") || text.contains("healthy"), "Collection should be healthy: " + text);
+		assertTrue(text.contains("5"), "Should report 5 documents: " + text);
+	}
+
+	@Test
+	@Order(7)
+	void searchAllDocuments() throws Exception {
+		CallToolResult result = mcpClient
+				.callTool(new CallToolRequest("search", Map.of("collection", COLLECTION, "query", "*:*", "rows", 10)));
+
+		assertNotNull(result);
+		assertNotError(result);
+		String text = extractText(result);
+
+		Map<String, Object> response = OBJECT_MAPPER.readValue(text, new TypeReference<>() {
+		});
+		assertEquals(5, getNumFound(response), "Should find all 5 documents");
+	}
+
+	@Test
+	@Order(8)
+	void searchWithFilterQuery() throws Exception {
+		CallToolResult result = mcpClient.callTool(new CallToolRequest("search",
+				Map.of("collection", COLLECTION, "query", "*:*", "filterQueries", List.of("category:search"))));
+
+		assertNotNull(result);
+		assertNotError(result);
+		String text = extractText(result);
+
+		Map<String, Object> response = OBJECT_MAPPER.readValue(text, new TypeReference<>() {
+		});
+		assertEquals(2, getNumFound(response), "Should find 2 search-category documents");
+	}
+
+	@Test
+	@Order(9)
+	void searchWithKeyword() throws Exception {
+		CallToolResult result = mcpClient
+				.callTool(new CallToolRequest("search", Map.of("collection", COLLECTION, "query", "title:Solr")));
+
+		assertNotNull(result);
+		assertNotError(result);
+		String text = extractText(result);
+
+		Map<String, Object> response = OBJECT_MAPPER.readValue(text, new TypeReference<>() {
+		});
+		int numFound = getNumFound(response);
+		assertTrue(numFound >= 1, "Should find at least 1 document with 'Solr' in title: " + numFound);
+	}
+
+	@Test
+	@Order(10)
+	void searchWithPagination() throws Exception {
+		CallToolResult page1 = mcpClient.callTool(
+				new CallToolRequest("search", Map.of("collection", COLLECTION, "query", "*:*", "start", 0, "rows", 2)));
+		CallToolResult page2 = mcpClient.callTool(
+				new CallToolRequest("search", Map.of("collection", COLLECTION, "query", "*:*", "start", 2, "rows", 2)));
+
+		Map<String, Object> response1 = OBJECT_MAPPER.readValue(extractText(page1), new TypeReference<>() {
+		});
+		Map<String, Object> response2 = OBJECT_MAPPER.readValue(extractText(page2), new TypeReference<>() {
+		});
+
+		List<Map<String, Object>> docs1 = getDocuments(response1);
+		List<Map<String, Object>> docs2 = getDocuments(response2);
+
+		assertEquals(2, docs1.size(), "Page 1 should have 2 documents");
+		assertEquals(2, docs2.size(), "Page 2 should have 2 documents");
+		assertNotEquals(docs1.get(0).get("id"), docs2.get(0).get("id"), "Pages should return different documents");
+	}
+
+	@Test
+	@Order(11)
+	void getCollectionStats() {
+		CallToolResult result = mcpClient
+				.callTool(new CallToolRequest("get-collection-stats", Map.of("collection", COLLECTION)));
+
+		assertNotNull(result);
+		assertNotError(result);
+		String text = extractText(result);
+		assertTrue(text.contains("5") || text.contains("numDocs"), "Stats should reference indexed documents: " + text);
+	}
+
+	@Test
+	@Order(12)
+	void getSchema() {
+		CallToolResult result = mcpClient.callTool(new CallToolRequest("get-schema", Map.of("collection", COLLECTION)));
+
+		assertNotNull(result);
+		assertNotError(result);
+		String text = extractText(result);
+		assertFalse(text.isEmpty(), "Schema response should not be empty");
+	}
+
+	@Test
+	@Order(13)
+	void searchWithFacets() throws Exception {
+		CallToolResult result = mcpClient.callTool(new CallToolRequest("search",
+				Map.of("collection", COLLECTION, "query", "*:*", "facetFields", List.of("id"), "rows", 0)));
+
+		assertNotNull(result);
+		assertNotError(result);
+		String text = extractText(result);
+
+		Map<String, Object> response = OBJECT_MAPPER.readValue(text, new TypeReference<>() {
+		});
+		@SuppressWarnings("unchecked")
+		Map<String, Object> facets = (Map<String, Object>) response.get("facets");
+		assertNotNull(facets, "Should have facets in response");
+		assertTrue(facets.containsKey("id"), "Should have id facet");
+	}
+
+	@Test
+	@Order(14)
+	void indexCsvDocuments() {
+		String csv = """
+				id,title,author,category
+				6,CSV Document One,Eve,csv-test
+				7,CSV Document Two,Frank,csv-test
+				""";
+
+		CallToolResult result = mcpClient
+				.callTool(new CallToolRequest("index-csv-documents", Map.of("collection", COLLECTION, "csv", csv)));
+
+		assertNotNull(result);
+		assertNotError(result);
+	}
+
+	@Test
+	@Order(15)
+	void searchFindsAllDocumentsAfterCsvIndexing() throws Exception {
+		CallToolResult result = mcpClient
+				.callTool(new CallToolRequest("search", Map.of("collection", COLLECTION, "query", "*:*", "rows", 0)));
+
+		Map<String, Object> response = OBJECT_MAPPER.readValue(extractText(result), new TypeReference<>() {
+		});
+		assertEquals(7, getNumFound(response), "Should find 7 documents (5 JSON + 2 CSV)");
+	}
+
+	private static String extractText(CallToolResult result) {
+		assertNotNull(result.content(), "Result content should not be null");
+		assertFalse(result.content().isEmpty(), "Result content should not be empty");
+		assertInstanceOf(TextContent.class, result.content().get(0), "Content should be TextContent");
+		return ((TextContent) result.content().get(0)).text();
+	}
+
+	private static void assertNotError(CallToolResult result) {
+		if (Boolean.TRUE.equals(result.isError())) {
+			String errorText = result.content().isEmpty()
+					? "unknown error"
+					: ((TextContent) result.content().get(0)).text();
+			fail("MCP tool call returned error: " + errorText);
+		}
+	}
+
+	private static int getNumFound(Map<String, Object> response) {
+		Object value = response.get("numFound");
+		assertNotNull(value, "numFound should be present in response");
+		return ((Number) value).intValue();
+	}
+
+	@SuppressWarnings("unchecked")
+	private static List<Map<String, Object>> getDocuments(Map<String, Object> response) {
+		Object value = response.get("documents");
+		assertNotNull(value, "documents should be present in response");
+		return (List<Map<String, Object>>) value;
+	}
+
+}
diff --git a/src/test/java/org/apache/solr/mcp/server/TestcontainersConfiguration.java b/src/test/java/org/apache/solr/mcp/server/TestcontainersConfiguration.java
index 0a0f91d..5f6267a 100644
--- a/src/test/java/org/apache/solr/mcp/server/TestcontainersConfiguration.java
+++ b/src/test/java/org/apache/solr/mcp/server/TestcontainersConfiguration.java
@@ -29,7 +29,7 @@ public class TestcontainersConfiguration {
 
 	@Bean
 	SolrContainer solr() {
-		String solrImage = System.getProperty("solr.test.image");
+		String solrImage = System.getProperty("solr.test.image", "solr:9.9-slim");
 		return new SolrContainer(DockerImageName.parse(solrImage));
 	}
 
diff --git a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceDirectTest.java b/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceDirectTest.java
deleted file mode 100644
index 4d57b34..0000000
--- a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceDirectTest.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.mcp.server.indexing;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.response.UpdateResponse;
-import org.apache.solr.common.SolrInputDocument;
-import org.apache.solr.mcp.server.indexing.documentcreator.*;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-@ExtendWith(MockitoExtension.class)
-class IndexingServiceDirectTest {
-
-	@Mock
-	private SolrClient solrClient;
-
-	@Mock
-	private UpdateResponse updateResponse;
-
-	private IndexingService indexingService;
-	private IndexingDocumentCreator indexingDocumentCreator;
-
-	@BeforeEach
-	void setUp() {
-		indexingDocumentCreator = new IndexingDocumentCreator(new XmlDocumentCreator(), new CsvDocumentCreator(),
-				new JsonDocumentCreator());
-		indexingService = new IndexingService(solrClient, indexingDocumentCreator);
-	}
-
-	@Test
-	void testBatchIndexingErrorHandling() throws Exception {
-		// Create a list of test documents
-		List<SolrInputDocument> documents = new ArrayList<>();
-		for (int i = 0; i < 10; i++) {
-			SolrInputDocument doc = new SolrInputDocument();
-			doc.addField("id", "test" + i);
-			doc.addField("title", "Test Document " + i);
-			documents.add(doc);
-		}
-
-		// Mock behavior: Batch add fails, but individual adds succeed
-		when(solrClient.add(anyString(), anyList())).thenThrow(new RuntimeException("Batch indexing failed"));
-
-		// Individual document adds should succeed
-		when(solrClient.add(anyString(), any(SolrInputDocument.class))).thenReturn(updateResponse);
-
-		// Call the method under test
-		int successCount = indexingService.indexDocuments("test_collection", documents);
-
-		// Verify the results
-		assertEquals(10, successCount, "All documents should be successfully indexed individually");
-
-		// Verify that batch add was attempted once
-		verify(solrClient, times(1)).add(eq("test_collection"), anyList());
-
-		// Verify that individual adds were attempted for each document
-		verify(solrClient, times(10)).add(eq("test_collection"), any(SolrInputDocument.class));
-
-		// Verify that commit was called
-		verify(solrClient, times(1)).commit("test_collection");
-	}
-
-	@Test
-	void testBatchIndexingPartialFailure() throws Exception {
-		// Create a list of test documents
-		List<SolrInputDocument> documents = new ArrayList<>();
-		for (int i = 0; i < 10; i++) {
-			SolrInputDocument doc = new SolrInputDocument();
-			doc.addField("id", "test" + i);
-			doc.addField("title", "Test Document " + i);
-			documents.add(doc);
-		}
-
-		// Mock behavior: Batch add fails
-		when(solrClient.add(anyString(), anyList())).thenThrow(new RuntimeException("Batch indexing failed"));
-
-		// Even-numbered documents succeed, odd-numbered documents fail
-		for (int i = 0; i < 10; i++) {
-			if (i % 2 == 0) {
-				when(solrClient.add("test_collection", documents.get(i))).thenReturn(updateResponse);
-			} else {
-				when(solrClient.add("test_collection", documents.get(i)))
-						.thenThrow(new RuntimeException("Document " + i + " indexing failed"));
-			}
-		}
-
-		// Call the method under test
-		int successCount = indexingService.indexDocuments("test_collection", documents);
-
-		// Verify the results - only even-numbered documents should succeed
-		assertEquals(5, successCount, "Only half of the documents should be successfully indexed");
-
-		// Verify that batch add was attempted once
-		verify(solrClient, times(1)).add(eq("test_collection"), anyList());
-
-		// Verify that individual adds were attempted for each document
-		verify(solrClient, times(10)).add(eq("test_collection"), any(SolrInputDocument.class));
-
-		// Verify that commit was called
-		verify(solrClient, times(1)).commit("test_collection");
-	}
-
-	@Test
-	void testIndexJsonDocumentsWithJsonString() throws Exception {
-		// Test JSON string with multiple documents
-		String json = """
-				[
-				  {
-				    "id": "test001",
-				    "title": "Test Document 1",
-				    "content": "This is test content 1"
-				  },
-				  {
-				    "id": "test002",
-				    "title": "Test Document 2",
-				    "content": "This is test content 2"
-				  }
-				]
-				""";
-
-		// Create a spy on the indexingDocumentCreator and inject it into a new
-		// IndexingService
-		IndexingDocumentCreator indexingDocumentCreatorSpy = spy(indexingDocumentCreator);
-		IndexingService indexingServiceWithSpy = new IndexingService(solrClient, indexingDocumentCreatorSpy);
-		IndexingService indexingServiceSpy = spy(indexingServiceWithSpy);
-
-		// Create mock documents that would be returned by createSchemalessDocuments
-		List<SolrInputDocument> mockDocuments = new ArrayList<>();
-		SolrInputDocument doc1 = new SolrInputDocument();
-		doc1.addField("id", "test001");
-		doc1.addField("title", "Test Document 1");
-		doc1.addField("content", "This is test content 1");
-
-		SolrInputDocument doc2 = new SolrInputDocument();
-		doc2.addField("id", "test002");
-		doc2.addField("title", "Test Document 2");
-		doc2.addField("content", "This is test content 2");
-
-		mockDocuments.add(doc1);
-		mockDocuments.add(doc2);
-
-		// Mock the createSchemalessDocuments method to return our mock documents
-		doReturn(mockDocuments).when(indexingDocumentCreatorSpy).createSchemalessDocumentsFromJson(json);
-
-		// Mock the indexDocuments method that takes a collection and list of documents
-		doReturn(2).when(indexingServiceSpy).indexDocuments(anyString(), anyList());
-
-		// Call the method under test
-		indexingServiceSpy.indexJsonDocuments("test_collection", json);
-
-		// Verify that createSchemalessDocuments was called with the JSON string
-		verify(indexingDocumentCreatorSpy, times(1)).createSchemalessDocumentsFromJson(json);
-
-		// Verify that indexDocuments was called with the collection name and the
-		// documents
-		verify(indexingServiceSpy, times(1)).indexDocuments("test_collection", mockDocuments);
-	}
-
-	@Test
-	void testIndexJsonDocumentsWithJsonStringErrorHandling() throws Exception {
-		// Test JSON string with invalid format
-		String invalidJson = "{ This is not valid JSON }";
-
-		// Create a spy on the indexingDocumentCreator and inject it into a new
-		// IndexingService
-		IndexingDocumentCreator indexingDocumentCreatorSpy = spy(indexingDocumentCreator);
-		IndexingService indexingServiceWithSpy = new IndexingService(solrClient, indexingDocumentCreatorSpy);
-		IndexingService indexingServiceSpy = spy(indexingServiceWithSpy);
-
-		// Mock the createSchemalessDocuments method to throw an exception
-		doThrow(new DocumentProcessingException("Invalid JSON")).when(indexingDocumentCreatorSpy)
-				.createSchemalessDocumentsFromJson(invalidJson);
-
-		// Call the method under test and verify it throws an exception
-		DocumentProcessingException exception = assertThrows(DocumentProcessingException.class, () -> {
-			indexingServiceSpy.indexJsonDocuments("test_collection", invalidJson);
-		});
-
-		// Verify the exception message
-		assertTrue(exception.getMessage().contains("Invalid JSON"));
-
-		// Verify that createSchemalessDocuments was called
-		verify(indexingDocumentCreatorSpy, times(1)).createSchemalessDocumentsFromJson(invalidJson);
-
-		// Verify that indexDocuments with documents was not called
-		verify(indexingServiceSpy, never()).indexDocuments(anyString(), anyList());
-	}
-}
diff --git a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java b/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceIntegrationTest.java
similarity index 66%
copy from src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java
copy to src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceIntegrationTest.java
index c0bec69..bb7e586 100644
--- a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java
+++ b/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceIntegrationTest.java
@@ -17,16 +17,10 @@
 package org.apache.solr.mcp.server.indexing;
 
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.mcp.server.TestcontainersConfiguration;
@@ -37,22 +31,23 @@ import org.apache.solr.mcp.server.indexing.documentcreator.XmlDocumentCreator;
 import org.apache.solr.mcp.server.search.SearchResponse;
 import org.apache.solr.mcp.server.search.SearchService;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
+import org.junit.jupiter.api.condition.DisabledInNativeImage;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.context.annotation.Import;
 import org.testcontainers.containers.SolrContainer;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
+/**
+ * Integration tests for IndexingService using a real Solr instance via
+ * Testcontainers.
+ */
 @SpringBootTest
 @Import(TestcontainersConfiguration.class)
 @Testcontainers(disabledWithoutDocker = true)
-class IndexingServiceTest {
+@DisabledInNativeImage
+class IndexingServiceIntegrationTest {
 
 	private static boolean initialized = false;
 
@@ -758,289 +753,3 @@ class IndexingServiceTest {
 		assertEquals("Value 7", doc.getFieldValue("multiple_underscores"));
 	}
 }
-
-@Nested
-@ExtendWith(MockitoExtension.class)
-class UnitTests {
-
-	@Mock
-	private SolrClient solrClient;
-
-	@Mock
-	private IndexingDocumentCreator indexingDocumentCreator;
-
-	private IndexingService indexingService;
-
-	@BeforeEach
-	void setUp() {
-		indexingService = new IndexingService(solrClient, indexingDocumentCreator);
-	}
-
-	@Test
-	void constructor_ShouldInitializeWithDependencies() {
-		assertNotNull(indexingService);
-	}
-
-	@Test
-	void indexJsonDocuments_WithValidJson_ShouldIndexDocuments() throws Exception {
-		String json = "[{\"id\":\"1\",\"title\":\"Test\"}]";
-		List<SolrInputDocument> mockDocs = createMockDocuments(1);
-		when(indexingDocumentCreator.createSchemalessDocumentsFromJson(json)).thenReturn(mockDocs);
-		when(solrClient.add(eq("test_collection"), any(Collection.class))).thenReturn(null);
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		indexingService.indexJsonDocuments("test_collection", json);
-
-		verify(indexingDocumentCreator).createSchemalessDocumentsFromJson(json);
-		verify(solrClient).add(eq("test_collection"), any(Collection.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexJsonDocuments_WhenDocumentCreatorThrowsException_ShouldPropagateException() throws Exception {
-		String invalidJson = "not valid json";
-		when(indexingDocumentCreator.createSchemalessDocumentsFromJson(invalidJson)).thenThrow(
-				new org.apache.solr.mcp.server.indexing.documentcreator.DocumentProcessingException("Invalid JSON"));
-
-		assertThrows(org.apache.solr.mcp.server.indexing.documentcreator.DocumentProcessingException.class, () -> {
-			indexingService.indexJsonDocuments("test_collection", invalidJson);
-		});
-		verify(solrClient, never()).add(anyString(), any(Collection.class));
-		verify(solrClient, never()).commit(anyString());
-	}
-
-	@Test
-	void indexCsvDocuments_WithValidCsv_ShouldIndexDocuments() throws Exception {
-		String csv = "id,title\n1,Test\n2,Test2";
-		List<SolrInputDocument> mockDocs = createMockDocuments(2);
-		when(indexingDocumentCreator.createSchemalessDocumentsFromCsv(csv)).thenReturn(mockDocs);
-		when(solrClient.add(eq("test_collection"), any(Collection.class))).thenReturn(null);
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		indexingService.indexCsvDocuments("test_collection", csv);
-
-		verify(indexingDocumentCreator).createSchemalessDocumentsFromCsv(csv);
-		verify(solrClient).add(eq("test_collection"), any(Collection.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexCsvDocuments_WhenDocumentCreatorThrowsException_ShouldPropagateException() throws Exception {
-		String invalidCsv = "malformed csv data";
-		when(indexingDocumentCreator.createSchemalessDocumentsFromCsv(invalidCsv)).thenThrow(
-				new org.apache.solr.mcp.server.indexing.documentcreator.DocumentProcessingException("Invalid CSV"));
-
-		assertThrows(org.apache.solr.mcp.server.indexing.documentcreator.DocumentProcessingException.class, () -> {
-			indexingService.indexCsvDocuments("test_collection", invalidCsv);
-		});
-		verify(solrClient, never()).add(anyString(), any(Collection.class));
-		verify(solrClient, never()).commit(anyString());
-	}
-
-	@Test
-	void indexXmlDocuments_WithValidXml_ShouldIndexDocuments() throws Exception {
-		String xml = "<documents><doc><id>1</id><title>Test</title></doc></documents>";
-		List<SolrInputDocument> mockDocs = createMockDocuments(1);
-		when(indexingDocumentCreator.createSchemalessDocumentsFromXml(xml)).thenReturn(mockDocs);
-		when(solrClient.add(eq("test_collection"), any(Collection.class))).thenReturn(null);
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		indexingService.indexXmlDocuments("test_collection", xml);
-
-		verify(indexingDocumentCreator).createSchemalessDocumentsFromXml(xml);
-		verify(solrClient).add(eq("test_collection"), any(Collection.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexXmlDocuments_WhenParserConfigurationFails_ShouldPropagateException() throws Exception {
-		String xml = "<invalid>xml</invalid>";
-		when(indexingDocumentCreator.createSchemalessDocumentsFromXml(xml)).thenThrow(
-				new org.apache.solr.mcp.server.indexing.documentcreator.DocumentProcessingException("Parser error"));
-
-		assertThrows(org.apache.solr.mcp.server.indexing.documentcreator.DocumentProcessingException.class, () -> {
-			indexingService.indexXmlDocuments("test_collection", xml);
-		});
-		verify(solrClient, never()).add(anyString(), any(Collection.class));
-		verify(solrClient, never()).commit(anyString());
-	}
-
-	@Test
-	void indexXmlDocuments_WhenSaxExceptionOccurs_ShouldPropagateException() throws Exception {
-		String xml = "<malformed><unclosed>";
-		when(indexingDocumentCreator.createSchemalessDocumentsFromXml(xml))
-				.thenThrow(new org.apache.solr.mcp.server.indexing.documentcreator.DocumentProcessingException(
-						"SAX parsing error"));
-
-		assertThrows(org.apache.solr.mcp.server.indexing.documentcreator.DocumentProcessingException.class, () -> {
-			indexingService.indexXmlDocuments("test_collection", xml);
-		});
-		verify(solrClient, never()).add(anyString(), any(Collection.class));
-		verify(solrClient, never()).commit(anyString());
-	}
-
-	@Test
-	void indexDocuments_WithSmallBatch_ShouldIndexSuccessfully() throws Exception {
-		List<SolrInputDocument> docs = createMockDocuments(5);
-		when(solrClient.add(eq("test_collection"), any(Collection.class))).thenReturn(null);
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		int result = indexingService.indexDocuments("test_collection", docs);
-
-		assertEquals(5, result);
-		verify(solrClient).add(eq("test_collection"), any(Collection.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexDocuments_WithLargeBatch_ShouldProcessInBatches() throws Exception {
-		List<SolrInputDocument> docs = createMockDocuments(2500);
-		when(solrClient.add(eq("test_collection"), any(Collection.class))).thenReturn(null);
-		when(solrClient.commit(eq("test_collection"))).thenReturn(null);
-
-		int result = indexingService.indexDocuments("test_collection", docs);
-
-		assertEquals(2500, result);
-		verify(solrClient, times(3)).add(eq("test_collection"), any(Collection.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexDocuments_WhenBatchFails_ShouldRetryIndividually() throws Exception {
-		List<SolrInputDocument> docs = createMockDocuments(3);
-
-		when(solrClient.add(eq("test_collection"), any(List.class))).thenThrow(new SolrServerException("Batch error"));
-
-		when(solrClient.add(eq("test_collection"), any(SolrInputDocument.class))).thenReturn(null);
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		int result = indexingService.indexDocuments("test_collection", docs);
-
-		assertEquals(3, result);
-		verify(solrClient).add(eq("test_collection"), any(Collection.class));
-		verify(solrClient, times(3)).add(eq("test_collection"), any(SolrInputDocument.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexDocuments_WhenSomeIndividualDocumentsFail_ShouldIndexSuccessfulOnes() throws Exception {
-		List<SolrInputDocument> docs = createMockDocuments(3);
-
-		when(solrClient.add(eq("test_collection"), any(List.class))).thenThrow(new SolrServerException("Batch error"));
-
-		when(solrClient.add(eq("test_collection"), any(SolrInputDocument.class))).thenReturn(null)
-				.thenThrow(new SolrServerException("Document error")).thenReturn(null);
-
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		int result = indexingService.indexDocuments("test_collection", docs);
-
-		assertEquals(2, result);
-		verify(solrClient).add(eq("test_collection"), any(Collection.class));
-		verify(solrClient, times(3)).add(eq("test_collection"), any(SolrInputDocument.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexDocuments_WithEmptyList_ShouldStillCommit() throws Exception {
-		List<SolrInputDocument> emptyDocs = new ArrayList<>();
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		int result = indexingService.indexDocuments("test_collection", emptyDocs);
-
-		assertEquals(0, result);
-		verify(solrClient, never()).add(anyString(), any(List.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexDocuments_WhenCommitFails_ShouldPropagateException() throws Exception {
-		List<SolrInputDocument> docs = createMockDocuments(2);
-		when(solrClient.add(eq("test_collection"), any(Collection.class))).thenReturn(null);
-		when(solrClient.commit("test_collection")).thenThrow(new IOException("Commit failed"));
-
-		assertThrows(IOException.class, () -> {
-			indexingService.indexDocuments("test_collection", docs);
-		});
-		verify(solrClient).add(eq("test_collection"), any(Collection.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexDocuments_ShouldBatchCorrectly() throws Exception {
-		List<SolrInputDocument> docs = createMockDocuments(1000);
-		when(solrClient.add(eq("test_collection"), any(Collection.class))).thenReturn(null);
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		int result = indexingService.indexDocuments("test_collection", docs);
-
-		assertEquals(1000, result);
-
-		ArgumentCaptor<Collection<SolrInputDocument>> captor = ArgumentCaptor.forClass(Collection.class);
-		verify(solrClient).add(eq("test_collection"), captor.capture());
-		assertEquals(1000, captor.getValue().size());
-		verify(solrClient).commit("test_collection");
-	}
-
-	@Test
-	void indexJsonDocuments_WhenSolrClientThrowsException_ShouldPropagateException() throws Exception {
-		String json = "[{\"id\":\"1\"}]";
-		List<SolrInputDocument> mockDocs = createMockDocuments(1);
-		when(indexingDocumentCreator.createSchemalessDocumentsFromJson(json)).thenReturn(mockDocs);
-		when(solrClient.add(eq("test_collection"), any(List.class)))
-				.thenThrow(new SolrServerException("Solr connection error"));
-		when(solrClient.add(eq("test_collection"), any(SolrInputDocument.class)))
-				.thenThrow(new SolrServerException("Solr connection error"));
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		indexingService.indexJsonDocuments("test_collection", json);
-
-		verify(solrClient).add(eq("test_collection"), any(List.class));
-		verify(solrClient).add(eq("test_collection"), any(SolrInputDocument.class));
-	}
-
-	@Test
-	void indexCsvDocuments_WhenSolrClientThrowsIOException_ShouldPropagateException() throws Exception {
-		String csv = "id,title\n1,Test";
-		List<SolrInputDocument> mockDocs = createMockDocuments(1);
-		when(indexingDocumentCreator.createSchemalessDocumentsFromCsv(csv)).thenReturn(mockDocs);
-		when(solrClient.add(eq("test_collection"), any(List.class))).thenThrow(new IOException("Network error"));
-		when(solrClient.add(eq("test_collection"), any(SolrInputDocument.class)))
-				.thenThrow(new IOException("Network error"));
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		indexingService.indexCsvDocuments("test_collection", csv);
-
-		verify(solrClient).add(eq("test_collection"), any(List.class));
-		verify(solrClient).add(eq("test_collection"), any(SolrInputDocument.class));
-	}
-
-	@Test
-	void indexDocuments_WithRuntimeException_ShouldRetryIndividually() throws Exception {
-		List<SolrInputDocument> docs = createMockDocuments(2);
-
-		when(solrClient.add(eq("test_collection"), any(List.class)))
-				.thenThrow(new RuntimeException("Unexpected error"));
-
-		when(solrClient.add(eq("test_collection"), any(SolrInputDocument.class))).thenReturn(null);
-		when(solrClient.commit("test_collection")).thenReturn(null);
-
-		int result = indexingService.indexDocuments("test_collection", docs);
-
-		assertEquals(2, result);
-		verify(solrClient).add(eq("test_collection"), any(Collection.class));
-		verify(solrClient, times(2)).add(eq("test_collection"), any(SolrInputDocument.class));
-		verify(solrClient).commit("test_collection");
-	}
-
-	private List<SolrInputDocument> createMockDocuments(int count) {
-		List<SolrInputDocument> docs = new ArrayList<>();
-		for (int i = 0; i < count; i++) {
-			SolrInputDocument doc = new SolrInputDocument();
-			doc.addField("id", "doc" + i);
-			doc.addField("title", "Document " + i);
-			docs.add(doc);
-		}
-		return docs;
-	}
-}
diff --git a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java b/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java
index c0bec69..186b543 100644
--- a/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java
+++ b/src/test/java/org/apache/solr/mcp/server/indexing/IndexingServiceTest.java
@@ -24,744 +24,24 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.common.SolrInputDocument;
-import org.apache.solr.mcp.server.TestcontainersConfiguration;
-import org.apache.solr.mcp.server.indexing.documentcreator.CsvDocumentCreator;
 import org.apache.solr.mcp.server.indexing.documentcreator.IndexingDocumentCreator;
-import org.apache.solr.mcp.server.indexing.documentcreator.JsonDocumentCreator;
-import org.apache.solr.mcp.server.indexing.documentcreator.XmlDocumentCreator;
-import org.apache.solr.mcp.server.search.SearchResponse;
-import org.apache.solr.mcp.server.search.SearchService;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledInNativeImage;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.context.annotation.Import;
-import org.testcontainers.containers.SolrContainer;
-import org.testcontainers.junit.jupiter.Testcontainers;
 
-@SpringBootTest
-@Import(TestcontainersConfiguration.class)
-@Testcontainers(disabledWithoutDocker = true)
-class IndexingServiceTest {
-
-	private static boolean initialized = false;
-
-	private static final String COLLECTION_NAME = "indexing_test_" + System.currentTimeMillis();
-	@Autowired
-	private SolrContainer solrContainer;
-	@Autowired
-	private IndexingDocumentCreator indexingDocumentCreator;
-	@Autowired
-	private IndexingService indexingService;
-	@Autowired
-	private SearchService searchService;
-	@Autowired
-	private SolrClient solrClient;
-
-	@BeforeEach
-	void setUp() throws Exception {
-
-		// Create processor instances and wire them manually since this is not a Spring
-		// Boot test
-		XmlDocumentCreator xmlDocumentCreator = new XmlDocumentCreator();
-		CsvDocumentCreator csvDocumentCreator = new CsvDocumentCreator();
-		JsonDocumentCreator jsonDocumentCreator = new JsonDocumentCreator();
-
-		indexingDocumentCreator = new IndexingDocumentCreator(xmlDocumentCreator, csvDocumentCreator,
-				jsonDocumentCreator);
-
-		indexingService = new IndexingService(solrClient, indexingDocumentCreator);
-		searchService = new SearchService(solrClient);
-
-		if (!initialized) {
-			// Create collection
-			CollectionAdminRequest.Create createRequest = CollectionAdminRequest.createCollection(COLLECTION_NAME,
-					"_default", 1, 1);
-			createRequest.process(solrClient);
-			initialized = true;
-		}
-	}
-
-	@Test
-	void testCreateSchemalessDocumentsFromJson() throws Exception {
-		// Test JSON string
-		String json = """
-				[
-				  {
-				    "id": "test001",
-				    "cat": ["book"],
-				    "name": ["Test Book 1"],
-				    "price": [9.99],
-				    "inStock": [true],
-				    "author": ["Test Author"],
-				    "series_t": "Test Series",
-				    "sequence_i": 1,
-				    "genre_s": "test"
-				  }
-				]
-				""";
-
-		// Create documents
-		List<SolrInputDocument> documents = indexingDocumentCreator.createSchemalessDocumentsFromJson(json);
-
-		// Verify documents were created correctly
-		assertNotNull(documents);
-		assertEquals(1, documents.size());
-
-		SolrInputDocument doc = documents.getFirst();
-		assertEquals("test001", doc.getFieldValue("id"));
-
-		// Check field values - they might be stored directly or as collections
-		Object nameValue = doc.getFieldValue("name");
-		if (nameValue instanceof List) {
-			assertEquals("Test Book 1", ((List<?>) nameValue).getFirst());
-		} else {
-			assertEquals("Test Book 1", nameValue);
-		}
-
-		Object priceValue = doc.getFieldValue("price");
-		if (priceValue instanceof List) {
-			assertEquals(9.99, ((List<?>) priceValue).getFirst());
-		} else {
-			assertEquals(9.99, priceValue);
-		}
-
-		Object inStockValue = doc.getFieldValue("inStock");
-		// Check if inStock field exists
-		if (inStockValue != null) {
-			if (inStockValue instanceof List) {
-				assertEquals(true, ((List<?>) inStockValue).getFirst());
-			} else {
-				assertEquals(true, inStockValue);
-			}
-		} else {
-			// If inStock is not present in the document, we'll skip this assertion
-			// Removed debug print statement
-		}
-
-		Object authorValue = doc.getFieldValue("author");
-		if (authorValue instanceof List) {
-			assertEquals("Test Author", ((List<?>) authorValue).getFirst());
-		} else {
-			assertEquals("Test Author", authorValue);
-		}
-
-		assertEquals("Test Series", doc.getFieldValue("series_t"));
-		assertEquals(1, doc.getFieldValue("sequence_i"));
-		assertEquals("test", doc.getFieldValue("genre_s"));
-	}
-
-	@Test
-	void testIndexJsonDocuments() throws Exception {
-
-		// Test JSON string with multiple documents
-		String json = """
-				[
-				  {
-				    "id": "test002",
-				    "cat": ["book"],
-				    "name": ["Test Book 2"],
-				    "price": [19.99],
-				    "inStock": [true],
-				    "author": ["Test Author 2"],
-				    "genre_s": "scifi"
-				  },
-				  {
-				    "id": "test003",
-				    "cat": ["book"],
-				    "name": ["Test Book 3"],
-				    "price": [29.99],
-				    "inStock": [false],
-				    "author": ["Test Author 3"],
-				    "genre_s": "fantasy"
-				  }
-				]
-				""";
-
-		// Index documents
-		indexingService.indexJsonDocuments(COLLECTION_NAME, json);
-
-		// Verify documents were indexed by searching for them
-		SearchResponse result = searchService.search(COLLECTION_NAME, "id:test002 OR id:test003", null, null, null,
-				null, null);
-
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertEquals(2, documents.size());
-
-		// Verify specific document fields
-		boolean foundBook2 = false;
-		boolean foundBook3 = false;
-
-		for (Map<String, Object> book : documents) {
-			// Get ID and handle both String and List cases
-			Object idValue = book.get("id");
-			String id;
-			if (idValue instanceof List) {
-				id = (String) ((List<?>) idValue).getFirst();
-			} else {
-				id = (String) idValue;
-			}
-
-			if (id.equals("test002")) {
-				foundBook2 = true;
-
-				// Handle name field
-				Object nameValue = book.get("name");
-				if (nameValue instanceof List) {
-					assertEquals("Test Book 2", ((List<?>) nameValue).getFirst());
-				} else {
-					assertEquals("Test Book 2", nameValue);
-				}
-
-				// Handle author field
-				Object authorValue = book.get("author");
-				if (authorValue instanceof List) {
-					assertEquals("Test Author 2", ((List<?>) authorValue).getFirst());
-				} else {
-					assertEquals("Test Author 2", authorValue);
-				}
-
-				// Handle genre field
-				Object genreValue = book.get("genre_s");
-				if (genreValue instanceof List) {
-					assertEquals("scifi", ((List<?>) genreValue).getFirst());
-				} else {
-					assertEquals("scifi", genreValue);
-				}
-			} else if (id.equals("test003")) {
-				foundBook3 = true;
-
-				// Handle name field
-				Object nameValue = book.get("name");
-				if (nameValue instanceof List) {
-					assertEquals("Test Book 3", ((List<?>) nameValue).getFirst());
-				} else {
-					assertEquals("Test Book 3", nameValue);
-				}
-
-				// Handle author field
-				Object authorValue = book.get("author");
-				if (authorValue instanceof List) {
-					assertEquals("Test Author 3", ((List<?>) authorValue).getFirst());
-				} else {
-					assertEquals("Test Author 3", authorValue);
-				}
-
-				// Handle genre field
-				Object genreValue = book.get("genre_s");
-				if (genreValue instanceof List) {
-					assertEquals("fantasy", ((List<?>) genreValue).getFirst());
-				} else {
-					assertEquals("fantasy", genreValue);
-				}
-			}
-		}
-
-		assertTrue(foundBook2, "Book 2 should be found in search results");
-		assertTrue(foundBook3, "Book 3 should be found in search results");
-	}
-
-	@Test
-	void testIndexJsonDocumentsWithNestedObjects() throws Exception {
-
-		// Test JSON string with nested objects
-		String json = """
-				[
-				  {
-				    "id": "test004",
-				    "cat": ["book"],
-				    "name": ["Test Book 4"],
-				    "price": [39.99],
-				    "details": {
-				      "publisher": "Test Publisher",
-				      "year": 2023,
-				      "edition": 1
-				    },
-				    "author": ["Test Author 4"]
-				  }
-				]
-				""";
-
-		// Index documents
-		indexingService.indexJsonDocuments(COLLECTION_NAME, json);
-
-		// Verify documents were indexed by searching for them
-		SearchResponse result = searchService.search(COLLECTION_NAME, "id:test004", null, null, null, null, null);
-
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertEquals(1, documents.size());
-
-		Map<String, Object> book = documents.getFirst();
-
-		// Handle ID field
-		Object idValue = book.get("id");
-		if (idValue instanceof List) {
-			assertEquals("test004", ((List<?>) idValue).getFirst());
-		} else {
-			assertEquals("test004", idValue);
-		}
-
-		// Handle name field
-		Object nameValue = book.get("name");
-		if (nameValue instanceof List) {
-			assertEquals("Test Book 4", ((List<?>) nameValue).getFirst());
-		} else {
-			assertEquals("Test Book 4", nameValue);
-		}
-
-		// Check that nested fields were flattened with underscore prefix
-		assertNotNull(book.get("details_publisher"));
-		Object publisherValue = book.get("details_publisher");
-		if (publisherValue instanceof List) {
-			assertEquals("Test Publisher", ((List<?>) publisherValue).getFirst());
-		} else {
-			assertEquals("Test Publisher", publisherValue);
-		}
-
-		assertNotNull(book.get("details_year"));
-		Object yearValue = book.get("details_year");
-		if (yearValue instanceof List) {
-			assertEquals(2023, ((Number) ((List<?>) yearValue).getFirst()).intValue());
-		} else if (yearValue instanceof Number) {
-			assertEquals(2023, ((Number) yearValue).intValue());
-		} else {
-			assertEquals("2023", yearValue.toString());
-		}
-	}
-
-	@Test
-	void testSanitizeFieldName() throws Exception {
-
-		// Test JSON string with field names that need sanitizing
-		String json = """
-				[
-				  {
-				    "id": "test005",
-				    "invalid-field": "Value with hyphen",
-				    "another.invalid": "Value with dot",
-				    "UPPERCASE": "Value with uppercase",
-				    "multiple__underscores": "Value with multiple underscores"
-				  }
-				]
-				""";
-
-		// Index documents
-		indexingService.indexJsonDocuments(COLLECTION_NAME, json);
-
-		// Verify documents were indexed with sanitized field names
-		SearchResponse result = searchService.search(COLLECTION_NAME, "id:test005", null, null, null, null, null);
-
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertEquals(1, documents.size());
-
-		Map<String, Object> doc = documents.getFirst();
-
-		// Check that field names were sanitized
-		assertNotNull(doc.get("invalid_field"));
-		Object invalidFieldValue = doc.get("invalid_field");
-		if (invalidFieldValue instanceof List) {
-			assertEquals("Value with hyphen", ((List<?>) invalidFieldValue).getFirst());
-		} else {
-			assertEquals("Value with hyphen", invalidFieldValue);
-		}
-
-		assertNotNull(doc.get("another_invalid"));
-		Object anotherInvalidValue = doc.get("another_invalid");
-		if (anotherInvalidValue instanceof List) {
-			assertEquals("Value with dot", ((List<?>) anotherInvalidValue).getFirst());
-		} else {
-			assertEquals("Value with dot", anotherInvalidValue);
-		}
-
-		// Should be lowercase
-		assertNotNull(doc.get("uppercase"));
-		Object uppercaseValue = doc.get("uppercase");
-		if (uppercaseValue instanceof List) {
-			assertEquals("Value with uppercase", ((List<?>) uppercaseValue).getFirst());
-		} else {
-			assertEquals("Value with uppercase", uppercaseValue);
-		}
-
-		// Multiple underscores should be collapsed
-		assertNotNull(doc.get("multiple_underscores"));
-		Object multipleUnderscoresValue = doc.get("multiple_underscores");
-		if (multipleUnderscoresValue instanceof List) {
-			assertEquals("Value with multiple underscores", ((List<?>) multipleUnderscoresValue).getFirst());
-		} else {
-			assertEquals("Value with multiple underscores", multipleUnderscoresValue);
-		}
-	}
-
-	@Test
-	void testDeeplyNestedJsonStructures() throws Exception {
-
-		// Test JSON string with deeply nested objects (3+ levels)
-		String json = """
-				[
-				  {
-				    "id": "nested001",
-				    "title": "Deeply nested document",
-				    "metadata": {
-				      "publication": {
-				        "publisher": {
-				          "name": "Deep Nest Publishing",
-				          "location": {
-				            "city": "Nestville",
-				            "country": "Nestland",
-				            "coordinates": {
-				              "latitude": 42.123,
-				              "longitude": -71.456
-				            }
-				          }
-				        },
-				        "year": 2023,
-				        "edition": {
-				          "number": 1,
-				          "type": "First Edition",
-				          "notes": {
-				            "condition": "New",
-				            "availability": "Limited"
-				          }
-				        }
-				      },
-				      "classification": {
-				        "primary": "Test",
-				        "secondary": {
-				          "category": "Nested",
-				          "subcategory": "Deep"
-				        }
-				      }
-				    }
-				  }
-				]
-				""";
-
-		// Index documents
-		indexingService.indexJsonDocuments(COLLECTION_NAME, json);
-
-		// Verify documents were indexed by searching for them
-		SearchResponse result = searchService.search(COLLECTION_NAME, "id:nested001", null, null, null, null, null);
-
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertEquals(1, documents.size());
-
-		Map<String, Object> doc = documents.getFirst();
-
-		// Check that deeply nested fields were flattened with underscore prefix
-		// Level 1
-		assertNotNull(doc.get("metadata_publication_publisher_name"));
-		assertEquals("Deep Nest Publishing", getFieldValue(doc, "metadata_publication_publisher_name"));
-
-		// Level 2
-		assertNotNull(doc.get("metadata_publication_publisher_location_city"));
-		assertEquals("Nestville", getFieldValue(doc, "metadata_publication_publisher_location_city"));
-
-		// Level 3
-		assertNotNull(doc.get("metadata_publication_publisher_location_coordinates_latitude"));
-		assertEquals(42.123,
-				((Number) getFieldValue(doc, "metadata_publication_publisher_location_coordinates_latitude"))
-						.doubleValue(),
-				0.001);
-
-		// Check other branches of the nested structure
-		assertNotNull(doc.get("metadata_publication_edition_notes_condition"));
-		assertEquals("New", getFieldValue(doc, "metadata_publication_edition_notes_condition"));
-
-		assertNotNull(doc.get("metadata_classification_secondary_subcategory"));
-		assertEquals("Deep", getFieldValue(doc, "metadata_classification_secondary_subcategory"));
-	}
-
-	private Object getFieldValue(Map<String, Object> doc, String fieldName) {
-		Object value = doc.get(fieldName);
-		if (value instanceof List) {
-			return ((List<?>) value).getFirst();
-		}
-		return value;
-	}
-
-	@Test
-	void testSpecialCharactersInFieldNames() throws Exception {
-
-		// Test JSON string with field names containing various special characters
-		String json = """
-				[
-				  {
-				    "id": "special_fields_001",
-				    "field@with@at": "Value with @ symbols",
-				    "field#with#hash": "Value with # symbols",
-				    "field$with$dollar": "Value with $ symbols",
-				    "field%with%percent": "Value with % symbols",
-				    "field^with^caret": "Value with ^ symbols",
-				    "field&with&ampersand": "Value with & symbols",
-				    "field*with*asterisk": "Value with * symbols",
-				    "field(with)parentheses": "Value with parentheses",
-				    "field[with]brackets": "Value with brackets",
-				    "field{with}braces": "Value with braces",
-				    "field+with+plus": "Value with + symbols",
-				    "field=with=equals": "Value with = symbols",
-				    "field:with:colon": "Value with : symbols",
-				    "field;with;semicolon": "Value with ; symbols",
-				    "field'with'quotes": "Value with ' symbols",
-				    "field\\"with\\"doublequotes": "Value with \\" symbols",
-				    "field<with>anglebrackets": "Value with angle brackets",
-				    "field,with,commas": "Value with , symbols",
-				    "field?with?question": "Value with ? symbols",
-				    "field/with/slashes": "Value with / symbols",
-				    "field\\\\with\\\\backslashes": "Value with \\\\ symbols",
-				    "field|with|pipes": "Value with | symbols",
-				    "field`with`backticks": "Value with ` symbols",
-				    "field~with~tildes": "Value with ~ symbols"
-				  }
-				]
-				""";
-
-		// Index documents
-		indexingService.indexJsonDocuments(COLLECTION_NAME, json);
-
-		// Verify documents were indexed by searching for them
-		SearchResponse result = searchService.search(COLLECTION_NAME, "id:special_fields_001", null, null, null, null,
-				null);
-
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertEquals(1, documents.size());
-
-		Map<String, Object> doc = documents.getFirst();
-
-		// Check that field names with special characters were sanitized
-		// All special characters should be replaced with underscores
-		assertNotNull(doc.get("field_with_at"));
-		assertEquals("Value with @ symbols", getFieldValue(doc, "field_with_at"));
-
-		assertNotNull(doc.get("field_with_hash"));
-		assertEquals("Value with # symbols", getFieldValue(doc, "field_with_hash"));
-
-		assertNotNull(doc.get("field_with_dollar"));
-		assertEquals("Value with $ symbols", getFieldValue(doc, "field_with_dollar"));
-
-		assertNotNull(doc.get("field_with_percent"));
-		assertEquals("Value with % symbols", getFieldValue(doc, "field_with_percent"));
-
-		assertNotNull(doc.get("field_with_caret"));
-		assertEquals("Value with ^ symbols", getFieldValue(doc, "field_with_caret"));
-
-		assertNotNull(doc.get("field_with_ampersand"));
-		assertEquals("Value with & symbols", getFieldValue(doc, "field_with_ampersand"));
-
-		assertNotNull(doc.get("field_with_asterisk"));
-		assertEquals("Value with * symbols", getFieldValue(doc, "field_with_asterisk"));
-
-		assertNotNull(doc.get("field_with_parentheses"));
-		assertEquals("Value with parentheses", getFieldValue(doc, "field_with_parentheses"));
-
-		assertNotNull(doc.get("field_with_brackets"));
-		assertEquals("Value with brackets", getFieldValue(doc, "field_with_brackets"));
-
-		assertNotNull(doc.get("field_with_braces"));
-		assertEquals("Value with braces", getFieldValue(doc, "field_with_braces"));
-	}
-
-	@Test
-	void testArraysOfObjects() throws Exception {
-
-		// Test JSON string with arrays of objects
-		String json = """
-				[
-				  {
-				    "id": "array_objects_001",
-				    "title": "Document with arrays of objects",
-				    "authors": [
-				      {
-				        "name": "Author One",
-				        "email": "author1@example.com",
-				        "affiliation": "University A"
-				      },
-				      {
-				        "name": "Author Two",
-				        "email": "author2@example.com",
-				        "affiliation": "University B"
-				      }
-				    ],
-				    "reviews": [
-				      {
-				        "reviewer": "Reviewer A",
-				        "rating": 4,
-				        "comments": "Good document"
-				      },
-				      {
-				        "reviewer": "Reviewer B",
-				        "rating": 5,
-				        "comments": "Excellent document"
-				      },
-				      {
-				        "reviewer": "Reviewer C",
-				        "rating": 3,
-				        "comments": "Average document"
-				      }
-				    ],
-				    "keywords": ["arrays", "objects", "testing"]
-				  }
-				]
-				""";
-
-		// Index documents
-		indexingService.indexJsonDocuments(COLLECTION_NAME, json);
-
-		// Verify documents were indexed by searching for them
-		SearchResponse result = searchService.search(COLLECTION_NAME, "id:array_objects_001", null, null, null, null,
-				null);
-
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertEquals(1, documents.size());
-
-		Map<String, Object> doc = documents.getFirst();
-
-		// Check that the document was indexed correctly
-		assertEquals("array_objects_001", getFieldValue(doc, "id"));
-		assertEquals("Document with arrays of objects", getFieldValue(doc, "title"));
-
-		// Check that the arrays of primitive values were indexed correctly
-		Object keywordsObj = doc.get("keywords");
-		if (keywordsObj instanceof List) {
-			List<?> keywords = (List<?>) keywordsObj;
-			assertEquals(3, keywords.size());
-			assertTrue(keywords.contains("arrays"));
-			assertTrue(keywords.contains("objects"));
-			assertTrue(keywords.contains("testing"));
-		}
-
-		// For arrays of objects, the IndexingService should flatten them with field
-		// names
-		// that include the array name and the object field name
-		// We can't directly access the array elements, but we can check if the
-		// flattened fields
-		// exist
-
-		// Check for flattened author fields
-		// Note: The current implementation in IndexingService.java doesn't handle
-		// arrays of objects
-		// in a way that preserves the array structure. It skips object items in arrays
-		// (line
-		// 68-70).
-		// This test is checking the current behavior, which may need improvement in the
-		// future.
-
-		// Check for flattened review fields
-		// Same note as above applies here
-	}
-
-	@Test
-	void testNonArrayJsonInput() throws Exception {
-		// Test JSON string that is not an array but a single object
-		String json = """
-				{
-				  "id": "single_object_001",
-				  "title": "Single Object Document",
-				  "author": "Test Author",
-				  "year": 2023
-				}
-				""";
-
-		// Create documents
-		List<SolrInputDocument> documents = indexingDocumentCreator.createSchemalessDocumentsFromJson(json);
-
-		// Verify no documents were created since input is not an array
-		assertNotNull(documents);
-		assertEquals(0, documents.size());
-	}
-
-	@Test
-	void testConvertJsonValueTypes() throws Exception {
-		// Test JSON with different value types
-		String json = """
-				[
-				  {
-				    "id": "value_types_001",
-				    "boolean_value": true,
-				    "int_value": 42,
-				    "double_value": 3.14159,
-				    "long_value": 9223372036854775807,
-				    "text_value": "This is a text value"
-				  }
-				]
-				""";
-
-		// Create documents
-		List<SolrInputDocument> documents = indexingDocumentCreator.createSchemalessDocumentsFromJson(json);
-
-		// Verify documents were created correctly
-		assertNotNull(documents);
-		assertEquals(1, documents.size());
-
-		SolrInputDocument doc = documents.getFirst();
-		assertEquals("value_types_001", doc.getFieldValue("id"));
-
-		// Verify each value type was converted correctly
-		assertEquals(true, doc.getFieldValue("boolean_value"));
-		assertEquals(42, doc.getFieldValue("int_value"));
-		assertEquals(3.14159, doc.getFieldValue("double_value"));
-		assertEquals(9223372036854775807L, doc.getFieldValue("long_value"));
-		assertEquals("This is a text value", doc.getFieldValue("text_value"));
-	}
-
-	@Test
-	void testDirectSanitizeFieldName() throws Exception {
-		// Test sanitizing field names directly
-		// Create a document with field names that need sanitizing
-		String json = """
-				[
-				  {
-				    "id": "field_names_001",
-				    "field-with-hyphens": "Value 1",
-				    "field.with.dots": "Value 2",
-				    "field with spaces": "Value 3",
-				    "UPPERCASE_FIELD": "Value 4",
-				    "__leading_underscores__": "Value 5",
-				    "trailing_underscores___": "Value 6",
-				    "multiple___underscores": "Value 7"
-				  }
-				]
-				""";
-
-		// Create documents
-		List<SolrInputDocument> documents = indexingDocumentCreator.createSchemalessDocumentsFromJson(json);
-
-		// Verify documents were created correctly
-		assertNotNull(documents);
-		assertEquals(1, documents.size());
-
-		SolrInputDocument doc = documents.getFirst();
-
-		// Verify field names were sanitized correctly
-		assertEquals("field_names_001", doc.getFieldValue("id"));
-		assertEquals("Value 1", doc.getFieldValue("field_with_hyphens"));
-		assertEquals("Value 2", doc.getFieldValue("field_with_dots"));
-		assertEquals("Value 3", doc.getFieldValue("field_with_spaces"));
-		assertEquals("Value 4", doc.getFieldValue("uppercase_field"));
-		assertEquals("Value 5", doc.getFieldValue("leading_underscores"));
-		assertEquals("Value 6", doc.getFieldValue("trailing_underscores"));
-		assertEquals("Value 7", doc.getFieldValue("multiple_underscores"));
-	}
-}
-
-@Nested
+/**
+ * Unit tests for IndexingService with mocked SolrClient.
+ */
 @ExtendWith(MockitoExtension.class)
-class UnitTests {
+@DisabledInNativeImage
+class IndexingServiceTest {
 
 	@Mock
 	private SolrClient solrClient;
diff --git a/src/test/java/org/apache/solr/mcp/server/search/SearchServiceDirectTest.java b/src/test/java/org/apache/solr/mcp/server/search/SearchServiceDirectTest.java
deleted file mode 100644
index ae38775..0000000
--- a/src/test/java/org/apache/solr/mcp/server/search/SearchServiceDirectTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.solr.mcp.server.search;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.client.solrj.request.SolrQuery;
-import org.apache.solr.client.solrj.response.FacetField;
-import org.apache.solr.client.solrj.response.QueryResponse;
-import org.apache.solr.common.SolrDocument;
-import org.apache.solr.common.SolrDocumentList;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-@ExtendWith(MockitoExtension.class)
-class SearchServiceDirectTest {
-
-	@Mock
-	private SolrClient solrClient;
-
-	@Mock
-	private QueryResponse queryResponse;
-
-	private SearchService searchService;
-
-	@BeforeEach
-	void setUp() {
-		searchService = new SearchService(solrClient);
-	}
-
-	@Test
-	void testBasicSearch() throws SolrServerException, IOException {
-		// Setup mock response
-		SolrDocumentList documents = new SolrDocumentList();
-		documents.setNumFound(2);
-		documents.setStart(0);
-		documents.setMaxScore(1.0f);
-
-		SolrDocument doc1 = new SolrDocument();
-		doc1.addField("id", "1");
-		doc1.addField("name", List.of("Book 1"));
-		doc1.addField("author", List.of("Author 1"));
-
-		SolrDocument doc2 = new SolrDocument();
-		doc2.addField("id", "2");
-		doc2.addField("name", List.of("Book 2"));
-		doc2.addField("author", List.of("Author 2"));
-
-		documents.add(doc1);
-		documents.add(doc2);
-
-		when(queryResponse.getResults()).thenReturn(documents);
-		when(solrClient.query(eq("books"), any(SolrQuery.class))).thenReturn(queryResponse);
-
-		// Test
-		SearchResponse result = searchService.search("books", null, null, null, null, null, null);
-
-		// Verify
-		assertNotNull(result);
-		assertEquals(2L, result.numFound());
-
-		List<Map<String, Object>> resultDocs = result.documents();
-		assertEquals(2, resultDocs.size());
-		assertEquals("1", resultDocs.getFirst().get("id"));
-		assertEquals("2", resultDocs.get(1).get("id"));
-	}
-
-	@Test
-	void testSearchWithFacets() throws SolrServerException, IOException {
-		// Setup mock response
-		SolrDocumentList documents = new SolrDocumentList();
-		documents.setNumFound(2);
-		documents.setStart(0);
-		documents.setMaxScore(1.0f);
-
-		SolrDocument doc1 = new SolrDocument();
-		doc1.addField("id", "1");
-		doc1.addField("genre_s", "fantasy");
-
-		SolrDocument doc2 = new SolrDocument();
-		doc2.addField("id", "2");
-		doc2.addField("genre_s", "scifi");
-
-		documents.add(doc1);
-		documents.add(doc2);
-
-		// Create facet fields
-		List<FacetField> facetFields = new ArrayList<>();
-		FacetField genreFacet = new FacetField("genre_s");
-		genreFacet.add("fantasy", 1);
-		genreFacet.add("scifi", 1);
-		facetFields.add(genreFacet);
-
-		when(queryResponse.getResults()).thenReturn(documents);
-		when(queryResponse.getFacetFields()).thenReturn(facetFields);
-		when(solrClient.query(eq("books"), any(SolrQuery.class))).thenReturn(queryResponse);
-
-		// Test
-		SearchResponse result = searchService.search("books", null, null, null, null, null, null);
-
-		// Verify
-		assertNotNull(result);
-		assertTrue(result.facets().containsKey("genre_s"));
-
-		Map<String, Long> genreFacets = result.facets().get("genre_s");
-		assertEquals(2, genreFacets.size());
-		assertEquals(1L, genreFacets.get("fantasy"));
-		assertEquals(1L, genreFacets.get("scifi"));
-	}
-
-	@Test
-	void testSearchWithEmptyResults() throws SolrServerException, IOException {
-		// Setup mock response with empty results
-		SolrDocumentList emptyDocuments = new SolrDocumentList();
-		emptyDocuments.setNumFound(0);
-		emptyDocuments.setStart(0);
-		emptyDocuments.setMaxScore(0.0f);
-
-		when(queryResponse.getResults()).thenReturn(emptyDocuments);
-		when(solrClient.query(eq("books"), any(SolrQuery.class))).thenReturn(queryResponse);
-
-		// Test
-		SearchResponse result = searchService.search("books", "nonexistent_query", null, null, null, null, null);
-
-		// Verify
-		assertNotNull(result);
-		assertEquals(0L, result.numFound());
-		assertEquals(0, result.documents().size());
-		assertTrue(result.facets().isEmpty());
-	}
-
-	@Test
-	void testSearchWithEmptyFacets() throws SolrServerException, IOException {
-		// Setup mock response with documents but no facets
-		SolrDocumentList documents = new SolrDocumentList();
-		documents.setNumFound(2);
-		documents.setStart(0);
-		documents.setMaxScore(1.0f);
-
-		SolrDocument doc1 = new SolrDocument();
-		doc1.addField("id", "1");
-		doc1.addField("name", "Book 1");
-
-		SolrDocument doc2 = new SolrDocument();
-		doc2.addField("id", "2");
-		doc2.addField("name", "Book 2");
-
-		documents.add(doc1);
-		documents.add(doc2);
-
-		when(queryResponse.getResults()).thenReturn(documents);
-		when(queryResponse.getFacetFields()).thenReturn(null); // No facet fields
-		when(solrClient.query(eq("books"), any(SolrQuery.class))).thenReturn(queryResponse);
-
-		// Test with facet fields requested but none returned
-		SearchResponse result = searchService.search("books", null, null, List.of("genre_s"), null, null, null);
-
-		// Verify
-		assertNotNull(result);
-		assertEquals(2L, result.numFound());
-		assertEquals(2, result.documents().size());
-		assertTrue(result.facets().isEmpty());
-	}
-
-	@Test
-	void testSearchWithEmptyFacetValues() throws SolrServerException, IOException {
-		// Setup mock response with facet fields but no values
-		SolrDocumentList documents = new SolrDocumentList();
-		documents.setNumFound(2);
-		documents.setStart(0);
-		documents.setMaxScore(1.0f);
-
-		SolrDocument doc1 = new SolrDocument();
-		doc1.addField("id", "1");
-		SolrDocument doc2 = new SolrDocument();
-		doc2.addField("id", "2");
-
-		documents.add(doc1);
-		documents.add(doc2);
-
-		// Create facet field with no values
-		List<FacetField> facetFields = new ArrayList<>();
-		FacetField emptyFacet = new FacetField("genre_s");
-		facetFields.add(emptyFacet);
-
-		when(queryResponse.getResults()).thenReturn(documents);
-		when(queryResponse.getFacetFields()).thenReturn(facetFields);
-		when(solrClient.query(eq("books"), any(SolrQuery.class))).thenReturn(queryResponse);
-
-		// Test
-		SearchResponse result = searchService.search("books", null, null, List.of("genre_s"), null, null, null);
-
-		// Verify
-		assertNotNull(result);
-		assertEquals(2L, result.numFound());
-		assertTrue(result.facets().containsKey("genre_s"));
-		assertTrue(result.facets().get("genre_s").isEmpty());
-	}
-
-	@Test
-	void testSearchWithSolrError() {
-		// Setup mock to throw exception
-		try {
-			when(solrClient.query(eq("books"), any(SolrQuery.class)))
-					.thenThrow(new SolrServerException("Simulated Solr server error"));
-
-			// Test
-			assertThrows(SolrServerException.class, () -> {
-				searchService.search("books", null, null, null, null, null, null);
-			});
-		} catch (Exception e) {
-			fail("Test setup failed: " + e.getMessage());
-		}
-	}
-
-	@Test
-	void testSearchWithAllParameters() throws SolrServerException, IOException {
-		// Setup mock response
-		SolrDocumentList documents = new SolrDocumentList();
-		documents.setNumFound(1);
-		documents.setStart(5);
-		documents.setMaxScore(0.75f);
-
-		SolrDocument doc = new SolrDocument();
-		doc.addField("id", "5");
-		doc.addField("name", "Book 5");
-		doc.addField("author", "Author 5");
-		doc.addField("genre_s", "mystery");
-		doc.addField("price", 12.99);
-
-		documents.add(doc);
-
-		// Create facet fields
-		List<FacetField> facetFields = new ArrayList<>();
-		FacetField genreFacet = new FacetField("genre_s");
-		genreFacet.add("mystery", 1);
-		facetFields.add(genreFacet);
-
-		when(queryResponse.getResults()).thenReturn(documents);
-		when(queryResponse.getFacetFields()).thenReturn(facetFields);
-		when(solrClient.query(eq("books"), any(SolrQuery.class))).thenReturn(queryResponse);
-
-		// Test with all parameters
-		List<String> filterQueries = List.of("price:[10 TO 15]");
-		List<String> facetFields2 = List.of("genre_s", "author");
-		List<Map<String, String>> sortClauses = List.of(Map.of("item", "price", "order", "desc"));
-
-		SearchResponse result = searchService.search("books", "mystery", filterQueries, facetFields2, sortClauses, 5,
-				10);
-
-		// Verify
-		assertNotNull(result);
-		assertEquals(1L, result.numFound());
-		assertEquals(5, result.start());
-		assertEquals(0.75f, result.maxScore());
-		assertEquals(1, result.documents().size());
-		assertEquals("5", result.documents().getFirst().get("id"));
-		assertEquals("Book 5", result.documents().getFirst().get("name"));
-		assertTrue(result.facets().containsKey("genre_s"));
-		assertEquals(1L, result.facets().get("genre_s").get("mystery"));
-	}
-}
diff --git a/src/test/java/org/apache/solr/mcp/server/search/SearchServiceTest.java b/src/test/java/org/apache/solr/mcp/server/search/SearchServiceIntegrationTest.java
similarity index 54%
copy from src/test/java/org/apache/solr/mcp/server/search/SearchServiceTest.java
copy to src/test/java/org/apache/solr/mcp/server/search/SearchServiceIntegrationTest.java
index 1e8f8be..59f712a 100644
--- a/src/test/java/org/apache/solr/mcp/server/search/SearchServiceTest.java
+++ b/src/test/java/org/apache/solr/mcp/server/search/SearchServiceIntegrationTest.java
@@ -17,10 +17,6 @@
 package org.apache.solr.mcp.server.search;
 
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -30,30 +26,26 @@ import java.util.OptionalDouble;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
-import org.apache.solr.client.solrj.request.SolrQuery;
-import org.apache.solr.client.solrj.response.FacetField;
-import org.apache.solr.client.solrj.response.QueryResponse;
-import org.apache.solr.common.SolrDocument;
-import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.mcp.server.TestcontainersConfiguration;
 import org.apache.solr.mcp.server.indexing.IndexingService;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledInNativeImage;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.context.annotation.Import;
 import org.testcontainers.junit.jupiter.Testcontainers;
 
 /**
- * Combined tests for SearchService: integration + unit (mocked SolrClient) in
- * one class.
+ * Integration tests for SearchService using a real Solr instance via
+ * Testcontainers.
  */
 @SpringBootTest
 @Import(TestcontainersConfiguration.class)
 @Testcontainers(disabledWithoutDocker = true)
-class SearchServiceTest {
+@DisabledInNativeImage
+class SearchServiceIntegrationTest {
 
-	// ===== Integration test context =====
 	private static final String COLLECTION_NAME = "search_test_" + System.currentTimeMillis();
 
 	@Autowired
@@ -183,8 +175,6 @@ class SearchServiceTest {
 		}
 	}
 
-	// ===== Integration tests (from original SearchServiceTest) =====
-
 	@Test
 	void testBasicSearch() throws SolrServerException, IOException {
 		SearchResponse result = searchService.search(COLLECTION_NAME, null, null, null, null, null, null);
@@ -406,239 +396,6 @@ class SearchServiceTest {
 		assertTrue(result.numFound() > 0, "Should find at least one document");
 	}
 
-	// ===== Unit-style tests with mocked SolrClient (from SearchServiceUnitTest)
-	// =====
-
-	@Test
-	void unit_constructor_ShouldInitializeWithSolrClient() {
-		SearchService localService = new SearchService(mock(SolrClient.class));
-		assertNotNull(localService);
-	}
-
-	@Test
-	void unit_search_WithNullQuery_ShouldDefaultToMatchAll() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		SolrDocumentList mockDocuments = createMockDocumentList();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(null);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenAnswer(invocation -> {
-			SolrQuery q = invocation.getArgument(1);
-			assertEquals("*:*", q.getQuery());
-			return mockResponse;
-		});
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", null, null, null, null, null, null);
-		assertNotNull(result);
-	}
-
-	@Test
-	void unit_search_WithCustomQuery_ShouldUseProvidedQuery() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		String customQuery = "name:\"Spring Boot\"";
-		SolrDocumentList mockDocuments = createMockDocumentList();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(null);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenAnswer(invocation -> {
-			SolrQuery q = invocation.getArgument(1);
-			assertEquals(customQuery, q.getQuery());
-			return mockResponse;
-		});
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", customQuery, null, null, null, null, null);
-		assertNotNull(result);
-	}
-
-	@Test
-	void unit_search_WithFilterQueries_ShouldApplyFilters() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		List<String> filterQueries = List.of("genre_s:fantasy", "price:[0 TO 10]");
-		SolrDocumentList mockDocuments = createMockDocumentList();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(null);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenAnswer(invocation -> {
-			SolrQuery q = invocation.getArgument(1);
-			assertArrayEquals(filterQueries.toArray(), q.getFilterQueries());
-			return mockResponse;
-		});
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", null, filterQueries, null, null, null, null);
-		assertNotNull(result);
-	}
-
-	@Test
-	void unit_search_WithFacetFields_ShouldEnableFaceting() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		List<String> facetFields = List.of("genre_s", "author_ss");
-		SolrDocumentList mockDocuments = createMockDocumentList();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(createMockFacetFields());
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenAnswer(invocation -> mockResponse);
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", null, null, facetFields, null, null, null);
-		assertNotNull(result);
-		assertNotNull(result.facets());
-	}
-
-	@Test
-	void unit_search_WithSortClauses_ShouldApplySorting() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		List<Map<String, String>> sortClauses = List.of(Map.of("item", "price", "order", "asc"),
-				Map.of("item", "name", "order", "desc"));
-		SolrDocumentList mockDocuments = createMockDocumentList();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(null);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenAnswer(invocation -> mockResponse);
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", null, null, null, sortClauses, null, null);
-		assertNotNull(result);
-	}
-
-	@Test
-	void unit_search_WithPagination_ShouldApplyStartAndRows() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		Integer start = 10;
-		Integer rows = 20;
-		SolrDocumentList mockDocuments = createMockDocumentList();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(null);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenAnswer(invocation -> {
-			SolrQuery q = invocation.getArgument(1);
-			assertEquals(start, q.getStart());
-			assertEquals(rows, q.getRows());
-			return mockResponse;
-		});
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", null, null, null, null, start, rows);
-		assertNotNull(result);
-	}
-
-	@Test
-	void unit_search_WithAllParameters_ShouldCombineAllOptions() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		String query = "title:Java";
-		List<String> filterQueries = List.of("inStock:true");
-		List<String> facetFields = List.of("category");
-		List<Map<String, String>> sortClauses = List.of(Map.of("item", "price", "order", "asc"));
-		Integer start = 0;
-		Integer rows = 10;
-		SolrDocumentList mockDocuments = createMockDocumentList();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(createMockFacetFields());
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenAnswer(invocation -> {
-			SolrQuery captured = invocation.getArgument(1);
-			assertEquals(query, captured.getQuery());
-			assertArrayEquals(filterQueries.toArray(), captured.getFilterQueries());
-			assertNotNull(captured.getFacetFields());
-			assertEquals(start, captured.getStart());
-			assertEquals(rows, captured.getRows());
-			return mockResponse;
-		});
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", query, filterQueries, facetFields, sortClauses,
-				start, rows);
-		assertNotNull(result);
-	}
-
-	@Test
-	void unit_search_WhenSolrThrowsException_ShouldPropagateException() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class)))
-				.thenThrow(new SolrServerException("Connection error"));
-		SearchService localService = new SearchService(mockClient);
-		assertThrows(SolrServerException.class,
-				() -> localService.search("test_collection", null, null, null, null, null, null));
-	}
-
-	@Test
-	void unit_search_WhenIOException_ShouldPropagateException() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenThrow(new IOException("Network error"));
-		SearchService localService = new SearchService(mockClient);
-		assertThrows(IOException.class,
-				() -> localService.search("test_collection", null, null, null, null, null, null));
-	}
-
-	@Test
-	void unit_search_WithEmptyResults_ShouldReturnEmptyDocumentList() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		SolrDocumentList emptyDocuments = new SolrDocumentList();
-		emptyDocuments.setNumFound(0);
-		emptyDocuments.setStart(0);
-		when(mockResponse.getResults()).thenReturn(emptyDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(null);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenReturn(mockResponse);
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", "nonexistent:value", null, null, null, null,
-				null);
-		assertNotNull(result);
-		assertEquals(0, result.numFound());
-		assertTrue(result.documents().isEmpty());
-	}
-
-	@Test
-	void unit_search_WithNullFilterQueries_ShouldNotApplyFilters() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		SolrDocumentList mockDocuments = createMockDocumentList();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(null);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenAnswer(invocation -> {
-			SolrQuery q = invocation.getArgument(1);
-			assertNull(q.getFilterQueries());
-			return mockResponse;
-		});
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", null, null, null, null, null, null);
-		assertNotNull(result);
-	}
-
-	@Test
-	void unit_search_WithEmptyFacetFields_ShouldNotEnableFaceting() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		SolrDocumentList mockDocuments = createMockDocumentList();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(null);
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenAnswer(invocation -> {
-			SolrQuery q = invocation.getArgument(1);
-			assertNull(q.getFacetFields());
-			return mockResponse;
-		});
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", null, null, List.of(), null, null, null);
-		assertNotNull(result);
-	}
-
-	@Test
-	void unit_searchResponse_ShouldContainAllFields() throws Exception {
-		SolrClient mockClient = mock(SolrClient.class);
-		QueryResponse mockResponse = mock(QueryResponse.class);
-		SolrDocumentList mockDocuments = createMockDocumentListWithData();
-		when(mockResponse.getResults()).thenReturn(mockDocuments);
-		when(mockResponse.getFacetFields()).thenReturn(createMockFacetFields());
-		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenReturn(mockResponse);
-		SearchService localService = new SearchService(mockClient);
-		SearchResponse result = localService.search("test_collection", null, null, List.of("genre_s"), null, null,
-				null);
-		assertNotNull(result);
-		assertEquals(2, result.numFound());
-		assertEquals(0, result.start());
-		assertNotNull(result.documents());
-		assertEquals(2, result.documents().size());
-		assertNotNull(result.facets());
-		assertFalse(result.facets().isEmpty());
-	}
-
-	// ===== Helpers (from unit tests and integration tests) =====
-
 	private OptionalDouble extractPrice(Map<String, Object> document) {
 		Object priceObj = document.get("price");
 		if (priceObj == null) {
@@ -668,43 +425,4 @@ class SearchServiceTest {
 		}
 		return ids;
 	}
-
-	private SolrDocumentList createMockDocumentList() {
-		SolrDocumentList documents = new SolrDocumentList();
-		documents.setNumFound(0);
-		documents.setStart(0);
-		return documents;
-	}
-
-	private SolrDocumentList createMockDocumentListWithData() {
-		SolrDocumentList documents = new SolrDocumentList();
-		documents.setNumFound(2);
-		documents.setStart(0);
-		documents.setMaxScore(1.0f);
-		SolrDocument doc1 = new SolrDocument();
-		doc1.setField("id", "book001");
-		doc1.setField("name", "Spring Boot in Action");
-		doc1.setField("author_ss", List.of("Craig Walls"));
-		doc1.setField("price", 39.99);
-		doc1.setField("genre_s", "technology");
-		documents.add(doc1);
-		SolrDocument doc2 = new SolrDocument();
-		doc2.setField("id", "book002");
-		doc2.setField("name", "Effective Java");
-		doc2.setField("author_ss", List.of("Joshua Bloch"));
-		doc2.setField("price", 44.99);
-		doc2.setField("genre_s", "technology");
-		documents.add(doc2);
-		return documents;
-	}
-
-	private List<FacetField> createMockFacetFields() {
-		FacetField genreFacet = new FacetField("genre_s");
-		genreFacet.add("technology", 5);
-		genreFacet.add("fiction", 3);
-		FacetField authorFacet = new FacetField("author_ss");
-		authorFacet.add("Craig Walls", 2);
-		authorFacet.add("Joshua Bloch", 1);
-		return List.of(genreFacet, authorFacet);
-	}
 }
diff --git a/src/test/java/org/apache/solr/mcp/server/search/SearchServiceTest.java b/src/test/java/org/apache/solr/mcp/server/search/SearchServiceTest.java
index 1e8f8be..e12d9d1 100644
--- a/src/test/java/org/apache/solr/mcp/server/search/SearchServiceTest.java
+++ b/src/test/java/org/apache/solr/mcp/server/search/SearchServiceTest.java
@@ -23,400 +23,32 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.OptionalDouble;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.client.solrj.request.SolrQuery;
 import org.apache.solr.client.solrj.response.FacetField;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.common.SolrDocument;
 import org.apache.solr.common.SolrDocumentList;
-import org.apache.solr.mcp.server.TestcontainersConfiguration;
-import org.apache.solr.mcp.server.indexing.IndexingService;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.context.annotation.Import;
-import org.testcontainers.junit.jupiter.Testcontainers;
+import org.junit.jupiter.api.condition.DisabledInNativeImage;
 
 /**
- * Combined tests for SearchService: integration + unit (mocked SolrClient) in
- * one class.
+ * Unit tests for SearchService with mocked SolrClient.
  */
-@SpringBootTest
-@Import(TestcontainersConfiguration.class)
-@Testcontainers(disabledWithoutDocker = true)
+@DisabledInNativeImage
 class SearchServiceTest {
 
-	// ===== Integration test context =====
-	private static final String COLLECTION_NAME = "search_test_" + System.currentTimeMillis();
-
-	@Autowired
-	private SearchService searchService;
-	@Autowired
-	private IndexingService indexingService;
-	@Autowired
-	private SolrClient solrClient;
-
-	private static boolean initialized = false;
-
-	@BeforeEach
-	void setUp() throws Exception {
-		if (!initialized) {
-			CollectionAdminRequest.Create createRequest = CollectionAdminRequest.createCollection(COLLECTION_NAME,
-					"_default", 1, 1);
-			createRequest.process(solrClient);
-
-			String sampleData = """
-					[
-					  {
-					    "id": "book001",
-					    "name": ["A Game of Thrones"],
-					    "author_ss": ["George R.R. Martin"],
-					    "price": [7.99],
-					    "genre_s": "fantasy",
-					    "series_s": "A Song of Ice and Fire",
-					    "sequence_i": 1,
-					     "cat_ss": ["book"]
-					  },
-					  {
-					    "id": "book002",
-					    "name": ["A Clash of Kings"],
-					    "author_ss": ["George R.R. Martin"],
-					    "price": [8.99],
-					    "genre_s": "fantasy",
-					    "series_s": "A Song of Ice and Fire",
-					    "sequence_i": 2,
-					    "cat_ss": ["book"]
-					  },
-					  {
-					    "id": "book003",
-					    "name": ["A Storm of Swords"],
-					    "author_ss": ["George R.R. Martin"],
-					    "price": [9.99],
-					    "genre_s": "fantasy",
-					    "series_s": "A Song of Ice and Fire",
-					    "sequence_i": 3,
-					    "cat_ss": ["book"]
-					  },
-					  {
-					    "id": "book004",
-					    "name": ["The Hobbit"],
-					    "author_ss": ["J.R.R. Tolkien"],
-					    "price": [6.99],
-					    "genre_s": "fantasy",
-					    "series_s": "Middle Earth",
-					    "sequence_i": 1,
-					    "cat_ss": ["book"]
-					  },
-					  {
-					    "id": "book005",
-					    "name": ["Dune"],
-					    "author_ss": ["Frank Herbert"],
-					    "price": [10.99],
-					    "genre_s": "scifi",
-					    "series_s": "Dune",
-					    "sequence_i": 1,
-					    "cat_ss": ["book"]
-					  },
-					  {
-					    "id": "book006",
-					    "name": ["Foundation"],
-					    "author_ss": ["Isaac Asimov"],
-					    "price": [5.99],
-					    "genre_s": "scifi",
-					    "series_s": "Foundation",
-					    "sequence_i": 1,
-					    "cat_ss": ["book"]
-					  },
-					  {
-					    "id": "book007",
-					    "name": ["The Fellowship of the Ring"],
-					    "author_ss": ["J.R.R. Tolkien"],
-					    "price": [8.99],
-					    "genre_s": "fantasy",
-					    "series_s": "The Lord of the Rings",
-					    "sequence_i": 1,
-					    "cat_ss": ["book"]
-					  },
-					  {
-					    "id": "book008",
-					    "name": ["The Two Towers"],
-					    "author_ss": ["J.R.R. Tolkien"],
-					    "price": [8.99],
-					    "genre_s": "fantasy",
-					    "series_s": "The Lord of the Rings",
-					    "sequence_i": 2,
-					    "cat_ss": ["book"]
-					  },
-					  {
-					    "id": "book009",
-					    "name": ["The Return of the King"],
-					    "author_ss": ["J.R.R. Tolkien"],
-					    "price": [8.99],
-					    "genre_s": "fantasy",
-					    "series_s": "The Lord of the Rings",
-					    "sequence_i": 3,
-					    "cat_ss": ["book"]
-					  },
-					  {
-					    "id": "book010",
-					    "name": ["Neuromancer"],
-					    "author_ss": ["William Gibson"],
-					    "price": [7.99],
-					    "genre_s": "scifi",
-					    "series_s": "Sprawl",
-					    "sequence_i": 1,
-					    "cat_ss": ["book"]
-					  }
-					]
-					""";
-
-			indexingService.indexJsonDocuments(COLLECTION_NAME, sampleData);
-			solrClient.commit(COLLECTION_NAME);
-			initialized = true;
-		}
-	}
-
-	// ===== Integration tests (from original SearchServiceTest) =====
-
-	@Test
-	void testBasicSearch() throws SolrServerException, IOException {
-		SearchResponse result = searchService.search(COLLECTION_NAME, null, null, null, null, null, null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertFalse(documents.isEmpty());
-		assertEquals(10, documents.size());
-	}
-
-	@Test
-	void testSearchWithQuery() throws SolrServerException, IOException {
-		SearchResponse result = searchService.search(COLLECTION_NAME, "name:\"Game of Thrones\"", null, null, null,
-				null, null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertEquals(1, documents.size());
-		Map<String, Object> book = documents.getFirst();
-		assertEquals("A Game of Thrones", ((List<?>) book.get("name")).getFirst());
-	}
-
-	@Test
-	void testSearchReturnsAuthor() throws Exception {
-		SearchResponse result = searchService.search(COLLECTION_NAME, "author_ss:\"George R.R. Martin\"", null, null,
-				null, null, null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertEquals(3, documents.size());
-		Map<String, Object> book = documents.getFirst();
-		assertEquals("George R.R. Martin", ((List<?>) book.get("author_ss")).getFirst());
-	}
-
-	@Test
-	void testSearchWithFacets() throws Exception {
-		SearchResponse result = searchService.search(COLLECTION_NAME, null, null, List.of("genre_s"), null, null, null);
-		assertNotNull(result);
-		Map<String, Map<String, Long>> facets = result.facets();
-		assertNotNull(facets);
-		assertTrue(facets.containsKey("genre_s"));
-	}
-
-	@Test
-	void testSearchWithPrice() throws Exception {
-		SearchResponse result = searchService.search(COLLECTION_NAME, null, null, null, null, null, null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertFalse(documents.isEmpty());
-		Map<String, Object> book = documents.getFirst();
-		double currentPrice = ((List<?>) book.get("price")).isEmpty()
-				? 0.0
-				: ((Number) ((List<?>) book.get("price")).getFirst()).doubleValue();
-		assertTrue(currentPrice > 0);
-	}
-
-	@Test
-	void testSortByPriceAscending() throws Exception {
-		List<Map<String, String>> sortClauses = List.of(Map.of("item", "price", "order", "asc"));
-		SearchResponse result = searchService.search(COLLECTION_NAME, null, null, null, sortClauses, null, null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertFalse(documents.isEmpty());
-		double previousPrice = 0.0;
-		for (Map<String, Object> book : documents) {
-			OptionalDouble priceOpt = extractPrice(book);
-			if (priceOpt.isEmpty())
-				continue;
-			double currentPrice = priceOpt.getAsDouble();
-			assertTrue(currentPrice >= previousPrice, "Books should be sorted by price in ascending order");
-			previousPrice = currentPrice;
-		}
-	}
-
-	@Test
-	void testSortByPriceDescending() throws Exception {
-		List<Map<String, String>> sortClauses = List.of(Map.of("item", "price", "order", "desc"));
-		SearchResponse result = searchService.search(COLLECTION_NAME, null, null, null, sortClauses, null, null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertFalse(documents.isEmpty());
-		double previousPrice = Double.MAX_VALUE;
-		for (Map<String, Object> book : documents) {
-			OptionalDouble priceOpt = extractPrice(book);
-			if (priceOpt.isEmpty())
-				continue;
-			double currentPrice = priceOpt.getAsDouble();
-			assertTrue(currentPrice <= previousPrice, "Books should be sorted by price in descending order");
-			previousPrice = currentPrice;
-		}
-	}
-
-	@Test
-	void testSortBySequence() throws Exception {
-		List<Map<String, String>> sortClauses = List.of(Map.of("item", "sequence_i", "order", "asc"));
-		List<String> filterQueries = List.of("series_s:\"A Song of Ice and Fire\"");
-		SearchResponse result = searchService.search(COLLECTION_NAME, null, filterQueries, null, sortClauses, null,
-				null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertFalse(documents.isEmpty());
-		int previousSequence = 0;
-		for (Map<String, Object> book : documents) {
-			int currentSequence = ((Number) book.get("sequence_i")).intValue();
-			assertTrue(currentSequence >= previousSequence, "Books should be sorted by sequence_i in ascending order");
-			previousSequence = currentSequence;
-		}
-	}
-
-	@Test
-	void testFilterByGenre() throws Exception {
-		List<String> filterQueries = List.of("genre_s:fantasy");
-		SearchResponse result = searchService.search(COLLECTION_NAME, null, filterQueries, null, null, null, null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertFalse(documents.isEmpty());
-		for (Map<String, Object> book : documents) {
-			String genre = (String) book.get("genre_s");
-			assertEquals("fantasy", genre, "All books should have genre_s = fantasy");
-		}
-	}
-
 	@Test
-	void testFilterByPriceRange() throws Exception {
-		List<String> filterQueries = List.of("price:[6.0 TO 7.0]");
-		SearchResponse result = searchService.search(COLLECTION_NAME, null, filterQueries, null, null, null, null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertFalse(documents.isEmpty());
-		for (Map<String, Object> book : documents) {
-			if (book.get("price") == null)
-				continue;
-			OptionalDouble priceOpt = extractPrice(book);
-			if (priceOpt.isEmpty())
-				continue;
-			double price = priceOpt.getAsDouble();
-			assertTrue(price >= 6.0 && price <= 7.0, "All books should have price between 6.0 and 7.0");
-		}
-	}
-
-	@Test
-	void testCombinedSortingAndFiltering() throws Exception {
-		List<Map<String, String>> sortClauses = List.of(Map.of("item", "price", "order", "desc"));
-		List<String> filterQueries = List.of("genre_s:fantasy");
-		SearchResponse result = searchService.search(COLLECTION_NAME, null, filterQueries, null, sortClauses, null,
-				null);
-		assertNotNull(result);
-		List<Map<String, Object>> documents = result.documents();
-		assertFalse(documents.isEmpty());
-		for (Map<String, Object> book : documents) {
-			String genre = (String) book.get("genre_s");
-			assertEquals("fantasy", genre, "All books should have genre_s = fantasy");
-		}
-		double previousPrice = Double.MAX_VALUE;
-		for (Map<String, Object> book : documents) {
-			Object priceObj = book.get("price");
-			double currentPrice;
-			if (priceObj instanceof List) {
-				List<?> priceList = (List<?>) priceObj;
-				if (priceList.isEmpty()) {
-					continue;
-				}
-				currentPrice = ((Number) priceList.getFirst()).doubleValue();
-			} else if (priceObj instanceof Number) {
-				currentPrice = ((Number) priceObj).doubleValue();
-			} else {
-				continue;
-			}
-			assertTrue(currentPrice <= previousPrice, "Books should be sorted by price in descending order");
-			previousPrice = currentPrice;
-		}
-	}
-
-	@Test
-	void testPagination() throws Exception {
-		SearchResponse allResults = searchService.search(COLLECTION_NAME, null, null, null, null, null, null);
-		assertNotNull(allResults);
-		long totalDocuments = allResults.numFound();
-		assertTrue(totalDocuments > 0, "Should have at least some documents");
-		SearchResponse firstPage = searchService.search(COLLECTION_NAME, null, null, null, null, 0, 2);
-		assertNotNull(firstPage);
-		assertEquals(0, firstPage.start(), "Start offset should be 0");
-		assertEquals(totalDocuments, firstPage.numFound(), "Total count should match");
-		assertEquals(2, firstPage.documents().size(), "Should return exactly 2 documents");
-		SearchResponse secondPage = searchService.search(COLLECTION_NAME, null, null, null, null, 2, 2);
-		assertNotNull(secondPage);
-		assertEquals(2, secondPage.start(), "Start offset should be 2");
-		assertEquals(totalDocuments, secondPage.numFound(), "Total count should match");
-		assertEquals(2, secondPage.documents().size(), "Should return exactly 2 documents");
-		List<String> firstPageIds = getDocumentIds(firstPage.documents());
-		List<String> secondPageIds = getDocumentIds(secondPage.documents());
-		for (String id : firstPageIds) {
-			assertFalse(secondPageIds.contains(id), "Second page should not contain documents from first page");
-		}
-	}
-
-	@Test
-	void testSpecialCharactersInQuery() throws Exception {
-		String specialJson = """
-				[
-				  {
-				    "id": "special001",
-				    "title": "Book with special characters: & + - ! ( ) { } [ ] ^ \\" ~ * ? : \\\\ /",
-				    "author_ss": ["Special Author (with parentheses)"],
-				    "description": "This is a test document with special characters: & + - ! ( ) { } [ ] ^ \\" ~ * ? : \\\\ /"
-				  }
-				]
-				""";
-		indexingService.indexJsonDocuments(COLLECTION_NAME, specialJson);
-		solrClient.commit(COLLECTION_NAME);
-		String query = "id:special001";
-		SearchResponse result = searchService.search(COLLECTION_NAME, query, null, null, null, null, null);
-		assertNotNull(result);
-		assertEquals(1, result.numFound(), "Should find exactly one document");
-		query = "author_ss:\"Special Author \\(" + "with parentheses\\)\""; // escape parentheses
-		result = searchService.search(COLLECTION_NAME, query, null, null, null, null, null);
-		assertNotNull(result);
-		assertEquals(1, result.numFound(), "Should find exactly one document");
-		query = "title:special*";
-		result = searchService.search(COLLECTION_NAME, query, null, null, null, null, null);
-		assertNotNull(result);
-		assertTrue(result.numFound() > 0, "Should find at least one document");
-	}
-
-	// ===== Unit-style tests with mocked SolrClient (from SearchServiceUnitTest)
-	// =====
-
-	@Test
-	void unit_constructor_ShouldInitializeWithSolrClient() {
+	void constructor_ShouldInitializeWithSolrClient() {
 		SearchService localService = new SearchService(mock(SolrClient.class));
 		assertNotNull(localService);
 	}
 
 	@Test
-	void unit_search_WithNullQuery_ShouldDefaultToMatchAll() throws Exception {
+	void search_WithNullQuery_ShouldDefaultToMatchAll() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		SolrDocumentList mockDocuments = createMockDocumentList();
@@ -433,7 +65,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WithCustomQuery_ShouldUseProvidedQuery() throws Exception {
+	void search_WithCustomQuery_ShouldUseProvidedQuery() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		String customQuery = "name:\"Spring Boot\"";
@@ -451,7 +83,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WithFilterQueries_ShouldApplyFilters() throws Exception {
+	void search_WithFilterQueries_ShouldApplyFilters() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		List<String> filterQueries = List.of("genre_s:fantasy", "price:[0 TO 10]");
@@ -469,7 +101,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WithFacetFields_ShouldEnableFaceting() throws Exception {
+	void search_WithFacetFields_ShouldEnableFaceting() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		List<String> facetFields = List.of("genre_s", "author_ss");
@@ -484,7 +116,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WithSortClauses_ShouldApplySorting() throws Exception {
+	void search_WithSortClauses_ShouldApplySorting() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		List<Map<String, String>> sortClauses = List.of(Map.of("item", "price", "order", "asc"),
@@ -499,7 +131,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WithPagination_ShouldApplyStartAndRows() throws Exception {
+	void search_WithPagination_ShouldApplyStartAndRows() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		Integer start = 10;
@@ -519,7 +151,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WithAllParameters_ShouldCombineAllOptions() throws Exception {
+	void search_WithAllParameters_ShouldCombineAllOptions() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		String query = "title:Java";
@@ -547,7 +179,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WhenSolrThrowsException_ShouldPropagateException() throws Exception {
+	void search_WhenSolrThrowsException_ShouldPropagateException() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		when(mockClient.query(eq("test_collection"), any(SolrQuery.class)))
 				.thenThrow(new SolrServerException("Connection error"));
@@ -557,7 +189,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WhenIOException_ShouldPropagateException() throws Exception {
+	void search_WhenIOException_ShouldPropagateException() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		when(mockClient.query(eq("test_collection"), any(SolrQuery.class))).thenThrow(new IOException("Network error"));
 		SearchService localService = new SearchService(mockClient);
@@ -566,7 +198,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WithEmptyResults_ShouldReturnEmptyDocumentList() throws Exception {
+	void search_WithEmptyResults_ShouldReturnEmptyDocumentList() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		SolrDocumentList emptyDocuments = new SolrDocumentList();
@@ -584,7 +216,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WithNullFilterQueries_ShouldNotApplyFilters() throws Exception {
+	void search_WithNullFilterQueries_ShouldNotApplyFilters() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		SolrDocumentList mockDocuments = createMockDocumentList();
@@ -601,7 +233,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_search_WithEmptyFacetFields_ShouldNotEnableFaceting() throws Exception {
+	void search_WithEmptyFacetFields_ShouldNotEnableFaceting() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		SolrDocumentList mockDocuments = createMockDocumentList();
@@ -618,7 +250,7 @@ class SearchServiceTest {
 	}
 
 	@Test
-	void unit_searchResponse_ShouldContainAllFields() throws Exception {
+	void searchResponse_ShouldContainAllFields() throws Exception {
 		SolrClient mockClient = mock(SolrClient.class);
 		QueryResponse mockResponse = mock(QueryResponse.class);
 		SolrDocumentList mockDocuments = createMockDocumentListWithData();
@@ -637,38 +269,6 @@ class SearchServiceTest {
 		assertFalse(result.facets().isEmpty());
 	}
 
-	// ===== Helpers (from unit tests and integration tests) =====
-
-	private OptionalDouble extractPrice(Map<String, Object> document) {
-		Object priceObj = document.get("price");
-		if (priceObj == null) {
-			return OptionalDouble.empty();
-		}
-		if (priceObj instanceof List) {
-			List<?> priceList = (List<?>) priceObj;
-			if (priceList.isEmpty()) {
-				return OptionalDouble.empty();
-			}
-			return OptionalDouble.of(((Number) priceList.getFirst()).doubleValue());
-		} else if (priceObj instanceof Number) {
-			return OptionalDouble.of(((Number) priceObj).doubleValue());
-		}
-		return OptionalDouble.empty();
-	}
-
-	private List<String> getDocumentIds(List<Map<String, Object>> documents) {
-		List<String> ids = new ArrayList<>();
-		for (Map<String, Object> doc : documents) {
-			Object idObj = doc.get("id");
-			if (idObj instanceof List) {
-				ids.add(((List<?>) idObj).getFirst().toString());
-			} else if (idObj != null) {
-				ids.add(idObj.toString());
-			}
-		}
-		return ids;
-	}
-
 	private SolrDocumentList createMockDocumentList() {
 		SolrDocumentList documents = new SolrDocumentList();
 		documents.setNumFound(0);