#68 Mise a jour des tests

This commit is contained in:
FyloZ 2021-07-21 22:23:40 -04:00
parent febef06962
commit 84af6f3d8a
9 changed files with 118 additions and 120 deletions

View File

@ -2,12 +2,12 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
group = "dev.fyloz.colorrecipesexplorer" group = "dev.fyloz.colorrecipesexplorer"
val kotlinVersion = "1.5.0" val kotlinVersion = "1.5.21"
val springBootVersion = "2.3.4.RELEASE" val springBootVersion = "2.3.4.RELEASE"
plugins { plugins {
// Outer scope variables can't be accessed in the plugins section, so we have to redefine them here // Outer scope variables can't be accessed in the plugins section, so we have to redefine them here
val kotlinVersion = "1.5.0" val kotlinVersion = "1.5.21"
val springBootVersion = "2.3.4.RELEASE" val springBootVersion = "2.3.4.RELEASE"
id("java") id("java")
@ -46,7 +46,7 @@ dependencies {
implementation("org.springframework.boot:spring-boot-devtools:${springBootVersion}") implementation("org.springframework.boot:spring-boot-devtools:${springBootVersion}")
testImplementation("org.springframework:spring-test:5.1.6.RELEASE") testImplementation("org.springframework:spring-test:5.1.6.RELEASE")
testImplementation("org.mockito:mockito-inline:3.6.0") testImplementation("org.mockito:mockito-inline:3.11.2")
testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0") testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.2") testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.2")
testImplementation("io.mockk:mockk:1.10.6") testImplementation("io.mockk:mockk:1.10.6")

View File

@ -66,10 +66,16 @@ data class ConfigurationImageDto(
fun configuration( fun configuration(
type: ConfigurationType, type: ConfigurationType,
content: String, content: String = type.defaultContent.toString(),
lastUpdated: LocalDateTime? = null lastUpdated: LocalDateTime? = null
) = Configuration(type, content, lastUpdated ?: LocalDateTime.now()) ) = Configuration(type, content, lastUpdated ?: LocalDateTime.now())
fun configuration(
dto: ConfigurationDto
) = with(dto) {
configuration(type = key.toConfigurationType(), content = content)
}
enum class ConfigurationType( enum class ConfigurationType(
val key: String, val key: String,
val defaultContent: Any? = null, val defaultContent: Any? = null,

View File

@ -1,6 +1,5 @@
package dev.fyloz.colorrecipesexplorer.service package dev.fyloz.colorrecipesexplorer.service
import dev.fyloz.colorrecipesexplorer.config.properties.CreProperties
import dev.fyloz.colorrecipesexplorer.model.ConfigurationType import dev.fyloz.colorrecipesexplorer.model.ConfigurationType
import dev.fyloz.colorrecipesexplorer.model.touchupkit.* import dev.fyloz.colorrecipesexplorer.model.touchupkit.*
import dev.fyloz.colorrecipesexplorer.repository.TouchUpKitRepository import dev.fyloz.colorrecipesexplorer.repository.TouchUpKitRepository
@ -30,12 +29,12 @@ interface TouchUpKitService :
/** /**
* Generates and returns a [PdfDocument] for the given [job] as a [ByteArrayResource]. * Generates and returns a [PdfDocument] for the given [job] as a [ByteArrayResource].
* *
* If [CreProperties.cacheGeneratedFiles] is enabled and a file exists for the job, its content will be returned. * If TOUCH_UP_KIT_CACHE_PDF is enabled and a file exists for the job, its content will be returned.
* If caching is enabled but no file exists for the job, the generated ByteArrayResource will be cached on the disk. * If caching is enabled but no file exists for the job, the generated ByteArrayResource will be cached on the disk.
*/ */
fun generateJobPdfResource(job: String): ByteArrayResource fun generateJobPdfResource(job: String): ByteArrayResource
/** Writes the given [document] to the [FileService] if [CreProperties.cacheGeneratedFiles] is enabled. */ /** Writes the given [document] to the [FileService] if TOUCH_UP_KIT_CACHE_PDF is enabled. */
fun String.cachePdfDocument(document: PdfDocument) fun String.cachePdfDocument(document: PdfDocument)
} }
@ -48,6 +47,10 @@ class TouchUpKitServiceImpl(
) : AbstractExternalModelService<TouchUpKit, TouchUpKitSaveDto, TouchUpKitUpdateDto, TouchUpKitOutputDto, TouchUpKitRepository>( ) : AbstractExternalModelService<TouchUpKit, TouchUpKitSaveDto, TouchUpKitUpdateDto, TouchUpKitOutputDto, TouchUpKitRepository>(
touchUpKitRepository touchUpKitRepository
), TouchUpKitService { ), TouchUpKitService {
private val cacheGeneratedFiles by lazy {
configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF).content == true.toString()
}
override fun idNotFoundException(id: Long) = touchUpKitIdNotFoundException(id) override fun idNotFoundException(id: Long) = touchUpKitIdNotFoundException(id)
override fun idAlreadyExistsException(id: Long) = touchUpKitIdAlreadyExistsException(id) override fun idAlreadyExistsException(id: Long) = touchUpKitIdAlreadyExistsException(id)
@ -118,7 +121,7 @@ class TouchUpKitServiceImpl(
} }
override fun generateJobPdfResource(job: String): ByteArrayResource { override fun generateJobPdfResource(job: String): ByteArrayResource {
if (cacheGeneratedFiles()) { if (cacheGeneratedFiles) {
with(job.pdfDocumentPath()) { with(job.pdfDocumentPath()) {
if (fileService.exists(this)) { if (fileService.exists(this)) {
return fileService.read(this) return fileService.read(this)
@ -132,7 +135,7 @@ class TouchUpKitServiceImpl(
} }
override fun String.cachePdfDocument(document: PdfDocument) { override fun String.cachePdfDocument(document: PdfDocument) {
if (!cacheGeneratedFiles()) return if (!cacheGeneratedFiles) return
fileService.write(document.toByteArrayResource(), this.pdfDocumentPath(), true) fileService.write(document.toByteArrayResource(), this.pdfDocumentPath(), true)
} }
@ -142,7 +145,4 @@ class TouchUpKitServiceImpl(
private fun TouchUpKit.pdfUrl() = private fun TouchUpKit.pdfUrl() =
"${configService.get(ConfigurationType.INSTANCE_URL).content}$TOUCH_UP_KIT_CONTROLLER_PATH/pdf?job=$project" "${configService.get(ConfigurationType.INSTANCE_URL).content}$TOUCH_UP_KIT_CONTROLLER_PATH/pdf?job=$project"
private fun cacheGeneratedFiles() =
configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF).content == "true"
} }

View File

@ -0,0 +1,17 @@
package dev.fyloz.colorrecipesexplorer.utils
import org.springframework.security.crypto.encrypt.Encryptors
import org.springframework.security.crypto.encrypt.TextEncryptor
fun String.encrypt(password: String, salt: String): String =
withTextEncryptor(password, salt) {
it.encrypt(this)
}
fun String.decrypt(password: String, salt: String): String =
withTextEncryptor(password, salt) {
it.decrypt(this)
}
private fun withTextEncryptor(password: String, salt: String, op: (TextEncryptor) -> String) =
op(Encryptors.text(password, salt))

View File

@ -1,7 +1,7 @@
package dev.fyloz.colorrecipesexplorer.service package dev.fyloz.colorrecipesexplorer.service
import com.nhaarman.mockitokotlin2.* import com.nhaarman.mockitokotlin2.*
import dev.fyloz.colorrecipesexplorer.config.defaultGroupCookieName import dev.fyloz.colorrecipesexplorer.config.security.defaultGroupCookieName
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import dev.fyloz.colorrecipesexplorer.exception.NotFoundException
import dev.fyloz.colorrecipesexplorer.model.account.* import dev.fyloz.colorrecipesexplorer.model.account.*

View File

@ -1,22 +1,26 @@
package dev.fyloz.colorrecipesexplorer.service package dev.fyloz.colorrecipesexplorer.service
import dev.fyloz.colorrecipesexplorer.config.FileConfiguration import dev.fyloz.colorrecipesexplorer.config.properties.CreSecurityProperties
import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.model.*
import dev.fyloz.colorrecipesexplorer.repository.ConfigurationRepository import dev.fyloz.colorrecipesexplorer.service.config.CONFIGURATION_FORMATTED_LIST_DELIMITER
import dev.fyloz.colorrecipesexplorer.service.config.ConfigurationServiceImpl
import dev.fyloz.colorrecipesexplorer.service.config.ConfigurationSource
import dev.fyloz.colorrecipesexplorer.utils.encrypt
import io.mockk.* import io.mockk.*
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import java.time.LocalDateTime
import java.util.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertTrue import kotlin.test.assertTrue
class ConfigurationServiceTest { class ConfigurationServiceTest {
private val repository = mockk<ConfigurationRepository>() private val fileService = mockk<FileService>()
private val fileConfiguration = mockk<FileConfiguration>() private val configurationSource = mockk<ConfigurationSource>()
private val service = spyk(ConfigurationServiceImpl(repository, mockk(), fileConfiguration, mockk(), mockk(), mockk())) private val securityProperties = mockk<CreSecurityProperties> {
every { configSalt } returns "d32270943af7e1cc"
}
private val service = spyk(ConfigurationServiceImpl(fileService, configurationSource, securityProperties, mockk()))
@AfterEach @AfterEach
fun afterEach() { fun afterEach() {
@ -126,73 +130,22 @@ class ConfigurationServiceTest {
} }
@Test @Test
fun `get(type) gets in the repository when the given ConfigurationType is not computed or a file property`() { fun `get(type) gets the configuration in the ConfigurationSource`() {
val type = ConfigurationType.INSTANCE_ICON_PATH val type = ConfigurationType.INSTANCE_ICON_PATH
val configuration = configuration(type = type)
every { repository.findById(type.key) } returns Optional.of( every { configurationSource.get(type) } returns configuration
ConfigurationEntity(type.key, type.key, LocalDateTime.now())
)
val configuration = service.get(type) val found = service.get(type)
assertTrue { assertEquals(configuration, found)
configuration.key == type.key
}
verify {
service.get(type)
repository.findById(type.key)
}
confirmVerified(service, repository)
}
@Test
fun `get(type) gets in the FileConfiguration when the gien ConfigurationType is a file property`() {
val type = ConfigurationType.DATABASE_URL
every { fileConfiguration.get(type) } returns configuration(type, type.key)
val configuration = service.get(type)
assertTrue {
configuration.key == type.key
}
verify {
service.get(type)
fileConfiguration.get(type)
}
verify(exactly = 0) {
repository.findById(type.key)
}
confirmVerified(service, fileConfiguration, repository)
}
@Test
fun `get(type) computes computed properties`() {
val type = ConfigurationType.JAVA_VERSION
val configuration = service.get(type)
assertTrue {
configuration.key == type.key
}
verify {
service.get(type)
}
verify(exactly = 0) {
repository.findById(type.key)
fileConfiguration.get(type)
}
confirmVerified(service, repository, fileConfiguration)
} }
@Test @Test
fun `get(type) throws ConfigurationNotSetException when the given ConfigurationType has no set configuration`() { fun `get(type) throws ConfigurationNotSetException when the given ConfigurationType has no set configuration`() {
val type = ConfigurationType.INSTANCE_ICON_PATH val type = ConfigurationType.INSTANCE_ICON_PATH
every { repository.findById(type.key) } returns Optional.empty() every { configurationSource.get(type) } returns null
with(assertThrows<ConfigurationNotSetException> { service.get(type) }) { with(assertThrows<ConfigurationNotSetException> { service.get(type) }) {
assertEquals(type, this.type) assertEquals(type, this.type)
@ -200,56 +153,64 @@ class ConfigurationServiceTest {
verify { verify {
service.get(type) service.get(type)
repository.findById(type.key) configurationSource.get(type)
} }
} }
@Test @Test
fun `set() set the configuration in the FileConfiguration when the given ConfigurationType is a file configuration`() { fun `get(type) throws InvalidConfigurationKeyException when the given ConfigurationType is encryption salt`() {
val type = ConfigurationType.DATABASE_URL val type = ConfigurationType.GENERATED_ENCRYPTION_SALT
val content = "url"
every { fileConfiguration.set(type, content) } just runs assertThrows<InvalidConfigurationKeyException> { service.get(type) }
service.set(type, content)
verify {
service.set(type, content)
fileConfiguration.set(type, content)
}
confirmVerified(service, fileConfiguration)
} }
@Test @Test
fun `set() set the configuration in the repository when the given ConfigurationType is not a computed configuration of a file configuration`() { fun `get(type) decrypts configuration content when the given ConfigurationType is secure`() {
val type = ConfigurationType.INSTANCE_ICON_PATH val type = ConfigurationType.DATABASE_PASSWORD
val content = "path" val content = "securepassword"
val configuration = configuration(type, content) val configuration = configuration(
val entity = configuration.toEntity() type = type,
content = content.encrypt(type.key, securityProperties.configSalt!!)
)
every { repository.save(entity) } returns entity every { configurationSource.get(type) } returns configuration
service.set(type, content) val found = service.get(type)
verify { assertEquals(content, found.content)
service.set(type, content)
repository.save(entity)
}
confirmVerified(service, repository)
} }
@Test @Test
fun `set() throws CannotSetComputedConfigurationException when the given ConfigurationType is a computed configuration`() { fun `set(configuration) set configuration in ConfigurationSource`() {
val type = ConfigurationType.JAVA_VERSION val configuration = configuration(type = ConfigurationType.INSTANCE_NAME)
val content = "5"
with(assertThrows<CannotSetComputedConfigurationException> { service.set(type, content) }) { every { configurationSource.set(any<Configuration>()) } just runs
assertEquals(type, this.type)
} service.set(configuration)
verify { verify {
service.set(type, content) configurationSource.set(configuration)
}
}
@Test
fun `set(configuration) encrypts secure configurations`() {
val type = ConfigurationType.DATABASE_PASSWORD
val content = "securepassword"
val encryptedContent =content.encrypt(type.key, securityProperties.configSalt!!)
val configuration = configuration(type = type, content = content)
mockkStatic(String::encrypt)
every { configurationSource.set(any<Configuration>()) } just runs
every { content.encrypt(any(), any()) } returns encryptedContent
service.set(configuration)
verify {
configurationSource.set(match<Configuration> {
it.content == encryptedContent
})
} }
confirmVerified(service)
} }
} }

View File

@ -15,7 +15,6 @@ import kotlin.test.assertTrue
private val creProperties = CreProperties().apply { private val creProperties = CreProperties().apply {
dataDirectory = "data" dataDirectory = "data"
deploymentUrl = "http://localhost"
} }
private const val mockFilePath = "existingFile" private const val mockFilePath = "existingFile"
private val mockFilePathPath = Path.of(mockFilePath) private val mockFilePathPath = Path.of(mockFilePath)

View File

@ -5,6 +5,7 @@ import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.model.*
import dev.fyloz.colorrecipesexplorer.model.account.group import dev.fyloz.colorrecipesexplorer.model.account.group
import dev.fyloz.colorrecipesexplorer.repository.RecipeRepository import dev.fyloz.colorrecipesexplorer.repository.RecipeRepository
import dev.fyloz.colorrecipesexplorer.service.config.ConfigurationService
import io.mockk.* import io.mockk.*
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
@ -271,7 +272,7 @@ private class RecipeImageServiceTestContext {
val recipeImagesIds = setOf(1L, 10L, 21L) val recipeImagesIds = setOf(1L, 10L, 21L)
val recipeImagesNames = recipeImagesIds.map { it.imageName }.toSet() val recipeImagesNames = recipeImagesIds.map { it.imageName }.toSet()
val recipeImagesFiles = recipeImagesNames.map { File(it) }.toTypedArray() val recipeImagesFiles = recipeImagesNames.map { File(it) }.toTypedArray()
val recipeDirectory = spyk(File(recipe.imagesDirectoryPath)) { val recipeDirectory = mockk<File> {
every { exists() } returns true every { exists() } returns true
every { isDirectory } returns true every { isDirectory } returns true
every { listFiles() } returns recipeImagesFiles every { listFiles() } returns recipeImagesFiles

View File

@ -5,6 +5,7 @@ import dev.fyloz.colorrecipesexplorer.model.ConfigurationType
import dev.fyloz.colorrecipesexplorer.model.configuration import dev.fyloz.colorrecipesexplorer.model.configuration
import dev.fyloz.colorrecipesexplorer.repository.TouchUpKitRepository import dev.fyloz.colorrecipesexplorer.repository.TouchUpKitRepository
import dev.fyloz.colorrecipesexplorer.service.* import dev.fyloz.colorrecipesexplorer.service.*
import dev.fyloz.colorrecipesexplorer.service.config.ConfigurationService
import dev.fyloz.colorrecipesexplorer.utils.PdfDocument import dev.fyloz.colorrecipesexplorer.utils.PdfDocument
import dev.fyloz.colorrecipesexplorer.utils.toByteArrayResource import dev.fyloz.colorrecipesexplorer.utils.toByteArrayResource
import io.mockk.* import io.mockk.*
@ -18,9 +19,7 @@ private class TouchUpKitServiceTestContext {
val fileService = mockk<FileService> { val fileService = mockk<FileService> {
every { write(any<ByteArrayResource>(), any(), any()) } just Runs every { write(any<ByteArrayResource>(), any(), any()) } just Runs
} }
val creProperties = mockk<CreProperties> { val creProperties = mockk<CreProperties>()
every { cacheGeneratedFiles } returns false
}
val configService = mockk<ConfigurationService>(relaxed = true) val configService = mockk<ConfigurationService>(relaxed = true)
val touchUpKitService = spyk(TouchUpKitServiceImpl(fileService, configService, touchUpKitRepository)) val touchUpKitService = spyk(TouchUpKitServiceImpl(fileService, configService, touchUpKitRepository))
val pdfDocumentData = mockk<ByteArrayResource>() val pdfDocumentData = mockk<ByteArrayResource>()
@ -79,10 +78,13 @@ class TouchUpKitServiceTest {
@Test @Test
fun `generateJobPdfResource() returns a cached ByteArrayResource from the FileService when caching is enabled and a cached file eixsts for the given job`() { fun `generateJobPdfResource() returns a cached ByteArrayResource from the FileService when caching is enabled and a cached file eixsts for the given job`() {
test { test {
every { creProperties.cacheGeneratedFiles } returns true enableCachePdf()
every { fileService.exists(any()) } returns true every { fileService.exists(any()) } returns true
every { fileService.read(any()) } returns pdfDocumentData every { fileService.read(any()) } returns pdfDocumentData
every { configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF) } returns configuration(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF, "true") every { configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF) } returns configuration(
ConfigurationType.TOUCH_UP_KIT_CACHE_PDF,
"true"
)
val redResource = touchUpKitService.generateJobPdfResource(job) val redResource = touchUpKitService.generateJobPdfResource(job)
@ -95,7 +97,7 @@ class TouchUpKitServiceTest {
@Test @Test
fun `cachePdfDocument() does nothing when caching is disabled`() { fun `cachePdfDocument() does nothing when caching is disabled`() {
test { test {
every { creProperties.cacheGeneratedFiles } returns false disableCachePdf()
with(touchUpKitService) { with(touchUpKitService) {
job.cachePdfDocument(pdfDocument) job.cachePdfDocument(pdfDocument)
@ -110,8 +112,7 @@ class TouchUpKitServiceTest {
@Test @Test
fun `cachePdfDocument() writes the given document to the FileService when cache is enabled`() { fun `cachePdfDocument() writes the given document to the FileService when cache is enabled`() {
test { test {
every { creProperties.cacheGeneratedFiles } returns true enableCachePdf()
every { configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF) } returns configuration(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF, "true")
with(touchUpKitService) { with(touchUpKitService) {
job.cachePdfDocument(pdfDocument) job.cachePdfDocument(pdfDocument)
@ -123,6 +124,19 @@ class TouchUpKitServiceTest {
} }
} }
private fun TouchUpKitServiceTestContext.enableCachePdf() =
this.setCachePdf(true)
private fun TouchUpKitServiceTestContext.disableCachePdf() =
this.setCachePdf(false)
private fun TouchUpKitServiceTestContext.setCachePdf(enabled: Boolean) {
every { configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF) } returns configuration(
type = ConfigurationType.TOUCH_UP_KIT_CACHE_PDF,
enabled.toString()
)
}
private fun test(test: TouchUpKitServiceTestContext.() -> Unit) { private fun test(test: TouchUpKitServiceTestContext.() -> Unit) {
TouchUpKitServiceTestContext().test() TouchUpKitServiceTestContext().test()
} }