diff --git a/pom.xml b/pom.xml index 81ae75f28b623c6b46d1199869cbc2d182b1b012..d8c7249777439ebafac7dd69d0ac799175ae6f24 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ maven-enforcer-plugin - 3.0.0-M2 + 3.0.0-M1 dependencies-sanitization @@ -93,9 +93,6 @@ -Xjsr305=strict - - spring - 1.8 true diff --git a/talkadvisor-domain/pom.xml b/talkadvisor-domain/pom.xml index 2dc7a73939d8f5412cbeb211e4fed13ed80ead37..06630f6c131cb9b586b86779b32fe2f97f7900f0 100644 --- a/talkadvisor-domain/pom.xml +++ b/talkadvisor-domain/pom.xml @@ -39,6 +39,36 @@ + + kotlin-maven-plugin + org.jetbrains.kotlin + + + all-open + + + + + + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + + + maven-jar-plugin + + + + test-jar + + + + diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/Aggregate.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/Aggregate.kt new file mode 100644 index 0000000000000000000000000000000000000000..f98d09f4b31fa1dafa679b0858703d444ec1c2ba --- /dev/null +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/Aggregate.kt @@ -0,0 +1,8 @@ +package org.craftsrecords.hexarch + +import java.lang.annotation.Inherited + +@Retention(AnnotationRetention.SOURCE) +@Target(AnnotationTarget.CLASS) +@Inherited +annotation class Aggregate diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/DomainService.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/DomainService.kt new file mode 100644 index 0000000000000000000000000000000000000000..df3c7a0ccc0bcfe5cb024f42c0bcf91ae3635810 --- /dev/null +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/DomainService.kt @@ -0,0 +1,8 @@ +package org.craftsrecords.hexarch + +import java.lang.annotation.Inherited + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +@Inherited +annotation class DomainService diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/Repository.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/Repository.kt new file mode 100644 index 0000000000000000000000000000000000000000..cff4f9358b578dd2ac589dc1918f43e37a7b1fb9 --- /dev/null +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/Repository.kt @@ -0,0 +1,8 @@ +package org.craftsrecords.hexarch + +import java.lang.annotation.Inherited + +@Retention(AnnotationRetention.SOURCE) +@Target(AnnotationTarget.CLASS) +@Inherited +annotation class Repository diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/Stub.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/Stub.kt new file mode 100644 index 0000000000000000000000000000000000000000..14a2567ab1f6922147d33eddbb8c9fdb084944f9 --- /dev/null +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/hexarch/Stub.kt @@ -0,0 +1,8 @@ +package org.craftsrecords.hexarch + +import java.lang.annotation.Inherited + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +@Inherited +annotation class Stub diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/Recommendation.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/Recommendation.kt index decde4ad51a474b0997c48d355f22d3541dc9fc6..d7a149906380a1e72827a6de129d71876d1c5cb7 100644 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/Recommendation.kt +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/Recommendation.kt @@ -1,9 +1,11 @@ package org.craftsrecords.talkadvisor.recommendation +import org.craftsrecords.hexarch.Aggregate import org.craftsrecords.talkadvisor.recommendation.criteria.Criteria import org.craftsrecords.talkadvisor.recommendation.talk.Talk import java.util.* +@Aggregate class Recommendation(val id: UUID = UUID.randomUUID(), talks: Set, val criteria: Criteria) { val talks = talks.toSet() diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/TalksAdvisor.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/TalksAdvisor.kt index 4e0ca2e4644f4c7786d1c6d8affbc3bd6cda0ea7..7fb890e5329b336a9771b915a163b10d175b8cd8 100644 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/TalksAdvisor.kt +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/TalksAdvisor.kt @@ -1,19 +1,22 @@ package org.craftsrecords.talkadvisor.recommendation +import org.craftsrecords.hexarch.DomainService import org.craftsrecords.talkadvisor.recommendation.api.RecommendTalks import org.craftsrecords.talkadvisor.recommendation.criteria.Criteria import org.craftsrecords.talkadvisor.recommendation.criteria.GuestCriteria +import org.craftsrecords.talkadvisor.recommendation.profile.ProfileNotFoundException import org.craftsrecords.talkadvisor.recommendation.spi.Profiles import org.craftsrecords.talkadvisor.recommendation.spi.Recommendations import org.craftsrecords.talkadvisor.recommendation.spi.SearchTalks import org.craftsrecords.talkadvisor.recommendation.talk.Talk +@DomainService class TalksAdvisor(private val searchTalks: SearchTalks, private val recommendations: Recommendations, private val profiles: Profiles) : RecommendTalks { override fun to(userId: String): Recommendation { - val profile = profiles.fetch(userId) + val profile = profiles.fetch(userId) ?: throw ProfileNotFoundException(userId) return recommendTalksSatisfying(profile.preferences) } @@ -24,8 +27,7 @@ class TalksAdvisor(private val searchTalks: SearchTalks, private fun recommendTalksSatisfying(criteria: Criteria): Recommendation { val talks = retrieveTalksSatisfying(criteria) val recommendation = Recommendation(criteria = criteria, talks = talks) - recommendations.save(recommendation) - return recommendation + return recommendations.save(recommendation) } private fun retrieveTalksSatisfying(criteria: Criteria): Set { diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/NoProfileFoundException.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/NoProfileFoundException.kt deleted file mode 100644 index 4b7e1b494f6e743ef29e3078c2d8e98011c5ed58..0000000000000000000000000000000000000000 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/NoProfileFoundException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.craftsrecords.talkadvisor.recommendation.profile - -class NoProfileFoundException(val userId: String) : RuntimeException("No profile found to the user $userId") \ No newline at end of file diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/Profile.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/Profile.kt index 245adcc281fe71ee450ff223c5d361a8c962a97a..8615e5eca53a1ff1f11b0939bb843b631eb09ee7 100644 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/Profile.kt +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/Profile.kt @@ -21,6 +21,4 @@ class Profile(id: String, val preferences: Preferences) { override fun hashCode(): Int { return id.hashCode() } - - } \ No newline at end of file diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileAlreadyExistsException.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileAlreadyExistsException.kt new file mode 100644 index 0000000000000000000000000000000000000000..910cf2f6aec0c429e113331329a25314f98dc82d --- /dev/null +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileAlreadyExistsException.kt @@ -0,0 +1,3 @@ +package org.craftsrecords.talkadvisor.recommendation.profile + +class ProfileAlreadyExistsException(userId: String) : RuntimeException("A profile already exists for the user $userId") \ No newline at end of file diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileCreator.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileCreator.kt index ce6ca01fae5dd1f73325b3cca88fd692eb6bf8aa..c0309cdaf7efbf5f9d7ddcf586f4a76f32e5dcdd 100644 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileCreator.kt +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileCreator.kt @@ -1,13 +1,15 @@ package org.craftsrecords.talkadvisor.recommendation.profile +import org.craftsrecords.hexarch.DomainService import org.craftsrecords.talkadvisor.recommendation.api.CreateProfile import org.craftsrecords.talkadvisor.recommendation.preferences.Preferences import org.craftsrecords.talkadvisor.recommendation.spi.Profiles -class ProfileCreator(val profiles: Profiles) : CreateProfile { +@DomainService +class ProfileCreator(private val profiles: Profiles) : CreateProfile { override fun forUserWithPreferences(userId: String, preferences: Preferences): Profile { val profile = Profile(userId, preferences) - profiles.save(profile) - return profile + profiles.fetch(userId)?.let { throw ProfileAlreadyExistsException(userId) } + return profiles.save(profile) } } \ No newline at end of file diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileNotFoundException.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileNotFoundException.kt new file mode 100644 index 0000000000000000000000000000000000000000..859b99e0079faef5441c24a52d89886252279390 --- /dev/null +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileNotFoundException.kt @@ -0,0 +1,3 @@ +package org.craftsrecords.talkadvisor.recommendation.profile + +class ProfileNotFoundException(val userId: String) : RuntimeException("No profile found for the user $userId") \ No newline at end of file diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/Profiles.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/Profiles.kt index d51d3a3e5dea58684b7f7569ba1e40fffacd51c6..7d87843790f9fd6de333f87168978aed381f1e8f 100644 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/Profiles.kt +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/Profiles.kt @@ -1,9 +1,11 @@ package org.craftsrecords.talkadvisor.recommendation.spi +import org.craftsrecords.hexarch.Repository import org.craftsrecords.talkadvisor.recommendation.profile.Profile +@Repository interface Profiles { - fun save(profile: Profile) + fun save(profile: Profile): Profile - fun fetch(userId: String): Profile + fun fetch(userId: String): Profile? } diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/Recommendations.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/Recommendations.kt index 1e65f20ac5c1f4200d755294b05eedffeeab20f8..ef0958ce03958b778e4d7db4ab5e61b1c18428ae 100644 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/Recommendations.kt +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/Recommendations.kt @@ -1,7 +1,9 @@ package org.craftsrecords.talkadvisor.recommendation.spi +import org.craftsrecords.hexarch.Repository import org.craftsrecords.talkadvisor.recommendation.Recommendation +@Repository interface Recommendations { - fun save(recommendation: Recommendation) + fun save(recommendation: Recommendation): Recommendation } diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/HardCodedTalksSearcher.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/HardCodedTalksSearcher.kt index c7bfb70cdb4e0a1250f2ef6ac11ce04e8ca72bf0..59275cf58faa43a1fec434272dc69fff3a07f0f9 100644 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/HardCodedTalksSearcher.kt +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/HardCodedTalksSearcher.kt @@ -1,11 +1,13 @@ package org.craftsrecords.talkadvisor.recommendation.spi.stubs +import org.craftsrecords.hexarch.Stub import org.craftsrecords.talkadvisor.recommendation.preferences.Topic import org.craftsrecords.talkadvisor.recommendation.spi.SearchTalks import org.craftsrecords.talkadvisor.recommendation.talk.Talk import java.time.Duration import kotlin.random.Random +@Stub class HardCodedTalksSearcher : SearchTalks { override fun forTopics(topics: Set): Set { return createTalks(topics) diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/InMemoryProfiles.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/InMemoryProfiles.kt index dc1b42bd010a96039cab422c3d6bdafc7d31c40d..c2432b4a7a45b3610fd58979f91555b3c8880402 100644 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/InMemoryProfiles.kt +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/InMemoryProfiles.kt @@ -1,15 +1,17 @@ package org.craftsrecords.talkadvisor.recommendation.spi.stubs -import org.craftsrecords.talkadvisor.recommendation.profile.NoProfileFoundException +import org.craftsrecords.hexarch.Stub import org.craftsrecords.talkadvisor.recommendation.profile.Profile import org.craftsrecords.talkadvisor.recommendation.spi.Profiles +@Stub class InMemoryProfiles(private val profiles: MutableMap = HashMap()) : Profiles { - override fun fetch(userId: String): Profile { - return profiles[userId] ?: throw NoProfileFoundException(userId) + override fun fetch(userId: String): Profile? { + return profiles[userId] } - override fun save(profile: Profile) { + override fun save(profile: Profile): Profile { profiles[profile.id] = profile + return profile } } \ No newline at end of file diff --git a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/InMemoryRecommendations.kt b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/InMemoryRecommendations.kt index 33eb9fcaa936c6b22f3ec29b5e388737bee30773..96761f95e9f1d34ef5a11c526035ff688c35feb0 100644 --- a/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/InMemoryRecommendations.kt +++ b/talkadvisor-domain/src/main/kotlin/org/craftsrecords/talkadvisor/recommendation/spi/stubs/InMemoryRecommendations.kt @@ -1,12 +1,15 @@ package org.craftsrecords.talkadvisor.recommendation.spi.stubs +import org.craftsrecords.hexarch.Stub import org.craftsrecords.talkadvisor.recommendation.Recommendation import org.craftsrecords.talkadvisor.recommendation.spi.Recommendations import java.util.* +@Stub class InMemoryRecommendations(private val recommendations: MutableMap = HashMap()) : Recommendations { - override fun save(recommendation: Recommendation) { + override fun save(recommendation: Recommendation): Recommendation { recommendations[recommendation.id] = recommendation + return recommendation } } \ No newline at end of file diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/RandomExtension.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/RandomExtension.kt new file mode 100644 index 0000000000000000000000000000000000000000..427c6cf3a42d3624352ce621dc01d36ad79ff61e --- /dev/null +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/RandomExtension.kt @@ -0,0 +1,6 @@ +package org.craftsrecords.talkadvisor + +import java.nio.charset.Charset +import kotlin.random.Random + +fun Random.nextString() = String(Random.nextBytes(4), Charset.defaultCharset()) \ No newline at end of file diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/RunCucumberTest.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/RecommendationFunctionalTests.kt similarity index 54% rename from talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/RunCucumberTest.kt rename to talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/RecommendationFunctionalTests.kt index e9ca44fea6f048016398be44ff6a8ef2c2688660..9c4df9eaf2f7ae82f1db1500cadc474fd1d8a4df 100644 --- a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/RunCucumberTest.kt +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/RecommendationFunctionalTests.kt @@ -1,9 +1,9 @@ -package org.craftsrecords.talkadvisor +package org.craftsrecords.talkadvisor.recommendation import cucumber.api.CucumberOptions import cucumber.api.junit.Cucumber import org.junit.runner.RunWith @RunWith(Cucumber::class) -@CucumberOptions(strict = true, plugin = ["pretty", "html:target/cucumber"], features = ["classpath:features/"]) -class RunCucumberTest \ No newline at end of file +@CucumberOptions(strict = true, plugin = ["pretty", "html:target/cucumber"], features = ["classpath:features/recommendations.feature"]) +class RecommendationFunctionalTests \ No newline at end of file diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/RecommendationTest.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/RecommendationTest.kt index f9987391a3e406dfa2fc0ded94e0c3e4e7682488..303fddbf8ffb16a639bb28b977dea9640e54e42e 100644 --- a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/RecommendationTest.kt +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/RecommendationTest.kt @@ -1,7 +1,7 @@ package org.craftsrecords.talkadvisor.recommendation import org.assertj.core.api.Assertions.assertThat -import org.craftsrecords.talkadvisor.recommendation.profile.createCriteria +import org.craftsrecords.talkadvisor.recommendation.criteria.createCriteria import org.craftsrecords.talkadvisor.recommendation.talk.createTalk import org.craftsrecords.talkadvisor.recommendation.talk.createTalks import org.junit.jupiter.api.Test diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/assertions/ProfileAssert.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/assertions/ProfileAssert.kt index 028a6fbe865467c727a333f4f874e0baed8ea249..8e1407bdf13be3a25681ef076ff90eefa8873ab5 100644 --- a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/assertions/ProfileAssert.kt +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/assertions/ProfileAssert.kt @@ -8,12 +8,10 @@ class ProfileAssert(actual: Profile) : AbstractAssert( actual, ProfileAssert::class.java ) { - @JvmName("correspondsToUser") infix fun `corresponds to user`(userId: String) { matches({ actual.id == userId }, "profile id corresponds to userId") } - @JvmName("hasPreferences") infix fun `has preferences`(preferences: Preferences) { matches({ actual.preferences == preferences }, "matching expected preferences") } diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/assertions/RecommendationAssert.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/assertions/RecommendationAssert.kt index a1a5b40cf338cdbc783779b9a9f453bafddd69fc..adf0c3ba7d3e9533d288a7e8f85087cc7c731698 100644 --- a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/assertions/RecommendationAssert.kt +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/assertions/RecommendationAssert.kt @@ -12,12 +12,10 @@ class RecommendationAssert(actual: Recommendation) : AbstractAssert topic.name == topicName } @@ -26,7 +24,6 @@ class RecommendationAssert(actual: Recommendation) : AbstractAssert) { matches({ it.criteria.topics.all { topic -> topics.contains(topic) } @@ -35,7 +32,6 @@ class RecommendationAssert(actual: Recommendation) : AbstractAssert format == talkFormat } @@ -44,12 +40,10 @@ class RecommendationAssert(actual: Recommendation) : AbstractAssert) { actual.talks.those `have their duration in ` range } - @JvmName("hasOnlyTalksInTheFormats") infix fun `has only talks in the formats`(talksFormats: Set) { matches({ it.criteria.talksFormats.all { talkFormat -> talksFormats.contains(talkFormat) } @@ -57,7 +51,6 @@ class RecommendationAssert(actual: Recommendation) : AbstractAssert) : AbstractIterableAssert) { allSatisfy { TalkAssert(it) `is related to a topic in` topics } } - @JvmName("areInTheFormat") infix fun `are in the format`(talkFormat: TalkFormat) { allSatisfy { TalkAssert(it) `is in the format` talkFormat } } - @JvmName("haveTheirFormatIn") infix fun `have their format in`(talksFormats: Set) { allSatisfy { TalkAssert(it) `has its format in` talksFormats } } - @JvmName("haveTheirDurationIn") infix fun `have their duration in `(range: ClosedRange) { allSatisfy { TalkAssert(it) `has its duration in` range @@ -54,28 +48,23 @@ class TalkAssert(actual: Talk) : AbstractAssert( TalkAssert::class.java ) { - @JvmName("isRelatedToTopic") infix fun `is related to topic`(topicName: String) { matches({ it.title.contains(topicName) }, "is related to topic $topicName") } - @JvmName("isInTheFormat") infix fun `is in the format`(talkFormat: TalkFormat) { matches({ it.format == talkFormat }, "correspond explicitly to the format $talkFormat") } - @JvmName("hasItsFormatIn") infix fun `has its format in`(talksFormats: Set) { matches({ talksFormats.any { it == actual.format } }, "has its format in the expected ones") } - @JvmName("hasItsDurationIn") infix fun `has its duration in`(range: ClosedRange) { matches({ it.duration.coerceIn(range) == it.duration }, "duration is in the expected range") } - @JvmName("isRelatedToATopicIn") infix fun `is related to a topic in`(topics: Set) { matches({ topics.any { actual.title.contains(it.name) } }, "is related to a topic in") } diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/CriteriaFactory.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/criteria/CriteriaFactory.kt similarity index 64% rename from talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/CriteriaFactory.kt rename to talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/criteria/CriteriaFactory.kt index 2a616843d7f0cc0710c4467eda12c64cc8634318..58819ec3d1b684e58f39b3bcc93f40b6fc93aec9 100644 --- a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/CriteriaFactory.kt +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/criteria/CriteriaFactory.kt @@ -1,6 +1,6 @@ -package org.craftsrecords.talkadvisor.recommendation.profile +package org.craftsrecords.talkadvisor.recommendation.criteria -import org.craftsrecords.talkadvisor.recommendation.criteria.Criteria +import org.craftsrecords.talkadvisor.nextString import org.craftsrecords.talkadvisor.recommendation.preferences.Preferences import org.craftsrecords.talkadvisor.recommendation.preferences.Topic import org.craftsrecords.talkadvisor.recommendation.talk.TalkFormat @@ -8,7 +8,7 @@ import kotlin.random.Random fun createPreferences() = Preferences( - setOf(Topic(Random.nextInt().toString()), Topic(Random.nextInt().toString())), + setOf(Topic(Random.nextString()), Topic(Random.nextString())), setOf(TalkFormat.CONFERENCE, TalkFormat.QUICKIE)) fun createCriteria(): Criteria = createPreferences() diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileFactory.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileFactory.kt new file mode 100644 index 0000000000000000000000000000000000000000..e6c5a3c8fe7c6534638bca849d008e9fc7c3d868 --- /dev/null +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileFactory.kt @@ -0,0 +1,7 @@ +package org.craftsrecords.talkadvisor.recommendation.profile + +import org.craftsrecords.talkadvisor.nextString +import org.craftsrecords.talkadvisor.recommendation.criteria.createPreferences +import kotlin.random.Random + +fun createProfile() = Profile(Random.nextString(), createPreferences()) \ No newline at end of file diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileFunctionalTests.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileFunctionalTests.kt new file mode 100644 index 0000000000000000000000000000000000000000..d3543dea465036775090c28368bb8300eed3e894 --- /dev/null +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileFunctionalTests.kt @@ -0,0 +1,13 @@ +package org.craftsrecords.talkadvisor.recommendation.profile + +import cucumber.api.CucumberOptions +import cucumber.api.junit.Cucumber +import org.junit.runner.RunWith + +@RunWith(Cucumber::class) +@CucumberOptions( + strict = true, + plugin = ["pretty", "html:target/cucumber"], + features = ["classpath:features/profiles.feature"], + glue = ["classpath:org.craftsrecords.talkadvisor.recommendation.stepdefs"]) +class ProfileFunctionalTests \ No newline at end of file diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileTest.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileTest.kt index 02e5fc831bd23ac55f4da993852a2c5e6a7536da..4bbe859ba72155d97b1937f4c1856566e413eff3 100644 --- a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileTest.kt +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/profile/ProfileTest.kt @@ -2,6 +2,7 @@ package org.craftsrecords.talkadvisor.recommendation.profile import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy +import org.craftsrecords.talkadvisor.recommendation.criteria.createPreferences import org.junit.jupiter.api.Test internal class ProfileTest { diff --git a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/stepdefs/ProfileStepdefs.kt b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/stepdefs/ProfileStepdefs.kt index d3fd693a9312aca081699f5558654ce4da926443..47734df73570ff7aff215088804e86ca0631da98 100644 --- a/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/stepdefs/ProfileStepdefs.kt +++ b/talkadvisor-domain/src/test/kotlin/org/craftsrecords/talkadvisor/recommendation/stepdefs/ProfileStepdefs.kt @@ -6,10 +6,11 @@ import cucumber.api.java.en.When import org.assertj.core.api.Assertions.assertThat import org.craftsrecords.talkadvisor.recommendation.api.CreateProfile import org.craftsrecords.talkadvisor.recommendation.assertions.that +import org.craftsrecords.talkadvisor.recommendation.criteria.createPreferences import org.craftsrecords.talkadvisor.recommendation.preferences.Preferences -import org.craftsrecords.talkadvisor.recommendation.profile.NoProfileFoundException import org.craftsrecords.talkadvisor.recommendation.profile.Profile -import org.craftsrecords.talkadvisor.recommendation.profile.createPreferences +import org.craftsrecords.talkadvisor.recommendation.profile.ProfileAlreadyExistsException +import org.craftsrecords.talkadvisor.recommendation.profile.ProfileNotFoundException import org.craftsrecords.talkadvisor.recommendation.spi.Profiles class ProfileStepdefs(private val testContext: TestContext, @@ -26,6 +27,12 @@ class ProfileStepdefs(private val testContext: TestContext, testContext.userId = "noProfileUser" } + @Given("^he already has a profile$") + fun `he already has a profile`() { + val profile = Profile(testContext.userId, createPreferences()) + profiles.save(profile) + } + @Given("^he has stored his preferences in his profile$") fun `he has stored his preferences in his profile`() { val profile = createProfile(testContext.userId) @@ -44,6 +51,15 @@ class ProfileStepdefs(private val testContext: TestContext, testContext.createdProfile = profile } + @When("^he tries to create again his profile$") + fun `he tries to create again his profile`() { + try { + createProfile.forUserWithPreferences(testContext.userId, createPreferences()) + } catch (e: Exception) { + testContext.error = e + } + } + @Then("^his preferences are stored within$") fun `his preferences are stored within`() { val profile = testContext.createdProfile @@ -58,8 +74,16 @@ class ProfileStepdefs(private val testContext: TestContext, fun `he is notified that his profile cannot be found`() { assertThat(testContext.error) .isNotNull() - .isInstanceOf(NoProfileFoundException::class.java) - .hasMessage(String.format("No profile found to the user %s", testContext.userId)) + .isInstanceOf(ProfileNotFoundException::class.java) + .hasMessage(String.format("No profile found for the user %s", testContext.userId)) + } + + @Then("^he is notified that his profile already exists$") + fun `he is notified that his profile already exists`() { + assertThat(testContext.error) + .isNotNull() + .isInstanceOf(ProfileAlreadyExistsException::class.java) + .hasMessage(String.format("A profile already exists for the user %s", testContext.userId)) } private fun createProfile(userId: String): Profile { diff --git a/talkadvisor-domain/src/test/resources/features/profile-creation.feature b/talkadvisor-domain/src/test/resources/features/profiles.feature similarity index 65% rename from talkadvisor-domain/src/test/resources/features/profile-creation.feature rename to talkadvisor-domain/src/test/resources/features/profiles.feature index 5247aaf032cf18c1ea62bacf821e0b4fa595ccc2..918d6d2c73f22c2ecf411665e5e609429ea56581 100644 --- a/talkadvisor-domain/src/test/resources/features/profile-creation.feature +++ b/talkadvisor-domain/src/test/resources/features/profiles.feature @@ -11,3 +11,9 @@ Feature: As a frequent user, | QUICKIE | CONFERENCE | When he creates his profile Then his preferences are stored within + + Scenario: A user is trying to create a profile which already exists + Given a user + And he already has a profile + When he tries to create again his profile + Then he is notified that his profile already exists diff --git a/talkadvisor-infra/pom.xml b/talkadvisor-infra/pom.xml index 1a5195ec53e18e458c59d7f1ddb0d187bccf654e..b0be0f2104cd9b9ef843048ecd463424c0986981 100644 --- a/talkadvisor-infra/pom.xml +++ b/talkadvisor-infra/pom.xml @@ -11,26 +11,120 @@ talkadvisor-infra 2.1.2.RELEASE + 2.0.3.RELEASE + + org.jetbrains.kotlin + kotlin-maven-plugin + + + spring + + + org.springframework.boot spring-boot-maven-plugin 2.1.2.RELEASE + + org.asciidoctor + asciidoctor-maven-plugin + 1.5.3 + + + generate-docs + prepare-package + + process-asciidoc + + + true + html + book + + + + + + org.springframework.restdocs + spring-restdocs-asciidoctor + ${spring-rest-docs.version} + + + + + maven-resources-plugin + + + copy-resources + prepare-package + + copy-resources + + + + ${project.build.outputDirectory}/static/docs + + + + + ${project.build.directory}/generated-docs + + + + + + + + + org.craftsrecords + talkadvisor-domain + ${project.version} + + + com.fasterxml.jackson.module + jackson-module-kotlin + + + org.springframework + spring-web + org.springframework.boot spring-boot-starter + + org.springframework.boot + spring-boot-starter-web + org.springframework.boot spring-boot-starter-test test + + org.springframework.restdocs + spring-restdocs-mockmvc + test + + + org.craftsrecords + talkadvisor-domain + ${project.version} + test + test-jar + + + org.springframework.hateoas + spring-hateoas + 0.25.1.RELEASE + diff --git a/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/TalkAdvisorApplication.kt b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/TalkAdvisorApplication.kt index b9725911d368141560e640b7744342313416a851..34654b1bd513b72667f7d51bc715bf9388056854 100644 --- a/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/TalkAdvisorApplication.kt +++ b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/TalkAdvisorApplication.kt @@ -7,6 +7,6 @@ import org.springframework.boot.runApplication class TalkAdvisorApplication fun main(args: Array) { - runApplication(*args) + runApplication(*args) } diff --git a/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/configurations/DomainConfiguration.kt b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/configurations/DomainConfiguration.kt new file mode 100644 index 0000000000000000000000000000000000000000..95c5155e1728a1f435391b5ab37398867fa03f3a --- /dev/null +++ b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/configurations/DomainConfiguration.kt @@ -0,0 +1,15 @@ +package org.craftsrecords.talkadvisor.configurations + +import org.craftsrecords.hexarch.DomainService +import org.craftsrecords.hexarch.Stub +import org.craftsrecords.talkadvisor.recommendation.Recommendation +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.FilterType + +@Configuration +@ComponentScan( + basePackageClasses = [Recommendation::class], + includeFilters = [ComponentScan.Filter(type = FilterType.ANNOTATION, + value = [DomainService::class, Stub::class])]) +class DomainConfiguration \ No newline at end of file diff --git a/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/controller/ProfileController.kt b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/controller/ProfileController.kt new file mode 100644 index 0000000000000000000000000000000000000000..d34a2608019b68ae6b55fbc9b4944eb8f41d4005 --- /dev/null +++ b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/controller/ProfileController.kt @@ -0,0 +1,35 @@ +package org.craftsrecords.talkadvisor.controller + +import org.craftsrecords.talkadvisor.recommendation.api.CreateProfile +import org.craftsrecords.talkadvisor.recommendation.profile.ProfileAlreadyExistsException +import org.craftsrecords.talkadvisor.resources.Preferences +import org.craftsrecords.talkadvisor.resources.Profile +import org.craftsrecords.talkadvisor.resources.toResource +import org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import javax.servlet.http.HttpServletResponse +import javax.servlet.http.HttpServletResponse.SC_CONFLICT + +@RestController +@RequestMapping(path = ["/profiles"]) +class ProfileController(private val createProfile: CreateProfile) { + + /** + * simulating an authentication context by passing the userId in a header, + * no need to set up all the security frameworks for this demo, but never do that in production !!! + */ + @PostMapping + fun createProfile(@RequestHeader("User-Id") userId: String, @RequestBody preferences: Preferences): ResponseEntity { + val profile = createProfile.forUserWithPreferences(userId, preferences.toDomainObject()).toResource() + val location = linkTo(this::class.java).slash(profile).toUri() + return ResponseEntity.created(location).body(profile) + } + + @ExceptionHandler(ProfileAlreadyExistsException::class) + fun handleProfileAlreadyExistsException(response: HttpServletResponse, exception: ProfileAlreadyExistsException) { + response.sendError(SC_CONFLICT, exception.message) + + } +} + diff --git a/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/resources/Preferences.kt b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/resources/Preferences.kt new file mode 100644 index 0000000000000000000000000000000000000000..1cd7e8bb3439350d063815be65a80d0a1e080eb9 --- /dev/null +++ b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/resources/Preferences.kt @@ -0,0 +1,13 @@ +package org.craftsrecords.talkadvisor.resources + +import org.craftsrecords.talkadvisor.recommendation.preferences.Topic +import org.craftsrecords.talkadvisor.recommendation.talk.TalkFormat +import org.craftsrecords.talkadvisor.recommendation.preferences.Preferences as DomainPreferences + +data class Preferences(val topics: Set, val talksFormats: Set) { + fun toDomainObject(): DomainPreferences { + return DomainPreferences(topics, talksFormats) + } +} + +fun DomainPreferences.toResource() = Preferences(this.topics, this.talksFormats) \ No newline at end of file diff --git a/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/resources/Profile.kt b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/resources/Profile.kt new file mode 100644 index 0000000000000000000000000000000000000000..55f169e138b9adb57bc649428c3fa38b80ab6d8c --- /dev/null +++ b/talkadvisor-infra/src/main/kotlin/org/craftsrecords/talkadvisor/resources/Profile.kt @@ -0,0 +1,12 @@ +package org.craftsrecords.talkadvisor.resources + +import org.springframework.hateoas.Identifiable +import org.craftsrecords.talkadvisor.recommendation.profile.Profile as DomainProfile + +data class Profile(private val id: String, val preferences: Preferences) : Identifiable { + override fun getId(): String { + return id + } +} + +fun DomainProfile.toResource(): Profile = Profile(this.id, this.preferences.toResource()) diff --git a/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/TalkAdvisorApplicationTests.kt b/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/TalkAdvisorApplicationTests.kt index d541a1249106bc134b96840949dbf95f542b34b3..44188bda34bda2a52d6595ec2ad59f0e443c87ca 100644 --- a/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/TalkAdvisorApplicationTests.kt +++ b/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/TalkAdvisorApplicationTests.kt @@ -6,12 +6,11 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit.jupiter.SpringExtension @ExtendWith(SpringExtension::class) -@SpringBootTest +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class TalkAdvisorApplicationTests { @Test fun contextLoads() { } - } diff --git a/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/controller/ProfileControllerIT.kt b/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/controller/ProfileControllerIT.kt new file mode 100644 index 0000000000000000000000000000000000000000..674c871ac1260f514422c05fc9b3b1e7b99e31df --- /dev/null +++ b/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/controller/ProfileControllerIT.kt @@ -0,0 +1,69 @@ +package org.craftsrecords.talkadvisor.controller + +import org.craftsrecords.talkadvisor.configurations.DomainConfiguration +import org.craftsrecords.talkadvisor.recommendation.criteria.createPreferences +import org.craftsrecords.talkadvisor.recommendation.profile.Profile +import org.craftsrecords.talkadvisor.recommendation.spi.Profiles +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.context.annotation.Import +import org.springframework.core.io.Resource +import org.springframework.http.MediaType.APPLICATION_JSON_UTF8 +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.header +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status + + +@ExtendWith(SpringExtension::class) +@WebMvcTest(value = [ProfileController::class]) +@Import(DomainConfiguration::class) +internal class ProfileControllerIT { + + @Autowired + private lateinit var mvc: MockMvc + + @Autowired + private lateinit var profiles: Profiles + + @Value("classpath:payloads/create-profile-request.json") + private lateinit var createProfileRequest: Resource + + private val profilesUrl = "profiles" + + @Test + fun `should create a profile`() { + val requestContent = createProfileRequest.file.readBytes() + + val userId = "myself" + this.mvc.perform( + post("/$profilesUrl") + .accept(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON_UTF8) + .header("User-Id", userId) + .content(requestContent)) + .andExpect(status().isCreated) + .andExpect(header().string("Location", "http://localhost/$profilesUrl/$userId")) + } + + @Test + fun `should notifies that the profile already exists`() { + val requestContent = createProfileRequest.file.readBytes() + val userId = "profileExist" + + profiles.save(Profile(userId, createPreferences())) + + this.mvc.perform( + post("/$profilesUrl") + .accept(APPLICATION_JSON_UTF8) + .contentType(APPLICATION_JSON_UTF8) + .header("User-Id", userId) + .content(requestContent)) + .andExpect(status().isConflict) + .andExpect(status().reason("A profile already exists for the user $userId")) + } +} \ No newline at end of file diff --git a/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/resources/PreferencesTest.kt b/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/resources/PreferencesTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..1ac1bd43c50c7763942e935a6bd4511b06b1e1a0 --- /dev/null +++ b/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/resources/PreferencesTest.kt @@ -0,0 +1,33 @@ +package org.craftsrecords.talkadvisor.resources + +import org.assertj.core.api.Assertions.assertThat +import org.craftsrecords.talkadvisor.recommendation.criteria.createPreferences +import org.craftsrecords.talkadvisor.recommendation.preferences.Topic +import org.craftsrecords.talkadvisor.recommendation.talk.TalkFormat.CONFERENCE +import org.junit.jupiter.api.Test +import org.craftsrecords.talkadvisor.recommendation.preferences.Preferences as DomainPreferences + +internal class PreferencesTest { + + @Test + fun `should convert to domain preferences`() { + val topics = setOf(Topic("topic")) + val talksFormats = setOf(CONFERENCE) + val preferences = Preferences(topics, talksFormats) + + val domainPreferences: DomainPreferences = preferences.toDomainObject() + + assertThat(domainPreferences.topics).isEqualTo(topics) + assertThat(domainPreferences.talksFormats).isEqualTo(talksFormats) + } + + @Test + fun `should convert domain preferences to resource`() { + val domainPreferences = createPreferences() + + val preferences = domainPreferences.toResource() + + assertThat(preferences.topics).isEqualTo(domainPreferences.topics) + assertThat(preferences.talksFormats).isEqualTo(domainPreferences.talksFormats) + } +} \ No newline at end of file diff --git a/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/resources/ProfileTest.kt b/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/resources/ProfileTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..07dd70d365ebceced9b0bfb016effa986bc3700b --- /dev/null +++ b/talkadvisor-infra/src/test/kotlin/org/craftsrecords/talkadvisor/resources/ProfileTest.kt @@ -0,0 +1,19 @@ +package org.craftsrecords.talkadvisor.resources + +import org.assertj.core.api.Assertions.assertThat +import org.craftsrecords.talkadvisor.recommendation.profile.createProfile +import org.junit.jupiter.api.Test +import org.craftsrecords.talkadvisor.recommendation.profile.Profile as DomainProfile + +internal class ProfileTest { + + @Test + fun `should convert domain profile to resource`() { + val domainProfile = createProfile() + + val profile = domainProfile.toResource() + + assertThat(profile.id).isEqualTo(domainProfile.id) + assertThat(profile.preferences).isEqualTo(domainProfile.preferences.toResource()) + } +} \ No newline at end of file diff --git a/talkadvisor-infra/src/test/resources/payloads/create-profile-request.json b/talkadvisor-infra/src/test/resources/payloads/create-profile-request.json new file mode 100644 index 0000000000000000000000000000000000000000..b7a42863c277c5696bffca5375390da56180a66b --- /dev/null +++ b/talkadvisor-infra/src/test/resources/payloads/create-profile-request.json @@ -0,0 +1,14 @@ +{ + "topics": [ + { + "name": "DDD" + }, + { + "name": "Hexagonal Architecture" + } + ], + "talksFormats": [ + "CONFERENCE", + "QUICKIE" + ] +}