From fe30edd381eed34e3196671c2f59a99812795a67 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Mon, 4 Jun 2018 23:15:31 +0200 Subject: [PATCH 01/11] start exam implementation: with the notate method, driven by test --- build.gradle | 4 ++- {business-rules => interactors}/build.gradle | 0 .../results/repository/NotFoundException.kt | 3 ++ interactors/src/main/kotlin/entities/Exam.kt | 3 ++ .../kotlin/interactors/ExamsInteractor.kt | 17 +++++++++ .../main/kotlin/repository/ExamsRepository.kt | 9 +++++ interactors/src/main/kotlin/services/Exams.kt | 10 ++++++ .../kotlin/services/requests/NotateExam.kt | 5 +++ .../kotlin/interactors/ExamsInteractorTest.kt | 36 +++++++++++++++++++ persistence/build.gradle | 2 +- settings.gradle | 2 +- 11 files changed, 88 insertions(+), 3 deletions(-) rename {business-rules => interactors}/build.gradle (100%) create mode 100644 interactors/src/main/kotlin/com/students/results/repository/NotFoundException.kt create mode 100644 interactors/src/main/kotlin/entities/Exam.kt create mode 100644 interactors/src/main/kotlin/interactors/ExamsInteractor.kt create mode 100644 interactors/src/main/kotlin/repository/ExamsRepository.kt create mode 100644 interactors/src/main/kotlin/services/Exams.kt create mode 100644 interactors/src/main/kotlin/services/requests/NotateExam.kt create mode 100644 interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt diff --git a/build.gradle b/build.gradle index b63f091..57a6ba7 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,9 @@ subprojects { dependencies { compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8") compile("org.jetbrains.kotlin:kotlin-reflect") - testCompile('org.jetbrains.spek:spek-api:1.1.5') { + compile group: 'io.arrow-kt', name: 'arrow-core', version: '0.7.2' + testCompile('org.jetbrains.spek:spek-api:1.1.5') + { exclude group: 'org.jetbrains.kotlin' } testRuntime('org.jetbrains.spek:spek-junit-platform-engine:1.1.5') { diff --git a/business-rules/build.gradle b/interactors/build.gradle similarity index 100% rename from business-rules/build.gradle rename to interactors/build.gradle diff --git a/interactors/src/main/kotlin/com/students/results/repository/NotFoundException.kt b/interactors/src/main/kotlin/com/students/results/repository/NotFoundException.kt new file mode 100644 index 0000000..68a8442 --- /dev/null +++ b/interactors/src/main/kotlin/com/students/results/repository/NotFoundException.kt @@ -0,0 +1,3 @@ +package com.students.results.repository + +class NotFoundException(message: String) : RuntimeException(message) diff --git a/interactors/src/main/kotlin/entities/Exam.kt b/interactors/src/main/kotlin/entities/Exam.kt new file mode 100644 index 0000000..dbedc6f --- /dev/null +++ b/interactors/src/main/kotlin/entities/Exam.kt @@ -0,0 +1,3 @@ +package com.students.results.entities + +data class Exam(val id: Long) diff --git a/interactors/src/main/kotlin/interactors/ExamsInteractor.kt b/interactors/src/main/kotlin/interactors/ExamsInteractor.kt new file mode 100644 index 0000000..4e5a1b5 --- /dev/null +++ b/interactors/src/main/kotlin/interactors/ExamsInteractor.kt @@ -0,0 +1,17 @@ +package com.students.results.interactors + +import arrow.core.Either +import com.students.results.repository.ExamsRepository +import com.students.results.services.requests.NotateExam +import services.Exams +import services.NotateExamException + +class ExamsInteractor(private val examsRepository: ExamsRepository) : Exams { + override fun notate(notation: NotateExam): Either = + examsRepository.findExamById(notation.examId).bimap({ + NotateExamException(throwable = it) + }, { + Unit + }) + +} diff --git a/interactors/src/main/kotlin/repository/ExamsRepository.kt b/interactors/src/main/kotlin/repository/ExamsRepository.kt new file mode 100644 index 0000000..774d5d9 --- /dev/null +++ b/interactors/src/main/kotlin/repository/ExamsRepository.kt @@ -0,0 +1,9 @@ +package com.students.results.repository + +import arrow.core.Either +import com.students.results.entities.Exam + +interface ExamsRepository { + + fun findExamById(examId: Long): Either +} \ No newline at end of file diff --git a/interactors/src/main/kotlin/services/Exams.kt b/interactors/src/main/kotlin/services/Exams.kt new file mode 100644 index 0000000..0ae9318 --- /dev/null +++ b/interactors/src/main/kotlin/services/Exams.kt @@ -0,0 +1,10 @@ +package services + +import arrow.core.Either +import com.students.results.services.requests.NotateExam + +interface Exams { + fun notate(notation: NotateExam): Either +} + +class NotateExamException(message: String? = null, throwable: Throwable? = null) : RuntimeException(message, throwable) diff --git a/interactors/src/main/kotlin/services/requests/NotateExam.kt b/interactors/src/main/kotlin/services/requests/NotateExam.kt new file mode 100644 index 0000000..b3a0f5a --- /dev/null +++ b/interactors/src/main/kotlin/services/requests/NotateExam.kt @@ -0,0 +1,5 @@ +package com.students.results.services.requests + +import java.math.BigDecimal + +data class NotateExam(val examId: Long, val studentId: Long, val note: BigDecimal) diff --git a/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt b/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt new file mode 100644 index 0000000..3fb00d3 --- /dev/null +++ b/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt @@ -0,0 +1,36 @@ +package com.students.results.interactors + +import arrow.core.Either +import com.students.results.entities.Exam +import com.students.results.repository.ExamsRepository +import com.students.results.services.requests.NotateExam +import io.mockk.every +import io.mockk.verify +import org.amshove.kluent.mock +import org.amshove.kluent.shouldBe +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.given +import org.jetbrains.spek.api.dsl.it +import org.mockito.ArgumentMatchers.anyLong + +class ExamsInteractorTest : Spek({ + + val examsRepository = mock() + given("an exam interactor") { + val examsInteractor = ExamsInteractor(examsRepository) + it("should notate an exam, done by a student, with a note of 18") { + examsInteractor.notate20().isRight() shouldBe true + } + it("should locate the exam from the exam repository") { + every { examsRepository.findExamById(anyLong()) } returns Either.right(Exam(5L)) + examsInteractor.notate20() + verify { examsRepository.findExamById(5) } + } + } +}) + +private fun ExamsInteractor.notate20() = notate(NotateExam( + examId = 5, + studentId = 1, + note = "20".toBigDecimal() +)) \ No newline at end of file diff --git a/persistence/build.gradle b/persistence/build.gradle index b17bc95..8a7df8b 100644 --- a/persistence/build.gradle +++ b/persistence/build.gradle @@ -2,6 +2,6 @@ apply plugin: 'kotlin-spring' dependencies { - compile project(':business-rules') + compile project(':interactors') compile group: 'org.springframework.data', name: 'spring-data-redis', version: '2.0.7.RELEASE' } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index fde941e..b28791b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,4 @@ rootProject.name = 'students-results' -include 'business-rules', 'main', 'persistence' +include 'interactors', 'main', 'persistence' From b284f4421d4cc39194083f7c26e3c9ad5e4a0626 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Tue, 5 Jun 2018 08:03:14 +0200 Subject: [PATCH 02/11] Upadte source to fix units test failure --- .../src/main/kotlin/interactors/ExamsInteractor.kt | 14 +++++++------- interactors/src/main/kotlin/services/Exams.kt | 2 +- .../test/kotlin/interactors/ExamsInteractorTest.kt | 9 +++++---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/interactors/src/main/kotlin/interactors/ExamsInteractor.kt b/interactors/src/main/kotlin/interactors/ExamsInteractor.kt index 4e5a1b5..d67d9eb 100644 --- a/interactors/src/main/kotlin/interactors/ExamsInteractor.kt +++ b/interactors/src/main/kotlin/interactors/ExamsInteractor.kt @@ -7,11 +7,11 @@ import services.Exams import services.NotateExamException class ExamsInteractor(private val examsRepository: ExamsRepository) : Exams { - override fun notate(notation: NotateExam): Either = - examsRepository.findExamById(notation.examId).bimap({ - NotateExamException(throwable = it) - }, { - Unit - }) - + override fun notate(notation: NotateExam): Either = + examsRepository.findExamById(notation.examId).bimap({ + NotateExamException(throwable = it) + }, { + println("$it") + Unit + }) } diff --git a/interactors/src/main/kotlin/services/Exams.kt b/interactors/src/main/kotlin/services/Exams.kt index 0ae9318..d4fff36 100644 --- a/interactors/src/main/kotlin/services/Exams.kt +++ b/interactors/src/main/kotlin/services/Exams.kt @@ -4,7 +4,7 @@ import arrow.core.Either import com.students.results.services.requests.NotateExam interface Exams { - fun notate(notation: NotateExam): Either + fun notate(notation: NotateExam): Either } class NotateExamException(message: String? = null, throwable: Throwable? = null) : RuntimeException(message, throwable) diff --git a/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt b/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt index 3fb00d3..9f8f7ca 100644 --- a/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt +++ b/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt @@ -5,24 +5,25 @@ import com.students.results.entities.Exam import com.students.results.repository.ExamsRepository import com.students.results.services.requests.NotateExam import io.mockk.every +import io.mockk.mockk import io.mockk.verify -import org.amshove.kluent.mock import org.amshove.kluent.shouldBe import org.jetbrains.spek.api.Spek import org.jetbrains.spek.api.dsl.given import org.jetbrains.spek.api.dsl.it -import org.mockito.ArgumentMatchers.anyLong class ExamsInteractorTest : Spek({ - val examsRepository = mock() + val examsRepository = mockk().apply { + every { findExamById(any()) } returns Either.right(Exam(5L)) + } + given("an exam interactor") { val examsInteractor = ExamsInteractor(examsRepository) it("should notate an exam, done by a student, with a note of 18") { examsInteractor.notate20().isRight() shouldBe true } it("should locate the exam from the exam repository") { - every { examsRepository.findExamById(anyLong()) } returns Either.right(Exam(5L)) examsInteractor.notate20() verify { examsRepository.findExamById(5) } } From a0589aa47f169fbfdc59bbfb92e0b1515c5b9c35 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Tue, 5 Jun 2018 20:08:13 +0200 Subject: [PATCH 03/11] improve current model: students should be the entry point for the notation, not the exam. Start the refactoring --- .../src/main/kotlin/entities/Student.kt | 3 ++ .../kotlin/interactors/ExamsInteractor.kt | 4 +- .../kotlin/interactors/StudentsInteractor.kt | 17 ++++++++ .../repository/NotFoundException.kt | 0 .../kotlin/repository/StudentsRepository.kt | 10 +++++ interactors/src/main/kotlin/services/Exams.kt | 2 +- .../src/main/kotlin/services/Students.kt | 10 +++++ .../kotlin/interactors/ExamsInteractorTest.kt | 3 ++ .../interactors/StudentsInteractorTest.kt | 40 +++++++++++++++++++ 9 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 interactors/src/main/kotlin/entities/Student.kt create mode 100644 interactors/src/main/kotlin/interactors/StudentsInteractor.kt rename interactors/src/main/kotlin/{com/students/results => }/repository/NotFoundException.kt (100%) create mode 100644 interactors/src/main/kotlin/repository/StudentsRepository.kt create mode 100644 interactors/src/main/kotlin/services/Students.kt create mode 100644 interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt diff --git a/interactors/src/main/kotlin/entities/Student.kt b/interactors/src/main/kotlin/entities/Student.kt new file mode 100644 index 0000000..1f495a5 --- /dev/null +++ b/interactors/src/main/kotlin/entities/Student.kt @@ -0,0 +1,3 @@ +package entities + +data class Student(val id: Long) \ No newline at end of file diff --git a/interactors/src/main/kotlin/interactors/ExamsInteractor.kt b/interactors/src/main/kotlin/interactors/ExamsInteractor.kt index d67d9eb..04527ee 100644 --- a/interactors/src/main/kotlin/interactors/ExamsInteractor.kt +++ b/interactors/src/main/kotlin/interactors/ExamsInteractor.kt @@ -2,9 +2,9 @@ package com.students.results.interactors import arrow.core.Either import com.students.results.repository.ExamsRepository +import com.students.results.services.Exams +import com.students.results.services.NotateExamException import com.students.results.services.requests.NotateExam -import services.Exams -import services.NotateExamException class ExamsInteractor(private val examsRepository: ExamsRepository) : Exams { override fun notate(notation: NotateExam): Either = diff --git a/interactors/src/main/kotlin/interactors/StudentsInteractor.kt b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt new file mode 100644 index 0000000..f5365be --- /dev/null +++ b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt @@ -0,0 +1,17 @@ +package com.students.results.interactors + +import arrow.core.Either +import com.students.results.services.NotateExamException +import com.students.results.services.Students +import com.students.results.services.requests.NotateExam +import repository.StudentsRepository + +class StudentsInteractor(private val studentsRepository: StudentsRepository) : Students { + override fun notate(notateExam: NotateExam): Either = + studentsRepository.findStudentById(1).bimap({ + NotateExamException(throwable = it) + }, { + Unit + }) + +} diff --git a/interactors/src/main/kotlin/com/students/results/repository/NotFoundException.kt b/interactors/src/main/kotlin/repository/NotFoundException.kt similarity index 100% rename from interactors/src/main/kotlin/com/students/results/repository/NotFoundException.kt rename to interactors/src/main/kotlin/repository/NotFoundException.kt diff --git a/interactors/src/main/kotlin/repository/StudentsRepository.kt b/interactors/src/main/kotlin/repository/StudentsRepository.kt new file mode 100644 index 0000000..52fe53e --- /dev/null +++ b/interactors/src/main/kotlin/repository/StudentsRepository.kt @@ -0,0 +1,10 @@ +package repository + +import arrow.core.Either +import com.students.results.repository.NotFoundException +import entities.Student + +interface StudentsRepository { + + fun findStudentById(id: Long): Either +} \ No newline at end of file diff --git a/interactors/src/main/kotlin/services/Exams.kt b/interactors/src/main/kotlin/services/Exams.kt index d4fff36..091566f 100644 --- a/interactors/src/main/kotlin/services/Exams.kt +++ b/interactors/src/main/kotlin/services/Exams.kt @@ -1,4 +1,4 @@ -package services +package com.students.results.services import arrow.core.Either import com.students.results.services.requests.NotateExam diff --git a/interactors/src/main/kotlin/services/Students.kt b/interactors/src/main/kotlin/services/Students.kt new file mode 100644 index 0000000..b464384 --- /dev/null +++ b/interactors/src/main/kotlin/services/Students.kt @@ -0,0 +1,10 @@ +package com.students.results.services + +import arrow.core.Either +import com.students.results.services.requests.NotateExam + +interface Students { + + fun notate(notateExam: NotateExam): Either + +} diff --git a/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt b/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt index 9f8f7ca..04b228f 100644 --- a/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt +++ b/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt @@ -3,6 +3,7 @@ package com.students.results.interactors import arrow.core.Either import com.students.results.entities.Exam import com.students.results.repository.ExamsRepository +import com.students.results.services.Students import com.students.results.services.requests.NotateExam import io.mockk.every import io.mockk.mockk @@ -17,6 +18,8 @@ class ExamsInteractorTest : Spek({ val examsRepository = mockk().apply { every { findExamById(any()) } returns Either.right(Exam(5L)) } + val students = mockk().apply { + } given("an exam interactor") { val examsInteractor = ExamsInteractor(examsRepository) diff --git a/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt new file mode 100644 index 0000000..e3711e5 --- /dev/null +++ b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt @@ -0,0 +1,40 @@ +package com.students.results.interactors + +import arrow.core.Either +import com.students.results.services.requests.NotateExam +import entities.Student +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.amshove.kluent.`should be instance of` +import org.amshove.kluent.`should be` +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.given +import org.jetbrains.spek.api.dsl.it +import repository.StudentsRepository + + +class StudentsInteractorTest : Spek({ + + given("a student interactor") { + + val studentRepository = mockk() { + every { findStudentById(any()) } returns Either.right(Student(id = 10L)) + } + val studentsInteractor = StudentsInteractor(studentRepository) + it("should notate an existing exam with a note of 20") { + studentsInteractor.notate20().isRight() `should be` true + } + it("should retrieve student by his id") { + studentsInteractor.notate20() + verify { studentRepository.findStudentById(1) } + } + } +}) + + +private fun StudentsInteractor.notate20() = notate(NotateExam( + examId = 5, + studentId = 1, + note = "20".toBigDecimal() +)) \ No newline at end of file From 7797654a7e1d08d19271ddb61bbbbe4ecc80c652 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Tue, 5 Jun 2018 23:26:52 +0200 Subject: [PATCH 04/11] finish the notate interactor business implementation --- interactors/src/main/kotlin/entities/Exam.kt | 13 ++++++- .../src/main/kotlin/entities/Student.kt | 24 +++++++++++-- .../kotlin/interactors/ExamsInteractor.kt | 13 +------ .../kotlin/interactors/StudentsInteractor.kt | 17 +++++---- .../kotlin/repository/NotFoundException.kt | 3 -- .../main/kotlin/repository/Repositories.kt | 8 +++++ .../kotlin/repository/StudentsRepository.kt | 7 ++-- interactors/src/main/kotlin/services/Exams.kt | 3 +- .../src/main/kotlin/services/Services.kt | 5 +++ .../src/test/kotlin/entities/StudentTest.kt | 36 +++++++++++++++++++ .../kotlin/interactors/ExamsInteractorTest.kt | 33 ----------------- .../interactors/StudentsInteractorTest.kt | 35 ++++++++++++------ 12 files changed, 127 insertions(+), 70 deletions(-) delete mode 100644 interactors/src/main/kotlin/repository/NotFoundException.kt create mode 100644 interactors/src/main/kotlin/repository/Repositories.kt create mode 100644 interactors/src/main/kotlin/services/Services.kt create mode 100644 interactors/src/test/kotlin/entities/StudentTest.kt diff --git a/interactors/src/main/kotlin/entities/Exam.kt b/interactors/src/main/kotlin/entities/Exam.kt index dbedc6f..bd1669b 100644 --- a/interactors/src/main/kotlin/entities/Exam.kt +++ b/interactors/src/main/kotlin/entities/Exam.kt @@ -1,3 +1,14 @@ package com.students.results.entities -data class Exam(val id: Long) +import arrow.core.Either +import java.math.BigDecimal + +data class Exam(val id: Long) { + fun validateNotation(notation: BigDecimal): Either = + when (notation) { + in (0.toBigDecimal()..20.toBigDecimal()) -> Either.right(Unit) + else -> Either.left(InvalidNotationForThisExamException("This notation, $notation, is not in bound")) + } +} + +class InvalidNotationForThisExamException(msg: String?) : RuntimeException(msg) diff --git a/interactors/src/main/kotlin/entities/Student.kt b/interactors/src/main/kotlin/entities/Student.kt index 1f495a5..4af14a5 100644 --- a/interactors/src/main/kotlin/entities/Student.kt +++ b/interactors/src/main/kotlin/entities/Student.kt @@ -1,3 +1,23 @@ -package entities +package com.students.results.entities -data class Student(val id: Long) \ No newline at end of file +import arrow.core.Either +import arrow.core.right +import java.math.BigDecimal + +typealias Notes = Map + +data class Student(val id: Long, val notes: Notes = emptyMap()) { + fun getNotation(exam: Exam): Either = + when { + notes.containsKey(exam) -> Either.right(notes.getValue(exam)) + else -> Either.left(NotEvaluatedException()) + } + + fun notate(exam: Exam, note: BigDecimal): Either = + exam.validateNotation(note).map { + copy(id = id, + notes = notes + mapOf(exam to note)) + } +} + +class NotEvaluatedException(msg: String? = null, throwable: Throwable? = null) : RuntimeException(msg, throwable) \ No newline at end of file diff --git a/interactors/src/main/kotlin/interactors/ExamsInteractor.kt b/interactors/src/main/kotlin/interactors/ExamsInteractor.kt index 04527ee..575e80d 100644 --- a/interactors/src/main/kotlin/interactors/ExamsInteractor.kt +++ b/interactors/src/main/kotlin/interactors/ExamsInteractor.kt @@ -1,17 +1,6 @@ package com.students.results.interactors -import arrow.core.Either import com.students.results.repository.ExamsRepository import com.students.results.services.Exams -import com.students.results.services.NotateExamException -import com.students.results.services.requests.NotateExam -class ExamsInteractor(private val examsRepository: ExamsRepository) : Exams { - override fun notate(notation: NotateExam): Either = - examsRepository.findExamById(notation.examId).bimap({ - NotateExamException(throwable = it) - }, { - println("$it") - Unit - }) -} +class ExamsInteractor(private val examsRepository: ExamsRepository) : Exams diff --git a/interactors/src/main/kotlin/interactors/StudentsInteractor.kt b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt index f5365be..cecaffa 100644 --- a/interactors/src/main/kotlin/interactors/StudentsInteractor.kt +++ b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt @@ -1,17 +1,22 @@ package com.students.results.interactors import arrow.core.Either +import arrow.core.flatMap +import com.students.results.repository.ExamsRepository import com.students.results.services.NotateExamException import com.students.results.services.Students import com.students.results.services.requests.NotateExam import repository.StudentsRepository -class StudentsInteractor(private val studentsRepository: StudentsRepository) : Students { +class StudentsInteractor(private val studentsRepository: StudentsRepository, private val examsRepository: ExamsRepository) : Students { + override fun notate(notateExam: NotateExam): Either = - studentsRepository.findStudentById(1).bimap({ - NotateExamException(throwable = it) - }, { - Unit - }) + studentsRepository.findStudentById(studentId = 1).flatMap { student -> + examsRepository.findExamById(examId = notateExam.examId).flatMap { exam -> + student.notate(exam, notateExam.note).flatMap { updatedStudent -> + studentsRepository.save(student) + } + } + }.mapLeft { NotateExamException(throwable = it) } } diff --git a/interactors/src/main/kotlin/repository/NotFoundException.kt b/interactors/src/main/kotlin/repository/NotFoundException.kt deleted file mode 100644 index 68a8442..0000000 --- a/interactors/src/main/kotlin/repository/NotFoundException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.students.results.repository - -class NotFoundException(message: String) : RuntimeException(message) diff --git a/interactors/src/main/kotlin/repository/Repositories.kt b/interactors/src/main/kotlin/repository/Repositories.kt new file mode 100644 index 0000000..8c04654 --- /dev/null +++ b/interactors/src/main/kotlin/repository/Repositories.kt @@ -0,0 +1,8 @@ +package com.students.results.repository + + +sealed class RepositoryException(msg: String? = null, throwable: Throwable? = null) : RuntimeException(msg, throwable) + +class NotFoundException(msg: String? = null, throwable: Throwable? = null) : RepositoryException(msg, throwable) +class NotWrittenException(msg: String? = null, throwable: Throwable? = null) : RepositoryException(msg, throwable) +class RepositoryNotAvailableException(msg: String? = null, throwable: Throwable? = null) : RepositoryException(msg, throwable) \ No newline at end of file diff --git a/interactors/src/main/kotlin/repository/StudentsRepository.kt b/interactors/src/main/kotlin/repository/StudentsRepository.kt index 52fe53e..c0a8921 100644 --- a/interactors/src/main/kotlin/repository/StudentsRepository.kt +++ b/interactors/src/main/kotlin/repository/StudentsRepository.kt @@ -1,10 +1,13 @@ package repository import arrow.core.Either +import com.students.results.entities.Student import com.students.results.repository.NotFoundException -import entities.Student +import com.students.results.repository.NotWrittenException +import com.students.results.repository.RepositoryException interface StudentsRepository { - fun findStudentById(id: Long): Either + fun findStudentById(studentId: Long): Either + fun save(student: Student): Either } \ No newline at end of file diff --git a/interactors/src/main/kotlin/services/Exams.kt b/interactors/src/main/kotlin/services/Exams.kt index 091566f..466c35d 100644 --- a/interactors/src/main/kotlin/services/Exams.kt +++ b/interactors/src/main/kotlin/services/Exams.kt @@ -1,10 +1,11 @@ package com.students.results.services import arrow.core.Either +import com.students.results.entities.Exam import com.students.results.services.requests.NotateExam +import services.NotFoundException interface Exams { - fun notate(notation: NotateExam): Either } class NotateExamException(message: String? = null, throwable: Throwable? = null) : RuntimeException(message, throwable) diff --git a/interactors/src/main/kotlin/services/Services.kt b/interactors/src/main/kotlin/services/Services.kt new file mode 100644 index 0000000..5c22547 --- /dev/null +++ b/interactors/src/main/kotlin/services/Services.kt @@ -0,0 +1,5 @@ +package services + +sealed class ServicesException(msg: String? = null, throwable: Throwable? = null) : RuntimeException(msg, throwable) + +class NotFoundException(msg: String? = null, throwable: Throwable? = null) : ServicesException(msg, throwable) \ No newline at end of file diff --git a/interactors/src/test/kotlin/entities/StudentTest.kt b/interactors/src/test/kotlin/entities/StudentTest.kt new file mode 100644 index 0000000..69e0f0e --- /dev/null +++ b/interactors/src/test/kotlin/entities/StudentTest.kt @@ -0,0 +1,36 @@ +package entities + +import com.students.results.entities.Exam +import com.students.results.entities.Student +import org.amshove.kluent.`should be instance of` +import org.amshove.kluent.shouldBe +import org.amshove.kluent.shouldEqual +import org.jetbrains.spek.api.Spek +import org.jetbrains.spek.api.dsl.given +import org.jetbrains.spek.api.dsl.it + +class StudentTest : Spek({ + + given("a student") { + val student = Student(id = 40L) + val exam = Exam(id = 50L) + + it("getNot without note should returns NotEvaluatedException") { + student.getNotation(exam).isLeft() shouldBe true + } + it("notate an exam with 20 and get notation should return 20") { + student.notate(exam, "20".toBigDecimal()).apply { + isRight() shouldBe true + map { + it.getNotation(exam).apply { + isRight() shouldBe true + map { it shouldEqual "20".toBigDecimal() } + } + } + } + } + it("notate less than zero should fail to register note") { + student.notate(exam, "-1".toBigDecimal()).isLeft() shouldBe true + } + } +}) \ No newline at end of file diff --git a/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt b/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt index 04b228f..07b0b2d 100644 --- a/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt +++ b/interactors/src/test/kotlin/interactors/ExamsInteractorTest.kt @@ -1,40 +1,7 @@ package com.students.results.interactors -import arrow.core.Either -import com.students.results.entities.Exam -import com.students.results.repository.ExamsRepository -import com.students.results.services.Students -import com.students.results.services.requests.NotateExam -import io.mockk.every -import io.mockk.mockk -import io.mockk.verify -import org.amshove.kluent.shouldBe import org.jetbrains.spek.api.Spek -import org.jetbrains.spek.api.dsl.given -import org.jetbrains.spek.api.dsl.it class ExamsInteractorTest : Spek({ - val examsRepository = mockk().apply { - every { findExamById(any()) } returns Either.right(Exam(5L)) - } - val students = mockk().apply { - } - - given("an exam interactor") { - val examsInteractor = ExamsInteractor(examsRepository) - it("should notate an exam, done by a student, with a note of 18") { - examsInteractor.notate20().isRight() shouldBe true - } - it("should locate the exam from the exam repository") { - examsInteractor.notate20() - verify { examsRepository.findExamById(5) } - } - } }) - -private fun ExamsInteractor.notate20() = notate(NotateExam( - examId = 5, - studentId = 1, - note = "20".toBigDecimal() -)) \ No newline at end of file diff --git a/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt index e3711e5..a59adb5 100644 --- a/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt +++ b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt @@ -1,13 +1,16 @@ package com.students.results.interactors import arrow.core.Either +import com.students.results.entities.Exam +import com.students.results.entities.Student +import com.students.results.repository.ExamsRepository import com.students.results.services.requests.NotateExam -import entities.Student import io.mockk.every import io.mockk.mockk import io.mockk.verify -import org.amshove.kluent.`should be instance of` import org.amshove.kluent.`should be` +import org.amshove.kluent.shouldBe +import org.amshove.kluent.shouldEqual import org.jetbrains.spek.api.Spek import org.jetbrains.spek.api.dsl.given import org.jetbrains.spek.api.dsl.it @@ -16,23 +19,35 @@ import repository.StudentsRepository class StudentsInteractorTest : Spek({ + val student = Student(id = 10L) given("a student interactor") { val studentRepository = mockk() { - every { findStudentById(any()) } returns Either.right(Student(id = 10L)) + every { findStudentById(1) } returns Either.right(student) + every { save(student) } returns Either.right(Unit) } - val studentsInteractor = StudentsInteractor(studentRepository) - it("should notate an existing exam with a note of 20") { - studentsInteractor.notate20().isRight() `should be` true + val exam = Exam(id = 5) + val examsRepository = mockk().apply { + every { findExamById(5) } returns Either.right(exam) } - it("should retrieve student by his id") { - studentsInteractor.notate20() - verify { studentRepository.findStudentById(1) } + val studentsInteractor = StudentsInteractor(studentRepository, examsRepository) + studentsInteractor.notate20().apply { + it("should notate an existing exam with a note of 20") { + isRight() `should be` true + } + it("should retrieve student by his id") { + verify { studentRepository.findStudentById(1) } + } + it("should save student to repository") { + verify { studentRepository.save(student) } + } + it("should retrieve exam by id") { + verify { examsRepository.findExamById(5) } + } } } }) - private fun StudentsInteractor.notate20() = notate(NotateExam( examId = 5, studentId = 1, From bf9fbbbe93f0bbb04ee3259613172813f80eb309 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Tue, 5 Jun 2018 23:36:20 +0200 Subject: [PATCH 05/11] Fix an issue with the capture test: it did not control saved student correctly --- .../main/kotlin/interactors/StudentsInteractor.kt | 2 +- .../kotlin/interactors/StudentsInteractorTest.kt | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/interactors/src/main/kotlin/interactors/StudentsInteractor.kt b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt index cecaffa..f7eb234 100644 --- a/interactors/src/main/kotlin/interactors/StudentsInteractor.kt +++ b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt @@ -14,7 +14,7 @@ class StudentsInteractor(private val studentsRepository: StudentsRepository, pri studentsRepository.findStudentById(studentId = 1).flatMap { student -> examsRepository.findExamById(examId = notateExam.examId).flatMap { exam -> student.notate(exam, notateExam.note).flatMap { updatedStudent -> - studentsRepository.save(student) + studentsRepository.save(updatedStudent) } } }.mapLeft { NotateExamException(throwable = it) } diff --git a/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt index a59adb5..305a2c4 100644 --- a/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt +++ b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt @@ -1,12 +1,14 @@ package com.students.results.interactors import arrow.core.Either +import arrow.core.flatMap import com.students.results.entities.Exam import com.students.results.entities.Student import com.students.results.repository.ExamsRepository import com.students.results.services.requests.NotateExam import io.mockk.every import io.mockk.mockk +import io.mockk.slot import io.mockk.verify import org.amshove.kluent.`should be` import org.amshove.kluent.shouldBe @@ -22,9 +24,10 @@ class StudentsInteractorTest : Spek({ val student = Student(id = 10L) given("a student interactor") { + val studentSlot = slot() val studentRepository = mockk() { every { findStudentById(1) } returns Either.right(student) - every { save(student) } returns Either.right(Unit) + every { save(student = capture(studentSlot)) } returns Either.right(Unit) } val exam = Exam(id = 5) val examsRepository = mockk().apply { @@ -38,12 +41,15 @@ class StudentsInteractorTest : Spek({ it("should retrieve student by his id") { verify { studentRepository.findStudentById(1) } } - it("should save student to repository") { - verify { studentRepository.save(student) } - } it("should retrieve exam by id") { verify { examsRepository.findExamById(5) } } + it("should save student to the repository with the expected notation of 20 for this exam") { + studentSlot.captured.getNotation(exam).apply { + isRight() shouldBe true + map { it shouldEqual "20".toBigDecimal() } + } + } } } }) From 364a213a7f6bfe4b8e7a6846414f085959acb2e2 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Wed, 6 Jun 2018 00:04:06 +0200 Subject: [PATCH 06/11] Update gradle version to allow junit 5 test to be runned (4.8) --- build.gradle | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 54413 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- persistence/build.gradle | 13 ++++++++++++- .../embeded/redis/startup/EmbededRedisTest.kt | 2 ++ 5 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt diff --git a/build.gradle b/build.gradle index 57a6ba7..2ee64e1 100644 --- a/build.gradle +++ b/build.gradle @@ -23,6 +23,7 @@ version = '0.0.1-SNAPSHOT' subprojects { apply plugin: 'kotlin' apply plugin: 'org.junit.platform.gradle.plugin' + apply plugin: "org.jetbrains.kotlin.plugin.allopen" junitPlatform { filters { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 01b8bf6b1f99cad9213fc495b33ad5bbab8efd20..1948b9074f1016d15d505d185bc3f73deb82d8c8 100644 GIT binary patch delta 7399 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 Da{n=i delta 7286 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 KPzU?}WBw1fHw(7_ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 933b647..d2c45a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip diff --git a/persistence/build.gradle b/persistence/build.gradle index 8a7df8b..d4eb35a 100644 --- a/persistence/build.gradle +++ b/persistence/build.gradle @@ -1,7 +1,18 @@ - apply plugin: 'kotlin-spring' dependencies { compile project(':interactors') compile group: 'org.springframework.data', name: 'spring-data-redis', version: '2.0.7.RELEASE' + testCompile 'it.ozimov:embedded-redis:0.7.2' + testCompile group: 'org.springframework', name: 'spring-test', version: '5.0.6.RELEASE' + testImplementation( + 'org.junit.jupiter:junit-jupiter-api:5.1.0' + ) + testRuntimeOnly( + 'org.junit.jupiter:junit-jupiter-engine:5.1.0' + ) +} + +test { + useJUnitPlatform() } \ No newline at end of file diff --git a/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt b/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt new file mode 100644 index 0000000..8fd0689 --- /dev/null +++ b/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt @@ -0,0 +1,2 @@ +package embeded.redis.startup + From e4006249ab29e1df95611439a2af2afa03a771e2 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Wed, 6 Jun 2018 07:44:56 +0200 Subject: [PATCH 07/11] import and package clean (official package structure for pure kotlin project is not officilay supported in intellij today, job must be done manually) --- interactors/src/main/kotlin/entities/Student.kt | 1 - interactors/src/main/kotlin/repository/StudentsRepository.kt | 5 +---- interactors/src/main/kotlin/services/Exams.kt | 5 ----- interactors/src/test/kotlin/entities/StudentTest.kt | 1 - .../src/test/kotlin/interactors/StudentsInteractorTest.kt | 3 +-- 5 files changed, 2 insertions(+), 13 deletions(-) diff --git a/interactors/src/main/kotlin/entities/Student.kt b/interactors/src/main/kotlin/entities/Student.kt index 4af14a5..4541d7c 100644 --- a/interactors/src/main/kotlin/entities/Student.kt +++ b/interactors/src/main/kotlin/entities/Student.kt @@ -1,7 +1,6 @@ package com.students.results.entities import arrow.core.Either -import arrow.core.right import java.math.BigDecimal typealias Notes = Map diff --git a/interactors/src/main/kotlin/repository/StudentsRepository.kt b/interactors/src/main/kotlin/repository/StudentsRepository.kt index c0a8921..e2f4f4d 100644 --- a/interactors/src/main/kotlin/repository/StudentsRepository.kt +++ b/interactors/src/main/kotlin/repository/StudentsRepository.kt @@ -1,10 +1,7 @@ -package repository +package com.students.results.repository import arrow.core.Either import com.students.results.entities.Student -import com.students.results.repository.NotFoundException -import com.students.results.repository.NotWrittenException -import com.students.results.repository.RepositoryException interface StudentsRepository { diff --git a/interactors/src/main/kotlin/services/Exams.kt b/interactors/src/main/kotlin/services/Exams.kt index 466c35d..98983f3 100644 --- a/interactors/src/main/kotlin/services/Exams.kt +++ b/interactors/src/main/kotlin/services/Exams.kt @@ -1,10 +1,5 @@ package com.students.results.services -import arrow.core.Either -import com.students.results.entities.Exam -import com.students.results.services.requests.NotateExam -import services.NotFoundException - interface Exams { } diff --git a/interactors/src/test/kotlin/entities/StudentTest.kt b/interactors/src/test/kotlin/entities/StudentTest.kt index 69e0f0e..c1267bb 100644 --- a/interactors/src/test/kotlin/entities/StudentTest.kt +++ b/interactors/src/test/kotlin/entities/StudentTest.kt @@ -2,7 +2,6 @@ package entities import com.students.results.entities.Exam import com.students.results.entities.Student -import org.amshove.kluent.`should be instance of` import org.amshove.kluent.shouldBe import org.amshove.kluent.shouldEqual import org.jetbrains.spek.api.Spek diff --git a/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt index 305a2c4..d216739 100644 --- a/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt +++ b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt @@ -1,10 +1,10 @@ package com.students.results.interactors import arrow.core.Either -import arrow.core.flatMap import com.students.results.entities.Exam import com.students.results.entities.Student import com.students.results.repository.ExamsRepository +import com.students.results.repository.StudentsRepository import com.students.results.services.requests.NotateExam import io.mockk.every import io.mockk.mockk @@ -16,7 +16,6 @@ import org.amshove.kluent.shouldEqual import org.jetbrains.spek.api.Spek import org.jetbrains.spek.api.dsl.given import org.jetbrains.spek.api.dsl.it -import repository.StudentsRepository class StudentsInteractorTest : Spek({ From 59b25bbe009d443c48bcf1cd5ad0bdc72cbe7217 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Wed, 6 Jun 2018 08:24:36 +0200 Subject: [PATCH 08/11] first experimentations with spring integrations tests and embeded redis. Some issues remains with junit 5, spring integration and kotlin --- .../kotlin/interactors/StudentsInteractor.kt | 2 +- .../redis/configuration/RedisConfiguration.kt | 20 +++++++++++ .../embeded/redis/startup/EmbededRedisTest.kt | 35 +++++++++++++++++++ .../startup/RedisEmbededConfiguration.kt | 12 +++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 persistence/src/main/kotlin/redis/configuration/RedisConfiguration.kt create mode 100644 persistence/src/test/kotlin/embeded/redis/startup/RedisEmbededConfiguration.kt diff --git a/interactors/src/main/kotlin/interactors/StudentsInteractor.kt b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt index f7eb234..8154f92 100644 --- a/interactors/src/main/kotlin/interactors/StudentsInteractor.kt +++ b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt @@ -3,10 +3,10 @@ package com.students.results.interactors import arrow.core.Either import arrow.core.flatMap import com.students.results.repository.ExamsRepository +import com.students.results.repository.StudentsRepository import com.students.results.services.NotateExamException import com.students.results.services.Students import com.students.results.services.requests.NotateExam -import repository.StudentsRepository class StudentsInteractor(private val studentsRepository: StudentsRepository, private val examsRepository: ExamsRepository) : Students { diff --git a/persistence/src/main/kotlin/redis/configuration/RedisConfiguration.kt b/persistence/src/main/kotlin/redis/configuration/RedisConfiguration.kt new file mode 100644 index 0000000..d111688 --- /dev/null +++ b/persistence/src/main/kotlin/redis/configuration/RedisConfiguration.kt @@ -0,0 +1,20 @@ +package com.students.results.redis.configuration + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory +import org.springframework.data.redis.core.RedisTemplate +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories + +@Configuration +@EnableRedisRepositories +class RedisConfiguration { + + @Bean + fun connectionFactory() = JedisConnectionFactory() + + @Bean + fun redisTemplate(jedisConnectionFactory: JedisConnectionFactory) = RedisTemplate().apply { + connectionFactory = jedisConnectionFactory + } +} \ No newline at end of file diff --git a/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt b/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt index 8fd0689..4202012 100644 --- a/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt +++ b/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt @@ -1,2 +1,37 @@ package embeded.redis.startup +import com.students.results.redis.configuration.RedisConfiguration +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.* +import org.junit.runner.RunWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit4.SpringRunner +import redis.embedded.RedisServer + +@RunWith(SpringRunner::class) +@ContextConfiguration(classes = [RedisConfiguration::class, RedisEmbededConfiguration::class]) +@TestInstance(Lifecycle.PER_CLASS) +class EmbededRedisTest { + + @Autowired + private lateinit var redisServer: RedisServer + + @BeforeAll + fun beforeStart() { + redisServer.start() + } + + @Test + fun runATEst(){ + println("I am running") + } + + @AfterAll + fun afterStart() { + redisServer.stop() + } +} \ No newline at end of file diff --git a/persistence/src/test/kotlin/embeded/redis/startup/RedisEmbededConfiguration.kt b/persistence/src/test/kotlin/embeded/redis/startup/RedisEmbededConfiguration.kt new file mode 100644 index 0000000..b2ced02 --- /dev/null +++ b/persistence/src/test/kotlin/embeded/redis/startup/RedisEmbededConfiguration.kt @@ -0,0 +1,12 @@ +package embeded.redis.startup + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import redis.embedded.RedisServer + +@Configuration +class RedisEmbededConfiguration { + + @Bean + fun redisServer(): RedisServer = RedisServer(6379) +} \ No newline at end of file From 403c54092d620d7f18e8ebb67856c643f2fcc498 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Wed, 6 Jun 2018 20:21:20 +0200 Subject: [PATCH 09/11] fix some coments issues such as better naming and code style improve --- build.gradle | 15 +++++++++++---- interactors/src/main/kotlin/entities/Exam.kt | 6 +++--- .../src/main/kotlin/entities/Student.kt | 14 +++++++------- .../kotlin/interactors/StudentsInteractor.kt | 19 +++++++++---------- .../main/kotlin/repository/Repositories.kt | 2 +- interactors/src/main/kotlin/services/Exams.kt | 2 +- .../src/main/kotlin/services/Services.kt | 5 ++++- .../src/main/kotlin/services/Students.kt | 4 ++-- .../kotlin/services/requests/GradeExam.kt | 5 +++++ .../kotlin/services/requests/NotateExam.kt | 5 ----- .../src/test/kotlin/entities/StudentTest.kt | 6 +++--- .../interactors/StudentsInteractorTest.kt | 16 ++++++---------- 12 files changed, 52 insertions(+), 47 deletions(-) create mode 100644 interactors/src/main/kotlin/services/requests/GradeExam.kt delete mode 100644 interactors/src/main/kotlin/services/requests/NotateExam.kt diff --git a/build.gradle b/build.gradle index 2ee64e1..069f41f 100644 --- a/build.gradle +++ b/build.gradle @@ -36,11 +36,18 @@ subprojects { dependencies { compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8") compile("org.jetbrains.kotlin:kotlin-reflect") - compile group: 'io.arrow-kt', name: 'arrow-core', version: '0.7.2' + compile 'io.arrow-kt:arrow-core:0.7.2' + compile 'io.arrow-kt:arrow-syntax:0.7.2' + compile 'io.arrow-kt:arrow-typeclasses:0.7.2' + compile 'io.arrow-kt:arrow-data:0.7.2' + compile 'io.arrow-kt:arrow-instances-core:0.7.2' + compile 'io.arrow-kt:arrow-instances-data:0.7.2' + kapt 'io.arrow-kt:arrow-annotations-processor:0.7.2' + testCompile('org.jetbrains.spek:spek-api:1.1.5') - { - exclude group: 'org.jetbrains.kotlin' - } + { + exclude group: 'org.jetbrains.kotlin' + } testRuntime('org.jetbrains.spek:spek-junit-platform-engine:1.1.5') { exclude group: 'org.junit.platform' exclude group: 'org.jetbrains.kotlin' diff --git a/interactors/src/main/kotlin/entities/Exam.kt b/interactors/src/main/kotlin/entities/Exam.kt index bd1669b..196ce30 100644 --- a/interactors/src/main/kotlin/entities/Exam.kt +++ b/interactors/src/main/kotlin/entities/Exam.kt @@ -1,14 +1,14 @@ package com.students.results.entities import arrow.core.Either -import java.math.BigDecimal +import services.Grade data class Exam(val id: Long) { - fun validateNotation(notation: BigDecimal): Either = + fun validateGrade(notation: Grade): Either = when (notation) { in (0.toBigDecimal()..20.toBigDecimal()) -> Either.right(Unit) else -> Either.left(InvalidNotationForThisExamException("This notation, $notation, is not in bound")) } } -class InvalidNotationForThisExamException(msg: String?) : RuntimeException(msg) +class InvalidNotationForThisExamException(msg: String?) : Exception(msg) diff --git a/interactors/src/main/kotlin/entities/Student.kt b/interactors/src/main/kotlin/entities/Student.kt index 4541d7c..1ebe399 100644 --- a/interactors/src/main/kotlin/entities/Student.kt +++ b/interactors/src/main/kotlin/entities/Student.kt @@ -1,22 +1,22 @@ package com.students.results.entities import arrow.core.Either +import services.Grade import java.math.BigDecimal -typealias Notes = Map +typealias Grades = Map -data class Student(val id: Long, val notes: Notes = emptyMap()) { +data class Student(val id: Long, val grades: Grades = emptyMap()) { fun getNotation(exam: Exam): Either = when { - notes.containsKey(exam) -> Either.right(notes.getValue(exam)) + grades.containsKey(exam) -> Either.right(grades.getValue(exam)) else -> Either.left(NotEvaluatedException()) } fun notate(exam: Exam, note: BigDecimal): Either = - exam.validateNotation(note).map { - copy(id = id, - notes = notes + mapOf(exam to note)) + exam.validateGrade(note).map { + copy(grades = grades + mapOf(exam to note)) } } -class NotEvaluatedException(msg: String? = null, throwable: Throwable? = null) : RuntimeException(msg, throwable) \ No newline at end of file +class NotEvaluatedException(msg: String? = null, throwable: Throwable? = null) : Exception(msg, throwable) \ No newline at end of file diff --git a/interactors/src/main/kotlin/interactors/StudentsInteractor.kt b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt index 8154f92..107b4ed 100644 --- a/interactors/src/main/kotlin/interactors/StudentsInteractor.kt +++ b/interactors/src/main/kotlin/interactors/StudentsInteractor.kt @@ -4,19 +4,18 @@ import arrow.core.Either import arrow.core.flatMap import com.students.results.repository.ExamsRepository import com.students.results.repository.StudentsRepository -import com.students.results.services.NotateExamException +import com.students.results.services.GradeExamException import com.students.results.services.Students -import com.students.results.services.requests.NotateExam +import com.students.results.services.requests.GradeExam class StudentsInteractor(private val studentsRepository: StudentsRepository, private val examsRepository: ExamsRepository) : Students { - override fun notate(notateExam: NotateExam): Either = - studentsRepository.findStudentById(studentId = 1).flatMap { student -> - examsRepository.findExamById(examId = notateExam.examId).flatMap { exam -> - student.notate(exam, notateExam.note).flatMap { updatedStudent -> - studentsRepository.save(updatedStudent) + override fun grade(gradeExam: GradeExam): Either = + gradeExam.run { + studentsRepository.findStudentById(studentId).flatMap { student -> + examsRepository.findExamById(examId).flatMap { exam -> + student.notate(exam, grade).flatMap { studentsRepository.save(it) } } - } - }.mapLeft { NotateExamException(throwable = it) } - + }.mapLeft { GradeExamException(throwable = it) } + } } diff --git a/interactors/src/main/kotlin/repository/Repositories.kt b/interactors/src/main/kotlin/repository/Repositories.kt index 8c04654..658112a 100644 --- a/interactors/src/main/kotlin/repository/Repositories.kt +++ b/interactors/src/main/kotlin/repository/Repositories.kt @@ -1,7 +1,7 @@ package com.students.results.repository -sealed class RepositoryException(msg: String? = null, throwable: Throwable? = null) : RuntimeException(msg, throwable) +sealed class RepositoryException(msg: String? = null, throwable: Throwable? = null) : Exception(msg, throwable) class NotFoundException(msg: String? = null, throwable: Throwable? = null) : RepositoryException(msg, throwable) class NotWrittenException(msg: String? = null, throwable: Throwable? = null) : RepositoryException(msg, throwable) diff --git a/interactors/src/main/kotlin/services/Exams.kt b/interactors/src/main/kotlin/services/Exams.kt index 98983f3..61b6a16 100644 --- a/interactors/src/main/kotlin/services/Exams.kt +++ b/interactors/src/main/kotlin/services/Exams.kt @@ -3,4 +3,4 @@ package com.students.results.services interface Exams { } -class NotateExamException(message: String? = null, throwable: Throwable? = null) : RuntimeException(message, throwable) +class GradeExamException(message: String? = null, throwable: Throwable? = null) : Exception(message, throwable) diff --git a/interactors/src/main/kotlin/services/Services.kt b/interactors/src/main/kotlin/services/Services.kt index 5c22547..10e28e4 100644 --- a/interactors/src/main/kotlin/services/Services.kt +++ b/interactors/src/main/kotlin/services/Services.kt @@ -1,5 +1,8 @@ package services -sealed class ServicesException(msg: String? = null, throwable: Throwable? = null) : RuntimeException(msg, throwable) +import java.math.BigDecimal + +typealias Grade = BigDecimal +sealed class ServicesException(msg: String? = null, throwable: Throwable? = null) : Exception(msg, throwable) class NotFoundException(msg: String? = null, throwable: Throwable? = null) : ServicesException(msg, throwable) \ No newline at end of file diff --git a/interactors/src/main/kotlin/services/Students.kt b/interactors/src/main/kotlin/services/Students.kt index b464384..b34f748 100644 --- a/interactors/src/main/kotlin/services/Students.kt +++ b/interactors/src/main/kotlin/services/Students.kt @@ -1,10 +1,10 @@ package com.students.results.services import arrow.core.Either -import com.students.results.services.requests.NotateExam +import com.students.results.services.requests.GradeExam interface Students { - fun notate(notateExam: NotateExam): Either + fun grade(gradeExam: GradeExam): Either } diff --git a/interactors/src/main/kotlin/services/requests/GradeExam.kt b/interactors/src/main/kotlin/services/requests/GradeExam.kt new file mode 100644 index 0000000..84c1e79 --- /dev/null +++ b/interactors/src/main/kotlin/services/requests/GradeExam.kt @@ -0,0 +1,5 @@ +package com.students.results.services.requests + +import services.Grade + +data class GradeExam(val examId: Long, val studentId: Long, val grade: Grade) diff --git a/interactors/src/main/kotlin/services/requests/NotateExam.kt b/interactors/src/main/kotlin/services/requests/NotateExam.kt deleted file mode 100644 index b3a0f5a..0000000 --- a/interactors/src/main/kotlin/services/requests/NotateExam.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.students.results.services.requests - -import java.math.BigDecimal - -data class NotateExam(val examId: Long, val studentId: Long, val note: BigDecimal) diff --git a/interactors/src/test/kotlin/entities/StudentTest.kt b/interactors/src/test/kotlin/entities/StudentTest.kt index c1267bb..ed8d9d5 100644 --- a/interactors/src/test/kotlin/entities/StudentTest.kt +++ b/interactors/src/test/kotlin/entities/StudentTest.kt @@ -14,10 +14,10 @@ class StudentTest : Spek({ val student = Student(id = 40L) val exam = Exam(id = 50L) - it("getNot without note should returns NotEvaluatedException") { + it("getNot without grade should returns NotEvaluatedException") { student.getNotation(exam).isLeft() shouldBe true } - it("notate an exam with 20 and get notation should return 20") { + it("grade an exam with 20 and get notation should return 20") { student.notate(exam, "20".toBigDecimal()).apply { isRight() shouldBe true map { @@ -28,7 +28,7 @@ class StudentTest : Spek({ } } } - it("notate less than zero should fail to register note") { + it("grade less than zero should fail to register grade") { student.notate(exam, "-1".toBigDecimal()).isLeft() shouldBe true } } diff --git a/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt index d216739..22b6c6e 100644 --- a/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt +++ b/interactors/src/test/kotlin/interactors/StudentsInteractorTest.kt @@ -5,12 +5,11 @@ import com.students.results.entities.Exam import com.students.results.entities.Student import com.students.results.repository.ExamsRepository import com.students.results.repository.StudentsRepository -import com.students.results.services.requests.NotateExam +import com.students.results.services.requests.GradeExam import io.mockk.every import io.mockk.mockk import io.mockk.slot import io.mockk.verify -import org.amshove.kluent.`should be` import org.amshove.kluent.shouldBe import org.amshove.kluent.shouldEqual import org.jetbrains.spek.api.Spek @@ -25,7 +24,7 @@ class StudentsInteractorTest : Spek({ val studentSlot = slot() val studentRepository = mockk() { - every { findStudentById(1) } returns Either.right(student) + every { findStudentById(3) } returns Either.right(student) every { save(student = capture(studentSlot)) } returns Either.right(Unit) } val exam = Exam(id = 5) @@ -34,11 +33,8 @@ class StudentsInteractorTest : Spek({ } val studentsInteractor = StudentsInteractor(studentRepository, examsRepository) studentsInteractor.notate20().apply { - it("should notate an existing exam with a note of 20") { - isRight() `should be` true - } it("should retrieve student by his id") { - verify { studentRepository.findStudentById(1) } + verify { studentRepository.findStudentById(3) } } it("should retrieve exam by id") { verify { examsRepository.findExamById(5) } @@ -53,8 +49,8 @@ class StudentsInteractorTest : Spek({ } }) -private fun StudentsInteractor.notate20() = notate(NotateExam( +private fun StudentsInteractor.notate20() = grade(GradeExam( examId = 5, - studentId = 1, - note = "20".toBigDecimal() + studentId = 3, + grade = "20".toBigDecimal() )) \ No newline at end of file From dd61d5b0c47074a72431ca5d9aab9c1b7e3a826c Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Wed, 6 Jun 2018 21:11:10 +0200 Subject: [PATCH 10/11] first test with redis server launched with success --- persistence/build.gradle | 3 +++ .../src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/persistence/build.gradle b/persistence/build.gradle index d4eb35a..c2a90cf 100644 --- a/persistence/build.gradle +++ b/persistence/build.gradle @@ -3,6 +3,9 @@ apply plugin: 'kotlin-spring' dependencies { compile project(':interactors') compile group: 'org.springframework.data', name: 'spring-data-redis', version: '2.0.7.RELEASE' + compile group: 'org.apache.commons', name: 'commons-pool2', version: '2.5.0' + compile group: 'redis.clients', name: 'jedis', version: '2.9.0' + testCompile 'it.ozimov:embedded-redis:0.7.2' testCompile group: 'org.springframework', name: 'spring-test', version: '5.0.6.RELEASE' testImplementation( diff --git a/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt b/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt index 4202012..884af51 100644 --- a/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt +++ b/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt @@ -6,13 +6,15 @@ import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.TestInstance.* +import org.junit.jupiter.api.extension.ExtendWith import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.junit.jupiter.SpringExtension import org.springframework.test.context.junit4.SpringRunner import redis.embedded.RedisServer -@RunWith(SpringRunner::class) +@ExtendWith(SpringExtension::class) @ContextConfiguration(classes = [RedisConfiguration::class, RedisEmbededConfiguration::class]) @TestInstance(Lifecycle.PER_CLASS) class EmbededRedisTest { From 6d4b919239de7db341f83d81cd7e6bd0b6f11de8 Mon Sep 17 00:00:00 2001 From: Benjamin KUCHCIK Date: Thu, 7 Jun 2018 08:03:10 +0200 Subject: [PATCH 11/11] Start implementing redis repositories --- .../repository/impl/ExamsRepositoryImpl.kt | 12 ++++++++++++ .../repository/impl/StudentsRepositoryImpl.kt | 17 +++++++++++++++++ .../embeded/redis/startup/EmbededRedisTest.kt | 18 +++++++++++------- .../repository/impl/ExamsRepositoryImplTest.kt | 14 ++++++++++++++ 4 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 persistence/src/main/kotlin/repository/impl/ExamsRepositoryImpl.kt create mode 100644 persistence/src/main/kotlin/repository/impl/StudentsRepositoryImpl.kt create mode 100644 persistence/src/test/kotlin/repository/impl/ExamsRepositoryImplTest.kt diff --git a/persistence/src/main/kotlin/repository/impl/ExamsRepositoryImpl.kt b/persistence/src/main/kotlin/repository/impl/ExamsRepositoryImpl.kt new file mode 100644 index 0000000..130a036 --- /dev/null +++ b/persistence/src/main/kotlin/repository/impl/ExamsRepositoryImpl.kt @@ -0,0 +1,12 @@ +package repository.impl + +import arrow.core.Either +import com.students.results.entities.Exam +import com.students.results.repository.ExamsRepository +import com.students.results.repository.NotFoundException + +class ExamsRepositoryImpl : ExamsRepository { + override fun findExamById(examId: Long): Either { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/persistence/src/main/kotlin/repository/impl/StudentsRepositoryImpl.kt b/persistence/src/main/kotlin/repository/impl/StudentsRepositoryImpl.kt new file mode 100644 index 0000000..357d2cb --- /dev/null +++ b/persistence/src/main/kotlin/repository/impl/StudentsRepositoryImpl.kt @@ -0,0 +1,17 @@ +package repository.impl + +import arrow.core.Either +import com.students.results.entities.Student +import com.students.results.repository.RepositoryException +import com.students.results.repository.StudentsRepository + +class StudentsRepositoryImpl : StudentsRepository { + + override fun findStudentById(studentId: Long): Either { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun save(student: Student): Either { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt b/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt index 884af51..169b2b5 100644 --- a/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt +++ b/persistence/src/test/kotlin/embeded/redis/startup/EmbededRedisTest.kt @@ -17,8 +17,7 @@ import redis.embedded.RedisServer @ExtendWith(SpringExtension::class) @ContextConfiguration(classes = [RedisConfiguration::class, RedisEmbededConfiguration::class]) @TestInstance(Lifecycle.PER_CLASS) -class EmbededRedisTest { - +abstract class RedisTestConfiguration protected constructor() { @Autowired private lateinit var redisServer: RedisServer @@ -27,13 +26,18 @@ class EmbededRedisTest { redisServer.start() } - @Test - fun runATEst(){ - println("I am running") - } - @AfterAll fun afterStart() { redisServer.stop() } +} + +class EmbededRedisTest : RedisTestConfiguration() { + + + @Test + fun runATEst() { + println("I am running") + } + } \ No newline at end of file diff --git a/persistence/src/test/kotlin/repository/impl/ExamsRepositoryImplTest.kt b/persistence/src/test/kotlin/repository/impl/ExamsRepositoryImplTest.kt new file mode 100644 index 0000000..710a1e9 --- /dev/null +++ b/persistence/src/test/kotlin/repository/impl/ExamsRepositoryImplTest.kt @@ -0,0 +1,14 @@ +package repository.impl + +import embeded.redis.startup.RedisTestConfiguration +import org.junit.jupiter.api.Test + +import org.junit.jupiter.api.Assertions.* + +internal class ExamsRepositoryImplTest : RedisTestConfiguration() { + + + @Test + fun findExamById() { + } +} \ No newline at end of file