Migration to Drone CI #8
|
@ -2,12 +2,12 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|||
|
||||
group = "dev.fyloz.colorrecipesexplorer"
|
||||
|
||||
val kotlinVersion = "1.5.0"
|
||||
val kotlinVersion = "1.5.21"
|
||||
val springBootVersion = "2.3.4.RELEASE"
|
||||
|
||||
plugins {
|
||||
// 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"
|
||||
|
||||
id("java")
|
||||
|
@ -46,7 +46,7 @@ dependencies {
|
|||
implementation("org.springframework.boot:spring-boot-devtools:${springBootVersion}")
|
||||
|
||||
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("org.junit.jupiter:junit-jupiter-api:5.3.2")
|
||||
testImplementation("io.mockk:mockk:1.10.6")
|
||||
|
|
|
@ -66,10 +66,16 @@ data class ConfigurationImageDto(
|
|||
|
||||
fun configuration(
|
||||
type: ConfigurationType,
|
||||
content: String,
|
||||
content: String = type.defaultContent.toString(),
|
||||
lastUpdated: LocalDateTime? = null
|
||||
) = Configuration(type, content, lastUpdated ?: LocalDateTime.now())
|
||||
|
||||
fun configuration(
|
||||
dto: ConfigurationDto
|
||||
) = with(dto) {
|
||||
configuration(type = key.toConfigurationType(), content = content)
|
||||
}
|
||||
|
||||
enum class ConfigurationType(
|
||||
val key: String,
|
||||
val defaultContent: Any? = null,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package dev.fyloz.colorrecipesexplorer.service
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.config.properties.CreProperties
|
||||
import dev.fyloz.colorrecipesexplorer.model.ConfigurationType
|
||||
import dev.fyloz.colorrecipesexplorer.model.touchupkit.*
|
||||
import dev.fyloz.colorrecipesexplorer.repository.TouchUpKitRepository
|
||||
|
@ -30,12 +29,12 @@ interface TouchUpKitService :
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -48,6 +47,10 @@ class TouchUpKitServiceImpl(
|
|||
) : AbstractExternalModelService<TouchUpKit, TouchUpKitSaveDto, TouchUpKitUpdateDto, TouchUpKitOutputDto, TouchUpKitRepository>(
|
||||
touchUpKitRepository
|
||||
), 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 idAlreadyExistsException(id: Long) = touchUpKitIdAlreadyExistsException(id)
|
||||
|
||||
|
@ -118,7 +121,7 @@ class TouchUpKitServiceImpl(
|
|||
}
|
||||
|
||||
override fun generateJobPdfResource(job: String): ByteArrayResource {
|
||||
if (cacheGeneratedFiles()) {
|
||||
if (cacheGeneratedFiles) {
|
||||
with(job.pdfDocumentPath()) {
|
||||
if (fileService.exists(this)) {
|
||||
return fileService.read(this)
|
||||
|
@ -132,7 +135,7 @@ class TouchUpKitServiceImpl(
|
|||
}
|
||||
|
||||
override fun String.cachePdfDocument(document: PdfDocument) {
|
||||
if (!cacheGeneratedFiles()) return
|
||||
if (!cacheGeneratedFiles) return
|
||||
|
||||
fileService.write(document.toByteArrayResource(), this.pdfDocumentPath(), true)
|
||||
}
|
||||
|
@ -142,7 +145,4 @@ class TouchUpKitServiceImpl(
|
|||
|
||||
private fun TouchUpKit.pdfUrl() =
|
||||
"${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"
|
||||
}
|
||||
|
|
|
@ -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))
|
|
@ -1,7 +1,7 @@
|
|||
package dev.fyloz.colorrecipesexplorer.service
|
||||
|
||||
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.NotFoundException
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.*
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
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.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 org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ConfigurationServiceTest {
|
||||
private val repository = mockk<ConfigurationRepository>()
|
||||
private val fileConfiguration = mockk<FileConfiguration>()
|
||||
private val service = spyk(ConfigurationServiceImpl(repository, mockk(), fileConfiguration, mockk(), mockk(), mockk()))
|
||||
private val fileService = mockk<FileService>()
|
||||
private val configurationSource = mockk<ConfigurationSource>()
|
||||
private val securityProperties = mockk<CreSecurityProperties> {
|
||||
every { configSalt } returns "d32270943af7e1cc"
|
||||
}
|
||||
private val service = spyk(ConfigurationServiceImpl(fileService, configurationSource, securityProperties, mockk()))
|
||||
|
||||
@AfterEach
|
||||
fun afterEach() {
|
||||
|
@ -126,73 +130,22 @@ class ConfigurationServiceTest {
|
|||
}
|
||||
|
||||
@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 configuration = configuration(type = type)
|
||||
|
||||
every { repository.findById(type.key) } returns Optional.of(
|
||||
ConfigurationEntity(type.key, type.key, LocalDateTime.now())
|
||||
)
|
||||
every { configurationSource.get(type) } returns configuration
|
||||
|
||||
val configuration = service.get(type)
|
||||
val found = service.get(type)
|
||||
|
||||
assertTrue {
|
||||
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)
|
||||
assertEquals(configuration, found)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get(type) throws ConfigurationNotSetException when the given ConfigurationType has no set configuration`() {
|
||||
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) }) {
|
||||
assertEquals(type, this.type)
|
||||
|
@ -200,56 +153,64 @@ class ConfigurationServiceTest {
|
|||
|
||||
verify {
|
||||
service.get(type)
|
||||
repository.findById(type.key)
|
||||
configurationSource.get(type)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `set() set the configuration in the FileConfiguration when the given ConfigurationType is a file configuration`() {
|
||||
val type = ConfigurationType.DATABASE_URL
|
||||
val content = "url"
|
||||
fun `get(type) throws InvalidConfigurationKeyException when the given ConfigurationType is encryption salt`() {
|
||||
val type = ConfigurationType.GENERATED_ENCRYPTION_SALT
|
||||
|
||||
every { fileConfiguration.set(type, content) } just runs
|
||||
|
||||
service.set(type, content)
|
||||
|
||||
verify {
|
||||
service.set(type, content)
|
||||
fileConfiguration.set(type, content)
|
||||
}
|
||||
confirmVerified(service, fileConfiguration)
|
||||
assertThrows<InvalidConfigurationKeyException> { service.get(type) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `set() set the configuration in the repository when the given ConfigurationType is not a computed configuration of a file configuration`() {
|
||||
val type = ConfigurationType.INSTANCE_ICON_PATH
|
||||
val content = "path"
|
||||
val configuration = configuration(type, content)
|
||||
val entity = configuration.toEntity()
|
||||
fun `get(type) decrypts configuration content when the given ConfigurationType is secure`() {
|
||||
val type = ConfigurationType.DATABASE_PASSWORD
|
||||
val content = "securepassword"
|
||||
val configuration = configuration(
|
||||
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 {
|
||||
service.set(type, content)
|
||||
repository.save(entity)
|
||||
}
|
||||
confirmVerified(service, repository)
|
||||
assertEquals(content, found.content)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `set() throws CannotSetComputedConfigurationException when the given ConfigurationType is a computed configuration`() {
|
||||
val type = ConfigurationType.JAVA_VERSION
|
||||
val content = "5"
|
||||
fun `set(configuration) set configuration in ConfigurationSource`() {
|
||||
val configuration = configuration(type = ConfigurationType.INSTANCE_NAME)
|
||||
|
||||
with(assertThrows<CannotSetComputedConfigurationException> { service.set(type, content) }) {
|
||||
assertEquals(type, this.type)
|
||||
}
|
||||
every { configurationSource.set(any<Configuration>()) } just runs
|
||||
|
||||
service.set(configuration)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import kotlin.test.assertTrue
|
|||
|
||||
private val creProperties = CreProperties().apply {
|
||||
dataDirectory = "data"
|
||||
deploymentUrl = "http://localhost"
|
||||
}
|
||||
private const val mockFilePath = "existingFile"
|
||||
private val mockFilePathPath = Path.of(mockFilePath)
|
|
@ -5,6 +5,7 @@ import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
|
|||
import dev.fyloz.colorrecipesexplorer.model.*
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.group
|
||||
import dev.fyloz.colorrecipesexplorer.repository.RecipeRepository
|
||||
import dev.fyloz.colorrecipesexplorer.service.config.ConfigurationService
|
||||
import io.mockk.*
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
@ -271,7 +272,7 @@ private class RecipeImageServiceTestContext {
|
|||
val recipeImagesIds = setOf(1L, 10L, 21L)
|
||||
val recipeImagesNames = recipeImagesIds.map { it.imageName }.toSet()
|
||||
val recipeImagesFiles = recipeImagesNames.map { File(it) }.toTypedArray()
|
||||
val recipeDirectory = spyk(File(recipe.imagesDirectoryPath)) {
|
||||
val recipeDirectory = mockk<File> {
|
||||
every { exists() } returns true
|
||||
every { isDirectory } returns true
|
||||
every { listFiles() } returns recipeImagesFiles
|
||||
|
|
|
@ -5,6 +5,7 @@ import dev.fyloz.colorrecipesexplorer.model.ConfigurationType
|
|||
import dev.fyloz.colorrecipesexplorer.model.configuration
|
||||
import dev.fyloz.colorrecipesexplorer.repository.TouchUpKitRepository
|
||||
import dev.fyloz.colorrecipesexplorer.service.*
|
||||
import dev.fyloz.colorrecipesexplorer.service.config.ConfigurationService
|
||||
import dev.fyloz.colorrecipesexplorer.utils.PdfDocument
|
||||
import dev.fyloz.colorrecipesexplorer.utils.toByteArrayResource
|
||||
import io.mockk.*
|
||||
|
@ -18,9 +19,7 @@ private class TouchUpKitServiceTestContext {
|
|||
val fileService = mockk<FileService> {
|
||||
every { write(any<ByteArrayResource>(), any(), any()) } just Runs
|
||||
}
|
||||
val creProperties = mockk<CreProperties> {
|
||||
every { cacheGeneratedFiles } returns false
|
||||
}
|
||||
val creProperties = mockk<CreProperties>()
|
||||
val configService = mockk<ConfigurationService>(relaxed = true)
|
||||
val touchUpKitService = spyk(TouchUpKitServiceImpl(fileService, configService, touchUpKitRepository))
|
||||
val pdfDocumentData = mockk<ByteArrayResource>()
|
||||
|
@ -79,10 +78,13 @@ class TouchUpKitServiceTest {
|
|||
@Test
|
||||
fun `generateJobPdfResource() returns a cached ByteArrayResource from the FileService when caching is enabled and a cached file eixsts for the given job`() {
|
||||
test {
|
||||
every { creProperties.cacheGeneratedFiles } returns true
|
||||
enableCachePdf()
|
||||
every { fileService.exists(any()) } returns true
|
||||
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)
|
||||
|
||||
|
@ -95,7 +97,7 @@ class TouchUpKitServiceTest {
|
|||
@Test
|
||||
fun `cachePdfDocument() does nothing when caching is disabled`() {
|
||||
test {
|
||||
every { creProperties.cacheGeneratedFiles } returns false
|
||||
disableCachePdf()
|
||||
|
||||
with(touchUpKitService) {
|
||||
job.cachePdfDocument(pdfDocument)
|
||||
|
@ -110,8 +112,7 @@ class TouchUpKitServiceTest {
|
|||
@Test
|
||||
fun `cachePdfDocument() writes the given document to the FileService when cache is enabled`() {
|
||||
test {
|
||||
every { creProperties.cacheGeneratedFiles } returns true
|
||||
every { configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF) } returns configuration(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF, "true")
|
||||
enableCachePdf()
|
||||
|
||||
with(touchUpKitService) {
|
||||
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) {
|
||||
TouchUpKitServiceTestContext().test()
|
||||
}
|
Loading…
Reference in New Issue