From a91bb89859e23beb96b18c85ebb8bbd33ddeb270 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 15:02:46 +0900 Subject: [PATCH] =?UTF-8?q?test:=20=E3=83=A1=E3=83=87=E3=82=A3=E3=82=A2?= =?UTF-8?q?=E3=82=A2=E3=83=83=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89=E3=81=AE?= =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 + src/intTest/kotlin/mastodon/MediaTest.kt | 71 ++++++++++++++++++ src/intTest/resources/media/400x400.png | Bin 0 -> 7227 bytes ...cheTikaFileTypeDeterminationServiceTest.kt | 19 +++++ .../service/media/MediaServiceImplTest.kt | 11 +++ src/test/resources/400x400.png | Bin 0 -> 7227 bytes 6 files changed, 103 insertions(+) create mode 100644 src/intTest/kotlin/mastodon/MediaTest.kt create mode 100644 src/intTest/resources/media/400x400.png create mode 100644 src/test/kotlin/dev/usbharu/hideout/core/service/media/ApatcheTikaFileTypeDeterminationServiceTest.kt create mode 100644 src/test/kotlin/dev/usbharu/hideout/core/service/media/MediaServiceImplTest.kt create mode 100644 src/test/resources/400x400.png diff --git a/build.gradle.kts b/build.gradle.kts index a17c93a4..e507ec54 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -180,6 +180,7 @@ dependencies { implementation("org.postgresql:postgresql:42.6.0") implementation("com.twelvemonkeys.imageio:imageio-webp:3.10.0") implementation("org.apache.tika:tika-core:2.9.1") + implementation("org.apache.tika:tika-parsers:2.9.1") implementation("net.coobird:thumbnailator:0.4.20") implementation("org.bytedeco:javacv-platform:1.5.9") implementation("org.flywaydb:flyway-core") @@ -208,6 +209,7 @@ dependencies { intTestImplementation("org.springframework.security:spring-security-test") intTestImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") intTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4") + intTestImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") } diff --git a/src/intTest/kotlin/mastodon/MediaTest.kt b/src/intTest/kotlin/mastodon/MediaTest.kt new file mode 100644 index 00000000..1a170c81 --- /dev/null +++ b/src/intTest/kotlin/mastodon/MediaTest.kt @@ -0,0 +1,71 @@ +package mastodon + +import dev.usbharu.hideout.SpringApplication +import dev.usbharu.hideout.core.service.media.MediaDataStore +import dev.usbharu.hideout.core.service.media.MediaSaveRequest +import dev.usbharu.hideout.core.service.media.SuccessSavedMedia +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.whenever +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.mock.mockito.MockBean +import org.springframework.mock.web.MockMultipartFile +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.multipart +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext + +@SpringBootTest(classes = [SpringApplication::class]) +@AutoConfigureMockMvc +@Transactional +@Sql("/sql/test-user.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +class MediaTest { + + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + + @MockBean + private lateinit var mediaDataStore: MediaDataStore + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + @Test + fun メディアをアップロードできる() = runTest { + whenever(mediaDataStore.save(any())).doReturn(SuccessSavedMedia("", "", "")) + + mockMvc + .multipart("/api/v1/media") { + + file( + MockMultipartFile( + "file", + "400x400.png", + "image/png", + String.javaClass.classLoader.getResourceAsStream("media/400x400.png") + ) + ) + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } +} diff --git a/src/intTest/resources/media/400x400.png b/src/intTest/resources/media/400x400.png new file mode 100644 index 0000000000000000000000000000000000000000..0d2e71bee323fed58e3aab0a839c0c2044bba54f GIT binary patch literal 7227 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 literal 0 HcmV?d00001 diff --git a/src/test/kotlin/dev/usbharu/hideout/core/service/media/ApatcheTikaFileTypeDeterminationServiceTest.kt b/src/test/kotlin/dev/usbharu/hideout/core/service/media/ApatcheTikaFileTypeDeterminationServiceTest.kt new file mode 100644 index 00000000..5b445356 --- /dev/null +++ b/src/test/kotlin/dev/usbharu/hideout/core/service/media/ApatcheTikaFileTypeDeterminationServiceTest.kt @@ -0,0 +1,19 @@ +package dev.usbharu.hideout.core.service.media + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import kotlin.io.path.toPath + +class ApatcheTikaFileTypeDeterminationServiceTest { + @Test + fun png() { + val apatcheTikaFileTypeDeterminationService = ApatcheTikaFileTypeDeterminationService() + + val mimeType = apatcheTikaFileTypeDeterminationService.fileType( + String.javaClass.classLoader.getResource("400x400.png").toURI().toPath(), "400x400.png" + ) + + assertThat(mimeType.type).isEqualTo("image") + assertThat(mimeType.subtype).isEqualTo("png") + } +} diff --git a/src/test/kotlin/dev/usbharu/hideout/core/service/media/MediaServiceImplTest.kt b/src/test/kotlin/dev/usbharu/hideout/core/service/media/MediaServiceImplTest.kt new file mode 100644 index 00000000..cec6e5aa --- /dev/null +++ b/src/test/kotlin/dev/usbharu/hideout/core/service/media/MediaServiceImplTest.kt @@ -0,0 +1,11 @@ +package dev.usbharu.hideout.core.service.media + + +import org.junit.jupiter.api.Test + +class MediaServiceImplTest { + @Test + fun png画像をアップロードできる() { + + } +} diff --git a/src/test/resources/400x400.png b/src/test/resources/400x400.png new file mode 100644 index 0000000000000000000000000000000000000000..0d2e71bee323fed58e3aab0a839c0c2044bba54f GIT binary patch literal 7227 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 literal 0 HcmV?d00001