From 57c69356062f4d911097cbaad29ab49344a95be4 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 19 Jun 2024 22:08:54 -0300 Subject: [PATCH 1/6] fix "it builds an entire system" test and MicroserviceBuilder.and() method implementation --- .../kotlin/com/usvision/model/systembuilder/SystemBuilder.kt | 2 +- .../com/usvision/model/systembuilder/SystemBuilderTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt b/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt index 9a3190f..579a0fe 100644 --- a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt +++ b/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt @@ -85,7 +85,7 @@ class MicroserviceBuilder(private val parent: SystemBuilder? = null) { fun and(): MicroserviceBuilder { endMicroservices() - return parent!!.thatHasMicroservices() + return MicroserviceBuilder(this.parent) } fun named(name: String) = fluentInterface { diff --git a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt index dc5ff99..795c77f 100644 --- a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt +++ b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt @@ -46,7 +46,7 @@ internal class SystemBuilderTest { assertEquals(1, system.getSubsystemSet().size) val firstLevelSubsys = system.getSubsystemSet().first() assertIs(firstLevelSubsys) - assertEquals(1, firstLevelSubsys.getSubsystemSet().size) + assertEquals(2, firstLevelSubsys.getSubsystemSet().size) assertIs(firstLevelSubsys.getSubsystemSet().first()) } From 2aef39f0580c79e796df7ba946b548cdd46e6b1c Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 19 Jun 2024 22:33:53 -0300 Subject: [PATCH 2/6] add SystemBuilderException when a MicroserviceBuilder tries to build a Microservice with no name --- .../model/systembuilder/SystemBuilder.kt | 18 ++++++++++-------- .../model/systembuilder/SystemBuilderTest.kt | 9 +++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt b/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt index 579a0fe..f031a90 100644 --- a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt +++ b/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt @@ -61,7 +61,7 @@ class SystemBuilder(private val parent: SystemBuilder? = null) { } class MicroserviceBuilder(private val parent: SystemBuilder? = null) { - private lateinit var name: String + private var name: String? = null private val exposedOperations = mutableSetOf() private val consumedOperations = mutableSetOf() private val databases = mutableSetOf() @@ -117,12 +117,14 @@ class MicroserviceBuilder(private val parent: SystemBuilder? = null) { } fun build(): Microservice { - return Microservice(name).also { msvc -> - exposedOperations.forEach(msvc::exposeOperation) - consumedOperations.forEach(msvc::consumeOperation) - databases.forEach(msvc::addDatabaseConnection) - channelsPublished.forEach(msvc::addPublishChannel) - channelsSubscribed.forEach(msvc::addSubscribedChannel) - } + return this.name?.let { name -> + Microservice(name).also { msvc -> + exposedOperations.forEach(msvc::exposeOperation) + consumedOperations.forEach(msvc::consumeOperation) + databases.forEach(msvc::addDatabaseConnection) + channelsPublished.forEach(msvc::addPublishChannel) + channelsSubscribed.forEach(msvc::addSubscribedChannel) + } + } ?: throw SystemBuilderException("Attempted to build a Microservice with no name") } } \ No newline at end of file diff --git a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt index 795c77f..06230df 100644 --- a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt +++ b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt @@ -158,6 +158,15 @@ internal class MicroserviceBuilderTest { assertNotNull(result.module) } + @Test + fun `it throws SystemBuilderException when building a Microservice with no name`() { + // given nothing + // when ... then + assertThrows { + underTest.build() + } + } + @Test fun `it adds exposed rest endpoints`() { // given From a048c3e2b7a3faf1dc86a95db640c7bc8496f53e Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 19 Jun 2024 23:03:47 -0300 Subject: [PATCH 3/6] add SystemBuilderException when a MicroserviceBuilder calls named() twice --- .../usvision/model/systembuilder/SystemBuilder.kt | 4 ++++ .../model/systembuilder/SystemBuilderTest.kt | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt b/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt index f031a90..d9c188b 100644 --- a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt +++ b/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt @@ -89,6 +89,10 @@ class MicroserviceBuilder(private val parent: SystemBuilder? = null) { } fun named(name: String) = fluentInterface { + this.name?.also { + throw SystemBuilderException("Microservice already has a name: $name") + } + this.name = name } diff --git a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt index 06230df..10550f1 100644 --- a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt +++ b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt @@ -298,6 +298,21 @@ internal class MicroserviceBuilderTest { verify { underTest.named(name) } } + @Test + fun `it throws SystemBuilderException when calling 'named' method twice`() { + // given + val name = "micro" + + val result = underTest + .named(name) + + + // when ... then + assertThrows { + result.named(name) + } + } + @Test fun `it offers 'and' as a convenience for finishing one and beginning another`() { // given From 3d900ee21f069adafff4204e4c3e5fbc0fc353f2 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Thu, 27 Jun 2024 01:03:43 -0300 Subject: [PATCH 4/6] add MicroserviceBuilder.and().and() test, fix parent without subsystems set on MicroserviceBuilder tests --- .../model/systembuilder/SystemBuilderTest.kt | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt index 10550f1..ae6feb8 100644 --- a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt +++ b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt @@ -113,7 +113,11 @@ internal class MicroserviceBuilderTest { @BeforeTest fun `create clean, new instance of MicroserviceBuilder`() { - underTest = MicroserviceBuilder() + val parent = spyk(SystemBuilder()) + + // when + underTest = parent + .thatHasMicroservices() } @Test @@ -129,7 +133,8 @@ internal class MicroserviceBuilderTest { fun `it returns its parent when closing a properly opened microservice env`() { // given val parent = spyk(SystemBuilder()) - underTest = MicroserviceBuilder(parent) + underTest = parent + .thatHasMicroservices() // when val environment = underTest @@ -303,16 +308,35 @@ internal class MicroserviceBuilderTest { // given val name = "micro" + // when val result = underTest .named(name) - // when ... then + //then assertThrows { result.named(name) } } + + @Test + fun `it throws SystemBuilderException when calling 'and' method twice without setting a name for the second microservice`() { + // given + val name = "micro" + + // when + val result = underTest + .named(name) + .and() + + + //then + assertThrows { + result.and() + } + } + @Test fun `it offers 'and' as a convenience for finishing one and beginning another`() { // given From 92461bfd3692c6fe0c72b6d7381ccb932e5a426d Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Fri, 12 Jul 2024 02:08:05 -0300 Subject: [PATCH 5/6] make SystemBuilder able to add more than one subsystem to System --- .../model/systembuilder/SystemBuilder.kt | 34 ++++++++++------- .../model/systembuilder/SystemBuilderTest.kt | 37 ++++++++++++++++--- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt b/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt index d9c188b..a424de7 100644 --- a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt +++ b/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt @@ -13,34 +13,41 @@ class SystemBuilderException(message: String) : RuntimeException(message) class SystemBuilder(private val parent: SystemBuilder? = null) { - private lateinit var rootName: String - private lateinit var subsystems: MutableSet + private var rootName: String? = null + private var subsystems: MutableSet = mutableSetOf() private fun fluentInterface(instance: SystemBuilder = this, implementation: SystemBuilder.() -> Unit): SystemBuilder { implementation() return instance } - fun setName(name: String) = fluentInterface { rootName = name } + fun setName(name: String) = fluentInterface { + this.rootName?.also { + throw SystemBuilderException("System already has a name: $rootName") + } + rootName = name + } + + fun addSubsystems(): SystemBuilder { + return SystemBuilder(this) + } - fun addSubsystems() = fluentInterface(SystemBuilder(this)) { - subsystems = mutableSetOf() + fun and(): SystemBuilder { + endSubsystems() + return SystemBuilder(this.parent) } fun endSubsystems(): SystemBuilder { if (parent == null) throw SystemBuilderException("Attempted to close an environment that had not being opened") - if (this::rootName.isInitialized) { - val system = build() - parent.addSubsystem(system) - } + val system = build() + parent.addSubsystem(system) return parent } fun thatHasMicroservices(): MicroserviceBuilder { - subsystems = mutableSetOf() return MicroserviceBuilder(this) } @@ -53,10 +60,11 @@ class SystemBuilder(private val parent: SystemBuilder? = null) { } fun build(): System { - return CompanySystem(rootName).also { root -> - if (this::subsystems.isInitialized) + return this.rootName?.let { rootName -> + CompanySystem(rootName).also { root -> subsystems.forEach(root::addSubsystem) - } + } + } ?: throw SystemBuilderException("Attempted to build a System with no name") } } diff --git a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt index ae6feb8..dc2f6c4 100644 --- a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt +++ b/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt @@ -50,6 +50,34 @@ internal class SystemBuilderTest { assertIs(firstLevelSubsys.getSubsystemSet().first()) } + + @Test + fun `it builds a system with two subsystems`() { + + // given ... when + val system = underTest + .setName("Bank") + .addSubsystems() + .setName("Bank subsystem one") + .thatHasMicroservices() + .oneNamed("Balance API") + .exposingRestEndpoint("GET", "/account/balance", "account balance") + .endMicroservices() + .and() + .setName("Bank subsystem two") + .endSubsystems() + .build() + + // then + assertIs(system) + assertEquals(2, system.getSubsystemSet().size) + val firstLevelSubsys = system.getSubsystemSet().first() + assertIs(firstLevelSubsys) + assertEquals(1, firstLevelSubsys.getSubsystemSet().size) + assertIs(firstLevelSubsys.getSubsystemSet().first()) + } + + @Test fun `it defaults to a company system`() { // given @@ -66,7 +94,7 @@ internal class SystemBuilderTest { } @Test - fun `opening and closing a subsystem environment gives an empty subsys set`() { + fun `it throws SystemBuilderException when endSubsystems without setting a name for the subsystem`() { // given val name = "test" @@ -74,12 +102,11 @@ internal class SystemBuilderTest { val result = underTest .setName(name) .addSubsystems() - .endSubsystems() - .build() // then - assertIs(result) - assertContentEquals(listOf(), result.getSubsystemSet()) + assertThrows { + result.endSubsystems() + } } @Test From 8270b87e84b33139d6766c0d4612f3d529a8e668 Mon Sep 17 00:00:00 2001 From: Vinicius Frota Date: Wed, 7 Aug 2024 22:10:40 -0300 Subject: [PATCH 6/6] rename SystemBuilder to CompanySystemBuilder --- ...ystemBuilder.kt => CompanySystemBuilder.kt} | 18 +++++++++--------- ...lderTest.kt => CompanySystemBuilderTest.kt} | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) rename app-model/src/main/kotlin/com/usvision/model/systembuilder/{SystemBuilder.kt => CompanySystemBuilder.kt} (88%) rename app-model/src/test/kotlin/com/usvision/model/systembuilder/{SystemBuilderTest.kt => CompanySystemBuilderTest.kt} (96%) diff --git a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt b/app-model/src/main/kotlin/com/usvision/model/systembuilder/CompanySystemBuilder.kt similarity index 88% rename from app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt rename to app-model/src/main/kotlin/com/usvision/model/systembuilder/CompanySystemBuilder.kt index a424de7..e36ae6a 100644 --- a/app-model/src/main/kotlin/com/usvision/model/systembuilder/SystemBuilder.kt +++ b/app-model/src/main/kotlin/com/usvision/model/systembuilder/CompanySystemBuilder.kt @@ -12,11 +12,11 @@ import com.usvision.model.systemcomposite.System class SystemBuilderException(message: String) : RuntimeException(message) -class SystemBuilder(private val parent: SystemBuilder? = null) { +class CompanySystemBuilder(private val parent: CompanySystemBuilder? = null) { private var rootName: String? = null private var subsystems: MutableSet = mutableSetOf() - private fun fluentInterface(instance: SystemBuilder = this, implementation: SystemBuilder.() -> Unit): SystemBuilder { + private fun fluentInterface(instance: CompanySystemBuilder = this, implementation: CompanySystemBuilder.() -> Unit): CompanySystemBuilder { implementation() return instance } @@ -28,16 +28,16 @@ class SystemBuilder(private val parent: SystemBuilder? = null) { rootName = name } - fun addSubsystems(): SystemBuilder { - return SystemBuilder(this) + fun addSubsystems(): CompanySystemBuilder { + return CompanySystemBuilder(this) } - fun and(): SystemBuilder { + fun and(): CompanySystemBuilder { endSubsystems() - return SystemBuilder(this.parent) + return CompanySystemBuilder(this.parent) } - fun endSubsystems(): SystemBuilder { + fun endSubsystems(): CompanySystemBuilder { if (parent == null) throw SystemBuilderException("Attempted to close an environment that had not being opened") @@ -68,7 +68,7 @@ class SystemBuilder(private val parent: SystemBuilder? = null) { } } -class MicroserviceBuilder(private val parent: SystemBuilder? = null) { +class MicroserviceBuilder(private val parent: CompanySystemBuilder? = null) { private var name: String? = null private val exposedOperations = mutableSetOf() private val consumedOperations = mutableSetOf() @@ -81,7 +81,7 @@ class MicroserviceBuilder(private val parent: SystemBuilder? = null) { return this } - fun endMicroservices(): SystemBuilder { + fun endMicroservices(): CompanySystemBuilder { if (parent == null) throw SystemBuilderException("Attempted to close an environment that had not being opened") diff --git a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt b/app-model/src/test/kotlin/com/usvision/model/systembuilder/CompanySystemBuilderTest.kt similarity index 96% rename from app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt rename to app-model/src/test/kotlin/com/usvision/model/systembuilder/CompanySystemBuilderTest.kt index dc2f6c4..b6db52e 100644 --- a/app-model/src/test/kotlin/com/usvision/model/systembuilder/SystemBuilderTest.kt +++ b/app-model/src/test/kotlin/com/usvision/model/systembuilder/CompanySystemBuilderTest.kt @@ -8,12 +8,12 @@ import io.mockk.verify import org.junit.jupiter.api.assertThrows import kotlin.test.* -internal class SystemBuilderTest { - private lateinit var underTest: SystemBuilder +internal class CompanySystemBuilderTest { + private lateinit var underTest: CompanySystemBuilder @BeforeTest fun `create clean, new instance of SystemBuilder`() { - underTest = SystemBuilder() + underTest = CompanySystemBuilder() } @Test @@ -140,7 +140,7 @@ internal class MicroserviceBuilderTest { @BeforeTest fun `create clean, new instance of MicroserviceBuilder`() { - val parent = spyk(SystemBuilder()) + val parent = spyk(CompanySystemBuilder()) // when underTest = parent @@ -159,7 +159,7 @@ internal class MicroserviceBuilderTest { @Test fun `it returns its parent when closing a properly opened microservice env`() { // given - val parent = spyk(SystemBuilder()) + val parent = spyk(CompanySystemBuilder()) underTest = parent .thatHasMicroservices() @@ -169,7 +169,7 @@ internal class MicroserviceBuilderTest { .endMicroservices() // then - assertIs(environment) + assertIs(environment) assertEquals(parent, environment) verify { parent.addMicroservice(any()) } } @@ -369,7 +369,7 @@ internal class MicroserviceBuilderTest { // given val nameOne = "name one" val nameTwo = "name two" - val parent = spyk(SystemBuilder()) + val parent = spyk(CompanySystemBuilder()) // when parent