Skip to content

Commit

Permalink
M7l4 Cassandra
Browse files Browse the repository at this point in the history
  • Loading branch information
svok committed Oct 2, 2024
1 parent afee6ff commit 6ba8d45
Show file tree
Hide file tree
Showing 28 changed files with 744 additions and 39 deletions.
13 changes: 11 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ spring-boot = "3.2.0"

liquibase = "4.27.0"
exposed = "0.50.0"
cassandra = "4.17.0"

# Docker
testcontainers = "1.19.7"
muschko = "9.4.0"

# BASE
jvm-compiler = "17"
jvm-compiler = "21"
jvm-language = "21"

[libraries]
Expand All @@ -40,6 +41,7 @@ coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", ve
coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
coroutines-reactor = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactor", version.ref = "coroutines" }
coroutines-reactive = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactive", version.ref = "coroutines" }
coroutines-jdk9 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-jdk9", version.ref = "coroutines" }
cor = { module = "ru.otus.otuskotlin.marketplace.libs:ok-marketplace-lib-cor" }
uuid = "com.benasher44:uuid:0.8.4"

Expand Down Expand Up @@ -91,9 +93,13 @@ db-hikari = "com.zaxxer:HikariCP:5.1.0"
db-exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }
db-exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" }
db-exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" }
db-cassandra-core = { module = "com.datastax.oss:java-driver-core", version.ref = "cassandra" }
db-cassandra-qbuilder = { module = "com.datastax.oss:java-driver-query-builder", version.ref = "cassandra" }
db-cassandra-kapt = { module = "com.datastax.oss:java-driver-mapper-processor", version.ref = "cassandra" }
db-cassandra-mapper = { module = "com.datastax.oss:java-driver-mapper-runtime", version.ref = "cassandra" }

# Liquidbase
liquibase-core = {module = "org.liquibase:liquibase-core", version.ref = "liquibase"}
liquibase-core = { module = "org.liquibase:liquibase-core", version.ref = "liquibase" }
liquibase-picocli = "info.picocli:picocli:4.7.5"
liquibase-snakeyml = "org.yaml:snakeyaml:1.33"

Expand All @@ -107,14 +113,17 @@ mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version = "5.2.
testcontainers-core = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" }
testcontainers-rabbitmq = { module = "org.testcontainers:rabbitmq", version.ref = "testcontainers" }
testcontainers-postgres = { module = "org.testcontainers:postgresql", version.ref = "testcontainers" }
testcontainers-cassandra = { module = "org.testcontainers:cassandra", version.ref = "testcontainers" }

[bundles]
kotest = ["kotest-junit5", "kotest-core", "kotest-datatest", "kotest-property"]
exposed = ["db-exposed-core", "db-exposed-dao", "db-exposed-jdbc"]
cassandra = ["db-cassandra-core", "db-cassandra-mapper", "db-cassandra-qbuilder"]

[plugins]
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
openapi-generator = { id = "org.openapi.generator", version.ref = "openapi-generator" }
crowdproj-generator = { id = "com.crowdproj.generator", version = "0.2.0" }
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
Expand Down
1 change: 1 addition & 0 deletions ok-marketplace-be/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
plugins {
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.kotlin.kapt) apply false
alias(libs.plugins.muschko.remote) apply false
alias(libs.plugins.muschko.java) apply false
}
Expand Down
4 changes: 3 additions & 1 deletion ok-marketplace-be/ok-marketplace-app-ktor/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ kotlin {
implementation(project(":ok-marketplace-api-v1-jackson"))
implementation(project(":ok-marketplace-api-v1-mappers"))

implementation(projects.okMarketplaceRepoCassandra)

implementation("ru.otus.otuskotlin.marketplace.libs:ok-marketplace-lib-logging-logback")
implementation(libs.testcontainers.postgres)
implementation(libs.testcontainers.cassandra)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ru.otus.otuskotlin.marketplace.app.ktor.configs

import io.ktor.server.config.*

data class CassandraConfig(
val host: String = "localhost",
val port: Int = 9042,
val user: String = "cassandra",
val pass: String = "cassandra",
val keyspace: String = "test_keyspace"
) {
constructor(config: ApplicationConfig) : this(
host = config.property("$PATH.host").getString(),
port = config.property("$PATH.port").getString().toInt(),
user = config.property("$PATH.user").getString(),
pass = config.property("$PATH.pass").getString(),
keyspace = config.property("$PATH.keyspace").getString()
)

companion object {
const val PATH = "${ConfigPaths.repository}.cassandra"
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package ru.otus.otuskotlin.marketplace.app.ktor.plugins

import io.ktor.server.application.*
import ru.otus.otuskotlin.marketplace.app.ktor.configs.CassandraConfig
import ru.otus.otuskotlin.marketplace.app.ktor.configs.ConfigPaths
import ru.otus.otuskotlin.marketplace.backend.repo.cassandra.RepoAdCassandra
import ru.otus.otuskotlin.marketplace.common.repo.IRepoAd

actual fun Application.getDatabaseConf(type: AdDbType): IRepoAd {
Expand All @@ -10,9 +12,22 @@ actual fun Application.getDatabaseConf(type: AdDbType): IRepoAd {
return when (dbSetting) {
"in-memory", "inmemory", "memory", "mem" -> initInMemory()
"postgres", "postgresql", "pg", "sql", "psql" -> initPostgres()
"cassandra", "nosql", "cass" -> initCassandra()
else -> throw IllegalArgumentException(
"$dbSettingPath must be set in application.yml to one of: " +
"'inmemory', 'postgres', 'cassandra', 'gremlin'"
)
}
}

private fun Application.initCassandra(): IRepoAd {
val config = CassandraConfig(environment.config)
return RepoAdCassandra(
keyspaceName = config.keyspace,
host = config.host,
port = config.port,
user = config.user,
pass = config.pass,
)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package ru.otus.otuskotlin.marketplace.app.ktor.repo

import com.benasher44.uuid.uuid4
import org.junit.AfterClass
import org.junit.BeforeClass
import org.testcontainers.containers.CassandraContainer
import ru.otus.otuskotlin.marketplace.api.v1.models.AdRequestDebugMode
import ru.otus.otuskotlin.marketplace.app.ktor.MkplAppSettings
import ru.otus.otuskotlin.marketplace.backend.repo.cassandra.RepoAdCassandra
import ru.otus.otuskotlin.marketplace.common.MkplCorSettings
import ru.otus.otuskotlin.marketplace.common.repo.IRepoAd
import ru.otus.otuskotlin.marketplace.repo.common.AdRepoInitialized
import java.time.Duration

class V1AdRepoCassandraTest : V1AdRepoBaseTest() {
override val workMode: AdRequestDebugMode = AdRequestDebugMode.TEST
private fun mkAppSettings(repo: IRepoAd) = MkplAppSettings(
corSettings = MkplCorSettings(
repoTest = repo
)
)

override val appSettingsCreate: MkplAppSettings = mkAppSettings(
repo = AdRepoInitialized(repository("ks_create", uuidNew))
)
override val appSettingsRead: MkplAppSettings = mkAppSettings(
repo = AdRepoInitialized(
repository("ks_read"),
initObjects = listOf(initAd),
)
)
override val appSettingsUpdate: MkplAppSettings = mkAppSettings(
repo = AdRepoInitialized(
repository("ks_update", uuidNew),
initObjects = listOf(initAd),
)
)
override val appSettingsDelete: MkplAppSettings = mkAppSettings(
repo = AdRepoInitialized(
repository("ks_delete"),
initObjects = listOf(initAd),
)
)
override val appSettingsSearch: MkplAppSettings = mkAppSettings(
repo = AdRepoInitialized(
repository("ks_search"),
initObjects = listOf(initAd),
)
)
override val appSettingsOffers: MkplAppSettings = mkAppSettings(
repo = AdRepoInitialized(
repository("ks_offers"),
initObjects = listOf(initAd, initAdSupply),
)
)

companion object {
class TestCasandraContainer : CassandraContainer<TestCasandraContainer>("cassandra:3.11.2")
private val container by lazy {
@Suppress("Since15")
TestCasandraContainer().withStartupTimeout(Duration.ofSeconds(300L))
}

@JvmStatic
@BeforeClass
fun tearUp() {
container.start()
}

@JvmStatic
@AfterClass
fun tearDown() {
container.stop()
}

fun repository(keyspace: String, uuid: String? = null): RepoAdCassandra {
return RepoAdCassandra(
keyspaceName = keyspace,
host = container.host,
port = container.getMappedPort(CassandraContainer.CQL_PORT),
testing = true,
randomUuid = uuid?.let { { uuid } } ?: { uuid4().toString() },
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ru.otus.otuskotlin.marketplace.biz.validation

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.withContext

@OptIn(ExperimentalCoroutinesApi::class)
fun runBizTest(block: suspend () -> Unit) = runTest {
withContext(Dispatchers.Default.limitedParallelism(1)) {
block()
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package ru.otus.otuskotlin.marketplace.biz.validation

import kotlinx.coroutines.test.runTest
import ru.otus.otuskotlin.marketplace.common.MkplContext
import ru.otus.otuskotlin.marketplace.common.models.MkplAdFilter
import ru.otus.otuskotlin.marketplace.common.models.MkplState
Expand All @@ -10,23 +9,23 @@ import kotlin.test.assertEquals

class ValidateSearchStringLengthTest {
@Test
fun emptyString() = runTest {
fun emptyString() = runBizTest {
val ctx = MkplContext(state = MkplState.RUNNING, adFilterValidating = MkplAdFilter(searchString = ""))
chain.exec(ctx)
assertEquals(MkplState.RUNNING, ctx.state)
assertEquals(0, ctx.errors.size)
}

@Test
fun blankString() = runTest {
fun blankString() = runBizTest {
val ctx = MkplContext(state = MkplState.RUNNING, adFilterValidating = MkplAdFilter(searchString = " "))
chain.exec(ctx)
assertEquals(MkplState.RUNNING, ctx.state)
assertEquals(0, ctx.errors.size)
}

@Test
fun shortString() = runTest {
fun shortString() = runBizTest {
val ctx = MkplContext(state = MkplState.RUNNING, adFilterValidating = MkplAdFilter(searchString = "12"))
chain.exec(ctx)
assertEquals(MkplState.FAILING, ctx.state)
Expand All @@ -35,15 +34,15 @@ class ValidateSearchStringLengthTest {
}

@Test
fun normalString() = runTest {
fun normalString() = runBizTest {
val ctx = MkplContext(state = MkplState.RUNNING, adFilterValidating = MkplAdFilter(searchString = "123"))
chain.exec(ctx)
assertEquals(MkplState.RUNNING, ctx.state)
assertEquals(0, ctx.errors.size)
}

@Test
fun longString() = runTest {
fun longString() = runBizTest {
val ctx = MkplContext(state = MkplState.RUNNING, adFilterValidating = MkplAdFilter(searchString = "12".repeat(51)))
chain.exec(ctx)
assertEquals(MkplState.FAILING, ctx.state)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package ru.otus.otuskotlin.marketplace.biz.validation

import kotlinx.coroutines.test.runTest
import ru.otus.otuskotlin.marketplace.common.MkplContext
import ru.otus.otuskotlin.marketplace.common.models.MkplAd
import ru.otus.otuskotlin.marketplace.common.models.MkplAdFilter
Expand All @@ -11,15 +10,15 @@ import kotlin.test.assertEquals

class ValidateTitleHasContentTest {
@Test
fun emptyString() = runTest {
fun emptyString() = runBizTest {
val ctx = MkplContext(state = MkplState.RUNNING, adValidating = MkplAd(title = ""))
chain.exec(ctx)
assertEquals(MkplState.RUNNING, ctx.state)
assertEquals(0, ctx.errors.size)
}

@Test
fun noContent() = runTest {
fun noContent() = runBizTest {
val ctx = MkplContext(state = MkplState.RUNNING, adValidating = MkplAd(title = "12!@#$%^&*()_+-="))
chain.exec(ctx)
assertEquals(MkplState.FAILING, ctx.state)
Expand All @@ -28,7 +27,7 @@ class ValidateTitleHasContentTest {
}

@Test
fun normalString() = runTest {
fun normalString() = runBizTest {
val ctx = MkplContext(state = MkplState.RUNNING, adFilterValidating = MkplAdFilter(searchString = "Ж"))
chain.exec(ctx)
assertEquals(MkplState.RUNNING, ctx.state)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package ru.otus.otuskotlin.marketplace.biz.validation

import kotlinx.coroutines.test.runTest
import ru.otus.otuskotlin.marketplace.biz.MkplAdProcessor
import ru.otus.otuskotlin.marketplace.common.MkplContext
import ru.otus.otuskotlin.marketplace.common.models.*
import ru.otus.otuskotlin.marketplace.common.models.MkplCommand
import ru.otus.otuskotlin.marketplace.common.models.MkplState
import ru.otus.otuskotlin.marketplace.common.models.MkplWorkMode
import ru.otus.otuskotlin.marketplace.stubs.MkplAdStub
import kotlin.test.assertContains
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals

fun validationDescriptionCorrect(command: MkplCommand, processor: MkplAdProcessor) = runTest {
fun validationDescriptionCorrect(command: MkplCommand, processor: MkplAdProcessor) = runBizTest {
val ctx = MkplContext(
command = command,
state = MkplState.NONE,
Expand All @@ -22,7 +23,7 @@ fun validationDescriptionCorrect(command: MkplCommand, processor: MkplAdProcesso
assertContains(ctx.adValidated.description, "болт")
}

fun validationDescriptionTrim(command: MkplCommand, processor: MkplAdProcessor) = runTest {
fun validationDescriptionTrim(command: MkplCommand, processor: MkplAdProcessor) = runBizTest {
val ctx = MkplContext(
command = command,
state = MkplState.NONE,
Expand All @@ -37,7 +38,7 @@ fun validationDescriptionTrim(command: MkplCommand, processor: MkplAdProcessor)
assertEquals("abc", ctx.adValidated.description)
}

fun validationDescriptionEmpty(command: MkplCommand, processor: MkplAdProcessor) = runTest {
fun validationDescriptionEmpty(command: MkplCommand, processor: MkplAdProcessor) = runBizTest {
val ctx = MkplContext(
command = command,
state = MkplState.NONE,
Expand All @@ -54,7 +55,7 @@ fun validationDescriptionEmpty(command: MkplCommand, processor: MkplAdProcessor)
assertContains(error?.message ?: "", "description")
}

fun validationDescriptionSymbols(command: MkplCommand, processor: MkplAdProcessor) = runTest {
fun validationDescriptionSymbols(command: MkplCommand, processor: MkplAdProcessor) = runBizTest {
val ctx = MkplContext(
command = command,
state = MkplState.NONE,
Expand Down
Loading

0 comments on commit 6ba8d45

Please sign in to comment.