From 7725416dfee3d0f10daebc03700e217a14e2b665 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 22 Sep 2024 22:29:20 -0300 Subject: [PATCH 01/34] add system creation module --- app-creation/build.gradle.kts | 25 +++++ app-creation/gradle.properties | 2 + .../com/usvision/creation/SystemCreator.kt | 105 ++++++++++++++++++ .../com/usvision/creation/SystemRepository.kt | 10 ++ settings.gradle.kts | 3 +- 5 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 app-creation/build.gradle.kts create mode 100644 app-creation/gradle.properties create mode 100644 app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt create mode 100644 app-creation/src/main/kotlin/com/usvision/creation/SystemRepository.kt diff --git a/app-creation/build.gradle.kts b/app-creation/build.gradle.kts new file mode 100644 index 0000000..3e9d301 --- /dev/null +++ b/app-creation/build.gradle.kts @@ -0,0 +1,25 @@ +val mockk_version: String by project + +plugins { + `java-library` + kotlin("jvm") + kotlin("plugin.serialization") +} + +group = "com.usvision.reports" +version = "0.0.1" + +repositories { + mavenCentral() +} + +tasks.test { + useJUnitPlatform() +} + +dependencies { + implementation(project(":app-model")) + testImplementation("io.mockk:mockk:${mockk_version}") + testImplementation(kotlin("test")) + implementation(project(":app-model")) +} diff --git a/app-creation/gradle.properties b/app-creation/gradle.properties new file mode 100644 index 0000000..c65e709 --- /dev/null +++ b/app-creation/gradle.properties @@ -0,0 +1,2 @@ +mockk_version=1.12.3 +kotlin.code.style=official diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt new file mode 100644 index 0000000..9debfa8 --- /dev/null +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt @@ -0,0 +1,105 @@ +package com.usvision.creation + +import com.usvision.model.domain.CompanySystem +import com.usvision.model.domain.MessageChannel +import com.usvision.model.domain.Microservice +import com.usvision.model.domain.databases.Database +import com.usvision.model.domain.operations.Operation +import com.usvision.model.systemcomposite.System + +typealias CompanySystemDTO = CompanySystem +typealias SystemDTO = System +typealias MicroserviceDTO = Microservice +typealias DatabaseDTO = Database + +class SystemCreator( + private val systemRepository: SystemRepository +) { + + fun createCompanySystem(companySystem: CompanySystemDTO): CompanySystemDTO { + checkIfSystemAlreadyExists(companySystem.name) + return systemRepository.save(companySystem) as CompanySystemDTO + } + + fun createSubsystem(system: SystemDTO, fatherSystemName: String? = null): SystemDTO { + checkIfSystemAlreadyExists(system.name) + + fatherSystemName?.also { + val fatherSystem = systemRepository.getSystemOfSystems(fatherSystemName) + + return@createSubsystem fatherSystem?.let { + fatherSystem.addSubsystem(system) + systemRepository.save(fatherSystem) + } ?: throw Exception("A System Of Systems with name $fatherSystemName does not exist") + } + + return systemRepository.save(system) + } + + fun createMicroservice( + microservice: MicroserviceDTO, + fatherSystemName: String? = null + ) = createSubsystem(microservice, fatherSystemName) as MicroserviceDTO + + fun addNewDatabaseConnectionToMicroservice( + database: DatabaseDTO, + microserviceName: String + ) = getExistingMicroservice(microserviceName).let { + it.addDatabaseConnection(database) + systemRepository.save(it) + } + + fun addExposedOperationsToMicroservice( + exposedOperations: List, + microserviceName: String + ) = getExistingMicroservice(microserviceName).let { + exposedOperations.forEach { + operation -> it.exposeOperation(operation) + } + systemRepository.save(it) + } + + + fun addConsumedOperationsToMicroservice( + exposedOperations: List, + microserviceName: String + ) = getExistingMicroservice(microserviceName).let { + exposedOperations.forEach { + operation -> it.exposeOperation(operation) + } + systemRepository.save(it) + } + + + fun addPublishChannelsToMicroservice( + messageChannels: List, + microserviceName: String + ) = getExistingMicroservice(microserviceName).let { + messageChannels.forEach { + operation -> it.addPublishChannel(operation) + } + systemRepository.save(it) + } + + fun addSubscribedChannelsOperationsToMicroservice( + messageChannels: List, + microserviceName: String + ) = getExistingMicroservice(microserviceName).let { + messageChannels.forEach { + operation -> it.addSubscribedChannel(operation) + } + systemRepository.save(it) + } + + private fun getExistingMicroservice( + microserviceName: String + ) = systemRepository.getSystem( + microserviceName + ) as MicroserviceDTO? ?: throw Exception("A Microservice with name $microserviceName does not exist") + + private fun checkIfSystemAlreadyExists(name: String) { + systemRepository.getSystem(name)?.also { + throw Exception("A system with name $name already exists") + } + } +} \ No newline at end of file diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemRepository.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemRepository.kt new file mode 100644 index 0000000..186bc4d --- /dev/null +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemRepository.kt @@ -0,0 +1,10 @@ +package com.usvision.creation + +import com.usvision.model.systemcomposite.System +import com.usvision.model.systemcomposite.SystemOfSystems + +interface SystemRepository { + fun getSystem(name: String): System? + fun save(system: System): System + fun getSystemOfSystems(fatherSystemName: String): SystemOfSystems? +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 0190d34..d64241d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -4,4 +4,5 @@ include("app-model") include("app-analyses") include("app-reports") include("app-persistence") -include("app-web") \ No newline at end of file +include("app-web") +include("app-creation") From cb3c7f32bcbc97171b7c165d072f082c78a456d6 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 29 Sep 2024 01:05:12 -0300 Subject: [PATCH 02/34] refactor SystemCreator class and SystemAggregateStorage interface --- .../creation/SystemAggregateStorage.kt | 12 ++++++ .../com/usvision/creation/SystemCreator.kt | 37 ++++++++----------- .../com/usvision/creation/SystemRepository.kt | 10 ----- 3 files changed, 28 insertions(+), 31 deletions(-) create mode 100644 app-creation/src/main/kotlin/com/usvision/creation/SystemAggregateStorage.kt delete mode 100644 app-creation/src/main/kotlin/com/usvision/creation/SystemRepository.kt diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemAggregateStorage.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemAggregateStorage.kt new file mode 100644 index 0000000..851ad5d --- /dev/null +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemAggregateStorage.kt @@ -0,0 +1,12 @@ +package com.usvision.creation + +import com.usvision.model.domain.CompanySystem +import com.usvision.model.domain.Microservice +import com.usvision.model.systemcomposite.System + +interface SystemAggregateStorage { + fun getSystem(name: String): System? + fun save(microservice: Microservice): Microservice + fun save(companySystem: CompanySystem): CompanySystem + fun getCompanySystem(name: String): CompanySystem? +} \ No newline at end of file diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt index 9debfa8..0551a6e 100644 --- a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt @@ -13,40 +13,35 @@ typealias MicroserviceDTO = Microservice typealias DatabaseDTO = Database class SystemCreator( - private val systemRepository: SystemRepository + private val systemAggregateStorage: SystemAggregateStorage ) { fun createCompanySystem(companySystem: CompanySystemDTO): CompanySystemDTO { checkIfSystemAlreadyExists(companySystem.name) - return systemRepository.save(companySystem) as CompanySystemDTO + return systemAggregateStorage.save(companySystem) } - fun createSubsystem(system: SystemDTO, fatherSystemName: String? = null): SystemDTO { - checkIfSystemAlreadyExists(system.name) + fun createMicroservice(microservice: MicroserviceDTO, fatherSystemName: String? = null): SystemDTO { + checkIfSystemAlreadyExists(microservice.name) fatherSystemName?.also { - val fatherSystem = systemRepository.getSystemOfSystems(fatherSystemName) + val fatherSystem = systemAggregateStorage.getCompanySystem(fatherSystemName) - return@createSubsystem fatherSystem?.let { - fatherSystem.addSubsystem(system) - systemRepository.save(fatherSystem) + return@createMicroservice fatherSystem?.let { + fatherSystem.addSubsystem(microservice) + systemAggregateStorage.save(fatherSystem) } ?: throw Exception("A System Of Systems with name $fatherSystemName does not exist") } - return systemRepository.save(system) + return systemAggregateStorage.save(microservice) } - fun createMicroservice( - microservice: MicroserviceDTO, - fatherSystemName: String? = null - ) = createSubsystem(microservice, fatherSystemName) as MicroserviceDTO - fun addNewDatabaseConnectionToMicroservice( database: DatabaseDTO, microserviceName: String ) = getExistingMicroservice(microserviceName).let { it.addDatabaseConnection(database) - systemRepository.save(it) + systemAggregateStorage.save(it) } fun addExposedOperationsToMicroservice( @@ -56,7 +51,7 @@ class SystemCreator( exposedOperations.forEach { operation -> it.exposeOperation(operation) } - systemRepository.save(it) + systemAggregateStorage.save(it) } @@ -67,7 +62,7 @@ class SystemCreator( exposedOperations.forEach { operation -> it.exposeOperation(operation) } - systemRepository.save(it) + systemAggregateStorage.save(it) } @@ -78,7 +73,7 @@ class SystemCreator( messageChannels.forEach { operation -> it.addPublishChannel(operation) } - systemRepository.save(it) + systemAggregateStorage.save(it) } fun addSubscribedChannelsOperationsToMicroservice( @@ -88,17 +83,17 @@ class SystemCreator( messageChannels.forEach { operation -> it.addSubscribedChannel(operation) } - systemRepository.save(it) + systemAggregateStorage.save(it) } private fun getExistingMicroservice( microserviceName: String - ) = systemRepository.getSystem( + ) = systemAggregateStorage.getSystem( microserviceName ) as MicroserviceDTO? ?: throw Exception("A Microservice with name $microserviceName does not exist") private fun checkIfSystemAlreadyExists(name: String) { - systemRepository.getSystem(name)?.also { + systemAggregateStorage.getSystem(name)?.also { throw Exception("A system with name $name already exists") } } diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemRepository.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemRepository.kt deleted file mode 100644 index 186bc4d..0000000 --- a/app-creation/src/main/kotlin/com/usvision/creation/SystemRepository.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.usvision.creation - -import com.usvision.model.systemcomposite.System -import com.usvision.model.systemcomposite.SystemOfSystems - -interface SystemRepository { - fun getSystem(name: String): System? - fun save(system: System): System - fun getSystemOfSystems(fatherSystemName: String): SystemOfSystems? -} \ No newline at end of file From 53e5b0ed03ea4bd16fa2e0f55cdf5e3a70356b0a Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 29 Sep 2024 01:16:01 -0300 Subject: [PATCH 03/34] add SystemAggregateStorage implementation to MongoSystemRepository --- .../com/usvision/model/domain/Module.kt | 2 +- app-persistence/build.gradle.kts | 1 + .../persistence/documents/SystemDocument.kt | 81 ++++++++++++++++--- .../UnknownOperationClassException.kt | 4 + .../exceptions/UnknownSystemClassException.kt | 4 + .../repositories/MongoSystemRepository.kt | 56 ++++++++++--- 6 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt create mode 100644 app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt diff --git a/app-model/src/main/kotlin/com/usvision/model/domain/Module.kt b/app-model/src/main/kotlin/com/usvision/model/domain/Module.kt index 649f26b..cda8ffe 100644 --- a/app-model/src/main/kotlin/com/usvision/model/domain/Module.kt +++ b/app-model/src/main/kotlin/com/usvision/model/domain/Module.kt @@ -7,7 +7,7 @@ import java.util.UUID @Serializable data class Module( - val id: String? + val id: String ) : Visitable { companion object { fun createWithId() = Module(id = UUID.randomUUID().toString()) diff --git a/app-persistence/build.gradle.kts b/app-persistence/build.gradle.kts index 9ff33b0..22efacf 100644 --- a/app-persistence/build.gradle.kts +++ b/app-persistence/build.gradle.kts @@ -21,6 +21,7 @@ tasks.test { dependencies { implementation(project(":app-model")) implementation(project(":app-reports")) + implementation(project(":app-creation")) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutine_version") implementation("org.mongodb:mongodb-driver-kotlin-coroutine:$mongodb_version") diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt index 960c816..178b525 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt @@ -1,6 +1,15 @@ package com.usvision.persistence.documents +import com.usvision.model.domain.CompanySystem +import com.usvision.model.domain.MessageChannel +import com.usvision.model.domain.Microservice +import com.usvision.model.domain.Module +import com.usvision.model.domain.databases.Database +import com.usvision.model.domain.operations.Operation import com.usvision.model.domain.operations.RestEndpoint +import com.usvision.model.systemcomposite.System +import com.usvision.persistence.exceptions.UnknownOperationClassException +import com.usvision.persistence.exceptions.UnknownSystemClassException import org.bson.Document import org.bson.codecs.pojo.annotations.BsonId import org.bson.types.ObjectId @@ -17,14 +26,6 @@ data class SystemDocument( val module: ModuleDocument? = null ) -fun RestEndpoint.toDocument(): Document { - return Document().also { doc: Document -> - doc["description"] = this.description - doc["httpVerb"] = this.httpVerb - doc["path"] = this.path - } -} - data class DatabaseDocument( @BsonId val id: ObjectId, val description: String @@ -38,4 +39,66 @@ data class MessageChannelDocument( data class ModuleDocument( @BsonId val id: ObjectId, val uuid: String -) \ No newline at end of file +) + +fun CompanySystem.toDocument( + id: ObjectId = ObjectId() +): SystemDocument = SystemDocument( + id = id, + name = this.name, + subsystems = this.getSubsystemSet().toDocument() +) + +fun Microservice.toDocument( + id: ObjectId = ObjectId() +): SystemDocument = SystemDocument( + id = id, + name = this.name, + module = this.module.toDocument(), + databases = this.getDatabases().toDocument(), + exposedOperations = this.getExposedOperations().toDocument(), + consumedOperations = this.getConsumedOperations().toDocument(), + publishedChannels = this.getPublishChannels().toDocument(), + subscribedChannels = this.getSubscribedChannels().toDocument(), +) + +private fun System.toDocument( + id: ObjectId = ObjectId() +) = when (this) { + is CompanySystem -> { + this.toDocument(id) + } + is Microservice -> { + this.toDocument(id) + } + else -> { + throw UnknownSystemClassException(this.name) + } +} + +private fun Set.toDocument(): Set = this.map { it.toDocument() }.toSet() + +private fun Set.toDocument(): Set = this.map { it.toDocument() }.toSet() + +private fun Set.toDocument(): Set = this.map { it.toDocument() }.toSet() + +fun RestEndpoint.toDocument(): Document { + return Document().also { doc: Document -> + doc["description"] = this.description + doc["httpVerb"] = this.httpVerb + doc["path"] = this.path + } +} + +private fun Set.toDocument(): Set = this.map { it.toDocument() }.toSet() + +private fun MessageChannel.toDocument(id: ObjectId = ObjectId()) = MessageChannelDocument(id = id, name) + +private fun Module.toDocument() = ModuleDocument(id = ObjectId(this.id), uuid = id) + +private fun Operation.toDocument() = when (this) { + is RestEndpoint -> this.toDocument() + else -> throw UnknownOperationClassException() +} + +private fun Database.toDocument() = DatabaseDocument(id = ObjectId(this.id), description = this.description) diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt new file mode 100644 index 0000000..b9cba70 --- /dev/null +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt @@ -0,0 +1,4 @@ +package com.usvision.persistence.exceptions + +class UnknownOperationClassException + : RuntimeException("Operation has a unknown class to SystemDocument") \ No newline at end of file diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt new file mode 100644 index 0000000..f992f0c --- /dev/null +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt @@ -0,0 +1,4 @@ +package com.usvision.persistence.exceptions + +class UnknownSystemClassException(name: String) + : RuntimeException("System $name has a unknown class to SystemDocument") diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt index 53c05bb..2bbf865 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt @@ -3,16 +3,21 @@ package com.usvision.persistence.repositories import com.mongodb.client.model.Filters import com.mongodb.kotlin.client.coroutine.MongoCollection import com.mongodb.kotlin.client.coroutine.MongoDatabase +import com.usvision.creation.SystemAggregateStorage +import com.usvision.model.domain.CompanySystem +import com.usvision.model.domain.Microservice import com.usvision.model.systemcomposite.System import com.usvision.persistence.documents.SystemDocument +import com.usvision.persistence.documents.toDocument import com.usvision.persistence.exceptions.SystemNotFoundException import com.usvision.reports.SystemRepository -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.runBlocking -import java.util.NoSuchElementException +import org.bson.types.ObjectId + class MongoSystemRepository(db: MongoDatabase) : SystemRepository { +class MongoSystemRepository(db: MongoDatabase) : SystemRepository, SystemAggregateStorage { companion object { const val COLLECTION_NAME = "systems" } @@ -23,15 +28,40 @@ class MongoSystemRepository(db: MongoDatabase) : SystemRepository { systemCollection = db.getCollection(COLLECTION_NAME) } - override fun load(name: String): System = try { - runBlocking { - systemCollection - .find(Filters.eq("name", name)) - .limit(1) - .map { SystemMapper.fromDocument(it) } - .first() - } - } catch (nsee: NoSuchElementException) { - throw SystemNotFoundException(name) + + override fun load(name: String): System = getSystem(name) ?: throw SystemNotFoundException(name) + + override fun getSystem(name: String): System? = runBlocking { + systemCollection + .find(Filters.eq("name", name)) + .firstOrNull() + ?.let { SystemMapper.fromDocument(it) } + } + + + override fun save(companySystem: CompanySystem): CompanySystem = runBlocking { + val insertedId = systemCollection.insertOne( + companySystem.toDocument() + ).insertedId ?: throw SystemNotFoundException(companySystem.name) + + getSystemById(ObjectId(insertedId.toString())) as CompanySystem + } + + override fun save(microservice: Microservice): Microservice = runBlocking { + val insertedId = systemCollection.insertOne( + microservice.toDocument() + ).insertedId ?: throw SystemNotFoundException(microservice.name) + + getSystemById(ObjectId(insertedId.toString())) as Microservice + } + + + override fun getCompanySystem(name: String): CompanySystem? = getSystem(name = name) as CompanySystem? + + fun getSystemById(id: ObjectId): System? = runBlocking { + systemCollection + .find(Filters.eq("_id", id)) + .firstOrNull() + ?.let { SystemMapper.fromDocument(it) } } } From 86f3d07335d62b6c133af392abe1f10583998a80 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 29 Sep 2024 21:18:35 -0300 Subject: [PATCH 04/34] adjust Dockerfile to build the app-creation module --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 85afb8e..6f96752 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ FROM gradle:7.4.2-jdk17 AS dependencies WORKDIR /home/gradle/usvision -RUN mkdir app-analyses app-model app-persistence app-reports app-web \ +RUN mkdir app-analyses app-model app-persistence app-reports app-web app-creation \ && chown gradle:gradle . -R USER gradle @@ -20,6 +20,7 @@ COPY --chown=gradle:gradle app-model/build.gradle.kts app-model/gradle COPY --chown=gradle:gradle app-persistence/build.gradle.kts app-persistence/gradle.properties ./app-persistence/ COPY --chown=gradle:gradle app-reports/build.gradle.kts app-reports/gradle.properties ./app-reports/ COPY --chown=gradle:gradle app-web/build.gradle.kts app-web/gradle.properties ./app-web/ +COPY --chown=gradle:gradle app-creation/build.gradle.kts app-creation/gradle.properties ./app-creation # PRE-INSTALL JUST THE DEPENDENCIES -- THIS SHALL SPEEDUP FUTURE BUILDS From d5c1a1104ee278b8debb74353c04d64fc45d7a45 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 29 Sep 2024 21:31:15 -0300 Subject: [PATCH 05/34] refactor SystemDocument due to compilation error --- .../persistence/documents/SystemDocument.kt | 38 +++++++++---------- .../repositories/MongoSystemRepository.kt | 6 +-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt index 178b525..96367fb 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt @@ -41,46 +41,46 @@ data class ModuleDocument( val uuid: String ) -fun CompanySystem.toDocument( +fun CompanySystem.toSystemDocument( id: ObjectId = ObjectId() ): SystemDocument = SystemDocument( id = id, name = this.name, - subsystems = this.getSubsystemSet().toDocument() + subsystems = this.getSubsystemSet().toSystemDocumentSet() ) -fun Microservice.toDocument( +fun Microservice.toSystemDocument( id: ObjectId = ObjectId() ): SystemDocument = SystemDocument( id = id, name = this.name, - module = this.module.toDocument(), - databases = this.getDatabases().toDocument(), - exposedOperations = this.getExposedOperations().toDocument(), - consumedOperations = this.getConsumedOperations().toDocument(), - publishedChannels = this.getPublishChannels().toDocument(), - subscribedChannels = this.getSubscribedChannels().toDocument(), + module = this.module.toModuleDocument(), + databases = this.getDatabases().toDatabaseDocumentSet(), + exposedOperations = this.getExposedOperations().toOperationDocumentSet(), + consumedOperations = this.getConsumedOperations().toOperationDocumentSet(), + publishedChannels = this.getPublishChannels().toMessageChannelDocumentSet(), + subscribedChannels = this.getSubscribedChannels().toMessageChannelDocumentSet(), ) -private fun System.toDocument( +private fun System.toSystemDocument( id: ObjectId = ObjectId() ) = when (this) { is CompanySystem -> { - this.toDocument(id) + this.toSystemDocument(id) } is Microservice -> { - this.toDocument(id) + this.toSystemDocument(id) } else -> { throw UnknownSystemClassException(this.name) } } -private fun Set.toDocument(): Set = this.map { it.toDocument() }.toSet() +private fun Set.toSystemDocumentSet(): Set = this.map { it.toSystemDocument() }.toSet() -private fun Set.toDocument(): Set = this.map { it.toDocument() }.toSet() +private fun Set.toDatabaseDocumentSet(): Set = this.map { it.toDatabaseDocument() }.toSet() -private fun Set.toDocument(): Set = this.map { it.toDocument() }.toSet() +private fun Set.toOperationDocumentSet(): Set = this.map { it.toDocument() }.toSet() fun RestEndpoint.toDocument(): Document { return Document().also { doc: Document -> @@ -90,15 +90,15 @@ fun RestEndpoint.toDocument(): Document { } } -private fun Set.toDocument(): Set = this.map { it.toDocument() }.toSet() +private fun Set.toMessageChannelDocumentSet(): Set = this.map { it.toMessageChannelDocument() }.toSet() -private fun MessageChannel.toDocument(id: ObjectId = ObjectId()) = MessageChannelDocument(id = id, name) +private fun MessageChannel.toMessageChannelDocument(id: ObjectId = ObjectId()) = MessageChannelDocument(id = id, name) -private fun Module.toDocument() = ModuleDocument(id = ObjectId(this.id), uuid = id) +private fun Module.toModuleDocument() = ModuleDocument(id = ObjectId(this.id), uuid = id) private fun Operation.toDocument() = when (this) { is RestEndpoint -> this.toDocument() else -> throw UnknownOperationClassException() } -private fun Database.toDocument() = DatabaseDocument(id = ObjectId(this.id), description = this.description) +private fun Database.toDatabaseDocument() = DatabaseDocument(id = ObjectId(this.id), description = this.description) diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt index 2bbf865..eed11ea 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt @@ -8,7 +8,7 @@ import com.usvision.model.domain.CompanySystem import com.usvision.model.domain.Microservice import com.usvision.model.systemcomposite.System import com.usvision.persistence.documents.SystemDocument -import com.usvision.persistence.documents.toDocument +import com.usvision.persistence.documents.toSystemDocument import com.usvision.persistence.exceptions.SystemNotFoundException import com.usvision.reports.SystemRepository import kotlinx.coroutines.flow.firstOrNull @@ -41,7 +41,7 @@ class MongoSystemRepository(db: MongoDatabase) : SystemRepository, SystemAggrega override fun save(companySystem: CompanySystem): CompanySystem = runBlocking { val insertedId = systemCollection.insertOne( - companySystem.toDocument() + companySystem.toSystemDocument() ).insertedId ?: throw SystemNotFoundException(companySystem.name) getSystemById(ObjectId(insertedId.toString())) as CompanySystem @@ -49,7 +49,7 @@ class MongoSystemRepository(db: MongoDatabase) : SystemRepository, SystemAggrega override fun save(microservice: Microservice): Microservice = runBlocking { val insertedId = systemCollection.insertOne( - microservice.toDocument() + microservice.toSystemDocument() ).insertedId ?: throw SystemNotFoundException(microservice.name) getSystemById(ObjectId(insertedId.toString())) as Microservice From 5798b0b1719805a1da5240b0eff327976edd0cda Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 2 Oct 2024 00:57:05 -0300 Subject: [PATCH 06/34] rename init-mongo.js to mongo-init.js and bind it to the mongo container --- docker-compose.yaml | 1 + init-mongo.js => mongo-init.js | 0 2 files changed, 1 insertion(+) rename init-mongo.js => mongo-init.js (100%) diff --git a/docker-compose.yaml b/docker-compose.yaml index 27a5d43..3031e56 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -16,6 +16,7 @@ services: - ./.env.docker-compose volumes: - mongodb_data:/data/db + - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro ports: - "27017:27017" diff --git a/init-mongo.js b/mongo-init.js similarity index 100% rename from init-mongo.js rename to mongo-init.js From f7c4ab97f29f307db5240b3e8d0d92a0e7222480 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 6 Oct 2024 00:07:51 -0300 Subject: [PATCH 07/34] add CompanySystem as Subsystem in SystemCreator --- .../kotlin/com/usvision/creation/SystemCreator.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt index 0551a6e..32a5b9b 100644 --- a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt @@ -16,8 +16,18 @@ class SystemCreator( private val systemAggregateStorage: SystemAggregateStorage ) { - fun createCompanySystem(companySystem: CompanySystemDTO): CompanySystemDTO { + fun createCompanySystem(companySystem: CompanySystemDTO, fatherSystemName: String? = null): CompanySystemDTO { checkIfSystemAlreadyExists(companySystem.name) + + fatherSystemName?.also { + val fatherSystem = systemAggregateStorage.getCompanySystem(fatherSystemName) + + return@createCompanySystem fatherSystem?.let { + fatherSystem.addSubsystem(companySystem) + systemAggregateStorage.save(fatherSystem) + } ?: throw Exception("A System Of Systems with name $fatherSystemName does not exist") + } + return systemAggregateStorage.save(companySystem) } From 587715d2b452b47af5b7ad629dc1816cec45d7ab Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 6 Oct 2024 00:11:28 -0300 Subject: [PATCH 08/34] refactor: turn addExposedOperationsToMicroservice() and addConsumedOperationsToMicroservice() into addOperationsToMicroservice() --- .../com/usvision/creation/SystemCreator.kt | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt index 32a5b9b..6ca7920 100644 --- a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt @@ -54,28 +54,22 @@ class SystemCreator( systemAggregateStorage.save(it) } - fun addExposedOperationsToMicroservice( + fun addOperationsToMicroservice( exposedOperations: List, + consumedOperations: List, microserviceName: String ) = getExistingMicroservice(microserviceName).let { exposedOperations.forEach { operation -> it.exposeOperation(operation) } - systemAggregateStorage.save(it) - } - - fun addConsumedOperationsToMicroservice( - exposedOperations: List, - microserviceName: String - ) = getExistingMicroservice(microserviceName).let { - exposedOperations.forEach { - operation -> it.exposeOperation(operation) + consumedOperations.forEach { + operation -> it.consumeOperation(operation) } + systemAggregateStorage.save(it) } - fun addPublishChannelsToMicroservice( messageChannels: List, microserviceName: String From d4ca8331c65a6b7a416b6716588bd7b08cc35924 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 6 Oct 2024 00:16:47 -0300 Subject: [PATCH 09/34] refactor: turn addPublishChannelsToMicroservice() and addSubscribedChannelsOperationsToMicroservice() into addMessageChannelsToMicroservice() --- .../com/usvision/creation/SystemCreator.kt | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt index 6ca7920..3fd3545 100644 --- a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt @@ -70,23 +70,19 @@ class SystemCreator( systemAggregateStorage.save(it) } - fun addPublishChannelsToMicroservice( - messageChannels: List, + fun addMessageChannelsToMicroservice( + publishMessageChannels: List, + subscribedMessageChannels: List, microserviceName: String ) = getExistingMicroservice(microserviceName).let { - messageChannels.forEach { + publishMessageChannels.forEach { operation -> it.addPublishChannel(operation) } - systemAggregateStorage.save(it) - } - fun addSubscribedChannelsOperationsToMicroservice( - messageChannels: List, - microserviceName: String - ) = getExistingMicroservice(microserviceName).let { - messageChannels.forEach { - operation -> it.addSubscribedChannel(operation) + subscribedMessageChannels.forEach { + operation -> it.addPublishChannel(operation) } + systemAggregateStorage.save(it) } From 8c330ef711569376ce472d74bced9a27fcb4df07 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 6 Oct 2024 01:00:47 -0300 Subject: [PATCH 10/34] Fix: get ObjectId value from Systems correctly --- .../persistence/repositories/MongoSystemRepository.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt index eed11ea..fea022d 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt @@ -44,7 +44,7 @@ class MongoSystemRepository(db: MongoDatabase) : SystemRepository, SystemAggrega companySystem.toSystemDocument() ).insertedId ?: throw SystemNotFoundException(companySystem.name) - getSystemById(ObjectId(insertedId.toString())) as CompanySystem + getSystemById(insertedId.asObjectId().value) as CompanySystem } override fun save(microservice: Microservice): Microservice = runBlocking { @@ -52,7 +52,7 @@ class MongoSystemRepository(db: MongoDatabase) : SystemRepository, SystemAggrega microservice.toSystemDocument() ).insertedId ?: throw SystemNotFoundException(microservice.name) - getSystemById(ObjectId(insertedId.toString())) as Microservice + getSystemById(insertedId.asObjectId().value) as Microservice } From fbe65922219d2f3426db2ebafc50358f07b081de Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 6 Oct 2024 12:00:14 -0300 Subject: [PATCH 11/34] add http routes accessing SystemCreator --- .../repositorybuilder/DBRepositoryProvider.kt | 2 + .../MongoDBRepositoryProvider.kt | 7 +- app-web/build.gradle.kts | 3 + .../kotlin/com/usvision/web/Application.kt | 6 +- .../MessageChannelsRequestDTO.kt | 8 ++ .../usvision/web/configuration/appcreator.kt | 9 ++ .../usvision/web/configuration/database.kt | 26 +++++ .../com/usvision/web/configuration/reports.kt | 21 +--- .../com/usvision/web/configuration/routing.kt | 108 +++++++++++++++++- .../web/dto/RestEndpointsRequestDTO.kt | 10 ++ 10 files changed, 175 insertions(+), 25 deletions(-) create mode 100644 app-web/src/main/kotlin/com/usvision/web/configuration/MessageChannelsRequestDTO.kt create mode 100644 app-web/src/main/kotlin/com/usvision/web/configuration/appcreator.kt create mode 100644 app-web/src/main/kotlin/com/usvision/web/configuration/database.kt create mode 100644 app-web/src/main/kotlin/com/usvision/web/dto/RestEndpointsRequestDTO.kt diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/repositorybuilder/DBRepositoryProvider.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/repositorybuilder/DBRepositoryProvider.kt index 16fb964..7b1d380 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/repositorybuilder/DBRepositoryProvider.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/repositorybuilder/DBRepositoryProvider.kt @@ -1,7 +1,9 @@ package com.usvision.persistence.repositorybuilder +import com.usvision.creation.SystemAggregateStorage import com.usvision.reports.SystemRepository interface DBRepositoryProvider : DBConnectionBuilder { fun getRepository(): SystemRepository + fun getAggregateStorage(): SystemAggregateStorage } diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/repositorybuilder/MongoDBRepositoryProvider.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/repositorybuilder/MongoDBRepositoryProvider.kt index 462818c..3728aee 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/repositorybuilder/MongoDBRepositoryProvider.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/repositorybuilder/MongoDBRepositoryProvider.kt @@ -2,6 +2,7 @@ package com.usvision.persistence.repositorybuilder import com.mongodb.kotlin.client.coroutine.MongoClient import com.mongodb.kotlin.client.coroutine.MongoDatabase +import com.usvision.creation.SystemAggregateStorage import com.usvision.persistence.repositories.MongoSystemRepository class MongoDBRepositoryProvider : DBRepositoryProvider, DBConnectionProvider { @@ -38,7 +39,11 @@ class MongoDBRepositoryProvider : DBRepositoryProvider, DBConnectionProvider) = io.ktor.server.netty.EngineMain.main(args) fun Application.module() { - val reportSupervisor = configureReports() + val (databaseRepository, databaseAggregateStorage) = configureDatabaseConnection() + val systemCreator = configureSystemCreator(databaseAggregateStorage) + val reportSupervisor = configureReports(databaseRepository) configureCORS() configureSerialization() - configureRouting(reportSupervisor) + configureRouting(reportSupervisor, systemCreator) configureExceptionHandling() } \ No newline at end of file diff --git a/app-web/src/main/kotlin/com/usvision/web/configuration/MessageChannelsRequestDTO.kt b/app-web/src/main/kotlin/com/usvision/web/configuration/MessageChannelsRequestDTO.kt new file mode 100644 index 0000000..a43058b --- /dev/null +++ b/app-web/src/main/kotlin/com/usvision/web/configuration/MessageChannelsRequestDTO.kt @@ -0,0 +1,8 @@ +package com.usvision.web.configuration + +import com.usvision.model.domain.MessageChannel + +data class MessageChannelsRequestDTO( + val publishMessageChannels: List, + val subscribedMessageChannels: List +) diff --git a/app-web/src/main/kotlin/com/usvision/web/configuration/appcreator.kt b/app-web/src/main/kotlin/com/usvision/web/configuration/appcreator.kt new file mode 100644 index 0000000..407e2ae --- /dev/null +++ b/app-web/src/main/kotlin/com/usvision/web/configuration/appcreator.kt @@ -0,0 +1,9 @@ +package com.usvision.web.configuration + +import com.usvision.creation.SystemAggregateStorage +import com.usvision.creation.SystemCreator +import io.ktor.server.application.* + +fun Application.configureSystemCreator( + systemAggregateStorage: SystemAggregateStorage +) = SystemCreator(systemAggregateStorage) \ No newline at end of file diff --git a/app-web/src/main/kotlin/com/usvision/web/configuration/database.kt b/app-web/src/main/kotlin/com/usvision/web/configuration/database.kt new file mode 100644 index 0000000..d242cb7 --- /dev/null +++ b/app-web/src/main/kotlin/com/usvision/web/configuration/database.kt @@ -0,0 +1,26 @@ +package com.usvision.web.configuration + +import com.usvision.creation.SystemAggregateStorage +import com.usvision.persistence.repositorybuilder.DBRepositoryProvider +import com.usvision.persistence.repositorybuilder.MongoDBRepositoryProvider +import com.usvision.reports.SystemRepository +import io.ktor.server.application.* + +fun Application.configureDatabaseConnection(): Pair { + val host = environment.config.property("persistence.host").getString() + val port = environment.config.property("persistence.port").getString() + val user = environment.config.property("persistence.username").getString() + val pass = environment.config.property("persistence.password").getString() + val dbName = environment.config.property("persistence.database_name").getString() + + val repoProvider: DBRepositoryProvider = MongoDBRepositoryProvider() + + return repoProvider.run { + connectTo(host) + setPort(port) + withCredentials(user, pass) + setDatabase(dbName) + Pair(getRepository(), getAggregateStorage()) + } + +} \ No newline at end of file diff --git a/app-web/src/main/kotlin/com/usvision/web/configuration/reports.kt b/app-web/src/main/kotlin/com/usvision/web/configuration/reports.kt index 17a9806..16bbb00 100644 --- a/app-web/src/main/kotlin/com/usvision/web/configuration/reports.kt +++ b/app-web/src/main/kotlin/com/usvision/web/configuration/reports.kt @@ -1,31 +1,14 @@ package com.usvision.web.configuration -import com.usvision.persistence.repositorybuilder.DBRepositoryProvider -import com.usvision.persistence.repositorybuilder.MongoDBRepositoryProvider import com.usvision.reports.ReportSupervisor +import com.usvision.reports.SystemRepository import io.ktor.server.application.* import io.ktor.server.config.* -fun Application.configureReports(): ReportSupervisor { - val host = environment.config.property("persistence.host").getString() - val port = environment.config.property("persistence.port").getString() - val user = environment.config.property("persistence.username").getString() - val pass = environment.config.property("persistence.password").getString() - val dbName = environment.config.property("persistence.database_name").getString() - +fun Application.configureReports(systemRepository: SystemRepository): ReportSupervisor { val presets = parsePresetsConfig(environment.config.config("reports.presets")) - val repoProvider: DBRepositoryProvider = MongoDBRepositoryProvider() - - val systemRepository = repoProvider.run { - connectTo(host) - setPort(port) - withCredentials(user, pass) - setDatabase(dbName) - getRepository() - } - return ReportSupervisor( systemRepository, presets = presets diff --git a/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt b/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt index cbcad8f..0f93d79 100644 --- a/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt +++ b/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt @@ -1,18 +1,120 @@ package com.usvision.web.configuration +import com.usvision.creation.CompanySystemDTO +import com.usvision.creation.DatabaseDTO +import com.usvision.creation.MicroserviceDTO +import com.usvision.creation.SystemCreator import com.usvision.reports.ReportSupervisor +import com.usvision.web.dto.RestEndpointsRequestDTO import com.usvision.web.exceptions.MissingRequiredPathParameterException import io.ktor.http.* import io.ktor.server.application.* +import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* -fun Application.configureRouting(reportSupervisor: ReportSupervisor) { +fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreator: SystemCreator) { val defaultPreset = environment.config.property("reports.default_preset_name").getString() routing { - route("/systems/{name}/reports") { - get { + route("/microservice") { + post { + val microservice = call.receive() + val createMicroserviceResult = systemCreator.createMicroservice(microservice) + + call.respond( + message = createMicroserviceResult, + status = HttpStatusCode.Created + ) + } + post("/{name}/database") { + val microserviceName: String = call.parameters["name"] + ?: throw MissingRequiredPathParameterException("name", "String") + + val databaseDTO = call.receive() + val addDatabaseResult = systemCreator.addNewDatabaseConnectionToMicroservice(databaseDTO, microserviceName) + + call.respond( + message = addDatabaseResult, + status = HttpStatusCode.Created + ) + } + + post("/{name}/rest-endpoints") { + val microserviceName: String = call.parameters["name"] + ?: throw MissingRequiredPathParameterException("name", "String") + val restEndpoints = call.receive() + + val addOperationsResult = systemCreator.addOperationsToMicroservice( + exposedOperations = restEndpoints.exposedOperations, + consumedOperations = restEndpoints.consumedOperations, + microserviceName = microserviceName + ) + + call.respond( + message = addOperationsResult, + status = HttpStatusCode.Created + ) + } + + post("/{name}/message-channels") { + val microserviceName: String = call.parameters["name"] + ?: throw MissingRequiredPathParameterException("name", "String") + + val messageChannels = call.receive() + + + val addMessageChannelsResult = systemCreator.addMessageChannelsToMicroservice( + publishMessageChannels = messageChannels.publishMessageChannels, + subscribedMessageChannels = messageChannels.subscribedMessageChannels, + microserviceName = microserviceName + ) + + call.respond( + message = addMessageChannelsResult, + status = HttpStatusCode.Created + ) + } + } + + route("/systems") { + post { + val companySystem = call.receive() + val createCompanySystemResult = systemCreator.createCompanySystem(companySystem) + + call.respond( + message = createCompanySystemResult, + status = HttpStatusCode.Created + ) + } + + post("/{name}/microservice") { + val systemName: String = call.parameters["name"] + ?: throw MissingRequiredPathParameterException("name", "String") + + val microservice = call.receive() + val createMicroserviceResult = systemCreator.createMicroservice(microservice, systemName) + + call.respond( + message = createMicroserviceResult, + status = HttpStatusCode.Created + ) + } + + post("/{name}/companySubsystem") { + val systemName: String = call.parameters["name"] + ?: throw MissingRequiredPathParameterException("name", "String") + + val companySystem = call.receive() + val createMicroserviceResult = systemCreator.createCompanySystem(companySystem, systemName) + + call.respond( + message = createMicroserviceResult, + status = HttpStatusCode.Created + ) + } + + get("/{name}/reports") { val systemName: String = call.parameters["name"] ?: throw MissingRequiredPathParameterException("name", "String") diff --git a/app-web/src/main/kotlin/com/usvision/web/dto/RestEndpointsRequestDTO.kt b/app-web/src/main/kotlin/com/usvision/web/dto/RestEndpointsRequestDTO.kt new file mode 100644 index 0000000..c0f413d --- /dev/null +++ b/app-web/src/main/kotlin/com/usvision/web/dto/RestEndpointsRequestDTO.kt @@ -0,0 +1,10 @@ +package com.usvision.web.dto + +import com.usvision.model.domain.operations.Operation +import kotlinx.serialization.Serializable + +@Serializable +data class RestEndpointsRequestDTO( + val exposedOperations: List, + val consumedOperations: List +) From c10a58252ff726007234d674420bd21c09d19c98 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Tue, 8 Oct 2024 21:18:21 -0300 Subject: [PATCH 12/34] move exceptions related to interfaces implementations to app-model module --- .../model/exceptions/UnknownDatabaseClassException.kt | 4 ++++ .../model/exceptions/UnknownOperationClassException.kt | 4 ++++ .../usvision/model/exceptions/UnknownSystemClassException.kt | 4 ++++ .../persistence/exceptions/UnknownOperationClassException.kt | 4 ---- .../persistence/exceptions/UnknownSystemClassException.kt | 4 ---- 5 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownDatabaseClassException.kt create mode 100644 app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownOperationClassException.kt create mode 100644 app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownSystemClassException.kt delete mode 100644 app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt delete mode 100644 app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt diff --git a/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownDatabaseClassException.kt b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownDatabaseClassException.kt new file mode 100644 index 0000000..02dee20 --- /dev/null +++ b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownDatabaseClassException.kt @@ -0,0 +1,4 @@ +package com.usvision.model.exceptions + +class UnknownDatabaseClassException(className: String) + : RuntimeException("Database has a unknown class to $className") diff --git a/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownOperationClassException.kt b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownOperationClassException.kt new file mode 100644 index 0000000..d4364f6 --- /dev/null +++ b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownOperationClassException.kt @@ -0,0 +1,4 @@ +package com.usvision.model.exceptions + +class UnknownOperationClassException(className: String) + : RuntimeException("Operation has a unknown class to $className") \ No newline at end of file diff --git a/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownSystemClassException.kt b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownSystemClassException.kt new file mode 100644 index 0000000..79e63fa --- /dev/null +++ b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownSystemClassException.kt @@ -0,0 +1,4 @@ +package com.usvision.model.exceptions + +class UnknownSystemClassException(name: String, className: String) + : RuntimeException("System $name has a unknown class to $className") diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt deleted file mode 100644 index b9cba70..0000000 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.usvision.persistence.exceptions - -class UnknownOperationClassException - : RuntimeException("Operation has a unknown class to SystemDocument") \ No newline at end of file diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt deleted file mode 100644 index f992f0c..0000000 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.usvision.persistence.exceptions - -class UnknownSystemClassException(name: String) - : RuntimeException("System $name has a unknown class to SystemDocument") From 9dc9e9b76daba432a34284d01af2825fda2e5351 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Tue, 8 Oct 2024 21:18:21 -0300 Subject: [PATCH 13/34] move exceptions related to interfaces implementations to app-model module --- .../model/exceptions/UnknownDatabaseClassException.kt | 4 ++++ .../model/exceptions/UnknownOperationClassException.kt | 4 ++++ .../model/exceptions/UnknownSystemClassException.kt | 4 ++++ .../com/usvision/persistence/documents/SystemDocument.kt | 8 ++++---- .../exceptions/UnknownOperationClassException.kt | 4 ---- .../persistence/exceptions/UnknownSystemClassException.kt | 4 ---- 6 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownDatabaseClassException.kt create mode 100644 app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownOperationClassException.kt create mode 100644 app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownSystemClassException.kt delete mode 100644 app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt delete mode 100644 app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt diff --git a/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownDatabaseClassException.kt b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownDatabaseClassException.kt new file mode 100644 index 0000000..02dee20 --- /dev/null +++ b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownDatabaseClassException.kt @@ -0,0 +1,4 @@ +package com.usvision.model.exceptions + +class UnknownDatabaseClassException(className: String) + : RuntimeException("Database has a unknown class to $className") diff --git a/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownOperationClassException.kt b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownOperationClassException.kt new file mode 100644 index 0000000..d4364f6 --- /dev/null +++ b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownOperationClassException.kt @@ -0,0 +1,4 @@ +package com.usvision.model.exceptions + +class UnknownOperationClassException(className: String) + : RuntimeException("Operation has a unknown class to $className") \ No newline at end of file diff --git a/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownSystemClassException.kt b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownSystemClassException.kt new file mode 100644 index 0000000..79e63fa --- /dev/null +++ b/app-model/src/main/kotlin/com/usvision/model/exceptions/UnknownSystemClassException.kt @@ -0,0 +1,4 @@ +package com.usvision.model.exceptions + +class UnknownSystemClassException(name: String, className: String) + : RuntimeException("System $name has a unknown class to $className") diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt index 96367fb..723c754 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt @@ -8,8 +8,8 @@ import com.usvision.model.domain.databases.Database import com.usvision.model.domain.operations.Operation import com.usvision.model.domain.operations.RestEndpoint import com.usvision.model.systemcomposite.System -import com.usvision.persistence.exceptions.UnknownOperationClassException -import com.usvision.persistence.exceptions.UnknownSystemClassException +import com.usvision.model.exceptions.UnknownOperationClassException +import com.usvision.model.exceptions.UnknownSystemClassException import org.bson.Document import org.bson.codecs.pojo.annotations.BsonId import org.bson.types.ObjectId @@ -72,7 +72,7 @@ private fun System.toSystemDocument( this.toSystemDocument(id) } else -> { - throw UnknownSystemClassException(this.name) + throw UnknownSystemClassException(this.name, "SystemDocument") } } @@ -98,7 +98,7 @@ private fun Module.toModuleDocument() = ModuleDocument(id = ObjectId(this.id), u private fun Operation.toDocument() = when (this) { is RestEndpoint -> this.toDocument() - else -> throw UnknownOperationClassException() + else -> throw UnknownOperationClassException("SystemDocument") } private fun Database.toDatabaseDocument() = DatabaseDocument(id = ObjectId(this.id), description = this.description) diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt deleted file mode 100644 index b9cba70..0000000 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownOperationClassException.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.usvision.persistence.exceptions - -class UnknownOperationClassException - : RuntimeException("Operation has a unknown class to SystemDocument") \ No newline at end of file diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt deleted file mode 100644 index f992f0c..0000000 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/exceptions/UnknownSystemClassException.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.usvision.persistence.exceptions - -class UnknownSystemClassException(name: String) - : RuntimeException("System $name has a unknown class to SystemDocument") From affc839144250b10da47ab74fe9ffcd8d43f217b Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Tue, 8 Oct 2024 21:20:43 -0300 Subject: [PATCH 14/34] change RestEndpointsRequestDTO contract, using data classes instead of Operation interfaces --- .../kotlin/com/usvision/web/dto/RestEndpointsRequestDTO.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app-web/src/main/kotlin/com/usvision/web/dto/RestEndpointsRequestDTO.kt b/app-web/src/main/kotlin/com/usvision/web/dto/RestEndpointsRequestDTO.kt index c0f413d..138caf3 100644 --- a/app-web/src/main/kotlin/com/usvision/web/dto/RestEndpointsRequestDTO.kt +++ b/app-web/src/main/kotlin/com/usvision/web/dto/RestEndpointsRequestDTO.kt @@ -1,10 +1,10 @@ package com.usvision.web.dto -import com.usvision.model.domain.operations.Operation +import com.usvision.model.domain.operations.RestEndpoint import kotlinx.serialization.Serializable @Serializable data class RestEndpointsRequestDTO( - val exposedOperations: List, - val consumedOperations: List + val exposedOperations: List, + val consumedOperations: List ) From 7025f76430707bf28c191c47833f991bdadeaeb3 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Tue, 8 Oct 2024 22:44:24 -0300 Subject: [PATCH 15/34] create requestDTO and responseDTO to fix web module parse error --- .../com/usvision/web/configuration/routing.kt | 32 ++++---- .../MessageChannelsRequestDTO.kt | 2 +- .../com/usvision/web/dto/SystemRequestDTO.kt | 52 +++++++++++++ .../com/usvision/web/dto/SystemResponseDTO.kt | 74 +++++++++++++++++++ 4 files changed, 142 insertions(+), 18 deletions(-) rename app-web/src/main/kotlin/com/usvision/web/{configuration => dto}/MessageChannelsRequestDTO.kt (83%) create mode 100644 app-web/src/main/kotlin/com/usvision/web/dto/SystemRequestDTO.kt create mode 100644 app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt diff --git a/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt b/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt index 0f93d79..b74ad57 100644 --- a/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt +++ b/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt @@ -1,11 +1,9 @@ package com.usvision.web.configuration -import com.usvision.creation.CompanySystemDTO -import com.usvision.creation.DatabaseDTO -import com.usvision.creation.MicroserviceDTO import com.usvision.creation.SystemCreator +import com.usvision.model.domain.databases.PostgreSQL import com.usvision.reports.ReportSupervisor -import com.usvision.web.dto.RestEndpointsRequestDTO +import com.usvision.web.dto.* import com.usvision.web.exceptions.MissingRequiredPathParameterException import io.ktor.http.* import io.ktor.server.application.* @@ -19,11 +17,11 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat routing { route("/microservice") { post { - val microservice = call.receive() + val microservice = call.receive().toMicroservice() val createMicroserviceResult = systemCreator.createMicroservice(microservice) call.respond( - message = createMicroserviceResult, + message = createMicroserviceResult.toMicroserviceResponseDTO(), status = HttpStatusCode.Created ) } @@ -31,11 +29,11 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat val microserviceName: String = call.parameters["name"] ?: throw MissingRequiredPathParameterException("name", "String") - val databaseDTO = call.receive() + val databaseDTO = call.receive() val addDatabaseResult = systemCreator.addNewDatabaseConnectionToMicroservice(databaseDTO, microserviceName) call.respond( - message = addDatabaseResult, + message = addDatabaseResult.toMicroserviceResponseDTO(), status = HttpStatusCode.Created ) } @@ -52,7 +50,7 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat ) call.respond( - message = addOperationsResult, + message = addOperationsResult.toMicroserviceResponseDTO(), status = HttpStatusCode.Created ) } @@ -71,7 +69,7 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat ) call.respond( - message = addMessageChannelsResult, + message = addMessageChannelsResult.toMicroserviceResponseDTO(), status = HttpStatusCode.Created ) } @@ -79,11 +77,11 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat route("/systems") { post { - val companySystem = call.receive() + val companySystem = call.receive().toCompanySystem() val createCompanySystemResult = systemCreator.createCompanySystem(companySystem) call.respond( - message = createCompanySystemResult, + message = createCompanySystemResult.toCompanySystemResponseDTO(), status = HttpStatusCode.Created ) } @@ -92,11 +90,11 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat val systemName: String = call.parameters["name"] ?: throw MissingRequiredPathParameterException("name", "String") - val microservice = call.receive() + val microservice = call.receive().toMicroservice() val createMicroserviceResult = systemCreator.createMicroservice(microservice, systemName) call.respond( - message = createMicroserviceResult, + message = createMicroserviceResult.toMicroserviceResponseDTO(), status = HttpStatusCode.Created ) } @@ -105,11 +103,11 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat val systemName: String = call.parameters["name"] ?: throw MissingRequiredPathParameterException("name", "String") - val companySystem = call.receive() - val createMicroserviceResult = systemCreator.createCompanySystem(companySystem, systemName) + val companySystem = call.receive().toCompanySystem() + val createCompanySystemResult = systemCreator.createCompanySystem(companySystem, systemName) call.respond( - message = createMicroserviceResult, + message = createCompanySystemResult.toCompanySystemResponseDTO(), status = HttpStatusCode.Created ) } diff --git a/app-web/src/main/kotlin/com/usvision/web/configuration/MessageChannelsRequestDTO.kt b/app-web/src/main/kotlin/com/usvision/web/dto/MessageChannelsRequestDTO.kt similarity index 83% rename from app-web/src/main/kotlin/com/usvision/web/configuration/MessageChannelsRequestDTO.kt rename to app-web/src/main/kotlin/com/usvision/web/dto/MessageChannelsRequestDTO.kt index a43058b..72ea750 100644 --- a/app-web/src/main/kotlin/com/usvision/web/configuration/MessageChannelsRequestDTO.kt +++ b/app-web/src/main/kotlin/com/usvision/web/dto/MessageChannelsRequestDTO.kt @@ -1,4 +1,4 @@ -package com.usvision.web.configuration +package com.usvision.web.dto import com.usvision.model.domain.MessageChannel diff --git a/app-web/src/main/kotlin/com/usvision/web/dto/SystemRequestDTO.kt b/app-web/src/main/kotlin/com/usvision/web/dto/SystemRequestDTO.kt new file mode 100644 index 0000000..de78f92 --- /dev/null +++ b/app-web/src/main/kotlin/com/usvision/web/dto/SystemRequestDTO.kt @@ -0,0 +1,52 @@ +package com.usvision.web.dto + +import com.usvision.model.domain.CompanySystem +import com.usvision.model.domain.MessageChannel +import com.usvision.model.domain.Microservice +import com.usvision.model.domain.Module +import com.usvision.model.domain.databases.PostgreSQL +import com.usvision.model.domain.operations.RestEndpoint +import com.usvision.model.systemcomposite.System +import kotlinx.serialization.Serializable + +@Serializable +data class SystemRequestDTO( + val name: String, + val subsystems: Set? = null, + val module: Module? = null, + val exposedOperations: MutableSet? = null, + val consumedOperations: MutableSet? = null, + val databases: MutableSet? = null, + val publishChannels: MutableSet? = null, + val subscribedChannels: MutableSet? = null, +) { + fun toMicroservice(): Microservice { + val microservice = module?.let { Microservice(name, module) } ?: Microservice(name) + + databases?.forEach { database -> microservice.addDatabaseConnection(database) } + + exposedOperations?.forEach { operation -> microservice.exposeOperation(operation) } + consumedOperations?.forEach { operation -> microservice.consumeOperation(operation) } + + publishChannels?.forEach { messageChannel -> microservice.addPublishChannel(messageChannel) } + subscribedChannels?.forEach { messageChannel -> microservice.addSubscribedChannel(messageChannel) } + + return microservice + } + + fun toCompanySystem(): CompanySystem { + val companySystem = CompanySystem(name) + + subsystems?.forEach { subsystemRequestDTO -> + companySystem.addSubsystem(subsystemRequestDTO.toSystem()) + } + + return companySystem + } + + private fun toSystem(): System { + subsystems ?: return this.toCompanySystem() + + return this.toMicroservice() + } +} diff --git a/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt b/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt new file mode 100644 index 0000000..d2565eb --- /dev/null +++ b/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt @@ -0,0 +1,74 @@ +package com.usvision.web.dto + +import com.usvision.model.domain.CompanySystem +import com.usvision.model.domain.MessageChannel +import com.usvision.model.domain.Microservice +import com.usvision.model.domain.Module +import com.usvision.model.domain.databases.Database +import com.usvision.model.domain.databases.PostgreSQL +import com.usvision.model.domain.operations.Operation +import com.usvision.model.domain.operations.RestEndpoint +import com.usvision.model.exceptions.UnknownOperationClassException +import com.usvision.model.exceptions.UnknownSystemClassException +import com.usvision.model.exceptions.UnknownDatabaseClassException +import com.usvision.model.systemcomposite.System +import kotlinx.serialization.Serializable + + +interface SystemResponseDTO + +@Serializable +data class CompanySystemResponseDTO( + val name: String, + val subsystems: Set? = setOf(), +): SystemResponseDTO + + +@Serializable +data class MicroserviceResponseDTO( + val name: String, + val module: Module, + val exposedOperations: Set, + val consumedOperations: Set, + val databases: Set, + val publishChannels: Set, + val subscribedChannels: Set +): SystemResponseDTO + +fun CompanySystem.toCompanySystemResponseDTO() = CompanySystemResponseDTO( + this.name, + this.getSubsystemSet().toSystemResponseDTOSet() +) + +fun Microservice.toMicroserviceResponseDTO() = MicroserviceResponseDTO( + name = this.name, + module = this.module, + exposedOperations = this.getExposedOperations().toRestEndpointSet(), + consumedOperations = this.getConsumedOperations().toRestEndpointSet(), + databases = this.getDatabases().toPostgreSQLSet(), + publishChannels = this.getPublishChannels(), + subscribedChannels = this.getSubscribedChannels() +) + +private fun Set.toPostgreSQLSet(): Set = this.map { database -> + when (database) { + is PostgreSQL -> database + else -> throw UnknownDatabaseClassException("SystemResponseDTO") + } +}.toSet() + +private fun Set.toRestEndpointSet(): Set = this.map { operation -> + when (operation) { + is RestEndpoint -> operation + else -> throw UnknownOperationClassException("SystemResponseDTO") + } +}.toSet() + +private fun Set.toSystemResponseDTOSet(): Set = this.map { system -> + when (system) { + is CompanySystem -> system.toCompanySystemResponseDTO() + is Microservice -> system.toMicroserviceResponseDTO() + else -> throw UnknownSystemClassException(system.name, "SystemResponseDTO") + } +}.toSet() + From 029d37f3770aa8a62535cf664c8ea227f94085fe Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 9 Oct 2024 21:42:41 -0300 Subject: [PATCH 16/34] fix /microservice and /{name}/microservice response mapping --- .../com/usvision/web/configuration/routing.kt | 4 ++-- .../com/usvision/web/dto/SystemResponseDTO.kt | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt b/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt index b74ad57..490e6b7 100644 --- a/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt +++ b/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt @@ -21,7 +21,7 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat val createMicroserviceResult = systemCreator.createMicroservice(microservice) call.respond( - message = createMicroserviceResult.toMicroserviceResponseDTO(), + message = createMicroserviceResult.toSystemResponseDTO(), status = HttpStatusCode.Created ) } @@ -94,7 +94,7 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat val createMicroserviceResult = systemCreator.createMicroservice(microservice, systemName) call.respond( - message = createMicroserviceResult.toMicroserviceResponseDTO(), + message = createMicroserviceResult.toSystemResponseDTO(), status = HttpStatusCode.Created ) } diff --git a/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt b/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt index d2565eb..5f75724 100644 --- a/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt +++ b/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt @@ -50,6 +50,12 @@ fun Microservice.toMicroserviceResponseDTO() = MicroserviceResponseDTO( subscribedChannels = this.getSubscribedChannels() ) +fun System.toSystemResponseDTO(): SystemResponseDTO = when (this) { + is Microservice -> this.toMicroserviceResponseDTO() + is CompanySystem -> this.toCompanySystemResponseDTO() + else -> throw UnknownSystemClassException(this.name, "SystemResponseDTO") +} + private fun Set.toPostgreSQLSet(): Set = this.map { database -> when (database) { is PostgreSQL -> database @@ -64,11 +70,5 @@ private fun Set.toRestEndpointSet(): Set = this.map { o } }.toSet() -private fun Set.toSystemResponseDTOSet(): Set = this.map { system -> - when (system) { - is CompanySystem -> system.toCompanySystemResponseDTO() - is Microservice -> system.toMicroserviceResponseDTO() - else -> throw UnknownSystemClassException(system.name, "SystemResponseDTO") - } -}.toSet() +private fun Set.toSystemResponseDTOSet(): Set = this.map { it.toSystemResponseDTO() }.toSet() From 05e6e59df3f61d3bebfd58c028bf11a3e8e63fab Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 9 Oct 2024 22:27:45 -0300 Subject: [PATCH 17/34] fix serialization in app-web module --- app-web/build.gradle.kts | 1 + .../kotlin/com/usvision/web/dto/MessageChannelsRequestDTO.kt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app-web/build.gradle.kts b/app-web/build.gradle.kts index 6fc845f..a796afe 100644 --- a/app-web/build.gradle.kts +++ b/app-web/build.gradle.kts @@ -3,6 +3,7 @@ plugins { kotlin("jvm") id("io.ktor.plugin") version "2.3.5" id("com.github.johnrengelman.shadow") version "7.0.0" + kotlin("plugin.serialization") } group = "com.usvision.web" diff --git a/app-web/src/main/kotlin/com/usvision/web/dto/MessageChannelsRequestDTO.kt b/app-web/src/main/kotlin/com/usvision/web/dto/MessageChannelsRequestDTO.kt index 72ea750..498669a 100644 --- a/app-web/src/main/kotlin/com/usvision/web/dto/MessageChannelsRequestDTO.kt +++ b/app-web/src/main/kotlin/com/usvision/web/dto/MessageChannelsRequestDTO.kt @@ -1,7 +1,9 @@ package com.usvision.web.dto import com.usvision.model.domain.MessageChannel +import kotlinx.serialization.Serializable +@Serializable data class MessageChannelsRequestDTO( val publishMessageChannels: List, val subscribedMessageChannels: List From 956dd92caed6c3db1943f32e20284d0cea11ab3a Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 9 Oct 2024 22:48:44 -0300 Subject: [PATCH 18/34] fix ObjectId instantiation while converting Module to Mongo Document --- .../kotlin/com/usvision/persistence/documents/SystemDocument.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt index 723c754..44c8167 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt @@ -94,7 +94,7 @@ private fun Set.toMessageChannelDocumentSet(): Set this.toDocument() From 2de1fbb9b525da463e07d2cf32dfa25f177c8541 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 9 Oct 2024 22:53:09 -0300 Subject: [PATCH 19/34] add Serializable annotation and sealed to SystemResponseDTO interface --- .../src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt b/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt index 5f75724..24a9b0a 100644 --- a/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt +++ b/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt @@ -15,7 +15,8 @@ import com.usvision.model.systemcomposite.System import kotlinx.serialization.Serializable -interface SystemResponseDTO +@Serializable +sealed interface SystemResponseDTO @Serializable data class CompanySystemResponseDTO( From e8b6a9795456b05dcb32a20faba1a2284c4e63d0 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 9 Oct 2024 23:19:43 -0300 Subject: [PATCH 20/34] add SerialName to CompanySystemResponseDTO and MicroserviceResponseDTO --- .../src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt b/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt index 24a9b0a..ad2e902 100644 --- a/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt +++ b/app-web/src/main/kotlin/com/usvision/web/dto/SystemResponseDTO.kt @@ -12,19 +12,21 @@ import com.usvision.model.exceptions.UnknownOperationClassException import com.usvision.model.exceptions.UnknownSystemClassException import com.usvision.model.exceptions.UnknownDatabaseClassException import com.usvision.model.systemcomposite.System +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable sealed interface SystemResponseDTO +@SerialName("CompanySystem") @Serializable data class CompanySystemResponseDTO( val name: String, val subsystems: Set? = setOf(), ): SystemResponseDTO - +@SerialName("Microservice") @Serializable data class MicroserviceResponseDTO( val name: String, From c885ecb7c2d9c83e974f9d3b78b01fbc043cd0d1 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sat, 12 Oct 2024 22:51:47 -0300 Subject: [PATCH 21/34] add unit tests to CompanySystem and Microservice creation --- .../usvision/creation/SystemCreatorTest.kt | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt diff --git a/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt b/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt new file mode 100644 index 0000000..c5448dc --- /dev/null +++ b/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt @@ -0,0 +1,213 @@ +package com.usvision.creation + +import com.usvision.model.systemcomposite.System +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.jupiter.api.assertDoesNotThrow +import org.junit.jupiter.api.assertThrows +import kotlin.test.Test +import kotlin.test.assertContains +import kotlin.test.assertEquals +import kotlin.test.assertIs + +internal class SystemCreatorTest { + private val systemAggregateStorage = mockk() + private val systemCreator = SystemCreator(systemAggregateStorage) + + @Test + fun `it saves a CompanySystem and returns itself when a fatherName is not passed as argument`() { + val systemName = "name" + val companySystem = CompanySystemDTO(systemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.save(companySystem) } returns companySystem + + val resultCompanySystem = assertDoesNotThrow { + systemCreator.createCompanySystem(companySystem) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.save(companySystem) + } + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + + assertEquals(companySystem, resultCompanySystem) + } + + @Test + fun `it adds a CompanySystem to the father system and returns it when a CompanySystem and a fatherName are passed as arguments`() { + val systemName = "name" + val fatherSystemName = "fatherName" + val companySystem = CompanySystemDTO(systemName) + + val fatherCompanySystem = CompanySystemDTO(fatherSystemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.getCompanySystem(fatherSystemName) } returns fatherCompanySystem + every { systemAggregateStorage.save(fatherCompanySystem) } returns fatherCompanySystem + + val resultCompanySystem = assertDoesNotThrow { + systemCreator.createCompanySystem(companySystem, fatherSystemName) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.getCompanySystem(fatherSystemName) + systemAggregateStorage.save(fatherCompanySystem) + } + verify(exactly = 0) { + systemAggregateStorage.save(any()) + } + + assertEquals(fatherCompanySystem, resultCompanySystem) + assertContains(resultCompanySystem.getSubsystemSet(), companySystem) + } + + @Test + fun `it throws Exception when CompanySystem and a fatherName are passed as arguments and father System does not exist`() { + val systemName = "name" + val fatherSystemName = "fatherName" + val companySystem = CompanySystemDTO(systemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.getCompanySystem(fatherSystemName) } returns null + + assertThrows { + systemCreator.createCompanySystem(companySystem, fatherSystemName) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.getCompanySystem(fatherSystemName) + } + verify(exactly = 0) { + systemAggregateStorage.save(any()) + systemAggregateStorage.save(any()) + } + } + + @Test + fun `it throws exception when a system with the same name already exists when attempting to create a CompanySystem`() { + val systemName = "name" + + every { systemAggregateStorage.getSystem(systemName) } returns mockk() + + assertThrows { + systemCreator.createCompanySystem(CompanySystemDTO(systemName)) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + } + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + systemAggregateStorage.save(any()) + } + } + + + + @Test + fun `it saves a Microservice and returns itself when a fatherName is not passed as argument`() { + val systemName = "name" + val microservice = MicroserviceDTO(systemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.save(microservice) } returns microservice + + val resultCompanySystem = assertDoesNotThrow { + systemCreator.createMicroservice(microservice) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.save(microservice) + } + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + + assertEquals(microservice, resultCompanySystem) + } + + @Test + fun `it adds a Microservice to the father system and returns it when a Microservice and a fatherName are passed as arguments`() { + val systemName = "name" + val fatherSystemName = "fatherName" + val microservice = MicroserviceDTO(systemName) + + val fatherCompanySystem = CompanySystemDTO(fatherSystemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.getCompanySystem(fatherSystemName) } returns fatherCompanySystem + every { systemAggregateStorage.save(fatherCompanySystem) } returns fatherCompanySystem + + val resultCompanySystem = assertDoesNotThrow { + systemCreator.createMicroservice(microservice, fatherSystemName) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.getCompanySystem(fatherSystemName) + systemAggregateStorage.save(fatherCompanySystem) + } + verify(exactly = 0) { + systemAggregateStorage.save(any()) + } + + assertEquals(fatherCompanySystem, resultCompanySystem) + assertIs(resultCompanySystem) + assertContains(resultCompanySystem.getSubsystemSet(), microservice) + } + + @Test + fun `it throws Exception when Microservice and a fatherName are passed as arguments and father System does not exist`() { + val systemName = "name" + val fatherSystemName = "fatherName" + val microservice = MicroserviceDTO(systemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.getCompanySystem(fatherSystemName) } returns null + + assertThrows { + systemCreator.createMicroservice(microservice, fatherSystemName) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.getCompanySystem(fatherSystemName) + } + verify(exactly = 0) { + systemAggregateStorage.save(any()) + systemAggregateStorage.save(any()) + } + } + + @Test + fun `it throws exception when a system with the same name already exists when attempting to create a Microservice`() { + val systemName = "name" + + every { systemAggregateStorage.getSystem(systemName) } returns mockk() + + assertThrows { + systemCreator.createMicroservice(MicroserviceDTO(systemName)) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + } + + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + systemAggregateStorage.save(any()) + } + } +} \ No newline at end of file From aeaf9cc7c8727d84488c0688f78f75a4253c85b2 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sat, 12 Oct 2024 22:51:47 -0300 Subject: [PATCH 22/34] add unit tests to CompanySystem and Microservice in SystemCreator --- .../usvision/creation/SystemCreatorTest.kt | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt diff --git a/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt b/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt new file mode 100644 index 0000000..c5448dc --- /dev/null +++ b/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt @@ -0,0 +1,213 @@ +package com.usvision.creation + +import com.usvision.model.systemcomposite.System +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.junit.jupiter.api.assertDoesNotThrow +import org.junit.jupiter.api.assertThrows +import kotlin.test.Test +import kotlin.test.assertContains +import kotlin.test.assertEquals +import kotlin.test.assertIs + +internal class SystemCreatorTest { + private val systemAggregateStorage = mockk() + private val systemCreator = SystemCreator(systemAggregateStorage) + + @Test + fun `it saves a CompanySystem and returns itself when a fatherName is not passed as argument`() { + val systemName = "name" + val companySystem = CompanySystemDTO(systemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.save(companySystem) } returns companySystem + + val resultCompanySystem = assertDoesNotThrow { + systemCreator.createCompanySystem(companySystem) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.save(companySystem) + } + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + + assertEquals(companySystem, resultCompanySystem) + } + + @Test + fun `it adds a CompanySystem to the father system and returns it when a CompanySystem and a fatherName are passed as arguments`() { + val systemName = "name" + val fatherSystemName = "fatherName" + val companySystem = CompanySystemDTO(systemName) + + val fatherCompanySystem = CompanySystemDTO(fatherSystemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.getCompanySystem(fatherSystemName) } returns fatherCompanySystem + every { systemAggregateStorage.save(fatherCompanySystem) } returns fatherCompanySystem + + val resultCompanySystem = assertDoesNotThrow { + systemCreator.createCompanySystem(companySystem, fatherSystemName) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.getCompanySystem(fatherSystemName) + systemAggregateStorage.save(fatherCompanySystem) + } + verify(exactly = 0) { + systemAggregateStorage.save(any()) + } + + assertEquals(fatherCompanySystem, resultCompanySystem) + assertContains(resultCompanySystem.getSubsystemSet(), companySystem) + } + + @Test + fun `it throws Exception when CompanySystem and a fatherName are passed as arguments and father System does not exist`() { + val systemName = "name" + val fatherSystemName = "fatherName" + val companySystem = CompanySystemDTO(systemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.getCompanySystem(fatherSystemName) } returns null + + assertThrows { + systemCreator.createCompanySystem(companySystem, fatherSystemName) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.getCompanySystem(fatherSystemName) + } + verify(exactly = 0) { + systemAggregateStorage.save(any()) + systemAggregateStorage.save(any()) + } + } + + @Test + fun `it throws exception when a system with the same name already exists when attempting to create a CompanySystem`() { + val systemName = "name" + + every { systemAggregateStorage.getSystem(systemName) } returns mockk() + + assertThrows { + systemCreator.createCompanySystem(CompanySystemDTO(systemName)) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + } + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + systemAggregateStorage.save(any()) + } + } + + + + @Test + fun `it saves a Microservice and returns itself when a fatherName is not passed as argument`() { + val systemName = "name" + val microservice = MicroserviceDTO(systemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.save(microservice) } returns microservice + + val resultCompanySystem = assertDoesNotThrow { + systemCreator.createMicroservice(microservice) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.save(microservice) + } + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + + assertEquals(microservice, resultCompanySystem) + } + + @Test + fun `it adds a Microservice to the father system and returns it when a Microservice and a fatherName are passed as arguments`() { + val systemName = "name" + val fatherSystemName = "fatherName" + val microservice = MicroserviceDTO(systemName) + + val fatherCompanySystem = CompanySystemDTO(fatherSystemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.getCompanySystem(fatherSystemName) } returns fatherCompanySystem + every { systemAggregateStorage.save(fatherCompanySystem) } returns fatherCompanySystem + + val resultCompanySystem = assertDoesNotThrow { + systemCreator.createMicroservice(microservice, fatherSystemName) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.getCompanySystem(fatherSystemName) + systemAggregateStorage.save(fatherCompanySystem) + } + verify(exactly = 0) { + systemAggregateStorage.save(any()) + } + + assertEquals(fatherCompanySystem, resultCompanySystem) + assertIs(resultCompanySystem) + assertContains(resultCompanySystem.getSubsystemSet(), microservice) + } + + @Test + fun `it throws Exception when Microservice and a fatherName are passed as arguments and father System does not exist`() { + val systemName = "name" + val fatherSystemName = "fatherName" + val microservice = MicroserviceDTO(systemName) + + every { systemAggregateStorage.getSystem(systemName) } returns null + every { systemAggregateStorage.getCompanySystem(fatherSystemName) } returns null + + assertThrows { + systemCreator.createMicroservice(microservice, fatherSystemName) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + systemAggregateStorage.getCompanySystem(fatherSystemName) + } + verify(exactly = 0) { + systemAggregateStorage.save(any()) + systemAggregateStorage.save(any()) + } + } + + @Test + fun `it throws exception when a system with the same name already exists when attempting to create a Microservice`() { + val systemName = "name" + + every { systemAggregateStorage.getSystem(systemName) } returns mockk() + + assertThrows { + systemCreator.createMicroservice(MicroserviceDTO(systemName)) + } + + verify(exactly = 1) { + systemAggregateStorage.getSystem(systemName) + } + + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + systemAggregateStorage.save(any()) + } + } +} \ No newline at end of file From 5a66b6540349f09d80cbe56480eea49b45264f2d Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 13 Oct 2024 00:11:59 -0300 Subject: [PATCH 23/34] create getExistingMicroservice method in SystemAggregateStorage and use it in SystemCreator --- .../kotlin/com/usvision/creation/SystemAggregateStorage.kt | 1 + .../src/main/kotlin/com/usvision/creation/SystemCreator.kt | 5 ++--- .../persistence/repositories/MongoSystemRepository.kt | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemAggregateStorage.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemAggregateStorage.kt index 851ad5d..8dfa35c 100644 --- a/app-creation/src/main/kotlin/com/usvision/creation/SystemAggregateStorage.kt +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemAggregateStorage.kt @@ -9,4 +9,5 @@ interface SystemAggregateStorage { fun save(microservice: Microservice): Microservice fun save(companySystem: CompanySystem): CompanySystem fun getCompanySystem(name: String): CompanySystem? + fun getMicroservice(name: String): Microservice? } \ No newline at end of file diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt index 3fd3545..f5e5490 100644 --- a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt @@ -88,9 +88,8 @@ class SystemCreator( private fun getExistingMicroservice( microserviceName: String - ) = systemAggregateStorage.getSystem( - microserviceName - ) as MicroserviceDTO? ?: throw Exception("A Microservice with name $microserviceName does not exist") + ) = systemAggregateStorage.getMicroservice(microserviceName) + ?: throw Exception("A Microservice with name $microserviceName does not exist") private fun checkIfSystemAlreadyExists(name: String) { systemAggregateStorage.getSystem(name)?.also { diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt index fea022d..08196b4 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt @@ -58,6 +58,8 @@ class MongoSystemRepository(db: MongoDatabase) : SystemRepository, SystemAggrega override fun getCompanySystem(name: String): CompanySystem? = getSystem(name = name) as CompanySystem? + override fun getMicroservice(name: String): Microservice? = getSystem(name = name) as Microservice? + fun getSystemById(id: ObjectId): System? = runBlocking { systemCollection .find(Filters.eq("_id", id)) From 7f74a1e71a29d3f5002a21285cbc2411da478342 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 13 Oct 2024 14:47:36 -0300 Subject: [PATCH 24/34] add unit tests to adding Databases, operations and message channels in SystemCreator --- .../usvision/creation/SystemCreatorTest.kt | 236 +++++++++++++++++- 1 file changed, 232 insertions(+), 4 deletions(-) diff --git a/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt b/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt index c5448dc..01cd21d 100644 --- a/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt +++ b/app-creation/src/test/kotlin/com/usvision/creation/SystemCreatorTest.kt @@ -1,15 +1,15 @@ package com.usvision.creation +import com.usvision.model.domain.MessageChannel +import com.usvision.model.domain.databases.PostgreSQL +import com.usvision.model.domain.operations.RestEndpoint import com.usvision.model.systemcomposite.System import io.mockk.every import io.mockk.mockk import io.mockk.verify import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows -import kotlin.test.Test -import kotlin.test.assertContains -import kotlin.test.assertEquals -import kotlin.test.assertIs +import kotlin.test.* internal class SystemCreatorTest { private val systemAggregateStorage = mockk() @@ -210,4 +210,232 @@ internal class SystemCreatorTest { systemAggregateStorage.save(any()) } } + + @Test + fun `it adds rest endpoints to Microservice and saves it`() { + val microserviceName = "name" + val microservice = MicroserviceDTO(microserviceName) + + val consumedRestEndpoints = listOf( + RestEndpoint(httpVerb = "GET", path = "/test") + ) + + val exposedRestEndpoints = listOf( + RestEndpoint(httpVerb = "POST", path = "/test") + ) + + every { systemAggregateStorage.getMicroservice(microserviceName) } returns microservice + every { systemAggregateStorage.save(microservice) } returns microservice + + val addRestEndpointsResult = assertDoesNotThrow { + systemCreator.addOperationsToMicroservice( + exposedOperations = exposedRestEndpoints, + consumedOperations = consumedRestEndpoints, + microserviceName = microserviceName + ) + } + + verify(exactly = 1) { + systemAggregateStorage.getMicroservice(microserviceName) + systemAggregateStorage.save(microservice) + } + + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + + assertContains(addRestEndpointsResult.getExposedOperations(), exposedRestEndpoints.first()) + assertContains(addRestEndpointsResult.getConsumedOperations(), consumedRestEndpoints.first()) + + assertTrue { + addRestEndpointsResult.getExposedOperations().all { + operation -> operation != consumedRestEndpoints.first() + } + } + + assertTrue { + addRestEndpointsResult.getConsumedOperations().all { + operation -> operation != exposedRestEndpoints.first() + } + } + } + + @Test + fun `it throws exception when attempting to add rest endpoints to non-existent Microservice`() { + val microserviceName = "name" + val microservice = MicroserviceDTO(microserviceName) + + val consumedRestEndpoints = listOf( + RestEndpoint(httpVerb = "GET", path = "/test") + ) + + val exposedRestEndpoints = listOf( + RestEndpoint(httpVerb = "POST", path = "/test") + ) + + every { systemAggregateStorage.getMicroservice(microserviceName) } returns null + + assertThrows { + systemCreator.addOperationsToMicroservice( + exposedOperations = exposedRestEndpoints, + consumedOperations = consumedRestEndpoints, + microserviceName = microserviceName + ) + } + + verify(exactly = 1) { + systemAggregateStorage.getMicroservice(microserviceName) + } + + verify(exactly = 0) { + systemAggregateStorage.save(microservice) + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + } + + @Test + fun `it adds message channels to Microservice and saves it`() { + val microserviceName = "name" + val microservice = MicroserviceDTO(microserviceName) + + val publishMessageChannels = listOf( + MessageChannel(name="publish.test") + ) + + val subscribedMessageChannels = listOf( + MessageChannel(name="subscribe.test") + ) + + every { systemAggregateStorage.getMicroservice(microserviceName) } returns microservice + every { systemAggregateStorage.save(microservice) } returns microservice + + val addRestEndpointsResult = assertDoesNotThrow { + systemCreator.addMessageChannelsToMicroservice( + publishMessageChannels = publishMessageChannels, + subscribedMessageChannels = subscribedMessageChannels, + microserviceName = microserviceName + ) + } + + verify(exactly = 1) { + systemAggregateStorage.getMicroservice(microserviceName) + systemAggregateStorage.save(microservice) + } + + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + + assertContains(addRestEndpointsResult.getPublishChannels(), publishMessageChannels.first()) + assertContains(addRestEndpointsResult.getSubscribedChannels(), subscribedMessageChannels.first()) + + assertTrue { + addRestEndpointsResult.getPublishChannels().all { + operation -> operation != subscribedMessageChannels.first() + } + } + + assertTrue { + addRestEndpointsResult.getSubscribedChannels().all { + operation -> operation != publishMessageChannels.first() + } + } + } + + @Test + fun `it throws exception when attempting to add message channels to non-existent Microservice`() { + val microserviceName = "name" + val microservice = MicroserviceDTO(microserviceName) + + val publishMessageChannels = listOf( + MessageChannel(name="publish.test") + ) + + val subscribedMessageChannels = listOf( + MessageChannel(name="subscribe.test") + ) + + + every { systemAggregateStorage.getMicroservice(microserviceName) } returns null + + + assertThrows { + systemCreator.addMessageChannelsToMicroservice( + publishMessageChannels = publishMessageChannels, + subscribedMessageChannels = subscribedMessageChannels, + microserviceName = microserviceName + ) + } + + verify(exactly = 1) { + systemAggregateStorage.getMicroservice(microserviceName) + } + + verify(exactly = 0) { + systemAggregateStorage.save(microservice) + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + } + + @Test + fun `it adds a database to Microservice and saves it`() { + val microserviceName = "name" + val microservice = MicroserviceDTO(microserviceName) + + val database = PostgreSQL() + + every { systemAggregateStorage.getMicroservice(microserviceName) } returns microservice + every { systemAggregateStorage.save(microservice) } returns microservice + + + val addRestEndpointsResult = assertDoesNotThrow { + systemCreator.addNewDatabaseConnectionToMicroservice( + database = database, + microserviceName = microserviceName + ) + } + + verify(exactly = 1) { + systemAggregateStorage.getMicroservice(microserviceName) + systemAggregateStorage.save(microservice) + } + + verify(exactly = 0) { + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + + assertContains(addRestEndpointsResult.getDatabases(), database) + } + + @Test + fun `it throws exception when attempting to add a database to non-existent Microservice`() { + val microserviceName = "name" + val microservice = MicroserviceDTO(microserviceName) + + val database = PostgreSQL() + + every { systemAggregateStorage.getMicroservice(microserviceName) } returns null + + assertThrows { + systemCreator.addNewDatabaseConnectionToMicroservice( + database = database, + microserviceName = microserviceName + ) + } + + verify(exactly = 1) { + systemAggregateStorage.getMicroservice(microserviceName) + } + + verify(exactly = 0) { + systemAggregateStorage.save(microservice) + systemAggregateStorage.getCompanySystem(any()) + systemAggregateStorage.save(any()) + } + } } \ No newline at end of file From 4df635d95520f261775c29b8feae96a25c8fbe65 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sun, 13 Oct 2024 14:54:34 -0300 Subject: [PATCH 25/34] fix addMessageChannelsToMicroservice method in SystemCreator --- .../src/main/kotlin/com/usvision/creation/SystemCreator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt index f5e5490..91f32d9 100644 --- a/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt +++ b/app-creation/src/main/kotlin/com/usvision/creation/SystemCreator.kt @@ -80,7 +80,7 @@ class SystemCreator( } subscribedMessageChannels.forEach { - operation -> it.addPublishChannel(operation) + operation -> it.addSubscribedChannel(operation) } systemAggregateStorage.save(it) From f60796c02d4f228ce625c7b39042123d128a0e1f Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Mon, 14 Oct 2024 22:05:58 -0300 Subject: [PATCH 26/34] remove duplicated dependency in app-creation build.gradle.kts --- app-creation/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/app-creation/build.gradle.kts b/app-creation/build.gradle.kts index 3e9d301..dc8c0e6 100644 --- a/app-creation/build.gradle.kts +++ b/app-creation/build.gradle.kts @@ -21,5 +21,4 @@ dependencies { implementation(project(":app-model")) testImplementation("io.mockk:mockk:${mockk_version}") testImplementation(kotlin("test")) - implementation(project(":app-model")) } From 40b784d7be228dc875bc69e5f837ae68e41867c3 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Tue, 15 Oct 2024 22:57:18 -0300 Subject: [PATCH 27/34] add tests to microservices and companySystems creation endpoints --- app-web/build.gradle.kts | 7 + app-web/gradle.properties | 3 +- .../configuration/ApplicationRoutingTest.kt | 316 ++++++++++++++++++ app-web/src/test/resources/application.yaml | 6 + 4 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 app-web/src/test/kotlin/com/usvision/web/configuration/ApplicationRoutingTest.kt create mode 100644 app-web/src/test/resources/application.yaml diff --git a/app-web/build.gradle.kts b/app-web/build.gradle.kts index a796afe..dfd63be 100644 --- a/app-web/build.gradle.kts +++ b/app-web/build.gradle.kts @@ -1,3 +1,5 @@ +val mockk_version: String by project + plugins { application kotlin("jvm") @@ -43,4 +45,9 @@ dependencies { implementation("io.ktor:ktor-server-status-pages-jvm") implementation("io.ktor:ktor-server-config-yaml") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") + + testImplementation("io.mockk:mockk:${mockk_version}") + testImplementation("io.ktor:ktor-server-test-host") + testImplementation("io.ktor:ktor-client-content-negotiation") + testImplementation(kotlin("test")) } \ No newline at end of file diff --git a/app-web/gradle.properties b/app-web/gradle.properties index 29e08e8..34fb41c 100644 --- a/app-web/gradle.properties +++ b/app-web/gradle.properties @@ -1 +1,2 @@ -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official +mockk_version=1.12.3 diff --git a/app-web/src/test/kotlin/com/usvision/web/configuration/ApplicationRoutingTest.kt b/app-web/src/test/kotlin/com/usvision/web/configuration/ApplicationRoutingTest.kt new file mode 100644 index 0000000..285869e --- /dev/null +++ b/app-web/src/test/kotlin/com/usvision/web/configuration/ApplicationRoutingTest.kt @@ -0,0 +1,316 @@ +package com.usvision.web.configuration + +import com.usvision.creation.CompanySystemDTO +import com.usvision.creation.SystemCreator +import com.usvision.model.domain.MessageChannel +import com.usvision.model.domain.Microservice +import com.usvision.model.domain.databases.PostgreSQL +import com.usvision.model.domain.operations.RestEndpoint +import com.usvision.reports.ReportSupervisor +import com.usvision.web.dto.* +import io.ktor.client.* +import io.ktor.client.call.* +import io.ktor.server.testing.* +import io.ktor.client.request.* +import io.ktor.http.* +import io.ktor.serialization.kotlinx.json.* +import io.ktor.client.plugins.contentnegotiation.* +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlin.test.* + +internal class ApplicationRoutingTest { + private val systemCreator = mockk() + private val reportSupervisor = mockk() + + @Test + fun `it creates a new microservice`() = testApplication { + loadUnitTestModules() + val client = getHttpClient() + + val microserviceName = "microserviceName" + + val microserviceRequest = SystemRequestDTO( + name = microserviceName + ) + + val createdMicroservice = Microservice(name = microserviceName) + + val expectedResponseBody = createdMicroservice.toMicroserviceResponseDTO() + + every { systemCreator.createMicroservice(any()) } returns createdMicroservice + + val response = client.postRequest( + "/microservice", + microserviceRequest + ) + + val responseBody: SystemResponseDTO = response.body() + + verify(exactly = 1) { + systemCreator.createMicroservice(createdMicroservice) + } + + assertEquals(HttpStatusCode.Created, response.status) + assertEquals(expectedResponseBody, responseBody) + } + + @Test + fun `it adds a database to a microservice`() = testApplication { + loadUnitTestModules() + val client = getHttpClient() + + val microserviceName = "microserviceName" + + val databaseRequest = PostgreSQL() + + val updatedMicroservice = Microservice( + name = microserviceName + ).apply { + addDatabaseConnection(databaseRequest) + } + + val expectedResponseBody = updatedMicroservice.toMicroserviceResponseDTO() + + every { systemCreator.addNewDatabaseConnectionToMicroservice(any(), any()) } returns updatedMicroservice + + val response = client.postRequest( + "/microservice/$microserviceName/database", + databaseRequest + ) + + val responseBody: MicroserviceResponseDTO = response.body() + + verify(exactly = 1) { + systemCreator.addNewDatabaseConnectionToMicroservice(databaseRequest, microserviceName) + } + + assertEquals(HttpStatusCode.Created, response.status) + assertEquals(expectedResponseBody, responseBody) + } + + @Test + fun `it adds rest endpoints to a microservice`() = testApplication { + loadUnitTestModules() + val client = getHttpClient() + + val microserviceName = "microserviceName" + + val restEndpointsRequest = RestEndpointsRequestDTO( + consumedOperations = listOf(RestEndpoint("GET", "/test")), + exposedOperations = listOf(RestEndpoint("POST", "/test")) + ) + + val updatedMicroservice = Microservice( + name = microserviceName + ).apply { + consumeOperation(RestEndpoint("GET", "/test")) + exposeOperation(RestEndpoint("POST", "/test")) + } + + val expectedResponseBody = updatedMicroservice.toMicroserviceResponseDTO() + + every { systemCreator.addOperationsToMicroservice(any(), any(), any()) } returns updatedMicroservice + + val response = client.postRequest( + "/microservice/$microserviceName/rest-endpoints", + restEndpointsRequest + ) + + val responseBody: MicroserviceResponseDTO = response.body() + + verify(exactly = 1) { + systemCreator.addOperationsToMicroservice( + consumedOperations = restEndpointsRequest.consumedOperations, + exposedOperations = restEndpointsRequest.exposedOperations, + microserviceName = microserviceName + ) + } + + assertEquals(HttpStatusCode.Created, response.status) + assertEquals(expectedResponseBody, responseBody) + } + + @Test + fun `it adds message channels to a microservice`() = testApplication { + loadUnitTestModules() + val client = getHttpClient() + + val microserviceName = "microserviceName" + + val messageChannelsRequest = MessageChannelsRequestDTO( + publishMessageChannels = listOf(MessageChannel("publish")), + subscribedMessageChannels = listOf(MessageChannel("subscribe")) + ) + + val updatedMicroservice = Microservice( + name = microserviceName + ).apply { + addPublishChannel(MessageChannel("publish")) + addSubscribedChannel(MessageChannel("subscribe")) + } + + val expectedResponseBody = updatedMicroservice.toMicroserviceResponseDTO() + + every { systemCreator.addMessageChannelsToMicroservice(any(), any(), any()) } returns updatedMicroservice + + val response = client.postRequest( + "/microservice/$microserviceName/message-channels", + messageChannelsRequest + ) + + val responseBody: MicroserviceResponseDTO = response.body() + + verify(exactly = 1) { + systemCreator.addMessageChannelsToMicroservice( + publishMessageChannels = messageChannelsRequest.publishMessageChannels, + subscribedMessageChannels = messageChannelsRequest.subscribedMessageChannels, + microserviceName = microserviceName + ) + } + + assertEquals(HttpStatusCode.Created, response.status) + assertEquals(expectedResponseBody, responseBody) + } + + + @Test + fun `it creates a new companySystem`() = testApplication { + loadUnitTestModules() + val client = getHttpClient() + + val companySystemName = "companySystemName" + + val companySystemRequest = SystemRequestDTO( + name = companySystemName + ) + + val createdCompanySystem = CompanySystemDTO(name = companySystemName) + + val expectedResponseBody = createdCompanySystem.toCompanySystemResponseDTO() + + every { systemCreator.createCompanySystem(any()) } returns createdCompanySystem + + val response = client.postRequest( + "/systems", + companySystemRequest + ) + + val responseBody: CompanySystemResponseDTO = response.body() + + verify(exactly = 1) { + systemCreator.createCompanySystem(createdCompanySystem) + } + + assertEquals(HttpStatusCode.Created, response.status) + assertEquals(expectedResponseBody, responseBody) + } + + @Test + fun `it adds a child microservice to a CompanySystem`() = testApplication { + loadUnitTestModules() + val client = getHttpClient() + + val companySystemName = "companySystemName" + val microserviceName = "microServiceName" + + + val microserviceRequest = SystemRequestDTO( + name = microserviceName + ) + + val createdMicroservice = Microservice(name = microserviceName) + + val createdCompanySystem = CompanySystemDTO(name = companySystemName).apply { + addSubsystem(createdMicroservice) + } + + val expectedResponseBody = createdCompanySystem.toSystemResponseDTO() + + every { systemCreator.createMicroservice(any(), any()) } returns createdCompanySystem + + val response = client.postRequest( + "/systems/$companySystemName/microservice", + microserviceRequest + ) + + val responseBody: SystemResponseDTO = response.body() + + verify(exactly = 1) { + systemCreator.createMicroservice(createdMicroservice, companySystemName) + } + + assertEquals(HttpStatusCode.Created, response.status) + assertEquals(expectedResponseBody, responseBody) + } + + @Test + fun `it adds a child CompanySystem to a CompanySystem`() = testApplication { + loadUnitTestModules() + val client = getHttpClient() + + val fatherCompanySystemName = "fatherCompanySystemName" + val childCompanySystemName = "childCompanySystemName" + + + val companySystemRequest = SystemRequestDTO( + name = childCompanySystemName + ) + + val createdChildCompanySystem = CompanySystemDTO(name = childCompanySystemName) + + val createdFatherCompanySystem = CompanySystemDTO(name = fatherCompanySystemName).apply { + addSubsystem(createdChildCompanySystem) + } + + val expectedResponseBody = createdFatherCompanySystem.toSystemResponseDTO() + + every { systemCreator.createCompanySystem(any(), any()) } returns createdFatherCompanySystem + + val response = client.postRequest( + "/systems/$fatherCompanySystemName/companySubsystem", + companySystemRequest + ) + + val responseBody: CompanySystemResponseDTO = response.body() + + verify(exactly = 1) { + systemCreator.createCompanySystem(createdChildCompanySystem, fatherCompanySystemName) + } + + assertEquals(HttpStatusCode.Created, response.status) + assertEquals(expectedResponseBody, responseBody) + } + + + private suspend inline fun HttpClient.postRequest( + urlString: String, + body: T + ) = this.post(urlString) { + url { + protocol = URLProtocol.HTTPS + contentType(ContentType.Application.Json) + setBody(body) + } + } + + private fun ApplicationTestBuilder.getHttpClient(): HttpClient { + val client = createClient { + install(ContentNegotiation) { + json() + } + } + return client + } + + private fun ApplicationTestBuilder.loadUnitTestModules() { + application { + configureCORS() + configureSerialization() + configureRouting(reportSupervisor, systemCreator) + configureExceptionHandling() + } + } + +} \ No newline at end of file diff --git a/app-web/src/test/resources/application.yaml b/app-web/src/test/resources/application.yaml new file mode 100644 index 0000000..b8cbef4 --- /dev/null +++ b/app-web/src/test/resources/application.yaml @@ -0,0 +1,6 @@ +ktor: + deployment: + port: 8080 + +reports: + default_preset_name: all \ No newline at end of file From bf5b22241fce00ad8f06e3ccd6d9da0611914e35 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Tue, 15 Oct 2024 23:00:11 -0300 Subject: [PATCH 28/34] fix /microservices and /systems endpoints paths --- .../main/kotlin/com/usvision/web/configuration/routing.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt b/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt index 490e6b7..7745f8c 100644 --- a/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt +++ b/app-web/src/main/kotlin/com/usvision/web/configuration/routing.kt @@ -15,7 +15,7 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat val defaultPreset = environment.config.property("reports.default_preset_name").getString() routing { - route("/microservice") { + route("/microservices") { post { val microservice = call.receive().toMicroservice() val createMicroserviceResult = systemCreator.createMicroservice(microservice) @@ -25,7 +25,7 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat status = HttpStatusCode.Created ) } - post("/{name}/database") { + post("/{name}/databases") { val microserviceName: String = call.parameters["name"] ?: throw MissingRequiredPathParameterException("name", "String") @@ -86,7 +86,7 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat ) } - post("/{name}/microservice") { + post("/{name}/microservices") { val systemName: String = call.parameters["name"] ?: throw MissingRequiredPathParameterException("name", "String") @@ -99,7 +99,7 @@ fun Application.configureRouting(reportSupervisor: ReportSupervisor, systemCreat ) } - post("/{name}/companySubsystem") { + post("/{name}/companySubsystems") { val systemName: String = call.parameters["name"] ?: throw MissingRequiredPathParameterException("name", "String") From 5d7da25c00ad57c983ec306d833549e772956017 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Tue, 15 Oct 2024 23:02:10 -0300 Subject: [PATCH 29/34] fix /microservices and /systems endpoints paths in ApplicationRoutingTest --- .../web/configuration/ApplicationRoutingTest.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app-web/src/test/kotlin/com/usvision/web/configuration/ApplicationRoutingTest.kt b/app-web/src/test/kotlin/com/usvision/web/configuration/ApplicationRoutingTest.kt index 285869e..c131f08 100644 --- a/app-web/src/test/kotlin/com/usvision/web/configuration/ApplicationRoutingTest.kt +++ b/app-web/src/test/kotlin/com/usvision/web/configuration/ApplicationRoutingTest.kt @@ -42,7 +42,7 @@ internal class ApplicationRoutingTest { every { systemCreator.createMicroservice(any()) } returns createdMicroservice val response = client.postRequest( - "/microservice", + "/microservices", microserviceRequest ) @@ -76,7 +76,7 @@ internal class ApplicationRoutingTest { every { systemCreator.addNewDatabaseConnectionToMicroservice(any(), any()) } returns updatedMicroservice val response = client.postRequest( - "/microservice/$microserviceName/database", + "/microservices/$microserviceName/databases", databaseRequest ) @@ -114,7 +114,7 @@ internal class ApplicationRoutingTest { every { systemCreator.addOperationsToMicroservice(any(), any(), any()) } returns updatedMicroservice val response = client.postRequest( - "/microservice/$microserviceName/rest-endpoints", + "/microservices/$microserviceName/rest-endpoints", restEndpointsRequest ) @@ -156,7 +156,7 @@ internal class ApplicationRoutingTest { every { systemCreator.addMessageChannelsToMicroservice(any(), any(), any()) } returns updatedMicroservice val response = client.postRequest( - "/microservice/$microserviceName/message-channels", + "/microservices/$microserviceName/message-channels", messageChannelsRequest ) @@ -231,7 +231,7 @@ internal class ApplicationRoutingTest { every { systemCreator.createMicroservice(any(), any()) } returns createdCompanySystem val response = client.postRequest( - "/systems/$companySystemName/microservice", + "/systems/$companySystemName/microservices", microserviceRequest ) @@ -269,7 +269,7 @@ internal class ApplicationRoutingTest { every { systemCreator.createCompanySystem(any(), any()) } returns createdFatherCompanySystem val response = client.postRequest( - "/systems/$fatherCompanySystemName/companySubsystem", + "/systems/$fatherCompanySystemName/companySubsystems", companySystemRequest ) From 369ae36c0c3655bc98922d45bb33a6c25ab5e2b0 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Tue, 15 Oct 2024 23:06:50 -0300 Subject: [PATCH 30/34] move kotlinx serialization version to gradle.properties in app-web module --- app-web/build.gradle.kts | 3 ++- app-web/gradle.properties | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app-web/build.gradle.kts b/app-web/build.gradle.kts index dfd63be..b251fbc 100644 --- a/app-web/build.gradle.kts +++ b/app-web/build.gradle.kts @@ -1,4 +1,5 @@ val mockk_version: String by project +val kotlinx_serialization_version: String by project plugins { application @@ -44,7 +45,7 @@ dependencies { implementation("io.ktor:ktor-server-host-common-jvm") implementation("io.ktor:ktor-server-status-pages-jvm") implementation("io.ktor:ktor-server-config-yaml") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:${kotlinx_serialization_version}") testImplementation("io.mockk:mockk:${mockk_version}") testImplementation("io.ktor:ktor-server-test-host") diff --git a/app-web/gradle.properties b/app-web/gradle.properties index 34fb41c..be79e87 100644 --- a/app-web/gradle.properties +++ b/app-web/gradle.properties @@ -1,2 +1,3 @@ kotlin.code.style=official mockk_version=1.12.3 +kotlinx_serialization_version=1.6.0 \ No newline at end of file From a6a4818cf0f83af57191495563c28472dcde8338 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sat, 19 Oct 2024 13:00:47 -0300 Subject: [PATCH 31/34] add unit tests to MongoSystemRepository --- app-persistence/build.gradle.kts | 1 + .../repositories/MongoSystemRepositoryTest.kt | 167 ++++++++++++++++++ 2 files changed, 168 insertions(+) diff --git a/app-persistence/build.gradle.kts b/app-persistence/build.gradle.kts index 22efacf..85ad114 100644 --- a/app-persistence/build.gradle.kts +++ b/app-persistence/build.gradle.kts @@ -28,4 +28,5 @@ dependencies { testImplementation(kotlin("test")) testImplementation("io.mockk:mockk:$mockk_version") + testImplementation("org.junit.jupiter:junit-jupiter-params") } \ No newline at end of file diff --git a/app-persistence/src/test/kotlin/com/usvision/persistence/repositories/MongoSystemRepositoryTest.kt b/app-persistence/src/test/kotlin/com/usvision/persistence/repositories/MongoSystemRepositoryTest.kt index d340e9b..fe8b18a 100644 --- a/app-persistence/src/test/kotlin/com/usvision/persistence/repositories/MongoSystemRepositoryTest.kt +++ b/app-persistence/src/test/kotlin/com/usvision/persistence/repositories/MongoSystemRepositoryTest.kt @@ -4,8 +4,11 @@ import com.mongodb.client.model.Filters import com.mongodb.kotlin.client.coroutine.MongoCollection import com.mongodb.kotlin.client.coroutine.MongoDatabase import com.usvision.model.domain.CompanySystem +import com.usvision.model.domain.MessageChannel import com.usvision.model.domain.Microservice +import com.usvision.model.domain.databases.PostgreSQL import com.usvision.model.domain.operations.RestEndpoint +import com.usvision.model.systemcomposite.System import com.usvision.persistence.documents.* import com.usvision.persistence.exceptions.MalformedSystemDocumentException import com.usvision.persistence.repositorybuilder.MongoDBRepositoryProvider @@ -14,7 +17,11 @@ import kotlinx.coroutines.runBlocking import org.bson.Document import org.bson.types.ObjectId import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource import java.util.* +import java.util.stream.Stream import kotlin.test.* internal class MongoSystemRepositoryTest { @@ -166,6 +173,158 @@ internal class MongoSystemRepositoryTest { assertTrue { system.getSubscribedChannels().isNotEmpty() } } + @Test + fun `it saves a CompanySystem and returns it`() { + val companySystem = CompanySystem( + name = "companySystem" + ).apply { + addSubsystem(CompanySystem(name = "childCompanySystem")) + addSubsystem(Microservice(name = "childMicroservice")) + } + + val createdSystem = underTest.save(companySystem) + + assertEquals(companySystem, createdSystem) + } + + @Test + fun `it saves a Microservice and returns it`() { + val microservice = Microservice( + name = "microservice" + ).apply { + addDatabaseConnection(PostgreSQL()) + addPublishChannel(MessageChannel("publishChannel")) + addSubscribedChannel(MessageChannel("subscribeChannel")) + consumeOperation(RestEndpoint("GET", "/test")) + exposeOperation(RestEndpoint("POST", "/test")) + } + + val createdSystem = underTest.save(microservice) + + assertEquals(microservice, createdSystem) + } + + @Test + fun `it returns a CompanySystem when it exists`() { + val companySystemName = "companySystemName" + + val companySystem = CompanySystem( + name = companySystemName + ).apply { + addSubsystem(CompanySystem(name = "childCompanySystem")) + addSubsystem(Microservice(name = "childMicroservice")) + } + + underTest.save(companySystem) + + val returnedSystem = underTest.getCompanySystem(companySystemName) + + assertEquals(companySystem, returnedSystem) + } + + @Test + fun `it returns null when no such name is found while trying to get a CompanySystem`() { + assertNull(underTest.getCompanySystem("companySystemName")) + } + + @Test + fun `it returns null when given name is from a Microservice while trying to get a CompanySystem`() { + val microserviceName = "microserviceName" + + underTest.save(Microservice(name = microserviceName)) + + assertNull(underTest.getCompanySystem(microserviceName)) + } + + @Test + fun `it returns a Microservice when it exists`() { + val microserviceName = "microserviceName" + + val microservice = Microservice( + name = microserviceName + ).apply { + addDatabaseConnection(PostgreSQL()) + addPublishChannel(MessageChannel("publishChannel")) + addSubscribedChannel(MessageChannel("subscribeChannel")) + consumeOperation(RestEndpoint("GET", "/test")) + exposeOperation(RestEndpoint("POST", "/test")) + } + underTest.save(microservice) + + val returnedSystem = underTest.getMicroservice(microserviceName) + + assertEquals(microservice, returnedSystem) + } + + @Test + fun `it returns null when no such name is found while trying to get a Microservice`() { + assertNull(underTest.getMicroservice("microserviceName")) + } + + @Test + fun `it returns null when given name is from a CompanySystem while trying to get a Microservice`() { + val companySystemName = "companySystemName" + + underTest.save(CompanySystem(name = companySystemName)) + + assertNull(underTest.getMicroservice(companySystemName)) + } + + @ParameterizedTest + @MethodSource("systemProvider") + fun `it returns a System when it exists`(system: System) { + when (system) { + is Microservice -> underTest.save(system) + is CompanySystem -> underTest.save(system) + } + + assertEquals(system, underTest.getSystem(system.name)) + } + + @Test + fun `it returns null when no such name is found while trying to get a System`() { + assertNull(underTest.getSystem("systemName")) + } + + @Test + fun `it updates existing CompanySystem`() { + val companySystem = CompanySystem( + name = "companySystemName" + ) + + underTest.save(companySystem) + + val updatedCompanySystem = companySystem.copy().apply { + addSubsystem(Microservice(name = "microserviceName")) + } + + underTest.save(updatedCompanySystem) + + assertEquals(updatedCompanySystem, underTest.getCompanySystem("companySystemName")) + } + + @Test + fun `it updates existing Microservice`() { + val microservice = Microservice( + name = "microserviceName" + ) + + underTest.save(microservice) + + val updatedMicroservice = microservice.copy().apply { + addDatabaseConnection(PostgreSQL()) + addPublishChannel(MessageChannel("publishChannel")) + addSubscribedChannel(MessageChannel("subscribeChannel")) + consumeOperation(RestEndpoint("GET", "/test")) + exposeOperation(RestEndpoint("POST", "/test")) + } + + underTest.save(updatedMicroservice) + + assertEquals(updatedMicroservice, underTest.getMicroservice("microserviceName")) + } + + private fun createSystemWithoutSubsysNorModule(name: String) = runBlocking { systemsCollection.insertOne( SystemDocument( @@ -305,4 +464,12 @@ internal class MongoSystemRepositoryTest { ) ) } + + companion object { + @JvmStatic + fun systemProvider(): Stream = Stream.of( + Arguments.of(Microservice(name = "microserviceName")), + Arguments.of(CompanySystem(name = "companySystemName")) + ) + } } \ No newline at end of file From 55706fa9e6e2928f32bbdfb14b624a614e254eaf Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sat, 19 Oct 2024 13:52:56 -0300 Subject: [PATCH 32/34] handle invalid casting in getCompanySystem and getMicroservice methods --- .../repositories/MongoSystemRepository.kt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt index 08196b4..bd6e057 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt @@ -55,12 +55,19 @@ class MongoSystemRepository(db: MongoDatabase) : SystemRepository, SystemAggrega getSystemById(insertedId.asObjectId().value) as Microservice } + override fun getCompanySystem(name: String): CompanySystem? = try { + getSystem(name = name) as CompanySystem? + } catch (ex: ClassCastException) { + null + } - override fun getCompanySystem(name: String): CompanySystem? = getSystem(name = name) as CompanySystem? - - override fun getMicroservice(name: String): Microservice? = getSystem(name = name) as Microservice? + override fun getMicroservice(name: String): Microservice? = try { + getSystem(name = name) as Microservice? + } catch (ex: ClassCastException) { + null + } - fun getSystemById(id: ObjectId): System? = runBlocking { + private fun getSystemById(id: ObjectId): System? = runBlocking { systemCollection .find(Filters.eq("_id", id)) .firstOrNull() From 399a026768937be2f7d26f764d81b739a5fc99a2 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Sat, 19 Oct 2024 16:04:23 -0300 Subject: [PATCH 33/34] fix ObjectId instantiation in Database.toDatabaseDocument() converter --- .../com/usvision/persistence/documents/SystemDocument.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt index 44c8167..6e40c00 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/documents/SystemDocument.kt @@ -101,4 +101,7 @@ private fun Operation.toDocument() = when (this) { else -> throw UnknownOperationClassException("SystemDocument") } -private fun Database.toDatabaseDocument() = DatabaseDocument(id = ObjectId(this.id), description = this.description) +private fun Database.toDatabaseDocument() = DatabaseDocument( + id = this.id?.let { ObjectId(this.id) } ?: ObjectId(), + description = this.description +) From d31100c1c2780351a2cf354de0b327bcf6502071 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Tue, 10 Dec 2024 00:10:58 -0300 Subject: [PATCH 34/34] fix MongoSystemRepository --- .../usvision/persistence/repositories/MongoSystemRepository.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt index bd6e057..2152137 100644 --- a/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt +++ b/app-persistence/src/main/kotlin/com/usvision/persistence/repositories/MongoSystemRepository.kt @@ -16,7 +16,6 @@ import kotlinx.coroutines.runBlocking import org.bson.types.ObjectId -class MongoSystemRepository(db: MongoDatabase) : SystemRepository { class MongoSystemRepository(db: MongoDatabase) : SystemRepository, SystemAggregateStorage { companion object { const val COLLECTION_NAME = "systems"