@ -3,7 +3,7 @@ plugins {
|
||||
alias(libs.plugins.multiplatform) apply false
|
||||
}
|
||||
|
||||
group = "ru.otus.lessons"
|
||||
group = "ru.otus"
|
||||
version = "0.0.1"
|
||||
|
||||
subprojects {
|
||||
|
||||
@ -6,7 +6,7 @@ import ru.otus.messenger.api.v1.mappers.exceptions.UnknownRequestClass
|
||||
import ru.otus.messenger.api.v1.models.*
|
||||
import ru.otus.messenger.common.models.*
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.stubs.Stubs
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
|
||||
fun MessengerContext.fromTransport(request: IRequest) = when (request) {
|
||||
is ChatCreateRequest -> fromTransport(request)
|
||||
@ -31,13 +31,13 @@ private fun Debug?.transportToWorkMode(): WorkMode = when (this?.mode) {
|
||||
null -> WorkMode.PROD
|
||||
}
|
||||
|
||||
private fun Debug?.transportToStubCase(): Stubs = when (this?.stub) {
|
||||
DebugStubs.SUCCESS -> Stubs.SUCCESS
|
||||
DebugStubs.NOT_FOUND -> Stubs.NOT_FOUND
|
||||
DebugStubs.VALUE_ERROR -> Stubs.VALUE_ERROR
|
||||
DebugStubs.MISSING_DATA -> Stubs.MISSING_DATA
|
||||
DebugStubs.CANNOT_DELETE -> Stubs.CANNOT_DELETE
|
||||
null -> Stubs.NONE
|
||||
private fun Debug?.transportToStubCase(): MessengerStubs = when (this?.stub) {
|
||||
DebugStubs.SUCCESS -> MessengerStubs.SUCCESS
|
||||
DebugStubs.NOT_FOUND -> MessengerStubs.NOT_FOUND
|
||||
DebugStubs.VALUE_ERROR -> MessengerStubs.VALUE_ERROR
|
||||
DebugStubs.MISSING_DATA -> MessengerStubs.MISSING_DATA
|
||||
DebugStubs.CANNOT_DELETE -> MessengerStubs.CANNOT_DELETE
|
||||
null -> MessengerStubs.NONE
|
||||
}
|
||||
|
||||
fun MessengerContext.fromTransport(request: ChatCreateRequest) {
|
||||
|
||||
@ -20,7 +20,7 @@ import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.common.models.RequestId
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.Stubs
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
|
||||
class MapperCreateTest {
|
||||
@Test
|
||||
@ -42,7 +42,7 @@ class MapperCreateTest {
|
||||
val context = MessengerContext()
|
||||
context.fromTransport(req)
|
||||
|
||||
assertEquals(Stubs.SUCCESS, context.stubCase)
|
||||
assertEquals(MessengerStubs.SUCCESS, context.stubCase)
|
||||
assertEquals(WorkMode.STUB, context.workMode)
|
||||
assertEquals("title", context.chatRequest.title)
|
||||
assertEquals(ChatType.PRIVATE, context.chatRequest.type)
|
||||
|
||||
@ -17,7 +17,7 @@ import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.models.RequestId
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.Stubs
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
|
||||
class MapperDeleteTest {
|
||||
@Test
|
||||
@ -33,7 +33,7 @@ class MapperDeleteTest {
|
||||
val context = MessengerContext()
|
||||
context.fromTransport(req)
|
||||
|
||||
assertEquals(Stubs.SUCCESS, context.stubCase)
|
||||
assertEquals(MessengerStubs.SUCCESS, context.stubCase)
|
||||
assertEquals(WorkMode.STUB, context.workMode)
|
||||
assertEquals("", context.chatRequest.title)
|
||||
assertEquals("chat-id", context.chatRequest.id.asString())
|
||||
|
||||
@ -19,7 +19,7 @@ import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.common.models.RequestId
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.Stubs
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
|
||||
class MapperReadTest {
|
||||
@Test
|
||||
@ -35,7 +35,7 @@ class MapperReadTest {
|
||||
val context = MessengerContext()
|
||||
context.fromTransport(req)
|
||||
|
||||
assertEquals(Stubs.SUCCESS, context.stubCase)
|
||||
assertEquals(MessengerStubs.SUCCESS, context.stubCase)
|
||||
assertEquals(WorkMode.STUB, context.workMode)
|
||||
assertEquals("", context.chatRequest.title)
|
||||
assertEquals("chat-id", context.chatRequest.id.asString())
|
||||
|
||||
@ -20,7 +20,7 @@ import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.common.models.RequestId
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.Stubs
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
|
||||
class MapperSearchTest {
|
||||
@Test
|
||||
@ -41,7 +41,7 @@ class MapperSearchTest {
|
||||
val context = MessengerContext()
|
||||
context.fromTransport(req)
|
||||
|
||||
assertEquals(Stubs.SUCCESS, context.stubCase)
|
||||
assertEquals(MessengerStubs.SUCCESS, context.stubCase)
|
||||
assertEquals(WorkMode.STUB, context.workMode)
|
||||
assertEquals("title", context.chatRequest.title)
|
||||
assertEquals(ChatType.PRIVATE, context.chatRequest.type)
|
||||
|
||||
@ -20,7 +20,7 @@ import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.common.models.RequestId
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.Stubs
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
|
||||
class MapperUpdateTest {
|
||||
@Test
|
||||
@ -47,7 +47,7 @@ class MapperUpdateTest {
|
||||
val context = MessengerContext()
|
||||
context.fromTransport(req)
|
||||
|
||||
assertEquals(Stubs.SUCCESS, context.stubCase)
|
||||
assertEquals(MessengerStubs.SUCCESS, context.stubCase)
|
||||
assertEquals(WorkMode.STUB, context.workMode)
|
||||
assertEquals("chat-id", context.chatRequest.id.asString())
|
||||
assertEquals("title", context.chatRequest.title)
|
||||
|
||||
@ -1,13 +1,19 @@
|
||||
package ru.otus.messenger.api.v1
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||
import com.fasterxml.jackson.databind.MapperFeature
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import java.text.SimpleDateFormat
|
||||
import ru.otus.messenger.api.v1.models.IRequest
|
||||
import ru.otus.messenger.api.v1.models.IResponse
|
||||
|
||||
val apiV1Mapper: JsonMapper = JsonMapper.builder().run {
|
||||
addModule(KotlinModule.Builder().build())
|
||||
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||
defaultDateFormat(SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"))
|
||||
serializationInclusion(Include.NON_NULL)
|
||||
enable(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL)
|
||||
build()
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ class RequestV1SerializationTest {
|
||||
title = "New chat",
|
||||
type = ChatCreateRequestAllOfChat.Type.GROUP,
|
||||
mode = ChatCreateRequestAllOfChat.Mode.PERSONAL,
|
||||
participants = emptyList(),
|
||||
participants = emptySet(),
|
||||
metadata = """
|
||||
{
|
||||
"isOwner": true,
|
||||
|
||||
@ -16,7 +16,7 @@ class ResponseV1SerializationTest {
|
||||
title = "Test chat title",
|
||||
type = Chat.Type.CHANNEL,
|
||||
mode = Chat.Mode.WORK,
|
||||
participants = emptyList(),
|
||||
participants = emptySet(),
|
||||
createdAt = Instant.now().toString(),
|
||||
isArchived = false,
|
||||
metadata = null
|
||||
|
||||
@ -1,2 +1,133 @@
|
||||
package ru.otus.messenger.app.stub
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||
import com.fasterxml.jackson.databind.SerializationFeature
|
||||
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.jackson.*
|
||||
import io.ktor.server.testing.*
|
||||
import java.util.UUID
|
||||
import ru.otus.messenger.api.v1.models.ChatCreateRequest
|
||||
import ru.otus.messenger.api.v1.models.ChatCreateRequestAllOfChat
|
||||
import ru.otus.messenger.api.v1.models.ChatCreateResponse
|
||||
import ru.otus.messenger.api.v1.models.ChatDeleteRequest
|
||||
import ru.otus.messenger.api.v1.models.ChatDeleteResponse
|
||||
import ru.otus.messenger.api.v1.models.ChatReadRequest
|
||||
import ru.otus.messenger.api.v1.models.ChatReadResponse
|
||||
import ru.otus.messenger.api.v1.models.ChatSearchRequest
|
||||
import ru.otus.messenger.api.v1.models.ChatSearchRequestAllOfCriteria
|
||||
import ru.otus.messenger.api.v1.models.ChatSearchResponse
|
||||
import ru.otus.messenger.api.v1.models.Debug
|
||||
import ru.otus.messenger.api.v1.models.DebugMode
|
||||
import ru.otus.messenger.api.v1.models.DebugStubs
|
||||
import ru.otus.messenger.api.v1.models.IRequest
|
||||
import ru.otus.messenger.api.v1.models.ResponseResult
|
||||
import ru.otus.messenger.app.common.MessengerAppSettingsData
|
||||
import ru.otus.messenger.app.module
|
||||
import ru.otus.messenger.common.MessengerCorSettings
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import ru.otus.messenger.stubs.MessengerChatStubSample
|
||||
|
||||
class V1StubApiTest {
|
||||
private val chatId = UUID.randomUUID().toString()
|
||||
private val participants = (MessengerChatStubSample.participants.map { it.asString() } + MessengerChatStubSample.chatOwnerId).toSet()
|
||||
|
||||
@Test
|
||||
fun create() = v1TestApplication(
|
||||
func = "create",
|
||||
request = ChatCreateRequest(
|
||||
chat = ChatCreateRequestAllOfChat(
|
||||
title = "New chat",
|
||||
description = "New chat description",
|
||||
),
|
||||
debug = Debug(
|
||||
mode = DebugMode.STUB,
|
||||
stub = DebugStubs.SUCCESS
|
||||
)
|
||||
),
|
||||
) { response ->
|
||||
val responseObj = response.body<ChatCreateResponse>()
|
||||
assertEquals(200, response.status.value)
|
||||
assertEquals(MessengerChatStubSample.chatOwnerId, responseObj.chat?.ownerId)
|
||||
assertEquals("New chat", responseObj.chat?.title)
|
||||
assertEquals(participants, responseObj.chat?.participants)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun read() = v1TestApplication(
|
||||
func = "read",
|
||||
request = ChatReadRequest(
|
||||
chatId = MessengerChatStubSample.chatId,
|
||||
debug = Debug(
|
||||
mode = DebugMode.STUB,
|
||||
stub = DebugStubs.SUCCESS
|
||||
)
|
||||
),
|
||||
) { response ->
|
||||
val responseObj = response.body<ChatReadResponse>()
|
||||
assertEquals(200, response.status.value)
|
||||
assertEquals(MessengerChatStubSample.chatId, responseObj.chat?.id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun delete() = v1TestApplication(
|
||||
func = "delete",
|
||||
request = ChatDeleteRequest(
|
||||
chatId = chatId,
|
||||
debug = Debug(
|
||||
mode = DebugMode.STUB,
|
||||
stub = DebugStubs.SUCCESS
|
||||
)
|
||||
),
|
||||
) { response ->
|
||||
val responseObj = response.body<ChatDeleteResponse>()
|
||||
assertEquals(200, response.status.value)
|
||||
assertEquals(ResponseResult.SUCCESS, responseObj.result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun search() = v1TestApplication(
|
||||
func = "search",
|
||||
request = ChatSearchRequest(
|
||||
criteria = ChatSearchRequestAllOfCriteria(
|
||||
title = "Chat search title",
|
||||
type = ChatSearchRequestAllOfCriteria.Type.GROUP,
|
||||
),
|
||||
debug = Debug(
|
||||
mode = DebugMode.STUB,
|
||||
stub = DebugStubs.SUCCESS
|
||||
)
|
||||
),
|
||||
) { response ->
|
||||
val responseObj = response.body<ChatSearchResponse>()
|
||||
assertEquals(200, response.status.value)
|
||||
assertEquals(2, responseObj.chats?.size)
|
||||
assertEquals("Chat search title", responseObj.chats?.first()?.title)
|
||||
}
|
||||
|
||||
private fun v1TestApplication(
|
||||
func: String,
|
||||
request: IRequest,
|
||||
function: suspend (HttpResponse) -> Unit,
|
||||
): Unit = testApplication {
|
||||
application { module(MessengerAppSettingsData(corSettings = MessengerCorSettings())) }
|
||||
val client = createClient {
|
||||
install(ContentNegotiation) {
|
||||
jackson {
|
||||
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
enable(SerializationFeature.INDENT_OUTPUT)
|
||||
writerWithDefaultPrettyPrinter()
|
||||
}
|
||||
}
|
||||
}
|
||||
val response = client.post("/v1/chat/$func") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(request)
|
||||
}
|
||||
function(response)
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,8 +4,13 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib"))
|
||||
implementation(libs.kotlin.coroutines)
|
||||
implementation(libs.kotlin.datetime)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(project(":ok-messenger-common"))
|
||||
implementation(project(":ok-messenger-stubs"))
|
||||
implementation("ru.otus.messenger.libs:ok-messenger-lib-cor")
|
||||
|
||||
testImplementation(kotlin("test-junit"))
|
||||
testImplementation(libs.kotlin.coroutines.test)
|
||||
}
|
||||
@ -1,17 +1,145 @@
|
||||
package ru.otus.messenger.biz
|
||||
|
||||
import ru.otus.messenger.biz.general.initStatus
|
||||
import ru.otus.messenger.biz.general.operation
|
||||
import ru.otus.messenger.biz.general.stubs
|
||||
import ru.otus.messenger.biz.general.validation
|
||||
import ru.otus.messenger.biz.stubs.stubCreateSuccess
|
||||
import ru.otus.messenger.biz.stubs.stubReadSuccess
|
||||
import ru.otus.messenger.biz.stubs.stubUpdateSuccess
|
||||
import ru.otus.messenger.biz.stubs.stubDbError
|
||||
import ru.otus.messenger.biz.stubs.stubDeleteSuccess
|
||||
import ru.otus.messenger.biz.stubs.stubNoCase
|
||||
import ru.otus.messenger.biz.stubs.stubSearchSuccess
|
||||
import ru.otus.messenger.biz.stubs.stubValidationBadDescription
|
||||
import ru.otus.messenger.biz.stubs.stubValidationBadId
|
||||
import ru.otus.messenger.biz.stubs.stubValidationBadTitle
|
||||
import ru.otus.messenger.biz.validation.finishChatFilterValidation
|
||||
import ru.otus.messenger.biz.validation.finishChatValidation
|
||||
import ru.otus.messenger.biz.validation.validateDescriptionHasContent
|
||||
import ru.otus.messenger.biz.validation.validateDescriptionNotEmpty
|
||||
import ru.otus.messenger.biz.validation.validateIdNotEmpty
|
||||
import ru.otus.messenger.biz.validation.validateIdProperFormat
|
||||
import ru.otus.messenger.biz.validation.validateSearchStringLength
|
||||
import ru.otus.messenger.biz.validation.validateTitleHasContent
|
||||
import ru.otus.messenger.biz.validation.validateTitleNotEmpty
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.MessengerCorSettings
|
||||
import ru.otus.messenger.common.models.ChatMode
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatId
|
||||
import ru.otus.messenger.cor.dsl.rootChain
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
@Suppress("unused", "RedundantSuspendModifier")
|
||||
class MessengerProcessor(val corSettings: MessengerCorSettings) {
|
||||
suspend fun exec(ctx: MessengerContext) {
|
||||
ctx.chatResponse = MessengerChatStub.get()
|
||||
ctx.chatsResponse = MessengerChatStub.prepareSearchList("New chat", ChatType.GROUP, ChatMode.PERSONAL).toMutableList()
|
||||
ctx.state = ChatState.RUNNING
|
||||
}
|
||||
class MessengerProcessor(
|
||||
private val corSettings: MessengerCorSettings = MessengerCorSettings.NONE
|
||||
) {
|
||||
suspend fun exec(ctx: MessengerContext) = businessChain.exec(
|
||||
ctx.also { it.corSettings = corSettings }
|
||||
)
|
||||
|
||||
private val businessChain = rootChain<MessengerContext> {
|
||||
initStatus("Инициализация статуса")
|
||||
|
||||
operation("Создание чата", ChatCommand.CREATE) {
|
||||
stubs("Обработка стабов") {
|
||||
stubCreateSuccess("Имитация успешной обработки", corSettings)
|
||||
stubValidationBadTitle("Имитация ошибки валидации заголовка")
|
||||
stubValidationBadDescription("Имитация ошибки валидации описания")
|
||||
stubDbError("Имитация ошибки работы с БД")
|
||||
stubNoCase("Ошибка: запрошенный стаб недопустим")
|
||||
}
|
||||
|
||||
validation {
|
||||
worker("Копируем поля в chatValidating") { chatValidating = chatRequest.deepCopy() }
|
||||
worker("Очистка id") { chatValidating.id = ChatId.NONE }
|
||||
worker("Очистка заголовка") { chatValidating.title = chatValidating.title.trim() }
|
||||
worker("Очистка описания") { chatValidating.description = chatValidating.description.trim() }
|
||||
validateTitleNotEmpty("Проверка, что заголовок не пуст")
|
||||
validateTitleHasContent("Проверка символов")
|
||||
validateDescriptionNotEmpty("Проверка, что описание не пусто")
|
||||
validateDescriptionHasContent("Проверка символов")
|
||||
|
||||
finishChatValidation("Завершение проверок")
|
||||
}
|
||||
}
|
||||
|
||||
operation("Получить чат", ChatCommand.READ) {
|
||||
stubs("Обработка стабов") {
|
||||
stubReadSuccess("Имитация успешной обработки", corSettings)
|
||||
stubValidationBadId("Имитация ошибки валидации id")
|
||||
stubDbError("Имитация ошибки работы с БД")
|
||||
stubNoCase("Ошибка: запрошенный стаб недопустим")
|
||||
}
|
||||
|
||||
validation {
|
||||
worker("Копируем поля в chatValidating") { chatValidating = chatRequest.deepCopy() }
|
||||
worker("Очистка id") { chatValidating.id = ChatId(chatValidating.id.asString().trim()) }
|
||||
validateIdNotEmpty("Проверка на непустой id")
|
||||
validateIdProperFormat("Проверка формата id")
|
||||
|
||||
finishChatValidation("Успешное завершение процедуры валидации")
|
||||
}
|
||||
}
|
||||
|
||||
operation("Изменить чат", ChatCommand.UPDATE) {
|
||||
stubs("Обработка стабов") {
|
||||
stubUpdateSuccess("Имитация успешной обработки", corSettings)
|
||||
stubValidationBadId("Имитация ошибки валидации id")
|
||||
stubValidationBadTitle("Имитация ошибки валидации заголовка")
|
||||
stubValidationBadDescription("Имитация ошибки валидации описания")
|
||||
stubDbError("Имитация ошибки работы с БД")
|
||||
stubNoCase("Ошибка: запрошенный стаб недопустим")
|
||||
}
|
||||
|
||||
validation {
|
||||
worker("Копируем поля в chatValidating") { chatValidating = chatRequest.deepCopy() }
|
||||
worker("Очистка id") { chatValidating.id = ChatId(chatValidating.id.asString().trim()) }
|
||||
worker("Очистка заголовка") { chatValidating.title = chatValidating.title.trim() }
|
||||
worker("Очистка описания") { chatValidating.description = chatValidating.description.trim() }
|
||||
validateIdNotEmpty("Проверка на непустой id")
|
||||
validateIdProperFormat("Проверка формата id")
|
||||
validateTitleNotEmpty("Проверка на непустой заголовок")
|
||||
validateTitleHasContent("Проверка на наличие содержания в заголовке")
|
||||
validateDescriptionNotEmpty("Проверка на непустое описание")
|
||||
validateDescriptionHasContent("Проверка на наличие содержания в описании")
|
||||
|
||||
finishChatValidation("Успешное завершение процедуры валидации")
|
||||
}
|
||||
}
|
||||
|
||||
operation("Удалить чат", ChatCommand.DELETE) {
|
||||
stubs("Обработка стабов") {
|
||||
stubDeleteSuccess("Имитация успешной обработки", corSettings)
|
||||
stubValidationBadId("Имитация ошибки валидации id")
|
||||
stubDbError("Имитация ошибки работы с БД")
|
||||
stubNoCase("Ошибка: запрошенный стаб недопустим")
|
||||
}
|
||||
|
||||
validation {
|
||||
worker("Копируем поля в chatValidating") {
|
||||
chatValidating = chatRequest.deepCopy()
|
||||
}
|
||||
worker("Очистка id") { chatValidating.id = ChatId(chatValidating.id.asString().trim()) }
|
||||
validateIdNotEmpty("Проверка на непустой id")
|
||||
validateIdProperFormat("Проверка формата id")
|
||||
finishChatValidation("Успешное завершение процедуры валидации")
|
||||
}
|
||||
}
|
||||
|
||||
operation("Поиск чата", ChatCommand.SEARCH) {
|
||||
stubs("Обработка стабов") {
|
||||
stubSearchSuccess("Имитация успешной обработки", corSettings)
|
||||
stubValidationBadId("Имитация ошибки валидации id")
|
||||
stubDbError("Имитация ошибки работы с БД")
|
||||
stubNoCase("Ошибка: запрошенный стаб недопустим")
|
||||
}
|
||||
|
||||
validation {
|
||||
worker("Копируем поля в chatFilterValidating") { chatFilterValidating = chatFilterRequest.deepCopy() }
|
||||
validateSearchStringLength("Валидация длины строки поиска в фильтре")
|
||||
|
||||
finishChatFilterValidation("Успешное завершение процедуры валидации")
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package ru.otus.messenger.biz.general
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.initStatus(title: String) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Этот обработчик устанавливает стартовый статус обработки. Запускается только в случае не заданного статуса.
|
||||
""".trimIndent()
|
||||
on { state == ChatState.NONE }
|
||||
handle { state = ChatState.RUNNING }
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package ru.otus.messenger.biz.general
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.chain
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.operation(
|
||||
title: String,
|
||||
command: ChatCommand,
|
||||
block: ICorChainDsl<MessengerContext>.() -> Unit
|
||||
) = chain {
|
||||
block()
|
||||
this.title = title
|
||||
on { this.command == command && state == ChatState.RUNNING }
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package ru.otus.messenger.biz.general
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.chain
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubs(title: String = "Обработка стабов", block: ICorChainDsl<MessengerContext>.() -> Unit) = chain {
|
||||
block()
|
||||
this.title = title
|
||||
on { workMode == WorkMode.STUB && state == ChatState.RUNNING }
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package ru.otus.messenger.biz.general
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.chain
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.validation(block: ICorChainDsl<MessengerContext>.() -> Unit) = chain {
|
||||
block()
|
||||
title = "Валидация"
|
||||
on { state == ChatState.RUNNING }
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.MessengerCorSettings
|
||||
import ru.otus.messenger.common.models.ChatMode
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
import ru.otus.messenger.logging.common.LogLevel
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubCreateSuccess(title: String, corSettings: MessengerCorSettings) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Кейс успеха для создания чата
|
||||
""".trimIndent()
|
||||
on { stubCase == MessengerStubs.SUCCESS && state == ChatState.RUNNING }
|
||||
val logger = corSettings.loggerProvider.logger("stubCreateSuccess")
|
||||
handle {
|
||||
logger.doWithLogging(id = this.requestId.asString(), LogLevel.DEBUG) {
|
||||
state = ChatState.FINISHING
|
||||
val stub = MessengerChatStub.prepareResult {
|
||||
chatRequest.title.takeIf { it.isNotBlank() }?.also { this.title = it }
|
||||
chatRequest.description.takeIf { it.isNotBlank() }?.also { this.description = it }
|
||||
chatRequest.type.takeIf { it != ChatType.NONE }?.also { this.type = it }
|
||||
chatRequest.mode.takeIf { it != ChatMode.NONE }?.also { this.mode = it }
|
||||
}
|
||||
chatResponse = stub
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.common.models.ChatError
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubDbError(title: String) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Кейс ошибки базы данных
|
||||
""".trimIndent()
|
||||
on { stubCase == MessengerStubs.DB_ERROR && state == ChatState.RUNNING }
|
||||
handle {
|
||||
fail(
|
||||
ChatError(
|
||||
group = "internal",
|
||||
code = "internal-db",
|
||||
message = "Internal error"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.MessengerCorSettings
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
import ru.otus.messenger.logging.common.LogLevel
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubDeleteSuccess(title: String, corSettings: MessengerCorSettings) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Кейс успеха для удаления объявления
|
||||
""".trimIndent()
|
||||
on { stubCase == MessengerStubs.SUCCESS && state == ChatState.RUNNING }
|
||||
val logger = corSettings.loggerProvider.logger("stubDeleteSuccess")
|
||||
handle {
|
||||
logger.doWithLogging(id = this.requestId.asString(), LogLevel.DEBUG) {
|
||||
state = ChatState.FINISHING
|
||||
val stub = MessengerChatStub.prepareResult {
|
||||
chatRequest.title.takeIf { it.isNotBlank() }?.also { this.title = it }
|
||||
}
|
||||
chatResponse = stub
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.common.models.ChatError
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubNoCase(title: String) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Валидируем ситуацию, когда запрошен кейс, который не поддерживается в стабах
|
||||
""".trimIndent()
|
||||
on { state == ChatState.RUNNING }
|
||||
handle {
|
||||
fail(
|
||||
ChatError(
|
||||
code = "validation",
|
||||
field = "stub",
|
||||
group = "validation",
|
||||
message = "Wrong stub case is requested: ${stubCase.name}"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.common.models.ChatError
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubNotFound(title: String) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Entity of interest were not found
|
||||
""".trimIndent()
|
||||
|
||||
on { stubCase == MessengerStubs.NOT_FOUND && state == ChatState.RUNNING }
|
||||
|
||||
handle {
|
||||
fail(
|
||||
ChatError(
|
||||
group = "internal",
|
||||
code = "internal-db",
|
||||
message = "Entity not found error"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.MessengerCorSettings
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
import ru.otus.messenger.logging.common.LogLevel
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubReadSuccess(title: String, corSettings: MessengerCorSettings) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Кейс успеха для чтения чата
|
||||
""".trimIndent()
|
||||
on { stubCase == MessengerStubs.SUCCESS && state == ChatState.RUNNING }
|
||||
val logger = corSettings.loggerProvider.logger("stubReadSuccess")
|
||||
handle {
|
||||
logger.doWithLogging(id = this.requestId.asString(), LogLevel.DEBUG) {
|
||||
state = ChatState.FINISHING
|
||||
val stub = MessengerChatStub.prepareResult {
|
||||
chatRequest.title.takeIf { it.isNotBlank() }?.also { this.title = it }
|
||||
}
|
||||
chatResponse = stub
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.MessengerCorSettings
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter.StringSearchField
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
import ru.otus.messenger.logging.common.LogLevel
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubSearchSuccess(title: String, corSettings: MessengerCorSettings) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Кейс успеха для поиска объявлений
|
||||
""".trimIndent()
|
||||
on { stubCase == MessengerStubs.SUCCESS && state == ChatState.RUNNING }
|
||||
val logger = corSettings.loggerProvider.logger("stubSearchSuccess")
|
||||
handle {
|
||||
logger.doWithLogging(id = this.requestId.asString(), LogLevel.DEBUG) {
|
||||
state = ChatState.FINISHING
|
||||
chatsResponse.addAll(
|
||||
MessengerChatStub.prepareSearchList(
|
||||
(chatFilterRequest.searchFields.first() as StringSearchField).stringValue,
|
||||
ChatType.GROUP
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.MessengerCorSettings
|
||||
import ru.otus.messenger.common.models.ChatId
|
||||
import ru.otus.messenger.common.models.ChatMode
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
import ru.otus.messenger.logging.common.LogLevel
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubUpdateSuccess(title: String, corSettings: MessengerCorSettings) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Кейс успеха для изменения объявления
|
||||
""".trimIndent()
|
||||
on { stubCase == MessengerStubs.SUCCESS && state == ChatState.RUNNING }
|
||||
val logger = corSettings.loggerProvider.logger("stubUpdateSuccess")
|
||||
handle {
|
||||
logger.doWithLogging(id = this.requestId.asString(), LogLevel.DEBUG) {
|
||||
state = ChatState.FINISHING
|
||||
val stub = MessengerChatStub.prepareResult {
|
||||
chatRequest.id.takeIf { it != ChatId.NONE }?.also { this.id = it }
|
||||
chatRequest.title.takeIf { it.isNotBlank() }?.also { this.title = it }
|
||||
chatRequest.description.takeIf { it.isNotBlank() }?.also { this.description = it }
|
||||
chatRequest.type.takeIf { it != ChatType.NONE }?.also { this.type = it }
|
||||
chatRequest.mode.takeIf { it != ChatMode.NONE }?.also { this.mode = it }
|
||||
}
|
||||
chatResponse = stub
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.common.models.ChatError
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubValidationBadDescription(title: String) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Кейс ошибки валидации для описания чата
|
||||
""".trimIndent()
|
||||
on { stubCase == MessengerStubs.BAD_DESCRIPTION && state == ChatState.RUNNING }
|
||||
handle {
|
||||
fail(
|
||||
ChatError(
|
||||
group = "validation",
|
||||
code = "validation-description",
|
||||
field = "description",
|
||||
message = "Wrong description field"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.common.models.ChatError
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubValidationBadId(title: String) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Кейс ошибки валидации для идентификатора объявления
|
||||
""".trimIndent()
|
||||
on { stubCase == MessengerStubs.BAD_ID && state == ChatState.RUNNING }
|
||||
handle {
|
||||
fail(
|
||||
ChatError(
|
||||
group = "validation",
|
||||
code = "validation-id",
|
||||
field = "id",
|
||||
message = "Wrong id field"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package ru.otus.messenger.biz.stubs
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.common.models.ChatError
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.stubValidationBadTitle(title: String) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Кейс ошибки валидации для заголовка чата
|
||||
""".trimIndent()
|
||||
on { stubCase == MessengerStubs.BAD_TITLE && state == ChatState.RUNNING }
|
||||
handle {
|
||||
fail(
|
||||
ChatError(
|
||||
group = "validation",
|
||||
code = "validation-title",
|
||||
field = "title",
|
||||
message = "Wrong title field"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.finishChatValidation(title: String) = worker {
|
||||
this.title = title
|
||||
on { state == ChatState.RUNNING }
|
||||
handle {
|
||||
chatValidated = chatValidating
|
||||
}
|
||||
}
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.finishChatFilterValidation(title: String) = worker {
|
||||
this.title = title
|
||||
on { state == ChatState.RUNNING }
|
||||
handle {
|
||||
chatFilterValidated = chatFilterValidating
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.errorValidation
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.validateDescriptionHasContent(title: String) = worker {
|
||||
this.title = title
|
||||
val regExp = Regex("\\p{L}")
|
||||
on { chatValidating.description.isNotEmpty() && !chatValidating.description.contains(regExp) }
|
||||
handle {
|
||||
fail(
|
||||
errorValidation(
|
||||
field = "description",
|
||||
violationCode = "noContent",
|
||||
description = "field must contain letters"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.errorValidation
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.validateDescriptionNotEmpty(title: String) = worker {
|
||||
this.title = title
|
||||
on { chatValidating.description.isEmpty() }
|
||||
handle {
|
||||
fail(
|
||||
errorValidation(
|
||||
field = "description",
|
||||
violationCode = "empty",
|
||||
description = "field must not be empty"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.errorValidation
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.validateIdNotEmpty(title: String) = worker {
|
||||
this.title = title
|
||||
on { chatValidating.id.asString().isEmpty() }
|
||||
handle {
|
||||
fail(
|
||||
errorValidation(
|
||||
field = "id",
|
||||
violationCode = "empty",
|
||||
description = "field must not be empty"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.errorValidation
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.common.models.ChatId
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.validateIdProperFormat(title: String) = worker {
|
||||
this.title = title
|
||||
|
||||
// Может быть вынесен в ChatId для реализации различных форматов
|
||||
val regExp = Regex("^[0-9a-zA-Z#:-]+$")
|
||||
on { chatValidating.id != ChatId.NONE && ! chatValidating.id.asString().matches(regExp) }
|
||||
handle {
|
||||
val encodedId = chatValidating.id.asString()
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
fail(
|
||||
errorValidation(
|
||||
field = "id",
|
||||
violationCode = "badFormat",
|
||||
description = "value $encodedId must contain only letters and numbers"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import kotlin.collections.first
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.errorValidation
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter.StringSearchField
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.chain
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.validateSearchStringLength(title: String) = chain {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Валидация длины строки поиска в поисковых фильтрах. Допустимые значения:
|
||||
- null - не выполняем поиск по строке
|
||||
- 3-100 - допустимая длина
|
||||
- больше 100 - слишком длинная строка
|
||||
""".trimIndent()
|
||||
on { state == ChatState.RUNNING }
|
||||
worker("Обрезка пустых символов") {
|
||||
(chatFilterValidating.searchFields.first() as StringSearchField).stringValue =
|
||||
(chatFilterValidating.searchFields.first() as StringSearchField).stringValue.trim() }
|
||||
worker {
|
||||
this.title = "Проверка кейса длины на 0-2 символа"
|
||||
this.description = this.title
|
||||
on { state == ChatState.RUNNING && (chatFilterValidating.searchFields.first() as StringSearchField).stringValue.length in (1..2) }
|
||||
handle {
|
||||
fail(
|
||||
errorValidation(
|
||||
field = "searchString",
|
||||
violationCode = "tooShort",
|
||||
description = "Search string must contain at least 3 symbols"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
worker {
|
||||
this.title = "Проверка кейса длины на более 100 символов"
|
||||
this.description = this.title
|
||||
on { state == ChatState.RUNNING && (chatFilterValidating.searchFields.first() as StringSearchField).stringValue.length > 100 }
|
||||
handle {
|
||||
fail(
|
||||
errorValidation(
|
||||
field = "searchString",
|
||||
violationCode = "tooLong",
|
||||
description = "Search string must be no more than 100 symbols long"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.errorValidation
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.validateTitleHasContent(title: String) = worker {
|
||||
this.title = title
|
||||
this.description = """
|
||||
Проверяем, что у нас есть какие-то слова в заголовке.
|
||||
Отказываем в публикации заголовков, в которых только бессмысленные символы типа %^&^$^%#^))&^*&%^^&
|
||||
""".trimIndent()
|
||||
val regExp = Regex("\\p{L}")
|
||||
on { chatValidating.title.isNotEmpty() && ! chatValidating.title.contains(regExp) }
|
||||
handle {
|
||||
fail(
|
||||
errorValidation(
|
||||
field = "title",
|
||||
violationCode = "noContent",
|
||||
description = "field must contain letters"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.helpers.errorValidation
|
||||
import ru.otus.messenger.common.helpers.fail
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
fun ICorChainDsl<MessengerContext>.validateTitleNotEmpty(title: String) = worker {
|
||||
this.title = title
|
||||
on { chatValidating.title.isEmpty() }
|
||||
handle {
|
||||
fail(
|
||||
errorValidation(
|
||||
field = "title",
|
||||
violationCode = "empty",
|
||||
description = "field must not be empty"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
package ru.otus.messenger.biz
|
||||
@ -0,0 +1,94 @@
|
||||
package ru.otus.messenger.biz.stub
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.put
|
||||
import ru.otus.messenger.biz.MessengerProcessor
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
class MessengerCreateStubTest {
|
||||
private val processor = MessengerProcessor()
|
||||
private val timestamp = Instant.parse("2025-01-31T06:30:00Z")
|
||||
private val content = buildJsonObject {
|
||||
put("sampleId", "uuid4")
|
||||
put("testParam", "test")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun create() = runTest {
|
||||
val context = MessengerContext(
|
||||
command = ChatCommand.CREATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.SUCCESS,
|
||||
)
|
||||
processor.exec(context)
|
||||
assertEquals(MessengerChatStub.get().title, context.chatResponse.title)
|
||||
assertEquals(timestamp, context.chatResponse.createdAt)
|
||||
assertEquals(content.toString(), context.chatResponse.metadata.asString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badTitle() = runTest {
|
||||
val context = MessengerContext(
|
||||
command = ChatCommand.CREATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_TITLE,
|
||||
)
|
||||
processor.exec(context)
|
||||
assertEquals(MessengerChat(), context.chatResponse)
|
||||
assertEquals("title", context.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", context.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badDescription() = runTest {
|
||||
val context = MessengerContext(
|
||||
command = ChatCommand.CREATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_DESCRIPTION,
|
||||
)
|
||||
processor.exec(context)
|
||||
assertEquals(MessengerChat(), context.chatResponse)
|
||||
assertEquals("description", context.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", context.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun databaseError() = runTest {
|
||||
val context = MessengerContext(
|
||||
command = ChatCommand.CREATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.DB_ERROR,
|
||||
)
|
||||
processor.exec(context)
|
||||
assertEquals(MessengerChat(), context.chatResponse)
|
||||
assertEquals("internal", context.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badNoCase() = runTest {
|
||||
val context = MessengerContext(
|
||||
command = ChatCommand.CREATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.NOT_FOUND,
|
||||
)
|
||||
processor.exec(context)
|
||||
assertEquals(MessengerChat(), context.chatResponse)
|
||||
assertEquals("stub", context.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", context.errors.firstOrNull()?.group)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package ru.otus.messenger.biz.stub
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import ru.otus.messenger.biz.MessengerProcessor
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
class MessengerDeleteStubTest {
|
||||
private val processor = MessengerProcessor()
|
||||
|
||||
@Test
|
||||
fun delete() = runTest {
|
||||
val context = MessengerContext(
|
||||
command = ChatCommand.DELETE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.SUCCESS,
|
||||
)
|
||||
processor.exec(context)
|
||||
|
||||
val stub = MessengerChatStub.get()
|
||||
assertEquals(stub.id, context.chatResponse.id)
|
||||
assertEquals(stub.title, context.chatResponse.title)
|
||||
assertEquals(stub.type, context.chatResponse.type)
|
||||
assertEquals(stub.mode, context.chatResponse.mode)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badNoCase() = runTest {
|
||||
val context = MessengerContext(
|
||||
command = ChatCommand.DELETE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.NOT_FOUND,
|
||||
)
|
||||
processor.exec(context)
|
||||
assertEquals(MessengerChat(), context.chatResponse)
|
||||
assertEquals("stub", context.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", context.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badId() = runTest {
|
||||
val context = MessengerContext(
|
||||
command = ChatCommand.DELETE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_ID
|
||||
)
|
||||
processor.exec(context)
|
||||
assertEquals(MessengerChat(), context.chatResponse)
|
||||
assertEquals("id", context.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", context.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun databaseError() = runTest {
|
||||
val context = MessengerContext(
|
||||
command = ChatCommand.DELETE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.DB_ERROR,
|
||||
)
|
||||
processor.exec(context)
|
||||
assertEquals(MessengerChat(), context.chatResponse)
|
||||
assertEquals("internal", context.errors.firstOrNull()?.group)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package ru.otus.messenger.biz.stub
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import ru.otus.messenger.biz.MessengerProcessor
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
class MessengerReadStubTest {
|
||||
private val processor = MessengerProcessor()
|
||||
|
||||
@Test
|
||||
fun read() = runTest {
|
||||
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.READ,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.SUCCESS,
|
||||
)
|
||||
processor.exec(ctx)
|
||||
with (MessengerChatStub.get()) {
|
||||
assertEquals(id, ctx.chatResponse.id)
|
||||
assertEquals(title, ctx.chatResponse.title)
|
||||
assertEquals(description, ctx.chatResponse.description)
|
||||
assertEquals(type, ctx.chatResponse.type)
|
||||
assertEquals(mode, ctx.chatResponse.mode)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badId() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.READ,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_ID,
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("id", ctx.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", ctx.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun databaseError() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.READ,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.DB_ERROR,
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("internal", ctx.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badNoCase() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.READ,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_TITLE,
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("stub", ctx.errors.firstOrNull()?.field)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package ru.otus.messenger.biz.stub
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import ru.otus.messenger.biz.MessengerProcessor
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter.StringSearchField
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
class MessengerSearchStubTest {
|
||||
private val processor = MessengerProcessor()
|
||||
val filter = ChatSearchFilter(
|
||||
searchFields = listOf(
|
||||
StringSearchField(fieldName = "title", stringValue = "New chat" ),
|
||||
StringSearchField(fieldName = "description", stringValue = "New chat description" )
|
||||
)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun read() = runTest {
|
||||
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.SEARCH,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.SUCCESS,
|
||||
chatFilterRequest = filter,
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertTrue(ctx.chatsResponse.size > 1)
|
||||
val first = ctx.chatsResponse.firstOrNull() ?: fail("Empty response list")
|
||||
assertTrue(first.title.contains((filter.searchFields[0] as StringSearchField).stringValue))
|
||||
assertTrue(first.description.contains((filter.searchFields[1] as StringSearchField).stringValue))
|
||||
with(MessengerChatStub.get()) {
|
||||
assertEquals(type, first.type)
|
||||
assertEquals(mode, first.mode)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badId() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.SEARCH,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_ID,
|
||||
chatFilterRequest = filter,
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("id", ctx.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", ctx.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun databaseError() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.SEARCH,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.DB_ERROR,
|
||||
chatFilterRequest = filter,
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("internal", ctx.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badNoCase() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.SEARCH,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_TITLE,
|
||||
chatFilterRequest = filter,
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("stub", ctx.errors.firstOrNull()?.field)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,117 @@
|
||||
package ru.otus.messenger.biz.stub
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import ru.otus.messenger.biz.MessengerProcessor
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatId
|
||||
import ru.otus.messenger.common.models.ChatMode
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.stubs.MessengerChatStubSample
|
||||
|
||||
class MessengerUpdateStubTest {
|
||||
private val processor = MessengerProcessor()
|
||||
val id = ChatId(MessengerChatStubSample.chatId)
|
||||
val title = "New chat"
|
||||
val description = "New chat description"
|
||||
val type = ChatType.GROUP
|
||||
val mode = ChatMode.PERSONAL
|
||||
|
||||
@Test
|
||||
fun create() = runTest {
|
||||
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.UPDATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.SUCCESS
|
||||
)
|
||||
|
||||
processor.exec(ctx)
|
||||
assertEquals(id, ctx.chatResponse.id)
|
||||
assertEquals(title, ctx.chatResponse.title)
|
||||
assertEquals(description, ctx.chatResponse.description)
|
||||
assertEquals(type, ctx.chatResponse.type)
|
||||
assertEquals(mode, ctx.chatResponse.mode)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badId() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.UPDATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_ID,
|
||||
chatRequest = MessengerChat(),
|
||||
)
|
||||
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("id", ctx.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", ctx.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badTitle() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.UPDATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_TITLE,
|
||||
)
|
||||
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("title", ctx.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", ctx.errors.firstOrNull()?.group)
|
||||
}
|
||||
@Test
|
||||
fun badDescription() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.UPDATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_DESCRIPTION,
|
||||
)
|
||||
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("description", ctx.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", ctx.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun databaseError() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.UPDATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.DB_ERROR,
|
||||
)
|
||||
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("internal", ctx.errors.firstOrNull()?.group)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun badNoCase() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = ChatCommand.UPDATE,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.STUB,
|
||||
stubCase = MessengerStubs.BAD_SEARCH_STRING,
|
||||
)
|
||||
|
||||
processor.exec(ctx)
|
||||
assertEquals(MessengerChat(), ctx.chatResponse)
|
||||
assertEquals("stub", ctx.errors.firstOrNull()?.field)
|
||||
assertEquals("validation", ctx.errors.firstOrNull()?.group)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import ru.otus.messenger.biz.MessengerProcessor
|
||||
import ru.otus.messenger.common.MessengerCorSettings
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
|
||||
abstract class BaseBizValidationTest {
|
||||
protected abstract val command: ChatCommand
|
||||
private val settings by lazy { MessengerCorSettings() }
|
||||
protected val processor by lazy { MessengerProcessor(settings) }
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import kotlin.test.Test
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
|
||||
class BizValidationCreateTest : BaseBizValidationTest() {
|
||||
override val command: ChatCommand = ChatCommand.CREATE
|
||||
|
||||
@Test fun correctTitle() = validationTitleCorrect(command, processor)
|
||||
@Test fun trimTitle() = validationTitleTrim(command, processor)
|
||||
@Test fun emptyTitle() = validationTitleEmpty(command, processor)
|
||||
@Test fun badSymbolsTitle() = validationTitleSymbols(command, processor)
|
||||
|
||||
@Test fun correctDescription() = validationDescriptionCorrect(command, processor)
|
||||
@Test fun trimDescription() = validationDescriptionTrim(command, processor)
|
||||
@Test fun emptyDescription() = validationDescriptionEmpty(command, processor)
|
||||
@Test fun badSymbolsDescription() = validationDescriptionSymbols(command, processor)
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import org.junit.Test
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
|
||||
class BizValidationDeleteTest : BaseBizValidationTest() {
|
||||
override val command: ChatCommand = ChatCommand.DELETE
|
||||
|
||||
@Test fun correctId() = validationIdCorrect(command, processor)
|
||||
@Test fun trimId() = validationIdTrim(command, processor)
|
||||
@Test fun emptyId() = validationIdEmpty(command, processor)
|
||||
@Test fun badFormatId() = validationIdFormat(command, processor)
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import org.junit.Test
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
|
||||
class BizValidationReadTest : BaseBizValidationTest() {
|
||||
override val command: ChatCommand = ChatCommand.READ
|
||||
|
||||
@Test fun correctId() = validationIdCorrect(command, processor)
|
||||
@Test fun trimId() = validationIdTrim(command, processor)
|
||||
@Test fun emptyId() = validationIdEmpty(command, processor)
|
||||
@Test fun badFormatId() = validationIdFormat(command, processor)
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter.StringSearchField
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
|
||||
class BizValidationSearchTest : BaseBizValidationTest() {
|
||||
override val command: ChatCommand = ChatCommand.SEARCH
|
||||
|
||||
@Test
|
||||
fun correctEmpty() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatFilterRequest = ChatSearchFilter(
|
||||
searchFields = listOf(
|
||||
StringSearchField(
|
||||
fieldName = "",
|
||||
stringValue = ""
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
assertNotEquals(ChatState.FAILING, ctx.state)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import org.junit.Test
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
|
||||
class BizValidationUpdateTest : BaseBizValidationTest() {
|
||||
override val command: ChatCommand = ChatCommand.UPDATE
|
||||
|
||||
@Test fun correctTitle() = validationTitleCorrect(command, processor)
|
||||
@Test fun trimTitle() = validationTitleTrim(command, processor)
|
||||
@Test fun emptyTitle() = validationTitleEmpty(command, processor)
|
||||
@Test fun badSymbolsTitle() = validationTitleSymbols(command, processor)
|
||||
|
||||
@Test fun correctDescription() = validationDescriptionCorrect(command, processor)
|
||||
@Test fun trimDescription() = validationDescriptionTrim(command, processor)
|
||||
@Test fun emptyDescription() = validationDescriptionEmpty(command, processor)
|
||||
@Test fun badSymbolsDescription() = validationDescriptionSymbols(command, processor)
|
||||
|
||||
@Test fun correctId() = validationIdCorrect(command, processor)
|
||||
@Test fun trimId() = validationIdTrim(command, processor)
|
||||
@Test fun emptyId() = validationIdEmpty(command, processor)
|
||||
@Test fun badFormatId() = validationIdFormat(command, processor)
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter.StringSearchField
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.cor.dsl.rootChain
|
||||
|
||||
class ValidateSearchStringLengthTest {
|
||||
@Test
|
||||
fun emptyString() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
state = ChatState.RUNNING,
|
||||
chatFilterValidating = ChatSearchFilter(
|
||||
searchFields = listOf(
|
||||
StringSearchField(
|
||||
fieldName = "title",
|
||||
stringValue = "",
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
chain.exec(ctx)
|
||||
assertEquals(ChatState.RUNNING, ctx.state)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun blankString() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
state = ChatState.RUNNING,
|
||||
chatFilterValidating = ChatSearchFilter(
|
||||
searchFields = listOf(
|
||||
StringSearchField(
|
||||
fieldName = "title",
|
||||
stringValue = " ",
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
chain.exec(ctx)
|
||||
assertEquals(ChatState.RUNNING, ctx.state)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shortString() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
state = ChatState.RUNNING,
|
||||
chatFilterValidating = ChatSearchFilter(
|
||||
searchFields = listOf(
|
||||
StringSearchField(
|
||||
fieldName = "title",
|
||||
stringValue = "12",
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
chain.exec(ctx)
|
||||
assertEquals(ChatState.FAILING, ctx.state)
|
||||
assertEquals(1, ctx.errors.size)
|
||||
assertEquals("validation-searchString-tooShort", ctx.errors.first().code)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun normalString() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
state = ChatState.RUNNING,
|
||||
chatFilterValidating = ChatSearchFilter(
|
||||
searchFields = listOf(
|
||||
StringSearchField(
|
||||
fieldName = "title",
|
||||
stringValue = "123",
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
chain.exec(ctx)
|
||||
assertEquals(ChatState.RUNNING, ctx.state)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun longString() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
state = ChatState.RUNNING,
|
||||
chatFilterValidating = ChatSearchFilter(
|
||||
searchFields = listOf(
|
||||
StringSearchField(
|
||||
fieldName = "title",
|
||||
stringValue = "12".repeat(51),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
chain.exec(ctx)
|
||||
assertEquals(ChatState.FAILING, ctx.state)
|
||||
assertEquals(1, ctx.errors.size)
|
||||
assertEquals("validation-searchString-tooLong", ctx.errors.first().code)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val chain = rootChain {
|
||||
validateSearchStringLength("")
|
||||
}.build()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter
|
||||
import ru.otus.messenger.common.models.ChatSearchFilter.StringSearchField
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.cor.dsl.rootChain
|
||||
|
||||
class ValidateTitleHasContentTest {
|
||||
@Test
|
||||
fun emptyString() = runTest {
|
||||
val ctx = MessengerContext(state = ChatState.RUNNING, chatValidating = MessengerChat(title = ""))
|
||||
chain.exec(ctx)
|
||||
assertEquals(ChatState.RUNNING, ctx.state)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun noContent() = runTest {
|
||||
val ctx =
|
||||
MessengerContext(state = ChatState.RUNNING, chatValidating = MessengerChat(title = "12!@#$%^&*()_+-="))
|
||||
chain.exec(ctx)
|
||||
assertEquals(ChatState.FAILING, ctx.state)
|
||||
assertEquals(1, ctx.errors.size)
|
||||
assertEquals("validation-title-noContent", ctx.errors.first().code)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun normalString() = runTest {
|
||||
val ctx = MessengerContext(
|
||||
state = ChatState.RUNNING,
|
||||
chatFilterValidating = ChatSearchFilter(
|
||||
searchFields = listOf(
|
||||
StringSearchField(
|
||||
fieldName = "title",
|
||||
stringValue = "Ж"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
chain.exec(ctx)
|
||||
assertEquals(ChatState.RUNNING, ctx.state)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val chain = rootChain {
|
||||
validateTitleHasContent("")
|
||||
}.build()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import kotlin.test.assertContains
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import ru.otus.messenger.biz.MessengerProcessor
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
fun validationDescriptionCorrect(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.get(),
|
||||
)
|
||||
|
||||
processor.exec(ctx)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
assertNotEquals(ChatState.FAILING, ctx.state)
|
||||
assertContains(ctx.chatValidated.description, "description")
|
||||
}
|
||||
|
||||
fun validationDescriptionTrim(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
description = " \n\tabc \n\t"
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
assertNotEquals(ChatState.FAILING, ctx.state)
|
||||
assertEquals("abc", ctx.chatValidated.description)
|
||||
}
|
||||
|
||||
fun validationDescriptionEmpty(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
description = ""
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(1, ctx.errors.size)
|
||||
assertEquals(ChatState.FAILING, ctx.state)
|
||||
val error = ctx.errors.firstOrNull()
|
||||
assertEquals("description", error?.field)
|
||||
assertContains(error?.message ?: "", "description")
|
||||
}
|
||||
|
||||
fun validationDescriptionSymbols(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
description = "!@#$%^&*(),.{}"
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(1, ctx.errors.size)
|
||||
assertEquals(ChatState.FAILING, ctx.state)
|
||||
val error = ctx.errors.firstOrNull()
|
||||
assertEquals("description", error?.field)
|
||||
assertContains(error?.message ?: "", "description")
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import kotlin.test.assertContains
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import ru.otus.messenger.biz.MessengerProcessor
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatId
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
fun validationIdCorrect(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.get(),
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
assertNotEquals(ChatState.FAILING, ctx.state)
|
||||
}
|
||||
|
||||
fun validationIdTrim(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
id = ChatId(" \n\t ${id.asString()} \n\t ")
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
assertNotEquals(ChatState.FAILING, ctx.state)
|
||||
}
|
||||
|
||||
fun validationIdEmpty(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
id = ChatId("")
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(1, ctx.errors.size)
|
||||
assertEquals(ChatState.FAILING, ctx.state)
|
||||
val error = ctx.errors.firstOrNull()
|
||||
assertEquals("id", error?.field)
|
||||
assertContains(error?.message ?: "", "id")
|
||||
}
|
||||
|
||||
fun validationIdFormat(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
id = ChatId("!@#\$%^&*(),.{}")
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(1, ctx.errors.size)
|
||||
assertEquals(ChatState.FAILING, ctx.state)
|
||||
val error = ctx.errors.firstOrNull()
|
||||
assertEquals("id", error?.field)
|
||||
assertContains(error?.message ?: "", "id")
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package ru.otus.messenger.biz.validation
|
||||
|
||||
import kotlin.test.assertContains
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import ru.otus.messenger.biz.MessengerProcessor
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatCommand
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
import ru.otus.messenger.common.models.WorkMode
|
||||
import ru.otus.messenger.stubs.MessengerChatStub
|
||||
|
||||
fun validationTitleCorrect(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
title = "abc"
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
assertNotEquals(ChatState.FAILING, ctx.state)
|
||||
assertEquals("abc", ctx.chatValidated.title)
|
||||
}
|
||||
|
||||
fun validationTitleTrim(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
title = " \n\t abc \t\n "
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(0, ctx.errors.size)
|
||||
assertNotEquals(ChatState.FAILING, ctx.state)
|
||||
assertEquals("abc", ctx.chatValidated.title)
|
||||
}
|
||||
|
||||
fun validationTitleEmpty(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
title = ""
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(1, ctx.errors.size)
|
||||
assertEquals(ChatState.FAILING, ctx.state)
|
||||
val error = ctx.errors.firstOrNull()
|
||||
assertEquals("title", error?.field)
|
||||
assertContains(error?.message ?: "", "title")
|
||||
}
|
||||
|
||||
fun validationTitleSymbols(command: ChatCommand, processor: MessengerProcessor) = runTest {
|
||||
val ctx = MessengerContext(
|
||||
command = command,
|
||||
state = ChatState.NONE,
|
||||
workMode = WorkMode.TEST,
|
||||
chatRequest = MessengerChatStub.prepareResult {
|
||||
title = "!@#$%^&*(),.{}"
|
||||
},
|
||||
)
|
||||
processor.exec(ctx)
|
||||
assertEquals(1, ctx.errors.size)
|
||||
assertEquals(ChatState.FAILING, ctx.state)
|
||||
val error = ctx.errors.firstOrNull()
|
||||
assertEquals("title", error?.field)
|
||||
assertContains(error?.message ?: "", "title")
|
||||
}
|
||||
@ -2,7 +2,7 @@ package ru.otus.messenger.common
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
import ru.otus.messenger.common.models.*
|
||||
import ru.otus.messenger.common.stubs.Stubs
|
||||
import ru.otus.messenger.common.stubs.MessengerStubs
|
||||
import ru.otus.messenger.common.ws.IMessengerWsSession
|
||||
|
||||
data class MessengerContext(
|
||||
@ -10,8 +10,9 @@ data class MessengerContext(
|
||||
var state: ChatState = ChatState.NONE,
|
||||
val errors: MutableList<ChatError> = mutableListOf(),
|
||||
|
||||
var corSettings: MessengerCorSettings = MessengerCorSettings(),
|
||||
var workMode: WorkMode = WorkMode.PROD,
|
||||
var stubCase: Stubs = Stubs.NONE,
|
||||
var stubCase: MessengerStubs = MessengerStubs.NONE,
|
||||
var wsSession: IMessengerWsSession = IMessengerWsSession.NONE,
|
||||
|
||||
var requestId: RequestId = RequestId.NONE,
|
||||
@ -19,6 +20,12 @@ data class MessengerContext(
|
||||
var chatRequest: MessengerChat = MessengerChat(),
|
||||
var chatFilterRequest: ChatSearchFilter = ChatSearchFilter.NONE,
|
||||
|
||||
var chatValidating: MessengerChat = MessengerChat(),
|
||||
var chatFilterValidating: ChatSearchFilter = ChatSearchFilter.NONE,
|
||||
|
||||
var chatValidated: MessengerChat = MessengerChat(),
|
||||
var chatFilterValidated: ChatSearchFilter = ChatSearchFilter.NONE,
|
||||
|
||||
var chatResponse: MessengerChat = MessengerChat(),
|
||||
var chatsResponse: MutableList<MessengerChat> = mutableListOf(),
|
||||
)
|
||||
@ -0,0 +1,12 @@
|
||||
package ru.otus.messenger.common.helpers
|
||||
|
||||
import ru.otus.messenger.common.MessengerContext
|
||||
import ru.otus.messenger.common.models.ChatError
|
||||
import ru.otus.messenger.common.models.ChatState
|
||||
|
||||
fun MessengerContext.addError(vararg error: ChatError) = errors.addAll(error)
|
||||
|
||||
fun MessengerContext.fail(error: ChatError) {
|
||||
addError(error)
|
||||
state = ChatState.FAILING
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package ru.otus.messenger.common.helpers
|
||||
|
||||
import ru.otus.messenger.common.models.ChatError
|
||||
import ru.otus.messenger.logging.common.LogLevel
|
||||
|
||||
fun Throwable.asMessengerError(
|
||||
code: String = "unknown",
|
||||
@ -12,4 +13,17 @@ fun Throwable.asMessengerError(
|
||||
field = "",
|
||||
message = message,
|
||||
exception = this,
|
||||
)
|
||||
|
||||
fun errorValidation(
|
||||
field: String,
|
||||
violationCode: String,
|
||||
description: String,
|
||||
level: LogLevel = LogLevel.ERROR,
|
||||
) = ChatError(
|
||||
code = "validation-$field-$violationCode",
|
||||
field = field,
|
||||
group = "validation",
|
||||
message = "Validation error for field $field: $description",
|
||||
level = level,
|
||||
)
|
||||
@ -6,9 +6,14 @@ data class ChatSearchFilter(
|
||||
var type: ChatType = ChatType.NONE,
|
||||
var mode: ChatMode = ChatMode.NONE,
|
||||
) {
|
||||
fun deepCopy(): ChatSearchFilter = copy(
|
||||
searchFields = searchFields.toMutableList().toList()
|
||||
)
|
||||
|
||||
interface SearchField {
|
||||
val fieldName: String
|
||||
val action: SearchAction
|
||||
fun deepCopy(fieldName: String? = null): SearchField
|
||||
}
|
||||
|
||||
enum class SearchAction {
|
||||
@ -21,10 +26,24 @@ data class ChatSearchFilter(
|
||||
data class StringSearchField(
|
||||
override val fieldName: String,
|
||||
override val action: SearchAction = SearchAction.CONTAINS,
|
||||
val stringValue: String,
|
||||
) : SearchField
|
||||
var stringValue: String,
|
||||
) : SearchField {
|
||||
override fun deepCopy(fieldName: String?): SearchField {
|
||||
fieldName?.let {
|
||||
return this.copy(fieldName = it)
|
||||
}
|
||||
return this.copy()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val NONE = ChatSearchFilter()
|
||||
val NONE = ChatSearchFilter(
|
||||
searchFields = listOf(
|
||||
StringSearchField(
|
||||
fieldName = "",
|
||||
stringValue = ""
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,8 @@ data class MessengerChat(
|
||||
) {
|
||||
fun isEmpty() = this == NONE
|
||||
|
||||
fun deepCopy(): MessengerChat = copy()
|
||||
|
||||
companion object {
|
||||
private val NONE = MessengerChat()
|
||||
}
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
package ru.otus.messenger.common.stubs
|
||||
|
||||
enum class Stubs {
|
||||
enum class MessengerStubs {
|
||||
NONE,
|
||||
SUCCESS,
|
||||
NOT_FOUND,
|
||||
BAD_ID,
|
||||
BAD_TITLE,
|
||||
BAD_DESCRIPTION,
|
||||
BAD_ARCHIVED,
|
||||
CANNOT_DELETE,
|
||||
MISSING_DATA,
|
||||
VALUE_ERROR,
|
||||
BAD_SEARCH_STRING,
|
||||
DB_ERROR,
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
package ru.otus.messenger.stubs
|
||||
|
||||
import ru.otus.messenger.common.models.ChatMode
|
||||
import ru.otus.messenger.common.models.ChatType
|
||||
import ru.otus.messenger.common.models.MessengerChat
|
||||
import ru.otus.messenger.stubs.MessengerChatStubSample.CHAT_SAMPLE_1
|
||||
@ -14,9 +13,8 @@ object MessengerChatStub {
|
||||
fun prepareSearchList(
|
||||
chatTitle: String,
|
||||
chatType: ChatType,
|
||||
chatMode: ChatMode,
|
||||
) = listOf(
|
||||
CHAT_SAMPLE_1,
|
||||
CHAT_SAMPLE_2
|
||||
).filter { it.title == chatTitle && it.type == chatType && it.mode == chatMode }
|
||||
).filter { it.title == chatTitle && it.type == chatType }
|
||||
}
|
||||
11
ok-messenger-libs/ok-messenger-lib-cor/build.gradle.kts
Normal file
11
ok-messenger-libs/ok-messenger-lib-cor/build.gradle.kts
Normal file
@ -0,0 +1,11 @@
|
||||
plugins {
|
||||
id("build-jvm")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib"))
|
||||
implementation(libs.kotlin.coroutines)
|
||||
|
||||
testImplementation(kotlin("test-junit"))
|
||||
testImplementation(libs.kotlin.coroutines.test)
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
package ru.otus.messenger.cor
|
||||
|
||||
@DslMarker
|
||||
annotation class CorDslMarker
|
||||
@ -0,0 +1,10 @@
|
||||
package ru.otus.messenger.cor
|
||||
|
||||
/**
|
||||
* Блок кода, который обрабатывает контекст. Имеет имя и описание
|
||||
*/
|
||||
interface ICorExec<T> {
|
||||
val title: String
|
||||
val description: String
|
||||
suspend fun exec(context: T)
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package ru.otus.messenger.cor.dsl
|
||||
|
||||
import ru.otus.messenger.cor.CorDslMarker
|
||||
import ru.otus.messenger.cor.ICorExec
|
||||
import ru.otus.messenger.cor.handlers.CorChain
|
||||
|
||||
@CorDslMarker
|
||||
class CorChainDsl<T>(
|
||||
) : CorExecDsl<T>(), ICorChainDsl<T> {
|
||||
private val workers: MutableList<ICorExecDsl<T>> = mutableListOf()
|
||||
override fun add(worker: ICorExecDsl<T>) {
|
||||
workers.add(worker)
|
||||
}
|
||||
|
||||
override fun build(): ICorExec<T> = CorChain(
|
||||
title = title,
|
||||
description = description,
|
||||
execs = workers.map { it.build() },
|
||||
blockOn = blockOn,
|
||||
blockExcept = blockExcept
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package ru.otus.messenger.cor.dsl
|
||||
|
||||
/**
|
||||
* Точка входа в dsl построения цепочек.
|
||||
* Элементы исполняются последовательно.
|
||||
*
|
||||
* Пример:
|
||||
* ```
|
||||
* rootChain<SomeContext> {
|
||||
* worker {
|
||||
* }
|
||||
* chain {
|
||||
* worker(...) {
|
||||
* }
|
||||
* worker(...) {
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
fun <T> rootChain(function: ICorChainDsl<T>.() -> Unit): ICorChainDsl<T> = CorChainDsl<T>().apply(function)
|
||||
|
||||
|
||||
/**
|
||||
* Создает цепочку, элементы которой исполняются последовательно.
|
||||
*/
|
||||
fun <T> ICorChainDsl<T>.chain(function: ICorChainDsl<T>.() -> Unit) {
|
||||
add(CorChainDsl<T>().apply(function))
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает рабочего
|
||||
*/
|
||||
fun <T> ICorChainDsl<T>.worker(function: ICorWorkerDsl<T>.() -> Unit) {
|
||||
add(CorWorkerDsl<T>().apply(function))
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает рабочего с on и except по умолчанию
|
||||
*/
|
||||
fun <T> ICorChainDsl<T>.worker(
|
||||
title: String,
|
||||
description: String = "",
|
||||
blockHandle: T.() -> Unit
|
||||
) {
|
||||
add(CorWorkerDsl<T>().also {
|
||||
it.title = title
|
||||
it.description = description
|
||||
it.handle(blockHandle)
|
||||
})
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package ru.otus.messenger.cor.dsl
|
||||
|
||||
abstract class CorExecDsl<T> : ICorExecDsl<T> {
|
||||
protected var blockOn: suspend T.() -> Boolean = { true }
|
||||
protected var blockExcept: suspend T.(e: Throwable) -> Unit = { e: Throwable -> throw e }
|
||||
|
||||
override var title: String = ""
|
||||
override var description: String = ""
|
||||
|
||||
override fun on(function: suspend T.() -> Boolean) {
|
||||
blockOn = function
|
||||
}
|
||||
|
||||
override fun except(function: suspend T.(e: Throwable) -> Unit) {
|
||||
blockExcept = function
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package ru.otus.messenger.cor.dsl
|
||||
|
||||
import ru.otus.messenger.cor.CorDslMarker
|
||||
import ru.otus.messenger.cor.ICorExec
|
||||
import ru.otus.messenger.cor.handlers.CorWorker
|
||||
|
||||
@CorDslMarker
|
||||
class CorWorkerDsl<T> : CorExecDsl<T>(), ICorWorkerDsl<T> {
|
||||
private var blockHandle: suspend T.() -> Unit = {}
|
||||
override fun handle(function: suspend T.() -> Unit) {
|
||||
blockHandle = function
|
||||
}
|
||||
|
||||
override fun build(): ICorExec<T> = CorWorker(
|
||||
title = title,
|
||||
description = description,
|
||||
blockOn = blockOn,
|
||||
blockHandle = blockHandle,
|
||||
blockExcept = blockExcept
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package ru.otus.messenger.cor.dsl
|
||||
|
||||
import ru.otus.messenger.cor.CorDslMarker
|
||||
|
||||
/**
|
||||
* Билдер (dsl) для цепочек (chain)
|
||||
*/
|
||||
@CorDslMarker
|
||||
interface ICorChainDsl<T> : ICorExecDsl<T> {
|
||||
fun add(worker: ICorExecDsl<T>)
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package ru.otus.messenger.cor.dsl
|
||||
|
||||
import ru.otus.messenger.cor.CorDslMarker
|
||||
import ru.otus.messenger.cor.ICorExec
|
||||
|
||||
/**
|
||||
* Базовый билдер (dsl)
|
||||
*/
|
||||
@CorDslMarker
|
||||
interface ICorExecDsl<T> {
|
||||
var title: String
|
||||
var description: String
|
||||
fun on(function: suspend T.() -> Boolean)
|
||||
fun except(function: suspend T.(e: Throwable) -> Unit)
|
||||
|
||||
fun build(): ICorExec<T>
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package ru.otus.messenger.cor.dsl
|
||||
|
||||
import ru.otus.messenger.cor.CorDslMarker
|
||||
|
||||
/**
|
||||
* Билдер (dsl) для рабочих (worker)
|
||||
*/
|
||||
@CorDslMarker
|
||||
interface ICorWorkerDsl<T> : ICorExecDsl<T> {
|
||||
fun handle(function: suspend T.() -> Unit)
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package ru.otus.messenger.cor.handlers
|
||||
|
||||
import ru.otus.messenger.cor.ICorExec
|
||||
|
||||
abstract class AbstractCorExec<T>(
|
||||
override val title: String,
|
||||
override val description: String = "",
|
||||
private val blockOn: suspend T.() -> Boolean = { true },
|
||||
private val blockExcept: suspend T.(Throwable) -> Unit = {},
|
||||
): ICorExec<T> {
|
||||
protected abstract suspend fun handle(context: T)
|
||||
|
||||
private suspend fun on(context: T): Boolean = context.blockOn()
|
||||
private suspend fun except(context: T, e: Throwable) = context.blockExcept(e)
|
||||
|
||||
override suspend fun exec(context: T) {
|
||||
if (on(context)) {
|
||||
try {
|
||||
handle(context)
|
||||
} catch (e: Throwable) {
|
||||
except(context, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package ru.otus.messenger.cor.handlers
|
||||
|
||||
import ru.otus.messenger.cor.ICorExec
|
||||
|
||||
/**
|
||||
* Реализация цепочки (chain), которая исполняет свои вложенные цепочки и рабочие
|
||||
*/
|
||||
class CorChain<T>(
|
||||
private val execs: List<ICorExec<T>>,
|
||||
title: String,
|
||||
description: String = "",
|
||||
blockOn: suspend T.() -> Boolean = { true },
|
||||
blockExcept: suspend T.(Throwable) -> Unit = {},
|
||||
) : AbstractCorExec<T>(title, description, blockOn, blockExcept) {
|
||||
override suspend fun handle(context: T) {
|
||||
execs.forEach {
|
||||
it.exec(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package ru.otus.messenger.cor.handlers
|
||||
|
||||
class CorWorker<T>(
|
||||
title: String,
|
||||
description: String = "",
|
||||
blockOn: suspend T.() -> Boolean = { true },
|
||||
private val blockHandle: suspend T.() -> Unit = {},
|
||||
blockExcept: suspend T.(Throwable) -> Unit = {},
|
||||
) : AbstractCorExec<T>(title, description, blockOn, blockExcept) {
|
||||
override suspend fun handle(context: T) = blockHandle(context)
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package ru.otus.messenger.cor
|
||||
|
||||
import junit.framework.Assert.assertEquals
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import ru.otus.messenger.cor.handlers.CorChain
|
||||
import ru.otus.messenger.cor.handlers.CorWorker
|
||||
|
||||
class CorChainTest {
|
||||
@Test
|
||||
fun `chain should execute workers`() = runTest {
|
||||
val createWorker = { title: String ->
|
||||
CorWorker<TestContext>(
|
||||
title = title,
|
||||
blockOn = { status == TestContext.CorStatus.NONE },
|
||||
blockHandle = { history += "$title; " }
|
||||
)
|
||||
}
|
||||
val chain = CorChain<TestContext>(
|
||||
execs = listOf(createWorker("w1"), createWorker("w2")),
|
||||
title = "chain",
|
||||
)
|
||||
val ctx = TestContext()
|
||||
chain.exec(ctx)
|
||||
assertEquals("w1; w2; ", ctx.history)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
package ru.otus.messenger.cor
|
||||
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFails
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import ru.otus.messenger.cor.dsl.ICorChainDsl
|
||||
import ru.otus.messenger.cor.dsl.ICorExecDsl
|
||||
import ru.otus.messenger.cor.dsl.chain
|
||||
import ru.otus.messenger.cor.dsl.rootChain
|
||||
import ru.otus.messenger.cor.dsl.worker
|
||||
|
||||
class CorDslTest {
|
||||
private suspend fun execute(dsl: ICorExecDsl<TestContext>): TestContext {
|
||||
val ctx = TestContext()
|
||||
dsl.build().exec(ctx)
|
||||
return ctx
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `handle should execute`() = runTest {
|
||||
val chain = rootChain<TestContext> {
|
||||
worker {
|
||||
handle { history += "w1; " }
|
||||
}
|
||||
}
|
||||
val ctx = execute(chain)
|
||||
assertEquals("w1; ", ctx.history)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on should check condition`() = runTest {
|
||||
val chain = rootChain<TestContext> {
|
||||
worker {
|
||||
on { status == TestContext.CorStatus.ERROR }
|
||||
handle { history += "w1; " }
|
||||
}
|
||||
worker {
|
||||
on { status == TestContext.CorStatus.NONE }
|
||||
handle {
|
||||
history += "w2; "
|
||||
status = TestContext.CorStatus.FAILING
|
||||
}
|
||||
}
|
||||
worker {
|
||||
on { status == TestContext.CorStatus.FAILING }
|
||||
handle { history += "w3; " }
|
||||
}
|
||||
}
|
||||
assertEquals("w2; w3; ", execute(chain).history)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `except should execute when exception`() = runTest {
|
||||
val chain = rootChain<TestContext> {
|
||||
worker {
|
||||
handle { throw RuntimeException("some error") }
|
||||
except { history += it.message }
|
||||
}
|
||||
}
|
||||
assertEquals("some error", execute(chain).history)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should throw when exception and no except`() = runTest {
|
||||
val chain = rootChain<TestContext> {
|
||||
worker("throw") { throw RuntimeException("some error") }
|
||||
}
|
||||
assertFails {
|
||||
execute(chain)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `complex chain example`() = runTest {
|
||||
val chain = rootChain<TestContext> {
|
||||
worker {
|
||||
title = "Инициализация статуса"
|
||||
description = "При старте обработки цепочки, статус еще не установлен. Проверяем его"
|
||||
|
||||
on { status == TestContext.CorStatus.NONE }
|
||||
handle { status = TestContext.CorStatus.RUNNING }
|
||||
except { status = TestContext.CorStatus.ERROR }
|
||||
}
|
||||
|
||||
chain {
|
||||
on { status == TestContext.CorStatus.RUNNING }
|
||||
|
||||
worker(
|
||||
title = "Лямбда обработчик",
|
||||
description = "Пример использования обработчика в виде лямбды"
|
||||
) {
|
||||
some += 4
|
||||
}
|
||||
}
|
||||
|
||||
printResult()
|
||||
|
||||
}.build()
|
||||
|
||||
val ctx = TestContext()
|
||||
chain.exec(ctx)
|
||||
println("Complete: $ctx")
|
||||
}
|
||||
|
||||
private fun ICorChainDsl<TestContext>.printResult() = worker(title = "Print example") {
|
||||
println("some = $some")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package ru.otus.messenger.cor
|
||||
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import ru.otus.messenger.cor.handlers.CorWorker
|
||||
|
||||
class CorWorkerTest {
|
||||
@Test
|
||||
fun `worker should execute handle`() = runTest {
|
||||
val worker = CorWorker<TestContext>(
|
||||
title = "w1",
|
||||
blockHandle = { history += "w1; " }
|
||||
)
|
||||
val ctx = TestContext()
|
||||
worker.exec(ctx)
|
||||
assertEquals("w1; ", ctx.history)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `worker should not execute when off`() = runTest {
|
||||
val worker = CorWorker<TestContext>(
|
||||
title = "w1",
|
||||
blockOn = { status == TestContext.CorStatus.ERROR },
|
||||
blockHandle = { history += "w1; " }
|
||||
)
|
||||
val ctx = TestContext()
|
||||
worker.exec(ctx)
|
||||
assertEquals("", ctx.history)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `worker should handle exception`() = runTest {
|
||||
val worker = CorWorker<TestContext>(
|
||||
title = "w1",
|
||||
blockHandle = { throw RuntimeException("some error") },
|
||||
blockExcept = { e -> history += e.message }
|
||||
)
|
||||
val ctx = TestContext()
|
||||
worker.exec(ctx)
|
||||
assertEquals("some error", ctx.history)
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package ru.otus.messenger.cor
|
||||
|
||||
data class TestContext(
|
||||
var status: CorStatus = CorStatus.NONE,
|
||||
var some: Int = 0,
|
||||
var history: String = "",
|
||||
) {
|
||||
enum class CorStatus {
|
||||
NONE,
|
||||
RUNNING,
|
||||
FAILING,
|
||||
ERROR
|
||||
}
|
||||
}
|
||||
@ -23,4 +23,5 @@ plugins {
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0"
|
||||
}
|
||||
|
||||
include(":ok-messenger-lib-logging")
|
||||
include(":ok-messenger-lib-logging")
|
||||
include(":ok-messenger-lib-cor")
|
||||
Reference in New Issue
Block a user