From 890c84c762151f669b9d5733a603bb755321e37d Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Tue, 17 Mar 2020 14:53:56 +0100 Subject: [PATCH] #42 Add tests for WorkgroupVoter --- .../kotlin/fr/dcproject/entity/Workgroup.kt | 6 +- .../security/voter/WorkgroupVoter.kt | 17 +- .../security/voter/WorkgroupVoterTest.kt | 204 ++++++++++++++++++ 3 files changed, 211 insertions(+), 16 deletions(-) create mode 100644 src/test/kotlin/fr/dcproject/security/voter/WorkgroupVoterTest.kt diff --git a/src/main/kotlin/fr/dcproject/entity/Workgroup.kt b/src/main/kotlin/fr/dcproject/entity/Workgroup.kt index 8780ecc..e507271 100644 --- a/src/main/kotlin/fr/dcproject/entity/Workgroup.kt +++ b/src/main/kotlin/fr/dcproject/entity/Workgroup.kt @@ -6,7 +6,7 @@ import fr.postgresjson.entity.mutable.EntityDeletedAtImp import java.util.* class Workgroup( - id: UUID?, + id: UUID? = null, name: String, description: String, logo: String? = null, @@ -28,7 +28,7 @@ class Workgroup( EntityUpdatedAt by EntityUpdatedAtImp() open class WorkgroupSimple( - id: UUID?, + id: UUID? = null, var name: String, var description: String, var logo: String? = null, @@ -40,7 +40,7 @@ open class WorkgroupSimple( EntityDeletedAt by EntityDeletedAtImp() open class WorkgroupRef( - id: UUID? + id: UUID? = null ) : UuidEntity(id ?: UUID.randomUUID()), WorkgroupI interface WorkgroupWithAuthI : WorkgroupWithMembersI, EntityCreatedBy, EntityDeletedAt { diff --git a/src/main/kotlin/fr/dcproject/security/voter/WorkgroupVoter.kt b/src/main/kotlin/fr/dcproject/security/voter/WorkgroupVoter.kt index ee0e604..f2cf2f3 100644 --- a/src/main/kotlin/fr/dcproject/security/voter/WorkgroupVoter.kt +++ b/src/main/kotlin/fr/dcproject/security/voter/WorkgroupVoter.kt @@ -15,7 +15,7 @@ class WorkgroupVoter : Voter { override fun supports(action: ActionI, call: ApplicationCall, subject: Any?): Boolean { return (action is Action) - .and(subject is List<*> || subject is WorkgroupI?) + .and(subject is WorkgroupI?) } override fun vote(action: ActionI, call: ApplicationCall, subject: Any?): Vote { @@ -31,14 +31,6 @@ class WorkgroupVoter : Voter { else if (subject.anonymous && user != null && subject.isMember(user)) Vote.GRANTED else Vote.DENIED } - if (subject is List<*>) { - subject.forEach { - if (it !is WorkgroupWithAuthI<*> || it.isDeleted()) { - return Vote.DENIED - } - } - return Vote.GRANTED - } return Vote.DENIED } @@ -52,10 +44,9 @@ class WorkgroupVoter : Voter { } return Vote.DENIED - } - - if (action is Action) { - return Vote.DENIED + } else if (subject !is WorkgroupWithAuthI<*> && (action == Action.DELETE || action == Action.UPDATE)) { + throw object : + VoterException("Unable to define if your are granted, the subject must implement 'WorkgroupWithAuthI'") {} } return Vote.ABSTAIN diff --git a/src/test/kotlin/fr/dcproject/security/voter/WorkgroupVoterTest.kt b/src/test/kotlin/fr/dcproject/security/voter/WorkgroupVoterTest.kt new file mode 100644 index 0000000..5179274 --- /dev/null +++ b/src/test/kotlin/fr/dcproject/security/voter/WorkgroupVoterTest.kt @@ -0,0 +1,204 @@ +package fr.dcproject.security.voter + +import fr.dcproject.entity.* +import io.ktor.application.ApplicationCall +import io.ktor.locations.KtorExperimentalLocationsAPI +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import org.amshove.kluent.`should be` +import org.joda.time.DateTime +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import fr.dcproject.entity.Workgroup as WorkgroupEntity + +@KtorExperimentalLocationsAPI +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@Tag("voter") +internal class WorkgroupVoterTest { + private val tesla = CitizenBasic( + user = User( + username = "nicolas-tesla", + roles = listOf(UserI.Roles.ROLE_USER) + ), + birthday = DateTime.now(), + email = "tesla@best.com", + name = CitizenI.Name("Nicolas", "Tesla"), + followAnonymous = false + ) + + private val einstein = CitizenBasic( + user = User( + username = "albert-einstein", + roles = listOf(UserI.Roles.ROLE_USER) + ), + birthday = DateTime.now(), + email = "einstein@best.com", + name = CitizenI.Name("Albert", "Einstein"), + followAnonymous = true + ) + + private val article1 = Article( + content = "Hi", + createdBy = einstein, + description = "blablabla", + title = "Super article" + ) + + private val workgroupPublic = WorkgroupEntity( + createdBy = tesla, + description = "Super desc", + name = "super name", + owner = tesla, + anonymous = false + ) + + private val workgroupAnon = WorkgroupEntity( + createdBy = tesla, + description = "Super desc", + name = "super name", + owner = tesla, + anonymous = true + ) + + private val workgroupref = WorkgroupRef() + + init { + mockkStatic("fr.dcproject.security.voter.VoterKt") + } + + @Test + fun `support workgroup`() = WorkgroupVoter().run { + val p = object : ActionI {} + mockk { + every { user } returns tesla.user + }.let { + supports(WorkgroupVoter.Action.VIEW, it, workgroupPublic) `should be` true + supports(WorkgroupVoter.Action.VIEW, it, article1) `should be` false + supports(p, it, workgroupPublic) `should be` false + } + } + + @Test + fun `can be view your workgroup`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns tesla.user + }.let { + can(WorkgroupVoter.Action.VIEW, it, workgroupPublic) `should be` true + } + } + + @Test + fun `can be view your workgroup if is not public`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns tesla.user + }.let { + can(WorkgroupVoter.Action.VIEW, it, workgroupAnon) `should be` true + } + } + + @Test + fun `can be view workgroup of other if is public`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns einstein.user + }.let { + can(WorkgroupVoter.Action.VIEW, it, workgroupPublic) `should be` true + } + } + + @Test + fun `can not be view workgroup of other if is not public`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns einstein.user + }.let { + can(WorkgroupVoter.Action.VIEW, it, workgroupAnon) `should be` false + } + } + + @Test + fun `can be not view the workgroup if is null`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns tesla.user + }.let { + can(WorkgroupVoter.Action.VIEW, it, null) `should be` false + } + } + + @Test + fun `can be view your workgroup list`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns tesla.user + }.let { + can(WorkgroupVoter.Action.VIEW, it, listOf(workgroupPublic)) `should be` true + } + } + + @Test + fun `can be create workgroup`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns tesla.user + }.let { + can(WorkgroupVoter.Action.CREATE, it, workgroupPublic) `should be` true + } + } + + @Test + fun `can not be create workgroup if not connected`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns null + }.let { + can(WorkgroupVoter.Action.CREATE, it, workgroupPublic) `should be` false + } + } + + @Test + fun `can be delete workgroup if owner`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns tesla.user + }.let { + can(WorkgroupVoter.Action.DELETE, it, workgroupPublic) `should be` true + } + } + + @Test + fun `can not be delete workgroup if not owner`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns einstein.user + }.let { + can(WorkgroupVoter.Action.DELETE, it, workgroupPublic) `should be` false + } + } + + @Test + fun `can be update workgroup if owner`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns tesla.user + }.let { + can(WorkgroupVoter.Action.UPDATE, it, workgroupPublic) `should be` true + } + } + + @Test + fun `can not be update workgroup if not owner`() = listOf(WorkgroupVoter()).run { + mockk { + every { user } returns einstein.user + }.let { + can(WorkgroupVoter.Action.UPDATE, it, workgroupPublic) `should be` false + } + } + + @Test + fun `can not be update workgroup if workgroup has no user`() { + Assertions.assertThrows(VoterException::class.java) { + listOf(WorkgroupVoter()).run { + mockk { + every { user } returns tesla.user + }.let { + can(WorkgroupVoter.Action.UPDATE, it, workgroupref) + } + } + } + } +} \ No newline at end of file