From 819c9f97266c9cb6375aba06e1d9a74c47b43a47 Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Thu, 30 Mar 2023 13:54:23 +0100 Subject: [PATCH 01/13] MPA-73: Getting projects from the API --- shared/build.gradle.kts | 10 +++++++-- .../mindera/minderapeople/DTO/ProjectDTO.kt | 5 ++++- .../minderapeople/MinderaPeopleAPIClient.kt | 18 ++++++++++++++- .../apiclient/ProjectApiClientImpI.kt | 22 +++++++++++++++++++ .../interfaces/IProjectsApiClient.kt | 7 ++++++ .../repository/ProjectRepository.kt | 6 ----- .../repository/ProjectRepositoryImpl.kt | 12 ++++++++++ .../interfaces/IProjectRepository.kt | 7 ++++++ 8 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/ProjectApiClientImpI.kt create mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IProjectsApiClient.kt delete mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepository.kt create mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepositoryImpl.kt create mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IProjectRepository.kt diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index cf590bf..a9839d6 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -2,6 +2,7 @@ plugins { kotlin("multiplatform") id("com.android.library") id("com.chromaticnoise.multiplatform-swiftpackage") version "2.0.3" + kotlin("plugin.serialization") version "1.8.10" } kotlin { @@ -34,10 +35,15 @@ kotlin { } sourceSets { + val ktorVersion = "2.2.4" val commonMain by getting { dependencies{ - implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.1") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.1") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") + implementation("io.ktor:ktor-client-core:$ktorVersion") + implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") } } val commonTest by getting { diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/ProjectDTO.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/ProjectDTO.kt index 13c92ec..927c80c 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/ProjectDTO.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/ProjectDTO.kt @@ -3,4 +3,7 @@ package com.mindera.minderapeople.DTO import kotlinx.serialization.Serializable @Serializable -data class ProjectDTO(val aux:String) +data class ProjectDTO( + val project_id: String, + val project_name: String +) diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/MinderaPeopleAPIClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/MinderaPeopleAPIClient.kt index 2ea89b5..cf48fbd 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/MinderaPeopleAPIClient.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/MinderaPeopleAPIClient.kt @@ -1,4 +1,20 @@ package com.mindera.minderapeople -class MinderaPeopleAPIClient { +import io.ktor.client.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.serialization.kotlinx.json.* +import kotlinx.serialization.json.Json + +object MinderaPeopleAPIClient { + + const val BASE_URL = "http://localhost:3000/api" + + val httpClient = HttpClient { + install(ContentNegotiation) { + json(Json { + ignoreUnknownKeys = true + useAlternativeNames = false + }) + } + } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/ProjectApiClientImpI.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/ProjectApiClientImpI.kt new file mode 100644 index 0000000..5ded17e --- /dev/null +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/ProjectApiClientImpI.kt @@ -0,0 +1,22 @@ +package com.mindera.minderapeople.apiclient + +import com.mindera.minderapeople.DTO.ProjectDTO +import com.mindera.minderapeople.MinderaPeopleAPIClient +import com.mindera.minderapeople.apiclient.interfaces.IProjectsApiClient +import io.ktor.client.call.* +import io.ktor.client.request.* + +class ProjectApiClientImpl: IProjectsApiClient { + + val httpClient = MinderaPeopleAPIClient.httpClient + val baseUrl = MinderaPeopleAPIClient.BASE_URL + + override suspend fun getAllProjects(): Result> { + return try{ + val response: List = httpClient.get("${baseUrl}/policies").body() + Result.success(response) + }catch (e: Exception){ + Result.failure(e) + } + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IProjectsApiClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IProjectsApiClient.kt new file mode 100644 index 0000000..4bfbeb4 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IProjectsApiClient.kt @@ -0,0 +1,7 @@ +package com.mindera.minderapeople.apiclient.interfaces + +import com.mindera.minderapeople.DTO.ProjectDTO + +interface IProjectsApiClient { + suspend fun getAllProjects(): Result> +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepository.kt deleted file mode 100644 index 5cf3703..0000000 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepository.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.mindera.minderapeople.repository - -import com.mindera.minderapeople.MinderaPeopleAPIClient - -class ProjectRepository(val apiClient: MinderaPeopleAPIClient) { -} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepositoryImpl.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepositoryImpl.kt new file mode 100644 index 0000000..11f4dba --- /dev/null +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepositoryImpl.kt @@ -0,0 +1,12 @@ +package com.mindera.minderapeople.repository + +import com.mindera.minderapeople.DTO.ProjectDTO +import com.mindera.minderapeople.apiclient.interfaces.IProjectsApiClient +import com.mindera.minderapeople.repository.interfaces.IProjectRepository + +class ProjectRepositoryImpl(val apiClient: IProjectsApiClient) : IProjectRepository{ + override suspend fun getAllProjects(): Result> { + return apiClient.getAllProjects() + } + +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IProjectRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IProjectRepository.kt new file mode 100644 index 0000000..6c83b4d --- /dev/null +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IProjectRepository.kt @@ -0,0 +1,7 @@ +package com.mindera.minderapeople.repository.interfaces + +import com.mindera.minderapeople.DTO.ProjectDTO + +interface IProjectRepository { + suspend fun getAllProjects(): Result> +} \ No newline at end of file From 83c265ecc82caed5f70f00e53eb3a8dc005d8ff7 Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Mon, 3 Apr 2023 09:49:09 +0100 Subject: [PATCH 02/13] using HttpClientEngine for the HttpClient --- .../mindera/minderapeople/DTO/ProjectDTO.kt | 9 --------- .../{ => apiclient}/MinderaPeopleAPIClient.kt | 12 +++++++----- .../apiclient/ProjectApiClientImpI.kt | 19 ++++++++++++------- .../interfaces/IProjectsApiClient.kt | 2 +- .../minderapeople/{DTO => dto}/EventDTO.kt | 2 +- .../{DTO => dto}/PartOfDayDTO.kt | 2 +- .../minderapeople/{DTO => dto}/PolicyDTO.kt | 2 +- .../mindera/minderapeople/dto/ProjectDTO.kt | 10 ++++++++++ .../repository/EventRepository.kt | 2 +- .../repository/PartOfDayRepository.kt | 2 +- .../repository/PolicyRepository.kt | 2 +- .../repository/ProjectRepositoryImpl.kt | 4 ++-- .../interfaces/IProjectRepository.kt | 2 +- 13 files changed, 39 insertions(+), 31 deletions(-) delete mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/ProjectDTO.kt rename shared/src/commonMain/kotlin/com/mindera/minderapeople/{ => apiclient}/MinderaPeopleAPIClient.kt (56%) rename shared/src/commonMain/kotlin/com/mindera/minderapeople/{DTO => dto}/EventDTO.kt (70%) rename shared/src/commonMain/kotlin/com/mindera/minderapeople/{DTO => dto}/PartOfDayDTO.kt (72%) rename shared/src/commonMain/kotlin/com/mindera/minderapeople/{DTO => dto}/PolicyDTO.kt (71%) create mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/ProjectDTO.kt diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/ProjectDTO.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/ProjectDTO.kt deleted file mode 100644 index 927c80c..0000000 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/ProjectDTO.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.mindera.minderapeople.DTO - -import kotlinx.serialization.Serializable - -@Serializable -data class ProjectDTO( - val project_id: String, - val project_name: String -) diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/MinderaPeopleAPIClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/MinderaPeopleAPIClient.kt similarity index 56% rename from shared/src/commonMain/kotlin/com/mindera/minderapeople/MinderaPeopleAPIClient.kt rename to shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/MinderaPeopleAPIClient.kt index cf48fbd..33ff5c5 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/MinderaPeopleAPIClient.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/MinderaPeopleAPIClient.kt @@ -1,15 +1,17 @@ -package com.mindera.minderapeople +package com.mindera.minderapeople.apiclient import io.ktor.client.* +import io.ktor.client.engine.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json -object MinderaPeopleAPIClient { - - const val BASE_URL = "http://localhost:3000/api" +class MinderaPeopleAPIClient(engine:HttpClientEngine) { + companion object { + const val BASE_URL = "http://localhost:3000/api" + } - val httpClient = HttpClient { + val httpClient = HttpClient (engine){ install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/ProjectApiClientImpI.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/ProjectApiClientImpI.kt index 5ded17e..68b6e42 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/ProjectApiClientImpI.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/ProjectApiClientImpI.kt @@ -1,20 +1,25 @@ package com.mindera.minderapeople.apiclient -import com.mindera.minderapeople.DTO.ProjectDTO -import com.mindera.minderapeople.MinderaPeopleAPIClient +import com.mindera.minderapeople.dto.ProjectDTO import com.mindera.minderapeople.apiclient.interfaces.IProjectsApiClient import io.ktor.client.call.* +import io.ktor.client.engine.* import io.ktor.client.request.* +import io.ktor.http.* -class ProjectApiClientImpl: IProjectsApiClient { +class ProjectApiClientImpl (engine: HttpClientEngine): IProjectsApiClient { - val httpClient = MinderaPeopleAPIClient.httpClient - val baseUrl = MinderaPeopleAPIClient.BASE_URL + private val httpClient = MinderaPeopleAPIClient(engine).httpClient + private val baseUrl = MinderaPeopleAPIClient.BASE_URL override suspend fun getAllProjects(): Result> { return try{ - val response: List = httpClient.get("${baseUrl}/policies").body() - Result.success(response) + val response = httpClient.get("${baseUrl}/policies") + + if(response.status == HttpStatusCode.OK) + Result.success(response.body()) + else + Result.failure(Exception(response.status.description)) }catch (e: Exception){ Result.failure(e) } diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IProjectsApiClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IProjectsApiClient.kt index 4bfbeb4..8133bc5 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IProjectsApiClient.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IProjectsApiClient.kt @@ -1,6 +1,6 @@ package com.mindera.minderapeople.apiclient.interfaces -import com.mindera.minderapeople.DTO.ProjectDTO +import com.mindera.minderapeople.dto.ProjectDTO interface IProjectsApiClient { suspend fun getAllProjects(): Result> diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/EventDTO.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/EventDTO.kt similarity index 70% rename from shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/EventDTO.kt rename to shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/EventDTO.kt index 435b38a..9c40aa9 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/EventDTO.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/EventDTO.kt @@ -1,4 +1,4 @@ -package com.mindera.minderapeople.DTO +package com.mindera.minderapeople.dto import kotlinx.serialization.Serializable diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/PartOfDayDTO.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/PartOfDayDTO.kt similarity index 72% rename from shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/PartOfDayDTO.kt rename to shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/PartOfDayDTO.kt index a47a238..51c4430 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/PartOfDayDTO.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/PartOfDayDTO.kt @@ -1,4 +1,4 @@ -package com.mindera.minderapeople.DTO +package com.mindera.minderapeople.dto import kotlinx.serialization.Serializable diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/PolicyDTO.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/PolicyDTO.kt similarity index 71% rename from shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/PolicyDTO.kt rename to shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/PolicyDTO.kt index 35301af..4d7bd20 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/DTO/PolicyDTO.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/PolicyDTO.kt @@ -1,4 +1,4 @@ -package com.mindera.minderapeople.DTO +package com.mindera.minderapeople.dto import kotlinx.serialization.Serializable diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/ProjectDTO.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/ProjectDTO.kt new file mode 100644 index 0000000..b2b7e42 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/ProjectDTO.kt @@ -0,0 +1,10 @@ +package com.mindera.minderapeople.dto + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ProjectDTO( + @SerialName("id") val id: String? = null, + @SerialName("project_name") val projectName: String? = null +) diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt index f9409ab..d4f6818 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt @@ -1,6 +1,6 @@ package com.mindera.minderapeople.repository -import com.mindera.minderapeople.MinderaPeopleAPIClient +import com.mindera.minderapeople.apiclient.MinderaPeopleAPIClient class EventRepository(val apiClient: MinderaPeopleAPIClient) { } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/PartOfDayRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/PartOfDayRepository.kt index 9712aff..b220850 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/PartOfDayRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/PartOfDayRepository.kt @@ -1,6 +1,6 @@ package com.mindera.minderapeople.repository -import com.mindera.minderapeople.MinderaPeopleAPIClient +import com.mindera.minderapeople.apiclient.MinderaPeopleAPIClient class PartOfDayRepository(val apiClient: MinderaPeopleAPIClient) { } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/PolicyRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/PolicyRepository.kt index edda397..22a5ea1 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/PolicyRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/PolicyRepository.kt @@ -1,6 +1,6 @@ package com.mindera.minderapeople.repository -import com.mindera.minderapeople.MinderaPeopleAPIClient +import com.mindera.minderapeople.apiclient.MinderaPeopleAPIClient class PolicyRepository(val apiClient: MinderaPeopleAPIClient) { } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepositoryImpl.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepositoryImpl.kt index 11f4dba..49d7c09 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/ProjectRepositoryImpl.kt @@ -1,10 +1,10 @@ package com.mindera.minderapeople.repository -import com.mindera.minderapeople.DTO.ProjectDTO +import com.mindera.minderapeople.dto.ProjectDTO import com.mindera.minderapeople.apiclient.interfaces.IProjectsApiClient import com.mindera.minderapeople.repository.interfaces.IProjectRepository -class ProjectRepositoryImpl(val apiClient: IProjectsApiClient) : IProjectRepository{ +class ProjectRepositoryImpl(private val apiClient: IProjectsApiClient) : IProjectRepository{ override suspend fun getAllProjects(): Result> { return apiClient.getAllProjects() } diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IProjectRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IProjectRepository.kt index 6c83b4d..8640fc2 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IProjectRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IProjectRepository.kt @@ -1,6 +1,6 @@ package com.mindera.minderapeople.repository.interfaces -import com.mindera.minderapeople.DTO.ProjectDTO +import com.mindera.minderapeople.dto.ProjectDTO interface IProjectRepository { suspend fun getAllProjects(): Result> From 590e2cadbadc156cdf2fcf0ab9a25d53bc627c67 Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Mon, 3 Apr 2023 09:49:37 +0100 Subject: [PATCH 03/13] unit tests for ProjectRepository and ProjectApiClient --- shared/build.gradle.kts | 13 +++ .../unit/apiClient/ProjectApiClientTest.kt | 106 ++++++++++++++++++ .../unit/repository/ProjectRepositoryTest.kt | 77 +++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiClient/ProjectApiClientTest.kt create mode 100644 shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/ProjectRepositoryTest.kt diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index a9839d6..8b42970 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -3,6 +3,7 @@ plugins { id("com.android.library") id("com.chromaticnoise.multiplatform-swiftpackage") version "2.0.3" kotlin("plugin.serialization") version "1.8.10" + id("com.google.devtools.ksp") version "1.8.0-1.0.9" } kotlin { @@ -49,6 +50,10 @@ kotlin { val commonTest by getting { dependencies { implementation(kotlin("test")) + implementation("io.ktor:ktor-client-mock:$ktorVersion") + implementation("org.jetbrains.kotlin:kotlin-test") + implementation("io.mockative:mockative:1.4.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4") } } val androidMain by getting @@ -74,6 +79,14 @@ kotlin { } } +dependencies { + configurations + .filter { it.name.startsWith("ksp") && it.name.contains("Test") } + .forEach { + add(it.name, "io.mockative:mockative-processor:1.4.0") + } +} + android { namespace = "com.mindera.minderapeople" compileSdk = 33 diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiClient/ProjectApiClientTest.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiClient/ProjectApiClientTest.kt new file mode 100644 index 0000000..e51b821 --- /dev/null +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiClient/ProjectApiClientTest.kt @@ -0,0 +1,106 @@ +package com.mindera.minderapeople.unit.apiClient + +import com.mindera.minderapeople.apiclient.ProjectApiClientImpl +import kotlin.test.Test +import io.ktor.client.engine.mock.* +import io.ktor.http.* +import io.ktor.utils.io.* +import kotlinx.coroutines.runBlocking +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class ProjectApiClientTest { + + private val validResponseWithElements = """ + [ + { + "id": "anova0001", + "project_name": "Anova(Unify)" + }, + { + "id": "farfetch0001", + "project_name": "Farfetch (PH Portugal)" + }, + { + "id": "farfetch0002", + "project_name": "Farfetch (FF Harrods)" + } + ] + """ + + private val validResponseWithoutElements = """[]""" + + + @Test + fun `test getAllProjects returns success and a list if API request was valid and there are objects`() { + val mockEngine = MockEngine { request -> + respond( + content = ByteReadChannel(validResponseWithElements), + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + runBlocking { + val client = ProjectApiClientImpl(mockEngine) + val result = client.getAllProjects() + + assertTrue(result.isSuccess) + assertEquals(3, result.getOrNull()?.size) + } + } + + @Test + fun `test getAllProjects returns success and an empty list if API request was valid and there are no objects`() { + val mockEngine = MockEngine { request -> + respond( + content = ByteReadChannel(validResponseWithoutElements), + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + runBlocking { + val client = ProjectApiClientImpl(mockEngine) + val result = client.getAllProjects() + + assertTrue(result.isSuccess) + assertEquals(0, result.getOrNull()?.size) + } + } + + @Test + fun `test getAllProjects returns failure if badRequest`() { + + val mockEngine = MockEngine { + respondBadRequest() + } + + runBlocking { + val client = ProjectApiClientImpl(mockEngine) + val result = client.getAllProjects() + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.BadRequest.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getAllProjects returns failure when Exception is thrown`() { + val errorMessage = "Error" + + val mockEngine = MockEngine { + throw Exception(errorMessage) + } + + runBlocking { + val client = ProjectApiClientImpl(mockEngine) + val result = client.getAllProjects() + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(errorMessage, result.exceptionOrNull()?.message) + } + } +} diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/ProjectRepositoryTest.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/ProjectRepositoryTest.kt new file mode 100644 index 0000000..411134f --- /dev/null +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/ProjectRepositoryTest.kt @@ -0,0 +1,77 @@ +package com.mindera.minderapeople.unit.repository + +import com.mindera.minderapeople.apiclient.interfaces.IProjectsApiClient +import com.mindera.minderapeople.dto.ProjectDTO +import com.mindera.minderapeople.repository.ProjectRepositoryImpl +import io.mockative.Mock +import io.mockative.classOf +import io.mockative.given +import io.mockative.mock +import kotlinx.coroutines.runBlocking +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + + +class ProjectRepositoryTest { + @Mock + private val api = mock(classOf()) + + private val validResponseWithElements = listOf( + ProjectDTO("anova0001","Anova(Unify)"), + ProjectDTO("farfetch0001","Farfetch (PH Portugal)"), + ProjectDTO("farfetch0002","Farfetch (FF Harrods)") + ) + + private val validResponseWithoutElements = listOf() + + @Test + fun `test getAllProjects returns success and a list if API request was valid and there are objects`(){ + given(api).suspendFunction(api::getAllProjects) + .whenInvoked() + .then { Result.success(validResponseWithElements) } + val projectRepo = ProjectRepositoryImpl(api) + + runBlocking { + val result = projectRepo.getAllProjects() + + assertTrue(result.isSuccess) + assertEquals(3, result.getOrNull()?.size) + assertEquals(validResponseWithElements, result.getOrNull()) + } + } + + @Test + fun `test getAllProjects returns success and a empty list if API request was valid and there are no objects`() { + given(api).suspendFunction(api::getAllProjects) + .whenInvoked() + .then { Result.success(validResponseWithoutElements) } + val projectRepo = ProjectRepositoryImpl(api) + + runBlocking { + val result = projectRepo.getAllProjects() + + assertTrue(result.isSuccess) + assertEquals(0, result.getOrNull()?.size) + assertEquals(validResponseWithoutElements, result.getOrNull()) + } + } + + @Test + fun `test getAllProjects returns failure if badRequest`() { + val errorMessage = "Server could not handle request" + + given(api).suspendFunction(api::getAllProjects) + .whenInvoked() + .then{ Result.failure(Exception(errorMessage))} + val projectRepo = ProjectRepositoryImpl(api) + + runBlocking { + val result = projectRepo.getAllProjects() + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(errorMessage, result.exceptionOrNull()?.message) + } + } +} \ No newline at end of file From 9fa17ebbc5f7a8dad1b4b15234bec4cfc7463b5e Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Mon, 3 Apr 2023 10:06:06 +0100 Subject: [PATCH 04/13] integration Tests for projectRepository and ProjectApiClient --- .../projects/ProjectIntegrationTests.kt | 119 ++++++++++++++++++ .../unit/apiClient/ProjectApiClientTest.kt | 20 +-- .../unit/repository/ProjectRepositoryTest.kt | 2 +- 3 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 shared/src/commonTest/kotlin/com/mindera/minderapeople/integration/projects/ProjectIntegrationTests.kt diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/integration/projects/ProjectIntegrationTests.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/integration/projects/ProjectIntegrationTests.kt new file mode 100644 index 0000000..d999b10 --- /dev/null +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/integration/projects/ProjectIntegrationTests.kt @@ -0,0 +1,119 @@ +package com.mindera.minderapeople.integration.projects + +import com.mindera.minderapeople.apiclient.ProjectApiClientImpl +import com.mindera.minderapeople.dto.ProjectDTO +import com.mindera.minderapeople.repository.ProjectRepositoryImpl +import io.ktor.client.engine.mock.* +import io.ktor.http.* +import io.ktor.utils.io.* +import kotlinx.coroutines.runBlocking +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class ProjectIntegrationTests { + private val validResponseWithElements = """ + [ + { + "id": "anova0001", + "project_name": "Anova(Unify)" + }, + { + "id": "farfetch0001", + "project_name": "Farfetch (PH Portugal)" + }, + { + "id": "farfetch0002", + "project_name": "Farfetch (FF Harrods)" + } + ] + """ + + private val validResponseWithoutElements = """[]""" + + private val expectedResponseWithElements = listOf( + ProjectDTO("anova0001","Anova(Unify)"), + ProjectDTO("farfetch0001","Farfetch (PH Portugal)"), + ProjectDTO("farfetch0002","Farfetch (FF Harrods)") + ) + + private val expectedResponseWithoutElements = listOf() + + @Test + fun `test getAllProjects returns success and a list if API request was valid and there are objects`(){ + val mockEngine = MockEngine { request -> + respond( + content = ByteReadChannel(validResponseWithElements), + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + runBlocking { + val apiClient = ProjectApiClientImpl(mockEngine) + val projectRepo = ProjectRepositoryImpl(apiClient) + val result = projectRepo.getAllProjects() + + assertTrue(result.isSuccess) + assertEquals(3, result.getOrNull()?.size) + assertEquals(expectedResponseWithElements, result.getOrNull()) + } + } + + @Test + fun `test getAllProjects returns success and a empty list if API request was valid and there are no objects`() { + val mockEngine = MockEngine { request -> + respond( + content = ByteReadChannel(validResponseWithoutElements), + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + runBlocking { + val apiClient = ProjectApiClientImpl(mockEngine) + val projectRepo = ProjectRepositoryImpl(apiClient) + val result = projectRepo.getAllProjects() + + assertTrue(result.isSuccess) + assertEquals(0, result.getOrNull()?.size) + assertEquals(expectedResponseWithoutElements, result.getOrNull()) + } + } + + @Test + fun `test getAllProjects returns failure if badRequest`() { + val mockEngine = MockEngine { request -> + respondBadRequest() + } + + runBlocking { + val apiClient = ProjectApiClientImpl(mockEngine) + val projectRepo = ProjectRepositoryImpl(apiClient) + val result = projectRepo.getAllProjects() + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.BadRequest.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getAllProjects returns failure if Exception is thrown`() { + val errorMessage = "Error" + + val mockEngine = MockEngine { + throw Exception(errorMessage) + } + + runBlocking { + val apiClient = ProjectApiClientImpl(mockEngine) + val projectRepo = ProjectRepositoryImpl(apiClient) + val result = projectRepo.getAllProjects() + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(errorMessage, result.exceptionOrNull()?.message) + } + } +} \ No newline at end of file diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiClient/ProjectApiClientTest.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiClient/ProjectApiClientTest.kt index e51b821..708a17b 100644 --- a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiClient/ProjectApiClientTest.kt +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiClient/ProjectApiClientTest.kt @@ -33,7 +33,7 @@ class ProjectApiClientTest { @Test fun `test getAllProjects returns success and a list if API request was valid and there are objects`() { - val mockEngine = MockEngine { request -> + val mockEngine = MockEngine { respond( content = ByteReadChannel(validResponseWithElements), status = HttpStatusCode.OK, @@ -42,8 +42,8 @@ class ProjectApiClientTest { } runBlocking { - val client = ProjectApiClientImpl(mockEngine) - val result = client.getAllProjects() + val apiClient = ProjectApiClientImpl(mockEngine) + val result = apiClient.getAllProjects() assertTrue(result.isSuccess) assertEquals(3, result.getOrNull()?.size) @@ -52,7 +52,7 @@ class ProjectApiClientTest { @Test fun `test getAllProjects returns success and an empty list if API request was valid and there are no objects`() { - val mockEngine = MockEngine { request -> + val mockEngine = MockEngine { respond( content = ByteReadChannel(validResponseWithoutElements), status = HttpStatusCode.OK, @@ -61,8 +61,8 @@ class ProjectApiClientTest { } runBlocking { - val client = ProjectApiClientImpl(mockEngine) - val result = client.getAllProjects() + val apiClient = ProjectApiClientImpl(mockEngine) + val result = apiClient.getAllProjects() assertTrue(result.isSuccess) assertEquals(0, result.getOrNull()?.size) @@ -77,8 +77,8 @@ class ProjectApiClientTest { } runBlocking { - val client = ProjectApiClientImpl(mockEngine) - val result = client.getAllProjects() + val apiClient = ProjectApiClientImpl(mockEngine) + val result = apiClient.getAllProjects() assertTrue(result.isFailure) assertEquals(null, result.getOrNull()) @@ -95,8 +95,8 @@ class ProjectApiClientTest { } runBlocking { - val client = ProjectApiClientImpl(mockEngine) - val result = client.getAllProjects() + val apiClient = ProjectApiClientImpl(mockEngine) + val result = apiClient.getAllProjects() assertTrue(result.isFailure) assertEquals(null, result.getOrNull()) diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/ProjectRepositoryTest.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/ProjectRepositoryTest.kt index 411134f..74b57bb 100644 --- a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/ProjectRepositoryTest.kt +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/ProjectRepositoryTest.kt @@ -58,7 +58,7 @@ class ProjectRepositoryTest { } @Test - fun `test getAllProjects returns failure if badRequest`() { + fun `test getAllProjects returns failure`() { val errorMessage = "Server could not handle request" given(api).suspendFunction(api::getAllProjects) From 4a6315c6e50830d50a03e7d12380706b5211f758 Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Mon, 3 Apr 2023 11:16:55 +0100 Subject: [PATCH 05/13] request specific event from API --- .../apiclient/EventApiClientImpl.kt | 27 +++++++++++++++++++ .../apiclient/interfaces/IEventApiClient.kt | 7 +++++ .../com/mindera/minderapeople/dto/EventDTO.kt | 18 ++++++++++++- .../repository/EventRepository.kt | 11 ++++++-- .../repository/interfaces/IEventRepository.kt | 7 +++++ 5 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt create mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt create mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt new file mode 100644 index 0000000..a51bd9b --- /dev/null +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt @@ -0,0 +1,27 @@ +package com.mindera.minderapeople.apiclient + +import com.mindera.minderapeople.apiclient.interfaces.IEventApiClient +import com.mindera.minderapeople.dto.EventDTO +import io.ktor.client.call.* +import io.ktor.client.engine.* +import io.ktor.client.request.* +import io.ktor.http.* + +class EventApiClientImpl(engine: HttpClientEngine): IEventApiClient { + + private val httpClient = MinderaPeopleAPIClient(engine).httpClient + private val baseUrl = MinderaPeopleAPIClient.BASE_URL + + override suspend fun getEventBy(userId: String, eventId: String): Result { + return try{ + val response = httpClient.get("${baseUrl}/events/${userId}/${eventId}") + + if(response.status == HttpStatusCode.OK) + Result.success(response.body()) + else + Result.failure(Exception(response.status.description)) + }catch (e: Exception){ + Result.failure(e) + } + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt new file mode 100644 index 0000000..45ef782 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt @@ -0,0 +1,7 @@ +package com.mindera.minderapeople.apiclient.interfaces + +import com.mindera.minderapeople.dto.EventDTO + +interface IEventApiClient { + suspend fun getEventBy(userId: String, eventId: String): Result +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/EventDTO.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/EventDTO.kt index 9c40aa9..0faed60 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/EventDTO.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/dto/EventDTO.kt @@ -1,6 +1,22 @@ package com.mindera.minderapeople.dto +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class EventDTO(val aux:String) \ No newline at end of file +data class EventDTO( + val id: String? = null, + val policy: PolicyDTO, + @SerialName("start_date") + val startDate: String, + @SerialName("end_date") + val endDate: String, + @SerialName("part_day") + val partOfDay: PartOfDayDTO, + @SerialName("additional_info") + val additionalInfo: String? = "", + @SerialName("includes_breakfast") + val includesBreakfast: Boolean? = null, + val city: String? = null, + val project: ProjectDTO? = null +) \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt index d4f6818..0352c43 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt @@ -1,6 +1,13 @@ package com.mindera.minderapeople.repository -import com.mindera.minderapeople.apiclient.MinderaPeopleAPIClient +import com.mindera.minderapeople.apiclient.interfaces.IEventApiClient +import com.mindera.minderapeople.dto.EventDTO +import com.mindera.minderapeople.repository.interfaces.IEventRepository + + +class EventRepository(val apiClient: IEventApiClient): IEventRepository { + override suspend fun getEventBy(userId: String, eventId: String): Result { + return apiClient.getEventBy(userId, eventId) + } -class EventRepository(val apiClient: MinderaPeopleAPIClient) { } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt new file mode 100644 index 0000000..e598c34 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt @@ -0,0 +1,7 @@ +package com.mindera.minderapeople.repository.interfaces + +import com.mindera.minderapeople.dto.EventDTO + +interface IEventRepository { + suspend fun getEventBy(userId: String, eventId: String): Result +} \ No newline at end of file From 26a9abbc0879b21f37c008bb9f5959e34bb8fd20 Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Tue, 4 Apr 2023 14:51:23 +0100 Subject: [PATCH 06/13] change name of method getEventBy to getEventById --- .../com/mindera/minderapeople/apiclient/EventApiClientImpl.kt | 2 +- .../minderapeople/apiclient/interfaces/IEventApiClient.kt | 2 +- .../com/mindera/minderapeople/repository/EventRepository.kt | 4 ++-- .../minderapeople/repository/interfaces/IEventRepository.kt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt index a51bd9b..ccdc31b 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt @@ -12,7 +12,7 @@ class EventApiClientImpl(engine: HttpClientEngine): IEventApiClient { private val httpClient = MinderaPeopleAPIClient(engine).httpClient private val baseUrl = MinderaPeopleAPIClient.BASE_URL - override suspend fun getEventBy(userId: String, eventId: String): Result { + override suspend fun getEventById(userId: String, eventId: String): Result { return try{ val response = httpClient.get("${baseUrl}/events/${userId}/${eventId}") diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt index 45ef782..dd4ce2f 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt @@ -3,5 +3,5 @@ package com.mindera.minderapeople.apiclient.interfaces import com.mindera.minderapeople.dto.EventDTO interface IEventApiClient { - suspend fun getEventBy(userId: String, eventId: String): Result + suspend fun getEventById(userId: String, eventId: String): Result } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt index 0352c43..6167dba 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt @@ -6,8 +6,8 @@ import com.mindera.minderapeople.repository.interfaces.IEventRepository class EventRepository(val apiClient: IEventApiClient): IEventRepository { - override suspend fun getEventBy(userId: String, eventId: String): Result { - return apiClient.getEventBy(userId, eventId) + override suspend fun getEventById(userId: String, eventId: String): Result { + return apiClient.getEventById(userId, eventId) } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt index e598c34..01f64f3 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt @@ -3,5 +3,5 @@ package com.mindera.minderapeople.repository.interfaces import com.mindera.minderapeople.dto.EventDTO interface IEventRepository { - suspend fun getEventBy(userId: String, eventId: String): Result + suspend fun getEventById(userId: String, eventId: String): Result } \ No newline at end of file From 88441808ae1cd4d97dab90b804dd936f127946dc Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Tue, 4 Apr 2023 14:57:27 +0100 Subject: [PATCH 07/13] implemented get events by policy --- .../minderapeople/apiclient/EventApiClientImpl.kt | 13 +++++++++++++ .../apiclient/interfaces/IEventApiClient.kt | 2 ++ .../minderapeople/repository/EventRepository.kt | 4 ++++ .../repository/interfaces/IEventRepository.kt | 1 + 4 files changed, 20 insertions(+) diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt index a51bd9b..cb7423a 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt @@ -24,4 +24,17 @@ class EventApiClientImpl(engine: HttpClientEngine): IEventApiClient { Result.failure(e) } } + + override suspend fun getEventByPolicy(userId: String, policyId: String): Result> { + return try{ + val response = httpClient.get("${baseUrl}/events/${userId}/${policyId}") + + if(response.status == HttpStatusCode.OK) + Result.success(response.body()) + else + Result.failure(Exception(response.status.description)) + }catch (e: Exception){ + Result.failure(e) + } + } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt index 45ef782..4e6e5cf 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt @@ -4,4 +4,6 @@ import com.mindera.minderapeople.dto.EventDTO interface IEventApiClient { suspend fun getEventBy(userId: String, eventId: String): Result + suspend fun getEventByPolicy(userId: String, policyId: String): Result> + } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt index 0352c43..de2f642 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt @@ -10,4 +10,8 @@ class EventRepository(val apiClient: IEventApiClient): IEventRepository { return apiClient.getEventBy(userId, eventId) } + override suspend fun getEventByPolicy(userId: String, policyId: String): Result> { + return apiClient.getEventByPolicy(userId, policyId) + } + } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt index e598c34..22f5fbc 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt @@ -4,4 +4,5 @@ import com.mindera.minderapeople.dto.EventDTO interface IEventRepository { suspend fun getEventBy(userId: String, eventId: String): Result + suspend fun getEventByPolicy(userId: String, policyId: String): Result> } \ No newline at end of file From 9074eeb7f3fd6f5b7089603bf5822a8520559709 Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Tue, 4 Apr 2023 14:59:03 +0100 Subject: [PATCH 08/13] Update EventRepositoryImpl.kt --- .../repository/{EventRepository.kt => EventRepositoryImpl.kt} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/{EventRepository.kt => EventRepositoryImpl.kt} (83%) diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepositoryImpl.kt similarity index 83% rename from shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt rename to shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepositoryImpl.kt index 6167dba..06bb0f8 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepositoryImpl.kt @@ -5,7 +5,7 @@ import com.mindera.minderapeople.dto.EventDTO import com.mindera.minderapeople.repository.interfaces.IEventRepository -class EventRepository(val apiClient: IEventApiClient): IEventRepository { +class EventRepositoryImpl(val apiClient: IEventApiClient): IEventRepository { override suspend fun getEventById(userId: String, eventId: String): Result { return apiClient.getEventById(userId, eventId) } From 81e2f6c2babce6649afd3e995786713219f66be4 Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Tue, 4 Apr 2023 15:12:26 +0100 Subject: [PATCH 09/13] Merge branch 'MPA-71_get-specific-event' into MPA-77_get-events-by-policy --- .../minderapeople/apiclient/interfaces/IEventApiClient.kt | 1 + .../minderapeople/repository/interfaces/IEventRepository.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt index dd4ce2f..fbfaf81 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt @@ -4,4 +4,5 @@ import com.mindera.minderapeople.dto.EventDTO interface IEventApiClient { suspend fun getEventById(userId: String, eventId: String): Result + suspend fun getEventByPolicy(userId: String, policyId: String): Result> } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt index 01f64f3..98076d4 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt @@ -4,4 +4,5 @@ import com.mindera.minderapeople.dto.EventDTO interface IEventRepository { suspend fun getEventById(userId: String, eventId: String): Result + suspend fun getEventByPolicy(userId: String, policyId: String): Result> } \ No newline at end of file From 7d7ae58a80dd47330c2907b14a16df1b10ee6bc3 Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Mon, 10 Apr 2023 13:54:26 +0100 Subject: [PATCH 10/13] unit tests for getEventsByPolicy --- .../minderapeople/apiclient/EventApiClient.kt | 13 +++ .../apiclient/EventApiClientImpl.kt | 40 -------- .../apiclient/MinderaPeopleAPIClient.kt | 22 ----- .../apiclient/interfaces/IEventApiClient.kt | 2 +- ...ntRepositoryImpl.kt => EventRepository.kt} | 4 +- .../repository/interfaces/IEventRepository.kt | 2 +- .../minderapeople/mocks/DefaultTestData.kt | 1 + .../minderapeople/mocks/EventApiClientMock.kt | 6 ++ .../unit/apiclient/EventApiClientTest.kt | 97 +++++++++++++++++++ .../unit/repository/EventRepositoryTest.kt | 81 ++++++++++++++++ 10 files changed, 202 insertions(+), 66 deletions(-) delete mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt delete mode 100644 shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/MinderaPeopleAPIClient.kt rename shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/{EventRepositoryImpl.kt => EventRepository.kt} (89%) diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClient.kt index 8ecf2e6..e7ca415 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClient.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClient.kt @@ -11,6 +11,19 @@ class EventApiClient(engine: HttpClientEngine) : IEventApiClient { private val apiHttpClient = ApiHttpClient(engine) private val httpClient = apiHttpClient.httpClient + override suspend fun getEventsByPolicy(userId: String, policyId: String): Result> { + return try { + val response = httpClient.get("${apiHttpClient.url}/events/${userId}?policy=${policyId}") + + if (response.status == HttpStatusCode.OK) { + Result.success(response.body()) + } else { + Result.failure(Exception(response.status.description)) + } + } catch (e: Exception) { + Result.failure(e) + } + } override suspend fun getAllEventsForUser(userId: String): Result> { return try { diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt deleted file mode 100644 index cbc10ba..0000000 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClientImpl.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.mindera.minderapeople.apiclient - -import com.mindera.minderapeople.apiclient.interfaces.IEventApiClient -import com.mindera.minderapeople.dto.EventDTO -import io.ktor.client.call.* -import io.ktor.client.engine.* -import io.ktor.client.request.* -import io.ktor.http.* - -class EventApiClientImpl(engine: HttpClientEngine): IEventApiClient { - - private val httpClient = MinderaPeopleAPIClient(engine).httpClient - private val baseUrl = MinderaPeopleAPIClient.BASE_URL - - override suspend fun getEventById(userId: String, eventId: String): Result { - return try{ - val response = httpClient.get("${baseUrl}/events/${userId}/${eventId}") - - if(response.status == HttpStatusCode.OK) - Result.success(response.body()) - else - Result.failure(Exception(response.status.description)) - }catch (e: Exception){ - Result.failure(e) - } - } - - override suspend fun getEventByPolicy(userId: String, policyId: String): Result> { - return try{ - val response = httpClient.get("${baseUrl}/events/${userId}/${policyId}") - - if(response.status == HttpStatusCode.OK) - Result.success(response.body()) - else - Result.failure(Exception(response.status.description)) - }catch (e: Exception){ - Result.failure(e) - } - } -} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/MinderaPeopleAPIClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/MinderaPeopleAPIClient.kt deleted file mode 100644 index 33ff5c5..0000000 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/MinderaPeopleAPIClient.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.mindera.minderapeople.apiclient - -import io.ktor.client.* -import io.ktor.client.engine.* -import io.ktor.client.plugins.contentnegotiation.* -import io.ktor.serialization.kotlinx.json.* -import kotlinx.serialization.json.Json - -class MinderaPeopleAPIClient(engine:HttpClientEngine) { - companion object { - const val BASE_URL = "http://localhost:3000/api" - } - - val httpClient = HttpClient (engine){ - install(ContentNegotiation) { - json(Json { - ignoreUnknownKeys = true - useAlternativeNames = false - }) - } - } -} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt index e8d6a72..ac79701 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/interfaces/IEventApiClient.kt @@ -3,7 +3,7 @@ package com.mindera.minderapeople.apiclient.interfaces import com.mindera.minderapeople.dto.EventDTO interface IEventApiClient { - suspend fun getEventByPolicy(userId: String, policyId: String): Result> + suspend fun getEventsByPolicy(userId: String, policyId: String): Result> suspend fun getAllEventsForUser(userId: String): Result> suspend fun editExistingEvent(userId: String, event: EventDTO): Result suspend fun removeEventById(userId: String, eventId: String): Result diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepositoryImpl.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt similarity index 89% rename from shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepositoryImpl.kt rename to shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt index c7d3b09..6e7b4cd 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/EventRepository.kt @@ -32,7 +32,7 @@ class EventRepository(private val apiClient: IEventApiClient) : IEventRepository override suspend fun getEventById(userId: String, eventId: String): Result { return apiClient.getEventById(userId, eventId) } - override suspend fun getEventByPolicy(userId: String, policyId: String): Result> { - return apiClient.getEventByPolicy(userId, policyId) + override suspend fun getEventsByPolicy(userId: String, policyId: String): Result> { + return apiClient.getEventsByPolicy(userId, policyId) } } diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt index 354d692..962b7a7 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/repository/interfaces/IEventRepository.kt @@ -21,5 +21,5 @@ interface IEventRepository { ): Result suspend fun removeEventById(userId: String, event: EventDTO): Result suspend fun getEventById(userId: String, eventId: String): Result - suspend fun getEventByPolicy(userId: String, policyId: String): Result> + suspend fun getEventsByPolicy(userId: String, policyId: String): Result> } diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/DefaultTestData.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/DefaultTestData.kt index 7be0c7b..91100bd 100644 --- a/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/DefaultTestData.kt +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/DefaultTestData.kt @@ -21,6 +21,7 @@ object DefaultTestData { //Events const val USER_ID_CORRECT = "3b1276b3-d2f6-4e29-af8f-a0cb00208dda" const val EVENT_ID_CORRECT = "f4b20503-0a59-4e76-8796-aee78726139f" + const val POLICY_ID_CORRECT = "0001" val CORRECT_EVENT = EventDTO( EVENT_ID_CORRECT, PolicyDTO( diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/EventApiClientMock.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/EventApiClientMock.kt index 485fa4d..bc7412d 100644 --- a/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/EventApiClientMock.kt +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/EventApiClientMock.kt @@ -5,6 +5,12 @@ import com.mindera.minderapeople.dto.EventDTO import io.ktor.http.* class EventApiClientMock : IEventApiClient { + override suspend fun getEventsByPolicy( + userId: String, + policyId: String + ): Result> { + TODO("Not yet implemented") + } override suspend fun getAllEventsForUser(userId: String): Result> { if (userId == DefaultTestData.USER_ID_CORRECT) { diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiclient/EventApiClientTest.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiclient/EventApiClientTest.kt index 417d049..c1d4435 100644 --- a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiclient/EventApiClientTest.kt +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/apiclient/EventApiClientTest.kt @@ -285,4 +285,101 @@ class EventApiClientTest { assertEquals(error, result.exceptionOrNull()?.message) } } + + @Test + fun `test getEventsByPolicy returns success and a list of events if successful`() { + val mockEngine = MockEngine { + respond( + content = ByteReadChannel(Json.encodeToString(listOf(DefaultTestData.CORRECT_EVENT))), + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + runBlocking { + val client = EventApiClient(mockEngine) + val result = client.getEventsByPolicy(DefaultTestData.USER_ID_CORRECT, DefaultTestData.POLICY_ID_CORRECT) + + assertTrue(result.isSuccess) + assertNotEquals(null, result.getOrNull()) + assertEquals(listOf(DefaultTestData.CORRECT_EVENT), result.getOrNull()) + } + } + + @Test + fun `test getEventsByPolicy returns failure and NotFound status if userId is incorrect`(){ + val mockEngine = MockEngine { + respond( + content = ByteReadChannel(""), + status = HttpStatusCode.NotFound, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + runBlocking { + val client = EventApiClient(mockEngine) + val result = client.getEventsByPolicy("0001", DefaultTestData.POLICY_ID_CORRECT) + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.NotFound.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getEventsByPolicy returns failure and NotFound status if policyId is incorrect`(){ + val mockEngine = MockEngine { + respond( + content = ByteReadChannel(""), + status = HttpStatusCode.NotFound, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + runBlocking { + val client = EventApiClient(mockEngine) + val result = client.getEventsByPolicy(DefaultTestData.USER_ID_CORRECT, "0001") + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.NotFound.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getEventsByPolicy returns failure and NotFound status if policyId and userId are incorrect`(){ + val mockEngine = MockEngine { + respond( + content = ByteReadChannel(""), + status = HttpStatusCode.NotFound, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + runBlocking { + val client = EventApiClient(mockEngine) + val result = client.getEventsByPolicy("0001", "0001") + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.NotFound.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getEventsByPolicy returns failure when Exception is thrown`(){ + val error = "Error occurred" + val mockEngine = MockEngine { + throw Exception(error) + } + + runBlocking { + val client = EventApiClient(mockEngine) + val result = client.getEventsByPolicy(DefaultTestData.USER_ID_CORRECT, DefaultTestData.EVENT_ID_CORRECT) + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(error, result.exceptionOrNull()?.message) + } + } } \ No newline at end of file diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/EventRepositoryTest.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/EventRepositoryTest.kt index 55b8ea8..a9b915b 100644 --- a/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/EventRepositoryTest.kt +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/unit/repository/EventRepositoryTest.kt @@ -213,4 +213,85 @@ class EventRepositoryTest { assertEquals(error, result.exceptionOrNull()?.message) } } + + @Test + fun `test getEventsByPolicy returns success and a list of events event if successful`() { + given(api).suspendFunction(api::getEventsByPolicy, fun2()) + .whenInvokedWith(oneOf(DefaultTestData.USER_ID_CORRECT), oneOf(DefaultTestData.POLICY_ID_CORRECT)) + .thenReturn(Result.success(listOf(DefaultTestData.CORRECT_EVENT))) + val eventRepo = EventRepository(api) + + runBlocking { + val result = eventRepo.getEventsByPolicy(DefaultTestData.USER_ID_CORRECT, DefaultTestData.POLICY_ID_CORRECT) + + assertTrue(result.isSuccess) + assertNotEquals(null, result.getOrNull()) + assertEquals(listOf(DefaultTestData.CORRECT_EVENT), result.getOrNull()) + } + } + + @Test + fun `test getEventsByPolicy returns failure and NotFound status if userId is incorrect`(){ + given(api).suspendFunction(api::getEventsByPolicy, fun2()) + .whenInvokedWith(oneOf("0001"), oneOf(DefaultTestData.POLICY_ID_CORRECT)) + .thenReturn(Result.failure(Exception(HttpStatusCode.NotFound.description))) + val eventRepo = EventRepository(api) + + runBlocking { + val result = eventRepo.getEventsByPolicy("0001", DefaultTestData.POLICY_ID_CORRECT) + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.NotFound.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getEventsByPolicy returns failure and NotFound status if eventId is incorrect`(){ + given(api).suspendFunction(api::getEventsByPolicy, fun2()) + .whenInvokedWith(oneOf(DefaultTestData.USER_ID_CORRECT), oneOf("0001")) + .thenReturn(Result.failure(Exception(HttpStatusCode.NotFound.description))) + val eventRepo = EventRepository(api) + + runBlocking { + val result = eventRepo.getEventsByPolicy(DefaultTestData.USER_ID_CORRECT, "0001") + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.NotFound.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getEventsByPolicy returns failure and NotFound status if eventId and userId are incorrect`(){ + given(api).suspendFunction(api::getEventsByPolicy, fun2()) + .whenInvokedWith(oneOf("0001"), oneOf("0001")) + .thenReturn(Result.failure(Exception(HttpStatusCode.NotFound.description))) + val eventRepo = EventRepository(api) + + runBlocking { + val result = eventRepo.getEventsByPolicy("0001", "0001") + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.NotFound.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getEventsByPolicy returns failure when Exception is thrown`(){ + val error = "Error occurred" + given(api).suspendFunction(api::getEventsByPolicy, fun2()) + .whenInvokedWith(oneOf(DefaultTestData.USER_ID_CORRECT), oneOf(DefaultTestData.POLICY_ID_CORRECT)) + .thenReturn(Result.failure(Exception(error))) + val eventRepo = EventRepository(api) + + runBlocking { + val result = eventRepo.getEventsByPolicy(DefaultTestData.USER_ID_CORRECT, DefaultTestData.POLICY_ID_CORRECT) + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(error, result.exceptionOrNull()?.message) + } + } } From 1bee0401931ce54353df98d1b0c724f8ee8e9cec Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Mon, 10 Apr 2023 14:23:35 +0100 Subject: [PATCH 11/13] integration tests for getEventsByPolicy --- .../event/EventIntegrationTests.kt | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/integration/event/EventIntegrationTests.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/integration/event/EventIntegrationTests.kt index 8480be6..b5d38db 100644 --- a/shared/src/commonTest/kotlin/com/mindera/minderapeople/integration/event/EventIntegrationTests.kt +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/integration/event/EventIntegrationTests.kt @@ -314,4 +314,110 @@ class EventIntegrationTests { } } + @Test + fun `test getEventsByPolicy returns success and a list of events if successful`() { + val mockEngine = MockEngine { + respond( + content = ByteReadChannel(Json.encodeToString(listOf(DefaultTestData.CORRECT_EVENT))), + status = HttpStatusCode.OK, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + val client = EventApiClient(mockEngine) + val eventRepo = EventRepository(client) + + runBlocking { + val result = eventRepo.getEventsByPolicy(DefaultTestData.USER_ID_CORRECT, DefaultTestData.POLICY_ID_CORRECT) + + assertTrue(result.isSuccess) + assertNotEquals(null, result.getOrNull()) + assertEquals(listOf(DefaultTestData.CORRECT_EVENT), result.getOrNull()) + } + } + + @Test + fun `test getEventsByPolicy returns failure and NotFound status if userId is incorrect`(){ + val mockEngine = MockEngine { + respond( + content = ByteReadChannel(""), + status = HttpStatusCode.NotFound, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + val client = EventApiClient(mockEngine) + val eventRepo = EventRepository(client) + + runBlocking { + val result = eventRepo.getEventsByPolicy("0001", DefaultTestData.POLICY_ID_CORRECT) + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.NotFound.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getEventsByPolicy returns failure and NotFound status if policyId is incorrect`(){ + val mockEngine = MockEngine { + respond( + content = ByteReadChannel(""), + status = HttpStatusCode.NotFound, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + val client = EventApiClient(mockEngine) + val eventRepo = EventRepository(client) + + runBlocking { + val result = eventRepo.getEventsByPolicy(DefaultTestData.USER_ID_CORRECT, "0001") + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.NotFound.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getEventsByPolicy returns failure and NotFound status if policyId and userId are incorrect`(){ + val mockEngine = MockEngine { + respond( + content = ByteReadChannel(""), + status = HttpStatusCode.NotFound, + headers = headersOf(HttpHeaders.ContentType, "application/json") + ) + } + + val client = EventApiClient(mockEngine) + val eventRepo = EventRepository(client) + + runBlocking { + val result = eventRepo.getEventsByPolicy("0001", "0001") + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(HttpStatusCode.NotFound.description, result.exceptionOrNull()?.message) + } + } + + @Test + fun `test getEventsByPolicy returns failure when Exception is thrown`(){ + val error = "Error occurred" + val mockEngine = MockEngine { + throw Exception(error) + } + + val client = EventApiClient(mockEngine) + val eventRepo = EventRepository(client) + + runBlocking { + val result = eventRepo.getEventsByPolicy(DefaultTestData.USER_ID_CORRECT, DefaultTestData.POLICY_ID_CORRECT) + + assertTrue(result.isFailure) + assertEquals(null, result.getOrNull()) + assertEquals(error, result.exceptionOrNull()?.message) + } + } + } \ No newline at end of file From 5cc0e26642dd8d53a2f63eae7ff968b5aba49148 Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Thu, 13 Apr 2023 16:49:09 +0100 Subject: [PATCH 12/13] using manually implemented mock instead of Mockative for getEventsByPolicy --- .../com/mindera/minderapeople/mocks/DefaultTestData.kt | 2 +- .../com/mindera/minderapeople/mocks/EventApiClientMock.kt | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/DefaultTestData.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/DefaultTestData.kt index 91100bd..4b88a34 100644 --- a/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/DefaultTestData.kt +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/DefaultTestData.kt @@ -21,7 +21,7 @@ object DefaultTestData { //Events const val USER_ID_CORRECT = "3b1276b3-d2f6-4e29-af8f-a0cb00208dda" const val EVENT_ID_CORRECT = "f4b20503-0a59-4e76-8796-aee78726139f" - const val POLICY_ID_CORRECT = "0001" + const val POLICY_ID_CORRECT = "001" val CORRECT_EVENT = EventDTO( EVENT_ID_CORRECT, PolicyDTO( diff --git a/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/EventApiClientMock.kt b/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/EventApiClientMock.kt index ec381fa..90edf76 100644 --- a/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/EventApiClientMock.kt +++ b/shared/src/commonTest/kotlin/com/mindera/minderapeople/mocks/EventApiClientMock.kt @@ -9,7 +9,10 @@ class EventApiClientMock : IEventApiClient { userId: String, policyId: String ): Result> { - TODO("Not yet implemented") + if (userId == DefaultTestData.USER_ID_CORRECT && policyId == DefaultTestData.POLICY_ID_CORRECT) { + return Result.success(listOf(DefaultTestData.CORRECT_EVENT)) + } + return Result.failure(Exception(HttpStatusCode.NotFound.description)) } override suspend fun getAllEventsForUser(userId: String): Result> { From 563f3da6c4bf495ff685df05127aace4a5ce90bd Mon Sep 17 00:00:00 2001 From: Dani Camelo Date: Thu, 11 May 2023 14:29:51 +0100 Subject: [PATCH 13/13] added newLine --- .../kotlin/com/mindera/minderapeople/apiclient/EventApiClient.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClient.kt b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClient.kt index e7ca415..fb4f047 100644 --- a/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClient.kt +++ b/shared/src/commonMain/kotlin/com/mindera/minderapeople/apiclient/EventApiClient.kt @@ -11,6 +11,7 @@ class EventApiClient(engine: HttpClientEngine) : IEventApiClient { private val apiHttpClient = ApiHttpClient(engine) private val httpClient = apiHttpClient.httpClient + override suspend fun getEventsByPolicy(userId: String, policyId: String): Result> { return try { val response = httpClient.get("${apiHttpClient.url}/events/${userId}?policy=${policyId}")