#13 Bundle icon and logo to the backend #15

Merged
william merged 5 commits from 13-bundle-logo-icon into develop 2021-09-12 08:32:14 -04:00
11 changed files with 264 additions and 27 deletions
Showing only changes of commit 9a260b6edf - Show all commits

View File

@ -46,10 +46,10 @@ dependencies {
implementation("org.springframework.boot:spring-boot-devtools:${springBootVersion}")
testImplementation("org.springframework:spring-test:5.1.6.RELEASE")
testImplementation("org.mockito:mockito-inline:3.11.2")
testImplementation("org.mockito:mockito-inline:3.12.4")
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")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.2")
testImplementation("io.mockk:mockk:1.12.0")
testImplementation("org.springframework.boot:spring-boot-starter-test:${springBootVersion}")
testImplementation("org.springframework.boot:spring-boot-test-autoconfigure:${springBootVersion}")
testImplementation("org.jetbrains.kotlin:kotlin-test:${kotlinVersion}")

View File

@ -44,7 +44,7 @@ class ConfigurationController(val configurationService: ConfigurationService) {
@GetMapping("icon")
fun getIcon() =
ok(configurationService.getConfiguredIcon(), MediaType.IMAGE_PNG_VALUE)
okFile(configurationService.getConfiguredIcon(), MediaType.IMAGE_PNG_VALUE)
@PutMapping("icon")
@PreAuthorize("hasAuthority('ADMIN')")
@ -56,7 +56,7 @@ class ConfigurationController(val configurationService: ConfigurationService) {
@GetMapping("logo")
fun getLogo() =
ok(configurationService.getConfiguredLogo(), MediaType.IMAGE_PNG_VALUE)
okFile(configurationService.getConfiguredLogo(), MediaType.IMAGE_PNG_VALUE)
@PutMapping("logo")
@PreAuthorize("hasAuthority('ADMIN')")

View File

@ -22,7 +22,7 @@ class FileController(
fun upload(
@RequestParam path: String,
@RequestParam(required = false) mediaType: String?
) = ok(fileService.read(path), mediaType)
) = okFile(fileService.read(path), mediaType)
@PutMapping(consumes = [MediaType.MULTIPART_FORM_DATA_VALUE])
@PreAuthorize("hasAnyAuthority('WRITE_FILE')")

View File

@ -27,7 +27,7 @@ fun ok(action: () -> Unit): ResponseEntity<Void> {
}
/** Creates a HTTP OK [ResponseEntity] for the given [file], with the given [mediaType]. */
fun ok(file: Resource, mediaType: String? = null): ResponseEntity<Resource> =
fun okFile(file: Resource, mediaType: String? = null): ResponseEntity<Resource> =
ResponseEntity.ok()
.header("Content-Disposition", "filename=${file.filename}")
.contentLength(file.contentLength())

View File

@ -9,7 +9,7 @@ class ResourceFileService(
private val resourceLoader: ResourceLoader
) : FileService {
override fun exists(path: String) =
read(path).exists()
path.fullPath().resource.exists()
override fun read(path: String): Resource =
path.fullPath().resource.also {
@ -21,6 +21,6 @@ class ResourceFileService(
override fun String.fullPath() =
FilePath("classpath:${this}")
private val FilePath.resource: Resource
val FilePath.resource: Resource
get() = resourceLoader.getResource(this.path)
}

View File

@ -5,23 +5,35 @@ import dev.fyloz.colorrecipesexplorer.model.*
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.service.files.ResourceFileService
import dev.fyloz.colorrecipesexplorer.service.files.WriteableFileService
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 kotlin.UnsupportedOperationException
import org.springframework.core.io.Resource
import org.springframework.web.multipart.MultipartFile
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class ConfigurationServiceTest {
private val fileService = mockk<FileService>()
private val fileService = mockk<WriteableFileService>()
private val resourceFileService = mockk<ResourceFileService>()
private val configurationSource = mockk<ConfigurationSource>()
private val securityProperties = mockk<CreSecurityProperties> {
every { configSalt } returns "d32270943af7e1cc"
}
private val service = spyk(ConfigurationServiceImpl(fileService, configurationSource, securityProperties, mockk()))
private val service = spyk(
ConfigurationServiceImpl(
fileService,
resourceFileService,
configurationSource,
securityProperties,
mockk()
)
)
@AfterEach
fun afterEach() {
@ -49,8 +61,8 @@ class ConfigurationServiceTest {
fun `getAll() only returns set configurations`() {
val unsetConfigurationTypes = listOf(
ConfigurationType.INSTANCE_NAME,
ConfigurationType.INSTANCE_LOGO_PATH,
ConfigurationType.INSTANCE_ICON_PATH
ConfigurationType.INSTANCE_LOGO_SET,
ConfigurationType.INSTANCE_ICON_SET
)
every { service.get(match<ConfigurationType> { it in unsetConfigurationTypes }) } answers {
@ -82,8 +94,8 @@ class ConfigurationServiceTest {
fun `getAll() only includes configurations matching the formatted formatted key list`() {
val configurationTypes = listOf(
ConfigurationType.INSTANCE_NAME,
ConfigurationType.INSTANCE_LOGO_PATH,
ConfigurationType.INSTANCE_ICON_PATH
ConfigurationType.INSTANCE_LOGO_SET,
ConfigurationType.INSTANCE_ICON_SET
)
val formattedKeyList = configurationTypes
.map { it.key }
@ -113,7 +125,7 @@ class ConfigurationServiceTest {
@Test
fun `get(key) calls get() with the ConfigurationType matching the given key`() {
val type = ConfigurationType.INSTANCE_ICON_PATH
val type = ConfigurationType.INSTANCE_ICON_SET
val key = type.key
every { service.get(type) } answers {
@ -132,7 +144,7 @@ class ConfigurationServiceTest {
@Test
fun `get(type) gets the configuration in the ConfigurationSource`() {
val type = ConfigurationType.INSTANCE_ICON_PATH
val type = ConfigurationType.INSTANCE_ICON_SET
val configuration = configuration(type = type)
every { configurationSource.get(type) } returns configuration
@ -144,7 +156,7 @@ class ConfigurationServiceTest {
@Test
fun `get(type) throws ConfigurationNotSetException when the given ConfigurationType has no set configuration`() {
val type = ConfigurationType.INSTANCE_ICON_PATH
val type = ConfigurationType.INSTANCE_ICON_SET
every { configurationSource.get(type) } returns null
@ -228,6 +240,57 @@ class ConfigurationServiceTest {
assertThrows<UnsupportedOperationException> { service.getSecure(type) }
}
private fun getConfiguredImageTest(
configurationType: ConfigurationType,
imageSet: Boolean,
test: (Resource) -> Unit
) {
val resource = mockk<Resource>()
val configuration = configuration(configurationType, imageSet.toString())
val imageService = if (imageSet) fileService else resourceFileService
every { service.get(configurationType) } returns configuration
every { imageService.read(any()) } returns resource
test(resource)
}
@Test
fun `getConfiguredIcon() gets icon from resources when INSTANCE_ICON_SET configuration is false`() {
getConfiguredImageTest(ConfigurationType.INSTANCE_ICON_SET, false) { resource ->
val found = service.getConfiguredIcon()
assertEquals(resource, found)
}
}
@Test
fun `getConfiguredIcon() gets icon from files when INSTANCE_ICON_SET configuration is true`() {
getConfiguredImageTest(ConfigurationType.INSTANCE_ICON_SET, true) { resource ->
val found = service.getConfiguredIcon()
assertEquals(resource, found)
}
}
@Test
fun `getConfiguredLogo() gets logo from resources when INSTANCE_LOGO_SET is false`() {
getConfiguredImageTest(ConfigurationType.INSTANCE_LOGO_SET, false) { resource ->
val found = service.getConfiguredLogo()
assertEquals(resource, found)
}
}
@Test
fun `getConfiguredLogo() gets logo from files when INSTANCE_LOGO_SET is true`() {
getConfiguredImageTest(ConfigurationType.INSTANCE_LOGO_SET, true) { resource ->
val found = service.getConfiguredLogo()
assertEquals(resource, found)
}
}
@Test
fun `set(configuration) set configuration in ConfigurationSource`() {
val configuration = configuration(type = ConfigurationType.INSTANCE_NAME)
@ -261,4 +324,65 @@ class ConfigurationServiceTest {
})
}
}
private fun setConfiguredImageTest(test: (MultipartFile) -> Unit) {
val file = mockk<MultipartFile>()
every { service.set(any<Configuration>()) } just runs
every { fileService.write(any<MultipartFile>(), any(), any()) } just runs
test(file)
}
@Test
fun `setConfiguredIcon() sets icon in files`() {
setConfiguredImageTest { file ->
service.setConfiguredIcon(file)
verify {
fileService.write(file, any(), true)
}
}
}
@Test
fun `setConfiguredIcon() sets INSTANCE_ICON_SET configuration to true`() {
val type = ConfigurationType.INSTANCE_ICON_SET
setConfiguredImageTest { file ->
service.setConfiguredIcon(file)
verify {
service.set(match<Configuration> {
it.key == type.key && it.content == true.toString()
})
}
}
}
@Test
fun `setConfiguredLogo() sets logo in files`() {
setConfiguredImageTest { file ->
service.setConfiguredLogo(file)
verify {
fileService.write(file, any(), true)
}
}
}
@Test
fun `setConfiguredLogo() sets INSTANCE_LOGO_SET configuration to true`() {
val type = ConfigurationType.INSTANCE_LOGO_SET
setConfiguredImageTest { file ->
service.setConfiguredLogo(file)
verify {
service.set(match<Configuration> {
it.key == type.key && it.content == true.toString()
})
}
}
}
}

View File

@ -4,7 +4,7 @@ import com.nhaarman.mockitokotlin2.*
import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException
import dev.fyloz.colorrecipesexplorer.model.*
import dev.fyloz.colorrecipesexplorer.repository.MaterialRepository
import dev.fyloz.colorrecipesexplorer.service.FileService
import dev.fyloz.colorrecipesexplorer.service.files.WriteableFileService
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
@ -21,7 +21,7 @@ class MaterialServiceTest :
private val recipeService: RecipeService = mock()
private val mixService: MixService = mock()
private val materialTypeService: MaterialTypeService = mock()
private val fileService: FileService = mock()
private val fileService: WriteableFileService = mock()
override val service: MaterialService =
spy(MaterialServiceImpl(repository, recipeService, mixService, materialTypeService, fileService, mock()))

View File

@ -6,6 +6,7 @@ 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 dev.fyloz.colorrecipesexplorer.service.files.WriteableFileService
import io.mockk.*
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
@ -263,7 +264,7 @@ class RecipeServiceTest :
}
private class RecipeImageServiceTestContext {
val fileService = mockk<FileService> {
val fileService = mockk<WriteableFileService> {
every { write(any<MultipartFile>(), any(), any()) } just Runs
every { delete(any()) } just Runs
}

View File

@ -1,11 +1,10 @@
package dev.fyloz.colorrecipesexplorer.service
import dev.fyloz.colorrecipesexplorer.config.properties.CreProperties
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.service.files.WriteableFileService
import dev.fyloz.colorrecipesexplorer.utils.PdfDocument
import dev.fyloz.colorrecipesexplorer.utils.toByteArrayResource
import io.mockk.*
@ -16,10 +15,9 @@ import kotlin.test.assertEquals
private class TouchUpKitServiceTestContext {
val touchUpKitRepository = mockk<TouchUpKitRepository>()
val fileService = mockk<FileService> {
val fileService = mockk<WriteableFileService> {
every { write(any<ByteArrayResource>(), any(), any()) } just Runs
}
val creProperties = mockk<CreProperties>()
val configService = mockk<ConfigurationService>(relaxed = true)
val touchUpKitService = spyk(TouchUpKitServiceImpl(fileService, configService, touchUpKitRepository))
val pdfDocumentData = mockk<ByteArrayResource>()

View File

@ -1,4 +1,4 @@
package dev.fyloz.colorrecipesexplorer.service
package dev.fyloz.colorrecipesexplorer.service.files
import dev.fyloz.colorrecipesexplorer.config.properties.CreProperties
import io.mockk.*

View File

@ -0,0 +1,114 @@
package dev.fyloz.colorrecipesexplorer.service.files
import io.mockk.clearAllMocks
import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.springframework.core.io.Resource
import org.springframework.core.io.ResourceLoader
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class ResourceFileServiceTest {
private val resourceLoader = mockk<ResourceLoader>()
private val service = spyk(ResourceFileService(resourceLoader))
@AfterEach
fun afterEach() {
clearAllMocks()
}
private fun existsTest(shouldExists: Boolean, test: (String) -> Unit) {
val path = "unit_test_resource"
with(service) {
every { path.fullPath() } returns mockk {
every { resource } returns mockk {
every { exists() } returns shouldExists
}
}
test(path)
}
}
@Test
fun `exists() returns true when a resource exists at the given path`() {
existsTest(true) { path ->
val found = service.exists(path)
assertTrue { found }
}
}
@Test
fun `exists() returns false when no resource exists at the given path`() {
existsTest(false) { path ->
val found = service.exists(path)
assertFalse { found }
}
}
private fun readTest(shouldExists: Boolean, test: (Resource, String) -> Unit) {
val mockResource = mockk<Resource> {
every { exists() } returns shouldExists
}
val path = "unit_test_path"
with(service) {
every { path.fullPath() } returns mockk {
every { resource } returns mockResource
}
test(mockResource, path)
}
}
@Test
fun `read() returns the resource at the given path`() {
readTest(true) { resource, path ->
val found = service.read(path)
assertEquals(resource, found)
}
}
@Test
fun `read() throws FileNotFoundException when no resource exists at the given path`() {
readTest(false) { _, path ->
assertThrows<FileNotFoundException> {
service.read(path)
}
}
}
@Test
fun `fullPath() returns the given path in the classpath`() {
val path = "unit_test_path"
val expectedPath = "classpath:$path"
with(service) {
val found = path.fullPath()
assertEquals(expectedPath, found.path)
}
}
@Test
fun `resource returns a resource for the given path`() {
val filePath = FilePath("classpath:unit_test_path")
val resource = mockk<Resource>()
every { resourceLoader.getResource(filePath.path) } returns resource
with(service) {
val found = filePath.resource
assertEquals(resource, found)
}
}
}