diff --git a/csv_files/audit.csv b/csv_files/audit.csv index 232cb91..3d9752a 100644 --- a/csv_files/audit.csv +++ b/csv_files/audit.csv @@ -9,6 +9,7 @@ "AUDITDDD_26090","1746816126090","user1234","CREATE","","PROJECT","newprojctrrr_26090" "AUDITDDDD_91726","1746817691726","matetttt_16791","CREATE","","TASK","tasctitlett_91718" "AUDITDD_38672","1746870738672","user1234","CREATE","","TASK","testtaskanddbaftermergedddddd_38667" +"AUDITDD_38672","1746870738672","user1234","CREATE","","TASK","testtaskanddbaftermergedddddd_38667" "AUDITD_32769","1747065232769","user1234","CREATE","","TASK","refactorcc_32751" "AUDITDDDD_14350","1747065314357","user1234","UPDATE","","TASK","refactorcc_32751" "AUDITDDDD_33128","1747065333128","user1234","DELETE","","TASK","testtaskanddbaftermergedddddd_38667" diff --git a/csv_files/task.csv b/csv_files/task.csv index 6dcce37..d760f1f 100644 --- a/csv_files/task.csv +++ b/csv_files/task.csv @@ -5,6 +5,7 @@ "tasctitlett_91718","taskmangermmmm_97132","tasc title","desc","taskmangermmmm_97132","ahmadmmmm_70365","matetttt_16791" "refactorcc_32751","newprojctrrr_26090","refactor","","tododdd_32001","ahmadmmmm_70365","user1234" "tasctitlett_91718","taskmangermmmm_97132","tasc title","desc","taskmangermmmm_97132","matetttt_16791","matetttt_16791" +"testtaskanddbaftermergedddddd_38667","newprojctrrr_26090","test task and db after merge","this a description for the test task after merge","tododdd_32001","ahmadmmmm_70365","user1234" "titlett_29143","P1","titletgtrht","riothr","S1","ahmadmmmm_70365","user1234" "titlett_29143","P1","title is add readme file","description whole app","S1","ahmadmmmm_70365","user1234" "titlett_29143","P1","title is readme file","description whole app","S1","ahmadmmmm_70365","user1234" diff --git a/src/main/kotlin/data/dto/UserDto.kt b/src/main/kotlin/data/dto/UserDto.kt index 9410e14..5908d1b 100644 --- a/src/main/kotlin/data/dto/UserDto.kt +++ b/src/main/kotlin/data/dto/UserDto.kt @@ -6,7 +6,7 @@ import org.bson.codecs.pojo.annotations.BsonProperty data class UserDto( @BsonId val id: String, - @BsonProperty("user_name") val userName: String, + @BsonProperty("username") val userName: String, @BsonProperty("password") val password: String, @BsonProperty("role") val role: User.UserRole ) \ No newline at end of file diff --git a/src/main/kotlin/data/mapper/AuditLogMapper.kt b/src/main/kotlin/data/mapper/AuditLogMapper.kt index a80f266..a047552 100644 --- a/src/main/kotlin/data/mapper/AuditLogMapper.kt +++ b/src/main/kotlin/data/mapper/AuditLogMapper.kt @@ -4,27 +4,27 @@ import com.berlin.data.dto.AuditLogDto import com.berlin.domain.model.AuditLog class AuditLogMapper : EntityMapper { - override fun mapToDomainModel(auditLogDto: AuditLogDto): AuditLog { + override fun mapToDomainModel(from: AuditLogDto): AuditLog { return AuditLog( - id = auditLogDto.id, - timestamp = auditLogDto.timestamp, - createdByUserId = auditLogDto.createdByUserId, - auditAction = auditLogDto.auditAction, - changesDescription = auditLogDto.changesDescription, - entityType = auditLogDto.entityType, - entityId = auditLogDto.entityId + id = from.id, + timestamp = from.timestamp, + createdByUserId = from.createdByUserId, + auditAction = from.auditAction, + changesDescription = from.changesDescription, + entityType = from.entityType, + entityId = from.entityId ) } - override fun mapToDataModel(auditLog: AuditLog): AuditLogDto { + override fun mapToDataModel(from: AuditLog): AuditLogDto { return AuditLogDto( - id = auditLog.id, - timestamp = auditLog.timestamp, - createdByUserId = auditLog.createdByUserId, - auditAction = auditLog.auditAction, - changesDescription = auditLog.changesDescription, - entityType = auditLog.entityType, - entityId = auditLog.entityId + id = from.id, + timestamp = from.timestamp, + createdByUserId = from.createdByUserId, + auditAction = from.auditAction, + changesDescription = from.changesDescription, + entityType = from.entityType, + entityId = from.entityId ) } } \ No newline at end of file diff --git a/src/main/kotlin/data/mapper/ProjectMapper.kt b/src/main/kotlin/data/mapper/ProjectMapper.kt index b38a35c..223fc4e 100644 --- a/src/main/kotlin/data/mapper/ProjectMapper.kt +++ b/src/main/kotlin/data/mapper/ProjectMapper.kt @@ -4,23 +4,23 @@ import com.berlin.data.dto.ProjectDto import com.berlin.domain.model.Project class ProjectMapper : EntityMapper { - override fun mapToDomainModel(projectDto: ProjectDto): Project { + override fun mapToDomainModel(from: ProjectDto): Project { return Project( - id = projectDto.id, - title = projectDto.title, - statesId = projectDto.statesId, - description = projectDto.description, - tasksId = projectDto.tasksId + id = from.id, + title = from.title, + statesId = from.statesId, + description = from.description, + tasksId = from.tasksId ) } - override fun mapToDataModel(project: Project): ProjectDto { + override fun mapToDataModel(from: Project): ProjectDto { return ProjectDto( - id = project.id, - title = project.title, - statesId = project.statesId, - description = project.description, - tasksId = project.tasksId + id = from.id, + title = from.title, + statesId = from.statesId, + description = from.description, + tasksId = from.tasksId ) } } \ No newline at end of file diff --git a/src/main/kotlin/data/mapper/TaskMapper.kt b/src/main/kotlin/data/mapper/TaskMapper.kt index 9cf8723..22646cc 100644 --- a/src/main/kotlin/data/mapper/TaskMapper.kt +++ b/src/main/kotlin/data/mapper/TaskMapper.kt @@ -4,27 +4,27 @@ import com.berlin.data.dto.TaskDto import com.berlin.domain.model.Task class TaskMapper : EntityMapper { - override fun mapToDomainModel(taskDto: TaskDto): Task { + override fun mapToDomainModel(from: TaskDto): Task { return Task( - id = taskDto.id, - title = taskDto.title, - projectId = taskDto.projectId, - description = taskDto.description, - stateId = taskDto.stateId, - assignedToUserId = taskDto.assignedToUserId, - createByUserId = taskDto.createByUserId + id = from.id, + title = from.title, + projectId = from.projectId, + description = from.description, + stateId = from.stateId, + assignedToUserId = from.assignedToUserId, + createByUserId = from.createByUserId ) } - override fun mapToDataModel(task: Task): TaskDto { + override fun mapToDataModel(from: Task): TaskDto { return TaskDto( - id = task.id, - title = task.title, - projectId = task.projectId, - description = task.description, - stateId = task.stateId, - assignedToUserId = task.assignedToUserId, - createByUserId = task.createByUserId + id = from.id, + title = from.title, + projectId = from.projectId, + description = from.description, + stateId = from.stateId, + assignedToUserId = from.assignedToUserId, + createByUserId = from.createByUserId ) } } \ No newline at end of file diff --git a/src/main/kotlin/data/mapper/TaskStateMapper.kt b/src/main/kotlin/data/mapper/TaskStateMapper.kt index 1634b6c..513ffe1 100644 --- a/src/main/kotlin/data/mapper/TaskStateMapper.kt +++ b/src/main/kotlin/data/mapper/TaskStateMapper.kt @@ -4,19 +4,19 @@ import com.berlin.data.dto.TaskStateDto import com.berlin.domain.model.TaskState class TaskStateMapper : EntityMapper { - override fun mapToDomainModel(taskStateDto: TaskStateDto): TaskState { + override fun mapToDomainModel(from: TaskStateDto): TaskState { return TaskState( - id = taskStateDto.id, - name = taskStateDto.name, - projectId = taskStateDto.projectId + id = from.id, + name = from.name, + projectId = from.projectId ) } - override fun mapToDataModel(taskState: TaskState): TaskStateDto { + override fun mapToDataModel(from: TaskState): TaskStateDto { return TaskStateDto( - id = taskState.id, - name = taskState.name, - projectId = taskState.projectId + id = from.id, + name = from.name, + projectId = from.projectId ) } } \ No newline at end of file diff --git a/src/main/kotlin/data/mapper/UserMapper.kt b/src/main/kotlin/data/mapper/UserMapper.kt index eb931d9..95b075f 100644 --- a/src/main/kotlin/data/mapper/UserMapper.kt +++ b/src/main/kotlin/data/mapper/UserMapper.kt @@ -9,21 +9,21 @@ class UserMapper( private val userDataSource: BaseDataSource, ) : EntityMapper { - override fun mapToDomainModel(userDto: UserDto): User { + override fun mapToDomainModel(from: UserDto): User { return User( - id = userDto.id, - userName = userDto.userName, - role = userDto.role + id = from.id, + userName = from.userName, + role = from.role ) } - override fun mapToDataModel(user: User): UserDto { - val userDto = userDataSource.getById(user.id) + override fun mapToDataModel(from: User): UserDto { + val userDto = userDataSource.getById(from.id) ?: throw UserNotFoundException("user not found") return UserDto( - id = user.id, - userName = user.userName, - role = user.role, + id = from.id, + userName = from.userName, + role = from.role, password = userDto.password ) } diff --git a/src/main/kotlin/data/mongodb/config/MongoConfig.kt b/src/main/kotlin/data/mongodb/config/MongoConfig.kt index c7d9305..429082b 100644 --- a/src/main/kotlin/data/mongodb/config/MongoConfig.kt +++ b/src/main/kotlin/data/mongodb/config/MongoConfig.kt @@ -9,8 +9,8 @@ import org.bson.codecs.pojo.PojoCodecProvider import com.mongodb.kotlin.client.coroutine.MongoCollection class MongoConfig( - private val connectionString: String = "mongodb+srv://diyarHussein:7p53.t@GQ4F#@2c@planmate.gzyncow.mongodb.net/?retryWrites=true&w=majority&appName=PlanMate", - private val databaseName: String = "PlanMate" + private val connectionString: String = System.getenv("MONGO_URI"), + private val databaseName: String = "TaskManager", ) { fun createMongoClient(): MongoClient { diff --git a/src/main/kotlin/data/mongodb/datasource/MongoDBauditLogDataSource.kt b/src/main/kotlin/data/mongodb/datasource/MongoDBAuditLogDataSource.kt similarity index 71% rename from src/main/kotlin/data/mongodb/datasource/MongoDBauditLogDataSource.kt rename to src/main/kotlin/data/mongodb/datasource/MongoDBAuditLogDataSource.kt index f290ea8..719dcb6 100644 --- a/src/main/kotlin/data/mongodb/datasource/MongoDBauditLogDataSource.kt +++ b/src/main/kotlin/data/mongodb/datasource/MongoDBAuditLogDataSource.kt @@ -1,34 +1,34 @@ package com.berlin.data.mongodb.datasource import com.berlin.data.BaseDataSource +import com.berlin.data.dto.AuditLogDto import com.berlin.data.mongodb.config.MongoConfig -import com.berlin.domain.model.AuditLog import com.mongodb.client.model.Filters import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.toList import kotlinx.coroutines.runBlocking -class MongoDBauditLogDataSource( +class MongoDBAuditLogDataSource( private val mongoConfig: MongoConfig -) : BaseDataSource { +) : BaseDataSource { private val client = mongoConfig.createMongoClient() private val database = mongoConfig.getDatabase(client) - private val collection = mongoConfig.getCollection(database, "audit_logs") + private val collection = mongoConfig.getCollection(database, "audit_logs") - override fun getAll(): List { + override fun getAll(): List { return runBlocking { collection.find().toList() } } - override fun getById(id: String): AuditLog? { + override fun getById(id: String): AuditLogDto? { return runBlocking { collection.find(Filters.eq("_id", id)).firstOrNull() } } - override fun update(id: String, entity: AuditLog): Boolean { + override fun update(id: String, entity: AuditLogDto): Boolean { return runBlocking { collection.replaceOne(Filters.eq("_id", id), entity).wasAcknowledged() } @@ -40,13 +40,13 @@ class MongoDBauditLogDataSource( } } - override fun write(entity: AuditLog): Boolean { + override fun write(entity: AuditLogDto): Boolean { return runBlocking { collection.insertOne(entity).wasAcknowledged() } } - override fun writeAll(entities: List): Boolean { + override fun writeAll(entities: List): Boolean { if (entities.isEmpty()) { return false } diff --git a/src/main/kotlin/data/mongodb/datasource/MongoDBProjectDataSource.kt b/src/main/kotlin/data/mongodb/datasource/MongoDBProjectDataSource.kt index 4322804..97e04e4 100644 --- a/src/main/kotlin/data/mongodb/datasource/MongoDBProjectDataSource.kt +++ b/src/main/kotlin/data/mongodb/datasource/MongoDBProjectDataSource.kt @@ -1,6 +1,7 @@ package com.berlin.data.mongodb.datasource import com.berlin.data.BaseDataSource +import com.berlin.data.dto.ProjectDto import com.berlin.data.mongodb.config.MongoConfig import com.berlin.domain.model.Project import com.mongodb.client.model.Filters @@ -10,25 +11,25 @@ import kotlinx.coroutines.runBlocking class MongoDBProjectDataSource( private val mongoConfig: MongoConfig -) : BaseDataSource { +) : BaseDataSource { private val client = mongoConfig.createMongoClient() private val database = mongoConfig.getDatabase(client) - private val collection = mongoConfig.getCollection(database, "projects") + private val collection = mongoConfig.getCollection(database, "projects") - override fun getAll(): List { + override fun getAll(): List { return runBlocking { collection.find().toList() } } - override fun getById(id: String): Project? { + override fun getById(id: String): ProjectDto? { return runBlocking { collection.find(Filters.eq("_id", id)).firstOrNull() } } - override fun update(id: String, entity: Project): Boolean { + override fun update(id: String, entity: ProjectDto): Boolean { return runBlocking { collection.replaceOne(Filters.eq("_id", id), entity).wasAcknowledged() } @@ -40,13 +41,13 @@ class MongoDBProjectDataSource( } } - override fun write(entity: Project): Boolean { + override fun write(entity: ProjectDto): Boolean { return runBlocking { collection.insertOne(entity).wasAcknowledged() } } - override fun writeAll(entities: List): Boolean { + override fun writeAll(entities: List): Boolean { if (entities.isEmpty()) { return false } diff --git a/src/main/kotlin/data/mongodb/datasource/MongoDBStateDataSource.kt b/src/main/kotlin/data/mongodb/datasource/MongoDBStateDataSource.kt index b173c1f..872d5ba 100644 --- a/src/main/kotlin/data/mongodb/datasource/MongoDBStateDataSource.kt +++ b/src/main/kotlin/data/mongodb/datasource/MongoDBStateDataSource.kt @@ -1,6 +1,7 @@ package com.berlin.data.mongodb.datasource import com.berlin.data.BaseDataSource +import com.berlin.data.dto.TaskStateDto import com.berlin.data.mongodb.config.MongoConfig import com.berlin.domain.model.TaskState import com.mongodb.client.model.Filters @@ -10,25 +11,25 @@ import kotlinx.coroutines.runBlocking class MongoDBStateDataSource( private val mongoConfig: MongoConfig -) : BaseDataSource { +) : BaseDataSource { private val client = mongoConfig.createMongoClient() private val database = mongoConfig.getDatabase(client) - private val collection = mongoConfig.getCollection(database, "states") + private val collection = mongoConfig.getCollection(database, "states") - override fun getAll(): List { + override fun getAll(): List { return runBlocking { collection.find().toList() } } - override fun getById(id: String): TaskState? { + override fun getById(id: String): TaskStateDto? { return runBlocking { collection.find(Filters.eq("_id", id)).firstOrNull() } } - override fun update(id: String, entity: TaskState): Boolean { + override fun update(id: String, entity: TaskStateDto): Boolean { return runBlocking { collection.replaceOne(Filters.eq("_id", id), entity).wasAcknowledged() } @@ -40,13 +41,13 @@ class MongoDBStateDataSource( } } - override fun write(entity: TaskState): Boolean { + override fun write(entity: TaskStateDto): Boolean { return runBlocking { collection.insertOne(entity).wasAcknowledged() } } - override fun writeAll(entities: List): Boolean { + override fun writeAll(entities: List): Boolean { if (entities.isEmpty()) { return false } diff --git a/src/main/kotlin/data/mongodb/datasource/MongoDBTaskDataSource.kt b/src/main/kotlin/data/mongodb/datasource/MongoDBTaskDataSource.kt index 2322cc7..6fb2173 100644 --- a/src/main/kotlin/data/mongodb/datasource/MongoDBTaskDataSource.kt +++ b/src/main/kotlin/data/mongodb/datasource/MongoDBTaskDataSource.kt @@ -1,6 +1,7 @@ package com.berlin.data.mongodb.datasource import com.berlin.data.BaseDataSource +import com.berlin.data.dto.TaskDto import com.berlin.data.mongodb.config.MongoConfig import com.berlin.domain.model.Task import com.mongodb.client.model.Filters @@ -10,25 +11,25 @@ import kotlinx.coroutines.runBlocking class MongoDBTaskDataSource( private val mongoConfig: MongoConfig -) : BaseDataSource { +) : BaseDataSource { private val client = mongoConfig.createMongoClient() private val database = mongoConfig.getDatabase(client) - private val collection = mongoConfig.getCollection(database, "tasks") + private val collection = mongoConfig.getCollection(database, "tasks") - override fun getAll(): List { + override fun getAll(): List { return runBlocking { collection.find().toList() } } - override fun getById(id: String): Task? { + override fun getById(id: String): TaskDto? { return runBlocking { collection.find(Filters.eq("_id", id)).firstOrNull() } } - override fun update(id: String, entity: Task): Boolean { + override fun update(id: String, entity: TaskDto): Boolean { return runBlocking { collection.replaceOne(Filters.eq("_id", id), entity).wasAcknowledged() } @@ -40,13 +41,13 @@ class MongoDBTaskDataSource( } } - override fun write(entity: Task): Boolean { + override fun write(entity: TaskDto): Boolean { return runBlocking { collection.insertOne(entity).wasAcknowledged() } } - override fun writeAll(entities: List): Boolean { + override fun writeAll(entities: List): Boolean { if (entities.isEmpty()) { return false } diff --git a/src/main/kotlin/data/mongodb/datasource/MongoDBUserDataSource.kt b/src/main/kotlin/data/mongodb/datasource/MongoDBUserDataSource.kt index 21c549a..933e43e 100644 --- a/src/main/kotlin/data/mongodb/datasource/MongoDBUserDataSource.kt +++ b/src/main/kotlin/data/mongodb/datasource/MongoDBUserDataSource.kt @@ -1,8 +1,8 @@ package com.berlin.data.mongodb.datasource import com.berlin.data.BaseDataSource +import com.berlin.data.dto.UserDto import com.berlin.data.mongodb.config.MongoConfig -import com.berlin.domain.model.user.User import com.mongodb.client.model.Filters import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.toList @@ -10,25 +10,25 @@ import kotlinx.coroutines.runBlocking class MongoDBUserDataSource( private val mongoConfig: MongoConfig -) : BaseDataSource { +) : BaseDataSource { private val client = mongoConfig.createMongoClient() private val database = mongoConfig.getDatabase(client) - private val collection = mongoConfig.getCollection(database, "users") + private val collection = mongoConfig.getCollection(database, "users") - override fun getAll(): List { + override fun getAll(): List { return runBlocking { collection.find().toList() } } - override fun getById(id: String): User? { + override fun getById(id: String): UserDto? { return runBlocking { collection.find(Filters.eq("_id", id)).firstOrNull() } } - override fun update(id: String, entity: User): Boolean { + override fun update(id: String, entity: UserDto): Boolean { return runBlocking { collection.replaceOne(Filters.eq("_id", id), entity).wasAcknowledged() } @@ -40,13 +40,13 @@ class MongoDBUserDataSource( } } - override fun write(entity: User): Boolean { + override fun write(entity: UserDto): Boolean { return runBlocking { collection.insertOne(entity).wasAcknowledged() } } - override fun writeAll(entities: List): Boolean { + override fun writeAll(entities: List): Boolean { if (entities.isEmpty()) { return false } diff --git a/src/main/kotlin/di/appModule.kt b/src/main/kotlin/di/appModule.kt index 9a4c79e..a58fba1 100644 --- a/src/main/kotlin/di/appModule.kt +++ b/src/main/kotlin/di/appModule.kt @@ -5,5 +5,5 @@ import org.koin.dsl.module val appModule = module { - includes(dataModule, repositoryModule, uiModule, useCaseModule) + includes(dataModule, repositoryModule, useCaseModule, uiModule) } diff --git a/src/main/kotlin/di/dataModule.kt b/src/main/kotlin/di/dataModule.kt index 86de66f..f6ae7d7 100644 --- a/src/main/kotlin/di/dataModule.kt +++ b/src/main/kotlin/di/dataModule.kt @@ -1,12 +1,10 @@ package com.berlin.di import com.berlin.data.BaseDataSource -import com.berlin.data.csv_data_source.CsvDataSource -import com.berlin.data.csv_data_source.schema.* +import com.berlin.data.mongodb.datasource.* import com.berlin.data.dto.* import com.berlin.data.mapper.* import com.berlin.data.mongodb.config.MongoConfig -import com.berlin.data.mongodb.datasource.* import com.berlin.domain.model.* import com.berlin.domain.model.user.User import com.berlin.domain.usecase.utils.hash_algorithm.HashingString @@ -22,73 +20,34 @@ import org.koin.dsl.module val dataModule = module { - singleOf(::IdGeneratorImplementation) bind IdGenerator::class - singleOf(::MD5Hasher) bind HashingString::class - - single { AdminUserProvider(get(named("UserDtoDataSource")), get()) } - single { UserCache(get().load()) } - - single>(named("UserSchema")) { - UserSchema( - fileName = "user.csv", header = listOf("User Id", "UserName", "Password", "User Role") - ) - } - single>(named("ProjectSchema")) { - ProjectSchema( - fileName = "project.csv", header = listOf("Project Id", "Project Name", "Description", "States", "Tasks") - ) - } - single>(named("AuditSchema")) { - AuditSchema( - fileName = "audit.csv", header = listOf( - "Audit Id", "Timestamp", "CreatedBy", "Audit Action", "Changes Description", "Entity Type", "Entity Id" - ) - ) - } - single>(named("StateSchema")) { - TaskStateSchema( - fileName = "state.csv", header = listOf("State Id", "Name", "Project Id") - ) - } - single>(named("TaskSchema")) { - TaskSchema( - fileName = "task.csv", header = listOf( - "Task Id", "Project Id", "Title", "Description", "State Id", "Assigned To User Id", "Create By User Id" - ) - ) - } single { MongoConfig() } - single> { CsvDataSource("csv_files", get(named("TaskSchema"))) } - single>(named("mongoDbStateDataSource")) { MongoDBStateDataSource(get()) } - single>(named("mongoDbProjectDataSource")) { MongoDBProjectDataSource(get()) } - single>(named("mongoDbAuditLogDataSource")) { MongoDBauditLogDataSource(get()) } - single>(named("mongoDbUserDataSource")) { MongoDBUserDataSource(get()) } + singleOf(::IdGeneratorImplementation) bind IdGenerator::class + singleOf(::MD5Hasher) bind HashingString::class - single>(named("AuditDataSource")) { CsvDataSource("csv_files", get(named("AuditSchema"))) } + single>(named(DatasourceQualifier.TASK_DATASOURCE)) { MongoDBTaskDataSource(get()) } + single>(named(DatasourceQualifier.TASK_STATE_DATASOURCE)) { MongoDBStateDataSource(get()) } + single>(named(DatasourceQualifier.PROJECT_DATASOURCE)) { MongoDBProjectDataSource(get()) } + single>(named(DatasourceQualifier.AUDIT_LOG_DATASOURCE)) { MongoDBAuditLogDataSource(get()) } + single>(named(DatasourceQualifier.USER_DATASOURCE)) { MongoDBUserDataSource(get()) } - single>(named("UserDataSource")) { CsvDataSource("csv_files", get(named("UserSchema"))) } - single>(named("ProjectDataSource")) { - CsvDataSource( - "csv_files", get(named("ProjectSchema")) - ) - } - single>(named("UserDtoDataSource")) { - CsvDataSource("csv_files", get(named("UserSchema"))) - } - single>(named("TaskDataSource")) { CsvDataSource("csv_files", get(named("TaskSchema"))) } - single>(named("StateDataSource")) { - CsvDataSource( - "csv_files", get(named("StateSchema")) - ) - } - single>(named("AuditDataSource")) { CsvDataSource("csv_files", get(named("AuditSchema"))) } + single { AdminUserProvider(get(named(DatasourceQualifier.USER_DATASOURCE)), get()) } + single { UserCache(get().load()) } single { TaskMapper() }.bind>() single { ProjectMapper() }.bind>() single { TaskStateMapper() }.bind>() - single { UserMapper(get()) }.bind>() + single { UserMapper(get(named(DatasourceQualifier.USER_DATASOURCE)))}.bind>() single { AuditLogMapper() }.bind>() + } +object DatasourceQualifier { + const val TASK_DATASOURCE = "mongoDbTaskDataSource" + const val TASK_STATE_DATASOURCE = "mongoDbStateDataSource" + const val PROJECT_DATASOURCE = "mongoDbProjectDataSource" + const val AUDIT_LOG_DATASOURCE = "mongoDbAuditLogDataSource" + const val USER_DATASOURCE = "mongoDbUserDataSource" + +} \ No newline at end of file diff --git a/src/main/kotlin/di/repositoryModule.kt b/src/main/kotlin/di/repositoryModule.kt index 6c3f64c..55f1833 100644 --- a/src/main/kotlin/di/repositoryModule.kt +++ b/src/main/kotlin/di/repositoryModule.kt @@ -14,31 +14,34 @@ val repositoryModule = module { single { ProjectRepositoryImpl( - get(named("ProjectDataSource")), get() + get(named(DatasourceQualifier.PROJECT_DATASOURCE)), get() ) } single { TaskRepositoryImpl( - get(named("TaskDataSource")), get() + get(named(DatasourceQualifier.TASK_DATASOURCE)), get() ) } single { AuditRepositoryImpl( - get(named("AuditDataSource")), get() + get(named(DatasourceQualifier.AUDIT_LOG_DATASOURCE)), get() ) } single { TaskStateRepositoryImpl( - get(named("StateDataSource")), get(), get(), get() + get(named(DatasourceQualifier.TASK_STATE_DATASOURCE)), + get(named(DatasourceQualifier.TASK_DATASOURCE)), + get(), + get() ) } single { AuthenticationRepositoryImpl( - get(), get(named("UserDataSource")), get() + get(), get(named(DatasourceQualifier.USER_DATASOURCE)), get() ) } } diff --git a/src/test/kotlin/data/audit/AuditRepositoryImplTest.kt b/src/test/kotlin/data/audit/AuditRepositoryImplTest.kt new file mode 100644 index 0000000..e69de29 diff --git a/src/test/kotlin/data/mongodb/datasource/MongoDBAuditLogDataSourceTest.kt b/src/test/kotlin/data/mongodb/datasource/MongoDBAuditLogDataSourceTest.kt new file mode 100644 index 0000000..9340aaa --- /dev/null +++ b/src/test/kotlin/data/mongodb/datasource/MongoDBAuditLogDataSourceTest.kt @@ -0,0 +1,240 @@ +package com.berlin.data.mongodb.datasource + +import com.berlin.data.dto.AuditLogDto +import com.berlin.data.mongodb.config.MongoConfig +import com.berlin.domain.model.AuditLog +import com.google.common.truth.Truth.assertThat +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import com.mongodb.client.result.DeleteResult +import com.mongodb.client.result.InsertManyResult +import com.mongodb.client.result.InsertOneResult +import com.mongodb.client.result.UpdateResult +import kotlinx.coroutines.flow.FlowCollector +import org.bson.conversions.Bson +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.Lifecycle + +@TestInstance(Lifecycle.PER_CLASS) +class MongoDBAuditLogDataSourceTest { + + private lateinit var dataSource: MongoDBAuditLogDataSource + private val mockMongoConfig = mockk() + private val mockCollection = mockk>() + private val mockMongoClient = mockk() + private val mockMongoDatabase = mockk() + private val mockFindPublisher = mockk>() + + private val mockAuditLog = AuditLogDto( + id = "log1", + timestamp = 1717027200, + createdByUserId = "user1", + auditAction = AuditLog.AuditAction.CREATE, + changesDescription = "Initial creation", + entityType = AuditLog.EntityType.TASK, + entityId = "task1" + ) + + private val mockAuditLogs = listOf( + mockAuditLog, + AuditLogDto( + id = "log2", + timestamp = 1717027300, + createdByUserId = "user2", + auditAction = AuditLog.AuditAction.UPDATE, + changesDescription = "Status changed", + entityType = AuditLog.EntityType.TASK, + entityId = "task1" + ) + ) + + @BeforeEach + fun setUp() { + every { mockMongoConfig.createMongoClient() } returns mockMongoClient + every { mockMongoConfig.getDatabase(mockMongoClient) } returns mockMongoDatabase + every { mockMongoConfig.getCollection(mockMongoDatabase, "audit_logs") } returns mockCollection + + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockAuditLog) + } + + dataSource = MongoDBAuditLogDataSource(mockMongoConfig) + } + + @Test + fun `getAll should return list of audit logs`() { + // Given + coEvery { mockCollection.find() } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + mockAuditLogs.forEach { collector.emit(it) } + } + + // When + val result = dataSource.getAll() + + // Then + assertThat(result).isEqualTo(mockAuditLogs) + } + + @Test + fun `getById should return audit log when found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockAuditLog) + } + + // When + val result = dataSource.getById("log1") + + // Then + assertThat(result).isEqualTo(mockAuditLog) + } + + @Test + fun `getById should return null when not found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { } + + // When + val result = dataSource.getById("nonexistent") + + // Then + assertThat(result).isNull() + } + + @Test + fun `update should return true when acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns true + + coEvery { + mockCollection.replaceOne( + any(), + any(), + any() + ) + } returns mockUpdateResult + + // When + val result = dataSource.update("log1", mockAuditLog) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `update should return false when not acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns false + coEvery { mockCollection.replaceOne(any(), any(), any()) } returns mockUpdateResult + + // When + val result = dataSource.update("log1", mockAuditLog) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `delete should return true when acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns true + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("log1") + + // Then + assertThat(result).isTrue() + } + + @Test + fun `delete should return false when not acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns false + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("log1") + + // Then + assertThat(result).isFalse() + } + + @Test + fun `write should return true when acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockAuditLog) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `write should return false when not acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockAuditLog) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return true when acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockAuditLogs) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `writeAll should return false when not acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockAuditLogs) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return false when list is empty`() { + // When + val result = dataSource.writeAll(emptyList()) + + // Then + assertThat(result).isFalse() + } +} \ No newline at end of file diff --git a/src/test/kotlin/data/mongodb/datasource/MongoDBProjectDataSourceTest.kt b/src/test/kotlin/data/mongodb/datasource/MongoDBProjectDataSourceTest.kt new file mode 100644 index 0000000..1d92876 --- /dev/null +++ b/src/test/kotlin/data/mongodb/datasource/MongoDBProjectDataSourceTest.kt @@ -0,0 +1,236 @@ +package com.berlin.data.mongodb.datasource + +import com.berlin.data.dto.ProjectDto +import com.berlin.data.mongodb.config.MongoConfig +import com.berlin.domain.model.Project +import com.google.common.truth.Truth.assertThat +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import com.mongodb.client.result.DeleteResult +import com.mongodb.client.result.InsertManyResult +import com.mongodb.client.result.InsertOneResult +import com.mongodb.client.result.UpdateResult +import kotlinx.coroutines.flow.FlowCollector +import org.bson.conversions.Bson +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.Lifecycle + +@TestInstance(Lifecycle.PER_CLASS) +class MongoDBProjectDataSourceTest { + + private lateinit var dataSource: MongoDBProjectDataSource + private val mockMongoConfig = mockk() + private val mockCollection = mockk>() + private val mockMongoClient = mockk() + private val mockMongoDatabase = mockk() + private val mockFindPublisher = mockk>() + + private val mockProject = ProjectDto( + id = "project1", + title = "Task Manager", + description = "Manage tasks efficiently", + statesId = listOf("state1", "state2"), + tasksId = listOf("task1", "task2") + ) + + private val mockProjects = listOf( + mockProject, + ProjectDto( + id = "project2", + title = "Marketing Campaign", + description = null, + statesId = emptyList(), + tasksId = null + ) + ) + + @BeforeEach + fun setUp() { + every { mockMongoConfig.createMongoClient() } returns mockMongoClient + every { mockMongoConfig.getDatabase(mockMongoClient) } returns mockMongoDatabase + every { mockMongoConfig.getCollection(mockMongoDatabase, "projects") } returns mockCollection + + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockProject) + } + + dataSource = MongoDBProjectDataSource(mockMongoConfig) + } + + @Test + fun `getAll should return list of projects`() { + // Given + coEvery { mockCollection.find() } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + mockProjects.forEach { collector.emit(it) } + } + + // When + val result = dataSource.getAll() + + // Then + assertThat(result).isEqualTo(mockProjects) + } + + @Test + fun `getById should return project when found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockProject) + } + + // When + val result = dataSource.getById("project1") + + // Then + assertThat(result).isEqualTo(mockProject) + } + + @Test + fun `getById should return null when not found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { } + + // When + val result = dataSource.getById("nonexistent") + + // Then + assertThat(result).isNull() + } + + @Test + fun `update should return true when acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns true + + coEvery { + mockCollection.replaceOne( + any(), + any(), + any() + ) + } returns mockUpdateResult + + // When + val result = dataSource.update("project1", mockProject) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `update should return false when not acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns false + coEvery { mockCollection.replaceOne(any(), any(), any()) } returns mockUpdateResult + + // When + val result = dataSource.update("project1", mockProject) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `delete should return true when acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns true + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("project1") + + // Then + assertThat(result).isTrue() + } + + @Test + fun `delete should return false when not acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns false + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("project1") + + // Then + assertThat(result).isFalse() + } + + @Test + fun `write should return true when acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockProject) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `write should return false when not acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockProject) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return true when acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockProjects) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `writeAll should return false when not acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockProjects) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return false when list is empty`() { + // When + val result = dataSource.writeAll(emptyList()) + + // Then + assertThat(result).isFalse() + } +} \ No newline at end of file diff --git a/src/test/kotlin/data/mongodb/datasource/MongoDBStateDataSourceTest.kt b/src/test/kotlin/data/mongodb/datasource/MongoDBStateDataSourceTest.kt new file mode 100644 index 0000000..3049870 --- /dev/null +++ b/src/test/kotlin/data/mongodb/datasource/MongoDBStateDataSourceTest.kt @@ -0,0 +1,231 @@ +package com.berlin.data.mongodb.datasource + +import com.berlin.data.dto.TaskStateDto +import com.berlin.data.mongodb.config.MongoConfig +import com.google.common.truth.Truth.assertThat +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import com.mongodb.client.result.DeleteResult +import com.mongodb.client.result.InsertManyResult +import com.mongodb.client.result.InsertOneResult +import com.mongodb.client.result.UpdateResult +import kotlinx.coroutines.flow.FlowCollector +import org.bson.conversions.Bson +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.Lifecycle + +@TestInstance(Lifecycle.PER_CLASS) +class MongoDBStateDataSourceTest { + + private lateinit var dataSource: MongoDBStateDataSource + private val mockMongoConfig = mockk() + private val mockCollection = mockk>() + private val mockMongoClient = mockk() + private val mockMongoDatabase = mockk() + private val mockFindPublisher = mockk>() + + private val mockState = TaskStateDto( + id = "state1", + name = "Todo", + projectId = "project1" + ) + + private val mockStates = listOf( + mockState, + TaskStateDto( + id = "state2", + name = "In Progress", + projectId = "project1" + ) + ) + + @BeforeEach + fun setUp() { + every { mockMongoConfig.createMongoClient() } returns mockMongoClient + every { mockMongoConfig.getDatabase(mockMongoClient) } returns mockMongoDatabase + every { mockMongoConfig.getCollection(mockMongoDatabase, "states") } returns mockCollection + + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockState) + } + + dataSource = MongoDBStateDataSource(mockMongoConfig) + } + + @Test + fun `getAll should return list of states`() { + // Given + coEvery { mockCollection.find() } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + mockStates.forEach { collector.emit(it) } + } + + // When + val result = dataSource.getAll() + + // Then + assertThat(result).isEqualTo(mockStates) + } + + @Test + fun `getById should return state when found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockState) + } + + // When + val result = dataSource.getById("state1") + + // Then + assertThat(result).isEqualTo(mockState) + } + + @Test + fun `getById should return null when not found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { } + + // When + val result = dataSource.getById("nonexistent") + + // Then + assertThat(result).isNull() + } + + @Test + fun `update should return true when acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns true + + coEvery { + mockCollection.replaceOne( + any(), + any(), + any() + ) + } returns mockUpdateResult + + // When + val result = dataSource.update("state1", mockState) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `update should return false when not acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns false + coEvery { mockCollection.replaceOne(any(), any(), any()) } returns mockUpdateResult + + // When + val result = dataSource.update("state1", mockState) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `delete should return true when acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns true + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("state1") + + // Then + assertThat(result).isTrue() + } + + @Test + fun `delete should return false when not acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns false + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("state1") + + // Then + assertThat(result).isFalse() + } + + @Test + fun `write should return true when acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockState) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `write should return false when not acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockState) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return true when acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockStates) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `writeAll should return false when not acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockStates) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return false when list is empty`() { + // When + val result = dataSource.writeAll(emptyList()) + + // Then + assertThat(result).isFalse() + } +} \ No newline at end of file diff --git a/src/test/kotlin/data/mongodb/datasource/MongoDBTaskDataSourceTest.kt b/src/test/kotlin/data/mongodb/datasource/MongoDBTaskDataSourceTest.kt new file mode 100644 index 0000000..69c469a --- /dev/null +++ b/src/test/kotlin/data/mongodb/datasource/MongoDBTaskDataSourceTest.kt @@ -0,0 +1,240 @@ +package com.berlin.data.mongodb.datasource + +import com.berlin.data.dto.TaskDto +import com.berlin.data.mongodb.config.MongoConfig +import com.berlin.domain.model.Task +import com.google.common.truth.Truth.assertThat +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import com.mongodb.client.result.DeleteResult +import com.mongodb.client.result.InsertManyResult +import com.mongodb.client.result.InsertOneResult +import com.mongodb.client.result.UpdateResult +import kotlinx.coroutines.flow.FlowCollector +import org.bson.conversions.Bson +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.Lifecycle + +@TestInstance(Lifecycle.PER_CLASS) +class MongoDBTaskDataSourceTest { + + private lateinit var dataSource: MongoDBTaskDataSource + private val mockMongoConfig = mockk() + private val mockCollection = mockk>() + private val mockMongoClient = mockk() + private val mockMongoDatabase = mockk() + private val mockFindPublisher = mockk>() + + private val mockTask = TaskDto( + id = "task1", + projectId = "project1", + title = "Test Task", + description = "Task description", + stateId = "todo", + assignedToUserId = "user1", + createByUserId = "user2" + ) + + private val mockTasks = listOf( + mockTask, + TaskDto( + id = "task2", + projectId = "project1", + title = "Another Task", + description = null, + stateId = "in_progress", + assignedToUserId = "user3", + createByUserId = "user2" + ) + ) + + @BeforeEach + fun setUp() { + every { mockMongoConfig.createMongoClient() } returns mockMongoClient + every { mockMongoConfig.getDatabase(mockMongoClient) } returns mockMongoDatabase + every { mockMongoConfig.getCollection(mockMongoDatabase, "tasks") } returns mockCollection + + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockTask) + } + + dataSource = MongoDBTaskDataSource(mockMongoConfig) + } + + @Test + fun `getAll should return list of tasks`() { + // Given + coEvery { mockCollection.find() } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + mockTasks.forEach { collector.emit(it) } + } + + // When + val result = dataSource.getAll() + + // Then + assertThat(result).isEqualTo(mockTasks) + } + + @Test + fun `getById should return task when found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockTask) + } + + // When + val result = dataSource.getById("task1") + + // Then + assertThat(result).isEqualTo(mockTask) + } + + @Test + fun `getById should return null when not found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { } // Emit nothing + + // When + val result = dataSource.getById("nonexistent") + + // Then + assertThat(result).isNull() + } + + @Test + fun `update should return true when acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns true + + coEvery { + mockCollection.replaceOne( + any(), + any(), + any() + ) + } returns mockUpdateResult + + // When + val result = dataSource.update("task1", mockTask) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `update should return false when not acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns false + coEvery { mockCollection.replaceOne(any(), any(), any()) } returns mockUpdateResult + + // When + val result = dataSource.update("task1", mockTask) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `delete should return true when acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns true + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("task1") + + // Then + assertThat(result).isTrue() + } + + @Test + fun `delete should return false when not acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns false + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("task1") + + // Then + assertThat(result).isFalse() + } + + @Test + fun `write should return true when acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockTask) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `write should return false when not acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockTask) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return true when acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockTasks) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `writeAll should return false when not acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockTasks) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return false when list is empty`() { + // When + val result = dataSource.writeAll(emptyList()) + + // Then + assertThat(result).isFalse() + } +} \ No newline at end of file diff --git a/src/test/kotlin/data/mongodb/datasource/MongoDBUserDataSourceTest.kt b/src/test/kotlin/data/mongodb/datasource/MongoDBUserDataSourceTest.kt new file mode 100644 index 0000000..8a516a1 --- /dev/null +++ b/src/test/kotlin/data/mongodb/datasource/MongoDBUserDataSourceTest.kt @@ -0,0 +1,234 @@ +package com.berlin.data.mongodb.datasource + +import com.berlin.data.dto.UserDto +import com.berlin.data.mongodb.config.MongoConfig +import com.berlin.domain.model.user.User +import com.google.common.truth.Truth.assertThat +import io.mockk.coEvery +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import com.mongodb.client.result.DeleteResult +import com.mongodb.client.result.InsertManyResult +import com.mongodb.client.result.InsertOneResult +import com.mongodb.client.result.UpdateResult +import kotlinx.coroutines.flow.FlowCollector +import org.bson.conversions.Bson +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestInstance.Lifecycle + +@TestInstance(Lifecycle.PER_CLASS) +class MongoDBUserDataSourceTest { + + private lateinit var dataSource: MongoDBUserDataSource + private val mockMongoConfig = mockk() + private val mockCollection = mockk>() + private val mockMongoClient = mockk() + private val mockMongoDatabase = mockk() + private val mockFindPublisher = mockk>() + + private val mockUser = UserDto( + id = "user1", + userName = "admin", + password = "secure123", + role = User.UserRole.ADMIN + ) + + private val mockUsers = listOf( + mockUser, + UserDto( + id = "user2", + userName = "mate", + password = "pass456", + role = User.UserRole.MATE + ) + ) + + @BeforeEach + fun setUp() { + every { mockMongoConfig.createMongoClient() } returns mockMongoClient + every { mockMongoConfig.getDatabase(mockMongoClient) } returns mockMongoDatabase + every { mockMongoConfig.getCollection(mockMongoDatabase, "users") } returns mockCollection + + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockUser) + } + + dataSource = MongoDBUserDataSource(mockMongoConfig) + } + + @Test + fun `getAll should return list of users`() { + // Given + coEvery { mockCollection.find() } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + mockUsers.forEach { collector.emit(it) } + } + + // When + val result = dataSource.getAll() + + // Then + assertThat(result).isEqualTo(mockUsers) + } + + @Test + fun `getById should return user when found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { + val collector = arg>(0) + collector.emit(mockUser) + } + + // When + val result = dataSource.getById("user1") + + // Then + assertThat(result).isEqualTo(mockUser) + } + + @Test + fun `getById should return null when not found`() { + // Given + coEvery { mockCollection.find(any()) } returns mockFindPublisher + coEvery { mockFindPublisher.collect(any()) } coAnswers { } + + // When + val result = dataSource.getById("nonexistent") + + // Then + assertThat(result).isNull() + } + + @Test + fun `update should return true when acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns true + + coEvery { + mockCollection.replaceOne( + any(), + any(), + any() + ) + } returns mockUpdateResult + + // When + val result = dataSource.update("user1", mockUser) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `update should return false when not acknowledged`() { + // Given + val mockUpdateResult = mockk() + every { mockUpdateResult.wasAcknowledged() } returns false + coEvery { mockCollection.replaceOne(any(), any(), any()) } returns mockUpdateResult + + // When + val result = dataSource.update("user1", mockUser) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `delete should return true when acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns true + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("user1") + + // Then + assertThat(result).isTrue() + } + + @Test + fun `delete should return false when not acknowledged`() { + // Given + val mockDeleteResult = mockk() + every { mockDeleteResult.wasAcknowledged() } returns false + coEvery { mockCollection.deleteOne(any(), any()) } returns mockDeleteResult + + // When + val result = dataSource.delete("user1") + + // Then + assertThat(result).isFalse() + } + + @Test + fun `write should return true when acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockUser) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `write should return false when not acknowledged`() { + // Given + val mockInsertOneResult = mockk() + every { mockInsertOneResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertOne(any(), any()) } returns mockInsertOneResult + + // When + val result = dataSource.write(mockUser) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return true when acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns true + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockUsers) + + // Then + assertThat(result).isTrue() + } + + @Test + fun `writeAll should return false when not acknowledged`() { + // Given + val mockInsertManyResult = mockk() + every { mockInsertManyResult.wasAcknowledged() } returns false + coEvery { mockCollection.insertMany(any>(), any()) } returns mockInsertManyResult + + // When + val result = dataSource.writeAll(mockUsers) + + // Then + assertThat(result).isFalse() + } + + @Test + fun `writeAll should return false when list is empty`() { + // When + val result = dataSource.writeAll(emptyList()) + + // Then + assertThat(result).isFalse() + } +} \ No newline at end of file