diff --git a/ok-marketplace-be/ok-marketplace-api-v1-jackson/src/main/kotlin/ApiV1Mapper.kt b/ok-marketplace-be/ok-marketplace-api-v1-jackson/src/main/kotlin/ApiV1Mapper.kt index 2a6f843..d1d713a 100644 --- a/ok-marketplace-be/ok-marketplace-api-v1-jackson/src/main/kotlin/ApiV1Mapper.kt +++ b/ok-marketplace-be/ok-marketplace-api-v1-jackson/src/main/kotlin/ApiV1Mapper.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.MapperFeature import com.fasterxml.jackson.databind.json.JsonMapper import ru.otus.otuskotlin.marketplace.api.v1.models.IRequest import ru.otus.otuskotlin.marketplace.api.v1.models.IResponse + val apiV1Mapper = JsonMapper.builder().run { // configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) enable(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL) diff --git a/ok-marketplace-be/ok-marketplace-api-v2-kmp/src/commonMain/kotlin/mappers/MappersV2ToTransport.kt b/ok-marketplace-be/ok-marketplace-api-v2-kmp/src/commonMain/kotlin/mappers/MappersV2ToTransport.kt index cfa3da0..67a27a1 100644 --- a/ok-marketplace-be/ok-marketplace-api-v2-kmp/src/commonMain/kotlin/mappers/MappersV2ToTransport.kt +++ b/ok-marketplace-be/ok-marketplace-api-v2-kmp/src/commonMain/kotlin/mappers/MappersV2ToTransport.kt @@ -89,14 +89,14 @@ private fun MkplAdPermissionClient.toTransportAd() = when (this) { MkplAdPermissionClient.DELETE -> AdPermissions.DELETE } -private fun MkplVisibility.toTransportAd(): AdVisibility? = when (this) { +fun MkplVisibility.toTransportAd(): AdVisibility? = when (this) { MkplVisibility.VISIBLE_PUBLIC -> AdVisibility.PUBLIC MkplVisibility.VISIBLE_TO_GROUP -> AdVisibility.REGISTERED_ONLY MkplVisibility.VISIBLE_TO_OWNER -> AdVisibility.OWNER_ONLY MkplVisibility.NONE -> null } -private fun MkplDealSide.toTransportAd(): DealSide? = when (this) { +fun MkplDealSide.toTransportAd(): DealSide? = when (this) { MkplDealSide.DEMAND -> DealSide.DEMAND MkplDealSide.SUPPLY -> DealSide.SUPPLY MkplDealSide.NONE -> null diff --git a/ok-marketplace-be/ok-marketplace-app-ktor/build.gradle.kts b/ok-marketplace-be/ok-marketplace-app-ktor/build.gradle.kts index 9539e60..8e09662 100644 --- a/ok-marketplace-be/ok-marketplace-app-ktor/build.gradle.kts +++ b/ok-marketplace-be/ok-marketplace-app-ktor/build.gradle.kts @@ -74,6 +74,11 @@ kotlin { implementation(libs.kotlinx.serialization.json) implementation(libs.ktor.serialization.json) + // DB + implementation(projects.okMarketplaceRepoCommon) + implementation(projects.okMarketplaceRepoStubs) + implementation(projects.okMarketplaceRepoInmemory) + // logging implementation(project(":ok-marketplace-api-log1")) implementation("ru.otus.otuskotlin.marketplace.libs:ok-marketplace-lib-logging-common") diff --git a/ok-marketplace-be/ok-marketplace-app-ktor/src/commonMain/kotlin/MkplAppSettings.kt b/ok-marketplace-be/ok-marketplace-app-ktor/src/commonMain/kotlin/MkplAppSettings.kt index 8619375..15607ba 100644 --- a/ok-marketplace-be/ok-marketplace-app-ktor/src/commonMain/kotlin/MkplAppSettings.kt +++ b/ok-marketplace-be/ok-marketplace-app-ktor/src/commonMain/kotlin/MkplAppSettings.kt @@ -8,4 +8,4 @@ data class MkplAppSettings( val appUrls: List = emptyList(), override val corSettings: MkplCorSettings = MkplCorSettings(), override val processor: MkplAdProcessor = MkplAdProcessor(corSettings), -): IMkplAppSettings +) : IMkplAppSettings diff --git a/ok-marketplace-be/ok-marketplace-app-ktor/src/commonMain/kotlin/plugins/InitAppSettings.kt b/ok-marketplace-be/ok-marketplace-app-ktor/src/commonMain/kotlin/plugins/InitAppSettings.kt index 5855ea9..10fd784 100644 --- a/ok-marketplace-be/ok-marketplace-app-ktor/src/commonMain/kotlin/plugins/InitAppSettings.kt +++ b/ok-marketplace-be/ok-marketplace-app-ktor/src/commonMain/kotlin/plugins/InitAppSettings.kt @@ -3,13 +3,18 @@ package ru.otus.otuskotlin.marketplace.app.ktor.plugins import io.ktor.server.application.* import ru.otus.otuskotlin.marketplace.app.ktor.MkplAppSettings import ru.otus.otuskotlin.marketplace.app.ktor.base.KtorWsSessionRepo +import ru.otus.otuskotlin.marketplace.backend.repository.inmemory.AdRepoStub import ru.otus.otuskotlin.marketplace.biz.MkplAdProcessor import ru.otus.otuskotlin.marketplace.common.MkplCorSettings +import ru.otus.otuskotlin.marketplace.repo.inmemory.AdRepoInMemory fun Application.initAppSettings(): MkplAppSettings { val corSettings = MkplCorSettings( loggerProvider = getLoggerProviderConf(), wsSessions = KtorWsSessionRepo(), + repoTest = AdRepoInMemory(), + repoProd = AdRepoInMemory(), + repoStub = AdRepoStub(), ) return MkplAppSettings( appUrls = environment.config.propertyOrNull("ktor.urls")?.getList() ?: emptyList(), diff --git a/ok-marketplace-be/ok-marketplace-app-ktor/src/commonTest/kotlin/repo/V2AdRepoBaseTest.kt b/ok-marketplace-be/ok-marketplace-app-ktor/src/commonTest/kotlin/repo/V2AdRepoBaseTest.kt new file mode 100644 index 0000000..2e986ec --- /dev/null +++ b/ok-marketplace-be/ok-marketplace-app-ktor/src/commonTest/kotlin/repo/V2AdRepoBaseTest.kt @@ -0,0 +1,181 @@ +package ru.otus.otuskotlin.marketplace.app.ktor.repo + +import io.ktor.client.call.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.request.* +import io.ktor.client.statement.* +import io.ktor.http.* +import io.ktor.serialization.kotlinx.json.* +import io.ktor.server.testing.* +import ru.otus.otuskotlin.marketplace.api.v2.apiV2Mapper +import ru.otus.otuskotlin.marketplace.api.v2.mappers.toTransportAd +import ru.otus.otuskotlin.marketplace.api.v2.models.* +import ru.otus.otuskotlin.marketplace.app.ktor.MkplAppSettings +import ru.otus.otuskotlin.marketplace.app.ktor.module +import ru.otus.otuskotlin.marketplace.common.models.MkplAdId +import ru.otus.otuskotlin.marketplace.common.models.MkplAdLock +import ru.otus.otuskotlin.marketplace.common.models.MkplDealSide +import ru.otus.otuskotlin.marketplace.stubs.MkplAdStub +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotEquals + +abstract class V2AdRepoBaseTest { + abstract val workMode: AdRequestDebugMode + abstract val appSettingsCreate: MkplAppSettings + abstract val appSettingsRead: MkplAppSettings + abstract val appSettingsUpdate: MkplAppSettings + abstract val appSettingsDelete: MkplAppSettings + abstract val appSettingsSearch: MkplAppSettings + abstract val appSettingsOffers: MkplAppSettings + + protected val uuidOld = "10000000-0000-0000-0000-000000000001" + protected val uuidNew = "10000000-0000-0000-0000-000000000002" + protected val uuidSup = "10000000-0000-0000-0000-000000000003" + protected val initAd = MkplAdStub.prepareResult { + id = MkplAdId(uuidOld) + adType = MkplDealSide.DEMAND + lock = MkplAdLock(uuidOld) + } + protected val initAdSupply = MkplAdStub.prepareResult { + id = MkplAdId(uuidSup) + adType = MkplDealSide.SUPPLY + } + + + @Test + fun create() { + val createAd = AdCreateObject( + title = initAd.title, + description = initAd.description, + adType = initAd.adType.toTransportAd(), + visibility = initAd.visibility.toTransportAd(), + ) + v2TestApplication( + conf = appSettingsCreate, + func = "create", + request = AdCreateRequest( + ad = createAd, + debug = AdDebug(mode = workMode), + ), + ) { response -> + val responseObj = response.body() as AdCreateResponse + assertEquals(200, response.status.value) + assertEquals(uuidNew, responseObj.ad?.id) + assertEquals(createAd.title, responseObj.ad?.title) + assertEquals(createAd.description, responseObj.ad?.description) + assertEquals(createAd.adType, responseObj.ad?.adType) + assertEquals(createAd.visibility, responseObj.ad?.visibility) + } + } + + @Test + fun read() = v2TestApplication( + conf = appSettingsRead, + func = "read", + request = AdReadRequest( + ad = AdReadObject(uuidOld), + debug = AdDebug(mode = workMode), + ), + ) { response -> + val responseObj = response.body() as AdReadResponse + assertEquals(200, response.status.value) + assertEquals(uuidOld, responseObj.ad?.id) + } + + @Test + fun update() { + val adUpdate = AdUpdateObject( + id = uuidOld, + title = initAd.title, + description = initAd.description, + adType = initAd.adType.toTransportAd(), + visibility = initAd.visibility.toTransportAd(), + lock = initAd.lock.asString(), + ) + v2TestApplication( + conf = appSettingsUpdate, + func = "update", + request = AdUpdateRequest( + ad = adUpdate, + debug = AdDebug(mode = workMode), + ), + ) { response -> + val responseObj = response.body() as AdUpdateResponse + assertEquals(200, response.status.value) + assertEquals(adUpdate.id, responseObj.ad?.id) + assertEquals(adUpdate.title, responseObj.ad?.title) + assertEquals(adUpdate.description, responseObj.ad?.description) + assertEquals(adUpdate.adType, responseObj.ad?.adType) + assertEquals(adUpdate.visibility, responseObj.ad?.visibility) + } + } + @Test + fun delete() = v2TestApplication( + conf = appSettingsDelete, + func = "delete", + request = AdDeleteRequest( + ad = AdDeleteObject( + id = uuidOld, + lock = initAd.lock.asString(), + ), + debug = AdDebug(mode = workMode), + ), + ) { response -> + val responseObj = response.body() as AdDeleteResponse + assertEquals(200, response.status.value) + assertEquals(uuidOld, responseObj.ad?.id) + } + + @Test + fun search() = v2TestApplication( + conf = appSettingsSearch, + func = "search", + request = AdSearchRequest( + adFilter = AdSearchFilter(), + debug = AdDebug(mode = workMode), + ), + ) { response -> + val responseObj = response.body() as AdSearchResponse + assertEquals(200, response.status.value) + assertNotEquals(0, responseObj.ads?.size) + assertEquals(uuidOld, responseObj.ads?.first()?.id) + } + + @Test + fun offers() = v2TestApplication( + conf = appSettingsOffers, + func = "offers", + request = AdOffersRequest( + ad = AdReadObject( + id = uuidOld, + ), + debug = AdDebug(mode = workMode), + ), + ) { response -> + val responseObj = response.body() as AdOffersResponse + assertEquals(200, response.status.value) + assertNotEquals(0, responseObj.ads?.size) + assertEquals(uuidSup, responseObj.ads?.first()?.id) + } + + private inline fun v2TestApplication( + conf: MkplAppSettings, + func: String, + request: T, + crossinline function: suspend (HttpResponse) -> Unit, + ): Unit = testApplication { + application { module(appSettings = conf) } + val client = createClient { + install(ContentNegotiation) { + json(apiV2Mapper) + } + } + val response = client.post("/v2/ad/$func") { + contentType(ContentType.Application.Json) + header("X-Trace-Id", "12345") + setBody(request) + } + function(response) + } +} diff --git a/ok-marketplace-be/ok-marketplace-app-ktor/src/commonTest/kotlin/repo/V2AdRepoInmemoryTest.kt b/ok-marketplace-be/ok-marketplace-app-ktor/src/commonTest/kotlin/repo/V2AdRepoInmemoryTest.kt new file mode 100644 index 0000000..065dc3d --- /dev/null +++ b/ok-marketplace-be/ok-marketplace-app-ktor/src/commonTest/kotlin/repo/V2AdRepoInmemoryTest.kt @@ -0,0 +1,51 @@ +package ru.otus.otuskotlin.marketplace.app.ktor.repo + +import ru.otus.otuskotlin.marketplace.api.v2.models.AdRequestDebugMode +import ru.otus.otuskotlin.marketplace.app.ktor.MkplAppSettings +import ru.otus.otuskotlin.marketplace.common.MkplCorSettings +import ru.otus.otuskotlin.marketplace.common.repo.IRepoAd +import ru.otus.otuskotlin.marketplace.repo.common.AdRepoInitialized +import ru.otus.otuskotlin.marketplace.repo.inmemory.AdRepoInMemory + +class V2AdRepoInmemoryTest : V2AdRepoBaseTest() { + override val workMode: AdRequestDebugMode = AdRequestDebugMode.TEST + private fun mkAppSettings(repo: IRepoAd) = MkplAppSettings( + corSettings = MkplCorSettings( + repoTest = repo + ) + ) + + override val appSettingsCreate: MkplAppSettings = mkAppSettings( + repo = AdRepoInitialized(AdRepoInMemory(randomUuid = { uuidNew })) + ) + override val appSettingsRead: MkplAppSettings = mkAppSettings( + repo = AdRepoInitialized( + AdRepoInMemory(randomUuid = { uuidNew }), + initObjects = listOf(initAd), + ) + ) + override val appSettingsUpdate: MkplAppSettings = mkAppSettings( + repo = AdRepoInitialized( + AdRepoInMemory(randomUuid = { uuidNew }), + initObjects = listOf(initAd), + ) + ) + override val appSettingsDelete: MkplAppSettings = mkAppSettings( + repo = AdRepoInitialized( + AdRepoInMemory(randomUuid = { uuidNew }), + initObjects = listOf(initAd), + ) + ) + override val appSettingsSearch: MkplAppSettings = mkAppSettings( + repo = AdRepoInitialized( + AdRepoInMemory(randomUuid = { uuidNew }), + initObjects = listOf(initAd), + ) + ) + override val appSettingsOffers: MkplAppSettings = mkAppSettings( + repo = AdRepoInitialized( + AdRepoInMemory(randomUuid = { uuidNew }), + initObjects = listOf(initAd, initAdSupply), + ) + ) +} diff --git a/ok-marketplace-be/ok-marketplace-biz/src/commonTest/kotlin/validation/BaseBizValidationTest.kt b/ok-marketplace-be/ok-marketplace-biz/src/commonTest/kotlin/validation/BaseBizValidationTest.kt index 4cc53f3..98944d8 100644 --- a/ok-marketplace-be/ok-marketplace-biz/src/commonTest/kotlin/validation/BaseBizValidationTest.kt +++ b/ok-marketplace-be/ok-marketplace-biz/src/commonTest/kotlin/validation/BaseBizValidationTest.kt @@ -3,13 +3,13 @@ package ru.otus.otuskotlin.marketplace.biz.validation import ru.otus.otuskotlin.marketplace.biz.MkplAdProcessor import ru.otus.otuskotlin.marketplace.common.MkplCorSettings import ru.otus.otuskotlin.marketplace.common.models.* -import ru.otus.otuskotlin.marketplace.repo.common.AtRepoInitialized +import ru.otus.otuskotlin.marketplace.repo.common.AdRepoInitialized import ru.otus.otuskotlin.marketplace.repo.inmemory.AdRepoInMemory import ru.otus.otuskotlin.marketplace.stubs.MkplAdStub abstract class BaseBizValidationTest { protected abstract val command: MkplCommand - private val repo = AtRepoInitialized( + private val repo = AdRepoInitialized( repo = AdRepoInMemory(), initObjects = listOf( MkplAdStub.get(), diff --git a/ok-marketplace-be/ok-marketplace-repo-common/src/commonMain/kotlin/AtRepoInitialized.kt b/ok-marketplace-be/ok-marketplace-repo-common/src/commonMain/kotlin/AdRepoInitialized.kt similarity index 82% rename from ok-marketplace-be/ok-marketplace-repo-common/src/commonMain/kotlin/AtRepoInitialized.kt rename to ok-marketplace-be/ok-marketplace-repo-common/src/commonMain/kotlin/AdRepoInitialized.kt index f5dd350..c783569 100644 --- a/ok-marketplace-be/ok-marketplace-repo-common/src/commonMain/kotlin/AtRepoInitialized.kt +++ b/ok-marketplace-be/ok-marketplace-repo-common/src/commonMain/kotlin/AdRepoInitialized.kt @@ -5,9 +5,10 @@ import ru.otus.otuskotlin.marketplace.common.models.MkplAd /** * Делегат для всех репозиториев, позволяющий инициализировать базу данных предзагруженными данными */ -class AtRepoInitialized( +class AdRepoInitialized( private val repo: IRepoAdInitializable, - private val initObjects: Collection = emptyList(), + initObjects: Collection = emptyList(), ) : IRepoAdInitializable by repo { + @Suppress("unused") val initializedObjects: List = save(initObjects).toList() } diff --git a/ok-marketplace-be/ok-marketplace-repo-inmemory/src/commonTest/kotlin/AdRepoInMemoryTest.kt b/ok-marketplace-be/ok-marketplace-repo-inmemory/src/commonTest/kotlin/AdRepoInMemoryTest.kt index c1b2c9c..6668f54 100644 --- a/ok-marketplace-be/ok-marketplace-repo-inmemory/src/commonTest/kotlin/AdRepoInMemoryTest.kt +++ b/ok-marketplace-be/ok-marketplace-repo-inmemory/src/commonTest/kotlin/AdRepoInMemoryTest.kt @@ -1,37 +1,37 @@ import ru.otus.otuskotlin.marketplace.backend.repo.tests.* -import ru.otus.otuskotlin.marketplace.repo.common.AtRepoInitialized +import ru.otus.otuskotlin.marketplace.repo.common.AdRepoInitialized import ru.otus.otuskotlin.marketplace.repo.inmemory.AdRepoInMemory class AdRepoInMemoryCreateTest : RepoAdCreateTest() { - override val repo = AtRepoInitialized( + override val repo = AdRepoInitialized( AdRepoInMemory(), initObjects = initObjects, ) } class AdRepoInMemoryDeleteTest : RepoAdDeleteTest() { - override val repo = AtRepoInitialized( + override val repo = AdRepoInitialized( AdRepoInMemory(), initObjects = initObjects, ) } class AdRepoInMemoryReadTest : RepoAdReadTest() { - override val repo = AtRepoInitialized( + override val repo = AdRepoInitialized( AdRepoInMemory(), initObjects = initObjects, ) } class AdRepoInMemorySearchTest : RepoAdSearchTest() { - override val repo = AtRepoInitialized( + override val repo = AdRepoInitialized( AdRepoInMemory(), initObjects = initObjects, ) } class AdRepoInMemoryUpdateTest : RepoAdUpdateTest() { - override val repo = AtRepoInitialized( + override val repo = AdRepoInitialized( AdRepoInMemory(), initObjects = initObjects, ) diff --git a/ok-marketplace-be/ok-marketplace-repo-stubs/README.MD b/ok-marketplace-be/ok-marketplace-repo-stubs/README.MD new file mode 100644 index 0000000..fe205de --- /dev/null +++ b/ok-marketplace-be/ok-marketplace-repo-stubs/README.MD @@ -0,0 +1,4 @@ +# Модуль `ok-marketplace-repo-stubs` + + +Модуль реализует интерфейс репозитария в виде стабов. diff --git a/ok-marketplace-be/ok-marketplace-repo-stubs/build.gradle.kts b/ok-marketplace-be/ok-marketplace-repo-stubs/build.gradle.kts new file mode 100644 index 0000000..5eaad1b --- /dev/null +++ b/ok-marketplace-be/ok-marketplace-repo-stubs/build.gradle.kts @@ -0,0 +1,35 @@ +plugins { + id("build-kmp") +} + +kotlin { + sourceSets { + val coroutinesVersion: String by project + + val commonMain by getting { + dependencies { + implementation(projects.okMarketplaceCommon) + implementation(projects.okMarketplaceStubs) + + implementation(libs.coroutines.core) + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + implementation(projects.okMarketplaceRepoTests) + } + } + val jvmMain by getting { + dependencies { + implementation(kotlin("stdlib-jdk8")) + } + } + val jvmTest by getting { + dependencies { + implementation(kotlin("test-junit")) + } + } + } +} diff --git a/ok-marketplace-be/ok-marketplace-repo-stubs/src/commonMain/kotlin/AdRepoStub.kt b/ok-marketplace-be/ok-marketplace-repo-stubs/src/commonMain/kotlin/AdRepoStub.kt new file mode 100644 index 0000000..3d4b047 --- /dev/null +++ b/ok-marketplace-be/ok-marketplace-repo-stubs/src/commonMain/kotlin/AdRepoStub.kt @@ -0,0 +1,37 @@ +package ru.otus.otuskotlin.marketplace.backend.repository.inmemory + +import ru.otus.otuskotlin.marketplace.common.models.MkplDealSide +import ru.otus.otuskotlin.marketplace.common.repo.* +import ru.otus.otuskotlin.marketplace.stubs.MkplAdStub + +class AdRepoStub() : IRepoAd { + override suspend fun createAd(rq: DbAdRequest): IDbAdResponse { + return DbAdResponseOk( + data = MkplAdStub.get(), + ) + } + + override suspend fun readAd(rq: DbAdIdRequest): IDbAdResponse { + return DbAdResponseOk( + data = MkplAdStub.get(), + ) + } + + override suspend fun updateAd(rq: DbAdRequest): IDbAdResponse { + return DbAdResponseOk( + data = MkplAdStub.get(), + ) + } + + override suspend fun deleteAd(rq: DbAdIdRequest): IDbAdResponse { + return DbAdResponseOk( + data = MkplAdStub.get(), + ) + } + + override suspend fun searchAd(rq: DbAdFilterRequest): IDbAdsResponse { + return DbAdsResponseOk( + data = MkplAdStub.prepareSearchList(filter = "", MkplDealSide.DEMAND), + ) + } +} diff --git a/ok-marketplace-be/ok-marketplace-stubs/build.gradle.kts b/ok-marketplace-be/ok-marketplace-stubs/build.gradle.kts index 65b6369..ed88012 100644 --- a/ok-marketplace-be/ok-marketplace-stubs/build.gradle.kts +++ b/ok-marketplace-be/ok-marketplace-stubs/build.gradle.kts @@ -3,7 +3,6 @@ plugins { } kotlin { - sourceSets { val commonMain by getting { dependencies { diff --git a/ok-marketplace-be/settings.gradle.kts b/ok-marketplace-be/settings.gradle.kts index 5efe857..b88fbe4 100644 --- a/ok-marketplace-be/settings.gradle.kts +++ b/ok-marketplace-be/settings.gradle.kts @@ -47,5 +47,6 @@ include(":ok-marketplace-app-kafka") // DB include(":ok-marketplace-repo-common") include(":ok-marketplace-repo-inmemory") +include(":ok-marketplace-repo-stubs") include(":ok-marketplace-repo-tests")