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

Support for bridging app to the validation context #176

Merged
merged 1 commit into from
Jul 27, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,27 @@ import com.trendyol.stove.testing.e2e.kafka.KafkaSystem.Companion.shouldBeFailed
import com.trendyol.stove.testing.e2e.kafka.KafkaSystem.Companion.shouldBePublishedOnCondition
import com.trendyol.stove.testing.e2e.kafka.kafka
import com.trendyol.stove.testing.e2e.system.TestSystem
import com.trendyol.stove.testing.e2e.using
import com.trendyol.stove.testing.e2e.wiremock.wiremock
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.string.shouldContain
import stove.spring.example.application.handlers.ProductCreateRequest
import stove.spring.example.application.handlers.ProductCreatedEvent
import stove.spring.example.application.services.SupplierPermission
import stove.spring.example.infrastructure.couchbase.CouchbaseProperties
import stove.spring.example.infrastructure.messaging.kafka.consumers.BusinessException
import stove.spring.example.infrastructure.messaging.kafka.consumers.ProductCreateEvent

class ExampleTest : FunSpec({
test("bridge should work") {
TestSystem.validate {
using<CouchbaseProperties> {
this.bucketName shouldBe "Stove"
}
}
}

test("index should be reachable") {
TestSystem.validate {
http {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stove.spring.example.e2e

import com.trendyol.stove.testing.e2e.bridge
import com.trendyol.stove.testing.e2e.couchbase.CouchbaseSystemOptions
import com.trendyol.stove.testing.e2e.couchbase.couchbase
import com.trendyol.stove.testing.e2e.http.httpClient
Expand Down Expand Up @@ -27,6 +28,7 @@ class TestSystemConfig : AbstractProjectConfig() {
kafka {
KafkaSystemOptions(containerOptions = KafkaContainerOptions(tag = "latest"))
}
bridge()
wiremock {
WireMockSystemOptions(
port = 9099,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.trendyol.stove.testing.e2e

import arrow.core.getOrElse
import com.trendyol.stove.testing.e2e.system.TestSystem
import com.trendyol.stove.testing.e2e.system.ValidationDsl
import com.trendyol.stove.testing.e2e.system.WithDsl
import com.trendyol.stove.testing.e2e.system.abstractions.AfterRunAwareWithContext
import com.trendyol.stove.testing.e2e.system.abstractions.ExperimentalStoveDsl
import com.trendyol.stove.testing.e2e.system.abstractions.PluggedSystem
import com.trendyol.stove.testing.e2e.system.abstractions.SystemNotRegisteredException
import org.springframework.beans.factory.getBean
import org.springframework.context.ApplicationContext

/**
* A system that provides a bridge between the test system and the application context.
*
* @property testSystem the test system to bridge.
*/
class BridgeSystem(override val testSystem: TestSystem) : PluggedSystem, AfterRunAwareWithContext<ApplicationContext> {

/**
* The application context used to resolve dependencies.
*/
lateinit var ctx: ApplicationContext

/**
* Closes the bridge system.
*/
override fun close(): Unit = Unit

/**
* Initializes the bridge system after the test run.
*
* @param context the application context.
*/
override suspend fun afterRun(context: ApplicationContext) {
ctx = context
}

/**
* Resolves a bean of the specified type from the application context.
*
* @param T the type of bean to resolve.
* @return the resolved bean.
*/
@PublishedApi
internal inline fun <reified T : Any> resolve(): T = ctx.getBean()

/**
* Executes the specified validation function using the resolved bean.
*
* @param T the type of object being validated.
* @param validation the validation function to apply to the object.
*/
inline fun <reified T : Any> using(validation: T.() -> Unit): Unit = validation(resolve())
}

/**
* Adds a bridge system to the test system and returns the modified test system.
*
* @receiver the test system to modify.
* @return the modified test system.
*/
fun TestSystem.withBridgeSystem(): TestSystem = getOrRegister(BridgeSystem(this)).let { this }

/**
* Returns the bridge system associated with the test system.
*
* @receiver the test system.
* @return the bridge system.
* @throws SystemNotRegisteredException if the bridge system is not registered.
*/
@ExperimentalStoveDsl
fun WithDsl.bridge(): TestSystem = this.testSystem.withBridgeSystem()

/**
* Returns the bridge system associated with the test system.
* This function is only available in the validation DSL.
*
* @receiver the test system.
* @return the bridge system.
* @throws SystemNotRegisteredException if the bridge system is not registered.
*/
fun TestSystem.bridge(): BridgeSystem = getOrNone<BridgeSystem>().getOrElse { throw SystemNotRegisteredException(BridgeSystem::class) }

/**
* Executes the specified validation function using the resolved bean from the bridge system.
* Resolved beans are using physical components of the application.
*
* Suggested usage: validating or preparing the application state without accessing the physical components directly.
* ```kotlin
* TestSystem.validate {
* using<PersonService> {
* this.serviceName shouldBe "personService"
* this.find(userId = 123) shouldBe Person(id = 123, name = "John Doe")
* }
* }
* ```
*
* @receiver the validation DSL.
* @param T the type of object being validated.
* @param validation the validation function to apply to the object.
*/
inline fun <reified T : Any> ValidationDsl.using(validation: T.() -> Unit): Unit = this.testSystem.bridge().using(validation)