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"
+ ]
+}