forked from testcontainers/testcontainers-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Apache Solr Module (testcontainers#2123)
- Loading branch information
Showing
14 changed files
with
584 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Solr Container | ||
|
||
!!! note | ||
This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy. | ||
|
||
|
||
This module helps running [solr](https://lucene.apache.org/solr/) using Testcontainers. | ||
|
||
Note that it's based on the [official Docker image](https://hub.docker.com/_/solr/). | ||
|
||
## Usage example | ||
|
||
You can start a solr container instance from any Java application by using: | ||
|
||
<!--codeinclude--> | ||
[Using a Solr container](../../modules/solr/src/test/java/org/testcontainers/containers/SolrContainerTest.java) inside_block:solrContainerUsage | ||
<!--/codeinclude--> | ||
|
||
## Adding this module to your project dependencies | ||
|
||
Add the following dependency to your `pom.xml`/`build.gradle` file: | ||
|
||
```groovy tab='Gradle' | ||
testCompile "org.testcontainers:solr:{{latest_version}}" | ||
``` | ||
|
||
```xml tab='Maven' | ||
<dependency> | ||
<groupId>org.testcontainers</groupId> | ||
<artifactId>solr</artifactId> | ||
<version>{{latest_version}}</version> | ||
<scope>test</scope> | ||
</dependency> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
plugins { | ||
id 'java' | ||
} | ||
|
||
repositories { | ||
jcenter() | ||
} | ||
|
||
dependencies { | ||
compileOnly "org.projectlombok:lombok:1.18.10" | ||
annotationProcessor "org.projectlombok:lombok:1.18.10" | ||
|
||
implementation 'org.apache.solr:solr-solrj:8.3.0' | ||
|
||
testImplementation 'org.testcontainers:testcontainers' | ||
testImplementation 'org.testcontainers:solr' | ||
|
||
} |
6 changes: 6 additions & 0 deletions
6
examples/solr-container/src/main/java/com/example/SearchEngine.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.example; | ||
|
||
public interface SearchEngine { | ||
|
||
public SearchResult search(String term); | ||
} |
20 changes: 20 additions & 0 deletions
20
examples/solr-container/src/main/java/com/example/SearchResult.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.example; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Data; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Data | ||
@Builder | ||
@NoArgsConstructor | ||
@AllArgsConstructor | ||
public class SearchResult { | ||
|
||
private long totalHits; | ||
|
||
private List<Map<String, Object>> results; | ||
} |
39 changes: 39 additions & 0 deletions
39
examples/solr-container/src/main/java/com/example/SolrSearchEngine.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.example; | ||
|
||
import java.util.stream.Collectors; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.SneakyThrows; | ||
|
||
import org.apache.solr.client.solrj.SolrClient; | ||
import org.apache.solr.client.solrj.SolrQuery; | ||
import org.apache.solr.client.solrj.response.QueryResponse; | ||
import org.apache.solr.client.solrj.util.ClientUtils; | ||
import org.apache.solr.common.SolrDocument; | ||
|
||
@RequiredArgsConstructor | ||
public class SolrSearchEngine implements SearchEngine { | ||
|
||
public static final String COLLECTION_NAME = "products"; | ||
|
||
private final SolrClient client; | ||
|
||
@SneakyThrows | ||
public SearchResult search(String term) { | ||
|
||
SolrQuery query = new SolrQuery(); | ||
query.setQuery("title:" + ClientUtils.escapeQueryChars(term)); | ||
QueryResponse response = client.query(COLLECTION_NAME, query); | ||
return createResult(response); | ||
} | ||
|
||
private SearchResult createResult(QueryResponse response) { | ||
return SearchResult.builder() | ||
.totalHits(response.getResults().getNumFound()) | ||
.results(response.getResults() | ||
.stream() | ||
.map(SolrDocument::getFieldValueMap) | ||
.collect(Collectors.toList())) | ||
.build(); | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
examples/solr-container/src/test/java/com/example/SolrQueryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package com.example; | ||
|
||
import static com.example.SolrSearchEngine.COLLECTION_NAME; | ||
import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; | ||
|
||
import java.io.IOException; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import org.apache.solr.client.solrj.SolrClient; | ||
import org.apache.solr.client.solrj.SolrServerException; | ||
import org.apache.solr.client.solrj.impl.Http2SolrClient; | ||
import org.apache.solr.common.SolrInputDocument; | ||
import org.apache.solr.common.SolrInputField; | ||
import org.junit.BeforeClass; | ||
import org.junit.Test; | ||
import org.testcontainers.containers.SolrContainer; | ||
|
||
public class SolrQueryTest { | ||
|
||
public static final SolrContainer solrContainer = new SolrContainer() | ||
.withCollection(COLLECTION_NAME); | ||
|
||
private static SolrClient solrClient; | ||
|
||
@BeforeClass | ||
public static void setUp() throws IOException, SolrServerException { | ||
solrContainer.start(); | ||
solrClient = new Http2SolrClient.Builder("http://" + solrContainer.getContainerIpAddress() + ":" + solrContainer.getSolrPort() + "/solr").build(); | ||
|
||
// Add Sample Data | ||
solrClient.add(COLLECTION_NAME, Collections.singletonList( | ||
new SolrInputDocument(createMap( | ||
"id", createInputField("id", "1"), | ||
"title", createInputField("title", "old skool - trainers - shoes") | ||
)) | ||
)); | ||
|
||
solrClient.add(COLLECTION_NAME, Collections.singletonList( | ||
new SolrInputDocument(createMap( | ||
"id", createInputField("id", "2"), | ||
"title", createInputField("title", "print t-shirt") | ||
)) | ||
)); | ||
|
||
solrClient.commit(COLLECTION_NAME); | ||
} | ||
|
||
@Test | ||
public void testQueryForShoes() { | ||
SolrSearchEngine searchEngine = new SolrSearchEngine(solrClient); | ||
|
||
SearchResult result = searchEngine.search("shoes"); | ||
assertEquals("When searching for shoes we expect one result", 1L, result.getTotalHits()); | ||
assertEquals("The result should have the id 1", "1", result.getResults().get(0).get("id")); | ||
} | ||
|
||
@Test | ||
public void testQueryForTShirt() { | ||
SolrSearchEngine searchEngine = new SolrSearchEngine(solrClient); | ||
|
||
SearchResult result = searchEngine.search("t-shirt"); | ||
assertEquals("When searching for t-shirt we expect one result", 1L, result.getTotalHits()); | ||
assertEquals("The result should have the id 2", "2", result.getResults().get(0).get("id")); | ||
} | ||
|
||
@Test | ||
public void testQueryForAsterisk() { | ||
SolrSearchEngine searchEngine = new SolrSearchEngine(solrClient); | ||
|
||
SearchResult result = searchEngine.search("*"); | ||
assertEquals("When searching for * we expect no results", 0L, result.getTotalHits()); | ||
} | ||
|
||
private static SolrInputField createInputField(String key, String value) { | ||
SolrInputField inputField = new SolrInputField(key); | ||
inputField.setValue(value); | ||
return inputField; | ||
} | ||
|
||
private static Map<String, SolrInputField> createMap(String k0, SolrInputField v0, String k1, SolrInputField v1) { | ||
Map<String, SolrInputField> result = new HashMap<>(); | ||
result.put(k0, v0); | ||
result.put(k1, v1); | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
description = "Testcontainers :: Solr" | ||
|
||
dependencies { | ||
compile project(':testcontainers') | ||
testCompile 'org.apache.solr:solr-solrj:8.3.0' | ||
|
||
} |
133 changes: 133 additions & 0 deletions
133
modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package org.testcontainers.containers; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.net.URISyntaxException; | ||
import java.net.URL; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.zip.ZipEntry; | ||
import java.util.zip.ZipOutputStream; | ||
|
||
import org.apache.commons.io.IOUtils; | ||
|
||
import okhttp3.HttpUrl; | ||
import okhttp3.MediaType; | ||
import okhttp3.OkHttpClient; | ||
import okhttp3.Request; | ||
import okhttp3.RequestBody; | ||
import okhttp3.Response; | ||
|
||
/** | ||
* Utils class which can create collections and configurations. | ||
* | ||
* @author Simon Schneider | ||
*/ | ||
public class SolrClientUtils { | ||
|
||
private static OkHttpClient httpClient = new OkHttpClient(); | ||
|
||
/** | ||
* Creates a new configuration and uploads the solrconfig.xml and schema.xml | ||
* | ||
* @param hostname the Hostname under which solr is reachable | ||
* @param port the Port on which solr is running | ||
* @param configurationName the name of the configuration which should be created | ||
* @param solrConfig the url under which the solrconfig.xml can be found | ||
* @param solrSchema the url under which the schema.xml can be found or null if the default schema should be used | ||
*/ | ||
public static void uploadConfiguration(String hostname, int port, String configurationName, URL solrConfig, URL solrSchema) throws URISyntaxException, IOException { | ||
Map<String, String> parameters = new HashMap<>(); | ||
parameters.put("action", "UPLOAD"); | ||
parameters.put("name", configurationName); | ||
HttpUrl url = generateSolrURL(hostname, port, Arrays.asList("admin", "configs"), parameters); | ||
|
||
byte[] configurationZipFile = generateConfigZipFile(solrConfig, solrSchema); | ||
executePost(url, configurationZipFile); | ||
|
||
} | ||
|
||
/** | ||
* Creates a new collection | ||
* | ||
* @param hostname the Hostname under which solr is reachable | ||
* @param port The Port on which solr is running | ||
* @param collectionName the name of the collection which should be created | ||
* @param configurationName the name of the configuration which should used to create the collection | ||
* or null if the default configuration should be used | ||
*/ | ||
public static void createCollection(String hostname, int port, String collectionName, String configurationName) throws URISyntaxException, IOException { | ||
Map<String, String> parameters = new HashMap<>(); | ||
parameters.put("action", "CREATE"); | ||
parameters.put("name", collectionName); | ||
parameters.put("numShards", "1"); | ||
parameters.put("replicationFactor", "1"); | ||
parameters.put("wt", "json"); | ||
if (configurationName != null) { | ||
parameters.put("collection.configName", configurationName); | ||
} | ||
HttpUrl url = generateSolrURL(hostname, port, Arrays.asList("admin", "collections"), parameters); | ||
executePost(url, null); | ||
} | ||
|
||
private static void executePost(HttpUrl url, byte[] data) throws IOException { | ||
|
||
RequestBody requestBody = data == null ? | ||
RequestBody.create(MediaType.parse("text/plain"), "") : | ||
RequestBody.create(MediaType.parse("application/octet-stream"), data); | ||
; | ||
|
||
Request request = new Request.Builder() | ||
.url(url) | ||
.post(requestBody) | ||
.build(); | ||
Response response = httpClient.newCall(request).execute(); | ||
if (!response.isSuccessful()) { | ||
String responseBody = ""; | ||
if (response.body() != null) { | ||
responseBody = response.body().string(); | ||
response.close(); | ||
} | ||
throw new SolrClientUtilsException(response.code(), "Unable to upload binary\n" + responseBody); | ||
} | ||
if (response.body() != null) { | ||
response.close(); | ||
} | ||
} | ||
|
||
private static HttpUrl generateSolrURL(String hostname, int port, List<String> pathSegments, Map<String, String> parameters) throws URISyntaxException { | ||
HttpUrl.Builder builder = new HttpUrl.Builder(); | ||
builder.scheme("http"); | ||
builder.host(hostname); | ||
builder.port(port); | ||
// Path | ||
builder.addPathSegment("solr"); | ||
if (pathSegments != null) { | ||
pathSegments.forEach(builder::addPathSegment); | ||
} | ||
// Query Parameters | ||
parameters.forEach(builder::addQueryParameter); | ||
return builder.build(); | ||
} | ||
|
||
private static byte[] generateConfigZipFile(URL solrConfiguration, URL solrSchema) throws IOException { | ||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | ||
ZipOutputStream zipOutputStream = new ZipOutputStream(bos); | ||
// SolrConfig | ||
zipOutputStream.putNextEntry(new ZipEntry("solrconfig.xml")); | ||
IOUtils.copy(solrConfiguration.openStream(), zipOutputStream); | ||
zipOutputStream.closeEntry(); | ||
|
||
// Solr Schema | ||
if (solrSchema != null) { | ||
zipOutputStream.putNextEntry(new ZipEntry("schema.xml")); | ||
IOUtils.copy(solrSchema.openStream(), zipOutputStream); | ||
zipOutputStream.closeEntry(); | ||
} | ||
|
||
zipOutputStream.close(); | ||
return bos.toByteArray(); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
modules/solr/src/main/java/org/testcontainers/containers/SolrClientUtilsException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.testcontainers.containers; | ||
|
||
public class SolrClientUtilsException extends RuntimeException { | ||
public SolrClientUtilsException(int statusCode, String msg) { | ||
super("Http Call Status: " + statusCode + "\n" + msg); | ||
} | ||
} |
Oops, something went wrong.