From 3739d09463e930f97e16152cf16b38e512508ef9 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 12:48:56 +0900 Subject: [PATCH 01/13] =?UTF-8?q?test:=20account=20api=E3=81=AE=E3=83=86?= =?UTF-8?q?=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 --- .../kotlin/mastodon/account/AccountApiTest.kt | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/intTest/kotlin/mastodon/account/AccountApiTest.kt diff --git a/src/intTest/kotlin/mastodon/account/AccountApiTest.kt b/src/intTest/kotlin/mastodon/account/AccountApiTest.kt new file mode 100644 index 00000000..88168a51 --- /dev/null +++ b/src/intTest/kotlin/mastodon/account/AccountApiTest.kt @@ -0,0 +1,136 @@ +package mastodon.account + +import dev.usbharu.hideout.SpringApplication +import dev.usbharu.hideout.core.infrastructure.exposedquery.UserQueryServiceImpl +import kotlinx.coroutines.test.runTest +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +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.http.MediaType +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.context.support.WithAnonymousUser +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.get +import org.springframework.test.web.servlet.post +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 AccountApiTest { + + @Autowired + private lateinit var userQueryServiceImpl: UserQueryServiceImpl + + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(springSecurity()) + .build() + } + + @Test + fun `apiV1AccountsVerifyCredentialsGetにreadでアクセスできる`() { + mockMvc + .get("/api/v1/accounts/verify_credentials") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsVerifyCredentialsGetにread_accountsでアクセスできる`() { + mockMvc + .get("/api/v1/accounts/verify_credentials") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:accounts"))) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + } + + @Test + @WithAnonymousUser + fun apiV1AccountsVerifyCredentialsGetに匿名でアクセスすると401() { + mockMvc + .get("/api/v1/accounts/verify_credentials") + .andExpect { status { isUnauthorized() } } + } + + @Test + @WithAnonymousUser + fun apiV1AccountsPostに匿名でPOSTしたらアカウントを作成できる() = runTest { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("username", "api-test-user-1") + param("password", "very-secure-password") + param("email", "test@example.com") + param("agreement", "true") + param("locale", "") + with(SecurityMockMvcRequestPostProcessors.csrf()) + } + .asyncDispatch() + .andExpect { status { isFound() } } + + userQueryServiceImpl.findByNameAndDomain("api-test-user-1", "localhost") + } + + @Test + @WithAnonymousUser + fun apiV1AccountsPostで必須パラメーター以外を省略しても作成できる() = runTest { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("username", "api-test-user-2") + param("password", "very-secure-password") + with(SecurityMockMvcRequestPostProcessors.csrf()) + } + .asyncDispatch() + .andExpect { status { isFound() } } + + userQueryServiceImpl.findByNameAndDomain("api-test-user-2", "localhost") + } + + @Test + @WithAnonymousUser + fun apiV1AccountsPostでusernameパラメーターを省略したら400() = runTest { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("username", "api-test-user-3") + with(SecurityMockMvcRequestPostProcessors.csrf()) + } + .andExpect { status { isBadRequest() } } + } + + @Test + @WithAnonymousUser + fun apiV1AccountsPostでpasswordパラメーターを省略したら400() = runTest { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("username", "api-test-user-3") + with(SecurityMockMvcRequestPostProcessors.csrf()) + } + .andExpect { status { isBadRequest() } } + } +} From c4c31bae757ceed0e43bb367d9bbeb6f3cee87d6 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 12:49:18 +0900 Subject: [PATCH 02/13] =?UTF-8?q?test:=20apps=20api=E3=81=AE=E3=83=86?= =?UTF-8?q?=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 | 4 +- gradle.properties | 2 +- src/intTest/kotlin/mastodon/apps/AppTest.kt | 88 +++++++++++++++++++++ src/intTest/resources/application.yml | 10 +-- 4 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 src/intTest/kotlin/mastodon/apps/AppTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index b5f5cb83..a17c93a4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,7 +13,7 @@ plugins { kotlin("jvm") version "1.8.21" id("org.graalvm.buildtools.native") version "0.9.21" id("io.gitlab.arturbosch.detekt") version "1.23.1" - id("org.springframework.boot") version "3.1.3" + id("org.springframework.boot") version "3.2.0" kotlin("plugin.spring") version "1.8.21" id("org.openapi.generator") version "7.0.1" id("org.jetbrains.kotlinx.kover") version "0.7.4" @@ -206,6 +206,8 @@ dependencies { intTestImplementation("org.springframework.boot:spring-boot-starter-test") 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") } diff --git a/gradle.properties b/gradle.properties index a7ffe13f..5516464a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ ktor_version=2.3.0 -kotlin_version=1.8.21 +kotlin_version=1.9.21 logback_version=1.4.6 kotlin.code.style=official exposed_version=0.44.0 diff --git a/src/intTest/kotlin/mastodon/apps/AppTest.kt b/src/intTest/kotlin/mastodon/apps/AppTest.kt new file mode 100644 index 00000000..f835d3be --- /dev/null +++ b/src/intTest/kotlin/mastodon/apps/AppTest.kt @@ -0,0 +1,88 @@ +package mastodon.apps + +import dev.usbharu.hideout.SpringApplication +import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.RegisteredClient +import org.assertj.core.api.Assertions.assertThat +import org.jetbrains.exposed.sql.select +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +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.http.MediaType +import org.springframework.security.test.context.support.WithAnonymousUser +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.post +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 +class AppTest { + + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + @Test + @WithAnonymousUser + fun apiV1AppsPostにformで匿名でappを作成できる() { + mockMvc + .post("/api/v1/apps") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("client_name", "test-client") + param("redirect_uris", "https://example.com") + param("scopes", "write read") + param("website", "https://example.com") + } + .asyncDispatch() + .andExpect { status { isOk() } } + + + val app = RegisteredClient + .select { RegisteredClient.clientName eq "test-client" } + .single() + + assertThat(app[RegisteredClient.clientName]).isEqualTo("test-client") + assertThat(app[RegisteredClient.redirectUris]).isEqualTo("https://example.com") + assertThat(app[RegisteredClient.scopes]).isEqualTo("read,write") + } + + @Test + @WithAnonymousUser + fun apiV1AppsPostにjsonで匿名でappを作成できる() { + mockMvc + .post("/api/v1/apps") { + contentType = MediaType.APPLICATION_JSON + content = """{ + "client_name": "test-client-2", + "redirect_uris": "https://example.com", + "scopes": "write read", + "website": "https;//example.com" +}""" + } + .asyncDispatch() + .andExpect { status { isOk() } } + + val app = RegisteredClient + .select { RegisteredClient.clientName eq "test-client-2" } + .single() + + assertThat(app[RegisteredClient.clientName]).isEqualTo("test-client-2") + assertThat(app[RegisteredClient.redirectUris]).isEqualTo("https://example.com") + assertThat(app[RegisteredClient.scopes]).isEqualTo("read,write") + } +} diff --git a/src/intTest/resources/application.yml b/src/intTest/resources/application.yml index 258014ca..3de298a1 100644 --- a/src/intTest/resources/application.yml +++ b/src/intTest/resources/application.yml @@ -18,10 +18,10 @@ hideout: spring: flyway: - enabled: false + enabled: true datasource: driver-class-name: org.h2.Driver - url: "jdbc:h2:mem:test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1" + url: "jdbc:h2:mem:test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4;" username: "" password: data: @@ -34,8 +34,8 @@ spring: console: enabled: true - exposed: - generate-ddl: true - excluded-packages: dev.usbharu.hideout.core.infrastructure.kjobexposed +# exposed: +# generate-ddl: true +# excluded-packages: dev.usbharu.hideout.core.infrastructure.kjobexposed server: port: 8080 From afc5efdec7ec0be0cbc878091db4a36b63377f8b 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 03/13] =?UTF-8?q?test:=20=E3=83=A1=E3=83=87=E3=82=A3?= =?UTF-8?q?=E3=82=A2=E3=82=A2=E3=83=83=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=AE=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 From 5788f423ba60d3e21c4432c76b2ab8d87cef564f Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 15:03:21 +0900 Subject: [PATCH 04/13] =?UTF-8?q?fix:=20png=E5=BD=A2=E5=BC=8F=E3=81=AE?= =?UTF-8?q?=E7=94=BB=E5=83=8F=E3=81=AE=E4=B8=80=E6=99=82=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E3=81=AE=E4=BD=9C=E6=88=90=E3=81=AB=E5=A4=B1?= =?UTF-8?q?=E6=95=97=E3=81=99=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../image/ImageMediaProcessService.kt | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/media/converter/image/ImageMediaProcessService.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/media/converter/image/ImageMediaProcessService.kt index d61d32ef..c713a63e 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/service/media/converter/image/ImageMediaProcessService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/media/converter/image/ImageMediaProcessService.kt @@ -13,6 +13,8 @@ import net.coobird.thumbnailator.Thumbnails import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Service +import java.awt.Color +import java.awt.image.BufferedImage import java.nio.file.Files import java.nio.file.Path import java.util.* @@ -57,7 +59,14 @@ class ImageMediaProcessService(private val imageMediaProcessorConfiguration: Ima filePath: Path, thumbnails: Path? ): ProcessedMediaPath = withContext(Dispatchers.IO + MDCContext()) { - val bufferedImage = ImageIO.read(filePath.inputStream()) + val read = ImageIO.read(filePath.inputStream()) + + val bufferedImage = BufferedImage(read.width, read.height, BufferedImage.TYPE_INT_RGB) + + val graphics = bufferedImage.createGraphics() + + graphics.drawImage(read, 0, 0, Color.BLACK, null) + val tempFileName = UUID.randomUUID().toString() val tempFile = Files.createTempFile(tempFileName, "tmp") @@ -67,9 +76,15 @@ class ImageMediaProcessService(private val imageMediaProcessorConfiguration: Ima tempThumbnailFile.outputStream().use { val write = ImageIO.write( if (thumbnails != null) { - Thumbnails.of(thumbnails.toFile()).size(width, height).asBufferedImage() + Thumbnails.of(thumbnails.toFile()) + .size(width, height) + .imageType(BufferedImage.TYPE_INT_RGB) + .asBufferedImage() } else { - Thumbnails.of(bufferedImage).size(width, height).asBufferedImage() + Thumbnails.of(bufferedImage) + .size(width, height) + .imageType(BufferedImage.TYPE_INT_RGB) + .asBufferedImage() }, convertType, it From d56ec95029b1f1c8af027ce3ee9ad1731f631056 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 15:17:52 +0900 Subject: [PATCH 05/13] =?UTF-8?q?test:=20=E3=83=A1=E3=83=87=E3=82=A3?= =?UTF-8?q?=E3=82=A2=E3=82=A2=E3=83=83=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=AE=E3=82=B9=E3=82=B3=E3=83=BC=E3=83=97=E3=81=AE=E3=83=86?= =?UTF-8?q?=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 --- src/intTest/kotlin/mastodon/MediaTest.kt | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/intTest/kotlin/mastodon/MediaTest.kt b/src/intTest/kotlin/mastodon/MediaTest.kt index 1a170c81..d3e54e88 100644 --- a/src/intTest/kotlin/mastodon/MediaTest.kt +++ b/src/intTest/kotlin/mastodon/MediaTest.kt @@ -68,4 +68,46 @@ class MediaTest { .asyncDispatch() .andExpect { status { isOk() } } } + + @Test + fun write_mediaスコープでメディアをアップロードできる() = 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:media"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun 権限がないと403() = 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_read"))) + } + .andExpect { status { isForbidden() } } + } + } From ccb036ebc140a315a1f6a7a4e2a5e5e5e8401a9c Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 15:18:12 +0900 Subject: [PATCH 06/13] =?UTF-8?q?fix:=20=E3=83=A1=E3=83=87=E3=82=A3?= =?UTF-8?q?=E3=82=A2=E3=82=A2=E3=83=83=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=AE=E3=82=B9=E3=82=B3=E3=83=BC=E3=83=97=E3=81=AE=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev/usbharu/hideout/application/config/SecurityConfig.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt b/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt index 089a545a..7d4b2d8e 100644 --- a/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt @@ -190,6 +190,8 @@ class SecurityConfig { it.requestMatchers(builder.pattern("/change-password")).authenticated() it.requestMatchers(builder.pattern("/api/v1/accounts/verify_credentials")) .hasAnyAuthority("SCOPE_read", "SCOPE_read:accounts") + it.requestMatchers(builder.pattern(HttpMethod.POST, "/api/v1/media")) + .hasAnyAuthority("SCOPE_write", "SCOPE_write:media") it.anyRequest().permitAll() } http.oauth2ResourceServer { From 9146d3911636bcc6c528235cce68291a5b05aedb Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 15:33:53 +0900 Subject: [PATCH 07/13] =?UTF-8?q?refactor:=20MediaTest.kt=E3=82=92?= =?UTF-8?q?=E7=A7=BB=E5=8B=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/intTest/kotlin/mastodon/{ => media}/MediaTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/intTest/kotlin/mastodon/{ => media}/MediaTest.kt (99%) diff --git a/src/intTest/kotlin/mastodon/MediaTest.kt b/src/intTest/kotlin/mastodon/media/MediaTest.kt similarity index 99% rename from src/intTest/kotlin/mastodon/MediaTest.kt rename to src/intTest/kotlin/mastodon/media/MediaTest.kt index d3e54e88..898462df 100644 --- a/src/intTest/kotlin/mastodon/MediaTest.kt +++ b/src/intTest/kotlin/mastodon/media/MediaTest.kt @@ -1,4 +1,4 @@ -package mastodon +package mastodon.media import dev.usbharu.hideout.SpringApplication import dev.usbharu.hideout.core.service.media.MediaDataStore From 2d0293aa25f26d0d0e277e8479093fc06fcdecb6 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:23:59 +0900 Subject: [PATCH 08/13] =?UTF-8?q?test:=20Status=E3=81=AE=E3=83=86=E3=82=B9?= =?UTF-8?q?=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 --- .../kotlin/mastodon/status/StatusTest.kt | 145 ++++++++++++++++++ src/intTest/resources/logback.xml | 1 + src/intTest/resources/sql/test-post.sql | 3 + 3 files changed, 149 insertions(+) create mode 100644 src/intTest/kotlin/mastodon/status/StatusTest.kt create mode 100644 src/intTest/resources/sql/test-post.sql diff --git a/src/intTest/kotlin/mastodon/status/StatusTest.kt b/src/intTest/kotlin/mastodon/status/StatusTest.kt new file mode 100644 index 00000000..2272895a --- /dev/null +++ b/src/intTest/kotlin/mastodon/status/StatusTest.kt @@ -0,0 +1,145 @@ +package mastodon.status + +import dev.usbharu.hideout.SpringApplication +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +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.http.MediaType +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.context.support.WithAnonymousUser +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf +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.post +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 StatusTest { + + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + @Test + fun 投稿できる() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun write_statusesスコープで投稿できる() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:statuses")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun 権限がないと403() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + @WithAnonymousUser + fun 匿名だと401() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + with(csrf()) + } + .andExpect { status { isUnauthorized() } } + } + + @Test + @WithAnonymousUser + fun 匿名の場合通常はcsrfが無いので403() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + } + .andExpect { status { isForbidden() } } + } + + @Test + fun formでも投稿できる() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("status", "hello") + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:statuses")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + @Sql("/sql/test-post.sql") + fun in_reply_to_idを指定したら返信として処理される() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + //language=JSON + content = """{ + "status": "hello", + "in_reply_to_id": "1" +}""" + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + .andExpect { jsonPath("\$.in_reply_to_id") { value("1") } } + } +} diff --git a/src/intTest/resources/logback.xml b/src/intTest/resources/logback.xml index 54cfd39a..a8bb21c4 100644 --- a/src/intTest/resources/logback.xml +++ b/src/intTest/resources/logback.xml @@ -7,4 +7,5 @@ + diff --git a/src/intTest/resources/sql/test-post.sql b/src/intTest/resources/sql/test-post.sql new file mode 100644 index 00000000..01bcb2dd --- /dev/null +++ b/src/intTest/resources/sql/test-post.sql @@ -0,0 +1,3 @@ +insert into posts (id, user_id, overview, text, created_at, visibility, url, repost_id, reply_id, sensitive, ap_id) +VALUES (1, 1, null, 'hello', 1234455, 0, 'https://localhost/users/1/posts/1', null, null, false, + 'https://users/1/posts/1'); From 5da3bc9d54d759e0a292429ebdd30ff611df19b6 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:24:30 +0900 Subject: [PATCH 09/13] =?UTF-8?q?fix:=20=E8=BF=94=E4=BF=A1=E3=81=8C?= =?UTF-8?q?=E7=84=A1=E8=A6=96=E3=81=95=E3=82=8C=E3=81=A6=E3=81=84=E3=81=9F?= =?UTF-8?q?=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usbharu/hideout/core/service/post/PostServiceImpl.kt | 4 +++- .../mastodon/service/status/StatusesApiService.kt | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImpl.kt index 027b3274..2e2c6c0c 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImpl.kt @@ -65,7 +65,9 @@ class PostServiceImpl( createdAt = Instant.now().toEpochMilli(), visibility = post.visibility, url = "${user.url}/posts/$id", - mediaIds = post.mediaIds + mediaIds = post.mediaIds, + replyId = post.repolyId, + repostId = post.repostId, ) return internalCreate(createPost, isLocal) } diff --git a/src/main/kotlin/dev/usbharu/hideout/mastodon/service/status/StatusesApiService.kt b/src/main/kotlin/dev/usbharu/hideout/mastodon/service/status/StatusesApiService.kt index 10b1a0c5..198681ce 100644 --- a/src/main/kotlin/dev/usbharu/hideout/mastodon/service/status/StatusesApiService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/mastodon/service/status/StatusesApiService.kt @@ -13,6 +13,7 @@ import dev.usbharu.hideout.mastodon.interfaces.api.status.StatusesRequest import dev.usbharu.hideout.mastodon.interfaces.api.status.toPostVisibility import dev.usbharu.hideout.mastodon.interfaces.api.status.toStatusVisibility import dev.usbharu.hideout.mastodon.service.account.AccountService +import org.slf4j.LoggerFactory import org.springframework.stereotype.Service import java.time.Instant @@ -38,12 +39,14 @@ class StatsesApiServiceImpl( statusesRequest: StatusesRequest, userId: Long ): Status = transaction.transaction { + logger.debug("START create post by mastodon api. {}", statusesRequest) + val post = postService.createLocal( PostCreateDto( text = statusesRequest.status.orEmpty(), overview = statusesRequest.spoiler_text, visibility = statusesRequest.visibility.toPostVisibility(), - repolyId = statusesRequest.in_reply_to_id?.toLongOrNull(), + repolyId = statusesRequest.in_reply_to_id?.toLong(), userId = userId, mediaIds = statusesRequest.media_ids.map { it.toLong() } ) @@ -91,4 +94,8 @@ class StatsesApiServiceImpl( editedAt = null, ) } + + companion object { + private val logger = LoggerFactory.getLogger(StatusesApiService::class.java) + } } From a673ae1443f445a23f98088ac078727bec5084ca Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:24:54 +0900 Subject: [PATCH 10/13] =?UTF-8?q?fix:=20=E6=8A=95=E7=A8=BF=E3=81=AE?= =?UTF-8?q?=E3=82=B9=E3=82=B3=E3=83=BC=E3=83=97=E3=81=AE=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usbharu/hideout/application/config/SecurityConfig.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt b/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt index 7d4b2d8e..b29a8e94 100644 --- a/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt @@ -182,7 +182,8 @@ class SecurityConfig { builder.pattern("/api/v1/instance/**"), builder.pattern("/.well-known/**"), builder.pattern("/error"), - builder.pattern("/nodeinfo/2.0") + builder.pattern("/nodeinfo/2.0"), + builder.pattern("/api/v1/accounts") ).permitAll() it.requestMatchers( builder.pattern("/auth/**") @@ -192,7 +193,9 @@ class SecurityConfig { .hasAnyAuthority("SCOPE_read", "SCOPE_read:accounts") it.requestMatchers(builder.pattern(HttpMethod.POST, "/api/v1/media")) .hasAnyAuthority("SCOPE_write", "SCOPE_write:media") - it.anyRequest().permitAll() + it.requestMatchers(builder.pattern(HttpMethod.POST, "/api/v1/statuses")) + .hasAnyAuthority("SCOPE_write", "SCOPE_write:statuses") + it.anyRequest().authenticated() } http.oauth2ResourceServer { it.jwt(Customizer.withDefaults()) From 1200a774e7f9ab2d505865d41767f628ab2f5917 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 29 Nov 2023 18:25:02 +0900 Subject: [PATCH 11/13] chore: build logging --- build.gradle.kts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index e507ec54..dfa827dd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.openapitools.generator.gradle.plugin.tasks.GenerateTask import kotlin.math.max @@ -68,6 +70,21 @@ tasks.withType { "--add-opens", "java.base/java.lang=ALL-UNNAMED" ).toMutableList() } + testLogging { + events( + TestLogEvent.FAILED, + TestLogEvent.SKIPPED, + TestLogEvent.PASSED, + TestLogEvent.STANDARD_OUT, + TestLogEvent.STANDARD_ERROR, + TestLogEvent.STARTED + ) + exceptionFormat = TestExceptionFormat.FULL + showCauses = true + showExceptions = true + showStackTraces = true + setShowStandardStreams(true) + } } tasks.withType>().configureEach { From cd7ccaf3f72e750c9702cd25d15d9b42a1691b18 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Thu, 30 Nov 2023 00:50:18 +0900 Subject: [PATCH 12/13] =?UTF-8?q?test:=20=E5=85=A8=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E5=BE=8C=E3=81=ABDB=E3=82=92Drop=E3=81=99=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 5 ++--- src/intTest/kotlin/activitypub/inbox/InboxTest.kt | 11 +++++++++++ src/intTest/kotlin/activitypub/note/NoteTest.kt | 11 +++++++++++ .../kotlin/activitypub/webfinger/WebFingerTest.kt | 12 ++++++++++++ .../kotlin/mastodon/account/AccountApiTest.kt | 12 +++++++++++- src/intTest/kotlin/mastodon/apps/AppTest.kt | 11 +++++++++++ src/intTest/kotlin/mastodon/media/MediaTest.kt | 11 +++++++++++ src/intTest/kotlin/mastodon/status/StatusTest.kt | 11 +++++++++++ src/intTest/resources/application.yml | 1 + 9 files changed, 81 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index dfa827dd..a5d52f43 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,6 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.openapitools.generator.gradle.plugin.tasks.GenerateTask -import kotlin.math.max val ktor_version: String by project val kotlin_version: String by project @@ -63,8 +62,8 @@ tasks.check { dependsOn(integrationTest) } tasks.withType { useJUnitPlatform() val cpus = Runtime.getRuntime().availableProcessors() - maxParallelForks = max(1, cpus - 1) - setForkEvery(4) +// maxParallelForks = max(1, cpus - 1) +// setForkEvery(4) doFirst { jvmArgs = arrayOf( "--add-opens", "java.base/java.lang=ALL-UNNAMED" diff --git a/src/intTest/kotlin/activitypub/inbox/InboxTest.kt b/src/intTest/kotlin/activitypub/inbox/InboxTest.kt index 080639b4..a1d2c64f 100644 --- a/src/intTest/kotlin/activitypub/inbox/InboxTest.kt +++ b/src/intTest/kotlin/activitypub/inbox/InboxTest.kt @@ -1,6 +1,8 @@ package activitypub.inbox import dev.usbharu.hideout.SpringApplication +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -92,4 +94,13 @@ class InboxTest { @Bean fun testTransaction() = TestTransaction } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } } diff --git a/src/intTest/kotlin/activitypub/note/NoteTest.kt b/src/intTest/kotlin/activitypub/note/NoteTest.kt index a559ca66..d2067aa7 100644 --- a/src/intTest/kotlin/activitypub/note/NoteTest.kt +++ b/src/intTest/kotlin/activitypub/note/NoteTest.kt @@ -1,6 +1,8 @@ package activitypub.note import dev.usbharu.hideout.SpringApplication +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -178,4 +180,13 @@ class NoteTest { .andExpect { jsonPath("\$.attachment[1].type") { value("Document") } } .andExpect { jsonPath("\$.attachment[1].url") { value("https://example.com/media/test-media2.png") } } } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } } diff --git a/src/intTest/kotlin/activitypub/webfinger/WebFingerTest.kt b/src/intTest/kotlin/activitypub/webfinger/WebFingerTest.kt index d0faaa7f..abee25d6 100644 --- a/src/intTest/kotlin/activitypub/webfinger/WebFingerTest.kt +++ b/src/intTest/kotlin/activitypub/webfinger/WebFingerTest.kt @@ -2,6 +2,8 @@ package activitypub.webfinger import dev.usbharu.hideout.SpringApplication import dev.usbharu.hideout.application.external.Transaction +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc @@ -24,6 +26,7 @@ class WebFingerTest { @Test @Sql("/sql/test-user.sql") + fun `webfinger 存在するユーザーを取得`() { mockMvc .get("/.well-known/webfinger?resource=acct:test-user@example.com") @@ -80,4 +83,13 @@ class WebFingerTest { @Bean fun testTransaction(): Transaction = TestTransaction } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } } diff --git a/src/intTest/kotlin/mastodon/account/AccountApiTest.kt b/src/intTest/kotlin/mastodon/account/AccountApiTest.kt index 88168a51..b08e2cc5 100644 --- a/src/intTest/kotlin/mastodon/account/AccountApiTest.kt +++ b/src/intTest/kotlin/mastodon/account/AccountApiTest.kt @@ -3,6 +3,8 @@ package mastodon.account import dev.usbharu.hideout.SpringApplication import dev.usbharu.hideout.core.infrastructure.exposedquery.UserQueryServiceImpl import kotlinx.coroutines.test.runTest +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -37,7 +39,6 @@ class AccountApiTest { private lateinit var mockMvc: MockMvc - @BeforeEach fun setUp() { mockMvc = MockMvcBuilders.webAppContextSetup(context) @@ -133,4 +134,13 @@ class AccountApiTest { } .andExpect { status { isBadRequest() } } } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } } diff --git a/src/intTest/kotlin/mastodon/apps/AppTest.kt b/src/intTest/kotlin/mastodon/apps/AppTest.kt index f835d3be..026a9163 100644 --- a/src/intTest/kotlin/mastodon/apps/AppTest.kt +++ b/src/intTest/kotlin/mastodon/apps/AppTest.kt @@ -3,7 +3,9 @@ package mastodon.apps import dev.usbharu.hideout.SpringApplication import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.RegisteredClient import org.assertj.core.api.Assertions.assertThat +import org.flywaydb.core.Flyway import org.jetbrains.exposed.sql.select +import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -85,4 +87,13 @@ class AppTest { assertThat(app[RegisteredClient.redirectUris]).isEqualTo("https://example.com") assertThat(app[RegisteredClient.scopes]).isEqualTo("read,write") } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } } diff --git a/src/intTest/kotlin/mastodon/media/MediaTest.kt b/src/intTest/kotlin/mastodon/media/MediaTest.kt index 898462df..4c9ee710 100644 --- a/src/intTest/kotlin/mastodon/media/MediaTest.kt +++ b/src/intTest/kotlin/mastodon/media/MediaTest.kt @@ -5,6 +5,8 @@ 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.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.mockito.kotlin.any @@ -110,4 +112,13 @@ class MediaTest { .andExpect { status { isForbidden() } } } + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } + } diff --git a/src/intTest/kotlin/mastodon/status/StatusTest.kt b/src/intTest/kotlin/mastodon/status/StatusTest.kt index 2272895a..54b61c9d 100644 --- a/src/intTest/kotlin/mastodon/status/StatusTest.kt +++ b/src/intTest/kotlin/mastodon/status/StatusTest.kt @@ -1,6 +1,8 @@ package mastodon.status import dev.usbharu.hideout.SpringApplication +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -142,4 +144,13 @@ class StatusTest { .andExpect { status { isOk() } } .andExpect { jsonPath("\$.in_reply_to_id") { value("1") } } } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } } diff --git a/src/intTest/resources/application.yml b/src/intTest/resources/application.yml index 3de298a1..b40fcd91 100644 --- a/src/intTest/resources/application.yml +++ b/src/intTest/resources/application.yml @@ -19,6 +19,7 @@ hideout: spring: flyway: enabled: true + clean-disabled: false datasource: driver-class-name: org.h2.Driver url: "jdbc:h2:mem:test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4;" From d0650adbcab638d2480da336bc8ac4cd61fafd03 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Thu, 30 Nov 2023 00:52:05 +0900 Subject: [PATCH 13/13] =?UTF-8?q?chore:=20=E3=83=86=E3=82=B9=E3=83=88?= =?UTF-8?q?=E6=99=82=E3=81=AE=E3=83=AD=E3=82=B0=E3=82=92=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a5d52f43..7a5f4242 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,4 @@ -import org.gradle.api.tasks.testing.logging.TestExceptionFormat -import org.gradle.api.tasks.testing.logging.TestLogEvent + import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.openapitools.generator.gradle.plugin.tasks.GenerateTask @@ -51,10 +50,6 @@ val integrationTest = task("integrationTest") { shouldRunAfter("test") useJUnitPlatform() - - testLogging { - events("passed") - } } tasks.check { dependsOn(integrationTest) } @@ -69,21 +64,6 @@ tasks.withType { "--add-opens", "java.base/java.lang=ALL-UNNAMED" ).toMutableList() } - testLogging { - events( - TestLogEvent.FAILED, - TestLogEvent.SKIPPED, - TestLogEvent.PASSED, - TestLogEvent.STANDARD_OUT, - TestLogEvent.STANDARD_ERROR, - TestLogEvent.STARTED - ) - exceptionFormat = TestExceptionFormat.FULL - showCauses = true - showExceptions = true - showStackTraces = true - setShowStandardStreams(true) - } } tasks.withType>().configureEach {