From 27ccca02c04e4d369385fdb5da4edccf7e3e1920 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:45:51 +0900 Subject: [PATCH 01/40] =?UTF-8?q?test:=20Repository=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 --- hideout-core/build.gradle.kts | 1 + .../InstanceRepositoryImplTest.kt | 56 ++++++++++++ .../kotlin/utils/AbstractRepositoryTest.kt | 85 +++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt create mode 100644 hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt diff --git a/hideout-core/build.gradle.kts b/hideout-core/build.gradle.kts index 88b2bca3..d88f2ac3 100644 --- a/hideout-core/build.gradle.kts +++ b/hideout-core/build.gradle.kts @@ -132,6 +132,7 @@ dependencies { testImplementation(libs.ktor.client.mock) testImplementation(libs.h2db) testImplementation(libs.mockito.kotlin) + testImplementation("org.assertj:assertj-db:2.0.2") } detekt { diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt new file mode 100644 index 00000000..4755a2cb --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt @@ -0,0 +1,56 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import dev.usbharu.hideout.core.domain.model.instance.* +import dev.usbharu.hideout.core.domain.model.instance.Instance +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import utils.AbstractRepositoryTest +import utils.isEqualTo +import utils.value +import java.net.URI +import java.sql.Timestamp +import java.time.Instant +import dev.usbharu.hideout.core.infrastructure.exposedrepository.Instance as InstanceTable + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { + + + @Test + fun save() = runTest { + InstanceRepositoryImpl().save( + Instance( + id = InstanceId(1), + name = InstanceName("test"), + description = InstanceDescription("id"), + url = URI.create("https://www.example.com"), + iconUrl = URI.create("https://www.example.com"), + sharedInbox = null, + software = InstanceSoftware(""), + version = InstanceVersion(""), + isBlocked = false, + isMuted = false, + moderationNote = InstanceModerationNote(""), + createdAt = Instant.parse("2020-01-01T00:00:00Z"), + ) + ) + + val table = assertTable + assertThat(table) + .row(1) + .isEqualTo(InstanceTable.id, 1) + .isEqualTo(InstanceTable.name, "test") + .isEqualTo(InstanceTable.url, "https://www.example.com") + .isEqualTo(InstanceTable.iconUrl, "https://www.example.com") + .isEqualTo(InstanceTable.sharedInbox, null) + .isEqualTo(InstanceTable.software, "") + .isEqualTo(InstanceTable.version, "") + .isEqualTo(InstanceTable.isBlocked, false) + .isEqualTo(InstanceTable.isMuted, false) + .isEqualTo(InstanceTable.moderationNote, "") + .value(InstanceTable.createdAt).isEqualTo(Timestamp.from(Instant.parse("2020-01-01T00:00:00Z"))) + } +} + diff --git a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt new file mode 100644 index 00000000..e2ea2838 --- /dev/null +++ b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt @@ -0,0 +1,85 @@ +package utils + +import com.zaxxer.hikari.HikariConfig +import com.zaxxer.hikari.HikariDataSource +import org.assertj.db.api.TableRowAssert +import org.assertj.db.api.TableRowValueAssert +import org.assertj.db.type.Table +import org.flywaydb.core.Flyway +import org.jetbrains.exposed.sql.Column +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.DatabaseConfig +import org.jetbrains.exposed.sql.Transaction +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.BeforeEach +import java.sql.Connection +import javax.sql.DataSource + +abstract class AbstractRepositoryTest(private val exposedTable: org.jetbrains.exposed.sql.Table) { + + protected val assertTable: Table + get() { + return Table(dataSource, exposedTable.tableName) + } + + protected fun getTable(name: String): Table { + return Table(dataSource, name) + } + + private lateinit var transaction: Transaction + + @BeforeEach + fun setUp() { + transaction = TransactionManager.currentOrNew(Connection.TRANSACTION_READ_UNCOMMITTED) + } + + @AfterEach + fun tearDown() { + transaction.rollback() + } + + companion object { + + lateinit var dataSource: DataSource + lateinit var flyway: Flyway + + @JvmStatic + @BeforeAll + fun setup() { + val hikariConfig = HikariConfig() + hikariConfig.jdbcUrl = + "jdbc:h2:./test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4;" + hikariConfig.driverClassName = "org.h2.Driver" + hikariConfig.transactionIsolation = "TRANSACTION_READ_UNCOMMITTED" + dataSource = HikariDataSource(hikariConfig) + + + flyway = Flyway.configure().cleanDisabled(false).dataSource(dataSource).load() + val db = Database.connect(dataSource, databaseConfig = DatabaseConfig { + this.defaultMaxAttempts = 1 + }) + flyway.clean() + flyway.migrate() + } + + @JvmStatic + @AfterAll + fun clean() { +// flyway.clean() + } + } +} + +fun TableRowAssert.value(column: Column): TableRowValueAssert = value(column.name) +fun TableRowValueAssert.value(column: Column): TableRowValueAssert = value(column.name) + +fun TableRowAssert.isEqualTo(column: Column, value: T): TableRowValueAssert { + return value(column).isEqualTo(value) +} + +fun TableRowValueAssert.isEqualTo(column: Column, value: T): TableRowValueAssert { + return value(column).isEqualTo(value) +} \ No newline at end of file From 37c8335165d145591ec91162fc0b973d3d9dbc6d Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Tue, 10 Sep 2024 18:55:55 +0900 Subject: [PATCH 02/40] =?UTF-8?q?test:=20InstanceRepositoryImpl=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 --- hideout-core/build.gradle.kts | 1 + .../InstanceRepositoryImpl.kt | 4 +- .../InstanceRepositoryImplTest.kt | 163 ++++++++++++++++-- .../kotlin/utils/AbstractRepositoryTest.kt | 7 +- 4 files changed, 158 insertions(+), 17 deletions(-) diff --git a/hideout-core/build.gradle.kts b/hideout-core/build.gradle.kts index d88f2ac3..d184d19c 100644 --- a/hideout-core/build.gradle.kts +++ b/hideout-core/build.gradle.kts @@ -133,6 +133,7 @@ dependencies { testImplementation(libs.h2db) testImplementation(libs.mockito.kotlin) testImplementation("org.assertj:assertj-db:2.0.2") + testImplementation("com.ninja-squad:DbSetup-kotlin:2.1.0") } detekt { diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt index de57ff44..c7259dbb 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt @@ -52,7 +52,7 @@ class InstanceRepositoryImpl : InstanceRepository, } override suspend fun findById(id: InstanceId): InstanceEntity? = query { - return@query Instance.selectAll().where { Instance.id eq id.instanceId } + return@query Instance.selectAll().where { Instance.id eq id.instanceId }.limit(1) .singleOrNull()?.toInstance() } @@ -61,7 +61,7 @@ class InstanceRepositoryImpl : InstanceRepository, } override suspend fun findByUrl(url: URI): dev.usbharu.hideout.core.domain.model.instance.Instance? = query { - return@query Instance.selectAll().where { Instance.url eq url.toString() }.singleOrNull()?.toInstance() + return@query Instance.selectAll().where { Instance.url eq url.toString() }.limit(1).singleOrNull()?.toInstance() } companion object { diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt index 4755a2cb..29d1bdfe 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt @@ -1,5 +1,6 @@ package dev.usbharu.hideout.core.infrastructure.exposedrepository +import com.ninja_squad.dbsetup_kotlin.dbSetup import dev.usbharu.hideout.core.domain.model.instance.* import dev.usbharu.hideout.core.domain.model.instance.Instance import kotlinx.coroutines.test.runTest @@ -12,6 +13,9 @@ import utils.value import java.net.URI import java.sql.Timestamp import java.time.Instant +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull import dev.usbharu.hideout.core.infrastructure.exposedrepository.Instance as InstanceTable @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -19,7 +23,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { @Test - fun save() = runTest { + fun save_idが同じレコードがない場合はinsertされる() = runTest { InstanceRepositoryImpl().save( Instance( id = InstanceId(1), @@ -38,19 +42,152 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { ) val table = assertTable - assertThat(table) - .row(1) - .isEqualTo(InstanceTable.id, 1) - .isEqualTo(InstanceTable.name, "test") + assertThat(table).row(1).isEqualTo(InstanceTable.id, 1).isEqualTo(InstanceTable.name, "test") .isEqualTo(InstanceTable.url, "https://www.example.com") - .isEqualTo(InstanceTable.iconUrl, "https://www.example.com") - .isEqualTo(InstanceTable.sharedInbox, null) - .isEqualTo(InstanceTable.software, "") - .isEqualTo(InstanceTable.version, "") - .isEqualTo(InstanceTable.isBlocked, false) - .isEqualTo(InstanceTable.isMuted, false) - .isEqualTo(InstanceTable.moderationNote, "") - .value(InstanceTable.createdAt).isEqualTo(Timestamp.from(Instant.parse("2020-01-01T00:00:00Z"))) + .isEqualTo(InstanceTable.iconUrl, "https://www.example.com").isEqualTo(InstanceTable.sharedInbox, null) + .isEqualTo(InstanceTable.software, "").isEqualTo(InstanceTable.version, "") + .isEqualTo(InstanceTable.isBlocked, false).isEqualTo(InstanceTable.isMuted, false) + .isEqualTo(InstanceTable.moderationNote, "").value(InstanceTable.createdAt) + .isEqualTo(Timestamp.from(Instant.parse("2020-01-01T00:00:00Z"))) + } + + @Test + fun save_idが同じレコードがある場合はupdateされる() = runTest { + dbSetup(to = dataSource) { + insertInto(InstanceTable.tableName) { + columns( + "ID", + "name", + "DESCRIPTION", + "URL", + "ICON_URL", + "SHARED_INBOX", + "SOFTWARE", + "VERSION", + "IS_BLOCKED", + "IS_MUTED", + "MODERATION_NOTE", + "CREATED_AT" + ) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + }.launch() + + + InstanceRepositoryImpl().save( + Instance( + id = InstanceId(1), + name = InstanceName("test"), + description = InstanceDescription("id"), + url = URI.create("https://www.example.com"), + iconUrl = URI.create("https://www.example.com"), + sharedInbox = null, + software = InstanceSoftware(""), + version = InstanceVersion(""), + isBlocked = false, + isMuted = false, + moderationNote = InstanceModerationNote(""), + createdAt = Instant.parse("2020-01-01T00:00:00Z"), + ) + ) + + val table = assertTable + assertThat(table).row(1).isEqualTo(InstanceTable.id, 1).isEqualTo(InstanceTable.name, "test") + .isEqualTo(InstanceTable.url, "https://www.example.com") + .isEqualTo(InstanceTable.iconUrl, "https://www.example.com").isEqualTo(InstanceTable.sharedInbox, null) + .isEqualTo(InstanceTable.software, "").isEqualTo(InstanceTable.version, "") + .isEqualTo(InstanceTable.isBlocked, false).isEqualTo(InstanceTable.isMuted, false) + .isEqualTo(InstanceTable.moderationNote, "").value(InstanceTable.createdAt) + .isEqualTo(Timestamp.from(Instant.parse("2020-01-01T00:00:00Z"))) + } + + @Test + fun findById_指定したidで存在したら返す() = runTest { + dbSetup(to = dataSource) { + insertInto(InstanceTable.tableName) { + columns( + "ID", + "name", + "DESCRIPTION", + "URL", + "ICON_URL", + "SHARED_INBOX", + "SOFTWARE", + "VERSION", + "IS_BLOCKED", + "IS_MUTED", + "MODERATION_NOTE", + "CREATED_AT" + ) + values( + 1, + "test", + "description", + "https://www.example.com", + "https://www.example.com", + null, + "", + "", + false, + false, + "", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val actual = InstanceRepositoryImpl().findById(InstanceId(1)) + val expected = Instance( + id = InstanceId(1), + name = InstanceName("test"), + description = InstanceDescription("description"), + url = URI.create("https://www.example.com"), + iconUrl = URI.create("https://www.example.com"), + sharedInbox = null, + software = InstanceSoftware(""), + version = InstanceVersion(""), + isBlocked = false, + isMuted = false, + moderationNote = InstanceModerationNote(""), + createdAt = Instant.parse("2020-01-01T00:00:00Z"), + ) + + assertEquals(expected, actual) + } + + @Test + fun findById_指定したIDで存在しないとnull() = runTest { + assertNull(InstanceRepositoryImpl().findById(InstanceId(1))) + } + + companion object { + fun assertEquals(expected: Instance, actual: Instance?) { + assertNotNull(actual) + kotlin.test.assertEquals(expected, actual) + assertEquals(expected.name, actual.name) + assertEquals(expected.description, actual.description) + assertEquals(expected.url, actual.url) + assertEquals(expected.iconUrl, actual.iconUrl) + assertEquals(expected.sharedInbox, actual.sharedInbox) + assertEquals(expected.software, actual.software) + assertEquals(expected.version, actual.version) + assertEquals(expected.isBlocked, actual.isBlocked) + assertEquals(expected.moderationNote, actual.moderationNote) + assertEquals(expected.createdAt, actual.createdAt) + } } } diff --git a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt index e2ea2838..15530abd 100644 --- a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt @@ -33,6 +33,8 @@ abstract class AbstractRepositoryTest(private val exposedTable: org.jetbrains.ex @BeforeEach fun setUp() { + flyway.clean() + flyway.migrate() transaction = TransactionManager.currentOrNew(Connection.TRANSACTION_READ_UNCOMMITTED) } @@ -58,8 +60,9 @@ abstract class AbstractRepositoryTest(private val exposedTable: org.jetbrains.ex flyway = Flyway.configure().cleanDisabled(false).dataSource(dataSource).load() - val db = Database.connect(dataSource, databaseConfig = DatabaseConfig { - this.defaultMaxAttempts = 1 + Database.connect(dataSource, databaseConfig = DatabaseConfig { + defaultMaxAttempts = 1 + }) flyway.clean() flyway.migrate() From 29cbb5f93e6b7e15e20969973c2801127e8d593e Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:56:08 +0900 Subject: [PATCH 03/40] =?UTF-8?q?test:=20InstanceRepositoryImpl=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 --- .../InstanceRepositoryImplTest.kt | 123 ++++++++++++++++++ .../kotlin/utils/AbstractRepositoryTest.kt | 4 + 2 files changed, 127 insertions(+) diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt index 29d1bdfe..8955aca5 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt @@ -173,6 +173,129 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { assertNull(InstanceRepositoryImpl().findById(InstanceId(1))) } + @Test + fun findByUrl_指定したURLで存在したら返す() = runTest { + dbSetup(to = dataSource) { + insertInto(InstanceTable.tableName) { + columns( + "ID", + "name", + "DESCRIPTION", + "URL", + "ICON_URL", + "SHARED_INBOX", + "SOFTWARE", + "VERSION", + "IS_BLOCKED", + "IS_MUTED", + "MODERATION_NOTE", + "CREATED_AT" + ) + values( + 1, + "test", + "description", + "https://www.example.com", + "https://www.example.com", + null, + "", + "", + false, + false, + "", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val actual = InstanceRepositoryImpl().findByUrl(URI.create("https://www.example.com")) + val expected = Instance( + id = InstanceId(1), + name = InstanceName("test"), + description = InstanceDescription("description"), + url = URI.create("https://www.example.com"), + iconUrl = URI.create("https://www.example.com"), + sharedInbox = null, + software = InstanceSoftware(""), + version = InstanceVersion(""), + isBlocked = false, + isMuted = false, + moderationNote = InstanceModerationNote(""), + createdAt = Instant.parse("2020-01-01T00:00:00Z"), + ) + + assertEquals(expected, actual) + } + + @Test + fun findByUrl_指定したURLで存在しないとnull() = runTest { + assertNull(InstanceRepositoryImpl().findByUrl(URI.create("https://www.example.com"))) + } + + @Test + fun delete_削除() = runTest { + dbSetup(to = dataSource) { + insertInto(InstanceTable.tableName) { + columns( + "ID", + "name", + "DESCRIPTION", + "URL", + "ICON_URL", + "SHARED_INBOX", + "SOFTWARE", + "VERSION", + "IS_BLOCKED", + "IS_MUTED", + "MODERATION_NOTE", + "CREATED_AT" + ) + values( + 1, + "test", + "description", + "https://www.example.com", + "https://www.example.com", + null, + "", + "", + false, + false, + "", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val instance = Instance( + id = InstanceId(1), + name = InstanceName("test"), + description = InstanceDescription("description"), + url = URI.create("https://www.example.com"), + iconUrl = URI.create("https://www.example.com"), + sharedInbox = null, + software = InstanceSoftware(""), + version = InstanceVersion(""), + isBlocked = false, + isMuted = false, + moderationNote = InstanceModerationNote(""), + createdAt = Instant.parse("2020-01-01T00:00:00Z"), + ) + + change.setStartPointNow() + + InstanceRepositoryImpl().delete(instance) + + change.setEndPointNow() + + assertThat(change) + .hasNumberOfChanges(1) + .changeOfDeletionOnTable(InstanceTable.tableName) + .rowAtStartPoint() + .value(InstanceTable.id.name).isEqualTo(1) + + } + companion object { fun assertEquals(expected: Instance, actual: Instance?) { assertNotNull(actual) diff --git a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt index 15530abd..a473df03 100644 --- a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt @@ -4,6 +4,7 @@ import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import org.assertj.db.api.TableRowAssert import org.assertj.db.api.TableRowValueAssert +import org.assertj.db.type.Changes import org.assertj.db.type.Table import org.flywaydb.core.Flyway import org.jetbrains.exposed.sql.Column @@ -31,11 +32,14 @@ abstract class AbstractRepositoryTest(private val exposedTable: org.jetbrains.ex private lateinit var transaction: Transaction + protected lateinit var change: Changes + @BeforeEach fun setUp() { flyway.clean() flyway.migrate() transaction = TransactionManager.currentOrNew(Connection.TRANSACTION_READ_UNCOMMITTED) + change = Changes(assertTable) } @AfterEach From 9daf79904bcf488ae0604724b39b8cb02633a82c Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:01:03 +0900 Subject: [PATCH 04/40] =?UTF-8?q?test:=20ExposedActorInstanceRelationshipR?= =?UTF-8?q?epository=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...osedActorInstanceRelationshipRepository.kt | 1 + ...ActorInstanceRelationshipRepositoryTest.kt | 365 ++++++++++++++++++ .../kotlin/utils/AbstractRepositoryTest.kt | 33 +- 3 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepository.kt index 76d80efd..74c71f07 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepository.kt @@ -75,6 +75,7 @@ class ExposedActorInstanceRelationshipRepository(override val domainEventPublish ActorInstanceRelationships.actorId eq actorId.id and (ActorInstanceRelationships.instanceId eq instanceId.instanceId) } + .limit(1) .singleOrNull() ?.toActorInstanceRelationship() } diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt new file mode 100644 index 00000000..dc9183ab --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt @@ -0,0 +1,365 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup.Operations +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.actorinstancerelationship.ActorInstanceRelationship +import dev.usbharu.hideout.core.domain.model.instance.InstanceId +import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import utils.AbstractRepositoryTest +import utils.columns +import utils.disableReferenceIntegrityConstraints +import utils.isEqualTo +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@ExtendWith(MockitoExtension::class) +class ExposedActorInstanceRelationshipRepositoryTest : AbstractRepositoryTest(ActorInstanceRelationships) { + + @InjectMocks + lateinit var repository: ExposedActorInstanceRelationshipRepository + + @Mock + lateinit var domainEventPublisher: DomainEventPublisher + + @Test + fun save_idが同じレコードがない場合はinsert() = runTest { + dbSetup(to = dataSource) { + execute(Operations.sql("SET REFERENTIAL_INTEGRITY FALSE")) + insertInto(Instance.tableName) { + columns( + "ID", + "name", + "DESCRIPTION", + "URL", + "ICON_URL", + "SHARED_INBOX", + "SOFTWARE", + "VERSION", + "IS_BLOCKED", + "IS_MUTED", + "MODERATION_NOTE", + "CREATED_AT" + ) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + insertInto("public.actors") { + columns( + "id", + "name", + "domain", + "screen_name", + "description", + "inbox", + "outbox", + "url", + "public_key", + "private_key", + "created_at", + "key_id", + "following", + "followers", + "instance", + "locked", + "following_count", + "followers_count", + "posts_count", + "last_post_at", + "last_update_at", + "suspend", + "move_to", + "emojis", + "deleted", + "icon", + "banner" + ) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + }.launch() + + + val actorInstanceRelationship = ActorInstanceRelationship( + actorId = ActorId(1), instanceId = InstanceId(1), blocking = false, muting = false, doNotSendPrivate = false + ) + + repository.save(actorInstanceRelationship) + + dbSetup(to = dataSource) { + execute(Operations.sql("SET REFERENTIAL_INTEGRITY TRUE")) + } + + assertThat(assertTable).row(0).isEqualTo(ActorInstanceRelationships.actorId, 1) + .isEqualTo(ActorInstanceRelationships.actorId, 1).isEqualTo(ActorInstanceRelationships.blocking, false) + .isEqualTo(ActorInstanceRelationships.muting, false) + .isEqualTo(ActorInstanceRelationships.doNotSendPrivate, false) + } + + @Test + fun save_idが同じレコードがある場合はupdate() = runTest { + dbSetup(to = dataSource) { + execute(Operations.sql("SET REFERENTIAL_INTEGRITY FALSE")) + insertInto(Instance.tableName) { + columns( + "ID", + "name", + "DESCRIPTION", + "URL", + "ICON_URL", + "SHARED_INBOX", + "SOFTWARE", + "VERSION", + "IS_BLOCKED", + "IS_MUTED", + "MODERATION_NOTE", + "CREATED_AT" + ) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + insertInto("public.actors") { + columns( + "id", + "name", + "domain", + "screen_name", + "description", + "inbox", + "outbox", + "url", + "public_key", + "private_key", + "created_at", + "key_id", + "following", + "followers", + "instance", + "locked", + "following_count", + "followers_count", + "posts_count", + "last_post_at", + "last_update_at", + "suspend", + "move_to", + "emojis", + "deleted", + "icon", + "banner" + ) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto(ActorInstanceRelationships.tableName) { + columns(ActorInstanceRelationships.columns) + values(1, 1, true, true, true) + } + }.launch() + + + val actorInstanceRelationship = ActorInstanceRelationship( + actorId = ActorId(1), instanceId = InstanceId(1), blocking = false, muting = false, doNotSendPrivate = false + ) + + repository.save(actorInstanceRelationship) + + dbSetup(to = dataSource) { + execute(Operations.sql("SET REFERENTIAL_INTEGRITY TRUE")) + } + + assertThat(assertTable).row(0).isEqualTo(ActorInstanceRelationships.actorId, 1) + .isEqualTo(ActorInstanceRelationships.actorId, 1).isEqualTo(ActorInstanceRelationships.blocking, false) + .isEqualTo(ActorInstanceRelationships.muting, false) + .isEqualTo(ActorInstanceRelationships.doNotSendPrivate, false) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(Operations.sql("SET REFERENTIAL_INTEGRITY FALSE")) + insertInto(ActorInstanceRelationships.tableName) { + columns(ActorInstanceRelationships.columns) + values(1, 1, true, true, true) + } + }.launch() + + val actorInstanceRelationship = ActorInstanceRelationship( + actorId = ActorId(1), instanceId = InstanceId(1), blocking = false, muting = false, doNotSendPrivate = false + ) + + change.setStartPointNow() + + repository.delete(actorInstanceRelationship) + + change.setEndPointNow() + + assertThat(change) + .changeOfDeletionOnTable(ActorInstanceRelationships.tableName) + .rowAtStartPoint() + .value(ActorInstanceRelationships.instanceId.name).isEqualTo(1) + .value(ActorInstanceRelationships.actorId.name).isEqualTo(1) + } + + @Test + fun findByActorIdAndInstanceId_指定したActorIdとInstanceIdで存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(ActorInstanceRelationships.tableName) { + columns(ActorInstanceRelationships.columns) + values(1, 1, true, true, true) + } + }.launch() + + val expected = ActorInstanceRelationship( + actorId = ActorId(1), instanceId = InstanceId(1), blocking = true, muting = true, doNotSendPrivate = true + ) + + val actual = repository.findByActorIdAndInstanceId(ActorId(1), InstanceId(1)) + + assertNotNull(actual) + assertEquals(expected, actual) + assertEquals(expected.actorId, actual.actorId) + assertEquals(expected.instanceId, actual.instanceId) + assertEquals(expected.blocking, actual.blocking) + assertEquals(expected.muting, actual.muting) + assertEquals(expected.doNotSendPrivate, actual.doNotSendPrivate) + } + + @Test + fun findByActorIdAndInstanceId_指定したActorIdとInstanceIdで存在しないとnull() = runTest { + assertNull(repository.findByActorIdAndInstanceId(ActorId(1), InstanceId(1))) + } + + @Test + fun save_ドメインイベントがパブリッシュされる() = runTest { + + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(ActorInstanceRelationships.tableName) { + columns(ActorInstanceRelationships.columns) + values(1, 1, true, true, true) + } + }.launch() + + val actorInstanceRelationship = ActorInstanceRelationship( + actorId = ActorId(1), instanceId = InstanceId(1), blocking = false, muting = false, doNotSendPrivate = false + ) + actorInstanceRelationship.block() + repository.save(actorInstanceRelationship) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } + + @Test + fun delete_ドメインイベントがパブリッシュされる() = runTest { + + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + }.launch() + + val actorInstanceRelationship = ActorInstanceRelationship( + actorId = ActorId(1), instanceId = InstanceId(1), blocking = false, muting = false, doNotSendPrivate = false + ) + actorInstanceRelationship.block() + repository.delete(actorInstanceRelationship) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt index a473df03..1e7b62c3 100644 --- a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt @@ -1,5 +1,8 @@ package utils +import com.ninja_squad.dbsetup.Operations +import com.ninja_squad.dbsetup.operation.Insert +import com.ninja_squad.dbsetup_kotlin.dbSetup import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import org.assertj.db.api.TableRowAssert @@ -44,6 +47,9 @@ abstract class AbstractRepositoryTest(private val exposedTable: org.jetbrains.ex @AfterEach fun tearDown() { + dbSetup(to = dataSource) { + execute(Operations.sql("SET REFERENTIAL_INTEGRITY TRUE")) + } transaction.rollback() } @@ -89,4 +95,29 @@ fun TableRowAssert.isEqualTo(column: Column, value: T): TableRowValueAsse fun TableRowValueAssert.isEqualTo(column: Column, value: T): TableRowValueAssert { return value(column).isEqualTo(value) -} \ No newline at end of file +} + +fun Insert.Builder.columns(columns: List>): Insert.Builder { + columns(*columns.map { it.name }.toTypedArray()) + return this +} + +fun Insert.Builder.columns(vararg columns: Column<*>): Insert.Builder { + columns(*columns.map { it.name }.toTypedArray()) + return this +} + +fun Changes.with(block: () -> Unit) { + setStartPointNow() + block() + setEndPointNow() +} + +suspend fun Changes.withSuspend(block: suspend () -> Unit) { + setStartPointNow() + block() + setEndPointNow() +} + +val disableReferenceIntegrityConstraints = Operations.sql("SET REFERENTIAL_INTEGRITY FALSE") +val enableReferenceIntegrityConstraints = Operations.sql("SET REFERENTIAL_INTEGRITY TRUE") \ No newline at end of file From ad112406b86402d5e8ff0dc170f19da23c3dfd80 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 10 Sep 2024 12:11:46 +0000 Subject: [PATCH 05/40] style: fix lint (CI) --- .../timeline/MastodonReadTimeline.kt | 4 +- .../MastodonReadTimelineApplicationService.kt | 135 +++++++++--------- .../interfaces/api/SpringTimelineApi.kt | 3 +- 3 files changed, 72 insertions(+), 70 deletions(-) diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimeline.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimeline.kt index 4d76bda5..737cfabf 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimeline.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimeline.kt @@ -8,6 +8,4 @@ class MastodonReadTimeline( val localOnly: Boolean, val remoteOnly: Boolean, val page: Page -) { - -} +) diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimelineApplicationService.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimelineApplicationService.kt index be0319c8..770cb239 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimelineApplicationService.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimelineApplicationService.kt @@ -38,75 +38,78 @@ class MastodonReadTimelineApplicationService( val readTimeline = timelineStore.readTimeline(timeline, readTimelineOption, command.page, principal) - return PaginationList(readTimeline.map { - Status( - it.postId.id.toString(), - it.post.url.toString(), - it.post.createdAt.toString(), - account = Account( - id = it.postActor.id.id.toString(), - username = it.postActor.name.name, - acct = Acct(it.postActor.name.name, it.postActor.domain.domain).toString(), - url = it.postActor.url.toString(), - displayName = it.postActor.screenName.screenName, - note = it.postActor.description.description, - avatar = it.postActorIconMedia?.url.toString(), - avatarStatic = it.postActorIconMedia?.thumbnailUrl.toString(), - header = "", - headerStatic = "", - locked = false, - fields = emptyList(), + return PaginationList( + readTimeline.map { + Status( + it.postId.id.toString(), + it.post.url.toString(), + it.post.createdAt.toString(), + account = Account( + id = it.postActor.id.id.toString(), + username = it.postActor.name.name, + acct = Acct(it.postActor.name.name, it.postActor.domain.domain).toString(), + url = it.postActor.url.toString(), + displayName = it.postActor.screenName.screenName, + note = it.postActor.description.description, + avatar = it.postActorIconMedia?.url.toString(), + avatarStatic = it.postActorIconMedia?.thumbnailUrl.toString(), + header = "", + headerStatic = "", + locked = false, + fields = emptyList(), + emojis = emptyList(), + bot = false, + group = false, + discoverable = true, + createdAt = it.postActor.createdAt.toString(), + statusesCount = it.postActor.postsCount.postsCount, + noindex = true, + moved = it.postActor.moveTo != null, + suspended = it.postActor.suspend, + limited = false, + lastStatusAt = it.postActor.lastPostAt?.toString(), + followersCount = it.postActor.followersCount?.relationshipCount, + followingCount = it.postActor.followingCount?.relationshipCount, + ), + content = it.post.content.content, + visibility = when (it.post.visibility) { + PUBLIC -> Status.Visibility.public + UNLISTED -> Status.Visibility.unlisted + FOLLOWERS -> Status.Visibility.private + DIRECT -> Status.Visibility.direct + }, + sensitive = it.post.sensitive, + spoilerText = it.post.overview?.overview.orEmpty(), + mediaAttachments = it.postMedias.map { MediaAttachment(it.id.id.toString()) }, + mentions = emptyList(), + tags = emptyList(), emojis = emptyList(), - bot = false, - group = false, - discoverable = true, - createdAt = it.postActor.createdAt.toString(), - statusesCount = it.postActor.postsCount.postsCount, - noindex = true, - moved = it.postActor.moveTo != null, - suspended = it.postActor.suspend, - limited = false, - lastStatusAt = it.postActor.lastPostAt?.toString(), - followersCount = it.postActor.followersCount?.relationshipCount, - followingCount = it.postActor.followingCount?.relationshipCount, - ), - content = it.post.content.content, - visibility = when (it.post.visibility) { - PUBLIC -> Status.Visibility.public - UNLISTED -> Status.Visibility.unlisted - FOLLOWERS -> Status.Visibility.private - DIRECT -> Status.Visibility.direct - }, - sensitive = it.post.sensitive, - spoilerText = it.post.overview?.overview.orEmpty(), - mediaAttachments = it.postMedias.map { MediaAttachment(it.id.id.toString()) }, - mentions = emptyList(), - tags = emptyList(), - emojis = emptyList(), - reblogsCount = 0, - favouritesCount = it.reactionsList.sumOf { it.count }, - repliesCount = 0, - url = it.post.url.toString(), - text = it.post.content.text, - application = null, - inReplyToId = it.replyPost?.id?.toString(), - inReplyToAccountId = it.replyPostActor?.id?.toString(), - reblog = null, - poll = null, - card = null, - language = null, - editedAt = null, - favourited = it.favourited, - reblogged = false, - muted = false, - bookmarked = false, - pinned = false, - filtered = emptyList(), - ) - }, readTimeline.next?.id, readTimeline.prev?.id) + reblogsCount = 0, + favouritesCount = it.reactionsList.sumOf { it.count }, + repliesCount = 0, + url = it.post.url.toString(), + text = it.post.content.text, + application = null, + inReplyToId = it.replyPost?.id?.toString(), + inReplyToAccountId = it.replyPostActor?.id?.toString(), + reblog = null, + poll = null, + card = null, + language = null, + editedAt = null, + favourited = it.favourited, + reblogged = false, + muted = false, + bookmarked = false, + pinned = false, + filtered = emptyList(), + ) + }, + readTimeline.next?.id, readTimeline.prev?.id + ) } companion object { private val logger = LoggerFactory.getLogger(MastodonReadTimelineApplicationService::class.java) } -} \ No newline at end of file +} diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringTimelineApi.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringTimelineApi.kt index 9f259736..511b3605 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringTimelineApi.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringTimelineApi.kt @@ -67,7 +67,8 @@ class SpringTimelineApi( minId?.toLongOrNull(), limit ) - ), principal + ), + principal ).asFlow() ) } From d2c608333d3fade4afc38c899e628f4f84d253c4 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 10 Sep 2024 12:14:38 +0000 Subject: [PATCH 06/40] style: fix lint (CI) --- .../timeline/MastodonReadTimelineApplicationService.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimelineApplicationService.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimelineApplicationService.kt index 770cb239..2390c841 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimelineApplicationService.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/timeline/MastodonReadTimelineApplicationService.kt @@ -105,7 +105,8 @@ class MastodonReadTimelineApplicationService( filtered = emptyList(), ) }, - readTimeline.next?.id, readTimeline.prev?.id + readTimeline.next?.id, + readTimeline.prev?.id ) } From fa66ccaa0c8522f3980e71f6112e14c952e9e251 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:34:45 +0900 Subject: [PATCH 07/40] =?UTF-8?q?test:=20=E5=8B=95=E3=81=8B=E3=81=AA?= =?UTF-8?q?=E3=81=84=E3=83=86=E3=82=B9=E3=83=88=E3=81=8C=E3=81=82=E3=81=A3?= =?UTF-8?q?=E3=81=9F=E3=81=AE=E3=81=A7=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ExposedActorInstanceRelationshipRepositoryTest.kt | 10 ++++------ .../src/test/kotlin/utils/AbstractRepositoryTest.kt | 3 ++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt index dc9183ab..2e863a1f 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt @@ -10,7 +10,6 @@ import kotlinx.coroutines.test.runTest import org.assertj.db.api.Assertions.assertThat import org.jetbrains.exposed.sql.transactions.TransactionManager import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.extension.ExtendWith import org.mockito.InjectMocks import org.mockito.Mock @@ -26,7 +25,6 @@ import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull -@TestInstance(TestInstance.Lifecycle.PER_CLASS) @ExtendWith(MockitoExtension::class) class ExposedActorInstanceRelationshipRepositoryTest : AbstractRepositoryTest(ActorInstanceRelationships) { @@ -328,10 +326,6 @@ class ExposedActorInstanceRelationshipRepositoryTest : AbstractRepositoryTest(Ac dbSetup(to = dataSource) { execute(disableReferenceIntegrityConstraints) - insertInto(ActorInstanceRelationships.tableName) { - columns(ActorInstanceRelationships.columns) - values(1, 1, true, true, true) - } }.launch() val actorInstanceRelationship = ActorInstanceRelationship( @@ -350,6 +344,10 @@ class ExposedActorInstanceRelationshipRepositoryTest : AbstractRepositoryTest(Ac dbSetup(to = dataSource) { execute(disableReferenceIntegrityConstraints) + insertInto(ActorInstanceRelationships.tableName) { + columns(ActorInstanceRelationships.columns) + values(1, 1, true, true, true) + } }.launch() val actorInstanceRelationship = ActorInstanceRelationship( diff --git a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt index 1e7b62c3..ce7a19f3 100644 --- a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt @@ -41,7 +41,7 @@ abstract class AbstractRepositoryTest(private val exposedTable: org.jetbrains.ex fun setUp() { flyway.clean() flyway.migrate() - transaction = TransactionManager.currentOrNew(Connection.TRANSACTION_READ_UNCOMMITTED) + transaction = TransactionManager.manager.newTransaction(Connection.TRANSACTION_READ_UNCOMMITTED) change = Changes(assertTable) } @@ -51,6 +51,7 @@ abstract class AbstractRepositoryTest(private val exposedTable: org.jetbrains.ex execute(Operations.sql("SET REFERENTIAL_INTEGRITY TRUE")) } transaction.rollback() + transaction.close() } companion object { From 1983841cefd4cd9a6c64216f734cb1089a968e55 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Tue, 10 Sep 2024 23:45:22 +0900 Subject: [PATCH 08/40] =?UTF-8?q?test:=20=E3=83=86=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=81=AE=E5=89=8D=E6=8F=90=E6=9D=A1=E4=BB=B6SQL=E3=82=92?= =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E3=81=8B=E3=82=89=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E3=81=AB=E7=94=9F=E6=88=90=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ActorInstanceRelationshipRepositoryTest.kt | 82 +------------------ .../InstanceRepositoryImplTest.kt | 53 ++---------- 2 files changed, 9 insertions(+), 126 deletions(-) diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt index 2e863a1f..6ed40eb6 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorInstanceRelationshipRepositoryTest.kt @@ -40,18 +40,7 @@ class ExposedActorInstanceRelationshipRepositoryTest : AbstractRepositoryTest(Ac execute(Operations.sql("SET REFERENTIAL_INTEGRITY FALSE")) insertInto(Instance.tableName) { columns( - "ID", - "name", - "DESCRIPTION", - "URL", - "ICON_URL", - "SHARED_INBOX", - "SOFTWARE", - "VERSION", - "IS_BLOCKED", - "IS_MUTED", - "MODERATION_NOTE", - "CREATED_AT" + Instance.columns ) values( 1, @@ -70,33 +59,7 @@ class ExposedActorInstanceRelationshipRepositoryTest : AbstractRepositoryTest(Ac } insertInto("public.actors") { columns( - "id", - "name", - "domain", - "screen_name", - "description", - "inbox", - "outbox", - "url", - "public_key", - "private_key", - "created_at", - "key_id", - "following", - "followers", - "instance", - "locked", - "following_count", - "followers_count", - "posts_count", - "last_post_at", - "last_update_at", - "suspend", - "move_to", - "emojis", - "deleted", - "icon", - "banner" + Actors.columns ) values( 1, @@ -153,18 +116,7 @@ class ExposedActorInstanceRelationshipRepositoryTest : AbstractRepositoryTest(Ac execute(Operations.sql("SET REFERENTIAL_INTEGRITY FALSE")) insertInto(Instance.tableName) { columns( - "ID", - "name", - "DESCRIPTION", - "URL", - "ICON_URL", - "SHARED_INBOX", - "SOFTWARE", - "VERSION", - "IS_BLOCKED", - "IS_MUTED", - "MODERATION_NOTE", - "CREATED_AT" + Instance.columns ) values( 1, @@ -183,33 +135,7 @@ class ExposedActorInstanceRelationshipRepositoryTest : AbstractRepositoryTest(Ac } insertInto("public.actors") { columns( - "id", - "name", - "domain", - "screen_name", - "description", - "inbox", - "outbox", - "url", - "public_key", - "private_key", - "created_at", - "key_id", - "following", - "followers", - "instance", - "locked", - "following_count", - "followers_count", - "posts_count", - "last_post_at", - "last_update_at", - "suspend", - "move_to", - "emojis", - "deleted", - "icon", - "banner" + Actors.columns ) values( 1, diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt index 8955aca5..ec30240f 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt @@ -8,6 +8,7 @@ import org.assertj.db.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import utils.AbstractRepositoryTest +import utils.columns import utils.isEqualTo import utils.value import java.net.URI @@ -56,18 +57,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { dbSetup(to = dataSource) { insertInto(InstanceTable.tableName) { columns( - "ID", - "name", - "DESCRIPTION", - "URL", - "ICON_URL", - "SHARED_INBOX", - "SOFTWARE", - "VERSION", - "IS_BLOCKED", - "IS_MUTED", - "MODERATION_NOTE", - "CREATED_AT" + InstanceTable.columns ) values( 1, @@ -119,18 +109,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { dbSetup(to = dataSource) { insertInto(InstanceTable.tableName) { columns( - "ID", - "name", - "DESCRIPTION", - "URL", - "ICON_URL", - "SHARED_INBOX", - "SOFTWARE", - "VERSION", - "IS_BLOCKED", - "IS_MUTED", - "MODERATION_NOTE", - "CREATED_AT" + InstanceTable.columns ) values( 1, @@ -178,18 +157,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { dbSetup(to = dataSource) { insertInto(InstanceTable.tableName) { columns( - "ID", - "name", - "DESCRIPTION", - "URL", - "ICON_URL", - "SHARED_INBOX", - "SOFTWARE", - "VERSION", - "IS_BLOCKED", - "IS_MUTED", - "MODERATION_NOTE", - "CREATED_AT" + InstanceTable.columns ) values( 1, @@ -237,18 +205,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { dbSetup(to = dataSource) { insertInto(InstanceTable.tableName) { columns( - "ID", - "name", - "DESCRIPTION", - "URL", - "ICON_URL", - "SHARED_INBOX", - "SOFTWARE", - "VERSION", - "IS_BLOCKED", - "IS_MUTED", - "MODERATION_NOTE", - "CREATED_AT" + InstanceTable.columns ) values( 1, From 5c554bfa16adc35505fd8092e051ad08c9a79401 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 00:02:28 +0900 Subject: [PATCH 09/40] =?UTF-8?q?test:=20UserDetailRepositoryImpl=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 --- .../UserDetailRepositoryImpl.kt | 30 +- .../UserDetailRepositoryImplTest.kt | 429 ++++++++++++++++++ 2 files changed, 443 insertions(+), 16 deletions(-) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImpl.kt index 8251ec08..2f4a22df 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImpl.kt @@ -39,24 +39,20 @@ class UserDetailRepositoryImpl(override val domainEventPublisher: DomainEventPub override val logger: Logger get() = Companion.logger - override suspend fun save(userDetail: UserDetail): UserDetail { - val userDetail1 = query { - UserDetails.upsert { - it[id] = userDetail.id.id - it[actorId] = userDetail.actorId.id - it[password] = userDetail.password.password - it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest - it[lastMigration] = userDetail.lastMigration - it[homeTimelineId] = userDetail.homeTimelineId?.value - } - - onComplete { - update(userDetail) - } - userDetail + override suspend fun save(userDetail: UserDetail): UserDetail = query { + UserDetails.upsert { + it[id] = userDetail.id.id + it[actorId] = userDetail.actorId.id + it[password] = userDetail.password.password + it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest + it[lastMigration] = userDetail.lastMigration + it[homeTimelineId] = userDetail.homeTimelineId?.value } - return userDetail1 + onComplete { + update(userDetail) + } + userDetail } override suspend fun delete(userDetail: UserDetail) { @@ -71,6 +67,7 @@ class UserDetailRepositoryImpl(override val domainEventPublisher: DomainEventPub override suspend fun findByActorId(actorId: Long): UserDetail? = query { return@query UserDetails .selectAll().where { UserDetails.actorId eq actorId } + .limit(1) .singleOrNull() ?.let { userDetail(it) @@ -80,6 +77,7 @@ class UserDetailRepositoryImpl(override val domainEventPublisher: DomainEventPub override suspend fun findById(id: UserDetailId): UserDetail? = query { UserDetails .selectAll().where { UserDetails.id eq id.id } + .limit(1) .singleOrNull() ?.let { userDetail(it) diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt new file mode 100644 index 00000000..37a11378 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt @@ -0,0 +1,429 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.timeline.TimelineId +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailHashedPassword +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId +import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.assertj.db.api.Assertions.assertThat +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import utils.* +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@ExtendWith(MockitoExtension::class) +class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { + + @InjectMocks + lateinit var userDetailRepository: UserDetailRepositoryImpl + + @Mock + lateinit var domainEventPublisher: DomainEventPublisher + + @Test + fun save_idが同じレコードがない場合insert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns( + "id", + "name", + "domain", + "screen_name", + "description", + "inbox", + "outbox", + "url", + "public_key", + "private_key", + "created_at", + "key_id", + "following", + "followers", + "instance", + "locked", + "following_count", + "followers_count", + "posts_count", + "last_post_at", + "last_update_at", + "suspend", + "move_to", + "emojis", + "deleted", + "icon", + "banner" + ) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + userDetailRepository.save( + UserDetail.create( + UserDetailId(1), + ActorId(1), + UserDetailHashedPassword("VeeeeeeeeeeeeeryStrongPassword"), + false, + null, + null + ) + ) + + assertThat(assertTable) + .row(0) + .isEqualTo(UserDetails.id, 1) + .isEqualTo(UserDetails.actorId, 1) + .isEqualTo(UserDetails.password, "VeeeeeeeeeeeeeryStrongPassword") + .isEqualTo(UserDetails.lastMigration, null) + .isEqualTo(UserDetails.autoAcceptFolloweeFollowRequest, false) + .isEqualTo(UserDetails.homeTimelineId, null) + } + + @Test + fun save_idが同じレコードがある場合update() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns( + Actors.columns + ) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto("public.user_details") { + columns( + UserDetails.columns + ) + values( + 1, + 1, + "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", + false, + null, + 1832779979297918976 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + userDetailRepository.save( + UserDetail.create( + UserDetailId(1), + ActorId(1), + UserDetailHashedPassword("VeeeeeeeeeeeeeryStrongPassword"), + false, + null, + null + ) + ) + + assertThat(assertTable) + .row(0) + .isEqualTo(UserDetails.id, 1) + .isEqualTo(UserDetails.actorId, 1) + .isEqualTo(UserDetails.password, "VeeeeeeeeeeeeeryStrongPassword") + .isEqualTo(UserDetails.lastMigration, null) + .isEqualTo(UserDetails.autoAcceptFolloweeFollowRequest, false) + .isEqualTo(UserDetails.homeTimelineId, null) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.user_details") { + columns( + UserDetails.columns + ) + values( + 1, + 1, + "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", + false, + null, + 1832779979297918976 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val userDetail = UserDetail( + UserDetailId(1), + ActorId(1), + UserDetailHashedPassword("VeeeeeeeeeeeeeryStrongPassword"), + false, + null, + null + ) + + change.withSuspend { + userDetailRepository.delete(userDetail) + } + + assertThat(change) + .changeOfDeletionOnTable(UserDetails.tableName) + .rowAtStartPoint() + .value(UserDetails.id.name).isEqualTo(1) + } + + @Test + fun findByActorId_指定したActorIdで存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.user_details") { + columns( + UserDetails.columns + ) + values( + 1, + 1, + "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", + false, + null, + 1832779979297918976 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expect = UserDetail( + id = UserDetailId(1), + actorId = ActorId(1), + password = UserDetailHashedPassword("$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm"), + autoAcceptFolloweeFollowRequest = false, + lastMigration = null, + homeTimelineId = TimelineId(1832779979297918976) + ) + + val actual = userDetailRepository.findByActorId(1) + + assertEquals(actual, expect) + } + + @Test + fun findByActorId_指定したActorIdで存在しないとnull() = runTest { + assertNull(userDetailRepository.findByActorId(1)) + } + + @Test + fun findById_指定したIdで存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.user_details") { + columns( + UserDetails.columns + ) + values( + 1, + 1, + "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", + false, + null, + 1832779979297918976 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expect = UserDetail( + id = UserDetailId(1), + actorId = ActorId(1), + password = UserDetailHashedPassword("$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm"), + autoAcceptFolloweeFollowRequest = false, + lastMigration = null, + homeTimelineId = TimelineId(1832779979297918976) + ) + + val actual = userDetailRepository.findById(UserDetailId(1)) + + assertEquals(actual, expect) + } + + @Test + fun findById_指定したIdで存在しないとnull() = runTest { + assertNull(userDetailRepository.findById(UserDetailId(1))) + } + + @Test + fun findAllById_指定されたidすべて返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.user_details") { + columns( + UserDetails.columns + ) + values( + 1, + 1, + "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", + false, + null, + null + ) + values( + 2, + 2, + "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", + false, + null, + 1832779979297918976 + ) + values( + 3, + 3, + "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", + false, + null, + 1832779979297918976 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val userDetailList = userDetailRepository.findAllById(listOf(UserDetailId(1), UserDetailId(3))) + + assertThat(userDetailList) + .hasSize(2) + } + + @Test + fun save_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + }.launch() + + userDetailRepository.save( + UserDetail.create( + UserDetailId(1), + ActorId(1), + UserDetailHashedPassword("VeeeeeeeeeeeeeryStrongPassword"), + false, + null, + null + ) + ) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } + + @Test + fun delete_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.user_details") { + columns( + UserDetails.columns + ) + values( + 1, + 1, + "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", + false, + null, + 1832779979297918976 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + userDetailRepository.delete( + UserDetail.create( + UserDetailId(1), + ActorId(1), + UserDetailHashedPassword("VeeeeeeeeeeeeeryStrongPassword"), + false, + null, + null + ) + ) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } + + private fun assertEquals( + actual: UserDetail?, + expect: UserDetail + ) { + assertNotNull(actual) + kotlin.test.assertEquals(expect, actual) + assertEquals(expect.id, actual.id) + assertEquals(expect.actorId, actual.actorId) + assertEquals(expect.password, actual.password) + assertEquals(expect.autoAcceptFolloweeFollowRequest, actual.autoAcceptFolloweeFollowRequest) + assertEquals(expect.lastMigration, actual.lastMigration) + assertEquals(expect.homeTimelineId, actual.homeTimelineId) + } +} From bf2dbf159a01125ecfc800f2c4a8624d55a7e12e Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 05:57:17 +0900 Subject: [PATCH 10/40] style: style --- .../UserDetailRepositoryImplTest.kt | 96 ++++--------------- 1 file changed, 17 insertions(+), 79 deletions(-) diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt index 37a11378..35bf81a5 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt @@ -38,35 +38,7 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { dbSetup(to = dataSource) { execute(disableReferenceIntegrityConstraints) insertInto("public.actors") { - columns( - "id", - "name", - "domain", - "screen_name", - "description", - "inbox", - "outbox", - "url", - "public_key", - "private_key", - "created_at", - "key_id", - "following", - "followers", - "instance", - "locked", - "following_count", - "followers_count", - "posts_count", - "last_post_at", - "last_update_at", - "suspend", - "move_to", - "emojis", - "deleted", - "icon", - "banner" - ) + columns(Actors.columns) values( 1, "b", @@ -111,13 +83,9 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { ) ) - assertThat(assertTable) - .row(0) - .isEqualTo(UserDetails.id, 1) - .isEqualTo(UserDetails.actorId, 1) + assertThat(assertTable).row(0).isEqualTo(UserDetails.id, 1).isEqualTo(UserDetails.actorId, 1) .isEqualTo(UserDetails.password, "VeeeeeeeeeeeeeryStrongPassword") - .isEqualTo(UserDetails.lastMigration, null) - .isEqualTo(UserDetails.autoAcceptFolloweeFollowRequest, false) + .isEqualTo(UserDetails.lastMigration, null).isEqualTo(UserDetails.autoAcceptFolloweeFollowRequest, false) .isEqualTo(UserDetails.homeTimelineId, null) } @@ -126,9 +94,7 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { dbSetup(to = dataSource) { execute(disableReferenceIntegrityConstraints) insertInto("public.actors") { - columns( - Actors.columns - ) + columns(Actors.columns) values( 1, "b", @@ -160,9 +126,7 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { ) } insertInto("public.user_details") { - columns( - UserDetails.columns - ) + columns(UserDetails.columns) values( 1, 1, @@ -186,13 +150,9 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { ) ) - assertThat(assertTable) - .row(0) - .isEqualTo(UserDetails.id, 1) - .isEqualTo(UserDetails.actorId, 1) + assertThat(assertTable).row(0).isEqualTo(UserDetails.id, 1).isEqualTo(UserDetails.actorId, 1) .isEqualTo(UserDetails.password, "VeeeeeeeeeeeeeryStrongPassword") - .isEqualTo(UserDetails.lastMigration, null) - .isEqualTo(UserDetails.autoAcceptFolloweeFollowRequest, false) + .isEqualTo(UserDetails.lastMigration, null).isEqualTo(UserDetails.autoAcceptFolloweeFollowRequest, false) .isEqualTo(UserDetails.homeTimelineId, null) } @@ -201,9 +161,7 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { dbSetup(to = dataSource) { execute(disableReferenceIntegrityConstraints) insertInto("public.user_details") { - columns( - UserDetails.columns - ) + columns(UserDetails.columns) values( 1, 1, @@ -217,22 +175,15 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { }.launch() val userDetail = UserDetail( - UserDetailId(1), - ActorId(1), - UserDetailHashedPassword("VeeeeeeeeeeeeeryStrongPassword"), - false, - null, - null + UserDetailId(1), ActorId(1), UserDetailHashedPassword("VeeeeeeeeeeeeeryStrongPassword"), false, null, null ) change.withSuspend { userDetailRepository.delete(userDetail) } - assertThat(change) - .changeOfDeletionOnTable(UserDetails.tableName) - .rowAtStartPoint() - .value(UserDetails.id.name).isEqualTo(1) + assertThat(change).changeOfDeletionOnTable(UserDetails.tableName).rowAtStartPoint().value(UserDetails.id.name) + .isEqualTo(1) } @Test @@ -240,9 +191,7 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { dbSetup(to = dataSource) { execute(disableReferenceIntegrityConstraints) insertInto("public.user_details") { - columns( - UserDetails.columns - ) + columns(UserDetails.columns) values( 1, 1, @@ -279,9 +228,7 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { dbSetup(to = dataSource) { execute(disableReferenceIntegrityConstraints) insertInto("public.user_details") { - columns( - UserDetails.columns - ) + columns(UserDetails.columns) values( 1, 1, @@ -318,16 +265,9 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { dbSetup(to = dataSource) { execute(disableReferenceIntegrityConstraints) insertInto("public.user_details") { - columns( - UserDetails.columns - ) + columns(UserDetails.columns) values( - 1, - 1, - "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", - false, - null, - null + 1, 1, "$2a$10\$EBj3lstVOv0wz3CxLpzYJu8FFrUJ2MPJW9Vlklyg.bfGEOn5sqIwm", false, null, null ) values( 2, @@ -351,8 +291,7 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { val userDetailList = userDetailRepository.findAllById(listOf(UserDetailId(1), UserDetailId(3))) - assertThat(userDetailList) - .hasSize(2) + assertThat(userDetailList).hasSize(2) } @Test @@ -414,8 +353,7 @@ class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { } private fun assertEquals( - actual: UserDetail?, - expect: UserDetail + actual: UserDetail?, expect: UserDetail ) { assertNotNull(actual) kotlin.test.assertEquals(expect, actual) From 2501990dac78efa958c08e401cc4e4e2b506a1ee Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 06:20:58 +0900 Subject: [PATCH 11/40] =?UTF-8?q?chore:=20gradle=E3=81=AE=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=81=A8=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=AA=BF?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 3 ++- hideout-core/gradle.properties | 4 ++-- .../src/test/kotlin/utils/AbstractRepositoryTest.kt | 2 +- owl/gradle.properties | 7 ++++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index 936dc96e..d345cf66 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,5 @@ org.gradle.parallel=true org.gradle.configureondemand=true org.gradle.caching=true -org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC --add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED \ No newline at end of file +org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC --add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED +kotlin.compiler.preciseCompilationResultsBackup=true \ No newline at end of file diff --git a/hideout-core/gradle.properties b/hideout-core/gradle.properties index e628db63..0e81c240 100644 --- a/hideout-core/gradle.properties +++ b/hideout-core/gradle.properties @@ -13,8 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # -kotlin.code.style=official org.gradle.parallel=true org.gradle.configureondemand=true org.gradle.caching=true -org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC \ No newline at end of file +org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC --add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED +kotlin.compiler.preciseCompilationResultsBackup=true \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt index ce7a19f3..569cfa60 100644 --- a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt @@ -64,7 +64,7 @@ abstract class AbstractRepositoryTest(private val exposedTable: org.jetbrains.ex fun setup() { val hikariConfig = HikariConfig() hikariConfig.jdbcUrl = - "jdbc:h2:./test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4;" + "jdbc:h2:mem:test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4;" hikariConfig.driverClassName = "org.h2.Driver" hikariConfig.transactionIsolation = "TRANSACTION_READ_UNCOMMITTED" dataSource = HikariDataSource(hikariConfig) diff --git a/owl/gradle.properties b/owl/gradle.properties index 43cbcbb4..d345cf66 100644 --- a/owl/gradle.properties +++ b/owl/gradle.properties @@ -1,4 +1,5 @@ -kotlin.code.style=official -org.gradle.daemon=true org.gradle.parallel=true -org.gradle.configureondemand=true \ No newline at end of file +org.gradle.configureondemand=true +org.gradle.caching=true +org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC --add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED +kotlin.compiler.preciseCompilationResultsBackup=true \ No newline at end of file From 95c901790feeeaa57d059aa5d7187ee899a6557d Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 07:36:53 +0900 Subject: [PATCH 12/40] =?UTF-8?q?refactor:=20=E5=91=BD=E5=90=8D=E8=A6=8F?= =?UTF-8?q?=E5=89=87=E3=81=AB=E5=BE=93=E3=81=A3=E3=81=A6=E5=90=8D=E5=89=8D?= =?UTF-8?q?=E3=82=92=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/post/GetPostDetailApplicationService.kt | 4 ++-- .../hideout/core/domain/model/media/MediaRepository.kt | 2 +- .../{MediaRepositoryImpl.kt => ExposedMediaRepository.kt} | 7 ++++--- .../core/infrastructure/timeline/DefaultTimelineStore.kt | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/{MediaRepositoryImpl.kt => ExposedMediaRepository.kt} (94%) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/GetPostDetailApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/GetPostDetailApplicationService.kt index 278c0afe..89dd080e 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/GetPostDetailApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/GetPostDetailApplicationService.kt @@ -40,7 +40,7 @@ class GetPostDetailApplicationService( val iconMedia = actor.icon?.let { mediaRepository.findById(it) } - val mediaList = mediaRepository.findByIds(post.mediaIds) + val mediaList = mediaRepository.findByIdIn(post.mediaIds) val reactions = reactionsQueryService.findAllByPostId(post.id) @@ -82,7 +82,7 @@ class GetPostDetailApplicationService( actor to iconMedia } - val mediaList = mediaRepository.findByIds(post.mediaIds) + val mediaList = mediaRepository.findByIdIn(post.mediaIds) return PostDetail.of( post = post, actor = first, diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/media/MediaRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/media/MediaRepository.kt index f762af7b..1237d2bc 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/media/MediaRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/media/MediaRepository.kt @@ -19,6 +19,6 @@ package dev.usbharu.hideout.core.domain.model.media interface MediaRepository { suspend fun save(media: Media): Media suspend fun findById(id: MediaId): Media? - suspend fun findByIds(ids: List): List + suspend fun findByIdIn(ids: List): List suspend fun delete(media: Media) } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/MediaRepositoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepository.kt similarity index 94% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/MediaRepositoryImpl.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepository.kt index 81fddc23..b6da65e8 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/MediaRepositoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepository.kt @@ -27,7 +27,7 @@ import java.net.URI import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia @Repository -class MediaRepositoryImpl : MediaRepository, AbstractRepository() { +class ExposedMediaRepository : MediaRepository, AbstractRepository() { override val logger: Logger get() = Companion.logger @@ -51,12 +51,13 @@ class MediaRepositoryImpl : MediaRepository, AbstractRepository() { return query { return@query Media .selectAll().where { Media.id eq id.id } + .limit(1) .singleOrNull() ?.toMedia() } } - override suspend fun findByIds(ids: List): List { + override suspend fun findByIdIn(ids: List): List { return query { return@query Media .selectAll() @@ -72,7 +73,7 @@ class MediaRepositoryImpl : MediaRepository, AbstractRepository() { } companion object { - private val logger = LoggerFactory.getLogger(MediaRepositoryImpl::class.java) + private val logger = LoggerFactory.getLogger(ExposedMediaRepository::class.java) } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/timeline/DefaultTimelineStore.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/timeline/DefaultTimelineStore.kt index c435bc85..e25751cd 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/timeline/DefaultTimelineStore.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/timeline/DefaultTimelineStore.kt @@ -158,7 +158,7 @@ open class DefaultTimelineStore( actorRepository.findAllById(actorIds).associateBy { it.id } override suspend fun getMedias(mediaIds: List): Map = - mediaRepository.findByIds(mediaIds).associateBy { it.id } + mediaRepository.findByIdIn(mediaIds).associateBy { it.id } override suspend fun getReactions(postIds: List): Map> = reactionsQueryService.findAllByPostIdIn(postIds).groupBy { PostId(it.postId) } From 93e93c6b01b017acbea3c7ebd1926451f69e9a03 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 07:37:21 +0900 Subject: [PATCH 13/40] =?UTF-8?q?test:=20ExposedMediaRepository=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 --- .../ExposedMediaRepositoryTest.kt | 363 ++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt new file mode 100644 index 00000000..a9085f95 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt @@ -0,0 +1,363 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.media.* +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import utils.* +import java.net.URI +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia + + +class ExposedMediaRepositoryTest : AbstractRepositoryTest(Media) { + @Test + fun save_idが同じレコードが存在しないとinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + val media = EntityMedia( + id = MediaId(1), + name = MediaName("name"), + url = URI.create("https://www.example.com"), + remoteUrl = null, + thumbnailUrl = null, + type = FileType.Audio, + mimeType = MimeType("audio", "mp3", FileType.Audio), + blurHash = null, + description = null, + actorId = ActorId(1) + ) + ExposedMediaRepository().save(media) + + assertThat(assertTable) + .row(0) + .isEqualTo(Media.id, 1) + .isEqualTo(Media.name, "name") + .isEqualTo(Media.url, "https://www.example.com") + .isEqualTo(Media.remoteUrl, null) + .isEqualTo(Media.thumbnailUrl, null) + .isEqualTo(Media.type, "Audio") + .isEqualTo(Media.mimeType, "audio/mp3") + .isEqualTo(Media.blurhash, null) + .isEqualTo(Media.description, null) + .isEqualTo(Media.actorId, 1) + } + + @Test + fun save_idが同じレコードが存在したらupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto("public.media") { + columns( + "id", + "name", + "url", + "remote_url", + "thumbnail_url", + "type", + "blurhash", + "mime_type", + "description", + "actor_id" + ) + values( + 1, + "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", + "http://localhost:8081/files/1833054358862827520.jpeg", + null, + "http://localhost:8081/files/thumbnail-1833054358862827520.jpeg", + "Image", + "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", + "image/jpeg", + null, + 1 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val media = EntityMedia( + id = MediaId(1), + name = MediaName("name"), + url = URI.create("https://www.example.com"), + remoteUrl = null, + thumbnailUrl = null, + type = FileType.Audio, + mimeType = MimeType("audio", "mp3", FileType.Audio), + blurHash = null, + description = null, + actorId = ActorId(1) + ) + ExposedMediaRepository().save(media) + + assertThat(assertTable) + .row(0) + .isEqualTo(Media.id, 1) + .isEqualTo(Media.name, "name") + .isEqualTo(Media.url, "https://www.example.com") + .isEqualTo(Media.remoteUrl, null) + .isEqualTo(Media.thumbnailUrl, null) + .isEqualTo(Media.type, "Audio") + .isEqualTo(Media.mimeType, "audio/mp3") + .isEqualTo(Media.blurhash, null) + .isEqualTo(Media.description, null) + .isEqualTo(Media.actorId, 1) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.media") { + columns( + "id", + "name", + "url", + "remote_url", + "thumbnail_url", + "type", + "blurhash", + "mime_type", + "description", + "actor_id" + ) + values( + 1, + "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", + "http://localhost:8081/files/1833054358862827520.jpeg", + null, + "http://localhost:8081/files/thumbnail-1833054358862827520.jpeg", + "Image", + "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", + "image/jpeg", + null, + 1 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + val media = EntityMedia( + id = MediaId(1), + name = MediaName("name"), + url = URI.create("https://www.example.com"), + remoteUrl = null, + thumbnailUrl = null, + type = FileType.Audio, + mimeType = MimeType("audio", "mp3", FileType.Audio), + blurHash = null, + description = null, + actorId = ActorId(1) + ) + + change.withSuspend { + ExposedMediaRepository().delete(media) + } + + assertThat(change) + .changeOfDeletionOnTable(Media.tableName) + .rowAtStartPoint() + .value(Media.id.name) + .isEqualTo(1) + } + + @Test + fun findById_指定されたIdで存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.media") { + columns( + "id", + "name", + "url", + "remote_url", + "thumbnail_url", + "type", + "blurhash", + "mime_type", + "description", + "actor_id" + ) + values( + 1, + "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", + "http://localhost:8081/files/1833054358862827520.jpeg", + null, + "http://localhost:8081/files/thumbnail-1833054358862827520.jpeg", + "Image", + "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", + "image/jpeg", + null, + 1 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expect = EntityMedia( + id = MediaId(1), + name = MediaName("pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg"), + url = URI.create("http://localhost:8081/files/1833054358862827520.jpeg"), + remoteUrl = null, + thumbnailUrl = URI.create("http://localhost:8081/files/thumbnail-1833054358862827520.jpeg"), + type = FileType.Image, + mimeType = MimeType("image", "jpeg", FileType.Image), + blurHash = MediaBlurHash("U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay"), + description = null, + actorId = ActorId(1) + ) + + val actual = ExposedMediaRepository().findById(MediaId(1)) + + assertNotNull(actual) + assertEquals(expect, actual) + assertEquals(expect.id, actual.id) + assertEquals(expect.name, actual.name) + assertEquals(expect.url, actual.url) + assertEquals(expect.remoteUrl, actual.remoteUrl) + assertEquals(expect.thumbnailUrl, actual.thumbnailUrl) + assertEquals(expect.type, actual.type) + assertEquals(expect.mimeType, actual.mimeType) + assertEquals(expect.blurHash, actual.blurHash) + assertEquals(expect.description, actual.description) + assertEquals(expect.actorId, actual.actorId) + } + + @Test + fun findById_指定されたIdで存在しないとnull() = runTest { + assertNull(ExposedMediaRepository().findById(MediaId(1))) + } + + @Test + fun findByIdIn_指定されたIdすべて返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.media") { + columns( + "id", + "name", + "url", + "remote_url", + "thumbnail_url", + "type", + "blurhash", + "mime_type", + "description", + "actor_id" + ) + values( + 1, + "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", + "http://localhost:8081/files/1833054358862827520.jpeg", + null, + "http://localhost:8081/files/thumbnail-1833054358862827520.jpeg", + "Image", + "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", + "image/jpeg", + null, + 1 + ) + values( + 3, + "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", + "http://localhost:8081/files/18330354358862827520.jpeg", + null, + "http://localhost:8081/files/thumbn3ail-1833054358862827520.jpeg", + "Image", + "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", + "image/jpeg", + null, + 1 + ) + values( + 2, + "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", + "http://localhost:8081/files/18330545358862827520.jpeg", + null, + "http://localhost:8081/files/thumbnai5l-1833054358862827520.jpeg", + "Image", + "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", + "image/jpeg", + null, + 1 + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val actual = ExposedMediaRepository().findByIdIn(listOf(MediaId(1), MediaId(3))) + + assertThat(actual) + .hasSize(2) + } +} \ No newline at end of file From 498d6d73daba21a271d4eeaa488ea0ce4971846f Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 07:53:00 +0900 Subject: [PATCH 14/40] =?UTF-8?q?test:=20ExposedMediaRepository=E3=81=AE?= =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exposedrepository/ExposedMediaRepositoryTest.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt index a9085f95..2691252e 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt @@ -252,7 +252,7 @@ class ExposedMediaRepositoryTest : AbstractRepositoryTest(Media) { 1, "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", "http://localhost:8081/files/1833054358862827520.jpeg", - null, + "http://localhost:8081/files/183305453584862827520.jpeg", "http://localhost:8081/files/thumbnail-1833054358862827520.jpeg", "Image", "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", @@ -268,7 +268,7 @@ class ExposedMediaRepositoryTest : AbstractRepositoryTest(Media) { id = MediaId(1), name = MediaName("pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg"), url = URI.create("http://localhost:8081/files/1833054358862827520.jpeg"), - remoteUrl = null, + remoteUrl = URI.create("http://localhost:8081/files/183305453584862827520.jpeg"), thumbnailUrl = URI.create("http://localhost:8081/files/thumbnail-1833054358862827520.jpeg"), type = FileType.Image, mimeType = MimeType("image", "jpeg", FileType.Image), @@ -320,11 +320,11 @@ class ExposedMediaRepositoryTest : AbstractRepositoryTest(Media) { "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", "http://localhost:8081/files/1833054358862827520.jpeg", null, - "http://localhost:8081/files/thumbnail-1833054358862827520.jpeg", + null, "Image", "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", "image/jpeg", - null, + "", 1 ) values( @@ -334,7 +334,7 @@ class ExposedMediaRepositoryTest : AbstractRepositoryTest(Media) { null, "http://localhost:8081/files/thumbn3ail-1833054358862827520.jpeg", "Image", - "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", + null, "image/jpeg", null, 1 @@ -343,8 +343,8 @@ class ExposedMediaRepositoryTest : AbstractRepositoryTest(Media) { 2, "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", "http://localhost:8081/files/18330545358862827520.jpeg", + "http://localhost:8081/files/183305453584862827520.jpeg", null, - "http://localhost:8081/files/thumbnai5l-1833054358862827520.jpeg", "Image", "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", "image/jpeg", From 34a36b5ed538677db784fe1f4d44bc686176c22e Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 08:09:01 +0900 Subject: [PATCH 15/40] =?UTF-8?q?refactor:=20Uri=E5=9E=8B=E3=81=AEColumnTy?= =?UTF-8?q?pe=E3=82=92=E4=BD=9C=E6=88=90=E3=81=97=E3=81=A6=E5=9E=8B?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E6=80=A7=E3=82=92=E5=90=91=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/exposed/UriColumnType.kt | 22 ++++++++++++++++ .../ExposedUserTimelineQueryService.kt | 2 +- .../ExposedMediaRepository.kt | 26 +++++++++---------- .../ExposedMediaRepositoryTest.kt | 4 +-- 4 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/UriColumnType.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/UriColumnType.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/UriColumnType.kt new file mode 100644 index 00000000..57c22b9c --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/UriColumnType.kt @@ -0,0 +1,22 @@ +package dev.usbharu.hideout.core.infrastructure.exposed + +import org.jetbrains.exposed.sql.Column +import org.jetbrains.exposed.sql.ColumnType +import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.sql.vendors.currentDialect +import java.net.URI + +class UriColumnType(val colLength: Int) : ColumnType() { + override fun sqlType(): String = currentDialect.dataTypeProvider.varcharType(colLength) + + override fun valueFromDB(value: Any): URI? = when (value) { + is URI -> value + is String -> URI(value) + is CharSequence -> URI(value.toString()) + else -> error("Unexpected value of type String: $value of ${value::class.qualifiedName}") + } + + override fun notNullValueToDB(value: URI): Any = value.toString() +} + +fun Table.uri(name: String, colLength: Int): Column = registerColumn(name, UriColumnType(colLength)) \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/ExposedUserTimelineQueryService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/ExposedUserTimelineQueryService.kt index 6bc068ff..f24d6ff3 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/ExposedUserTimelineQueryService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/ExposedUserTimelineQueryService.kt @@ -92,7 +92,7 @@ class ExposedUserTimelineQueryService : UserTimelineQueryService, AbstractReposi screenName = it[Actors.screenName], url = URI.create(it[Actors.url]), locked = it[Actors.locked], - icon = it.getOrNull(iconMedia[Media.url])?.let { URI.create(it) } + icon = it.getOrNull(iconMedia[Media.url]) ), overview = it[authorizedQuery[Posts.overview]], text = it[authorizedQuery[Posts.text]], diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepository.kt index b6da65e8..03502b72 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepository.kt @@ -18,12 +18,12 @@ package dev.usbharu.hideout.core.infrastructure.exposedrepository import dev.usbharu.hideout.core.domain.model.actor.ActorId import dev.usbharu.hideout.core.domain.model.media.* +import dev.usbharu.hideout.core.infrastructure.exposed.uri import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.stereotype.Repository -import java.net.URI import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia @Repository @@ -35,9 +35,9 @@ class ExposedMediaRepository : MediaRepository, AbstractRepository() { Media.upsert { it[id] = media.id.id it[name] = media.name.name - it[url] = media.url.toString() - it[remoteUrl] = media.remoteUrl?.toString() - it[thumbnailUrl] = media.thumbnailUrl?.toString() + it[url] = media.url + it[remoteUrl] = media.remoteUrl + it[thumbnailUrl] = media.thumbnailUrl it[type] = media.type.name it[blurhash] = media.blurHash?.hash it[mimeType] = media.mimeType.type + "/" + media.mimeType.subtype @@ -83,9 +83,9 @@ fun ResultRow.toMedia(): EntityMedia { return EntityMedia( id = MediaId(this[Media.id]), name = MediaName(this[Media.name]), - url = URI.create(this[Media.url]), - remoteUrl = this[Media.remoteUrl]?.let { URI.create(it) }, - thumbnailUrl = this[Media.thumbnailUrl]?.let { URI.create(it) }, + url = this[Media.url], + remoteUrl = this[Media.remoteUrl], + thumbnailUrl = this[Media.thumbnailUrl], type = fileType, blurHash = this[Media.blurhash]?.let { MediaBlurHash(it) }, mimeType = MimeType(mimeType.substringBefore("/"), mimeType.substringAfter("/"), fileType), @@ -100,9 +100,9 @@ fun ResultRow.toMediaOrNull(): EntityMedia? { return EntityMedia( id = MediaId(this.getOrNull(Media.id) ?: return null), name = MediaName(this.getOrNull(Media.name) ?: return null), - url = URI.create(this.getOrNull(Media.url) ?: return null), - remoteUrl = this[Media.remoteUrl]?.let { URI.create(it) }, - thumbnailUrl = this[Media.thumbnailUrl]?.let { URI.create(it) }, + url = this.getOrNull(Media.url) ?: return null, + remoteUrl = this[Media.remoteUrl], + thumbnailUrl = this[Media.thumbnailUrl], type = FileType.valueOf(this[Media.type]), blurHash = this[Media.blurhash]?.let { MediaBlurHash(it) }, mimeType = MimeType(mimeType.substringBefore("/"), mimeType.substringAfter("/"), fileType), @@ -114,9 +114,9 @@ fun ResultRow.toMediaOrNull(): EntityMedia? { object Media : Table("media") { val id = long("id") val name = varchar("name", 255) - val url = varchar("url", 255).uniqueIndex() - val remoteUrl = varchar("remote_url", 255).uniqueIndex().nullable() - val thumbnailUrl = varchar("thumbnail_url", 255).uniqueIndex().nullable() + val url = uri("url", 255).uniqueIndex() + val remoteUrl = uri("remote_url", 255).uniqueIndex().nullable() + val thumbnailUrl = uri("thumbnail_url", 255).uniqueIndex().nullable() val type = varchar("type", 100) val blurhash = varchar("blurhash", 255).nullable() val mimeType = varchar("mime_type", 255) diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt index 2691252e..a1f7f425 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedMediaRepositoryTest.kt @@ -72,7 +72,7 @@ class ExposedMediaRepositoryTest : AbstractRepositoryTest(Media) { .row(0) .isEqualTo(Media.id, 1) .isEqualTo(Media.name, "name") - .isEqualTo(Media.url, "https://www.example.com") + .value(Media.url).isEqualTo("https://www.example.com") .isEqualTo(Media.remoteUrl, null) .isEqualTo(Media.thumbnailUrl, null) .isEqualTo(Media.type, "Audio") @@ -165,7 +165,7 @@ class ExposedMediaRepositoryTest : AbstractRepositoryTest(Media) { .row(0) .isEqualTo(Media.id, 1) .isEqualTo(Media.name, "name") - .isEqualTo(Media.url, "https://www.example.com") + .value(Media.url).isEqualTo("https://www.example.com") .isEqualTo(Media.remoteUrl, null) .isEqualTo(Media.thumbnailUrl, null) .isEqualTo(Media.type, "Audio") From d1560f25aaeeeefdb2fd7a65f5beca09dc11212a Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 10 Sep 2024 23:14:47 +0000 Subject: [PATCH 16/40] style: fix lint (CI) --- .../hideout/core/infrastructure/exposed/UriColumnType.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/UriColumnType.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/UriColumnType.kt index 57c22b9c..06f2388b 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/UriColumnType.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/UriColumnType.kt @@ -19,4 +19,4 @@ class UriColumnType(val colLength: Int) : ColumnType() { override fun notNullValueToDB(value: URI): Any = value.toString() } -fun Table.uri(name: String, colLength: Int): Column = registerColumn(name, UriColumnType(colLength)) \ No newline at end of file +fun Table.uri(name: String, colLength: Int): Column = registerColumn(name, UriColumnType(colLength)) From d9297b0992989ceab03c4fc5cd36d49bf75bcb6a Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 08:18:29 +0900 Subject: [PATCH 17/40] =?UTF-8?q?refactor:=20Uri=E5=9E=8B=E3=81=AEColumnTy?= =?UTF-8?q?pe=E3=82=92=E4=BD=9C=E6=88=90=E3=81=97=E3=81=A6=E5=9E=8B?= =?UTF-8?q?=E5=AE=89=E5=85=A8=E6=80=A7=E3=82=92=E5=90=91=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InstanceRepositoryImpl.kt | 21 ++++++++++--------- .../InstanceRepositoryImplTest.kt | 10 +++++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt index c7259dbb..09c2b9be 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt @@ -17,6 +17,7 @@ package dev.usbharu.hideout.core.infrastructure.exposedrepository import dev.usbharu.hideout.core.domain.model.instance.* +import dev.usbharu.hideout.core.infrastructure.exposed.uri import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.javatime.timestamp @@ -37,9 +38,9 @@ class InstanceRepositoryImpl : InstanceRepository, it[id] = instance.id.instanceId it[name] = instance.name.name it[description] = instance.description.description - it[url] = instance.url.toString() - it[iconUrl] = instance.iconUrl.toString() - it[sharedInbox] = instance.sharedInbox?.toString() + it[url] = instance.url + it[iconUrl] = instance.iconUrl + it[sharedInbox] = instance.sharedInbox it[software] = instance.software.software it[version] = instance.version.version it[isBlocked] = instance.isBlocked @@ -61,7 +62,7 @@ class InstanceRepositoryImpl : InstanceRepository, } override suspend fun findByUrl(url: URI): dev.usbharu.hideout.core.domain.model.instance.Instance? = query { - return@query Instance.selectAll().where { Instance.url eq url.toString() }.limit(1).singleOrNull()?.toInstance() + return@query Instance.selectAll().where { Instance.url eq url }.limit(1).singleOrNull()?.toInstance() } companion object { @@ -74,9 +75,9 @@ fun ResultRow.toInstance(): InstanceEntity { id = InstanceId(this[Instance.id]), name = InstanceName(this[Instance.name]), description = InstanceDescription(this[Instance.description]), - url = URI.create(this[Instance.url]), - iconUrl = URI.create(this[Instance.iconUrl]), - sharedInbox = this[Instance.sharedInbox]?.let { URI.create(it) }, + url = this[Instance.url], + iconUrl = this[Instance.iconUrl], + sharedInbox = this[Instance.sharedInbox], software = InstanceSoftware(this[Instance.software]), version = InstanceVersion(this[Instance.version]), isBlocked = this[Instance.isBlocked], @@ -90,9 +91,9 @@ object Instance : Table("instance") { val id = long("id") val name = varchar("name", 1000) val description = varchar("description", 5000) - val url = varchar("url", 255).uniqueIndex() - val iconUrl = varchar("icon_url", 255) - val sharedInbox = varchar("shared_inbox", 255).nullable().uniqueIndex() + val url = uri("url", 255).uniqueIndex() + val iconUrl = uri("icon_url", 255) + val sharedInbox = uri("shared_inbox", 255).nullable().uniqueIndex() val software = varchar("software", 255) val version = varchar("version", 255) val isBlocked = bool("is_blocked") diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt index ec30240f..6bcb52fb 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt @@ -44,8 +44,9 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { val table = assertTable assertThat(table).row(1).isEqualTo(InstanceTable.id, 1).isEqualTo(InstanceTable.name, "test") - .isEqualTo(InstanceTable.url, "https://www.example.com") - .isEqualTo(InstanceTable.iconUrl, "https://www.example.com").isEqualTo(InstanceTable.sharedInbox, null) + .value(InstanceTable.url).isEqualTo("https://www.example.com") + .value(InstanceTable.iconUrl).isEqualTo("https://www.example.com") + .isEqualTo(InstanceTable.sharedInbox, null) .isEqualTo(InstanceTable.software, "").isEqualTo(InstanceTable.version, "") .isEqualTo(InstanceTable.isBlocked, false).isEqualTo(InstanceTable.isMuted, false) .isEqualTo(InstanceTable.moderationNote, "").value(InstanceTable.createdAt) @@ -96,8 +97,9 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { val table = assertTable assertThat(table).row(1).isEqualTo(InstanceTable.id, 1).isEqualTo(InstanceTable.name, "test") - .isEqualTo(InstanceTable.url, "https://www.example.com") - .isEqualTo(InstanceTable.iconUrl, "https://www.example.com").isEqualTo(InstanceTable.sharedInbox, null) + .value(InstanceTable.url).isEqualTo("https://www.example.com") + .value(InstanceTable.iconUrl).isEqualTo("https://www.example.com") + .isEqualTo(InstanceTable.sharedInbox, null) .isEqualTo(InstanceTable.software, "").isEqualTo(InstanceTable.version, "") .isEqualTo(InstanceTable.isBlocked, false).isEqualTo(InstanceTable.isMuted, false) .isEqualTo(InstanceTable.moderationNote, "").value(InstanceTable.createdAt) From 90a815cf5dcda441bb7426029dcd36ae70084b73 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:44:20 +0900 Subject: [PATCH 18/40] =?UTF-8?q?test:=20ExposedPostRepository=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 --- .../ExposedPostRepository.kt | 78 ++- .../core/domain/model/post/TestPostFactory.kt | 4 +- .../ExposedPostRepositoryTest.kt | 527 ++++++++++++++++++ 3 files changed, 590 insertions(+), 19 deletions(-) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepositoryTest.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepository.kt index 37a476b1..59965760 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepository.kt @@ -163,6 +163,8 @@ class ExposedPostRepository( override suspend fun findById(id: PostId): Post? = query { Posts .leftJoin(PostsMedia) + .leftJoin(PostsEmojis) + .leftJoin(PostsVisibleActors) .selectAll() .where { Posts.id eq id.id @@ -174,6 +176,9 @@ class ExposedPostRepository( override suspend fun findAllById(ids: List): List { return query { Posts + .leftJoin(PostsMedia) + .leftJoin(PostsEmojis) + .leftJoin(PostsVisibleActors) .selectAll() .where { Posts.id inList ids.map { it.id } @@ -182,21 +187,48 @@ class ExposedPostRepository( } } - override suspend fun findByActorId(id: ActorId, page: Page?): PaginationList = PaginationList( - query { - Posts + override suspend fun findByActorId(id: ActorId, page: Page?): PaginationList { + val postList = query { + val query = Posts + .leftJoin(PostsMedia) + .leftJoin(PostsEmojis) + .leftJoin(PostsVisibleActors) .selectAll() .where { - actorId eq actorId + actorId eq id.id } - .let(postQueryMapper::map) - }, - null, - null - ) + + page(page, query) + + page?.limit?.let { query.limit(it) } + + query.let(postQueryMapper::map) + } + + val posts = if (page?.minId != null) { + postList.reversed() + } else { + postList + } + + return PaginationList( + posts, + null, + null + ) + } override suspend fun delete(post: Post) { query { + PostsMedia.deleteWhere { + postId eq post.id.id + } + PostsEmojis.deleteWhere { + postId eq post.id.id + } + PostsVisibleActors.deleteWhere { + postId eq post.id.id + } Posts.deleteWhere { id eq post.id.id } @@ -213,20 +245,15 @@ class ExposedPostRepository( ): PaginationList { val postList = query { val query = Posts + .leftJoin(PostsMedia) + .leftJoin(PostsEmojis) + .leftJoin(PostsVisibleActors) .selectAll() .where { Posts.actorId eq actorId.id and (visibility inList visibilityList.map { it.name }) } - if (of?.minId != null) { - query.orderBy(Posts.createdAt, SortOrder.ASC) - of.minId?.let { query.andWhere { Posts.id greater it } } - of.maxId?.let { query.andWhere { Posts.id less it } } - } else { - query.orderBy(Posts.createdAt, SortOrder.DESC) - of?.sinceId?.let { query.andWhere { Posts.id greater it } } - of?.maxId?.let { query.andWhere { Posts.id less it } } - } + page(of, query) of?.limit?.let { query.limit(it) } @@ -246,6 +273,21 @@ class ExposedPostRepository( ) } + private fun page( + page: Page?, + query: Query + ) { + if (page?.minId != null) { + query.orderBy(createdAt, SortOrder.ASC) + page.minId?.let { query.andWhere { id greater it } } + page.maxId?.let { query.andWhere { id less it } } + } else { + query.orderBy(createdAt, SortOrder.DESC) + page?.sinceId?.let { query.andWhere { id greater it } } + page?.maxId?.let { query.andWhere { id less it } } + } + } + companion object { private val logger = LoggerFactory.getLogger(ExposedPostRepository::class.java) } diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/post/TestPostFactory.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/post/TestPostFactory.kt index 388aaca0..8dea9878 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/post/TestPostFactory.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/post/TestPostFactory.kt @@ -1,6 +1,7 @@ package dev.usbharu.hideout.core.domain.model.post import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId import dev.usbharu.hideout.core.domain.model.instance.InstanceId import dev.usbharu.hideout.core.domain.model.media.MediaId import dev.usbharu.hideout.core.infrastructure.other.TwitterSnowflakeIdGenerateService @@ -29,13 +30,14 @@ object TestPostFactory { visibleActors: List = emptyList(), hide: Boolean = false, moveTo: Long? = null, + emojiIds: List = emptyList(), ): Post { return Post( PostId(id), ActorId(actorId), instanceId = InstanceId(instanceId), overview = overview?.let { PostOverview(it) }, - content = PostContent(content, content, emptyList()), + content = PostContent(content, content, emojiIds.map { CustomEmojiId(it) }), createdAt = createdAt, visibility = visibility, url = url, diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepositoryTest.kt new file mode 100644 index 00000000..50f28889 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepositoryTest.kt @@ -0,0 +1,527 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId +import dev.usbharu.hideout.core.domain.model.instance.InstanceId +import dev.usbharu.hideout.core.domain.model.media.MediaId +import dev.usbharu.hideout.core.domain.model.post.* +import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher +import dev.usbharu.hideout.core.infrastructure.exposed.PostQueryMapper +import dev.usbharu.hideout.core.infrastructure.exposed.PostResultRowMapper +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Spy +import org.mockito.junit.jupiter.MockitoExtension +import utils.* +import java.net.URI +import java.sql.Timestamp +import java.time.Instant +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@ExtendWith(MockitoExtension::class) +class ExposedPostRepositoryTest : AbstractRepositoryTest(Posts) { + + @InjectMocks + lateinit var repository: ExposedPostRepository + + @Mock + lateinit var domainEventPublisher: DomainEventPublisher + + @Spy + val postQueryMapper = PostQueryMapper(PostResultRowMapper()) + + @Test + fun save_idが同じレコードがない場合はinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + values( + 2, + "a", + "test-hideout-dev.usbharu.dev", + "a", + "", + "https://test-hideout-dev.usbharu.dev/users/a/inbox", + "https://test-hideout-dev.usbharu.dev/users/a/outbox", + "https://test-hideout-dev.usbharu.dev/users/a", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/a#main-key", + "https://test-hideout-dev.usbharu.dev/users/a/following", + "https://test-hideout-dev.usbharu.dev/users/a/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto(Instance.tableName) { + columns(Instance.columns) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + insertInto("public.media") { + columns(Media.columns) + values( + 3, + "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", + "http://localhost:8081/files/18330354358862827520.jpeg", + null, + "http://localhost:8081/files/thumbn3ail-1833054358862827520.jpeg", + "Image", + null, + "image/jpeg", + null, + 1 + ) + values( + 2, + "pnc__picked_media_256f8e6d-68cd-4a76-bb38-57e35f6ca8c6.jpg", + "http://localhost:8081/files/18330545358862827520.jpeg", + "http://localhost:8081/files/183305453584862827520.jpeg", + null, + "Image", + "U\$JuAZWBxut7~qoLoft6j]t7Rjj[RjayWBay", + "image/jpeg", + null, + 1 + ) + } + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 4, + "emoji", + "example.com", + 1, + "https://example.com", + null, + "2024-09-09 17:12:03.941339" + ) + values( + 5, + "emoji2", + "example.com", + 1, + "https://example.com/2", + "test", + "2024-09-09 17:12:03.941339" + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val post = TestPostFactory.create( + id = 1, + createdAt = Instant.parse("2021-01-01T00:00:00Z"), + mediaIds = listOf(2, 3), + emojiIds = listOf(4, 5), + visibility = Visibility.DIRECT, + visibleActors = listOf(1, 2) + ) + repository.save(post) + + assertThat(assertTable) + .row(0) + .isEqualTo(Posts.id, post.id.id) + .isEqualTo(Posts.actorId, post.actorId.id) + .isEqualTo(Posts.instanceId, post.instanceId.instanceId) + .isEqualTo(Posts.overview, post.overview?.overview) + .isEqualTo(Posts.content, post.content.content) + .isEqualTo(Posts.text, post.text) + .value(Posts.createdAt).isEqualTo(Timestamp.from(post.createdAt)) + .isEqualTo(Posts.visibility, post.visibility.name) + .value(Posts.url).isEqualTo(post.url.toString()) + .value(Posts.repostId).isEqualTo(post.repostId?.id) + .value(Posts.replyId).isEqualTo(post.replyId?.id) + .isEqualTo(Posts.sensitive, post.sensitive) + .value(Posts.apId).isEqualTo(post.apId.toString()) + .isEqualTo(Posts.deleted, post.deleted) + .isEqualTo(Posts.hide, post.hide) + .value(Posts.moveTo).isEqualTo(post.moveTo?.id) + + assertThat(getTable(PostsMedia.tableName)) + .row(0) + .value(PostsMedia.postId).isEqualTo(post.id.id) + .value(PostsMedia.mediaId).isEqualTo(2) + .row(1) + .value(PostsMedia.postId).isEqualTo(post.id.id) + .value(PostsMedia.mediaId).isEqualTo(3) + + assertThat(getTable(PostsEmojis.tableName)) + .row(0) + .value(PostsEmojis.postId).isEqualTo(post.id.id) + .value(PostsEmojis.emojiId).isEqualTo(4) + .row(1) + .value(PostsEmojis.postId).isEqualTo(post.id.id) + .value(PostsEmojis.emojiId).isEqualTo(5) + + assertThat(getTable(PostsVisibleActors.tableName)) + .row(0) + .value(PostsVisibleActors.postId).isEqualTo(post.id.id) + .value(PostsVisibleActors.actorId).isEqualTo(1) + .row(1) + .value(PostsVisibleActors.postId).isEqualTo(post.id.id) + .value(PostsVisibleActors.actorId).isEqualTo(2) + } + + @Test + fun save_idが同じレコードがある場合はupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Instance.tableName) { + columns(Instance.columns) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1832779978794602496, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + } + }.launch() + + val post = TestPostFactory.create( + id = 1, + instanceId = 1, + overview = "aaaaaaaa", + createdAt = Instant.parse("2021-01-01T00:00:00Z"), + replyId = 2, + repostId = 2, + moveTo = 2 + ) + + repository.save(post) + + assertThat(assertTable) + .row(0) + .isEqualTo(Posts.id, post.id.id) + .isEqualTo(Posts.actorId, post.actorId.id) + .isEqualTo(Posts.instanceId, post.instanceId.instanceId) + .isEqualTo(Posts.overview, post.overview?.overview) + .isEqualTo(Posts.content, post.content.content) + .isEqualTo(Posts.text, post.text) + .value(Posts.createdAt).isEqualTo(Timestamp.from(post.createdAt)) + .isEqualTo(Posts.visibility, post.visibility.name) + .value(Posts.url).isEqualTo(post.url.toString()) + .value(Posts.repostId).isEqualTo(post.repostId?.id) + .value(Posts.replyId).isEqualTo(post.replyId?.id) + .isEqualTo(Posts.sensitive, post.sensitive) + .value(Posts.apId).isEqualTo(post.apId.toString()) + .isEqualTo(Posts.deleted, post.deleted) + .isEqualTo(Posts.hide, post.hide) + .value(Posts.moveTo).isEqualTo(post.moveTo?.id) + } + + @Test + fun findById_指定したIdがある場合は返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1832779978794602496, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + } + insertInto(PostsMedia.tableName) { + columns(PostsMedia.columns) + values(1, 2) + } + insertInto(PostsEmojis.tableName) { + columns(PostsEmojis.columns) + values(1, 3) + } + insertInto(PostsVisibleActors.tableName) { + columns(PostsVisibleActors.columns) + values(1, 4) + } + }.launch() + + val actual = repository.findById(PostId(1)) + + val expect = Post( + id = PostId(1), + actorId = ActorId(1832779978794602496), + instanceId = InstanceId(1832779642545639424), + overview = PostOverview(""), + content = PostContent("test", "

test

", listOf(CustomEmojiId(3))), + createdAt = Instant.parse("2020-01-01T00:00:00Z"), + visibility = Visibility.PUBLIC, + url = URI.create("http://localhost:8081/users/a/posts/1832779994749734912"), + repostId = null, + replyId = null, + sensitive = false, + apId = URI.create("http://localhost:8081/users/a/posts/1832779994749734912"), + deleted = false, + mediaIds = listOf(MediaId(2)), + visibleActors = setOf(ActorId(4)), + hide = false, moveTo = null + ) + + assertNotNull(actual) + assertEquals(expect, actual) + assertEquals(expect.id, actual.id) + assertEquals(expect.actorId, actual.actorId) + assertEquals(expect.instanceId, actual.instanceId) + assertEquals(expect.overview, actual.overview) + assertEquals(expect.content, actual.content) + assertEquals(expect.createdAt, actual.createdAt) + assertEquals(expect.visibility, actual.visibility) + assertEquals(expect.url, actual.url) + assertEquals(expect.repostId, actual.repostId) + assertEquals(expect.replyId, actual.replyId) + assertEquals(expect.sensitive, actual.sensitive) + assertEquals(expect.apId, actual.apId) + assertEquals(expect.deleted, actual.deleted) + assertEquals(expect.mediaIds, actual.mediaIds) + assertEquals(expect.visibleActors, actual.visibleActors) + assertEquals(expect.hide, actual.hide) + + } + + @Test + fun findById_指定したIdで存在しないとnull() = runTest { + assertNull(repository.findById(PostId(1))) + } + + @Test + fun findAllById_指定されたIdすべて返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1832779978794602496, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + values( + 2, + 1832779978794602496, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/18327739994749734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/18327793994749734912", + false, + false, + null + ) + values( + 3, + 1832779978794602496, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/183277399947494734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/183277939947493734912", + false, + false, + 2 + ) + } + }.launch() + + val findAllById = repository.findAllById(listOf(PostId(1), PostId(3))) + + assertThat(findAllById) + .hasSize(2) + } + + @Test + fun findByActorId_指定されたActorIdすべて返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + values( + 2, + 2, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/18327739994749734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/18327793994749734912", + false, + false, + null + ) + values( + 3, + 1, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/183277399947494734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/183277939947493734912", + false, + false, + 2 + ) + } + }.launch() + + val findAllById = repository.findByActorId(ActorId(1)) + + assertThat(findAllById) + .hasSize(2) + } +} \ No newline at end of file From 575763c605400b49a2006e171e9a5c5b9d389f07 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 10:48:40 +0900 Subject: [PATCH 19/40] =?UTF-8?q?test:=20ExposedPostRepository=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 --- .../ExposedPostRepository.kt | 18 +- .../ExposedPostRepositoryTest.kt | 673 ++++++++++++++++++ 2 files changed, 678 insertions(+), 13 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepository.kt index 59965760..7bbe3782 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepository.kt @@ -190,9 +190,6 @@ class ExposedPostRepository( override suspend fun findByActorId(id: ActorId, page: Page?): PaginationList { val postList = query { val query = Posts - .leftJoin(PostsMedia) - .leftJoin(PostsEmojis) - .leftJoin(PostsVisibleActors) .selectAll() .where { actorId eq id.id @@ -200,8 +197,6 @@ class ExposedPostRepository( page(page, query) - page?.limit?.let { query.limit(it) } - query.let(postQueryMapper::map) } @@ -213,8 +208,8 @@ class ExposedPostRepository( return PaginationList( posts, - null, - null + posts.lastOrNull()?.id, + posts.firstOrNull()?.id ) } @@ -245,9 +240,6 @@ class ExposedPostRepository( ): PaginationList { val postList = query { val query = Posts - .leftJoin(PostsMedia) - .leftJoin(PostsEmojis) - .leftJoin(PostsVisibleActors) .selectAll() .where { Posts.actorId eq actorId.id and (visibility inList visibilityList.map { it.name }) @@ -255,8 +247,6 @@ class ExposedPostRepository( page(of, query) - of?.limit?.let { query.limit(it) } - query.let(postQueryMapper::map) } @@ -279,13 +269,15 @@ class ExposedPostRepository( ) { if (page?.minId != null) { query.orderBy(createdAt, SortOrder.ASC) - page.minId?.let { query.andWhere { id greater it } } + page.minId!!.let { query.andWhere { id greater it } } page.maxId?.let { query.andWhere { id less it } } } else { query.orderBy(createdAt, SortOrder.DESC) page?.sinceId?.let { query.andWhere { id greater it } } page?.maxId?.let { query.andWhere { id less it } } } + + page?.limit?.let { query.limit(it) } } companion object { diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepositoryTest.kt index 50f28889..569432cd 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedPostRepositoryTest.kt @@ -6,18 +6,24 @@ import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId import dev.usbharu.hideout.core.domain.model.instance.InstanceId import dev.usbharu.hideout.core.domain.model.media.MediaId import dev.usbharu.hideout.core.domain.model.post.* +import dev.usbharu.hideout.core.domain.model.support.page.Page import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher import dev.usbharu.hideout.core.infrastructure.exposed.PostQueryMapper import dev.usbharu.hideout.core.infrastructure.exposed.PostResultRowMapper import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.assertj.db.api.Assertions.assertThat +import org.assertj.db.type.Changes +import org.jetbrains.exposed.sql.transactions.TransactionManager import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.InjectMocks import org.mockito.Mock import org.mockito.Spy import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import utils.* import java.net.URI import java.sql.Timestamp @@ -524,4 +530,671 @@ class ExposedPostRepositoryTest : AbstractRepositoryTest(Posts) { assertThat(findAllById) .hasSize(2) } + + @Test + fun findByActorId_page_max() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + values( + 2, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-02T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/18327739994749734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/18327793994749734912", + false, + false, + null + ) + values( + 3, + 1, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-03T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/183277399947494734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/183277939947493734912", + false, + false, + 2 + ) + } + }.launch() + + val findAllById = repository.findByActorId(ActorId(1), Page.of(maxId = 3)) + + assertThat(findAllById) + .hasSize(2) + + assertEquals(2, findAllById[0].id.id) + assertEquals(1, findAllById[1].id.id) + } + + @Test + fun findByActorId_page_min() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + values( + 2, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-02T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/18327739994749734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/18327793994749734912", + false, + false, + null + ) + values( + 3, + 1, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-03T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/183277399947494734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/183277939947493734912", + false, + false, + 2 + ) + } + }.launch() + + val findAllById = repository.findByActorId(ActorId(1), Page.of(minId = 1)) + + assertThat(findAllById) + .hasSize(2) + + assertEquals(3, findAllById[0].id.id) + assertEquals(2, findAllById[1].id.id) + } + + @Test + fun findByActorId_page_since() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + values( + 2, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-02T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/18327739994749734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/18327793994749734912", + false, + false, + null + ) + values( + 3, + 1, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-03T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/183277399947494734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/183277939947493734912", + false, + false, + 2 + ) + } + }.launch() + + val findAllById = repository.findByActorId(ActorId(1), Page.of(sinceId = 1)) + + assertThat(findAllById) + .hasSize(2) + + assertEquals(3, findAllById[0].id.id) + assertEquals(2, findAllById[1].id.id) + } + + @Test + fun findByActorId_page_limit() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + values( + 2, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-02T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/18327739994749734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/18327793994749734912", + false, + false, + null + ) + values( + 3, + 1, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-03T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/183277399947494734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/183277939947493734912", + false, + false, + 2 + ) + } + }.launch() + + val findAllById = repository.findByActorId(ActorId(1), Page.of(limit = 1)) + + assertThat(findAllById) + .hasSize(1) + + assertEquals(3, findAllById[0].id.id) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1832779978794602496, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + } + insertInto(PostsMedia.tableName) { + columns(PostsMedia.columns) + values(1, 2) + } + insertInto(PostsEmojis.tableName) { + columns(PostsEmojis.columns) + values(1, 3) + } + insertInto(PostsVisibleActors.tableName) { + columns(PostsVisibleActors.columns) + values(1, 4) + } + }.launch() + + val post = TestPostFactory.create(1) + + val changes = Changes(dataSource) + changes.withSuspend { + repository.delete(post) + } + + assertThat(changes) + .changeOfDeletionOnTable(Posts.tableName) + .rowAtStartPoint() + .value(Posts.id.name).isEqualTo(1) + .changeOfDeletionOnTable(PostsMedia.tableName) + .rowAtStartPoint() + .value(PostsMedia.mediaId.name).isEqualTo(2) + .changeOfDeletionOnTable(PostsEmojis.tableName) + .rowAtStartPoint() + .value(PostsEmojis.emojiId.name).isEqualTo(3) + .changeOfDeletionOnTable(PostsVisibleActors.tableName) + .rowAtStartPoint() + .value(PostsVisibleActors.actorId.name).isEqualTo(4) + } + + @Test + fun findByActorIdAndVisiblilityInList_指定されたActorIdかつVisibilityのPostすべて返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + values( + 2, + 2, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-02T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/18327739994749734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/18327793994749734912", + false, + false, + null + ) + values( + 3, + 1, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-03T00:00:00Z")), + "UNLISTED", + "http://localhost:8081/users/a/posts/183277399947494734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/183277939947493734912", + false, + false, + 2 + ) + values( + 4, + 1, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-04T00:00:00Z")), + "FOLLOWERS", + "http://localhost:8081/users/a/posts/1832773999474947343912", + null, + null, + false, + "http://localhost:8081/users/a/posts/1832779399474937349312", + false, + false, + 2 + ) + } + }.launch() + + val findAllById = + repository.findByActorIdAndVisibilityInList(ActorId(1), listOf(Visibility.PUBLIC, Visibility.FOLLOWERS)) + + assertThat(findAllById) + .hasSize(2) + + assertEquals(4, findAllById[0].id.id) + assertEquals(1, findAllById[1].id.id) + } + + @Test + fun saveAll_idがある場合はinsertなければupdateされる() = runTest { + + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + values( + 3, + 1, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-03T00:00:00Z")), + "UNLISTED", + "http://localhost:8081/users/a/posts/183277399947494734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/183277939947493734912", + false, + false, + 2 + ) + } + insertInto(PostsMedia.tableName) { + columns(PostsMedia.columns) + values(1, 1) + } + insertInto(PostsEmojis.tableName) { + columns(PostsEmojis.columns) + values(1, 2) + } + insertInto(PostsVisibleActors.tableName) { + columns(PostsVisibleActors.columns) + values(1, 3) + } + }.launch() + + val pl = listOf( + TestPostFactory.create(1, createdAt = Instant.parse("2020-01-04T00:00:00Z"), mediaIds = listOf(5)), + TestPostFactory.create(2, createdAt = Instant.parse("2020-01-05T00:00:00Z"), emojiIds = listOf(6)), + TestPostFactory.create( + 3, + createdAt = Instant.parse("2020-01-06T00:00:00Z"), + visibleActors = listOf(7), + overview = "", + replyId = 1, + repostId = 1, + moveTo = 1 + ) + ) + + repository.saveAll(pl) + + assertThat(assertTable) + .row(0) + .isEqualTo(Posts.id, 1) + .value(Posts.createdAt).isEqualTo(Timestamp.from(pl[0].createdAt)) + .row(1) + .isEqualTo(Posts.id, 2) + .value(Posts.createdAt).isEqualTo(Timestamp.from(pl[1].createdAt)) + .row(2) + .isEqualTo(Posts.id, 3) + .value(Posts.createdAt).isEqualTo(Timestamp.from(pl[2].createdAt)) + + assertThat(getTable(PostsMedia.tableName)) + .row(0) + .isEqualTo(PostsMedia.mediaId, 5) + + assertThat(getTable(PostsEmojis.tableName)) + .row(0) + .isEqualTo(PostsEmojis.emojiId, 6) + + assertThat(getTable(PostsVisibleActors.tableName)) + .row(0) + .isEqualTo(PostsVisibleActors.actorId, 7) + } + + @Test + fun save_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + }.launch() + + val post = TestPostFactory.create() + post.checkUpdate() + repository.save(post) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } + + @Test + fun saveAll_ドメインイベントがすべてパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + values( + 3, + 1, + 1832779642545639424, + "", + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-03T00:00:00Z")), + "UNLISTED", + "http://localhost:8081/users/a/posts/183277399947494734912", + null, + null, + false, + "http://localhost:8081/users/a/posts/183277939947493734912", + false, + false, + 2 + ) + } + insertInto(PostsMedia.tableName) { + columns(PostsMedia.columns) + values(1, 1) + } + insertInto(PostsEmojis.tableName) { + columns(PostsEmojis.columns) + values(1, 2) + } + insertInto(PostsVisibleActors.tableName) { + columns(PostsVisibleActors.columns) + values(1, 3) + } + }.launch() + + val pl = listOf( + TestPostFactory.create(1, createdAt = Instant.parse("2020-01-04T00:00:00Z"), mediaIds = listOf(5)), + TestPostFactory.create(2, createdAt = Instant.parse("2020-01-05T00:00:00Z"), emojiIds = listOf(6)), + TestPostFactory.create( + 3, + createdAt = Instant.parse("2020-01-06T00:00:00Z"), + visibleActors = listOf(7), + overview = "", + replyId = 1, + repostId = 1, + moveTo = 1 + ) + ).map { it.checkUpdate();it } + + repository.saveAll(pl) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(3)).publishEvent(any()) + } + + @Test + fun delete_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.posts") { + columns(Posts.columns) + values( + 1, + 1, + 1832779642545639424, + null, + "

test

", + "test", + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")), + "PUBLIC", + "http://localhost:8081/users/a/posts/1832779994749734912", + 2, + 2, + false, + "http://localhost:8081/users/a/posts/1832779994749734912", + false, + false, + null + ) + + } + }.launch() + + val post = TestPostFactory.create(1) + post.checkUpdate() + repository.delete(post) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } } \ No newline at end of file From 57430b7e4a9201393e3ccefbbe56c5c3085cdd58 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:55:42 +0900 Subject: [PATCH 20/40] =?UTF-8?q?test:=20ExposedActorRepository=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 --- .../MigrationLocalActorApplicationService.kt | 2 +- .../hideout/core/domain/model/actor/Actor.kt | 91 ++- .../domain/model/actor/ActorDescription.kt | 13 + .../domain/model/actor/ActorScreenName.kt | 13 + .../exposed/ActorQueryMapper.kt | 2 +- .../ExposedActorRepository.kt | 2 +- .../core/domain/model/actor/ActorsTest.kt | 12 +- .../domain/model/actor/TestActorFactory.kt | 10 +- .../ExposedActorRepositoryTest.kt | 558 ++++++++++++++++++ .../oauth2/UserDetailsServiceImplTest.kt | 2 +- 10 files changed, 675 insertions(+), 30 deletions(-) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepositoryTest.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/MigrationLocalActorApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/MigrationLocalActorApplicationService.kt index ea9b8313..24a36249 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/MigrationLocalActorApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/actor/MigrationLocalActorApplicationService.kt @@ -56,7 +56,7 @@ class MigrationLocalActorApplicationService( val canAccountMigration = localActorMigrationCheckDomainService.canAccountMigration(userDetail, fromActor, toActor) if (canAccountMigration.canMigration) { - fromActor.moveTo = toActorId + fromActor.setMoveTo(toActorId) actorRepository.save(fromActor) } else { when (canAccountMigration) { diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt index 8fd41710..77361e77 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt @@ -85,31 +85,40 @@ class Actor( } var alsoKnownAs = alsoKnownAs - set(value) { - require(value.none { it == id }) - field = value - } + private set + + fun setAlsoKnownAs(alsoKnownAs: Set) { + require(alsoKnownAs.none { it == id }) + this.alsoKnownAs = alsoKnownAs + } var moveTo = moveTo - set(value) { - require(value != id) - addDomainEvent(ActorDomainEventFactory(this).createEvent(MOVE)) - field = value - } + private set + + fun setMoveTo(moveTo: ActorId?) { + require(moveTo != id) + addDomainEvent(ActorDomainEventFactory(this).createEvent(MOVE)) + this.moveTo = moveTo + } var emojis = emojiIds private set var description = description - set(value) { - addDomainEvent(ActorDomainEventFactory(this).createEvent(UPDATE)) - field = value - } + private set + + fun setDescription(description: ActorDescription) { + addDomainEvent(ActorDomainEventFactory(this).createEvent(UPDATE)) + this.description = description + } + var screenName = screenName - set(value) { - addDomainEvent(ActorDomainEventFactory(this).createEvent(UPDATE)) - field = value - } + private set + + fun setScreenName(screenName: ActorScreenName) { + addDomainEvent(ActorDomainEventFactory(this).createEvent(UPDATE)) + this.screenName = screenName + } var deleted = deleted private set @@ -135,4 +144,52 @@ class Actor( fun checkUpdate() { addDomainEvent(ActorDomainEventFactory(this).createEvent(CHECK_UPDATE)) } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Actor + + return id == other.id + } + + override fun hashCode(): Int { + return id.hashCode() + } + + override fun toString(): String { + return "Actor(" + + "id=$id, " + + "name=$name, " + + "domain=$domain, " + + "inbox=$inbox, " + + "outbox=$outbox, " + + "url=$url, " + + "publicKey=$publicKey, " + + "privateKey=$privateKey, " + + "createdAt=$createdAt, " + + "keyId=$keyId, " + + "followersEndpoint=$followersEndpoint, " + + "followingEndpoint=$followingEndpoint, " + + "instance=$instance, " + + "locked=$locked, " + + "followersCount=$followersCount, " + + "followingCount=$followingCount, " + + "postsCount=$postsCount, " + + "lastPostAt=$lastPostAt, " + + "lastUpdateAt=$lastUpdateAt, " + + "banner=$banner, " + + "icon=$icon, " + + "suspend=$suspend, " + + "alsoKnownAs=$alsoKnownAs, " + + "moveTo=$moveTo, " + + "emojis=$emojis, " + + "description=$description, " + + "screenName=$screenName, " + + "deleted=$deleted" + + ")" + } + + } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorDescription.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorDescription.kt index 84c60eff..78ef02a6 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorDescription.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorDescription.kt @@ -19,6 +19,19 @@ package dev.usbharu.hideout.core.domain.model.actor class ActorDescription(description: String) { val description: String = description.take(LENGTH) + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ActorDescription + + return description == other.description + } + + override fun hashCode(): Int { + return description.hashCode() + } + companion object { const val LENGTH = 10000 val empty = ActorDescription("") diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorScreenName.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorScreenName.kt index 57866d77..29e13f03 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorScreenName.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorScreenName.kt @@ -20,6 +20,19 @@ class ActorScreenName(screenName: String) { val screenName: String = screenName.take(LENGTH) + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ActorScreenName + + return screenName == other.screenName + } + + override fun hashCode(): Int { + return screenName.hashCode() + } + companion object { const val LENGTH = 300 val empty = ActorScreenName("") diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorQueryMapper.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorQueryMapper.kt index e3bcab78..5e3c96c8 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorQueryMapper.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorQueryMapper.kt @@ -35,7 +35,7 @@ class ActorQueryMapper(private val actorResultRowMapper: ResultRowMapper) .first() .let(actorResultRowMapper::map) .apply { - alsoKnownAs = buildAlsoKnownAs(it) + setAlsoKnownAs(buildAlsoKnownAs(it)) clearDomainEvents() } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt index 8de778e1..717fdd7a 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt @@ -69,8 +69,8 @@ class ExposedActorRepository( override suspend fun delete(actor: Actor) { query { - Actors.deleteWhere { id eq actor.id.id } ActorsAlsoKnownAs.deleteWhere { actorId eq actor.id.id } + Actors.deleteWhere { id eq actor.id.id } onComplete { update(actor) } diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorsTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorsTest.kt index d4f55ff9..e98a7113 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorsTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorsTest.kt @@ -34,7 +34,7 @@ class ActorsTest { val actor = TestActorFactory.create(publicKey = ActorPublicKey("")) val actorIds = setOf(ActorId(100), ActorId(200)) - actor.alsoKnownAs = actorIds + actor.setAlsoKnownAs(actorIds) assertEquals(actorIds, actor.alsoKnownAs) } @@ -44,7 +44,7 @@ class ActorsTest { val actor = TestActorFactory.create(publicKey = ActorPublicKey("")) - actor.moveTo = ActorId(100) + actor.setMoveTo(ActorId(100)) assertContainsEvent(actor, ActorEvent.MOVE.eventName) } @@ -54,7 +54,7 @@ class ActorsTest { val actor = TestActorFactory.create(publicKey = ActorPublicKey("")) assertThrows { - actor.alsoKnownAs = setOf(actor.id) + actor.setAlsoKnownAs(setOf(actor.id)) } } @@ -63,7 +63,7 @@ class ActorsTest { val actor = TestActorFactory.create(publicKey = ActorPublicKey("")) assertThrows { - actor.moveTo = actor.id + actor.setMoveTo(actor.id) } } @@ -71,7 +71,7 @@ class ActorsTest { fun descriptionが更新されたときupdateイベントが発生する() { val actor = TestActorFactory.create(publicKey = ActorPublicKey("")) - actor.description = ActorDescription("hoge fuga") + actor.setDescription(ActorDescription("hoge fuga")) assertContainsEvent(actor, ActorEvent.UPDATE.eventName) } @@ -80,7 +80,7 @@ class ActorsTest { fun screenNameが更新されたときupdateイベントが発生する() { val actor = TestActorFactory.create(publicKey = ActorPublicKey("")) - actor.screenName = ActorScreenName("fuga hoge") + actor.setScreenName(ActorScreenName("fuga hoge")) assertContainsEvent(actor, ActorEvent.UPDATE.eventName) } diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActorFactory.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActorFactory.kt index 4f81a194..c39e8818 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActorFactory.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActorFactory.kt @@ -2,6 +2,7 @@ package dev.usbharu.hideout.core.domain.model.actor import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId import dev.usbharu.hideout.core.domain.model.instance.InstanceId +import dev.usbharu.hideout.core.domain.model.media.MediaId import dev.usbharu.hideout.core.domain.model.support.domain.Domain import dev.usbharu.hideout.core.infrastructure.other.TwitterSnowflakeIdGenerateService import kotlinx.coroutines.runBlocking @@ -32,12 +33,14 @@ object TestActorFactory { followingCount: Int = 0, postCount: Int = 0, lastPostDate: Instant? = null, + lastUpdateAt: Instant = createdAt, suspend: Boolean = false, alsoKnownAs: Set = emptySet(), moveTo: Long? = null, emojiIds: Set = emptySet(), deleted: Boolean = false, - roles: Set = emptySet(), + icon: Long? = null, + banner: Long? = null, ): Actor { return runBlocking { Actor( @@ -61,13 +64,14 @@ object TestActorFactory { followingCount = ActorRelationshipCount(followingCount), postsCount = ActorPostsCount(postCount), lastPostAt = lastPostDate, + lastUpdateAt = lastUpdateAt, suspend = suspend, alsoKnownAs = alsoKnownAs, moveTo = moveTo?.let { ActorId(it) }, emojiIds = emojiIds, deleted = deleted, - icon = null, - banner = null, + icon = icon?.let { MediaId(it) }, + banner = banner?.let { MediaId(it) }, ) } diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepositoryTest.kt new file mode 100644 index 00000000..2cbe8f22 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepositoryTest.kt @@ -0,0 +1,558 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.actor.* +import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher +import dev.usbharu.hideout.core.infrastructure.exposed.ActorQueryMapper +import dev.usbharu.hideout.core.infrastructure.exposed.ActorResultRowMapper +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.assertj.db.api.Assertions.assertThat +import org.assertj.db.type.Changes +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.Spy +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import utils.* +import java.net.URI +import java.sql.Timestamp +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@ExtendWith(MockitoExtension::class) +class ExposedActorRepositoryTest : AbstractRepositoryTest(Actors) { + + @InjectMocks + lateinit var repository: ExposedActorRepository + + @Mock + lateinit var domainEventPublisher: DomainEventPublisher + + @Spy + val actorQueryMapper = ActorQueryMapper(ActorResultRowMapper()) + + @Test + fun save_idが同じレコードがない場合はinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Instance.tableName) { + columns(Instance.columns) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val actor = TestActorFactory.create() + + repository.save(actor) + + assertThat(assertTable) + .row(1) + .isEqualTo(Actors.id, actor.id.id) + .isEqualTo(Actors.name, actor.name.name) + .isEqualTo(Actors.domain, actor.domain.domain) + .isEqualTo(Actors.screenName, actor.screenName.screenName) + .isEqualTo(Actors.description, actor.description.description) + .value(Actors.url).isEqualTo(actor.url.toString()) + .value(Actors.inbox).isEqualTo(actor.inbox.toString()) + .value(Actors.outbox).isEqualTo(actor.outbox.toString()) + .isEqualTo(Actors.publicKey, actor.publicKey.publicKey) + .isEqualTo(Actors.privateKey, actor.privateKey?.privateKey) + } + + @Test + fun save_idが同じレコードがある場合はupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Instance.tableName) { + columns(Instance.columns) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto(ActorsAlsoKnownAs.tableName) { + columns(ActorsAlsoKnownAs.columns) + values(1, 2) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val actor = TestActorFactory.create(1, alsoKnownAs = setOf(ActorId(1))) + + repository.save(actor) + + assertThat(assertTable) + .row(1) + .isEqualTo(Actors.id, actor.id.id) + .isEqualTo(Actors.name, actor.name.name) + .isEqualTo(Actors.domain, actor.domain.domain) + .isEqualTo(Actors.screenName, actor.screenName.screenName) + .isEqualTo(Actors.description, actor.description.description) + .value(Actors.url).isEqualTo(actor.url.toString()) + .value(Actors.inbox).isEqualTo(actor.inbox.toString()) + .value(Actors.outbox).isEqualTo(actor.outbox.toString()) + .isEqualTo(Actors.publicKey, actor.publicKey.publicKey) + .isEqualTo(Actors.privateKey, actor.privateKey?.privateKey) + + assertThat(getTable(ActorsAlsoKnownAs.tableName)) + .row(0) + .isEqualTo(ActorsAlsoKnownAs.actorId, 1) + .isEqualTo(ActorsAlsoKnownAs.alsoKnownAs, 1) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto(ActorsAlsoKnownAs.tableName) { + columns(ActorsAlsoKnownAs.columns) + values(1, 1) + } + }.launch() + + val actor = TestActorFactory.create(1, alsoKnownAs = setOf(ActorId(1))) + + val changes = Changes(dataSource) + changes.withSuspend { + repository.delete(actor) + } + + assertThat(changes) + .changeOfDeletionOnTable(Actors.tableName) + .rowAtStartPoint() + .value(Actors.id.name).isEqualTo(actor.id.id) + .changeOfDeletionOnTable(ActorsAlsoKnownAs.tableName) + .rowAtStartPoint() + .value(ActorsAlsoKnownAs.alsoKnownAs.name) + .isEqualTo(actor.alsoKnownAs.first().id) + } + + @Test + fun findById_指定されたIdがあれば返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + }.launch() + + val expect = TestActorFactory.create( + id = 1, + actorName = "b", + domain = "test-hideout-dev.usbharu.dev", + actorScreenName = "b", + description = "", + inbox = URI.create("https://test-hideout-dev.usbharu.dev/users/b/inbox"), + outbox = URI.create("https://test-hideout-dev.usbharu.dev/users/b/outbox"), + uri = URI.create("https://test-hideout-dev.usbharu.dev/users/b"), + publicKey = ActorPublicKey("-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----"), + privateKey = ActorPrivateKey( + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + ), + createdAt = Timestamp.valueOf("2024-09-09 17:12:03.941339").toInstant(), + keyId = "https://test-hideout-dev.usbharu.dev/users/b#main-key", + followingEndpoint = URI.create("https://test-hideout-dev.usbharu.dev/users/b/following"), + followersEndpoint = URI.create("https://test-hideout-dev.usbharu.dev/users/b/followers"), + instanceId = 1, + locked = false, + followersCount = 0, + followingCount = 0, + postCount = 0, + lastPostDate = null, + lastUpdateAt = Timestamp.valueOf("2024-09-09 17:12:03.941339").toInstant(), + suspend = false, + alsoKnownAs = emptySet(), + moveTo = null, + emojiIds = emptySet(), + deleted = false, + banner = null, + icon = null + ) + + val actual = repository.findById(ActorId(1)) + + assertEquals(actual, expect) + } + + private fun assertEquals( + actual: Actor?, + expect: Actor + ) { + assertNotNull(actual) + kotlin.test.assertEquals(expect, actual) + assertEquals(expect.id, actual.id) + assertEquals(expect.name, actual.name) + assertEquals(expect.domain, actual.domain) + assertEquals(expect.screenName, actual.screenName) + assertEquals(expect.description, actual.description) + assertEquals(expect.inbox, actual.inbox) + assertEquals(expect.outbox, actual.outbox) + assertEquals(expect.url, actual.url) + assertEquals(expect.publicKey, actual.publicKey) + assertEquals(expect.privateKey, actual.privateKey) + assertEquals(expect.createdAt, actual.createdAt) + assertEquals(expect.keyId, actual.keyId) + assertEquals(expect.followingEndpoint, actual.followingEndpoint) + assertEquals(expect.followersEndpoint, actual.followersEndpoint) + assertEquals(expect.postsCount, actual.postsCount) + assertEquals(expect.lastPostAt, actual.lastPostAt) + assertEquals(expect.lastUpdateAt, actual.lastUpdateAt) + assertEquals(expect.suspend, actual.suspend) + assertEquals(expect.moveTo, actual.moveTo) + assertEquals(expect.emojis, actual.emojis) + assertEquals(expect.deleted, actual.deleted) + assertEquals(expect.banner, actual.banner) + assertEquals(expect.icon, actual.icon) + assertEquals(expect.banner, actual.banner) + } + + @Test + fun findById_指定されたIdがなければnull() = runTest { + assertNull(repository.findById(ActorId(1))) + } + + @Test + fun findByNameAndDomain_指定されたNameとDomainがあれば返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + }.launch() + + val expect = TestActorFactory.create( + id = 1, + actorName = "b", + domain = "test-hideout-dev.usbharu.dev", + actorScreenName = "b", + description = "", + inbox = URI.create("https://test-hideout-dev.usbharu.dev/users/b/inbox"), + outbox = URI.create("https://test-hideout-dev.usbharu.dev/users/b/outbox"), + uri = URI.create("https://test-hideout-dev.usbharu.dev/users/b"), + publicKey = ActorPublicKey("-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----"), + privateKey = ActorPrivateKey( + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + ), + createdAt = Timestamp.valueOf("2024-09-09 17:12:03.941339").toInstant(), + keyId = "https://test-hideout-dev.usbharu.dev/users/b#main-key", + followingEndpoint = URI.create("https://test-hideout-dev.usbharu.dev/users/b/following"), + followersEndpoint = URI.create("https://test-hideout-dev.usbharu.dev/users/b/followers"), + instanceId = 1, + locked = false, + followersCount = 0, + followingCount = 0, + postCount = 0, + lastPostDate = null, + lastUpdateAt = Timestamp.valueOf("2024-09-09 17:12:03.941339").toInstant(), + suspend = false, + alsoKnownAs = emptySet(), + moveTo = null, + emojiIds = emptySet(), + deleted = false, + banner = null, + icon = null + ) + + val actual = repository.findByNameAndDomain("b", "test-hideout-dev.usbharu.dev") + + assertEquals(actual, expect) + } + + @Test + fun findByNameAndDomain_指定されたNameとDomainがなければnull() = runTest { + assertNull(repository.findByNameAndDomain("a", "b")) + } + + @Test + fun findAllById_指定されたIdすべて返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + values( + 2, + "a", + "test-hideout-dev.usbharu.dev", + "a", + "", + "https://test-hideout-dev.usbharu.dev/users/a/inbox", + "https://test-hideout-dev.usbharu.dev/users/a/outbox", + "https://test-hideout-dev.usbharu.dev/users/a", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/a#main-key", + "https://test-hideout-dev.usbharu.dev/users/a/following", + "https://test-hideout-dev.usbharu.dev/users/a/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + }.launch() + + val findAllById = repository.findAllById(listOf(ActorId(1), ActorId(2))) + + assertThat(findAllById) + .hasSize(2) + } + + @Test + fun save_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + }.launch() + + val actor = TestActorFactory.create() + actor.checkUpdate() + repository.save(actor) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } + + @Test + fun delete_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto(ActorsAlsoKnownAs.tableName) { + columns(ActorsAlsoKnownAs.columns) + values(1, 1) + } + }.launch() + + val actor = TestActorFactory.create(1, alsoKnownAs = setOf(ActorId(1))) + actor.delete() + + repository.delete(actor) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImplTest.kt index bb253ef6..cf24d329 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImplTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImplTest.kt @@ -59,7 +59,7 @@ class UserDetailsServiceImplTest { fun userDetailが見つからない場合失敗() = runTest { whenever(actorRepository.findByNameAndDomain(eq("test"), eq("example.com"))).doReturn( TestActorFactory.create( - actorName = "test", id = 1 + id = 1, actorName = "test" ) ) assertThrows { From 88ab8d23dffe0d2992ec3982edeb6b996ff41f17 Mon Sep 17 00:00:00 2001 From: usbharu Date: Wed, 11 Sep 2024 06:58:58 +0000 Subject: [PATCH 21/40] style: fix lint (CI) --- .../hideout/core/domain/model/actor/Actor.kt | 60 +++++++++---------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt index 77361e77..5823b111 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt @@ -160,36 +160,34 @@ class Actor( override fun toString(): String { return "Actor(" + - "id=$id, " + - "name=$name, " + - "domain=$domain, " + - "inbox=$inbox, " + - "outbox=$outbox, " + - "url=$url, " + - "publicKey=$publicKey, " + - "privateKey=$privateKey, " + - "createdAt=$createdAt, " + - "keyId=$keyId, " + - "followersEndpoint=$followersEndpoint, " + - "followingEndpoint=$followingEndpoint, " + - "instance=$instance, " + - "locked=$locked, " + - "followersCount=$followersCount, " + - "followingCount=$followingCount, " + - "postsCount=$postsCount, " + - "lastPostAt=$lastPostAt, " + - "lastUpdateAt=$lastUpdateAt, " + - "banner=$banner, " + - "icon=$icon, " + - "suspend=$suspend, " + - "alsoKnownAs=$alsoKnownAs, " + - "moveTo=$moveTo, " + - "emojis=$emojis, " + - "description=$description, " + - "screenName=$screenName, " + - "deleted=$deleted" + - ")" + "id=$id, " + + "name=$name, " + + "domain=$domain, " + + "inbox=$inbox, " + + "outbox=$outbox, " + + "url=$url, " + + "publicKey=$publicKey, " + + "privateKey=$privateKey, " + + "createdAt=$createdAt, " + + "keyId=$keyId, " + + "followersEndpoint=$followersEndpoint, " + + "followingEndpoint=$followingEndpoint, " + + "instance=$instance, " + + "locked=$locked, " + + "followersCount=$followersCount, " + + "followingCount=$followingCount, " + + "postsCount=$postsCount, " + + "lastPostAt=$lastPostAt, " + + "lastUpdateAt=$lastUpdateAt, " + + "banner=$banner, " + + "icon=$icon, " + + "suspend=$suspend, " + + "alsoKnownAs=$alsoKnownAs, " + + "moveTo=$moveTo, " + + "emojis=$emojis, " + + "description=$description, " + + "screenName=$screenName, " + + "deleted=$deleted" + + ")" } - - } From 554ce68c93456e0a0d2911e04daf66bdd4781086 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:12:36 +0900 Subject: [PATCH 22/40] =?UTF-8?q?refactor:=20ExposedActorRepository.kt?= =?UTF-8?q?=E3=81=ABuri=E5=9E=8B=E3=82=92=E5=B0=8E=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ExposedActorRepository.kt | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt index 717fdd7a..821d4f73 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedActorRepository.kt @@ -5,6 +5,7 @@ import dev.usbharu.hideout.core.domain.model.support.domain.Domain import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher import dev.usbharu.hideout.core.domain.shared.repository.DomainEventPublishableRepository import dev.usbharu.hideout.core.infrastructure.exposed.QueryMapper +import dev.usbharu.hideout.core.infrastructure.exposed.uri import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.javatime.timestamp @@ -30,15 +31,15 @@ class ExposedActorRepository( it[domain] = actor.domain.domain it[screenName] = actor.screenName.screenName it[description] = actor.description.description - it[inbox] = actor.inbox.toString() - it[outbox] = actor.outbox.toString() - it[url] = actor.url.toString() + it[inbox] = actor.inbox + it[outbox] = actor.outbox + it[url] = actor.url it[publicKey] = actor.publicKey.publicKey it[privateKey] = actor.privateKey?.privateKey it[createdAt] = actor.createdAt it[keyId] = actor.keyId.keyId - it[following] = actor.followingEndpoint?.toString() - it[followers] = actor.followersEndpoint?.toString() + it[following] = actor.followingEndpoint + it[followers] = actor.followersEndpoint it[instance] = actor.instance.instanceId it[locked] = actor.locked it[followingCount] = actor.followingCount?.relationshipCount @@ -126,15 +127,15 @@ object Actors : Table("actors") { val domain = varchar("domain", Domain.LENGTH) val screenName = varchar("screen_name", ActorScreenName.LENGTH) val description = varchar("description", ActorDescription.LENGTH) - val inbox = varchar("inbox", 1000).uniqueIndex() - val outbox = varchar("outbox", 1000).uniqueIndex() - val url = varchar("url", 1000).uniqueIndex() + val inbox = uri("inbox", 1000).uniqueIndex() + val outbox = uri("outbox", 1000).uniqueIndex() + val url = uri("url", 1000).uniqueIndex() val publicKey = varchar("public_key", 10000) val privateKey = varchar("private_key", 100000).nullable() val createdAt = timestamp("created_at") val keyId = varchar("key_id", 1000) - val following = varchar("following", 1000).nullable() - val followers = varchar("followers", 1000).nullable() + val following = uri("following", 1000).nullable() + val followers = uri("followers", 1000).nullable() val instance = long("instance").references(Instance.id) val locked = bool("locked") val followingCount = integer("following_count").nullable() From 404ca6c531c92717ffacada42e226ebc89ca4d4c Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 16:15:53 +0900 Subject: [PATCH 23/40] =?UTF-8?q?refactor:=20ExposedActorRepository.kt?= =?UTF-8?q?=E3=81=ABuri=E5=9E=8B=E3=82=92=E5=B0=8E=E5=85=A52?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastructure/exposed/ActorResultRowMapper.kt | 11 +++++------ .../exposedquery/ExposedUserTimelineQueryService.kt | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorResultRowMapper.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorResultRowMapper.kt index c552c541..d4daa3d4 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorResultRowMapper.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/ActorResultRowMapper.kt @@ -24,7 +24,6 @@ import dev.usbharu.hideout.core.domain.model.support.domain.Domain import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors import org.jetbrains.exposed.sql.ResultRow import org.springframework.stereotype.Component -import java.net.URI @Component class ActorResultRowMapper : ResultRowMapper { @@ -35,15 +34,15 @@ class ActorResultRowMapper : ResultRowMapper { domain = Domain(resultRow[Actors.domain]), screenName = ActorScreenName(resultRow[Actors.screenName]), description = ActorDescription(resultRow[Actors.description]), - inbox = URI.create(resultRow[Actors.inbox]), - outbox = URI.create(resultRow[Actors.outbox]), - url = URI.create(resultRow[Actors.url]), + inbox = resultRow[Actors.inbox], + outbox = resultRow[Actors.outbox], + url = resultRow[Actors.url], publicKey = ActorPublicKey(resultRow[Actors.publicKey]), privateKey = resultRow[Actors.privateKey]?.let { ActorPrivateKey(it) }, createdAt = resultRow[Actors.createdAt], keyId = ActorKeyId(resultRow[Actors.keyId]), - followersEndpoint = resultRow[Actors.followers]?.let { URI.create(it) }, - followingEndpoint = resultRow[Actors.following]?.let { URI.create(it) }, + followersEndpoint = resultRow[Actors.followers], + followingEndpoint = resultRow[Actors.following], instance = InstanceId(resultRow[Actors.instance]), locked = resultRow[Actors.locked], followersCount = resultRow[Actors.followersCount]?.let { ActorRelationshipCount(it) }, diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/ExposedUserTimelineQueryService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/ExposedUserTimelineQueryService.kt index f24d6ff3..f63a2e53 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/ExposedUserTimelineQueryService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedquery/ExposedUserTimelineQueryService.kt @@ -90,7 +90,7 @@ class ExposedUserTimelineQueryService : UserTimelineQueryService, AbstractReposi name = it[Actors.name], domain = it[Actors.domain], screenName = it[Actors.screenName], - url = URI.create(it[Actors.url]), + url = it[Actors.url], locked = it[Actors.locked], icon = it.getOrNull(iconMedia[Media.url]) ), From 85d36e5aa2df6f7d20643f09f5a67259942e6c44 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Wed, 11 Sep 2024 18:08:46 +0900 Subject: [PATCH 24/40] =?UTF-8?q?refactor:=20ExposedActorRepository.kt?= =?UTF-8?q?=E3=81=ABuri=E5=9E=8B=E3=82=92=E5=B0=8E=E5=85=A52?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exposedquery/ExposedAccountQueryServiceImpl.kt | 2 +- .../exposedquery/ExposedStatusQueryService.kt | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/ExposedAccountQueryServiceImpl.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/ExposedAccountQueryServiceImpl.kt index 4645c3af..51589189 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/ExposedAccountQueryServiceImpl.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/ExposedAccountQueryServiceImpl.kt @@ -50,7 +50,7 @@ class ExposedAccountQueryServiceImpl(private val applicationConfig: ApplicationC id = resultRow[Actors.id].toString(), username = resultRow[Actors.name], acct = "${resultRow[Actors.name]}@${resultRow[Actors.domain]}", - url = resultRow[Actors.url], + url = resultRow[Actors.url].toString(), displayName = resultRow[Actors.screenName], note = resultRow[Actors.description], avatar = "$userUrl/icon.jpg", diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/ExposedStatusQueryService.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/ExposedStatusQueryService.kt index d80009f1..93101819 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/ExposedStatusQueryService.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/ExposedStatusQueryService.kt @@ -225,13 +225,13 @@ private fun toStatus(it: ResultRow, queryAlias: QueryAlias, inReplyToAlias: Alia id = it[Actors.id].toString(), username = it[Actors.name], acct = "${it[Actors.name]}@${it[Actors.domain]}", - url = it[Actors.url], + url = it[Actors.url].toString(), displayName = it[Actors.screenName], note = it[Actors.description], - avatar = it[Actors.url] + "/icon.jpg", - avatarStatic = it[Actors.url] + "/icon.jpg", - header = it[Actors.url] + "/header.jpg", - headerStatic = it[Actors.url] + "/header.jpg", + avatar = "${it[Actors.url]}/icon.jpg", + avatarStatic = "${it[Actors.url]}/icon.jpg", + header = "${it[Actors.url]}/header.jpg", + headerStatic = "${it[Actors.url]}/header.jpg", locked = it[Actors.locked], fields = emptyList(), emojis = emptyList(), From d4fd61d31dfed00d1c5615c99a193e2009e17d12 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:00:04 +0900 Subject: [PATCH 25/40] =?UTF-8?q?test:=20ExposedTimelineRepository?= =?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 --- .../ExposedTimelineRepository.kt | 2 +- .../ExposedTimelineRepositoryTest.kt | 90 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepository.kt index 9fe9f694..8f5f8c65 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepository.kt @@ -54,7 +54,7 @@ class ExposedTimelineRepository(override val domainEventPublisher: DomainEventPu override suspend fun findById(id: TimelineId): Timeline? { return query { - Timelines.selectAll().where { Timelines.id eq id.value }.firstOrNull()?.toTimeline() + Timelines.selectAll().where { Timelines.id eq id.value }.limit(1).firstOrNull()?.toTimeline() } } diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt new file mode 100644 index 00000000..f80bc992 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt @@ -0,0 +1,90 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.timeline.Timeline +import dev.usbharu.hideout.core.domain.model.timeline.TimelineId +import dev.usbharu.hideout.core.domain.model.timeline.TimelineName +import dev.usbharu.hideout.core.domain.model.timeline.TimelineVisibility +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId +import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import utils.AbstractRepositoryTest +import utils.columns +import utils.disableReferenceIntegrityConstraints +import utils.isEqualTo + +@ExtendWith(MockitoExtension::class) +class ExposedTimelineRepositoryTest : AbstractRepositoryTest(Timelines) { + @InjectMocks + lateinit var repository: ExposedTimelineRepository + + @Mock + lateinit var domainEventPublisher: DomainEventPublisher + + @Test + fun save_idが同じレコードが存在しない場合insert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 1, "veeeeeeeeeeeeeeryStrongPassword", true, null, null) + } + }.launch() + val timeline = Timeline( + id = TimelineId(1), + userDetailId = UserDetailId(1), + name = TimelineName("timeline"), + visibility = TimelineVisibility.PUBLIC, + isSystem = false + ) + + repository.save(timeline) + + assertThat(assertTable) + .row(0) + .isEqualTo(Timelines.id, timeline.id.value) + .isEqualTo(Timelines.userDetailId, timeline.userDetailId.id) + .isEqualTo(Timelines.name, timeline.name.value) + .isEqualTo(Timelines.visibility, timeline.visibility.name) + .isEqualTo(Timelines.isSystem, timeline.isSystem) + } + + @Test + fun save_idが同じレコードが存在する場合update() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 1, "veeeeeeeeeeeeeeryStrongPassword", true, null, null) + } + insertInto(Timelines.tableName) { + columns(Timelines.columns) + values(1, 1, "test-timeline", "PUBLIC", true) + } + + }.launch() + val timeline = Timeline( + id = TimelineId(1), + userDetailId = UserDetailId(1), + name = TimelineName("timeline"), + visibility = TimelineVisibility.PRIVATE, + isSystem = false + ) + + repository.save(timeline) + + assertThat(assertTable) + .row(0) + .isEqualTo(Timelines.id, timeline.id.value) + .isEqualTo(Timelines.userDetailId, timeline.userDetailId.id) + .isEqualTo(Timelines.name, timeline.name.value) + .isEqualTo(Timelines.visibility, timeline.visibility.name) + .isEqualTo(Timelines.isSystem, timeline.isSystem) + } +} From 24e97abf3f786d3feec7873e42060d5cc1384e92 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Fri, 13 Sep 2024 14:41:19 +0900 Subject: [PATCH 26/40] =?UTF-8?q?test:=20ExposedTimelineRepository?= =?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 --- .../core/domain/model/timeline/Timeline.kt | 14 +++ .../ExposedTimelineRepositoryTest.kt | 110 +++++++++++++++++- 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt index 9b713d8f..d253d275 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt @@ -26,6 +26,20 @@ class Timeline( addDomainEvent(TimelineEventFactory(this).createEvent(TimelineEvent.CHANGE_VISIBILITY)) } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as Timeline + + return id == other.id + } + + override fun hashCode(): Int { + return id.hashCode() + } + + companion object { fun create( id: TimelineId, diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt index f80bc992..2802bc3d 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt @@ -8,16 +8,17 @@ import dev.usbharu.hideout.core.domain.model.timeline.TimelineVisibility import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat import org.assertj.db.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.InjectMocks import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension -import utils.AbstractRepositoryTest -import utils.columns -import utils.disableReferenceIntegrityConstraints -import utils.isEqualTo +import utils.* +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull @ExtendWith(MockitoExtension::class) class ExposedTimelineRepositoryTest : AbstractRepositoryTest(Timelines) { @@ -87,4 +88,105 @@ class ExposedTimelineRepositoryTest : AbstractRepositoryTest(Timelines) { .isEqualTo(Timelines.visibility, timeline.visibility.name) .isEqualTo(Timelines.isSystem, timeline.isSystem) } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 1, "veeeeeeeeeeeeeeryStrongPassword", true, null, null) + } + insertInto(Timelines.tableName) { + columns(Timelines.columns) + values(1, 1, "test-timeline", "PUBLIC", true) + } + + }.launch() + val timeline = Timeline( + id = TimelineId(1), + userDetailId = UserDetailId(1), + name = TimelineName("timeline"), + visibility = TimelineVisibility.PRIVATE, + isSystem = false + ) + + change.withSuspend { + repository.delete(timeline) + } + + assertThat(change) + .changeOfDeletionOnTable(Timelines.tableName) + .rowAtStartPoint() + .value(Timelines.id.name).isEqualTo(timeline.id.value) + } + + @Test + fun findByIds_指定されたIdすべて返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Timelines.tableName) { + columns(Timelines.columns) + values(1, 1, "test-timeline", "PUBLIC", true) + values(2, 1, "test-timeline2", "PUBLIC", true) + values(3, 1, "test-timeline3", "PUBLIC", true) + } + }.launch() + + val findByIds = repository.findByIds(listOf(TimelineId(1), TimelineId(3))) + + assertThat(findByIds) + .hasSize(2) + } + + @Test + fun findById_指定されたIdが存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Timelines.tableName) { + columns(Timelines.columns) + values(1, 1, "test-timeline", "PUBLIC", true) + values(2, 1, "test-timeline2", "PUBLIC", true) + values(3, 1, "test-timeline3", "PUBLIC", true) + } + }.launch() + + val actual = repository.findById(TimelineId(1)) + + val expected = Timeline( + TimelineId(1), UserDetailId(1), TimelineName("test-timeline"), TimelineVisibility.PUBLIC, true + ) + + assertEquals(expected, actual) + assertNotNull(actual) + assertEquals(expected.id, actual.id) + assertEquals(expected.userDetailId, actual.userDetailId) + assertEquals(expected.name, actual.name) + assertEquals(expected.visibility, actual.visibility) + assertEquals(expected.isSystem, actual.isSystem) + } + + @Test + fun findById_指定されたIdがなければnull() = runTest { + assertNull(repository.findById(TimelineId(1))) + } + + @Test + fun findAllByUserDetailIdANdVisibilityIn_指定されたVisibilityで指定されたUserDetailId全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Timelines.tableName) { + columns(Timelines.columns) + values(1, 1, "test-timeline", "PUBLIC", true) + values(2, 1, "test-timeline2", "PRIVATE", true) + values(3, 1, "test-timeline3", "PUBLIC", true) + } + }.launch() + + val timelines = + repository.findAllByUserDetailIdAndVisibilityIn(UserDetailId(1), listOf(TimelineVisibility.PUBLIC)) + + assertThat(timelines) + .hasSize(2) + } } From 74aa1302d48738349e478ae633c729d0c9fa3dfd Mon Sep 17 00:00:00 2001 From: usbharu Date: Fri, 13 Sep 2024 05:44:39 +0000 Subject: [PATCH 27/40] style: fix lint (CI) --- .../dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt index d253d275..73817d2e 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt @@ -39,7 +39,6 @@ class Timeline( return id.hashCode() } - companion object { fun create( id: TimelineId, From 67208e58992479346c7307b45a12ff8d3d6e4b89 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:30:36 +0900 Subject: [PATCH 28/40] =?UTF-8?q?test:=20ExposedReactionRepository?= =?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 --- .../ExposedReactionRepositoryTest.kt | 440 ++++++++++++++++++ 1 file changed, 440 insertions(+) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedReactionRepositoryTest.kt diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedReactionRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedReactionRepositoryTest.kt new file mode 100644 index 00000000..40dd62ed --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedReactionRepositoryTest.kt @@ -0,0 +1,440 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId +import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji +import dev.usbharu.hideout.core.domain.model.post.PostId +import dev.usbharu.hideout.core.domain.model.reaction.Reaction +import dev.usbharu.hideout.core.domain.model.reaction.ReactionId +import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.assertj.db.api.Assertions.assertThat +import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import utils.* +import java.sql.Timestamp +import java.time.Instant +import kotlin.test.* + +@ExtendWith(MockitoExtension::class) +class ExposedReactionRepositoryTest : AbstractRepositoryTest(Reactions) { + + @InjectMocks + lateinit var repository: ExposedReactionRepository + + @Mock + lateinit var domainEventPublisher: DomainEventPublisher + + + @Test + fun save_idが同じレコードがなければinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Posts.tableName) { + columns(Posts.columns) + values( + 1, + 1, + 1, + null, + "test", + "test", + Timestamp.from(Instant.parse("2021-01-01T00:00:00Z")), + "PUBLIC", + "https://example.com", + null, + null, + false, + "https://example.com", + false, + false, + null + ) + } + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values(1, "emoji", "example.com", 1, "https://example.com", null, Timestamp.from(Instant.now())) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val create = Reaction.create( + id = ReactionId(1), + postId = PostId(1), + actorId = ActorId(1), + customEmojiId = CustomEmojiId(1), + unicodeEmoji = UnicodeEmoji("❤"), + createdAt = Instant.parse("2021-01-01T00:00:00Z") + ) + + repository.save(create) + + assertThat(assertTable) + .row(0) + .isEqualTo(Reactions.id, create.id.value) + .isEqualTo(Reactions.postId, create.postId.id) + .isEqualTo(Reactions.actorId, create.actorId.id) + .isEqualTo(Reactions.customEmojiId, create.customEmojiId?.emojiId) + .isEqualTo(Reactions.unicodeEmoji, create.unicodeEmoji.name) + .value(Reactions.createdAt).isEqualTo(Timestamp.from(create.createdAt)) + } + + @Test + fun save_idが同じレコードが存在したらupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Posts.tableName) { + columns(Posts.columns) + values( + 1, + 1, + 1, + null, + "test", + "test", + Timestamp.from(Instant.parse("2021-01-01T00:00:00Z")), + "PUBLIC", + "https://example.com", + null, + null, + false, + "https://example.com", + false, + false, + null + ) + } + insertInto("public.actors") { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values(1, "emoji", "example.com", 1, "https://example.com", null, Timestamp.from(Instant.now())) + } + insertInto(Reactions.tableName) { + columns(Reactions.columns) + values(1, 1, 1, 2, "☠️", Timestamp.from(Instant.now())) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val create = Reaction.create( + id = ReactionId(1), + postId = PostId(1), + actorId = ActorId(1), + customEmojiId = CustomEmojiId(1), + unicodeEmoji = UnicodeEmoji("❤"), + createdAt = Instant.parse("2021-01-01T00:00:00Z") + ) + + repository.save(create) + + assertThat(assertTable) + .row(0) + .isEqualTo(Reactions.id, create.id.value) + .isEqualTo(Reactions.postId, create.postId.id) + .isEqualTo(Reactions.actorId, create.actorId.id) + .isEqualTo(Reactions.customEmojiId, create.customEmojiId?.emojiId) + .isEqualTo(Reactions.unicodeEmoji, create.unicodeEmoji.name) + .value(Reactions.createdAt).isEqualTo(Timestamp.from(create.createdAt)) + } + + @Test + fun findById_指定されたIdが存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Reactions.tableName) { + columns(Reactions.columns) + values(1, 1, 1, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + } + }.launch() + + val expected = Reaction.create( + id = ReactionId(1), + postId = PostId(1), + actorId = ActorId(1), + customEmojiId = CustomEmojiId(1), + unicodeEmoji = UnicodeEmoji("❤"), + createdAt = Instant.parse("2021-01-01T00:00:00Z") + ) + + val actual = repository.findById(ReactionId(1)) + + assertEquals(expected, actual) + + } + + private fun assertEquals( + expected: Reaction, + actual: Reaction? + ) { + kotlin.test.assertEquals(expected, actual) + assertNotNull(actual) + assertEquals(expected.id, actual.id) + assertEquals(expected.postId, actual.postId) + assertEquals(expected.actorId, actual.actorId) + assertEquals(expected.customEmojiId, actual.customEmojiId) + assertEquals(expected.unicodeEmoji, actual.unicodeEmoji) + assertEquals(expected.createdAt, actual.createdAt) + } + + @Test + fun findById_指定されたIdがなければnull() = runTest { + assertNull(repository.findById(ReactionId(1))) + } + + @Test + fun findByPostId_指定されたId全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Reactions.tableName) { + columns(Reactions.columns) + values(1, 1, 1, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(2, 3, 2, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(3, 1, 3, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + } + }.launch() + + val actual = repository.findByPostId(PostId(1)) + + assertThat(actual) + .hasSize(2) + } + + @Test + fun existsByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji_指定された条件で存在したらtrue() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Reactions.tableName) { + columns(Reactions.columns) + values(1, 1, 1, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(2, 3, 2, null, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(3, 1, 3, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + } + }.launch() + + val actual1 = repository.existsByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji( + PostId(1), + ActorId(1), CustomEmojiId + (1), "❤" + ) + val actual2 = repository.existsByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji( + PostId(3), + ActorId(2), null, "❤" + ) + + assertTrue(actual1) + assertTrue(actual2) + } + + @Test + fun existsByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji_指定された条件で存在しないとfalse() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Reactions.tableName) { + columns(Reactions.columns) + values(1, 1, 1, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(2, 3, 2, null, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(3, 1, 3, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + } + }.launch() + + val actual1 = repository.existsByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji( + PostId(3), + ActorId(1), CustomEmojiId + (1), "❤" + ) + val actual2 = repository.existsByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji( + PostId(2), + ActorId(2), null, "❤" + ) + + assertFalse(actual1) + assertFalse(actual2) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Reactions.tableName) { + columns(Reactions.columns) + values(1, 1, 1, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(2, 3, 2, null, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(3, 1, 3, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + } + }.launch() + + val reaction = Reaction( + ReactionId(1), + PostId(1), + ActorId(1), + CustomEmojiId(1), + UnicodeEmoji("❤"), + Instant.parse("2021-01-01T00:00:00Z") + ) + + repository.delete(reaction) + } + + @Test + fun findByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji_指定された条件で存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Reactions.tableName) { + columns(Reactions.columns) + values(1, 1, 1, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(2, 3, 2, null, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(3, 1, 3, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + } + }.launch() + + val expected = Reaction( + ReactionId(1), + PostId(1), + ActorId(1), + CustomEmojiId(1), + UnicodeEmoji("❤"), + Instant.parse("2021-01-01T00:00:00Z") + ) + + val actual = + repository.findByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji( + PostId(1), + ActorId(1), CustomEmojiId + (1), "❤" + ) + + assertEquals(expected, actual) + } + + @Test + fun findByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji_指定された条件で存在しないとnull() = runTest { + assertNull( + repository.findByPostIdAndActorIdAndCustomEmojiIdOrUnicodeEmoji( + PostId(1), + ActorId(1), CustomEmojiId + (1), "❤" + ) + ) + } + + @Test + fun save_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + }.launch() + repository.save( + Reaction.create( + ReactionId(1), + PostId(1), ActorId + (1), CustomEmojiId + (1), UnicodeEmoji("❤"), Instant.now + () + ) + ) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } + + @Test + fun delete_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Reactions.tableName) { + columns(Reactions.columns) + values(1, 1, 1, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(2, 3, 2, null, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + values(3, 1, 3, 1, "❤", Timestamp.from(Instant.parse("2021-01-01T00:00:00Z"))) + } + }.launch() + + val reaction = Reaction( + ReactionId(1), + PostId(1), ActorId + (1), CustomEmojiId + (1), UnicodeEmoji("❤"), Instant.now + () + ) + reaction.delete() + repository.delete( + reaction + ) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } +} \ No newline at end of file From e43e1575cf8a3f40bff4974f8220c5a09983ce87 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:33:17 +0900 Subject: [PATCH 29/40] style: fix lint --- .../dev/usbharu/hideout/core/domain/model/actor/Actor.kt | 4 +--- .../hideout/core/domain/model/actor/ActorDescription.kt | 4 +--- .../hideout/core/domain/model/actor/ActorScreenName.kt | 4 +--- .../usbharu/hideout/core/domain/model/timeline/Timeline.kt | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt index 5823b111..684c3474 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt @@ -154,9 +154,7 @@ class Actor( return id == other.id } - override fun hashCode(): Int { - return id.hashCode() - } + override fun hashCode(): Int = id.hashCode() override fun toString(): String { return "Actor(" + diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorDescription.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorDescription.kt index 78ef02a6..55cb6dc7 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorDescription.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorDescription.kt @@ -28,9 +28,7 @@ class ActorDescription(description: String) { return description == other.description } - override fun hashCode(): Int { - return description.hashCode() - } + override fun hashCode(): Int = description.hashCode() companion object { const val LENGTH = 10000 diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorScreenName.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorScreenName.kt index 29e13f03..4c594d73 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorScreenName.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorScreenName.kt @@ -29,9 +29,7 @@ class ActorScreenName(screenName: String) { return screenName == other.screenName } - override fun hashCode(): Int { - return screenName.hashCode() - } + override fun hashCode(): Int = screenName.hashCode() companion object { const val LENGTH = 300 diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt index 73817d2e..ca513707 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/Timeline.kt @@ -35,9 +35,7 @@ class Timeline( return id == other.id } - override fun hashCode(): Int { - return id.hashCode() - } + override fun hashCode(): Int = id.hashCode() companion object { fun create( From 900ed51d09fcbfaf0dcc04aebbb60396f042240a Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 14 Sep 2024 11:45:59 +0900 Subject: [PATCH 30/40] =?UTF-8?q?refactor:=20Repository=E5=AE=9F=E8=A3=85?= =?UTF-8?q?=E3=81=AE=E3=82=AF=E3=83=A9=E3=82=B9=E5=90=8D=E3=82=92=E7=B5=B1?= =?UTF-8?q?=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ryImpl.kt => ExposedCustomEmojiRepository.kt} | 4 ++-- ...itoryImpl.kt => ExposedInstanceRepository.kt} | 4 ++-- ...oryImpl.kt => ExposedUserDetailRepository.kt} | 4 ++-- ...lTest.kt => ExposedInstanceRepositoryTest.kt} | 16 ++++++++-------- ...est.kt => ExposedUserDetailRepositoryTest.kt} | 4 ++-- .../test/kotlin/utils/AbstractRepositoryTest.kt | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/{CustomEmojiRepositoryImpl.kt => ExposedCustomEmojiRepository.kt} (96%) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/{InstanceRepositoryImpl.kt => ExposedInstanceRepository.kt} (96%) rename hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/{UserDetailRepositoryImpl.kt => ExposedUserDetailRepository.kt} (95%) rename hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/{InstanceRepositoryImplTest.kt => ExposedInstanceRepositoryTest.kt} (94%) rename hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/{UserDetailRepositoryImplTest.kt => ExposedUserDetailRepositoryTest.kt} (99%) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/CustomEmojiRepositoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt similarity index 96% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/CustomEmojiRepositoryImpl.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt index e3ca9079..d96f7a0c 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/CustomEmojiRepositoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt @@ -31,7 +31,7 @@ import org.springframework.stereotype.Repository import java.net.URI @Repository -class CustomEmojiRepositoryImpl : CustomEmojiRepository, +class ExposedCustomEmojiRepository : CustomEmojiRepository, AbstractRepository() { override val logger: Logger get() = Companion.logger @@ -76,7 +76,7 @@ class CustomEmojiRepositoryImpl : CustomEmojiRepository, } companion object { - private val logger = LoggerFactory.getLogger(CustomEmojiRepositoryImpl::class.java) + private val logger = LoggerFactory.getLogger(ExposedCustomEmojiRepository::class.java) } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedInstanceRepository.kt similarity index 96% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedInstanceRepository.kt index 09c2b9be..1f4e35f4 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedInstanceRepository.kt @@ -28,7 +28,7 @@ import java.net.URI import dev.usbharu.hideout.core.domain.model.instance.Instance as InstanceEntity @Repository -class InstanceRepositoryImpl : InstanceRepository, +class ExposedInstanceRepository : InstanceRepository, AbstractRepository() { override val logger: Logger get() = Companion.logger @@ -66,7 +66,7 @@ class InstanceRepositoryImpl : InstanceRepository, } companion object { - private val logger = LoggerFactory.getLogger(InstanceRepositoryImpl::class.java) + private val logger = LoggerFactory.getLogger(ExposedInstanceRepository::class.java) } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedUserDetailRepository.kt similarity index 95% rename from hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImpl.kt rename to hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedUserDetailRepository.kt index 2f4a22df..cacaa922 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedUserDetailRepository.kt @@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory import org.springframework.stereotype.Repository @Repository -class UserDetailRepositoryImpl(override val domainEventPublisher: DomainEventPublisher) : +class ExposedUserDetailRepository(override val domainEventPublisher: DomainEventPublisher) : UserDetailRepository, AbstractRepository(), DomainEventPublishableRepository { @@ -105,7 +105,7 @@ class UserDetailRepositoryImpl(override val domainEventPublisher: DomainEventPub ) companion object { - private val logger = LoggerFactory.getLogger(UserDetailRepositoryImpl::class.java) + private val logger = LoggerFactory.getLogger(ExposedUserDetailRepository::class.java) } } diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedInstanceRepositoryTest.kt similarity index 94% rename from hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt rename to hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedInstanceRepositoryTest.kt index 6bcb52fb..1b6c47b5 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/InstanceRepositoryImplTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedInstanceRepositoryTest.kt @@ -20,12 +20,12 @@ import kotlin.test.assertNull import dev.usbharu.hideout.core.infrastructure.exposedrepository.Instance as InstanceTable @TestInstance(TestInstance.Lifecycle.PER_CLASS) -class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { +class ExposedInstanceRepositoryTest : AbstractRepositoryTest(InstanceTable) { @Test fun save_idが同じレコードがない場合はinsertされる() = runTest { - InstanceRepositoryImpl().save( + ExposedInstanceRepository().save( Instance( id = InstanceId(1), name = InstanceName("test"), @@ -78,7 +78,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { }.launch() - InstanceRepositoryImpl().save( + ExposedInstanceRepository().save( Instance( id = InstanceId(1), name = InstanceName("test"), @@ -130,7 +130,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { } }.launch() - val actual = InstanceRepositoryImpl().findById(InstanceId(1)) + val actual = ExposedInstanceRepository().findById(InstanceId(1)) val expected = Instance( id = InstanceId(1), name = InstanceName("test"), @@ -151,7 +151,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { @Test fun findById_指定したIDで存在しないとnull() = runTest { - assertNull(InstanceRepositoryImpl().findById(InstanceId(1))) + assertNull(ExposedInstanceRepository().findById(InstanceId(1))) } @Test @@ -178,7 +178,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { } }.launch() - val actual = InstanceRepositoryImpl().findByUrl(URI.create("https://www.example.com")) + val actual = ExposedInstanceRepository().findByUrl(URI.create("https://www.example.com")) val expected = Instance( id = InstanceId(1), name = InstanceName("test"), @@ -199,7 +199,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { @Test fun findByUrl_指定したURLで存在しないとnull() = runTest { - assertNull(InstanceRepositoryImpl().findByUrl(URI.create("https://www.example.com"))) + assertNull(ExposedInstanceRepository().findByUrl(URI.create("https://www.example.com"))) } @Test @@ -243,7 +243,7 @@ class InstanceRepositoryImplTest : AbstractRepositoryTest(InstanceTable) { change.setStartPointNow() - InstanceRepositoryImpl().delete(instance) + ExposedInstanceRepository().delete(instance) change.setEndPointNow() diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedUserDetailRepositoryTest.kt similarity index 99% rename from hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt rename to hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedUserDetailRepositoryTest.kt index 35bf81a5..532cbda6 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/UserDetailRepositoryImplTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedUserDetailRepositoryTest.kt @@ -25,10 +25,10 @@ import kotlin.test.assertNotNull import kotlin.test.assertNull @ExtendWith(MockitoExtension::class) -class UserDetailRepositoryImplTest : AbstractRepositoryTest(UserDetails) { +class ExposedUserDetailRepositoryTest : AbstractRepositoryTest(UserDetails) { @InjectMocks - lateinit var userDetailRepository: UserDetailRepositoryImpl + lateinit var userDetailRepository: ExposedUserDetailRepository @Mock lateinit var domainEventPublisher: DomainEventPublisher diff --git a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt index 569cfa60..4499081a 100644 --- a/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/utils/AbstractRepositoryTest.kt @@ -49,7 +49,7 @@ abstract class AbstractRepositoryTest(private val exposedTable: org.jetbrains.ex fun tearDown() { dbSetup(to = dataSource) { execute(Operations.sql("SET REFERENTIAL_INTEGRITY TRUE")) - } + }.launch() transaction.rollback() transaction.close() } From 1503ee1844af01fc4350851a3b9b2c16e5701d88 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:56:24 +0900 Subject: [PATCH 31/40] =?UTF-8?q?refactor:=20=E4=BD=BF=E7=94=A8=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=81=A6=E3=81=AA=E3=81=84=E9=96=A2=E6=95=B0=E3=82=92?= =?UTF-8?q?=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../relationship/RelationshipRepository.kt | 12 ------ .../ExposedRelationshipRepository.kt | 41 ++----------------- 2 files changed, 3 insertions(+), 50 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/RelationshipRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/RelationshipRepository.kt index ca6cebcd..3110d9d0 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/RelationshipRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/RelationshipRepository.kt @@ -35,17 +35,5 @@ interface RelationshipRepository { following: Boolean ): List - suspend fun findByTargetId( - targetId: ActorId, - option: FindRelationshipOption? = null, - inverseOption: FindRelationshipOption? = null - ): List } -data class FindRelationshipOption( - val follow: Boolean? = null, - val block: Boolean? = null, - val mute: Boolean? = null, - val followRequest: Boolean? = null, - val muteFollowRequest: Boolean? = null -) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt index 73675308..2cdc4c8c 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt @@ -17,7 +17,6 @@ package dev.usbharu.hideout.core.infrastructure.exposedrepository import dev.usbharu.hideout.core.domain.model.actor.ActorId -import dev.usbharu.hideout.core.domain.model.relationship.FindRelationshipOption import dev.usbharu.hideout.core.domain.model.relationship.Relationship import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher @@ -69,7 +68,7 @@ class ExposedRelationshipRepository(override val domainEventPublisher: DomainEve override suspend fun findByActorIdAndTargetId(actorId: ActorId, targetId: ActorId): Relationship? = query { Relationships.selectAll().where { Relationships.actorId eq actorId.id and (Relationships.targetActorId eq targetId.id) - }.singleOrNull()?.toRelationships() + }.limit(1).singleOrNull()?.toRelationships() } override suspend fun findByActorIdsAndTargetIdAndBlocking( @@ -78,7 +77,7 @@ class ExposedRelationshipRepository(override val domainEventPublisher: DomainEve blocking: Boolean ): List = query { Relationships.selectAll().where { - Relationships.actorId inList actorIds.map { it.id } and (Relationships.targetActorId eq targetId.id) + Relationships.actorId inList actorIds.map { it.id } and (Relationships.targetActorId eq targetId.id) and (Relationships.blocking eq blocking) }.map { it.toRelationships() } } @@ -88,49 +87,15 @@ class ExposedRelationshipRepository(override val domainEventPublisher: DomainEve following: Boolean ): List = query { Relationships.selectAll().where { - Relationships.actorId eq actorId.id and (Relationships.targetActorId inList targetIds.map { it.id }) + Relationships.actorId eq actorId.id and (Relationships.targetActorId inList targetIds.map { it.id }) and (Relationships.following eq following) }.map { it.toRelationships() } } - override suspend fun findByTargetId( - targetId: ActorId, - option: FindRelationshipOption?, - inverseOption: FindRelationshipOption? - ): List { - val query1 = Relationships.selectAll().where { Relationships.actorId eq targetId.id } - inverseOption.apply(query1) - // todo 逆のほうがいいかも - val query = query1.alias("INV").selectAll().where { - Relationships.targetActorId eq targetId.id - } - option.apply(query) - - return query.map(ResultRow::toRelationships) - } - companion object { private val logger = LoggerFactory.getLogger(ExposedRelationshipRepository::class.java) } } -fun FindRelationshipOption?.apply(query: Query) { - if (this?.follow != null) { - query.andWhere { Relationships.following eq this@apply.follow } - } - if (this?.mute != null) { - query.andWhere { Relationships.muting eq this@apply.mute } - } - if (this?.block != null) { - query.andWhere { Relationships.blocking eq this@apply.block } - } - if (this?.followRequest != null) { - query.andWhere { Relationships.followRequesting eq this@apply.followRequest } - } - if (this?.muteFollowRequest != null) { - query.andWhere { Relationships.mutingFollowRequest eq this@apply.muteFollowRequest } - } -} - fun ResultRow.toRelationships(): Relationship = Relationship( actorId = ActorId(this[Relationships.actorId]), targetActorId = ActorId(this[Relationships.targetActorId]), From e46c85984ce1fb8246201172990647238e81dbbb Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 14 Sep 2024 13:56:54 +0900 Subject: [PATCH 32/40] =?UTF-8?q?test:=20ExposedRelationshipRepository?= =?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 --- .../ExposedRelationshipRepositoryTest.kt | 447 ++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepositoryTest.kt diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepositoryTest.kt new file mode 100644 index 00000000..5327ded2 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepositoryTest.kt @@ -0,0 +1,447 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.relationship.Relationship +import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Mock +import org.mockito.junit.jupiter.MockitoExtension +import utils.* +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@ExtendWith(MockitoExtension::class) +class ExposedRelationshipRepositoryTest : AbstractRepositoryTest(Relationships) { + + @InjectMocks + lateinit var repository: ExposedRelationshipRepository + + @Mock + lateinit var domainEventPublisher: DomainEventPublisher + + @Test + fun save_idが同じレコードがなければinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Actors.tableName) { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + values( + 2, + "a", + "test-hideout-dev.usbharu.dev", + "a", + "", + "https://test-hideout-dev.usbharu.dev/users/a/inbox", + "https://test-hideout-dev.usbharu.dev/users/a/outbox", + "https://test-hideout-dev.usbharu.dev/users/a", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/a#main-key", + "https://test-hideout-dev.usbharu.dev/users/a/following", + "https://test-hideout-dev.usbharu.dev/users/a/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + }.launch() + + val relationship = Relationship.default( + ActorId(1), ActorId(2) + ) + + repository.save(relationship) + + assertThat(assertTable) + .row(0) + .isEqualTo(Relationships.actorId, relationship.actorId.id) + .isEqualTo(Relationships.targetActorId, relationship.targetActorId.id) + .isEqualTo(Relationships.following, relationship.following) + .isEqualTo(Relationships.blocking, relationship.blocking) + .isEqualTo(Relationships.muting, relationship.muting) + .isEqualTo(Relationships.followRequesting, relationship.followRequesting) + .isEqualTo(Relationships.mutingFollowRequest, relationship.mutingFollowRequest) + } + + @Test + fun save_idが同じレコードがあればupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Actors.tableName) { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + values( + 2, + "a", + "test-hideout-dev.usbharu.dev", + "a", + "", + "https://test-hideout-dev.usbharu.dev/users/a/inbox", + "https://test-hideout-dev.usbharu.dev/users/a/outbox", + "https://test-hideout-dev.usbharu.dev/users/a", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/a#main-key", + "https://test-hideout-dev.usbharu.dev/users/a/following", + "https://test-hideout-dev.usbharu.dev/users/a/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto(Relationships.tableName) { + columns(Relationships.columns) + values(1, 2, true, false, false, false, false) + } + }.launch() + + val relationship = Relationship( + actorId = ActorId(1), + targetActorId = ActorId(2), + following = false, + blocking = true, + muting = false, + followRequesting = false, + mutingFollowRequest = false, + ) + + repository.save(relationship) + + assertThat(assertTable) + .row(0) + .isEqualTo(Relationships.actorId, relationship.actorId.id) + .isEqualTo(Relationships.targetActorId, relationship.targetActorId.id) + .isEqualTo(Relationships.following, relationship.following) + .isEqualTo(Relationships.blocking, relationship.blocking) + .isEqualTo(Relationships.muting, relationship.muting) + .isEqualTo(Relationships.followRequesting, relationship.followRequesting) + .isEqualTo(Relationships.mutingFollowRequest, relationship.mutingFollowRequest) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Actors.tableName) { + columns(Actors.columns) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + values( + 2, + "a", + "test-hideout-dev.usbharu.dev", + "a", + "", + "https://test-hideout-dev.usbharu.dev/users/a/inbox", + "https://test-hideout-dev.usbharu.dev/users/a/outbox", + "https://test-hideout-dev.usbharu.dev/users/a", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/a#main-key", + "https://test-hideout-dev.usbharu.dev/users/a/following", + "https://test-hideout-dev.usbharu.dev/users/a/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + insertInto(Relationships.tableName) { + columns(Relationships.columns) + values(1, 2, true, false, false, false, false) + } + }.launch() + + val relationship = Relationship.default( + ActorId(1), ActorId(2) + ) + + change.withSuspend { + repository.delete(relationship) + } + + assertThat(change) + .changeOfDeletionOnTable(Relationships.tableName) + .rowAtStartPoint() + .value(Relationships.actorId.name).isEqualTo(relationship.actorId.id) + .value(Relationships.targetActorId.name).isEqualTo(relationship.targetActorId.id) + + } + + @Test + fun findByActorIdAndTargetId_指定された条件で存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Relationships.tableName) { + columns(Relationships.columns) + values(1, 2, true, false, true, true, false) + values(2, 1, true, false, false, false, false) + values(4, 3, true, false, false, false, true) + values(3, 5, true, false, false, true, false) + } + }.launch() + + val expected = Relationship( + actorId = ActorId(1), + targetActorId = ActorId(2), + following = true, + blocking = false, + muting = true, + followRequesting = true, + mutingFollowRequest = false + ) + + val actual = repository.findByActorIdAndTargetId(ActorId(1), ActorId(2)) + + assertEquals(expected, actual) + assertNotNull(actual) + assertEquals(expected.actorId, actual.actorId) + assertEquals(expected.targetActorId, actual.targetActorId) + assertEquals(expected.following, actual.following) + assertEquals(expected.blocking, actual.blocking) + assertEquals(expected.muting, actual.muting) + assertEquals(expected.followRequesting, actual.followRequesting) + assertEquals(expected.mutingFollowRequest, actual.mutingFollowRequest) + } + + @Test + fun findByActorIdAndTargetId_指定された条件で存在しないとnull() = runTest { + assertNull(repository.findByActorIdAndTargetId(ActorId(1), ActorId(2))) + } + + @Test + fun findByActorIdsAndTargetIdAndBlocking_指定された条件全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Relationships.tableName) { + columns(Relationships.columns) + values(1, 2, true, false, true, true, false) + values(1, 3, false, true, true, true, false) + values(1, 4, true, false, true, true, false) + values(2, 1, true, false, false, false, false) + values(4, 3, true, false, false, false, true) + values(3, 5, true, false, false, true, false) + } + }.launch() + + val expected = listOf( + Relationship( + actorId = ActorId(1), + targetActorId = ActorId(3), + following = false, + blocking = true, + muting = true, + followRequesting = true, + mutingFollowRequest = false + ) + ) + + val actual = repository.findByActorIdsAndTargetIdAndBlocking( + listOf(ActorId(1), ActorId(4)), ActorId(3), blocking = true + ) + + assertContentEquals(expected, actual) + + val expected2 = listOf( + Relationship( + actorId = ActorId(4), + targetActorId = ActorId(3), + following = true, + blocking = false, + muting = false, + followRequesting = false, + mutingFollowRequest = true + ) + ) + + val actual2 = repository.findByActorIdsAndTargetIdAndBlocking( + listOf(ActorId(1), ActorId(4)), ActorId(3), blocking = false + ) + + assertContentEquals(expected2, actual2) + } + + @Test + fun findByActorIdAndTargetIdsAndFollowing_指定された条件全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Relationships.tableName) { + columns(Relationships.columns) + values(1, 2, true, false, true, true, false) + values(1, 3, false, false, true, true, false) + values(1, 4, true, false, true, true, false) + values(2, 1, true, false, false, false, false) + values(4, 3, true, false, false, false, true) + values(3, 5, true, false, false, true, false) + } + }.launch() + + val expected = listOf( + Relationship( + actorId = ActorId(1), + targetActorId = ActorId(2), + following = false, + blocking = true, + muting = true, + followRequesting = true, + mutingFollowRequest = false + ), Relationship( + actorId = ActorId(1), + targetActorId = ActorId(4), + following = false, + blocking = true, + muting = true, + followRequesting = true, + mutingFollowRequest = false + ) + ) + + val actual = repository.findByActorIdAndTargetIdsAndFollowing( + ActorId(1), listOf(ActorId(2), ActorId(3), ActorId(4)), following = true + ) + + assertContentEquals(expected, actual) + + val expected2 = listOf( + Relationship( + actorId = ActorId(1), + targetActorId = ActorId(3), + following = true, + blocking = false, + muting = false, + followRequesting = false, + mutingFollowRequest = true + ) + ) + + val actual2 = repository.findByActorIdAndTargetIdsAndFollowing( + ActorId(1), listOf(ActorId(2), ActorId(3), ActorId(4)), following = false + ) + + assertContentEquals(expected2, actual2) + } + +} \ No newline at end of file From 94d0bedb36e7fdf1451ed49e7d136b570fad2f0e Mon Sep 17 00:00:00 2001 From: usbharu Date: Sat, 14 Sep 2024 05:00:09 +0000 Subject: [PATCH 33/40] style: fix lint (CI) --- .../domain/model/relationship/RelationshipRepository.kt | 2 -- .../exposedrepository/ExposedRelationshipRepository.kt | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/RelationshipRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/RelationshipRepository.kt index 3110d9d0..09f1bc3a 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/RelationshipRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/RelationshipRepository.kt @@ -34,6 +34,4 @@ interface RelationshipRepository { targetIds: List, following: Boolean ): List - } - diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt index 2cdc4c8c..3b0b63b0 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt @@ -77,7 +77,9 @@ class ExposedRelationshipRepository(override val domainEventPublisher: DomainEve blocking: Boolean ): List = query { Relationships.selectAll().where { - Relationships.actorId inList actorIds.map { it.id } and (Relationships.targetActorId eq targetId.id) and (Relationships.blocking eq blocking) + Relationships.actorId inList actorIds.map { + it.id + } and (Relationships.targetActorId eq targetId.id) and (Relationships.blocking eq blocking) }.map { it.toRelationships() } } @@ -87,7 +89,9 @@ class ExposedRelationshipRepository(override val domainEventPublisher: DomainEve following: Boolean ): List = query { Relationships.selectAll().where { - Relationships.actorId eq actorId.id and (Relationships.targetActorId inList targetIds.map { it.id }) and (Relationships.following eq following) + Relationships.actorId eq actorId.id and (Relationships.targetActorId inList targetIds.map { + it.id + }) and (Relationships.following eq following) }.map { it.toRelationships() } } From 8dd55744ec7f512f1adf6e197ac378801108e846 Mon Sep 17 00:00:00 2001 From: usbharu Date: Sat, 14 Sep 2024 05:04:08 +0000 Subject: [PATCH 34/40] style: fix lint (CI) --- .../exposedrepository/ExposedRelationshipRepository.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt index 3b0b63b0..b4827a4f 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepository.kt @@ -89,9 +89,11 @@ class ExposedRelationshipRepository(override val domainEventPublisher: DomainEve following: Boolean ): List = query { Relationships.selectAll().where { - Relationships.actorId eq actorId.id and (Relationships.targetActorId inList targetIds.map { - it.id - }) and (Relationships.following eq following) + Relationships.actorId eq actorId.id and ( + Relationships.targetActorId inList targetIds.map { + it.id + } + ) and (Relationships.following eq following) }.map { it.toRelationships() } } From 934e032b7010fdce674fc79ff64544873b28c09a Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 14 Sep 2024 16:39:34 +0900 Subject: [PATCH 35/40] =?UTF-8?q?test:=20ExposedTimelineRelationshipReposi?= =?UTF-8?q?tory=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...posedTimelineRelationshipRepositoryTest.kt | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRelationshipRepositoryTest.kt diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRelationshipRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRelationshipRepositoryTest.kt new file mode 100644 index 00000000..60e8ae36 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRelationshipRepositoryTest.kt @@ -0,0 +1,254 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.timeline.TimelineId +import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship +import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipId +import dev.usbharu.hideout.core.domain.model.timelinerelationship.Visible +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import utils.* +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class ExposedTimelineRelationshipRepositoryTest : AbstractRepositoryTest(TimelineRelationships) { + + @Test + fun save_idが同じレコードがなければinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Timelines.tableName) { + columns(Timelines.columns) + values(1, 1, "time-line", "PUBLIC", false) + } + insertInto("public.actors") { + columns( + Actors.columns + ) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val relationship = TimelineRelationship( + TimelineRelationshipId(1), TimelineId(1), ActorId(1), Visible.PUBLIC + ) + ExposedTimelineRelationshipRepository().save(relationship) + + assertThat(assertTable) + .row(0) + .isEqualTo(TimelineRelationships.id, relationship.id.value) + .isEqualTo(TimelineRelationships.timelineId, relationship.timelineId.value) + .isEqualTo(TimelineRelationships.actorId, relationship.actorId.id) + .isEqualTo(TimelineRelationships.visible, relationship.visible.name) + } + + @Test + fun save_idが同じレコードがあればupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Timelines.tableName) { + columns(Timelines.columns) + values(1, 1, "time-line", "PUBLIC", false) + } + insertInto(TimelineRelationships.tableName) { + columns(TimelineRelationships.columns) + values(1, 2, 3, "PUBLIC") + } + insertInto("public.actors") { + columns( + Actors.columns + ) + values( + 1, + "b", + "test-hideout-dev.usbharu.dev", + "b", + "", + "https://test-hideout-dev.usbharu.dev/users/b/inbox", + "https://test-hideout-dev.usbharu.dev/users/b/outbox", + "https://test-hideout-dev.usbharu.dev/users/b", + "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuMjzmQBsSxzK6NkOpZh\nWuohaUbzCY7AafXt+3+tiL6LulYNg/YRIqKc7Q/vTJE6CHrqo7RA/OqYrSMxF/LC\nf8aX5aHwJE1A2gSgCcs1IL5GJaYRlp4NcuazpBC9NO4xIrvH//jcVnZGXGWsCbls\nHXZGZdurWOF0Bl3mYN8CdupVumrGuOPs+wbI/Gh+OHw611TcXMyAwFwU2UjvPEgk\nEACW9OvJaq1K40jVCAa3b1nXt53vlXXZEUlL78L0C9xuFbJG0K/GKMBN44GyftJO\nhA95Rf1Nhd0vKDLBiRocGcARmBo9PaSCR5651gJEk5/wfLUnNAf0xj3R8LBoOhnT\nCQIDAQAB\n-----END PUBLIC KEY-----", + "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK4yPOZAGxLHMr\no2Q6lmFa6iFpRvMJjsBp9e37f62Ivou6Vg2D9hEiopztD+9MkToIeuqjtED86pit\nIzEX8sJ/xpflofAkTUDaBKAJyzUgvkYlphGWng1y5rOkEL007jEiu8f/+NxWdkZc\nZawJuWwddkZl26tY4XQGXeZg3wJ26lW6asa44+z7Bsj8aH44fDrXVNxczIDAXBTZ\nSO88SCQQAJb068lqrUrjSNUIBrdvWde3ne+VddkRSUvvwvQL3G4VskbQr8YowE3j\ngbJ+0k6ED3lF/U2F3S8oMsGJGhwZwBGYGj09pIJHnrnWAkSTn/B8tSc0B/TGPdHw\nsGg6GdMJAgMBAAECggEAHkEhLEb70kdOGgJLUR9D/5zYBE0eXdz/MsMyd1AH+Shs\n9AmetKsYzWDmuhp9Cp5swyn328Hmn7B+DvInVn+5YvjNhY07SbaJcVls4g5UQFXk\nu6WC4ZfKap7IyAeaUg54858r8677xcWXuByN5dn+1iU2hJGYK3Cx7rx0PRrUURYG\n2BRaEEwkcPNm9u679OOTyvTmA3NhewUuDaTMkZnnAml87uYYnmFKjQcR+S2UqOm6\nvBZ/devG4TfPBeKEAya/ba8JJ8frGOtjmR9EIliTQoxI2izeAfoGs1OsCSpuPy6s\nV5f0X3HYM7CA+Fpkt2pnixuwg96LaVr4OpVxujhNlwKBgQD1827VuKFGrneNO+c+\n4EIvh+vLh462bJiaVsMHfRhNZF1/5i8gfNJ16ST60hJo11E4riHPzi3q6GWuxOYl\nCkVKvhJ2g3mgnhoehcgnT7UBkasaC7JYd+LsFDnWOTVSJOy2OqfLdLDGAuSTN3kO\nBF4p0ZqQ/AouFNin57WNRGVZ7wKBgQDTLUZtfTkOU3G1nIMTRKmZjqdER5glzHCm\n9o/1ZsQktL+nzSXqYeoWh9fr7fkmC0k/07+SHzzfWvOhWWWlRenUVL5mj7FRq+L9\n9kDjChLR3Jr4L6Sj1iaQ+0uqDSQNYSYO9ctMjAVjFiNhiAd+S6B451Q1VbDKTCHt\nkRW9omz6hwKBgBFTsgY6eJorJl77zmG+mMsSb0kqZqJxahrNa/X2GSUyoeelxsIq\nKQWHhERrUkKykJVGpzkllFSNRMSYOIJ5g8ItO82/m2z2Vm66DAzA78aJhZ1TH6Bd\n6c2p6x0tcJU15rs7zKBnuyBoCcRZTxzur9eQXaxDJVBzxYOmrkKig+VfAoGBAMCP\n2Fiehxh5HobsYNmBEuXjHsM0RZiyA0c8LakoPFL8PodUme5PupUw6cNJDJeUUwbQ\nny8vLOK+nMnUKsu6JK5pV/VNsfM3OZU6p5Bf7ylOcEE/sHF1JVWu0CAQO3+3xmx9\n1RPH2mGwHjMhRzPy4jFdP3wi10KgiY+HbLuvEJChAoGAYCsh3UhtTzGUOlPBkmLL\n17bD0wN4J/fOv8BoXPZ8H2CdqVgWy0s+s+QaPqRxNcA6YyGymBqrmQAn1Uii25r9\nKAwVAjg3S2KDEMSI2RbMMmQJSZ1u0GkxqOUC/MMeZqBYTYxVeqcQPoqJZ0Nk7IOA\nZPFif8bVfcZqeimxrFaV6YI=\n-----END PRIVATE KEY-----", + "2024-09-09 17:12:03.941339", + "https://test-hideout-dev.usbharu.dev/users/b#main-key", + "https://test-hideout-dev.usbharu.dev/users/b/following", + "https://test-hideout-dev.usbharu.dev/users/b/followers", + 1, + false, + 0, + 0, + 0, + null, + "2024-09-09 17:12:03.941339", + false, + null, + "", + false, + null, + null + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val relationship = TimelineRelationship( + TimelineRelationshipId(1), TimelineId(1), ActorId(1), Visible.PUBLIC + ) + ExposedTimelineRelationshipRepository().save(relationship) + + assertThat(assertTable) + .row(0) + .isEqualTo(TimelineRelationships.id, relationship.id.value) + .isEqualTo(TimelineRelationships.timelineId, relationship.timelineId.value) + .isEqualTo(TimelineRelationships.actorId, relationship.actorId.id) + .isEqualTo(TimelineRelationships.visible, relationship.visible.name) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(TimelineRelationships.tableName) { + columns(TimelineRelationships.columns) + values(1, 2, 3, "PUBLIC") + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val timelineRelationship = TimelineRelationship( + TimelineRelationshipId(1), + TimelineId(1), ActorId + (3), Visible.PUBLIC + ) + + change.withSuspend { + ExposedTimelineRelationshipRepository().delete(timelineRelationship) + } + + assertThat(change) + .changeOfDeletionOnTable(TimelineRelationships.tableName) + .rowAtStartPoint() + .value(TimelineRelationships.id.name).isEqualTo(timelineRelationship.id.value) + } + + @Test + fun findByActorId_指定されたid全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(TimelineRelationships.tableName) { + columns(TimelineRelationships.columns) + values(1, 2, 3, "PUBLIC") + values(2, 3, 3, "PUBLIC") + values(3, 3, 4, "PUBLIC") + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + + val findByActorId = ExposedTimelineRelationshipRepository().findByActorId(actorId = ActorId(3)) + + assertThat(findByActorId) + .hasSize(2) + } + + @Test + fun findById_指定されたidで存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(TimelineRelationships.tableName) { + columns(TimelineRelationships.columns) + values(1, 2, 3, "PUBLIC") + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expected = TimelineRelationship( + id = TimelineRelationshipId(1), + timelineId = TimelineId(2), + actorId = ActorId + (3), + visible = Visible.PUBLIC + ) + + val actual = ExposedTimelineRelationshipRepository().findById(TimelineRelationshipId(1)) + + assertEquals(expected, actual) + assertNotNull(actual) + assertEquals(expected.id, actual.id) + assertEquals(expected.actorId, actual.actorId) + assertEquals(expected.timelineId, actual.timelineId) + assertEquals(expected.visible, actual.visible) + } + + @Test + fun findById_指定されたIdで存在しないとnull() = runTest { + assertNull(ExposedTimelineRelationshipRepository().findById(TimelineRelationshipId(1))) + } + + @Test + fun findByTimelineIdAndActorId_指定された条件で存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(TimelineRelationships.tableName) { + columns(TimelineRelationships.columns) + values(1, 2, 3, "PUBLIC") + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expected = TimelineRelationship( + id = TimelineRelationshipId(1), + timelineId = TimelineId(2), + actorId = ActorId + (3), + visible = Visible.PUBLIC + ) + + val actual = ExposedTimelineRelationshipRepository().findByTimelineIdAndActorId(TimelineId(2), ActorId(3)) + + assertEquals(expected, actual) + assertNotNull(actual) + assertEquals(expected.id, actual.id) + assertEquals(expected.actorId, actual.actorId) + assertEquals(expected.timelineId, actual.timelineId) + assertEquals(expected.visible, actual.visible) + } + + @Test + fun findByTimelineIdAndActorId_指定された条件で存在しないとnull() = runTest { + ExposedTimelineRelationshipRepository().findByTimelineIdAndActorId(TimelineId(1), ActorId(1)) + } +} \ No newline at end of file From 86d469451bfda9911ead7aa8ad7f0c50ce58eaea Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 14 Sep 2024 20:11:41 +0900 Subject: [PATCH 36/40] =?UTF-8?q?test:=20ExposedApplicationRepository?= =?UTF-8?q?=E3=81=A8ExposedCustomEmojiRepository=E3=81=A8ExposedFilterRepo?= =?UTF-8?q?sitory=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/model/filter/FilterKeyword.kt | 15 +- .../core/domain/model/filter/FilterName.kt | 15 + .../exposed/FilterQueryMapper.kt | 2 +- .../ExposedCustomEmojiRepository.kt | 14 +- .../ExposedFilterRepository.kt | 8 +- .../ExposedApplicationRepositoryTest.kt | 70 ++++ .../ExposedCustomEmojiRepositoryTest.kt | 324 ++++++++++++++++++ .../ExposedFilterRepositoryTest.kt | 301 ++++++++++++++++ 8 files changed, 739 insertions(+), 10 deletions(-) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepositoryTest.kt create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepositoryTest.kt create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepositoryTest.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterKeyword.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterKeyword.kt index 333eb8ae..6e5822fd 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterKeyword.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterKeyword.kt @@ -4,4 +4,17 @@ class FilterKeyword( val id: FilterKeywordId, var keyword: FilterKeywordKeyword, val mode: FilterMode -) +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as FilterKeyword + + return id == other.id + } + + override fun hashCode(): Int { + return id.hashCode() + } +} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt index bd6596f3..c829c4ee 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt @@ -4,7 +4,22 @@ class FilterName(name: String) { val name = name.take(LENGTH) + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as FilterName + + return name == other.name + } + + override fun hashCode(): Int { + return name.hashCode() + } + companion object { const val LENGTH = 300 } + + } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/FilterQueryMapper.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/FilterQueryMapper.kt index 5b6039c4..f0c2814d 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/FilterQueryMapper.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/FilterQueryMapper.kt @@ -33,7 +33,7 @@ class FilterQueryMapper(private val filterResultRowMapper: ResultRowMapper FilterKeyword( diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt index d96f7a0c..7f1a0b50 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt @@ -31,8 +31,7 @@ import org.springframework.stereotype.Repository import java.net.URI @Repository -class ExposedCustomEmojiRepository : CustomEmojiRepository, - AbstractRepository() { +class ExposedCustomEmojiRepository : CustomEmojiRepository, AbstractRepository() { override val logger: Logger get() = Companion.logger @@ -50,7 +49,12 @@ class ExposedCustomEmojiRepository : CustomEmojiRepository, } override suspend fun findById(id: Long): CustomEmoji? = query { - return@query CustomEmojis.selectAll().where { CustomEmojis.id eq id }.singleOrNull()?.toCustomEmoji() + CustomEmojis + .selectAll() + .where { CustomEmojis.id eq id } + .limit(1) + .singleOrNull() + ?.toCustomEmoji() } override suspend fun delete(customEmoji: CustomEmoji): Unit = query { @@ -58,7 +62,7 @@ class ExposedCustomEmojiRepository : CustomEmojiRepository, } override suspend fun findByNamesAndDomain(names: List, domain: String): List = query { - return@query CustomEmojis + CustomEmojis .selectAll() .where { CustomEmojis.name inList names and (CustomEmojis.domain eq domain) @@ -67,7 +71,7 @@ class ExposedCustomEmojiRepository : CustomEmojiRepository, } override suspend fun findByIds(ids: List): List = query { - return@query CustomEmojis + CustomEmojis .selectAll() .where { CustomEmojis.id inList ids diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepository.kt index 765641f1..837ccee9 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepository.kt @@ -63,18 +63,20 @@ class ExposedFilterRepository(private val filterQueryMapper: QueryMapper val filterId = FilterKeywords .selectAll() .where { FilterKeywords.id eq filterKeywordId.id } + .limit(1) .firstOrNull()?.get(FilterKeywords.filterId) ?: return@query null - val where = Filters.selectAll().where { Filters.id eq filterId } + val where = Filters.leftJoin(FilterKeywords).selectAll().where { Filters.id eq filterId } return@query filterQueryMapper.map(where).firstOrNull() } override suspend fun findByFilterId(filterId: FilterId): Filter? = query { - val where = Filters.selectAll().where { Filters.id eq filterId.id } + val where = Filters.leftJoin(FilterKeywords).selectAll().where { Filters.id eq filterId.id } return@query filterQueryMapper.map(where).firstOrNull() } override suspend fun findByUserDetailId(userDetailId: UserDetailId): List = query { - return@query Filters.selectAll().where { Filters.userId eq userDetailId.id }.let(filterQueryMapper::map) + return@query Filters.leftJoin(FilterKeywords).selectAll().where { Filters.userId eq userDetailId.id } + .let(filterQueryMapper::map) } companion object { diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepositoryTest.kt new file mode 100644 index 00000000..619db4fd --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepositoryTest.kt @@ -0,0 +1,70 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.application.Application +import dev.usbharu.hideout.core.domain.model.application.ApplicationId +import dev.usbharu.hideout.core.domain.model.application.ApplicationName +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import utils.AbstractRepositoryTest +import utils.columns +import utils.isEqualTo +import utils.withSuspend + +class ExposedApplicationRepositoryTest : AbstractRepositoryTest(Applications) { + @Test + fun save_idが同じレコードが存在しないとinsert() = runTest { + val application = Application(ApplicationId(1), ApplicationName("test-application")) + + ExposedApplicationRepository().save(application) + + assertThat(assertTable) + .row(0) + .isEqualTo(Applications.id, application.applicationId.id) + .isEqualTo(Applications.name, application.name.name) + } + + @Test + fun save_idが同じレコードが存在したらupdate() = runTest { + dbSetup(to = dataSource) { + insertInto(Applications.tableName) { + columns(Applications.columns) + values(1, "application-test") + } + }.launch() + + val application = Application(ApplicationId(1), ApplicationName("test-application")) + + ExposedApplicationRepository().save(application) + + assertThat(assertTable) + .row(0) + .isEqualTo(Applications.id, application.applicationId.id) + .isEqualTo(Applications.name, application.name.name) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + insertInto(Applications.tableName) { + columns(Applications.columns) + values(1, "test-application") + } + }.launch() + + val application = Application(ApplicationId(1), ApplicationName("test-application")) + + change.withSuspend { + ExposedApplicationRepository().delete(application) + } + + assertThat(change) + .changeOfDeletionOnTable(Applications.tableName) + .rowAtStartPoint() + .value(Applications.id.name).isEqualTo(application.applicationId.id) + .value(Applications.name.name).isEqualTo(application.name.name) + + + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepositoryTest.kt new file mode 100644 index 00000000..e32171d3 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepositoryTest.kt @@ -0,0 +1,324 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji +import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId +import dev.usbharu.hideout.core.domain.model.instance.InstanceId +import dev.usbharu.hideout.core.domain.model.support.domain.Domain +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import utils.* +import java.net.URI +import java.sql.Timestamp +import java.time.Instant +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class ExposedCustomEmojiRepositoryTest : AbstractRepositoryTest(CustomEmojis) { + @Test + fun save_idが同じレコードが存在しないとinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Instance.tableName) { + columns(Instance.columns) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + val customEmoji = CustomEmoji( + CustomEmojiId(1), + "name", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + + ExposedCustomEmojiRepository().save(customEmoji) + + assertThat(assertTable).row(0).isEqualTo(CustomEmojis.id, customEmoji.id.emojiId) + .isEqualTo(CustomEmojis.name, customEmoji.name).isEqualTo(CustomEmojis.domain, customEmoji.domain.domain) + .isEqualTo(CustomEmojis.instanceId, customEmoji.instanceId.instanceId) + .isEqualTo(CustomEmojis.url, customEmoji.url.toString()) + .isEqualTo(CustomEmojis.category, customEmoji.category).value(CustomEmojis.createdAt.name) + .isEqualTo(Timestamp.from(customEmoji.createdAt)) + } + + @Test + fun save_idが同じレコードが存在したらupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Instance.tableName) { + columns(Instance.columns) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + val customEmoji = CustomEmoji( + CustomEmojiId(1), + "name", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + + ExposedCustomEmojiRepository().save(customEmoji) + + assertThat(assertTable).row(0).isEqualTo(CustomEmojis.id, customEmoji.id.emojiId) + .isEqualTo(CustomEmojis.name, customEmoji.name).isEqualTo(CustomEmojis.domain, customEmoji.domain.domain) + .isEqualTo(CustomEmojis.instanceId, customEmoji.instanceId.instanceId) + .isEqualTo(CustomEmojis.url, customEmoji.url.toString()) + .isEqualTo(CustomEmojis.category, customEmoji.category).value(CustomEmojis.createdAt.name) + .isEqualTo(Timestamp.from(customEmoji.createdAt)) + } + + @Test + fun delete_削除される() = runTest { + + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val customEmoji = CustomEmoji( + CustomEmojiId(1), + "name", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + + + change.withSuspend { + ExposedCustomEmojiRepository().delete(customEmoji) + } + + assertThat(change).changeOfDeletionOnTable(CustomEmojis.tableName).rowAtStartPoint().value(CustomEmojis.id.name) + .isEqualTo(customEmoji.id.emojiId) + } + + @Test + fun findById_指定したIdで存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val customEmoji = CustomEmoji( + CustomEmojiId(1), + "emoji", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + + val actual = ExposedCustomEmojiRepository().findById(1) + + assertEquals(customEmoji, actual) + assertNotNull(actual) + assertEquals(customEmoji.id, actual.id) + assertEquals(customEmoji.createdAt, actual.createdAt) + assertEquals(customEmoji.url, actual.url) + assertEquals(customEmoji.category, actual.category) + assertEquals(customEmoji.instanceId, actual.instanceId) + assertEquals(customEmoji.domain, actual.domain) + assertEquals(customEmoji.name, actual.name) + } + + @Test + fun findById_指定したIdで存在しないとnull() = runTest { + assertNull(ExposedCustomEmojiRepository().findById(1)) + } + + @Test + fun findByNamesAndDomain_指定した条件全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com/1", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + values( + 2, + "emoji2", + "example.com", + 1, + "https://example.com/2", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + values( + 3, + "emoji3", + "example.com", + 1, + "https://example.com/3", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val expected = listOf( + CustomEmoji( + CustomEmojiId(1), + "emoji", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com/1"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ), CustomEmoji( + CustomEmojiId(2), + "emoji2", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com/2"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + ) + + val actual = ExposedCustomEmojiRepository().findByNamesAndDomain(listOf("emoji", "emoji2"), "example.com") + + assertContentEquals(expected, actual) + } + + @Test + fun findByIds_指定された条件全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com/1", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + values( + 2, + "emoji2", + "example.com", + 1, + "https://example.com/2", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + values( + 3, + "emoji3", + "example.com", + 1, + "https://example.com/3", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val expected = listOf( + CustomEmoji( + CustomEmojiId(1), + "emoji", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com/1"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ), CustomEmoji( + CustomEmojiId(3), + "emoji3", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com/3"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + ) + + val actual = ExposedCustomEmojiRepository().findByIds(listOf(1, 3)) + + assertContentEquals(expected, actual) + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepositoryTest.kt new file mode 100644 index 00000000..aa2394d4 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepositoryTest.kt @@ -0,0 +1,301 @@ +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.filter.* +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId +import dev.usbharu.hideout.core.infrastructure.exposed.FilterQueryMapper +import dev.usbharu.hideout.core.infrastructure.exposed.FilterResultRowMapper +import dev.usbharu.hideout.core.infrastructure.exposedrepository.ExposedFilterRepository +import dev.usbharu.hideout.core.infrastructure.exposedrepository.FilterKeywords +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.assertj.db.type.Changes +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Spy +import org.mockito.junit.jupiter.MockitoExtension +import utils.* +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +Epackage dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.filter.* +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId +import dev.usbharu.hideout.core.infrastructure.exposed.FilterQueryMapper +import dev.usbharu.hideout.core.infrastructure.exposed.FilterResultRowMapper +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.assertj.db.type.Changes +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Spy +import org.mockito.junit.jupiter.MockitoExtension +import utils.* +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@ExtendWith(MockitoExtension::class) +class ExposedFilterRepositoryTest : AbstractRepositoryTest(Filters) { + + @InjectMocks + lateinit var repository: ExposedFilterRepository + + @Spy + val filterQueryMapper: FilterQueryMapper = FilterQueryMapper(FilterResultRowMapper()) + + @Test + fun save_idが同じレコードが存在しないとinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 2, "VeeeeeeeeeeeeeeeeryStrongPassword", false, null, null) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val filter = Filter( + FilterId(1), + UserDetailId(1), + FilterName("filter"), + setOf(), + FilterAction.HIDE, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.NONE)) + ) + repository.save(filter) + + assertThat(assertTable).row(0).isEqualTo(Filters.id, filter.id.id) + .isEqualTo(Filters.userId, filter.userDetailId.id).isEqualTo(Filters.name, filter.name.name) + .isEqualTo(Filters.filterAction, filter.filterAction.name) + .isEqualTo(Filters.context, filter.filterContext.joinToString(",") { it.name }) + + assertThat(getTable(FilterKeywords.tableName)).row(0) + .isEqualTo(FilterKeywords.id, filter.filterKeywords.first().id.id) + .isEqualTo(FilterKeywords.filterId, filter.id.id) + .isEqualTo(FilterKeywords.keyword, filter.filterKeywords.first().keyword.keyword) + .isEqualTo(FilterKeywords.mode, filter.filterKeywords.first().mode.name) + } + + @Test + fun save_idが同じレコードが存在したらupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 2, "VeeeeeeeeeeeeeeeeryStrongPassword", false, null, null) + } + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "", "WARN") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "aaaaaaaaaaaaaaaaa", "REGEX") + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val filter = Filter( + FilterId(1), + UserDetailId(1), + FilterName("filter"), + setOf(), + FilterAction.HIDE, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.NONE)) + ) + repository.save(filter) + + assertThat(assertTable).row(0).isEqualTo(Filters.id, filter.id.id) + .isEqualTo(Filters.userId, filter.userDetailId.id).isEqualTo(Filters.name, filter.name.name) + .isEqualTo(Filters.filterAction, filter.filterAction.name) + .isEqualTo(Filters.context, filter.filterContext.joinToString(",") { it.name }) + + assertThat(getTable(FilterKeywords.tableName)).row(0) + .isEqualTo(FilterKeywords.id, filter.filterKeywords.first().id.id) + .isEqualTo(FilterKeywords.filterId, filter.id.id) + .isEqualTo(FilterKeywords.keyword, filter.filterKeywords.first().keyword.keyword) + .isEqualTo(FilterKeywords.mode, filter.filterKeywords.first().mode.name) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 2, "VeeeeeeeeeeeeeeeeryStrongPassword", false, null, null) + } + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "", "WARN") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "aaaaaaaaaaaaaaaaa", "REGEX") + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val filter = Filter( + FilterId(1), + UserDetailId(1), + FilterName("filter"), + setOf(), + FilterAction.HIDE, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.NONE)) + ) + + val changes = Changes(dataSource) + changes.withSuspend { + repository.delete(filter) + } + + assertThat(changes).changeOfDeletionOnTable(Filters.tableName).rowAtStartPoint().value(Filters.id.name) + .isEqualTo(filter.id.id).changeOfDeletionOnTable(FilterKeywords.tableName).rowAtStartPoint() + .value(FilterKeywords.id.name).isEqualTo(filter.filterKeywords.first().id.id) + } + + @Test + fun findByFilterKeywordId_指定された条件で存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "PUBLIC", "WARN") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "keyword", "REGEX") + } + + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expected = Filter( + FilterId(1), + UserDetailId(1), + FilterName("name"), + setOf(FilterContext.PUBLIC), + FilterAction.WARN, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.REGEX)) + ) + + val actual = repository.findByFilterKeywordId(FilterKeywordId(1)) + + assertEquals(expected, actual) + } + + private fun assertEquals( + expected: Filter, actual: Filter? + ) { + kotlin.test.assertEquals(expected, actual) + assertNotNull(actual) + assertEquals(expected.id, actual.id) + assertEquals(expected.name, actual.name) + assertContentEquals(expected.filterContext, actual.filterContext.asIterable()) + assertEquals(expected.userDetailId, actual.userDetailId) + assertEquals(expected.filterKeywords.size, actual.filterKeywords.size) + assertContentEquals(expected.filterKeywords, actual.filterKeywords.asIterable()) + } + + + @Test + fun findByFilterKeywordId_指定された条件で存在しないとnull() = runTest { + assertNull(repository.findByFilterKeywordId(FilterKeywordId(1))) + } + + @Test + fun findByFilterId_指定された条件で存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "PUBLIC", "WARN") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "keyword", "REGEX") + } + + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expected = Filter( + FilterId(1), + UserDetailId(1), + FilterName("name"), + setOf(FilterContext.PUBLIC), + FilterAction.WARN, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.REGEX)) + ) + + val actual = repository.findByFilterId(FilterId(1)) + + assertEquals(expected, actual) + } + + @Test + fun findByFilterId_指定された条件で存在しないとnull() = runTest { + assertNull(repository.findByFilterId(FilterId(1))) + } + + @Test + fun findByUserDetailId_指定された条件全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "PUBLIC", "WARN") + values(2, 1, "name2", "PUBLIC", "WARN") + values(3, 1, "name3", "PUBLIC", "HIDE") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "keyword", "REGEX") + values(2, 2, "keyword2", "REGEX") + values(3, 1, "keyword3", "REGEX") + } + + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expected = listOf( + Filter( + FilterId(1), UserDetailId(1), FilterName("name"), setOf(FilterContext.PUBLIC), FilterAction.WARN, setOf( + FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.REGEX), + FilterKeyword(FilterKeywordId(3), FilterKeywordKeyword("keyword3"), FilterMode.REGEX) + ) + ), Filter( + FilterId(2), + UserDetailId(1), + FilterName("name2"), + setOf(FilterContext.PUBLIC), + FilterAction.WARN, + setOf( + FilterKeyword(FilterKeywordId(2), FilterKeywordKeyword("keyword2"), FilterMode.REGEX) + ) + ), Filter( + FilterId(3), + UserDetailId(1), + FilterName("name3"), + setOf(FilterContext.PUBLIC), + FilterAction.HIDE, + setOf( + ) + ) + ) + + val actual = repository.findByUserDetailId(UserDetailId(1)) + + assertContentEquals(expected, actual) + } +} \ No newline at end of file From 857a46057f1cdc7ef7909755152e6b51d532ec17 Mon Sep 17 00:00:00 2001 From: usbharu Date: Sat, 14 Sep 2024 11:15:14 +0000 Subject: [PATCH 37/40] style: fix lint (CI) --- .../dev/usbharu/hideout/core/domain/model/filter/FilterName.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt index c829c4ee..2e517ceb 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt @@ -20,6 +20,4 @@ class FilterName(name: String) { companion object { const val LENGTH = 300 } - - } From 7ce7e3085af9c6e343a6a6cf9739c216c2c16d81 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 14 Sep 2024 20:11:41 +0900 Subject: [PATCH 38/40] =?UTF-8?q?test:=20ExposedApplicationRepository?= =?UTF-8?q?=E3=81=A8ExposedCustomEmojiRepository=E3=81=A8ExposedFilterRepo?= =?UTF-8?q?sitory=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/model/filter/FilterKeyword.kt | 15 +- .../core/domain/model/filter/FilterName.kt | 15 + .../exposed/FilterQueryMapper.kt | 2 +- .../ExposedCustomEmojiRepository.kt | 14 +- .../ExposedFilterRepository.kt | 8 +- .../ExposedApplicationRepositoryTest.kt | 70 ++++ .../ExposedCustomEmojiRepositoryTest.kt | 324 ++++++++++++++++++ .../ExposedFilterRepositoryTest.kt | 280 +++++++++++++++ 8 files changed, 718 insertions(+), 10 deletions(-) create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepositoryTest.kt create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepositoryTest.kt create mode 100644 hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepositoryTest.kt diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterKeyword.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterKeyword.kt index 333eb8ae..6e5822fd 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterKeyword.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterKeyword.kt @@ -4,4 +4,17 @@ class FilterKeyword( val id: FilterKeywordId, var keyword: FilterKeywordKeyword, val mode: FilterMode -) +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as FilterKeyword + + return id == other.id + } + + override fun hashCode(): Int { + return id.hashCode() + } +} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt index bd6596f3..c829c4ee 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt @@ -4,7 +4,22 @@ class FilterName(name: String) { val name = name.take(LENGTH) + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as FilterName + + return name == other.name + } + + override fun hashCode(): Int { + return name.hashCode() + } + companion object { const val LENGTH = 300 } + + } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/FilterQueryMapper.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/FilterQueryMapper.kt index 5b6039c4..f0c2814d 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/FilterQueryMapper.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposed/FilterQueryMapper.kt @@ -33,7 +33,7 @@ class FilterQueryMapper(private val filterResultRowMapper: ResultRowMapper FilterKeyword( diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt index d96f7a0c..7f1a0b50 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepository.kt @@ -31,8 +31,7 @@ import org.springframework.stereotype.Repository import java.net.URI @Repository -class ExposedCustomEmojiRepository : CustomEmojiRepository, - AbstractRepository() { +class ExposedCustomEmojiRepository : CustomEmojiRepository, AbstractRepository() { override val logger: Logger get() = Companion.logger @@ -50,7 +49,12 @@ class ExposedCustomEmojiRepository : CustomEmojiRepository, } override suspend fun findById(id: Long): CustomEmoji? = query { - return@query CustomEmojis.selectAll().where { CustomEmojis.id eq id }.singleOrNull()?.toCustomEmoji() + CustomEmojis + .selectAll() + .where { CustomEmojis.id eq id } + .limit(1) + .singleOrNull() + ?.toCustomEmoji() } override suspend fun delete(customEmoji: CustomEmoji): Unit = query { @@ -58,7 +62,7 @@ class ExposedCustomEmojiRepository : CustomEmojiRepository, } override suspend fun findByNamesAndDomain(names: List, domain: String): List = query { - return@query CustomEmojis + CustomEmojis .selectAll() .where { CustomEmojis.name inList names and (CustomEmojis.domain eq domain) @@ -67,7 +71,7 @@ class ExposedCustomEmojiRepository : CustomEmojiRepository, } override suspend fun findByIds(ids: List): List = query { - return@query CustomEmojis + CustomEmojis .selectAll() .where { CustomEmojis.id inList ids diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepository.kt index 765641f1..837ccee9 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepository.kt @@ -63,18 +63,20 @@ class ExposedFilterRepository(private val filterQueryMapper: QueryMapper val filterId = FilterKeywords .selectAll() .where { FilterKeywords.id eq filterKeywordId.id } + .limit(1) .firstOrNull()?.get(FilterKeywords.filterId) ?: return@query null - val where = Filters.selectAll().where { Filters.id eq filterId } + val where = Filters.leftJoin(FilterKeywords).selectAll().where { Filters.id eq filterId } return@query filterQueryMapper.map(where).firstOrNull() } override suspend fun findByFilterId(filterId: FilterId): Filter? = query { - val where = Filters.selectAll().where { Filters.id eq filterId.id } + val where = Filters.leftJoin(FilterKeywords).selectAll().where { Filters.id eq filterId.id } return@query filterQueryMapper.map(where).firstOrNull() } override suspend fun findByUserDetailId(userDetailId: UserDetailId): List = query { - return@query Filters.selectAll().where { Filters.userId eq userDetailId.id }.let(filterQueryMapper::map) + return@query Filters.leftJoin(FilterKeywords).selectAll().where { Filters.userId eq userDetailId.id } + .let(filterQueryMapper::map) } companion object { diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepositoryTest.kt new file mode 100644 index 00000000..619db4fd --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedApplicationRepositoryTest.kt @@ -0,0 +1,70 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.application.Application +import dev.usbharu.hideout.core.domain.model.application.ApplicationId +import dev.usbharu.hideout.core.domain.model.application.ApplicationName +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import utils.AbstractRepositoryTest +import utils.columns +import utils.isEqualTo +import utils.withSuspend + +class ExposedApplicationRepositoryTest : AbstractRepositoryTest(Applications) { + @Test + fun save_idが同じレコードが存在しないとinsert() = runTest { + val application = Application(ApplicationId(1), ApplicationName("test-application")) + + ExposedApplicationRepository().save(application) + + assertThat(assertTable) + .row(0) + .isEqualTo(Applications.id, application.applicationId.id) + .isEqualTo(Applications.name, application.name.name) + } + + @Test + fun save_idが同じレコードが存在したらupdate() = runTest { + dbSetup(to = dataSource) { + insertInto(Applications.tableName) { + columns(Applications.columns) + values(1, "application-test") + } + }.launch() + + val application = Application(ApplicationId(1), ApplicationName("test-application")) + + ExposedApplicationRepository().save(application) + + assertThat(assertTable) + .row(0) + .isEqualTo(Applications.id, application.applicationId.id) + .isEqualTo(Applications.name, application.name.name) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + insertInto(Applications.tableName) { + columns(Applications.columns) + values(1, "test-application") + } + }.launch() + + val application = Application(ApplicationId(1), ApplicationName("test-application")) + + change.withSuspend { + ExposedApplicationRepository().delete(application) + } + + assertThat(change) + .changeOfDeletionOnTable(Applications.tableName) + .rowAtStartPoint() + .value(Applications.id.name).isEqualTo(application.applicationId.id) + .value(Applications.name.name).isEqualTo(application.name.name) + + + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepositoryTest.kt new file mode 100644 index 00000000..e32171d3 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedCustomEmojiRepositoryTest.kt @@ -0,0 +1,324 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji +import dev.usbharu.hideout.core.domain.model.emoji.CustomEmojiId +import dev.usbharu.hideout.core.domain.model.instance.InstanceId +import dev.usbharu.hideout.core.domain.model.support.domain.Domain +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import utils.* +import java.net.URI +import java.sql.Timestamp +import java.time.Instant +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class ExposedCustomEmojiRepositoryTest : AbstractRepositoryTest(CustomEmojis) { + @Test + fun save_idが同じレコードが存在しないとinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Instance.tableName) { + columns(Instance.columns) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + val customEmoji = CustomEmoji( + CustomEmojiId(1), + "name", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + + ExposedCustomEmojiRepository().save(customEmoji) + + assertThat(assertTable).row(0).isEqualTo(CustomEmojis.id, customEmoji.id.emojiId) + .isEqualTo(CustomEmojis.name, customEmoji.name).isEqualTo(CustomEmojis.domain, customEmoji.domain.domain) + .isEqualTo(CustomEmojis.instanceId, customEmoji.instanceId.instanceId) + .isEqualTo(CustomEmojis.url, customEmoji.url.toString()) + .isEqualTo(CustomEmojis.category, customEmoji.category).value(CustomEmojis.createdAt.name) + .isEqualTo(Timestamp.from(customEmoji.createdAt)) + } + + @Test + fun save_idが同じレコードが存在したらupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Instance.tableName) { + columns(Instance.columns) + values( + 1, + "system", + "", + "https://example.com", + "", + null, + "", + "", + false, + false, + "", + "2024-09-10 16:59:50.160202" + ) + } + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + val customEmoji = CustomEmoji( + CustomEmojiId(1), + "name", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + + ExposedCustomEmojiRepository().save(customEmoji) + + assertThat(assertTable).row(0).isEqualTo(CustomEmojis.id, customEmoji.id.emojiId) + .isEqualTo(CustomEmojis.name, customEmoji.name).isEqualTo(CustomEmojis.domain, customEmoji.domain.domain) + .isEqualTo(CustomEmojis.instanceId, customEmoji.instanceId.instanceId) + .isEqualTo(CustomEmojis.url, customEmoji.url.toString()) + .isEqualTo(CustomEmojis.category, customEmoji.category).value(CustomEmojis.createdAt.name) + .isEqualTo(Timestamp.from(customEmoji.createdAt)) + } + + @Test + fun delete_削除される() = runTest { + + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val customEmoji = CustomEmoji( + CustomEmojiId(1), + "name", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + + + change.withSuspend { + ExposedCustomEmojiRepository().delete(customEmoji) + } + + assertThat(change).changeOfDeletionOnTable(CustomEmojis.tableName).rowAtStartPoint().value(CustomEmojis.id.name) + .isEqualTo(customEmoji.id.emojiId) + } + + @Test + fun findById_指定したIdで存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val customEmoji = CustomEmoji( + CustomEmojiId(1), + "emoji", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + + val actual = ExposedCustomEmojiRepository().findById(1) + + assertEquals(customEmoji, actual) + assertNotNull(actual) + assertEquals(customEmoji.id, actual.id) + assertEquals(customEmoji.createdAt, actual.createdAt) + assertEquals(customEmoji.url, actual.url) + assertEquals(customEmoji.category, actual.category) + assertEquals(customEmoji.instanceId, actual.instanceId) + assertEquals(customEmoji.domain, actual.domain) + assertEquals(customEmoji.name, actual.name) + } + + @Test + fun findById_指定したIdで存在しないとnull() = runTest { + assertNull(ExposedCustomEmojiRepository().findById(1)) + } + + @Test + fun findByNamesAndDomain_指定した条件全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com/1", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + values( + 2, + "emoji2", + "example.com", + 1, + "https://example.com/2", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + values( + 3, + "emoji3", + "example.com", + 1, + "https://example.com/3", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val expected = listOf( + CustomEmoji( + CustomEmojiId(1), + "emoji", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com/1"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ), CustomEmoji( + CustomEmojiId(2), + "emoji2", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com/2"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + ) + + val actual = ExposedCustomEmojiRepository().findByNamesAndDomain(listOf("emoji", "emoji2"), "example.com") + + assertContentEquals(expected, actual) + } + + @Test + fun findByIds_指定された条件全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(CustomEmojis.tableName) { + columns(CustomEmojis.columns) + values( + 1, + "emoji", + "example.com", + 1, + "https://example.com/1", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + values( + 2, + "emoji2", + "example.com", + 1, + "https://example.com/2", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + values( + 3, + "emoji3", + "example.com", + 1, + "https://example.com/3", + null, + Timestamp.from(Instant.parse("2020-01-01T00:00:00Z")) + ) + } + }.launch() + + val expected = listOf( + CustomEmoji( + CustomEmojiId(1), + "emoji", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com/1"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ), CustomEmoji( + CustomEmojiId(3), + "emoji3", + Domain("example.com"), + InstanceId(1), + URI.create("https://example.com/3"), + null, + Instant.parse("2020-01-01T00:00:00Z") + ) + ) + + val actual = ExposedCustomEmojiRepository().findByIds(listOf(1, 3)) + + assertContentEquals(expected, actual) + } +} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepositoryTest.kt new file mode 100644 index 00000000..952eb316 --- /dev/null +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedFilterRepositoryTest.kt @@ -0,0 +1,280 @@ +package dev.usbharu.hideout.core.infrastructure.exposedrepository + +import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.filter.* +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId +import dev.usbharu.hideout.core.infrastructure.exposed.FilterQueryMapper +import dev.usbharu.hideout.core.infrastructure.exposed.FilterResultRowMapper +import kotlinx.coroutines.test.runTest +import org.assertj.db.api.Assertions.assertThat +import org.assertj.db.type.Changes +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.InjectMocks +import org.mockito.Spy +import org.mockito.junit.jupiter.MockitoExtension +import utils.* +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@ExtendWith(MockitoExtension::class) +class ExposedFilterRepositoryTest : AbstractRepositoryTest(Filters) { + + @InjectMocks + lateinit var repository: ExposedFilterRepository + + @Spy + val filterQueryMapper: FilterQueryMapper = FilterQueryMapper(FilterResultRowMapper()) + + @Test + fun save_idが同じレコードが存在しないとinsert() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 2, "VeeeeeeeeeeeeeeeeryStrongPassword", false, null, null) + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val filter = Filter( + FilterId(1), + UserDetailId(1), + FilterName("filter"), + setOf(), + FilterAction.HIDE, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.NONE)) + ) + repository.save(filter) + + assertThat(assertTable).row(0).isEqualTo(Filters.id, filter.id.id) + .isEqualTo(Filters.userId, filter.userDetailId.id).isEqualTo(Filters.name, filter.name.name) + .isEqualTo(Filters.filterAction, filter.filterAction.name) + .isEqualTo(Filters.context, filter.filterContext.joinToString(",") { it.name }) + + assertThat(getTable(FilterKeywords.tableName)).row(0) + .isEqualTo(FilterKeywords.id, filter.filterKeywords.first().id.id) + .isEqualTo(FilterKeywords.filterId, filter.id.id) + .isEqualTo(FilterKeywords.keyword, filter.filterKeywords.first().keyword.keyword) + .isEqualTo(FilterKeywords.mode, filter.filterKeywords.first().mode.name) + } + + @Test + fun save_idが同じレコードが存在したらupdate() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 2, "VeeeeeeeeeeeeeeeeryStrongPassword", false, null, null) + } + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "", "WARN") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "aaaaaaaaaaaaaaaaa", "REGEX") + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val filter = Filter( + FilterId(1), + UserDetailId(1), + FilterName("filter"), + setOf(), + FilterAction.HIDE, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.NONE)) + ) + repository.save(filter) + + assertThat(assertTable).row(0).isEqualTo(Filters.id, filter.id.id) + .isEqualTo(Filters.userId, filter.userDetailId.id).isEqualTo(Filters.name, filter.name.name) + .isEqualTo(Filters.filterAction, filter.filterAction.name) + .isEqualTo(Filters.context, filter.filterContext.joinToString(",") { it.name }) + + assertThat(getTable(FilterKeywords.tableName)).row(0) + .isEqualTo(FilterKeywords.id, filter.filterKeywords.first().id.id) + .isEqualTo(FilterKeywords.filterId, filter.id.id) + .isEqualTo(FilterKeywords.keyword, filter.filterKeywords.first().keyword.keyword) + .isEqualTo(FilterKeywords.mode, filter.filterKeywords.first().mode.name) + } + + @Test + fun delete_削除される() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 2, "VeeeeeeeeeeeeeeeeryStrongPassword", false, null, null) + } + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "", "WARN") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "aaaaaaaaaaaaaaaaa", "REGEX") + } + execute(enableReferenceIntegrityConstraints) + }.launch() + + val filter = Filter( + FilterId(1), + UserDetailId(1), + FilterName("filter"), + setOf(), + FilterAction.HIDE, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.NONE)) + ) + + val changes = Changes(dataSource) + changes.withSuspend { + repository.delete(filter) + } + + assertThat(changes).changeOfDeletionOnTable(Filters.tableName).rowAtStartPoint().value(Filters.id.name) + .isEqualTo(filter.id.id).changeOfDeletionOnTable(FilterKeywords.tableName).rowAtStartPoint() + .value(FilterKeywords.id.name).isEqualTo(filter.filterKeywords.first().id.id) + } + + @Test + fun findByFilterKeywordId_指定された条件で存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "PUBLIC", "WARN") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "keyword", "REGEX") + } + + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expected = Filter( + FilterId(1), + UserDetailId(1), + FilterName("name"), + setOf(FilterContext.PUBLIC), + FilterAction.WARN, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.REGEX)) + ) + + val actual = repository.findByFilterKeywordId(FilterKeywordId(1)) + + assertEquals(expected, actual) + } + + private fun assertEquals( + expected: Filter, actual: Filter? + ) { + kotlin.test.assertEquals(expected, actual) + assertNotNull(actual) + assertEquals(expected.id, actual.id) + assertEquals(expected.name, actual.name) + assertContentEquals(expected.filterContext, actual.filterContext.asIterable()) + assertEquals(expected.userDetailId, actual.userDetailId) + assertEquals(expected.filterKeywords.size, actual.filterKeywords.size) + assertContentEquals(expected.filterKeywords, actual.filterKeywords.asIterable()) + } + + + @Test + fun findByFilterKeywordId_指定された条件で存在しないとnull() = runTest { + assertNull(repository.findByFilterKeywordId(FilterKeywordId(1))) + } + + @Test + fun findByFilterId_指定された条件で存在したら返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "PUBLIC", "WARN") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "keyword", "REGEX") + } + + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expected = Filter( + FilterId(1), + UserDetailId(1), + FilterName("name"), + setOf(FilterContext.PUBLIC), + FilterAction.WARN, + setOf(FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.REGEX)) + ) + + val actual = repository.findByFilterId(FilterId(1)) + + assertEquals(expected, actual) + } + + @Test + fun findByFilterId_指定された条件で存在しないとnull() = runTest { + assertNull(repository.findByFilterId(FilterId(1))) + } + + @Test + fun findByUserDetailId_指定された条件全部返す() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + + insertInto(Filters.tableName) { + columns(Filters.columns) + values(1, 1, "name", "PUBLIC", "WARN") + values(2, 1, "name2", "PUBLIC", "WARN") + values(3, 1, "name3", "PUBLIC", "HIDE") + } + insertInto(FilterKeywords.tableName) { + columns(FilterKeywords.columns) + values(1, 1, "keyword", "REGEX") + values(2, 2, "keyword2", "REGEX") + values(3, 1, "keyword3", "REGEX") + } + + execute(enableReferenceIntegrityConstraints) + }.launch() + + val expected = listOf( + Filter( + FilterId(1), UserDetailId(1), FilterName("name"), setOf(FilterContext.PUBLIC), FilterAction.WARN, setOf( + FilterKeyword(FilterKeywordId(1), FilterKeywordKeyword("keyword"), FilterMode.REGEX), + FilterKeyword(FilterKeywordId(3), FilterKeywordKeyword("keyword3"), FilterMode.REGEX) + ) + ), Filter( + FilterId(2), + UserDetailId(1), + FilterName("name2"), + setOf(FilterContext.PUBLIC), + FilterAction.WARN, + setOf( + FilterKeyword(FilterKeywordId(2), FilterKeywordKeyword("keyword2"), FilterMode.REGEX) + ) + ), Filter( + FilterId(3), + UserDetailId(1), + FilterName("name3"), + setOf(FilterContext.PUBLIC), + FilterAction.HIDE, + setOf( + ) + ) + ) + + val actual = repository.findByUserDetailId(UserDetailId(1)) + + assertContentEquals(expected, actual) + } +} \ No newline at end of file From c5f5883c967e35e03cb5208e38c5ea8ac38c3cb5 Mon Sep 17 00:00:00 2001 From: usbharu Date: Sat, 14 Sep 2024 11:24:43 +0000 Subject: [PATCH 39/40] style: fix lint (CI) --- .../dev/usbharu/hideout/core/domain/model/filter/FilterName.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt index c829c4ee..2e517ceb 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/filter/FilterName.kt @@ -20,6 +20,4 @@ class FilterName(name: String) { companion object { const val LENGTH = 300 } - - } From acd96aaed381eb4a352ceeed672ac491397733a1 Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Sat, 14 Sep 2024 20:41:15 +0900 Subject: [PATCH 40/40] =?UTF-8?q?test:=20=E3=83=89=E3=83=A1=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=82=A4=E3=83=99=E3=83=B3=E3=83=88=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 --- .../ExposedRelationshipRepositoryTest.kt | 56 ++++++++++ .../ExposedTimelineRepositoryTest.kt | 102 ++++++++++++++---- 2 files changed, 136 insertions(+), 22 deletions(-) diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepositoryTest.kt index 5327ded2..8220d6a2 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedRelationshipRepositoryTest.kt @@ -6,11 +6,15 @@ import dev.usbharu.hideout.core.domain.model.relationship.Relationship import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher import kotlinx.coroutines.test.runTest import org.assertj.db.api.Assertions.assertThat +import org.jetbrains.exposed.sql.transactions.TransactionManager import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.InjectMocks import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import utils.* import kotlin.test.assertContentEquals import kotlin.test.assertEquals @@ -444,4 +448,56 @@ class ExposedRelationshipRepositoryTest : AbstractRepositoryTest(Relationships) assertContentEquals(expected2, actual2) } + @Test + fun save_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + }.launch() + + val relationship = Relationship( + actorId = ActorId(1), + targetActorId = ActorId(2), + following = false, + blocking = true, + muting = false, + followRequesting = false, + mutingFollowRequest = false, + ) + + relationship.block() + + repository.save(relationship) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } + + @Test + fun delete_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(Relationships.tableName) { + columns(Relationships.columns) + values(1, 2, true, false, false, false, false) + } + }.launch() + + val relationship = Relationship( + actorId = ActorId(1), + targetActorId = ActorId(2), + following = false, + blocking = true, + muting = false, + followRequesting = false, + mutingFollowRequest = false, + ) + relationship.block() + + repository.delete(relationship) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } } \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt index 2802bc3d..82e7e5a7 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepositoryTest.kt @@ -1,20 +1,27 @@ package dev.usbharu.hideout.core.infrastructure.exposedrepository import com.ninja_squad.dbsetup_kotlin.dbSetup +import dev.usbharu.hideout.core.domain.model.actor.ActorId import dev.usbharu.hideout.core.domain.model.timeline.Timeline import dev.usbharu.hideout.core.domain.model.timeline.TimelineId import dev.usbharu.hideout.core.domain.model.timeline.TimelineName import dev.usbharu.hideout.core.domain.model.timeline.TimelineVisibility +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailHashedPassword import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventPublisher import kotlinx.coroutines.test.runTest import org.assertj.core.api.Assertions.assertThat import org.assertj.db.api.Assertions.assertThat +import org.jetbrains.exposed.sql.transactions.TransactionManager import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.InjectMocks import org.mockito.Mock import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify import utils.* import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -47,13 +54,9 @@ class ExposedTimelineRepositoryTest : AbstractRepositoryTest(Timelines) { repository.save(timeline) - assertThat(assertTable) - .row(0) - .isEqualTo(Timelines.id, timeline.id.value) - .isEqualTo(Timelines.userDetailId, timeline.userDetailId.id) - .isEqualTo(Timelines.name, timeline.name.value) - .isEqualTo(Timelines.visibility, timeline.visibility.name) - .isEqualTo(Timelines.isSystem, timeline.isSystem) + assertThat(assertTable).row(0).isEqualTo(Timelines.id, timeline.id.value) + .isEqualTo(Timelines.userDetailId, timeline.userDetailId.id).isEqualTo(Timelines.name, timeline.name.value) + .isEqualTo(Timelines.visibility, timeline.visibility.name).isEqualTo(Timelines.isSystem, timeline.isSystem) } @Test @@ -80,13 +83,9 @@ class ExposedTimelineRepositoryTest : AbstractRepositoryTest(Timelines) { repository.save(timeline) - assertThat(assertTable) - .row(0) - .isEqualTo(Timelines.id, timeline.id.value) - .isEqualTo(Timelines.userDetailId, timeline.userDetailId.id) - .isEqualTo(Timelines.name, timeline.name.value) - .isEqualTo(Timelines.visibility, timeline.visibility.name) - .isEqualTo(Timelines.isSystem, timeline.isSystem) + assertThat(assertTable).row(0).isEqualTo(Timelines.id, timeline.id.value) + .isEqualTo(Timelines.userDetailId, timeline.userDetailId.id).isEqualTo(Timelines.name, timeline.name.value) + .isEqualTo(Timelines.visibility, timeline.visibility.name).isEqualTo(Timelines.isSystem, timeline.isSystem) } @Test @@ -115,10 +114,8 @@ class ExposedTimelineRepositoryTest : AbstractRepositoryTest(Timelines) { repository.delete(timeline) } - assertThat(change) - .changeOfDeletionOnTable(Timelines.tableName) - .rowAtStartPoint() - .value(Timelines.id.name).isEqualTo(timeline.id.value) + assertThat(change).changeOfDeletionOnTable(Timelines.tableName).rowAtStartPoint().value(Timelines.id.name) + .isEqualTo(timeline.id.value) } @Test @@ -135,8 +132,7 @@ class ExposedTimelineRepositoryTest : AbstractRepositoryTest(Timelines) { val findByIds = repository.findByIds(listOf(TimelineId(1), TimelineId(3))) - assertThat(findByIds) - .hasSize(2) + assertThat(findByIds).hasSize(2) } @Test @@ -186,7 +182,69 @@ class ExposedTimelineRepositoryTest : AbstractRepositoryTest(Timelines) { val timelines = repository.findAllByUserDetailIdAndVisibilityIn(UserDetailId(1), listOf(TimelineVisibility.PUBLIC)) - assertThat(timelines) - .hasSize(2) + assertThat(timelines).hasSize(2) + } + + @Test + fun save_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + }.launch() + val timeline = Timeline( + id = TimelineId(1), + userDetailId = UserDetailId(1), + name = TimelineName("timeline"), + visibility = TimelineVisibility.PRIVATE, + isSystem = false + ) + + timeline.setVisibility( + TimelineVisibility.PUBLIC, UserDetail.create( + UserDetailId(1), ActorId(1), + UserDetailHashedPassword("aaaaaa"), + ) + ) + + repository.save(timeline) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) + } + + @Test + fun delete_ドメインイベントがパブリッシュされる() = runTest { + dbSetup(to = dataSource) { + execute(disableReferenceIntegrityConstraints) + insertInto(UserDetails.tableName) { + columns(UserDetails.columns) + values(1, 1, "veeeeeeeeeeeeeeryStrongPassword", true, null, null) + } + insertInto(Timelines.tableName) { + columns(Timelines.columns) + values(1, 1, "test-timeline", "PUBLIC", true) + } + + }.launch() + val timeline = Timeline( + id = TimelineId(1), + userDetailId = UserDetailId(1), + name = TimelineName("timeline"), + visibility = TimelineVisibility.PRIVATE, + isSystem = false + ) + + timeline.setVisibility( + TimelineVisibility.PUBLIC, UserDetail.create( + UserDetailId(1), ActorId(1), + UserDetailHashedPassword("aaaaaa"), + ) + ) + + repository.delete(timeline) + + TransactionManager.current().commit() + + verify(domainEventPublisher, times(1)).publishEvent(any()) } }