Skip to content

M7l4 cassandra #33

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

Merged
merged 3 commits into from
Jul 4, 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
11 changes: 10 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ spring-boot = "3.2.0"

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

# Docker
testcontainers = "1.19.7"
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
Loading