Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

elastic-search: remove default index migrator #492

Merged
merged 1 commit into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import co.elastic.clients.transport.rest_client.RestClientTransport
import com.trendyol.stove.functional.*
import com.trendyol.stove.testing.e2e.system.TestSystem
import com.trendyol.stove.testing.e2e.system.abstractions.*
import kotlinx.coroutines.*
import kotlinx.coroutines.runBlocking
import org.apache.http.HttpHost
import org.apache.http.auth.*
import org.apache.http.client.CredentialsProvider
Expand All @@ -24,7 +24,7 @@ import kotlin.jvm.optionals.getOrElse
@ElasticDsl
class ElasticsearchSystem internal constructor(
override val testSystem: TestSystem,
val context: ElasticsearchContext
private val context: ElasticsearchContext
) : PluggedSystem, RunAware, AfterRunAware, ExposesConfiguration {
@PublishedApi
internal lateinit var esClient: ElasticsearchClient
Expand Down Expand Up @@ -67,38 +67,40 @@ class ElasticsearchSystem internal constructor(
@ElasticDsl
inline fun <reified T : Any> shouldQuery(
query: String,
index: String,
assertion: (List<T>) -> Unit
): ElasticsearchSystem =
esClient.search(
SearchRequest.of { req ->
req.index(context.index).query { q -> q.withJson(query.reader()) }
},
): ElasticsearchSystem {
require(index.isNotBlank()) { "Index cannot be blank" }
require(query.isNotBlank()) { "Query cannot be blank" }
return esClient.search(
SearchRequest.of { req -> req.index(index).query { q -> q.withJson(query.reader()) } },
T::class.java
).hits().hits()
.mapNotNull { it.source() }
.also(assertion)
.let { this }
}

@ElasticDsl
inline fun <reified T : Any> shouldQuery(
query: Query,
assertion: (List<T>) -> Unit
): ElasticsearchSystem =
esClient.search(
SearchRequest.of { q -> q.query(query) },
T::class.java
).hits().hits()
.mapNotNull { it.source() }
.also(assertion)
.let { this }
): ElasticsearchSystem = esClient.search(
SearchRequest.of { q -> q.query(query) },
T::class.java
).hits().hits()
.mapNotNull { it.source() }
.also(assertion)
.let { this }

@ElasticDsl
inline fun <reified T : Any> shouldGet(
index: String = context.index,
index: String,
key: String,
assertion: (T) -> Unit
): ElasticsearchSystem {
require(index.isNotBlank()) { "Index cannot be blank" }
require(key.isNotBlank()) { "Key cannot be blank" }
return esClient
.get({ req -> req.index(index).id(key).refresh(true) }, T::class.java)
.source().toOption()
Expand All @@ -110,9 +112,11 @@ class ElasticsearchSystem internal constructor(
@ElasticDsl
fun shouldNotExist(
key: String,
onIndex: String = context.index
index: String
): ElasticsearchSystem {
val exists = esClient.exists { req -> req.index(onIndex).id(key) }
require(index.isNotBlank()) { "Index cannot be blank" }
require(key.isNotBlank()) { "Key cannot be blank" }
val exists = esClient.exists { req -> req.index(index).id(key) }
if (exists.value()) {
throw AssertionError("The document with the given id($key) was not expected, but found!")
}
Expand All @@ -122,24 +126,30 @@ class ElasticsearchSystem internal constructor(
@ElasticDsl
fun shouldDelete(
key: String,
fromIndex: String = context.index
): ElasticsearchSystem =
esClient
.delete(DeleteRequest.of { req -> req.index(fromIndex).id(key).refresh(Refresh.WaitFor) })
index: String
): ElasticsearchSystem {
require(index.isNotBlank()) { "Index cannot be blank" }
require(key.isNotBlank()) { "Key cannot be blank" }
return esClient
.delete(DeleteRequest.of { req -> req.index(index).id(key).refresh(Refresh.WaitFor) })
.let { this }
}

@ElasticDsl
fun <T : Any> save(
id: String,
instance: T,
toIndex: String = context.index
): ElasticsearchSystem =
esClient.index { req ->
req.index(toIndex)
index: String
): ElasticsearchSystem {
require(index.isNotBlank()) { "Index cannot be blank" }
require(id.isNotBlank()) { "Id cannot be blank" }
return esClient.index { req ->
req.index(index)
.id(id)
.document(instance)
.refresh(Refresh.WaitFor)
}.let { this }
}

/**
* Pauses the container. Use with care, as it will pause the container which might affect other tests.
Expand All @@ -155,20 +165,14 @@ class ElasticsearchSystem internal constructor(
@ElasticDsl
fun unpause(): ElasticsearchSystem = context.container.unpause().let { this }

override fun close(): Unit =
runBlocking(context = Dispatchers.IO) {
Try {
esClient._transport().close()
executeWithReuseCheck { stop() }
}.recover { logger.warn("got an error while stopping elasticsearch: ${it.message}") }
}
override fun close(): Unit = runBlocking {
Try {
esClient._transport().close()
executeWithReuseCheck { stop() }
}.recover { logger.warn("got an error while stopping elasticsearch: ${it.message}") }
}

override fun configuration(): List<String> =
context.options.configureExposedConfiguration(exposedConfiguration) +
listOf(
"elasticsearch.host=${exposedConfiguration.host}",
"elasticsearch.port=${exposedConfiguration.port}"
)
override fun configuration(): List<String> = context.options.configureExposedConfiguration(exposedConfiguration)

private fun createEsClient(exposedConfiguration: ElasticSearchExposedConfiguration): ElasticsearchClient =
context.options.clientConfigurer.restClientOverrideFn
Expand All @@ -195,9 +199,8 @@ class ElasticsearchSystem internal constructor(
AuthScope.ANY,
UsernamePasswordCredentials("elastic", exposedConfiguration.password)
)
val builder: RestClientBuilder =
RestClient
.builder(HttpHost(exposedConfiguration.host, exposedConfiguration.port, "https"))
val builder: RestClientBuilder = RestClient
.builder(HttpHost(exposedConfiguration.host, exposedConfiguration.port, "https"))

return builder.setHttpClientConfigCallback { clientBuilder: HttpAsyncClientBuilder ->
clientBuilder.setSSLContext(sslContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,10 @@ import com.trendyol.stove.testing.e2e.system.annotations.StoveDsl
/**
* Integrates Elasticsearch with the TestSystem.
*
* Provides an [options] class to define [DefaultIndex] parameter to create an index as default index.
* Provides an [options] class to configure the Elasticsearch container.
* You can configure it by changing the implementation of migrator.
*/
internal fun TestSystem.withElasticsearch(options: ElasticsearchSystemOptions): TestSystem {
options.migrations {
register<DefaultIndexMigrator> { options.defaultIndex.migrator }
}

options.objectMapper.registerArrowModule()

return withProvidedRegistry(
Expand All @@ -34,7 +30,7 @@ internal fun TestSystem.withElasticsearch(options: ElasticsearchSystemOptions):
withReuse(this@withElasticsearch.options.keepDependenciesRunning)
options.container.containerFn(this)
}
.let { getOrRegister(ElasticsearchSystem(this, ElasticsearchContext(options.defaultIndex.index, it, options))) }
.let { getOrRegister(ElasticsearchSystem(this, ElasticsearchContext(it, options))) }
.let { this }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import kotlin.time.Duration.Companion.minutes

@StoveDsl
data class ElasticsearchSystemOptions(
val defaultIndex: DefaultIndex,
val clientConfigurer: ElasticClientConfigurer = ElasticClientConfigurer(),
val container: ElasticContainerOptions = ElasticContainerOptions(),
val objectMapper: ObjectMapper = StoveObjectMapper.Default,
Expand Down Expand Up @@ -46,7 +45,6 @@ data class ElasticSearchExposedConfiguration(
) : ExposedConfiguration

data class ElasticsearchContext(
val index: String,
val container: StoveElasticSearchContainer,
val options: ElasticsearchSystemOptions
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package com.trendyol.stove.testing.e2e.elasticsearch

import co.elastic.clients.elasticsearch._types.query_dsl.QueryVariant

fun QueryVariant.asJsonString(): String = this._toQuery().toString().removePrefix("Query:")
internal fun QueryVariant.asJsonString(): String = this._toQuery().toString().removePrefix("Query:")
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import co.elastic.clients.elasticsearch.ElasticsearchClient
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.trendyol.stove.testing.e2e.database.migrations.DatabaseMigration
import com.trendyol.stove.testing.e2e.database.migrations.MigrationPriority
import com.trendyol.stove.testing.e2e.database.migrations.*
import com.trendyol.stove.testing.e2e.system.TestSystem
import com.trendyol.stove.testing.e2e.system.abstractions.ApplicationUnderTest
import io.kotest.core.config.AbstractProjectConfig
Expand All @@ -15,8 +14,7 @@ import io.kotest.matchers.shouldBe
import org.apache.http.HttpHost
import org.elasticsearch.client.RestClient
import org.junit.jupiter.api.assertThrows
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.slf4j.*
import java.util.*

const val TEST_INDEX = "stove-test-index"
Expand Down Expand Up @@ -51,24 +49,21 @@ class AnotherIndexMigrator : DatabaseMigration<ElasticsearchClient> {
}

class Setup : AbstractProjectConfig() {
override suspend fun beforeProject(): Unit =
TestSystem()
.with {
elasticsearch {
ElasticsearchSystemOptions(
DefaultIndex(index = TEST_INDEX, migrator = TestIndexMigrator()),
clientConfigurer =
ElasticClientConfigurer(
restClientOverrideFn =
Some { cfg ->
RestClient.builder(HttpHost(cfg.host, cfg.port)).build()
}
),
ElasticContainerOptions(tag = "8.9.0")
).migrations { register<AnotherIndexMigrator>() }
override suspend fun beforeProject(): Unit = TestSystem()
.with {
elasticsearch {
ElasticsearchSystemOptions(
clientConfigurer = ElasticClientConfigurer(
restClientOverrideFn = Some { cfg -> RestClient.builder(HttpHost(cfg.host, cfg.port)).build() }
),
ElasticContainerOptions(tag = "8.9.0")
).migrations {
register<TestIndexMigrator>()
register<AnotherIndexMigrator>()
}
applicationUnderTest(NoOpApplication())
}.run()
}
applicationUnderTest(NoOpApplication())
}.run()

override suspend fun afterProject(): Unit = TestSystem.stop()
}
Expand All @@ -90,8 +85,8 @@ class ElasticsearchTestSystemTests : FunSpec({
val exampleInstance = ExampleInstance("1", "1312")
TestSystem.validate {
elasticsearch {
save(exampleInstance.id, exampleInstance)
shouldGet<ExampleInstance>(key = exampleInstance.id) {
save(exampleInstance.id, exampleInstance, TEST_INDEX)
shouldGet<ExampleInstance>(key = exampleInstance.id, index = TEST_INDEX) {
it.description shouldBe exampleInstance.description
}
}
Expand All @@ -118,14 +113,14 @@ class ElasticsearchTestSystemTests : FunSpec({
val queryAsString = queryByDesc.asJsonString()
TestSystem.validate {
elasticsearch {
save(exampleInstance1.id, exampleInstance1)
save(exampleInstance2.id, exampleInstance2)
save(exampleInstance1.id, exampleInstance1, TEST_INDEX)
save(exampleInstance2.id, exampleInstance2, TEST_INDEX)
shouldQuery<ExampleInstance>(queryByDesc._toQuery()) {
it.size shouldBe 2
}
shouldDelete(exampleInstance1.id)
shouldGet<ExampleInstance>(key = exampleInstance2.id) {}
shouldQuery<ExampleInstance>(queryAsString) {
shouldDelete(exampleInstance1.id, TEST_INDEX)
shouldGet<ExampleInstance>(key = exampleInstance2.id, index = TEST_INDEX) {}
shouldQuery<ExampleInstance>(queryAsString, TEST_INDEX) {
it.size shouldBe 1
}
}
Expand All @@ -137,12 +132,12 @@ class ElasticsearchTestSystemTests : FunSpec({
val exampleInstance = ExampleInstance(existDocId, "1312")
TestSystem.validate {
elasticsearch {
save(exampleInstance.id, exampleInstance)
shouldGet<ExampleInstance>(key = exampleInstance.id) {
save(exampleInstance.id, exampleInstance, TEST_INDEX)
shouldGet<ExampleInstance>(key = exampleInstance.id, index = TEST_INDEX) {
it.description shouldBe exampleInstance.description
}

assertThrows<AssertionError> { shouldNotExist(existDocId) }
assertThrows<AssertionError> { shouldNotExist(existDocId, index = TEST_INDEX) }
}
}
}
Expand All @@ -151,7 +146,7 @@ class ElasticsearchTestSystemTests : FunSpec({
val notExistDocId = UUID.randomUUID().toString()
TestSystem.validate {
elasticsearch {
shouldNotExist(notExistDocId)
shouldNotExist(notExistDocId, index = TEST_INDEX)
}
}
}
Expand Down
Loading