-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add a docker implementation for the ES testing framework. (#48)
Also start publishing these jars, which required some minor javadoc cleanup.
- Loading branch information
John Plaisted
authored
Dec 1, 2020
1 parent
fd3b06a
commit 45b63b6
Showing
9 changed files
with
351 additions
and
32 deletions.
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
17 changes: 17 additions & 0 deletions
17
testing/elasticsearch-dao-integ-testing-docker/build.gradle
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,17 @@ | ||
apply plugin: 'java' | ||
|
||
apply from: "$rootDir/gradle/java-publishing.gradle" | ||
|
||
dependencies { | ||
compile project(':testing:elasticsearch-dao-integ-testing') | ||
|
||
compile externalDependency.assertJ | ||
compile externalDependency.junitJupiterApi | ||
compile externalDependency.junitJupiterParams | ||
compile externalDependency.testContainers | ||
compile externalDependency.testContainersJunit | ||
|
||
testRuntimeOnly externalDependency.junitJupiterEngine | ||
|
||
testCompile project(':testing:test-models') | ||
} |
81 changes: 81 additions & 0 deletions
81
.../src/main/java/com/linkedin/metadata/testing/ElasticsearchContainerFactoryDockerImpl.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,81 @@ | ||
package com.linkedin.metadata.testing; | ||
|
||
import java.net.InetAddress; | ||
import java.net.UnknownHostException; | ||
import javax.annotation.Nonnull; | ||
import org.apache.http.HttpHost; | ||
import org.apache.http.impl.nio.reactor.IOReactorConfig; | ||
import org.elasticsearch.client.RestClient; | ||
import org.elasticsearch.client.RestClientBuilder; | ||
import org.elasticsearch.client.RestHighLevelClient; | ||
import org.elasticsearch.client.transport.TransportClient; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.elasticsearch.common.transport.InetSocketTransportAddress; | ||
import org.elasticsearch.transport.client.PreBuiltTransportClient; | ||
import org.testcontainers.containers.GenericContainer; | ||
|
||
|
||
/** | ||
* Uses the TestContainers framework to launch an Elasticsearch instance using docker. | ||
*/ | ||
@ElasticsearchContainerFactory.Implementation | ||
public final class ElasticsearchContainerFactoryDockerImpl implements ElasticsearchContainerFactory { | ||
private static final String IMAGE_NAME = "docker.elastic.co/elasticsearch/elasticsearch:5.6.8"; | ||
private static final int HTTP_PORT = 9200; | ||
private static final int TRANSPORT_PORT = 9300; | ||
|
||
/** | ||
* Simple implementation that has no extra behavior and is just used to help with the generic typing. | ||
*/ | ||
private static final class GenericContainerImpl extends GenericContainer<GenericContainerImpl> { | ||
public GenericContainerImpl(@Nonnull String dockerImageName) { | ||
super(dockerImageName); | ||
} | ||
} | ||
|
||
private GenericContainerImpl _container; | ||
|
||
@Nonnull | ||
private static RestHighLevelClient buildRestClient(@Nonnull GenericContainerImpl gc) { | ||
final RestClientBuilder builder = RestClient.builder(new HttpHost("localhost", gc.getMappedPort(HTTP_PORT), "http")) | ||
.setHttpClientConfigCallback(httpAsyncClientBuilder -> httpAsyncClientBuilder.setDefaultIOReactorConfig( | ||
IOReactorConfig.custom().setIoThreadCount(1).build())); | ||
|
||
builder.setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder. | ||
setConnectionRequestTimeout(3000)); | ||
|
||
return new RestHighLevelClient(builder.build()); | ||
} | ||
|
||
@Nonnull | ||
private static TransportClient buildTransportClient(@Nonnull GenericContainerImpl gc) throws UnknownHostException { | ||
return new PreBuiltTransportClient( | ||
Settings.builder().put("cluster.name", "docker-cluster").build()).addTransportAddress( | ||
new InetSocketTransportAddress(InetAddress.getLoopbackAddress(), gc.getMappedPort(TRANSPORT_PORT))); | ||
} | ||
|
||
@Nonnull | ||
@Override | ||
public ElasticsearchConnection start() throws Exception { | ||
if (_container == null) { | ||
_container = new GenericContainerImpl(IMAGE_NAME).withExposedPorts(HTTP_PORT, TRANSPORT_PORT) | ||
.withEnv("xpack.security.enabled", "false"); | ||
_container.start(); | ||
} | ||
|
||
return new ElasticsearchConnection(buildRestClient(_container), buildTransportClient(_container)); | ||
} | ||
|
||
@Override | ||
public void close() throws Throwable { | ||
if (_container == null) { | ||
return; | ||
} | ||
|
||
try { | ||
_container.close(); | ||
} finally { | ||
_container = null; | ||
} | ||
} | ||
} |
132 changes: 132 additions & 0 deletions
132
...-docker/src/test/java/com/linkedin/metadata/testing/ElasticsearchIntegrationTestTest.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,132 @@ | ||
package com.linkedin.metadata.testing; | ||
|
||
import com.linkedin.metadata.dao.SearchResult; | ||
import com.linkedin.metadata.testing.annotations.SearchIndexMappings; | ||
import com.linkedin.metadata.testing.annotations.SearchIndexSettings; | ||
import com.linkedin.metadata.testing.annotations.SearchIndexType; | ||
import com.linkedin.testing.BarSearchDocument; | ||
import com.linkedin.testing.urn.BarUrn; | ||
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse; | ||
import org.elasticsearch.client.IndicesAdminClient; | ||
import org.elasticsearch.common.settings.Settings; | ||
import org.junit.jupiter.api.Order; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static com.linkedin.metadata.testing.asserts.SearchIndexAssert.assertThat; | ||
import static com.linkedin.metadata.testing.asserts.SearchResultAssert.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
|
||
@ElasticsearchIntegrationTest | ||
public class ElasticsearchIntegrationTestTest { | ||
@SearchIndexType(BarSearchDocument.class) | ||
public static SearchIndex<BarSearchDocument> classIndex; | ||
|
||
@SearchIndexType(BarSearchDocument.class) | ||
@SearchIndexSettings("/settings.json") | ||
@SearchIndexMappings("/mappings.json") | ||
public SearchIndex<BarSearchDocument> searchIndex; | ||
|
||
@SearchIndexType(BarSearchDocument.class) | ||
public SearchIndex<BarSearchDocument> secondSearchIndex; | ||
|
||
private static String _classIndexName; | ||
private static String _methodIndexName; | ||
|
||
@Test | ||
public void staticIndexInjected() { | ||
assertThat(classIndex).isNotNull(); | ||
} | ||
|
||
@Test | ||
public void instanceIndexesInjected() { | ||
assertThat(searchIndex).isNotNull(); | ||
assertThat(secondSearchIndex).isNotNull(); | ||
} | ||
|
||
@Test | ||
public void uniqueIndexesAreMadeForEachVariable() { | ||
assertThat(classIndex.getName()).isNotEqualTo(searchIndex.getName()); | ||
assertThat(searchIndex.getName()).isNotEqualTo(secondSearchIndex.getName()); | ||
} | ||
|
||
@Test | ||
@Order(1) | ||
public void saveIndexNames() { | ||
// not a real test, values used to test the life cycle later | ||
_classIndexName = classIndex.getName(); | ||
_methodIndexName = searchIndex.getName(); | ||
} | ||
|
||
@Test | ||
@Order(2) | ||
public void staticIndexIsSame() { | ||
assertThat(_classIndexName).isEqualTo(classIndex.getName()); | ||
} | ||
|
||
@Test | ||
@Order(2) | ||
public void instanceIndexIsDifferent() { | ||
assertThat(_methodIndexName).isNotEqualTo(searchIndex.getName()); | ||
} | ||
|
||
@Test | ||
@Order(2) | ||
public void instanceIsCleanedUpBetweenMethods() { | ||
// given | ||
final IndicesAdminClient indicesAdminClient = searchIndex.getConnection().getTransportClient().admin().indices(); | ||
|
||
// when | ||
final boolean exists = indicesAdminClient.prepareExists(_methodIndexName).get().isExists(); | ||
|
||
// then | ||
assertThat(exists).isFalse(); | ||
} | ||
|
||
@Test | ||
public void canWriteToIndex() throws Exception { | ||
// given | ||
final BarSearchDocument searchDocument = new BarSearchDocument().setUrn(new BarUrn(42)); | ||
|
||
// when | ||
searchIndex.getWriteDao().upsertDocument(searchDocument, "mydoc"); | ||
searchIndex.getRequestContainer().flushAndSettle(); | ||
|
||
// then | ||
assertThat(searchIndex).bulkRequests().documentIds().containsExactly("mydoc"); | ||
} | ||
|
||
@Test | ||
public void canReadAllFromIndex() throws Exception { | ||
// given | ||
final BarUrn urn = new BarUrn(42); | ||
final BarSearchDocument searchDocument = new BarSearchDocument().setUrn(urn); | ||
searchIndex.getWriteDao().upsertDocument(searchDocument, "mydoc"); | ||
searchIndex.getRequestContainer().flushAndSettle(); | ||
|
||
// when | ||
final SearchResult<BarSearchDocument> result = searchIndex.createReadAllDocumentsDao().search("", null, null, 0, 1); | ||
|
||
// then | ||
assertThat(result).hasNoMoreResults(); | ||
assertThat(result).hasTotalCount(1); | ||
assertThat(result).documents().containsExactly(searchDocument); | ||
assertThat(result).urns().containsExactly(urn); | ||
} | ||
|
||
@Test | ||
public void settingsAndMappingsAnnotation() throws Exception { | ||
// when | ||
final GetSettingsResponse response = searchIndex.getConnection() | ||
.getTransportClient() | ||
.admin() | ||
.indices() | ||
.prepareGetSettings(searchIndex.getName()) | ||
.get(); | ||
final Settings settings = response.getIndexToSettings().get(searchIndex.getName()); | ||
final String actual = settings.get("index.analysis.filter.autocomplete_filter.type"); | ||
|
||
// then | ||
assertThat(actual).isEqualTo("edge_ngram"); | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
...rch-dao-integ-testing-docker/src/test/java/com/linkedin/metadata/testing/ExampleTest.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,56 @@ | ||
package com.linkedin.metadata.testing; | ||
|
||
import com.linkedin.metadata.dao.SearchResult; | ||
import com.linkedin.metadata.testing.annotations.SearchIndexMappings; | ||
import com.linkedin.metadata.testing.annotations.SearchIndexSettings; | ||
import com.linkedin.metadata.testing.annotations.SearchIndexType; | ||
import com.linkedin.metadata.testing.asserts.SearchResultAssert; | ||
import com.linkedin.testing.BarSearchDocument; | ||
import com.linkedin.testing.urn.BarUrn; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static com.linkedin.metadata.testing.asserts.SearchIndexAssert.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
|
||
@ElasticsearchIntegrationTest | ||
public class ExampleTest { | ||
@SearchIndexType(BarSearchDocument.class) | ||
@SearchIndexSettings("/settings.json") | ||
@SearchIndexMappings("/mappings.json") | ||
public SearchIndex<BarSearchDocument> _searchIndex; | ||
|
||
@Test | ||
public void canWriteToIndex() throws Exception { | ||
// given | ||
final BarSearchDocument searchDocument = new BarSearchDocument().setUrn(new BarUrn(42)); | ||
|
||
// when | ||
_searchIndex.getWriteDao().upsertDocument(searchDocument, "mydoc"); | ||
_searchIndex.getRequestContainer().flushAndSettle(); | ||
|
||
// then | ||
assertThat(_searchIndex).bulkRequests().allRequestsSettled(); | ||
assertThat(_searchIndex).bulkRequests().hadNoErrors(); | ||
assertThat(_searchIndex).bulkRequests().documentIds().containsExactly("mydoc"); | ||
} | ||
|
||
@Test | ||
public void canReadAllFromIndex() throws Exception { | ||
// given | ||
final BarUrn urn = new BarUrn(42); | ||
final BarSearchDocument searchDocument = new BarSearchDocument().setUrn(urn); | ||
_searchIndex.getWriteDao().upsertDocument(searchDocument, "mydoc"); | ||
_searchIndex.getRequestContainer().flushAndSettle(); | ||
|
||
// when | ||
final SearchResult<BarSearchDocument> result = | ||
_searchIndex.createReadAllDocumentsDao().search("", null, null, 0, 1); | ||
|
||
// then | ||
SearchResultAssert.assertThat(result).hasNoMoreResults(); | ||
SearchResultAssert.assertThat(result).hasTotalCount(1); | ||
SearchResultAssert.assertThat(result).documents().containsExactly(searchDocument); | ||
SearchResultAssert.assertThat(result).urns().containsExactly(urn); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
testing/elasticsearch-dao-integ-testing-docker/src/test/resources/mappings.json
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,8 @@ | ||
{ | ||
"properties": { | ||
"urn": { | ||
"type": "keyword", | ||
"normalizer": "custom_normalizer" | ||
} | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
testing/elasticsearch-dao-integ-testing-docker/src/test/resources/settings.json
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,53 @@ | ||
{ | ||
"index": { | ||
"analysis": { | ||
"filter": { | ||
"autocomplete_filter": { | ||
"type": "edge_ngram", | ||
"min_gram": "3", | ||
"max_gram": "20" | ||
}, | ||
"custom_delimiter": { | ||
"split_on_numerics": "false", | ||
"split_on_case_change": "false", | ||
"type": "word_delimiter", | ||
"preserve_original": "true", | ||
"catenate_words": "false" | ||
} | ||
}, | ||
"normalizer": { | ||
"custom_normalizer": { | ||
"filter": [ | ||
"lowercase", | ||
"asciifolding" | ||
], | ||
"type": "custom" | ||
} | ||
}, | ||
"analyzer": { | ||
"delimit_edgengram": { | ||
"filter": [ | ||
"lowercase", | ||
"custom_delimiter", | ||
"autocomplete_filter" | ||
], | ||
"tokenizer": "whitespace" | ||
}, | ||
"delimit": { | ||
"filter": [ | ||
"lowercase", | ||
"custom_delimiter" | ||
], | ||
"tokenizer": "whitespace" | ||
}, | ||
"lowercase_keyword": { | ||
"filter": [ | ||
"lowercase" | ||
], | ||
"type": "custom", | ||
"tokenizer": "keyword" | ||
} | ||
} | ||
} | ||
} | ||
} |
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
Oops, something went wrong.