|
| 1 | +package com.trendyol.stove.testing.e2e |
| 2 | + |
| 3 | +import arrow.core.getOrElse |
| 4 | +import com.trendyol.stove.testing.e2e.system.TestSystem |
| 5 | +import com.trendyol.stove.testing.e2e.system.ValidationDsl |
| 6 | +import com.trendyol.stove.testing.e2e.system.WithDsl |
| 7 | +import com.trendyol.stove.testing.e2e.system.abstractions.AfterRunAwareWithContext |
| 8 | +import com.trendyol.stove.testing.e2e.system.abstractions.ExperimentalStoveDsl |
| 9 | +import com.trendyol.stove.testing.e2e.system.abstractions.PluggedSystem |
| 10 | +import com.trendyol.stove.testing.e2e.system.abstractions.SystemNotRegisteredException |
| 11 | +import org.springframework.beans.factory.getBean |
| 12 | +import org.springframework.context.ApplicationContext |
| 13 | + |
| 14 | +/** |
| 15 | + * A system that provides a bridge between the test system and the application context. |
| 16 | + * |
| 17 | + * @property testSystem the test system to bridge. |
| 18 | + */ |
| 19 | +class BridgeSystem(override val testSystem: TestSystem) : PluggedSystem, AfterRunAwareWithContext<ApplicationContext> { |
| 20 | + |
| 21 | + /** |
| 22 | + * The application context used to resolve dependencies. |
| 23 | + */ |
| 24 | + lateinit var ctx: ApplicationContext |
| 25 | + |
| 26 | + /** |
| 27 | + * Closes the bridge system. |
| 28 | + */ |
| 29 | + override fun close(): Unit = Unit |
| 30 | + |
| 31 | + /** |
| 32 | + * Initializes the bridge system after the test run. |
| 33 | + * |
| 34 | + * @param context the application context. |
| 35 | + */ |
| 36 | + override suspend fun afterRun(context: ApplicationContext) { |
| 37 | + ctx = context |
| 38 | + } |
| 39 | + |
| 40 | + /** |
| 41 | + * Resolves a bean of the specified type from the application context. |
| 42 | + * |
| 43 | + * @param T the type of bean to resolve. |
| 44 | + * @return the resolved bean. |
| 45 | + */ |
| 46 | + @PublishedApi |
| 47 | + internal inline fun <reified T : Any> resolve(): T = ctx.getBean() |
| 48 | + |
| 49 | + /** |
| 50 | + * Executes the specified validation function using the resolved bean. |
| 51 | + * |
| 52 | + * @param T the type of object being validated. |
| 53 | + * @param validation the validation function to apply to the object. |
| 54 | + */ |
| 55 | + inline fun <reified T : Any> using(validation: T.() -> Unit): Unit = validation(resolve()) |
| 56 | +} |
| 57 | + |
| 58 | +/** |
| 59 | + * Adds a bridge system to the test system and returns the modified test system. |
| 60 | + * |
| 61 | + * @receiver the test system to modify. |
| 62 | + * @return the modified test system. |
| 63 | + */ |
| 64 | +fun TestSystem.withBridgeSystem(): TestSystem = getOrRegister(BridgeSystem(this)).let { this } |
| 65 | + |
| 66 | +/** |
| 67 | + * Returns the bridge system associated with the test system. |
| 68 | + * |
| 69 | + * @receiver the test system. |
| 70 | + * @return the bridge system. |
| 71 | + * @throws SystemNotRegisteredException if the bridge system is not registered. |
| 72 | + */ |
| 73 | +@ExperimentalStoveDsl |
| 74 | +fun WithDsl.bridge(): TestSystem = this.testSystem.withBridgeSystem() |
| 75 | + |
| 76 | +/** |
| 77 | + * Returns the bridge system associated with the test system. |
| 78 | + * This function is only available in the validation DSL. |
| 79 | + * |
| 80 | + * @receiver the test system. |
| 81 | + * @return the bridge system. |
| 82 | + * @throws SystemNotRegisteredException if the bridge system is not registered. |
| 83 | + */ |
| 84 | +fun TestSystem.bridge(): BridgeSystem = getOrNone<BridgeSystem>().getOrElse { throw SystemNotRegisteredException(BridgeSystem::class) } |
| 85 | + |
| 86 | +/** |
| 87 | + * Executes the specified validation function using the resolved bean from the bridge system. |
| 88 | + * Resolved beans are using physical components of the application. |
| 89 | + * |
| 90 | + * Suggested usage: validating or preparing the application state without accessing the physical components directly. |
| 91 | + * ```kotlin |
| 92 | + * TestSystem.validate { |
| 93 | + * using<PersonService> { |
| 94 | + * this.serviceName shouldBe "personService" |
| 95 | + * this.find(userId = 123) shouldBe Person(id = 123, name = "John Doe") |
| 96 | + * } |
| 97 | + * } |
| 98 | + * ``` |
| 99 | + * |
| 100 | + * @receiver the validation DSL. |
| 101 | + * @param T the type of object being validated. |
| 102 | + * @param validation the validation function to apply to the object. |
| 103 | + */ |
| 104 | +inline fun <reified T : Any> ValidationDsl.using(validation: T.() -> Unit): Unit = this.testSystem.bridge().using(validation) |
0 commit comments