diff --git a/hideout-core/build.gradle.kts b/hideout-core/build.gradle.kts index ec38328f..52db4593 100644 --- a/hideout-core/build.gradle.kts +++ b/hideout-core/build.gradle.kts @@ -93,8 +93,8 @@ tasks.withType { kotlinOptions { freeCompilerArgs += "-Xjsr305=strict" } - dependsOn("openApiGenerateMastodonCompatibleApi") - mustRunAfter("openApiGenerateMastodonCompatibleApi") +// dependsOn("openApiGenerateMastodonCompatibleApi") +// mustRunAfter("openApiGenerateMastodonCompatibleApi") } diff --git a/hideout-core/src/intTest/kotlin/mastodon/filter/FilterTest.kt b/hideout-core/src/intTest/kotlin/mastodon/filter/FilterTest.kt index bb3dccae..2732663e 100644 --- a/hideout-core/src/intTest/kotlin/mastodon/filter/FilterTest.kt +++ b/hideout-core/src/intTest/kotlin/mastodon/filter/FilterTest.kt @@ -17,7 +17,6 @@ package mastodon.filter import dev.usbharu.hideout.SpringApplication -import dev.usbharu.hideout.application.config.ActivityPubConfig import dev.usbharu.hideout.domain.mastodon.model.generated.FilterKeywordsPostRequest import dev.usbharu.hideout.domain.mastodon.model.generated.FilterPostRequest import dev.usbharu.hideout.domain.mastodon.model.generated.FilterPostRequestKeyword diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/ActivityPubConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/ActivityPubConfig.kt deleted file mode 100644 index afe658a1..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/ActivityPubConfig.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.config - -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.annotation.JsonSetter -import com.fasterxml.jackson.annotation.Nulls -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.module.SimpleModule -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import dev.usbharu.hideout.activitypub.domain.model.StringORObjectSerializer -import dev.usbharu.hideout.activitypub.domain.model.StringOrObject -import dev.usbharu.hideout.core.infrastructure.httpsignature.HttpRequestMixIn -import dev.usbharu.httpsignature.common.HttpRequest -import dev.usbharu.httpsignature.sign.HttpSignatureSigner -import dev.usbharu.httpsignature.sign.RsaSha256HttpSignatureSigner -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import java.time.format.DateTimeFormatter -import java.util.* - -@Configuration -class ActivityPubConfig { - - @Bean - @Qualifier("activitypub") - fun objectMapper(): ObjectMapper { - val module = SimpleModule().addSerializer(StringOrObject::class.java, StringORObjectSerializer()) - - val objectMapper = jacksonObjectMapper() - .registerModules(module) - .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) - .setSerializationInclusion(JsonInclude.Include.NON_EMPTY) - .setDefaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.SKIP)) - .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SKIP)) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .configure(JsonParser.Feature.ALLOW_COMMENTS, true) - .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true) - .configure(JsonParser.Feature.ALLOW_TRAILING_COMMA, true) - .addMixIn(HttpRequest::class.java, HttpRequestMixIn::class.java) - - return objectMapper - } - - @Bean - @Qualifier("http") - fun dateTimeFormatter(): DateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - - @Bean - fun httpSignatureSigner(): HttpSignatureSigner = RsaSha256HttpSignatureSigner() -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt index 837a261c..0730dfb7 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/config/SecurityConfig.kt @@ -16,43 +16,25 @@ package dev.usbharu.hideout.application.config -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.databind.module.SimpleModule import com.nimbusds.jose.jwk.JWKSet import com.nimbusds.jose.jwk.RSAKey import com.nimbusds.jose.jwk.source.ImmutableJWKSet import com.nimbusds.jose.jwk.source.JWKSource import com.nimbusds.jose.proc.SecurityContext -import dev.usbharu.hideout.activitypub.domain.model.StringORObjectSerializer -import dev.usbharu.hideout.activitypub.domain.model.StringOrObject -import dev.usbharu.hideout.core.application.shared.Transaction -import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureFilter -import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureHeaderChecker -import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureUserDetailsService -import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureVerifierComposite import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.UserDetailsImpl -import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.UserDetailsServiceImpl import dev.usbharu.hideout.util.RsaUtil -import dev.usbharu.httpsignature.sign.RsaSha256HttpSignatureSigner -import dev.usbharu.httpsignature.verify.DefaultSignatureHeaderParser -import dev.usbharu.httpsignature.verify.RsaSha256HttpSignatureVerifier import jakarta.annotation.PostConstruct import jakarta.servlet.* import org.springframework.beans.factory.support.BeanDefinitionRegistry import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty -import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Primary import org.springframework.core.annotation.Order import org.springframework.http.HttpMethod.GET import org.springframework.http.HttpMethod.POST import org.springframework.http.HttpStatus -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter -import org.springframework.security.authentication.AccountStatusUserDetailsChecker import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.authentication.dao.DaoAuthenticationProvider import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder @@ -74,8 +56,6 @@ import org.springframework.security.oauth2.server.authorization.token.JwtEncodin import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer import org.springframework.security.web.FilterChainProxy import org.springframework.security.web.SecurityFilterChain -import org.springframework.security.web.access.ExceptionTranslationFilter -import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler import org.springframework.security.web.authentication.HttpStatusEntryPoint import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider @@ -83,7 +63,6 @@ import org.springframework.security.web.context.AbstractSecurityWebApplicationIn import org.springframework.security.web.debug.DebugFilter import org.springframework.security.web.firewall.HttpFirewall import org.springframework.security.web.firewall.RequestRejectedHandler -import org.springframework.security.web.savedrequest.RequestCacheAwareFilter import org.springframework.security.web.util.matcher.AnyRequestMatcher import org.springframework.web.filter.CompositeFilter import java.io.IOException @@ -105,14 +84,9 @@ class SecurityConfig { @Order(1) fun httpSignatureFilterChain( http: HttpSecurity, - httpSignatureFilter: HttpSignatureFilter, ): SecurityFilterChain { http { securityMatcher("/users/*/posts/*") - addFilterAt(httpSignatureFilter) - addFilterBefore( - ExceptionTranslationFilter(HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) - ) authorizeHttpRequests { authorize(anyRequest, permitAll) } @@ -130,57 +104,6 @@ class SecurityConfig { return http.build() } - @Bean - fun getHttpSignatureFilter( - authenticationManager: AuthenticationManager, - httpSignatureHeaderChecker: HttpSignatureHeaderChecker, - ): HttpSignatureFilter { - val httpSignatureFilter = - HttpSignatureFilter(DefaultSignatureHeaderParser(), httpSignatureHeaderChecker) - httpSignatureFilter.setAuthenticationManager(authenticationManager) - httpSignatureFilter.setContinueFilterChainOnUnsuccessfulAuthentication(false) - val authenticationEntryPointFailureHandler = - AuthenticationEntryPointFailureHandler(HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) - authenticationEntryPointFailureHandler.setRethrowAuthenticationServiceException(false) - httpSignatureFilter.setAuthenticationFailureHandler(authenticationEntryPointFailureHandler) - return httpSignatureFilter - } - - @Bean - @Order(2) - fun daoAuthenticationProvider(userDetailsServiceImpl: UserDetailsServiceImpl): DaoAuthenticationProvider { - val daoAuthenticationProvider = DaoAuthenticationProvider() - daoAuthenticationProvider.setUserDetailsService(userDetailsServiceImpl) - - return daoAuthenticationProvider - } - - @Bean - @Order(1) - fun httpSignatureAuthenticationProvider( - transaction: Transaction, - actorRepository: ActorRepository, - ): PreAuthenticatedAuthenticationProvider { - val provider = PreAuthenticatedAuthenticationProvider() - val signatureHeaderParser = DefaultSignatureHeaderParser() - provider.setPreAuthenticatedUserDetailsService( - HttpSignatureUserDetailsService( - HttpSignatureVerifierComposite( - mapOf( - "rsa-sha256" to RsaSha256HttpSignatureVerifier( - signatureHeaderParser, RsaSha256HttpSignatureSigner() - ) - ), - signatureHeaderParser - ), - transaction, - signatureHeaderParser, - actorRepository - ) - ) - provider.setUserDetailsChecker(AccountStatusUserDetailsChecker()) - return provider - } @Bean @Order(2) @@ -291,22 +214,6 @@ class SecurityConfig { } } - @Bean - @Primary - fun jackson2ObjectMapperBuilderCustomizer(): Jackson2ObjectMapperBuilderCustomizer { - return Jackson2ObjectMapperBuilderCustomizer { - it.serializationInclusion(JsonInclude.Include.ALWAYS) - .modulesToInstall(SimpleModule().addSerializer(StringOrObject::class.java, StringORObjectSerializer())) - .serializers() - } - } - - @Bean - fun mappingJackson2HttpMessageConverter(): MappingJackson2HttpMessageConverter { - val builder = Jackson2ObjectMapperBuilder().serializationInclusion(JsonInclude.Include.NON_NULL) - builder.modulesToInstall(SimpleModule().addSerializer(StringOrObject::class.java, StringORObjectSerializer())) - return MappingJackson2HttpMessageConverter(builder.build()) - } // Spring Security 3.2.1 に存在する EnableWebSecurity(debug = true)にすると発生するエラーに対処するためのコード // trueにしないときはコメントアウト diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/init/MetaService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/init/MetaService.kt deleted file mode 100644 index 32615016..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/init/MetaService.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.service.init - -import org.springframework.stereotype.Service - -@Service -interface MetaService { - suspend fun getMeta(): Meta - suspend fun updateMeta(meta: Meta) - suspend fun getJwtMeta(): Jwt -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/init/MetaServiceImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/init/MetaServiceImpl.kt deleted file mode 100644 index 3ca63744..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/init/MetaServiceImpl.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.service.init - -import dev.usbharu.hideout.core.application.shared.Transaction -import dev.usbharu.hideout.core.domain.exception.NotInitException -import org.springframework.stereotype.Service - -@Service -class MetaServiceImpl(private val metaRepository: MetaRepository, private val transaction: Transaction) : - MetaService { - override suspend fun getMeta(): Meta = - transaction.transaction { metaRepository.get() ?: throw NotInitException("Meta is null") } - - override suspend fun updateMeta(meta: Meta): Unit = transaction.transaction { - metaRepository.save(meta) - } - - override suspend fun getJwtMeta(): Jwt = getMeta().jwt -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/init/ServerInitialiseService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/init/ServerInitialiseService.kt deleted file mode 100644 index ffec5686..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/application/service/init/ServerInitialiseService.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.service.init - -import org.springframework.stereotype.Service - -@Service -interface ServerInitialiseService { - suspend fun init() -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationService.kt index 2a8c231e..0348c80f 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/post/UpdateLocalNoteApplicationService.kt @@ -36,7 +36,7 @@ class UpdateLocalNoteApplicationService( post.content = postContentFactoryImpl.create(updateLocalNote.content) post.overview = updateLocalNote.overview?.let { PostOverview(it) } - post.mediaIds = updateLocalNote.mediaIds.map { MediaId(it) } + post.addMediaIds(updateLocalNote.mediaIds.map { MediaId(it) }) post.sensitive = updateLocalNote.sensitive postRepository.save(post) 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 702f3246..8d13c8e6 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 @@ -72,7 +72,7 @@ class Actor( var moveTo = moveTo set(value) { - require(moveTo != id) + require(value != id) addDomainEvent(ActorDomainEventFactory(this).createEvent(move)) field = value } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actorinstancerelationship/ActorInstanceRelationship.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actorinstancerelationship/ActorInstanceRelationship.kt index bd1c0c1b..178716a0 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actorinstancerelationship/ActorInstanceRelationship.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actorinstancerelationship/ActorInstanceRelationship.kt @@ -85,4 +85,16 @@ data class ActorInstanceRelationship( result = 31 * result + instanceId.hashCode() return result } + + override fun toString(): String { + return "ActorInstanceRelationship(" + + "actorId=$actorId, " + + "instanceId=$instanceId, " + + "blocking=$blocking, " + + "muting=$muting, " + + "doNotSendPrivate=$doNotSendPrivate" + + ")" + } + + } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/media/Media.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/media/Media.kt index 529eb3af..5c3eddf6 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/media/Media.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/media/Media.kt @@ -28,4 +28,18 @@ data class Media( val mimeType: MimeType, val blurHash: MediaBlurHash?, val description: MediaDescription? = null, -) +) { + override fun toString(): String { + return "Media(" + + "id=$id, " + + "name=$name, " + + "url=$url, " + + "remoteUrl=$remoteUrl, " + + "thumbnailUrl=$thumbnailUrl, " + + "type=$type, " + + "mimeType=$mimeType, " + + "blurHash=$blurHash, " + + "description=$description" + + ")" + } +} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/post/Post.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/post/Post.kt index d992a78e..f1846382 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/post/Post.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/post/Post.kt @@ -24,7 +24,7 @@ import dev.usbharu.hideout.core.domain.shared.domainevent.DomainEventStorable import java.net.URI import java.time.Instant -class Post private constructor( +class Post( val id: PostId, actorId: ActorId, overview: PostOverview? = null, @@ -191,8 +191,8 @@ class Post private constructor( return id.hashCode() } - abstract class PostFactory { - protected fun create( + companion object { + fun create( id: PostId, actorId: ActorId, overview: PostOverview? = null, @@ -206,24 +206,30 @@ class Post private constructor( apId: URI, deleted: Boolean, mediaIds: List, - hide: Boolean, + visibleActors: List = emptyList(), + hide: Boolean = false, + moveTo: PostId? = null, ): Post { - return Post( - id = id, - actorId = actorId, - overview = overview, - content = content, - createdAt = createdAt, - visibility = visibility, - url = url, - repostId = repostId, - replyId = replyId, - sensitive = sensitive, - apId = apId, - deleted = deleted, - mediaIds = mediaIds, - hide = hide - ).apply { addDomainEvent(PostDomainEventFactory(this).createEvent(PostEvent.create)) } + val post = Post( + id, + actorId, + overview, + content, + createdAt, + visibility, + url, + repostId, + replyId, + sensitive, + apId, + deleted, + mediaIds, + visibleActors, + hide, + moveTo + ) + post.addDomainEvent(PostDomainEventFactory(post).createEvent(PostEvent.create)) + return post } } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/actor/RemoteActorCheckDomainService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/actor/RemoteActorCheckDomainService.kt index c4ef154b..d7bf7ba8 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/actor/RemoteActorCheckDomainService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/service/actor/RemoteActorCheckDomainService.kt @@ -26,5 +26,5 @@ interface IRemoteActorCheckDomainService { @Service class RemoteActorCheckDomainService(private val applicationConfig: ApplicationConfig) : IRemoteActorCheckDomainService { - override fun isRemoteActor(actor: Actor): Boolean = actor.domain.domain == applicationConfig.url.host + override fun isRemoteActor(actor: Actor): Boolean = actor.domain.domain != applicationConfig.url.host } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverAcceptTask.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverAcceptTask.kt deleted file mode 100644 index b7b19949..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverAcceptTask.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.external.job - -import dev.usbharu.hideout.activitypub.domain.model.Accept -import dev.usbharu.owl.common.property.* -import dev.usbharu.owl.common.task.PropertyDefinition -import dev.usbharu.owl.common.task.Task -import dev.usbharu.owl.common.task.TaskDefinition -import org.springframework.stereotype.Component - -data class DeliverAcceptTask( - val accept: Accept, - val inbox: String, - val signer: Long, -) : Task() - -@Component -data object DeliverAcceptTaskDef : TaskDefinition { - override val name: String - get() = "DeliverAccept" - override val priority: Int - get() = 10 - override val maxRetry: Int - get() = 5 - override val retryPolicy: String - get() = "" - override val timeoutMilli: Long - get() = 1000 - override val propertyDefinition: PropertyDefinition - get() = PropertyDefinition( - mapOf( - "accept" to PropertyType.binary, - "inbox" to PropertyType.string, - "signer" to PropertyType.number, - ) - ) - override val type: Class - get() = DeliverAcceptTask::class.java - - override fun serialize(task: DeliverAcceptTask): Map> { - return mapOf( - "accept" to ObjectPropertyValue(task.accept), - "inbox" to StringPropertyValue(task.inbox), - "signer" to LongPropertyValue(task.signer) - ) - } - - override fun deserialize(value: Map>): DeliverAcceptTask { - return DeliverAcceptTask( - value.getValue("accept").value as Accept, - value.getValue("inbox").value as String, - value.getValue("signer").value as Long, - ) - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverCreateTask.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverCreateTask.kt deleted file mode 100644 index 2c645290..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverCreateTask.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.external.job - -import dev.usbharu.hideout.activitypub.domain.model.Create -import dev.usbharu.owl.common.task.Task -import dev.usbharu.owl.common.task.TaskDefinition -import org.springframework.stereotype.Component - -data class DeliverCreateTask( - val create: Create, - val inbox: String, - val actor: String, -) : Task() - -@Component -data object DeliverCreateTaskDef : TaskDefinition { - override val type: Class - get() = DeliverCreateTask::class.java -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverDeleteTask.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverDeleteTask.kt deleted file mode 100644 index 6ce63ad2..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverDeleteTask.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.external.job - -import dev.usbharu.hideout.activitypub.domain.model.Delete -import dev.usbharu.owl.common.task.Task -import dev.usbharu.owl.common.task.TaskDefinition -import org.springframework.stereotype.Component - -data class DeliverDeleteTask( - val delete: Delete, - val inbox: String, - val signer: Long, -) : Task() - -@Component -data object DeliverDeleteTaskDef : TaskDefinition { - override val type: Class - get() = DeliverDeleteTask::class.java -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverReactionTask.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverReactionTask.kt deleted file mode 100644 index c1c73154..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverReactionTask.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.external.job - -import dev.usbharu.hideout.activitypub.domain.model.Like -import dev.usbharu.owl.common.task.Task -import dev.usbharu.owl.common.task.TaskDefinition -import org.springframework.stereotype.Component - -data class DeliverReactionTask( - val actor: String, - val like: Like, - val inbox: String, -) : Task() - -@Component -data object DeliverReactionTaskDef : TaskDefinition { - override val type: Class - get() = DeliverReactionTask::class.java -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverRejectTask.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverRejectTask.kt deleted file mode 100644 index 5bb47432..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverRejectTask.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.external.job - -import dev.usbharu.hideout.activitypub.domain.model.Reject -import dev.usbharu.owl.common.task.Task -import dev.usbharu.owl.common.task.TaskDefinition -import org.springframework.stereotype.Component - -data class DeliverRejectTask( - val reject: Reject, - val inbox: String, - val signer: Long, -) : Task() - -@Component -data object DeliverRejectTaskDef : TaskDefinition { - override val type: Class - get() = DeliverRejectTask::class.java -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverUndoTask.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverUndoTask.kt deleted file mode 100644 index 3ae7f129..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/DeliverUndoTask.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.external.job - -import dev.usbharu.hideout.activitypub.domain.model.Undo -import dev.usbharu.owl.common.task.Task -import dev.usbharu.owl.common.task.TaskDefinition -import org.springframework.stereotype.Component - -data class DeliverUndoTask( - val undo: Undo, - val inbox: String, - val signer: Long, -) : Task() - -@Component -data object DeliverUndoTaskDef : TaskDefinition { - override val type: Class - get() = DeliverUndoTask::class.java -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/InboxTask.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/InboxTask.kt deleted file mode 100644 index de6b926f..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/InboxTask.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.external.job - -import dev.usbharu.hideout.activitypub.service.common.ActivityType -import dev.usbharu.httpsignature.common.HttpRequest -import dev.usbharu.owl.common.property.ObjectPropertyValue -import dev.usbharu.owl.common.property.PropertyValue -import dev.usbharu.owl.common.property.StringPropertyValue -import dev.usbharu.owl.common.task.Task -import dev.usbharu.owl.common.task.TaskDefinition -import org.springframework.stereotype.Component - -data class InboxTask( - val json: String, - val type: ActivityType, - val httpRequest: HttpRequest, - val headers: Map>, -) : Task() - -@Component -data object InboxTaskDef : TaskDefinition { - override val type: Class - get() = InboxTask::class.java - - override fun serialize(task: InboxTask): Map> { - return mapOf( - "json" to StringPropertyValue(task.json), - "type" to ObjectPropertyValue(task.type), - "httpRequest" to ObjectPropertyValue(task.httpRequest), - "headers" to ObjectPropertyValue(task.headers), - ) - } - - override fun deserialize(value: Map>): InboxTask { - return InboxTask( - value.getValue("json").value as String, - value.getValue("type").value as ActivityType, - value.getValue("httpRequest").value as HttpRequest, - value.getValue("headers").value as Map>, - ) - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/ReceiveFollowTask.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/ReceiveFollowTask.kt deleted file mode 100644 index a72b0d5a..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/ReceiveFollowTask.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.external.job - -import dev.usbharu.hideout.activitypub.domain.model.Follow -import dev.usbharu.owl.common.property.ObjectPropertyValue -import dev.usbharu.owl.common.property.PropertyValue -import dev.usbharu.owl.common.property.StringPropertyValue -import dev.usbharu.owl.common.task.Task -import dev.usbharu.owl.common.task.TaskDefinition -import org.springframework.stereotype.Component - -data class ReceiveFollowTask( - val actor: String, - val follow: Follow, - val targetActor: String, -) : Task() - -@Component -data object ReceiveFollowTaskDef : TaskDefinition { - override val type: Class - get() = ReceiveFollowTask::class.java - - override fun serialize(task: ReceiveFollowTask): Map> { - return mapOf( - "actor" to StringPropertyValue(task.actor), - "follow" to ObjectPropertyValue(task.follow), - "targetActor" to StringPropertyValue(task.targetActor) - ) - } - - override fun deserialize(value: Map>): ReceiveFollowTask { - return ReceiveFollowTask( - value.getValue("actor").value as String, - value.getValue("follow").value as Follow, - value.getValue("targetActor").value as String, - ) - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/UpdateActorTask.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/UpdateActorTask.kt deleted file mode 100644 index 5fc1a272..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/UpdateActorTask.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.external.job - -import dev.usbharu.owl.common.task.Task -import dev.usbharu.owl.common.task.TaskDefinition -import org.springframework.stereotype.Component - -data class UpdateActorTask( - val id: Long, - val apId: String, -) : Task() - -@Component -data object UpdateActorTaskDef : TaskDefinition { - override val type: Class - get() = UpdateActorTask::class.java -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/ActorFactoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/ActorFactoryImpl.kt index 871b67b6..1273b68c 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/ActorFactoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/ActorFactoryImpl.kt @@ -59,7 +59,8 @@ class ActorFactoryImpl( postsCount = ActorPostsCount(0), lastPostAt = null, suspend = false, - emojiIds = emptySet() + emojiIds = emptySet(), + deleted = false ) } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostFactoryImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostFactoryImpl.kt index 9e240543..f28dd0d1 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostFactoryImpl.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/factory/PostFactoryImpl.kt @@ -34,7 +34,7 @@ class PostFactoryImpl( private val idGenerateService: IdGenerateService, private val postContentFactoryImpl: PostContentFactoryImpl, private val applicationConfig: ApplicationConfig, -) : Post.PostFactory() { +) { suspend fun createLocal( actorId: ActorId, actorName: ActorName, @@ -48,7 +48,7 @@ class PostFactoryImpl( ): Post { val id = idGenerateService.generateId() val url = URI.create(applicationConfig.url.toString() + "/users/" + actorName + "/posts/" + id) - return super.create( + return Post.create( PostId(id), actorId, overview, @@ -61,7 +61,7 @@ class PostFactoryImpl( sensitive, url, false, - mediaIds + mediaIds, ) } } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureFilter.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureFilter.kt deleted file mode 100644 index 27886cfb..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureFilter.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.httpsignature - -import dev.usbharu.httpsignature.common.HttpHeaders -import dev.usbharu.httpsignature.common.HttpMethod -import dev.usbharu.httpsignature.common.HttpRequest -import dev.usbharu.httpsignature.verify.SignatureHeaderParser -import jakarta.servlet.http.HttpServletRequest -import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter -import java.net.URL - -class HttpSignatureFilter( - private val httpSignatureHeaderParser: SignatureHeaderParser, - private val httpSignatureHeaderChecker: HttpSignatureHeaderChecker, -) : - AbstractPreAuthenticatedProcessingFilter() { - override fun getPreAuthenticatedPrincipal(request: HttpServletRequest?): Any? { - val headersList = request?.headerNames?.toList().orEmpty() - - val headers = - headersList.associateWith { header -> request?.getHeaders(header)?.toList().orEmpty() } - - val signature = try { - httpSignatureHeaderParser.parse(HttpHeaders(headers)) - } catch (_: IllegalArgumentException) { - return null - } catch (_: RuntimeException) { - return "" - } - return signature.keyId - } - - override fun getPreAuthenticatedCredentials(request: HttpServletRequest?): Any? { - requireNotNull(request) - val url = request.requestURL.toString() - - val headersList = request.headerNames?.toList().orEmpty() - - val headers = - headersList.associateWith { header -> request.getHeaders(header)?.toList().orEmpty() } - - val method = when (val method = request.method.lowercase()) { - "get" -> HttpMethod.GET - "post" -> HttpMethod.POST - else -> { -// throw IllegalArgumentException("Unsupported method: $method") - return null - } - } - - try { - httpSignatureHeaderChecker.checkDate(request.getHeader("date")!!) - httpSignatureHeaderChecker.checkHost(request.getHeader("host")!!) - if (request.method.equals("post", true)) { - httpSignatureHeaderChecker.checkDigest( - request.inputStream.readAllBytes()!!, - request.getHeader("digest")!! - ) - } - } catch (_: NullPointerException) { - return null - } catch (_: IllegalArgumentException) { - return null - } - - return HttpRequest( - URL(url + request.queryString.orEmpty()), - HttpHeaders(headers), - method - ) - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureHeaderChecker.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureHeaderChecker.kt deleted file mode 100644 index eab673cb..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureHeaderChecker.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.httpsignature - -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.util.Base64Util -import org.springframework.stereotype.Component -import java.security.MessageDigest -import java.time.Instant -import java.time.format.DateTimeFormatter -import java.util.* - -@Component -class HttpSignatureHeaderChecker(private val applicationConfig: ApplicationConfig) { - fun checkDate(date: String) { - val from = Instant.from(dateFormat.parse(date)) - - if (from.isAfter(Instant.now()) || from.isBefore(Instant.now().minusSeconds(86400))) { - throw IllegalArgumentException("未来") - } - } - - fun checkHost(host: String) { - if (applicationConfig.url.host.equals(host, true).not()) { - throw IllegalArgumentException("ホスト名が違う") - } - } - - fun checkDigest(byteArray: ByteArray, digest: String) { - val find = regex.find(digest) - val sha256 = MessageDigest.getInstance("SHA-256") - - val other = find?.groups?.get(2)?.value.orEmpty() - - if (Base64Util.encode(sha256.digest(byteArray)).equals(other, true).not()) { - throw IllegalArgumentException("リクエストボディが違う") - } - } - - companion object { - private val dateFormat = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - private val regex = Regex("^([a-zA-Z0-9\\-]+)=(.+)$") - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUser.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUser.kt deleted file mode 100644 index 50fc2c4e..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUser.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.httpsignature - -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.userdetails.User -import java.io.Serial - -class HttpSignatureUser( - username: String, - val domain: String, - val id: Long, - credentialsNonExpired: Boolean, - accountNonLocked: Boolean, - authorities: MutableCollection? -) : User( - username, - "", - true, - true, - credentialsNonExpired, - accountNonLocked, - authorities -) { - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is HttpSignatureUser) return false - if (!super.equals(other)) return false - - if (domain != other.domain) return false - if (id != other.id) return false - - return true - } - - override fun hashCode(): Int { - var result = super.hashCode() - result = 31 * result + domain.hashCode() - result = 31 * result + id.hashCode() - return result - } - - override fun toString(): String { - return "HttpSignatureUser(" + - "domain='$domain', " + - "id=$id" + - ")" + - " ${super.toString()}" - } - - companion object { - @Serial - private const val serialVersionUID: Long = -3330552099960982997L - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUserDetailsService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUserDetailsService.kt deleted file mode 100644 index 36c61d4c..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureUserDetailsService.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.httpsignature - -import dev.usbharu.hideout.core.application.shared.Transaction -import dev.usbharu.hideout.core.domain.exception.HttpSignatureVerifyException -import dev.usbharu.hideout.util.RsaUtil -import dev.usbharu.httpsignature.common.HttpMethod -import dev.usbharu.httpsignature.common.HttpRequest -import dev.usbharu.httpsignature.common.PublicKey -import dev.usbharu.httpsignature.verify.FailedVerification -import dev.usbharu.httpsignature.verify.HttpSignatureVerifier -import dev.usbharu.httpsignature.verify.SignatureHeaderParser -import kotlinx.coroutines.runBlocking -import org.slf4j.LoggerFactory -import org.springframework.security.authentication.BadCredentialsException -import org.springframework.security.core.userdetails.AuthenticationUserDetailsService -import org.springframework.security.core.userdetails.UserDetails -import org.springframework.security.core.userdetails.UsernameNotFoundException -import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken - -class HttpSignatureUserDetailsService( - private val httpSignatureVerifier: HttpSignatureVerifier, - private val transaction: Transaction, - private val httpSignatureHeaderParser: SignatureHeaderParser, - private val actorRepository: ActorRepository -) : - AuthenticationUserDetailsService { - override fun loadUserDetails(token: PreAuthenticatedAuthenticationToken): UserDetails = runBlocking { - check(token.principal is String) { "Token is not String" } - val credentials = token.credentials - - check(credentials is HttpRequest) { "Credentials is not HttpRequest" } - - val keyId = token.principal as String - val findByKeyId = transaction.transaction { - actorRepository.findByKeyId(keyId) ?: throw UsernameNotFoundException("keyId: $keyId not found.") - } - - val signature = httpSignatureHeaderParser.parse(credentials.headers) - - val requiredHeaders = when (credentials.method) { - HttpMethod.GET -> getRequiredHeaders - HttpMethod.POST -> postRequiredHeaders - } - if (signature.headers.containsAll(requiredHeaders).not()) { - logger.warn( - "FAILED Verify HTTP Signature. required headers: {} but actual: {}", - requiredHeaders, - signature.headers - ) - throw BadCredentialsException("HTTP Signature. required headers: $requiredHeaders") - } - - @Suppress("TooGenericExceptionCaught") - val verify = try { - httpSignatureVerifier.verify( - credentials, - PublicKey(RsaUtil.decodeRsaPublicKeyPem(findByKeyId.publicKey), keyId) - ) - } catch (e: RuntimeException) { - throw BadCredentialsException("", e) - } - - if (verify is FailedVerification) { - logger.warn("FAILED Verify HTTP Signature reason: {}", verify.reason) - throw HttpSignatureVerifyException(verify.reason) - } - - HttpSignatureUser( - username = findByKeyId.name, - domain = findByKeyId.domain, - id = findByKeyId.id, - credentialsNonExpired = true, - accountNonLocked = true, - authorities = mutableListOf() - ) - } - - companion object { - private val logger = LoggerFactory.getLogger(HttpSignatureUserDetailsService::class.java) - private val postRequiredHeaders = listOf("(request-target)", "date", "host", "digest") - private val getRequiredHeaders = listOf("(request-target)", "date", "host") - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureVerifierComposite.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureVerifierComposite.kt deleted file mode 100644 index 8dd83ee3..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureVerifierComposite.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.httpsignature - -import dev.usbharu.httpsignature.common.HttpRequest -import dev.usbharu.httpsignature.common.PublicKey -import dev.usbharu.httpsignature.verify.HttpSignatureVerifier -import dev.usbharu.httpsignature.verify.SignatureHeaderParser -import dev.usbharu.httpsignature.verify.VerificationResult - -class HttpSignatureVerifierComposite( - private val map: Map, - private val httpSignatureHeaderParser: SignatureHeaderParser -) : HttpSignatureVerifier { - override fun verify(httpRequest: HttpRequest, key: PublicKey): VerificationResult { - val signature = httpSignatureHeaderParser.parse(httpRequest.headers) - val verify = map[signature.algorithm]?.verify(httpRequest, key) - if (verify != null) { - return verify - } - - throw IllegalArgumentException("Unsupported algorithm. ${signature.algorithm}") - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as HttpSignatureVerifierComposite - - if (map != other.map) return false - if (httpSignatureHeaderParser != other.httpSignatureHeaderParser) return false - - return true - } - - override fun hashCode(): Int { - var result = map.hashCode() - result = 31 * result + httpSignatureHeaderParser.hashCode() - return result - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImpl.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImpl.kt deleted file mode 100644 index 04b1f298..00000000 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/oauth2/UserDetailsServiceImpl.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.infrastructure.springframework.oauth2 - -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.core.application.shared.Transaction -import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException -import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository -import kotlinx.coroutines.runBlocking -import org.springframework.security.core.userdetails.UserDetails -import org.springframework.security.core.userdetails.UserDetailsService -import org.springframework.security.core.userdetails.UsernameNotFoundException -import org.springframework.stereotype.Service - -@Service -class UserDetailsServiceImpl( - private val applicationConfig: ApplicationConfig, - private val userDetailRepository: UserDetailRepository, - private val transaction: Transaction, - private val actorRepository: ActorRepository -) : - UserDetailsService { - override fun loadUserByUsername(username: String?): UserDetails = runBlocking { - if (username == null) { - throw UsernameNotFoundException("$username not found") - } - transaction.transaction { - val findById = - actorRepository.findByNameAndDomain(username, applicationConfig.url.host) - ?: throw UserNotFoundException.withNameAndDomain(username, applicationConfig.url.host) - - val userDetails = userDetailRepository.findByActorId(findById.id) - ?: throw UsernameNotFoundException("${findById.id} not found.") - UserDetailsImpl( - id = findById.id, - username = findById.name, - password = userDetails.password, - enabled = true, - accountNonExpired = true, - credentialsNonExpired = true, - accountNonLocked = true, - authorities = mutableListOf() - ) - } - } -} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostContentFormatter.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostContentFormatter.kt new file mode 100644 index 00000000..5819c47b --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/service/post/PostContentFormatter.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dev.usbharu.hideout.core.service.post + +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import org.jsoup.nodes.TextNode +import org.jsoup.select.Elements +import org.owasp.html.PolicyFactory +import org.springframework.stereotype.Service + + +interface PostContentFormatter { + fun format(content: String): FormattedPostContent +} + +@Service +class DefaultPostContentFormatter(private val policyFactory: PolicyFactory) : PostContentFormatter { + override fun format(content: String): FormattedPostContent { + // まず不正なHTMLを整形する + val document = Jsoup.parseBodyFragment(content) + val outputSettings = Document.OutputSettings() + outputSettings.prettyPrint(false) + + document.outputSettings(outputSettings) + + val unsafeElement = document.getElementsByTag("body").first() ?: return FormattedPostContent( + "", + "" + ) + + // 文字だけのHTMLなどはここでpタグで囲む + val flattenHtml = unsafeElement.childNodes().mapNotNull { + if (it is Element) { + it + } else if (it is TextNode) { + Element("p").appendText(it.text()) + } else { + null + } + }.filter { it.text().isNotBlank() } + + // HTMLのサニタイズをする + val unsafeHtml = Elements(flattenHtml).outerHtml() + + val safeHtml = policyFactory.sanitize(unsafeHtml) + + val safeDocument = + Jsoup.parseBodyFragment(safeHtml).getElementsByTag("body").first() ?: return FormattedPostContent("", "") + + val formattedHtml = mutableListOf() + + // 連続するbrタグを段落に変換する + for (element in safeDocument.children()) { + var brCount = 0 + var prevIndex = 0 + val childNodes = element.childNodes() + for ((index, childNode) in childNodes.withIndex()) { + if (childNode is Element && childNode.tagName() == "br") { + brCount++ + } else if (brCount >= 2) { + formattedHtml.add(Element("p").appendChildren(childNodes.subList(prevIndex, index - brCount))) + prevIndex = index + } + } + formattedHtml.add(Element("p").appendChildren(childNodes.subList(prevIndex, childNodes.size))) + } + + val elements = Elements(formattedHtml) + + return FormattedPostContent(elements.outerHtml().replace("\n", ""), printHtml(elements)) + } + + private fun printHtml(element: Elements): String { + return element.joinToString("\n\n") { + it.childNodes().joinToString("") { node -> + if (node is Element && node.tagName() == "br") { + "\n" + } else if (node is Element) { + node.text() + } else if (node is TextNode) { + node.text() + } else { + "" + } + } + } + } +} + +data class FormattedPostContent( + val html: String, + val content: String, +) \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/EqualsAndToStringTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/EqualsAndToStringTest.kt index b25ec4a2..96f3655f 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/EqualsAndToStringTest.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/EqualsAndToStringTest.kt @@ -124,7 +124,7 @@ class EqualsAndToStringTest { } try { ToStringVerifier.forClass(it).withPreset(Presets.INTELLI_J).verify() - } catch (e: Exception) { + } catch (e: Throwable) { e.printStackTrace() } } diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/AnnounceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/AnnounceTest.kt deleted file mode 100644 index ed037bd6..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/AnnounceTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.junit.jupiter.api.Test - -class AnnounceTest{ - @Test - fun mastodonのjsonをデシリアライズできる() { - //language=JSON - val json = """{ - "@context": "https://www.w3.org/ns/activitystreams", - "id": "https://kb.usbharu.dev/users/usbharu/statuses/111859915842276344/activity", - "type": "Announce", - "actor": "https://kb.usbharu.dev/users/usbharu", - "published": "2024-02-02T04:07:40Z", - "to": [ - "https://kb.usbharu.dev/users/usbharu/followers" - ], - "cc": [ - "https://kb.usbharu.dev/users/usbharu" - ], - "object": "https://kb.usbharu.dev/users/usbharu/statuses/111850484548963326" -}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - - } -} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/CreateTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/CreateTest.kt deleted file mode 100644 index ce633497..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/CreateTest.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.intellij.lang.annotations.Language -import org.junit.jupiter.api.Test - -class CreateTest { - @Test - fun Createのデイシリアライズができる() { - @Language("JSON") val json = """{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "Hashtag": "as:Hashtag", - "quoteUrl": "as:quoteUrl", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "featured": "toot:featured", - "discoverable": "toot:discoverable", - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value", - "misskey": "https://misskey-hub.net/ns#", - "_misskey_content": "misskey:_misskey_content", - "_misskey_quote": "misskey:_misskey_quote", - "_misskey_reaction": "misskey:_misskey_reaction", - "_misskey_votes": "misskey:_misskey_votes", - "isCat": "misskey:isCat", - "vcard": "http://www.w3.org/2006/vcard/ns#" - } - ], - "id": "https://misskey.usbharu.dev/notes/9f2i9cm88e/activity", - "actor": "https://misskey.usbharu.dev/users/97ws8y3rj6", - "type": "Create", - "published": "2023-05-22T14:26:53.600Z", - "object": { - "id": "https://misskey.usbharu.dev/notes/9f2i9cm88e", - "type": "Note", - "attributedTo": "https://misskey.usbharu.dev/users/97ws8y3rj6", - "content": "

@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…

", - "_misskey_content": "@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…", - "source": { - "content": "@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…", - "mediaType": "text/x.misskeymarkdown" - }, - "published": "2023-05-22T14:26:53.600Z", - "to": [ - "https://misskey.usbharu.dev/users/97ws8y3rj6/followers" - ], - "cc": [ - "https://www.w3.org/ns/activitystreams#Public", - "https://calckey.jp/users/9bu1xzwjyb" - ], - "inReplyTo": "https://calckey.jp/notes/9f2i7ymf1d", - "attachment": [], - "sensitive": false, - "tag": [ - { - "type": "Mention", - "href": "https://calckey.jp/users/9bu1xzwjyb", - "name": "@trapezial@calckey.jp" - } - ] - }, - "to": [ - "https://misskey.usbharu.dev/users/97ws8y3rj6/followers" - ], - "cc": [ - "https://www.w3.org/ns/activitystreams#Public", - "https://calckey.jp/users/9bu1xzwjyb" - ] -} -""" - - val objectMapper = ActivityPubConfig().objectMapper() - - objectMapper.readValue(json) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/DeleteSerializeTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/DeleteSerializeTest.kt deleted file mode 100644 index 6f964232..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/DeleteSerializeTest.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.activitypub.domain.Constant -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.intellij.lang.annotations.Language -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -class DeleteSerializeTest { - @Test - fun Misskeyの発行するJSONをデシリアライズできる() { - @Language("JSON") val json = """{ - "@context" : [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", { - "manuallyApprovesFollowers" : "as:manuallyApprovesFollowers", - "sensitive" : "as:sensitive", - "Hashtag" : "as:Hashtag", - "quoteUrl" : "as:quoteUrl", - "toot" : "http://joinmastodon.org/ns#", - "Emoji" : "toot:Emoji", - "featured" : "toot:featured", - "discoverable" : "toot:discoverable", - "schema" : "http://schema.org#", - "PropertyValue" : "schema:PropertyValue", - "value" : "schema:value" - } ], - "type" : "Delete", - "actor" : "https://misskey.usbharu.dev/users/97ws8y3rj6", - "object" : { - "id" : "https://misskey.usbharu.dev/notes/9lkwqnwqk9", - "type" : "Tombstone" - }, - "published" : "2023-11-02T15:30:34.160Z", - "id" : "https://misskey.usbharu.dev/4b5b6ed5-9269-45f3-8403-cba1e74b4b69" -} -""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - val expected = Delete( - actor = "https://misskey.usbharu.dev/users/97ws8y3rj6", - id = "https://misskey.usbharu.dev/4b5b6ed5-9269-45f3-8403-cba1e74b4b69", - `object` = Tombstone( - id = "https://misskey.usbharu.dev/notes/9lkwqnwqk9", - ), - published = "2023-11-02T15:30:34.160Z", - ) - expected.context = Constant.context - assertEquals(expected, readValue) - } - - @Test - fun シリアライズできる() { - val delete = Delete( - actor = "https://misskey.usbharu.dev/users/97ws8y3rj6", - id = "https://misskey.usbharu.dev/4b5b6ed5-9269-45f3-8403-cba1e74b4b69", - `object` = Tombstone( - id = "https://misskey.usbharu.dev/notes/9lkwqnwqk9", - ), - published = "2023-11-02T15:30:34.160Z", - ) - - - val objectMapper = ActivityPubConfig().objectMapper() - - val actual = objectMapper.writeValueAsString(delete) - val expected = - """{"type":"Delete","actor":"https://misskey.usbharu.dev/users/97ws8y3rj6","id":"https://misskey.usbharu.dev/4b5b6ed5-9269-45f3-8403-cba1e74b4b69","object":{"type":"Tombstone","id":"https://misskey.usbharu.dev/notes/9lkwqnwqk9"},"published":"2023-11-02T15:30:34.160Z"}""" - assertEquals(expected, actual) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/DocumentTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/DocumentTest.kt deleted file mode 100644 index 168e88d4..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/DocumentTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.intellij.lang.annotations.Language -import org.junit.jupiter.api.Test - -class DocumentTest { - @Test - fun Documentをデシリアライズできる() { - @Language("JSON") val json = """{ - "type": "Document", - "mediaType": "image/webp", - "url": "https://s3misskey.usbharu.dev/misskey-minio/misskey-minio/data/81ec9ad1-2581-466e-b90c-d9d2350ab95c.webp", - "name": "ALTテスト" - }""" - - val objectMapper = ActivityPubConfig().objectMapper() - - objectMapper.readValue(json) - } - - @Test - fun nameがnullなDocumentのデイシリアライズができる() { - //language=JSON - val json = """{ - "type": "Document", - "mediaType": "image/webp", - "url": "https://s3misskey.usbharu.dev/misskey-minio/misskey-minio/data/81ec9ad1-2581-466e-b90c-d9d2350ab95c.webp", - "name": null - }""" - - val objectMapper = ActivityPubConfig().objectMapper() - - objectMapper.readValue(json) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/JsonLdSerializeTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/JsonLdSerializeTest.kt deleted file mode 100644 index 9c9530cc..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/JsonLdSerializeTest.kt +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -class JsonLdSerializeTest { - @Test - fun contextが文字列のときデシリアライズできる() { - //language=JSON - val json = """{"@context":"https://example.com"}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - assertEquals(JsonLd(listOf(StringOrObject("https://example.com"))), readValue) - } - - @Test - fun contextが文字列の配列のときデシリアライズできる() { - //language=JSON - val json = """{"@context":["https://example.com","https://www.w3.org/ns/activitystreams"]}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - assertEquals( - JsonLd( - listOf( - StringOrObject("https://example.com"), - StringOrObject("https://www.w3.org/ns/activitystreams") - ) - ), readValue - ) - } - - @Test - fun contextがnullのとき空のlistとして解釈してデシリアライズする() { - //language=JSON - val json = """{"@context":null}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - assertEquals(JsonLd(emptyList()), readValue) - } - - @Test - fun contextがnullを含む文字列の配列のときnullを無視してデシリアライズできる() { - //language=JSON - val json = """{"@context":["https://example.com",null,"https://www.w3.org/ns/activitystreams"]}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - assertEquals( - JsonLd( - listOf( - StringOrObject("https://example.com"), - StringOrObject("https://www.w3.org/ns/activitystreams") - ) - ), readValue - ) - } - - @Test - fun contextがオブジェクトのとき無視してデシリアライズする() { - //language=JSON - val json = """{"@context":{"hoge": "fuga"}}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - assertEquals(JsonLd(listOf(StringOrObject(mapOf("hoge" to "fuga")))), readValue) - } - - @Test - fun contextがオブジェクトを含む文字列の配列のときオブジェクトを無視してデシリアライズする() { - //language=JSON - val json = """{"@context":["https://example.com",{"hoge": "fuga"},"https://www.w3.org/ns/activitystreams"]}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - assertEquals( - JsonLd( - listOf( - StringOrObject("https://example.com"), - StringOrObject(mapOf("hoge" to "fuga")), - StringOrObject("https://www.w3.org/ns/activitystreams") - ) - ), readValue - ) - } - - @Test - fun contextが配列の配列のとき無視してデシリアライズする() { - //language=JSON - val json = """{"@context":[["a","b"],["c","d"]]}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - assertEquals(JsonLd(emptyList()), readValue) - } - - @Test - fun contextが空のとき無視してシリアライズする() { - val jsonLd = JsonLd(emptyList()) - - val objectMapper = ActivityPubConfig().objectMapper() - - val actual = objectMapper.writeValueAsString(jsonLd) - - assertEquals("{}", actual) - } - - @Test - fun contextがnullのとき無視してシリアライズする() { - val jsonLd = JsonLd(listOf(null)) - - val objectMapper = ActivityPubConfig().objectMapper() - - val actual = objectMapper.writeValueAsString(jsonLd) - - assertEquals("{}", actual) - } - - @Test - fun contextが文字列のとき文字列としてシリアライズされる() { - val jsonLd = JsonLd(listOf(StringOrObject("https://example.com"))) - - val objectMapper = ActivityPubConfig().objectMapper() - - val actual = objectMapper.writeValueAsString(jsonLd) - - assertEquals("""{"@context":"https://example.com"}""", actual) - } - - @Test - fun contextが文字列の配列のとき配列としてシリアライズされる() { - val jsonLd = JsonLd( - listOf( - StringOrObject("https://example.com"), - StringOrObject("https://www.w3.org/ns/activitystreams") - ) - ) - - val objectMapper = ActivityPubConfig().objectMapper() - - val actual = objectMapper.writeValueAsString(jsonLd) - - assertEquals("""{"@context":["https://example.com","https://www.w3.org/ns/activitystreams"]}""", actual) - } - - @Test - fun contextがオブジェクトのときシリアライズできる() { - val jsonLd = JsonLd( - listOf( - StringOrObject(mapOf("hoge" to "fuga")) - ) - ) - - val objectMapper = ActivityPubConfig().objectMapper() - - val actual = objectMapper.writeValueAsString(jsonLd) - - assertEquals("""{"@context":{"hoge":"fuga"}}""", actual) - - } - - @Test - fun contextが複数のオブジェクトのときシリアライズできる() { - val jsonLd = JsonLd( - listOf( - StringOrObject(mapOf("hoge" to "fuga")), - StringOrObject(mapOf("foo" to "bar")) - ) - ) - - val objectMapper = ActivityPubConfig().objectMapper() - - val actual = objectMapper.writeValueAsString(jsonLd) - - assertEquals("""{"@context":[{"hoge":"fuga"},{"foo":"bar"}]}""", actual) - } - - @Test - fun contextが複数のオブジェクトのときデシリアライズできる() { - //language=JSON - val json = """{"@context":["https://example.com",{"hoge": "fuga"},{"foo": "bar"}]}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - assertEquals( - JsonLd( - listOf( - StringOrObject("https://example.com"), - StringOrObject(mapOf("hoge" to "fuga")), - StringOrObject(mapOf("foo" to "bar")) - ) - ), readValue - ) - } - - @Test - fun contextがオブジェクトのときデシリアライズできる() { - //language=JSON - val json = """{"@context":{"hoge": "fuga"}}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - assertEquals( - JsonLd( - listOf( - StringOrObject(mapOf("hoge" to "fuga")) - ) - ), readValue - ) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/KeySerializeTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/KeySerializeTest.kt deleted file mode 100644 index c0ffbfaf..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/KeySerializeTest.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.junit.jupiter.api.Test - -class KeySerializeTest { - @Test - fun Keyのデシリアライズができる() { - //language=JSON - val trimIndent = """ - { - "id": "https://mastodon.social/users/Gargron#main-key", - "owner": "https://mastodon.social/users/Gargron", - "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvXc4vkECU2/CeuSo1wtn\nFoim94Ne1jBMYxTZ9wm2YTdJq1oiZKif06I2fOqDzY/4q/S9uccrE9Bkajv1dnkO\nVm31QjWlhVpSKynVxEWjVBO5Ienue8gND0xvHIuXf87o61poqjEoepvsQFElA5ym\novljWGSA/jpj7ozygUZhCXtaS2W5AD5tnBQUpcO0lhItYPYTjnmzcc4y2NbJV8hz\n2s2G8qKv8fyimE23gY1XrPJg+cRF+g4PqFXujjlJ7MihD9oqtLGxbu7o1cifTn3x\nBfIdPythWu5b4cujNsB3m3awJjVmx+MHQ9SugkSIYXV0Ina77cTNS0M2PYiH1PFR\nTwIDAQAB\n-----END PUBLIC KEY-----\n" - } - """.trimIndent() - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(trimIndent) - - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/NoteSerializeTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/NoteSerializeTest.kt deleted file mode 100644 index 8c4b3f9d..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/NoteSerializeTest.kt +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.activitypub.domain.Constant -import dev.usbharu.hideout.activitypub.service.objects.note.APNoteServiceImpl.Companion.public -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -class NoteSerializeTest { - @Test - fun Noteのシリアライズができる() { - val note = Note( - id = "https://example.com", - attributedTo = "https://example.com/actor", - content = "Hello", - published = "2023-05-20T10:28:17.308Z", - ) - - val objectMapper = ActivityPubConfig().objectMapper() - - val writeValueAsString = objectMapper.writeValueAsString(note) - - assertEquals( - """{"type":"Note","id":"https://example.com","attributedTo":"https://example.com/actor","content":"Hello","published":"2023-05-20T10:28:17.308Z","sensitive":false}""", - writeValueAsString - ) - } - - @Test - fun Noteのデシリアライズができる() { - //language=JSON - val json = """{ - "id": "https://misskey.usbharu.dev/notes/9f2i9cm88e", - "type": "Note", - "attributedTo": "https://misskey.usbharu.dev/users/97ws8y3rj6", - "content": "

@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…

", - "_misskey_content": "@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…", - "source": { - "content": "@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…", - "mediaType": "text/x.misskeymarkdown" - }, - "published": "2023-05-22T14:26:53.600Z", - "to": [ - "https://misskey.usbharu.dev/users/97ws8y3rj6/followers" - ], - "cc": [ - "https://www.w3.org/ns/activitystreams#Public", - "https://calckey.jp/users/9bu1xzwjyb" - ], - "inReplyTo": "https://calckey.jp/notes/9f2i7ymf1d", - "attachment": [], - "sensitive": false, - "tag": [ - - ] - }""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - val note = Note( - id = "https://misskey.usbharu.dev/notes/9f2i9cm88e", - type = listOf("Note"), - attributedTo = "https://misskey.usbharu.dev/users/97ws8y3rj6", - content = "

@trapezial@calckey.jp いやそういうことじゃなくて、連合先と自インスタンスで状態が狂うことが多いのでどっちに合わせるべきかと…

", - published = "2023-05-22T14:26:53.600Z", - to = listOf("https://misskey.usbharu.dev/users/97ws8y3rj6/followers"), - cc = listOf(public, "https://calckey.jp/users/9bu1xzwjyb"), - sensitive = false, - inReplyTo = "https://calckey.jp/notes/9f2i7ymf1d", - attachment = emptyList() - ) - assertEquals(note, readValue) - } - - @Test - fun 絵文字付きNoteのデシリアライズができる() { - val json = """{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "Hashtag": "as:Hashtag", - "quoteUrl": "as:quoteUrl", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "featured": "toot:featured", - "discoverable": "toot:discoverable", - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value" - } - ], - "id": "https://misskey.usbharu.dev/notes/9nj1omt1rn", - "type": "Note", - "attributedTo": "https://misskey.usbharu.dev/users/97ws8y3rj6", - "content": "

​:oyasumi:​

", - "_misskey_content": ":oyasumi:", - "source": { - "content": ":oyasumi:", - "mediaType": "text/x.misskeymarkdown" - }, - "published": "2023-12-21T17:32:36.853Z", - "to": [ - "https://www.w3.org/ns/activitystreams#Public" - ], - "cc": [ - "https://misskey.usbharu.dev/users/97ws8y3rj6/followers" - ], - "inReplyTo": null, - "attachment": [], - "sensitive": false, - "tag": [ - { - "id": "https://misskey.usbharu.dev/emojis/oyasumi", - "type": "Emoji", - "name": ":oyasumi:", - "updated": "2023-04-07T08:21:25.246Z", - "icon": { - "type": "Image", - "mediaType": "image/png", - "url": "https://s3misskey.usbharu.dev/misskey-minio/misskey-minio/data/cf8db710-1d70-4076-8a00-dbb28131096e.png" - } - } - ] -}""" - - - val objectMapper = ActivityPubConfig().objectMapper() - - val expected = Note( - type = emptyList(), - id = "https://misskey.usbharu.dev/notes/9nj1omt1rn", - attributedTo = "https://misskey.usbharu.dev/users/97ws8y3rj6", - content = "

\u200B:oyasumi:\u200B

", - published = "2023-12-21T17:32:36.853Z", - to = listOf("https://www.w3.org/ns/activitystreams#Public"), - cc = listOf("https://misskey.usbharu.dev/users/97ws8y3rj6/followers"), - sensitive = false, - inReplyTo = null, - attachment = emptyList(), - tag = listOf( - Emoji( - type = emptyList(), - name = ":oyasumi:", - id = "https://misskey.usbharu.dev/emojis/oyasumi", - updated = "2023-04-07T08:21:25.246Z", - icon = Image( - type = emptyList(), - mediaType = "image/png", - url = "https://s3misskey.usbharu.dev/misskey-minio/misskey-minio/data/cf8db710-1d70-4076-8a00-dbb28131096e.png" - ) - ) - ) - ) - - expected.context = Constant.context - - val note = objectMapper.readValue(json) - - assertThat(note).isEqualTo(expected) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/PersonSerializeTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/PersonSerializeTest.kt deleted file mode 100644 index ddd39162..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/PersonSerializeTest.kt +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.junit.jupiter.api.Test - -class PersonSerializeTest { - @Test - fun MastodonのPersonのデシリアライズができる() { - val personString = """ - { - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1" - ], - "id": "https://mastodon.social/users/Gargron", - "type": "Person", - "following": "https://mastodon.social/users/Gargron/following", - "followers": "https://mastodon.social/users/Gargron/followers", - "inbox": "https://mastodon.social/users/Gargron/inbox", - "outbox": "https://mastodon.social/users/Gargron/outbox", - "featured": "https://mastodon.social/users/Gargron/collections/featured", - "featuredTags": "https://mastodon.social/users/Gargron/collections/tags", - "preferredUsername": "Gargron", - "name": "Eugen Rochko", - "summary": "\u003cp\u003eFounder, CEO and lead developer \u003cspan class=\"h-card\"\u003e\u003ca href=\"https://mastodon.social/@Mastodon\" class=\"u-url mention\"\u003e@\u003cspan\u003eMastodon\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e, Germany.\u003c/p\u003e", - "url": "https://mastodon.social/@Gargron", - "manuallyApprovesFollowers": false, - "discoverable": true, - "published": "2016-03-16T00:00:00Z", - "devices": "https://mastodon.social/users/Gargron/collections/devices", - "alsoKnownAs": [ - "https://tooting.ai/users/Gargron" - ], - "publicKey": { - "id": "https://mastodon.social/users/Gargron#main-key", - "owner": "https://mastodon.social/users/Gargron", - "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvXc4vkECU2/CeuSo1wtn\nFoim94Ne1jBMYxTZ9wm2YTdJq1oiZKif06I2fOqDzY/4q/S9uccrE9Bkajv1dnkO\nVm31QjWlhVpSKynVxEWjVBO5Ienue8gND0xvHIuXf87o61poqjEoepvsQFElA5ym\novljWGSA/jpj7ozygUZhCXtaS2W5AD5tnBQUpcO0lhItYPYTjnmzcc4y2NbJV8hz\n2s2G8qKv8fyimE23gY1XrPJg+cRF+g4PqFXujjlJ7MihD9oqtLGxbu7o1cifTn3x\nBfIdPythWu5b4cujNsB3m3awJjVmx+MHQ9SugkSIYXV0Ina77cTNS0M2PYiH1PFR\nTwIDAQAB\n-----END PUBLIC KEY-----\n" - }, - "tag": [], - "attachment": [ - { - "type": "PropertyValue", - "name": "Patreon", - "value": "\u003ca href=\"https://www.patreon.com/mastodon\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"\u003e\u003cspan class=\"invisible\"\u003ehttps://www.\u003c/span\u003e\u003cspan class=\"\"\u003epatreon.com/mastodon\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e" - }, - { - "type": "PropertyValue", - "name": "GitHub", - "value": "\u003ca href=\"https://github.com/Gargron\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003egithub.com/Gargron\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e" - } - ], - "endpoints": { - "sharedInbox": "https://mastodon.social/inbox" - }, - "icon": { - "type": "Image", - "mediaType": "image/jpeg", - "url": "https://files.mastodon.social/accounts/avatars/000/000/001/original/dc4286ceb8fab734.jpg" - }, - "image": { - "type": "Image", - "mediaType": "image/jpeg", - "url": "https://files.mastodon.social/accounts/headers/000/000/001/original/3b91c9965d00888b.jpeg" - } - } - - """.trimIndent() - - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(personString) - } - - @Test - fun MisskeyのnameがnullのPersonのデシリアライズができる() { - //language=JSON - val json = """{ - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "Hashtag": "as:Hashtag", - "quoteUrl": "as:quoteUrl", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "featured": "toot:featured", - "discoverable": "toot:discoverable", - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value", - "misskey": "https://misskey-hub.net/ns#", - "_misskey_content": "misskey:_misskey_content", - "_misskey_quote": "misskey:_misskey_quote", - "_misskey_reaction": "misskey:_misskey_reaction", - "_misskey_votes": "misskey:_misskey_votes", - "_misskey_summary": "misskey:_misskey_summary", - "isCat": "misskey:isCat", - "vcard": "http://www.w3.org/2006/vcard/ns#" - } - ], - "type": "Person", - "id": "https://misskey.usbharu.dev/users/9ghwhv9zgg", - "inbox": "https://misskey.usbharu.dev/users/9ghwhv9zgg/inbox", - "outbox": "https://misskey.usbharu.dev/users/9ghwhv9zgg/outbox", - "followers": "https://misskey.usbharu.dev/users/9ghwhv9zgg/followers", - "following": "https://misskey.usbharu.dev/users/9ghwhv9zgg/following", - "featured": "https://misskey.usbharu.dev/users/9ghwhv9zgg/collections/featured", - "sharedInbox": "https://misskey.usbharu.dev/inbox", - "endpoints": { - "sharedInbox": "https://misskey.usbharu.dev/inbox" - }, - "url": "https://misskey.usbharu.dev/@relay_test", - "preferredUsername": "relay_test", - "name": null, - "summary": null, - "_misskey_summary": null, - "icon": null, - "image": null, - "tag": [], - "manuallyApprovesFollowers": true, - "discoverable": true, - "publicKey": { - "id": "https://misskey.usbharu.dev/users/9ghwhv9zgg#main-key", - "type": "Key", - "owner": "https://misskey.usbharu.dev/users/9ghwhv9zgg", - "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2n5yekTaI4ex5VDWzQfE\nJpWMURAMWl8RcXHLPyLQVQ/PrHp7qatGXmKJUnAOBcq1cwk+VCqTEqx8vJCOZsr1\nMq+D3FMcFdwgtJ0nivPJPx2457b5kfQ4LTkWajcFhj2qixa/XFq6hHei3LDaE6hJ\nGQbdj9NTVlMd7VpiFQkoU09vAPUwGxRoP9Qbc/sh7jrKYFB3iRmY/+zOc+PFpnfn\nG8V1d2v+lnkb9f7t0Z8y2ckk6TVcLPRZktF15eGClVptlgts3hwhrcyrpBs2Dn0U\n35KgIhkhZGAjzk0uyplpfKcserXuGvsjJvelZ3BtMGsuR4kGLHrmiRQp23mIoA1I\n8tfVuV0zPOyO3ruLk2fOjoeZ4XvFHGRNKo66Qx055/8G8Ug5vU8lvIGXm9sflaA9\ntR3AKDNsyxEfjAfrfgJ7cwlKSlLZmkU51jtYEqJ48ZkiIa6fMC0m4QGXdaXmhFWC\no1sGoIErRFpRHewdGlLC9S8R/cMxjex+n8maF0yh79y7aVvU+TS6pRWg5wYjY8r3\nZqAVg/PGRVGAbjVdIdcsjH5ClwAFBW16S633D3m7HJypwwVCzVOvMZqPqcQ/2o8c\nUk+xa88xQG+OPqoAaQqyV9iqsmCMgYM/AcX/BC2h7L2mE/PWoXnoCxGPxr5uvyBf\nHQakDGg4pFZcpVNrDlYo260CAwEAAQ==\n-----END PUBLIC KEY-----\n" - }, - "isCat": false -}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - objectMapper.readValue(json) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/RejectTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/RejectTest.kt deleted file mode 100644 index 65e26aac..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/RejectTest.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.activitypub.domain.Constant -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.assertj.core.api.Assertions.assertThat -import org.intellij.lang.annotations.Language -import org.junit.jupiter.api.Test -import org.springframework.boot.test.json.BasicJsonTester - -class RejectTest { - @Test - fun rejectDeserializeTest() { - @Language("JSON") val json = """{ - "@context" : [ "https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", { - "manuallyApprovesFollowers" : "as:manuallyApprovesFollowers", - "sensitive" : "as:sensitive", - "Hashtag" : "as:Hashtag", - "quoteUrl" : "as:quoteUrl", - "toot" : "http://joinmastodon.org/ns#", - "Emoji" : "toot:Emoji", - "featured" : "toot:featured", - "discoverable" : "toot:discoverable", - "schema" : "http://schema.org#", - "PropertyValue" : "schema:PropertyValue", - "value" : "schema:value" - } ], - "type" : "Reject", - "actor" : "https://misskey.usbharu.dev/users/97ws8y3rj6", - "object" : { - "id" : "https://misskey.usbharu.dev/follows/9mxh6mawru/97ws8y3rj6", - "type" : "Follow", - "actor" : "https://test-hideout.usbharu.dev/users/test-user2", - "object" : "https://misskey.usbharu.dev/users/97ws8y3rj6" - }, - "id" : "https://misskey.usbharu.dev/06407419-5aeb-4e2d-8885-aa54b03decf0" -} -""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val reject = objectMapper.readValue(json) - - val expected = Reject( - "https://misskey.usbharu.dev/users/97ws8y3rj6", - "https://misskey.usbharu.dev/06407419-5aeb-4e2d-8885-aa54b03decf0", - Follow( - apObject = "https://misskey.usbharu.dev/users/97ws8y3rj6", - actor = "https://test-hideout.usbharu.dev/users/test-user2", - id = "https://misskey.usbharu.dev/follows/9mxh6mawru/97ws8y3rj6" - ) - ).apply { - context = Constant.context - } - - assertThat(reject).isEqualTo(expected) - } - - @Test - fun rejectSerializeTest() { - val basicJsonTester = BasicJsonTester(javaClass) - - val reject = Reject( - "https://misskey.usbharu.dev/users/97ws8y3rj6", - "https://misskey.usbharu.dev/06407419-5aeb-4e2d-8885-aa54b03decf0", - Follow( - apObject = "https://misskey.usbharu.dev/users/97ws8y3rj6", - actor = "https://test-hideout.usbharu.dev/users/test-user2" - ) - ).apply { - context = listOf( - StringOrObject("https://www.w3.org/ns/activitystreams"), - StringOrObject("https://w3id.org/security/v1") - ) - } - - val objectMapper = ActivityPubConfig().objectMapper() - - val writeValueAsString = objectMapper.writeValueAsString(reject) - - val from = basicJsonTester.from(writeValueAsString) - - assertThat(from).extractingJsonPathStringValue("$.actor") - .isEqualTo("https://misskey.usbharu.dev/users/97ws8y3rj6") - assertThat(from).extractingJsonPathStringValue("$.id") - .isEqualTo("https://misskey.usbharu.dev/06407419-5aeb-4e2d-8885-aa54b03decf0") - assertThat(from).extractingJsonPathStringValue("$.type").isEqualTo("Reject") - assertThat(from).extractingJsonPathStringValue("$.object.actor") - .isEqualTo("https://test-hideout.usbharu.dev/users/test-user2") - assertThat(from).extractingJsonPathStringValue("$.object.object") - .isEqualTo("https://misskey.usbharu.dev/users/97ws8y3rj6") - assertThat(from).extractingJsonPathStringValue("$.object.type").isEqualTo("Follow") - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/UndoTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/UndoTest.kt deleted file mode 100644 index f4688916..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/UndoTest.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model - -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.intellij.lang.annotations.Language -import org.junit.jupiter.api.Test -import java.time.Clock -import java.time.Instant -import java.time.ZoneId - -class UndoTest { - @Test - fun Undoのシリアライズができる() { - val undo = Undo( - emptyList(), - "https://follower.example.com/", - "https://follower.example.com/undo/1", - Follow( - emptyList(), - "https://follower.example.com/users/", - actor = "https://follower.exaple.com/users/1" - ), - Instant.now(Clock.tickMillis(ZoneId.systemDefault())).toString() - ) - val writeValueAsString = ActivityPubConfig().objectMapper().writeValueAsString(undo) - println(writeValueAsString) - } - - @Test - fun Undoをデシリアライズ出来る() { - @Language("JSON") - val json = """ - { - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "Hashtag": "as:Hashtag", - "quoteUrl": "as:quoteUrl", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "featured": "toot:featured", - "discoverable": "toot:discoverable", - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value", - "misskey": "https://misskey-hub.net/ns#", - "_misskey_content": "misskey:_misskey_content", - "_misskey_quote": "misskey:_misskey_quote", - "_misskey_reaction": "misskey:_misskey_reaction", - "_misskey_votes": "misskey:_misskey_votes", - "isCat": "misskey:isCat", - "vcard": "http://www.w3.org/2006/vcard/ns#" - } - ], - "type": "Undo", - "id": "https://misskey.usbharu.dev/follows/97ws8y3rj6/9ezbh8qrh0/undo", - "actor": "https://misskey.usbharu.dev/users/97ws8y3rj6", - "object": { - "id": "https://misskey.usbharu.dev/follows/97ws8y3rj6/9ezbh8qrh0", - "type": "Follow", - "actor": "https://misskey.usbharu.dev/users/97ws8y3rj6", - "object": "https://test-hideout.usbharu.dev/users/test" - }, - "published": "2023-05-20T10:28:17.308Z" -} - - """.trimIndent() - - val undo = ActivityPubConfig().objectMapper().readValue(json, Undo::class.java) - println(undo) - } - - @Test - fun MastodonのUndoのデシリアライズができる() { - //language=JSON - val json = """{ - "@context" : "https://www.w3.org/ns/activitystreams", - "id" : "https://kb.usbharu.dev/users/usbharu#follows/12/undo", - "type" : "Undo", - "actor" : "https://kb.usbharu.dev/users/usbharu", - "object" : { - "id" : "https://kb.usbharu.dev/0347b269-4dcb-4eb1-b8c4-b5f157bb6957", - "type" : "Follow", - "actor" : "https://kb.usbharu.dev/users/usbharu", - "object" : "https://test-hideout.usbharu.dev/users/testuser15" - } -}""".trimIndent() - - val undo = ActivityPubConfig().objectMapper().readValue(json, Undo::class.java) - - println(undo) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/objects/ObjectSerializeTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/objects/ObjectSerializeTest.kt deleted file mode 100644 index a4981fe9..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/domain/model/objects/ObjectSerializeTest.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.domain.model.objects - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.application.config.ActivityPubConfig -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -class ObjectSerializeTest { - @Test - fun typeが文字列のときデシリアライズできる() { - //language=JSON - val json = """{"type": "Object"}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - val expected = Object( - listOf("Object") - ) - assertEquals(expected, readValue) - } - - @Test - fun typeが文字列の配列のときデシリアライズできる() { - //language=JSON - val json = """{"type": ["Hoge","Object"]}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - val expected = Object( - listOf("Hoge", "Object") - ) - - assertEquals(expected, readValue) - } - - @Test - fun typeが空のとき無視してデシリアライズする() { - //language=JSON - val json = """{"type": ""}""" - - val objectMapper = ActivityPubConfig().objectMapper() - - val readValue = objectMapper.readValue(json) - - val expected = Object( - emptyList() - ) - - assertEquals(expected, readValue) - } - -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/actor/ActorAPControllerImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/actor/ActorAPControllerImplTest.kt deleted file mode 100644 index 76239bdd..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/actor/ActorAPControllerImplTest.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.interfaces.api.actor - -import dev.usbharu.hideout.activitypub.domain.model.Image -import dev.usbharu.hideout.activitypub.domain.model.Key -import dev.usbharu.hideout.activitypub.domain.model.Person -import dev.usbharu.hideout.activitypub.service.objects.user.APUserService -import dev.usbharu.hideout.application.config.ActivityPubConfig -import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -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.doReturn -import org.mockito.kotlin.doThrow -import org.mockito.kotlin.eq -import org.mockito.kotlin.whenever -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.get -import org.springframework.test.web.servlet.post -import org.springframework.test.web.servlet.setup.MockMvcBuilders - -@ExtendWith(MockitoExtension::class) -class ActorAPControllerImplTest { - - private lateinit var mockMvc: MockMvc - - @Mock - private lateinit var apUserService: APUserService - - @InjectMocks - private lateinit var userAPControllerImpl: UserAPControllerImpl - - @BeforeEach - fun setUp() { - mockMvc = MockMvcBuilders - .standaloneSetup(userAPControllerImpl) - .setMessageConverters(MappingJackson2HttpMessageConverter(ActivityPubConfig().objectMapper())) - .build() - } - - @Test - fun `userAp 存在するユーザーにGETするとPersonが返ってくる`(): Unit = runTest { - val person = Person( - name = "Hoge", - id = "https://example.com/users/hoge", - preferredUsername = "hoge", - summary = "fuga", - inbox = "https://example.com/users/hoge/inbox", - outbox = "https://example.com/users/hoge/outbox", - url = "https://example.com/users/hoge", - icon = Image( - mediaType = "image/jpeg", - url = "https://example.com/users/hoge/icon.jpg" - ), - publicKey = Key( - id = "https://example.com/users/hoge#pubkey", - owner = "https://example.com/users/hoge", - publicKeyPem = "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----" - ), - endpoints = mapOf("sharedInbox" to "https://example.com/inbox"), - followers = "https://example.com/users/hoge/followers", - following = "https://example.com/users/hoge/following", - manuallyApprovesFollowers = false - ) - whenever(apUserService.getPersonByName(eq("hoge"))).doReturn(person) - - val objectMapper = ActivityPubConfig().objectMapper() - - mockMvc - .get("/users/hoge") - .asyncDispatch() - .andDo { print() } - .andExpect { status { isOk() } } - .andExpect { content { this.json(objectMapper.writeValueAsString(person)) } } - } - - @Test - fun `userAP 存在しないユーザーにGETすると404が返ってくる`() = runTest { - whenever(apUserService.getPersonByName(eq("fuga"))).doThrow(UserNotFoundException::class) - - mockMvc - .get("/users/fuga") - .asyncDispatch() - .andExpect { status { isNotFound() } } - } - - @Test - fun `userAP POSTすると405が返ってくる`() { - mockMvc - .post("/users/hoge") - .andExpect { status { isMethodNotAllowed() } } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/inbox/InboxControllerImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/inbox/InboxControllerImplTest.kt deleted file mode 100644 index 5ff88e2f..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/inbox/InboxControllerImplTest.kt +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.interfaces.api.inbox - -import dev.usbharu.hideout.activitypub.domain.exception.JsonParseException -import dev.usbharu.hideout.activitypub.service.common.APService -import dev.usbharu.hideout.activitypub.service.common.ActivityType -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException -import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureHeaderChecker -import dev.usbharu.hideout.util.Base64Util -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -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.* -import org.springframework.http.MediaType -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.get -import org.springframework.test.web.servlet.post -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import java.net.URI -import java.security.MessageDigest -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.util.* - -@ExtendWith(MockitoExtension::class) -class InboxControllerImplTest { - - private lateinit var mockMvc: MockMvc - - @Spy - private val httpSignatureHeaderChecker = - HttpSignatureHeaderChecker(ApplicationConfig(URI.create("https://example.com").toURL())) - - @Mock - private lateinit var apService: APService - - @InjectMocks - private lateinit var inboxController: InboxControllerImpl - - @BeforeEach - fun setUp() { - mockMvc = MockMvcBuilders.standaloneSetup(inboxController).build() - } - - - private val dateTimeFormatter: DateTimeFormatter = - DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - - @Test - fun `inbox 正常なPOSTリクエストをしたときAcceptが返ってくる`() = runTest { - - - val json = """{"type":"Follow"}""" - whenever(apService.parseActivity(eq(json))).doReturn(ActivityType.Follow) - whenever( - apService.processActivity( - eq(json), eq(ActivityType.Follow), any(), any() - - ) - ).doReturn(Unit) - - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - - mockMvc.post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "a") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=" + digest) - }.asyncDispatch().andExpect { - status { isAccepted() } - } - - } - - @Test - fun `inbox parseActivityに失敗したときAcceptが返ってくる`() = runTest { - val json = """{"type":"Hoge"}""" - whenever(apService.parseActivity(eq(json))).doThrow(JsonParseException::class) - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - mockMvc.post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "a") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - }.asyncDispatch().andExpect { - status { isAccepted() } - } - - } - - @Test - fun `inbox processActivityに失敗したときAcceptが返ってくる`() = runTest { - val json = """{"type":"Follow"}""" - whenever(apService.parseActivity(eq(json))).doReturn(ActivityType.Follow) - whenever( - apService.processActivity( - eq(json), eq(ActivityType.Follow), any(), any() - ) - ).doThrow(FailedToGetResourcesException::class) - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - mockMvc.post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "a") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - }.asyncDispatch().andExpect { - status { isAccepted() } - } - - } - - @Test - fun `inbox GETリクエストには405を返す`() { - mockMvc.get("/inbox").andExpect { status { isMethodNotAllowed() } } - } - - @Test - fun `user-inbox 正常なPOSTリクエストをしたときAcceptが返ってくる`() = runTest { - - - val json = """{"type":"Follow"}""" - whenever(apService.parseActivity(eq(json))).doReturn(ActivityType.Follow) - whenever(apService.processActivity(eq(json), eq(ActivityType.Follow), any(), any())).doReturn( - Unit - ) - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - mockMvc.post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "a") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - }.asyncDispatch().andExpect { - status { isAccepted() } - } - - } - - @Test - fun `user-inbox parseActivityに失敗したときAcceptが返ってくる`() = runTest { - val json = """{"type":"Hoge"}""" - whenever(apService.parseActivity(eq(json))).doThrow(JsonParseException::class) - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - mockMvc.post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "a") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - }.asyncDispatch().andExpect { - status { isAccepted() } - } - - } - - @Test - fun `user-inbox processActivityに失敗したときAcceptが返ってくる`() = runTest { - val json = """{"type":"Follow"}""" - whenever(apService.parseActivity(eq(json))).doReturn(ActivityType.Follow) - whenever( - apService.processActivity( - eq(json), eq(ActivityType.Follow), any(), any() - ) - ).doThrow(FailedToGetResourcesException::class) - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - mockMvc.post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "a") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - }.asyncDispatch().andExpect { - status { isAccepted() } - } - - } - - @Test - fun `user-inbox GETリクエストには405を返す`() { - mockMvc.get("/users/hoge/inbox").andExpect { status { isMethodNotAllowed() } } - } - - @Test - fun `inbox Dateヘッダーが無いと400`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - } - .asyncDispatch() - .andExpect { - status { - isBadRequest() - } - } - } - - @Test - fun `user-inbox Dateヘッダーが無いと400`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - } - .asyncDispatch() - .andExpect { - status { - isBadRequest() - } - } - } - - @Test - fun `inbox Dateヘッダーが未来だと401`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Date", ZonedDateTime.now().plusDays(1).format(dateTimeFormatter)) - } - .asyncDispatch() - .andExpect { - status { - isUnauthorized() - } - } - } - - @Test - fun `user-inbox Dateヘッダーが未来だと401`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Date", ZonedDateTime.now().plusDays(1).format(dateTimeFormatter)) - } - .asyncDispatch() - .andExpect { - status { - isUnauthorized() - } - } - } - - @Test - fun `inbox Dateヘッダーが過去過ぎると401`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Date", ZonedDateTime.now().minusDays(1).format(dateTimeFormatter)) - } - .asyncDispatch() - .andExpect { - status { - isUnauthorized() - } - } - } - - @Test - fun `user-inbox Dateヘッダーが過去過ぎると401`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Date", ZonedDateTime.now().minusDays(1).format(dateTimeFormatter)) - } - .asyncDispatch() - .andExpect { - status { - isUnauthorized() - } - } - } - - @Test - fun `inbox Hostヘッダーが無いと400`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - } - .asyncDispatch() - .andExpect { - status { - isBadRequest() - } - } - } - - @Test - fun `user-inbox Hostヘッダーが無いと400`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - } - .asyncDispatch() - .andExpect { - status { - isBadRequest() - } - } - } - - @Test - fun `inbox Hostヘッダーが間違ってると401`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Host", "example.jp") - } - .asyncDispatch() - .andExpect { - status { - isUnauthorized() - } - } - } - - @Test - fun `user-inbox Hostヘッダーが間違ってると401`() { - val json = """{"type":"Follow"}""" - mockMvc - .post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Host", "example.jp") - } - .asyncDispatch() - .andExpect { - status { - isUnauthorized() - } - } - } - - @Test - fun `inbox Digestヘッダーがないと400`() = runTest { - - - val json = """{"type":"Follow"}""" - - mockMvc - .post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - } - .asyncDispatch() - .andExpect { - status { isBadRequest() } - } - - } - - @Test - fun `inbox Digestヘッダーが間違ってると401`() = runTest { - val json = """{"type":"Follow"}""" - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(("$json aaaaaaaa").toByteArray())) - - mockMvc - .post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - } - .asyncDispatch() - .andExpect { - status { isUnauthorized() } - } - } - - @Test - fun `user-inbox Digestヘッダーがないと400`() = runTest { - - - val json = """{"type":"Follow"}""" - - mockMvc - .post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - } - .asyncDispatch() - .andExpect { - status { isBadRequest() } - } - - } - - @Test - fun `user-inbox Digestヘッダーが間違ってると401`() = runTest { - val json = """{"type":"Follow"}""" - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(("$json aaaaaaaa").toByteArray())) - - mockMvc - .post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - } - .asyncDispatch() - .andExpect { - status { isUnauthorized() } - } - } - - @Test - fun `inbox Signatureヘッダーがないと401`() = runTest { - - - val json = """{"type":"Follow"}""" - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - - mockMvc - .post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - } - .asyncDispatch() - .andExpect { - status { isUnauthorized() } - } - - } - - @Test - fun `inbox Signatureヘッダーが空だと401`() = runTest { - val json = """{"type":"Follow"}""" - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - - mockMvc - .post("/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - } - .asyncDispatch() - .andExpect { - status { isUnauthorized() } - } - } - - @Test - fun `user-inbox Digestヘッダーがないと401`() = runTest { - - val json = """{"type":"Follow"}""" - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - mockMvc - .post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - } - .asyncDispatch() - .andExpect { - status { isUnauthorized() } - } - - } - - @Test - fun `user-inbox Digestヘッダーが空だと401`() = runTest { - val json = """{"type":"Follow"}""" - val sha256 = MessageDigest.getInstance("SHA-256") - - val digest = Base64Util.encode(sha256.digest(json.toByteArray())) - - mockMvc - .post("/users/hoge/inbox") { - content = json - contentType = MediaType.APPLICATION_JSON - header("Signature", "") - header("Host", "example.com") - header("Date", ZonedDateTime.now().format(dateTimeFormatter)) - header("Digest", "SHA-256=$digest") - } - .asyncDispatch() - .andExpect { - status { isUnauthorized() } - } - } -} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/note/NoteApControllerImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/note/NoteApControllerImplTest.kt deleted file mode 100644 index cb60896e..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/note/NoteApControllerImplTest.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.interfaces.api.note - -import dev.usbharu.hideout.activitypub.domain.model.Note -import dev.usbharu.hideout.activitypub.service.objects.note.NoteApApiService -import dev.usbharu.hideout.application.config.ActivityPubConfig -import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureUser -import dev.usbharu.httpsignature.common.HttpHeaders -import dev.usbharu.httpsignature.common.HttpMethod -import dev.usbharu.httpsignature.common.HttpRequest -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -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.* -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.get -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import java.net.URL - -@ExtendWith(MockitoExtension::class) -class NoteApControllerImplTest { - - private lateinit var mockMvc: MockMvc - - @Mock - private lateinit var noteApApiService: NoteApApiService - - @InjectMocks - private lateinit var noteApControllerImpl: NoteApControllerImpl - - @BeforeEach - fun setUp() { - - mockMvc = MockMvcBuilders.standaloneSetup(noteApControllerImpl) -// .apply( -// springSecurity( -// FilterChainProxy( -// DefaultSecurityFilterChain( -// AnyRequestMatcher.INSTANCE -// ) -// ) -// ) -// ) - .build() - } - - @Test - fun `postAP 匿名で取得できる`() = runTest { - SecurityContextHolder.clearContext() - val note = Note( - id = "https://example.com/users/hoge/posts/1234", - attributedTo = "https://example.com/users/hoge", - content = "Hello", - published = "2023-11-02T15:30:34.160Z" - ) - whenever(noteApApiService.getNote(eq(1234), isNull())).doReturn( - note - ) - - val objectMapper = ActivityPubConfig().objectMapper() - - mockMvc - .get("/users/hoge/posts/1234") { -// with(anonymous()) - } - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(note)) } } - } - - @Test - fun `postAP 存在しない場合は404`() = runTest { - SecurityContextHolder.clearContext() - whenever(noteApApiService.getNote(eq(123), isNull())).doReturn(null) - - mockMvc - .get("/users/hoge/posts/123") { -// with(anonymous()) - } - .asyncDispatch() - .andExpect { status { isNotFound() } } - } - - @Test - fun `postAP 認証に成功している場合userIdがnullでない`() = runTest { - val note = Note( - id = "https://example.com/users/hoge/posts/1234", - attributedTo = "https://example.com/users/hoge", - content = "Hello", - published = "2023-11-02T15:30:34.160Z" - ) - whenever(noteApApiService.getNote(eq(1234), isNotNull())).doReturn(note) - - val objectMapper = ActivityPubConfig().objectMapper() - - val preAuthenticatedAuthenticationToken = PreAuthenticatedAuthenticationToken( - "", HttpRequest( - URL("https://follower.example.com"), - HttpHeaders( - mapOf() - ), HttpMethod.GET - ) - ).apply { details = HttpSignatureUser("fuga", "follower.example.com", 123, true, true, mutableListOf()) } - SecurityContextHolder.getContext().authentication = preAuthenticatedAuthenticationToken - - mockMvc.get("/users/hoge/posts/1234") { -// with( -// authentication( -// preAuthenticatedAuthenticationToken -// ) -// ) - }.asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(note)) } } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/outbox/OutboxControllerImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/outbox/OutboxControllerImplTest.kt deleted file mode 100644 index 927bd784..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/outbox/OutboxControllerImplTest.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.interfaces.api.outbox - -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.InjectMocks -import org.mockito.junit.jupiter.MockitoExtension -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.get -import org.springframework.test.web.servlet.post -import org.springframework.test.web.servlet.setup.MockMvcBuilders - -@ExtendWith(MockitoExtension::class) -class OutboxControllerImplTest { - - private lateinit var mockMvc: MockMvc - - @InjectMocks - private lateinit var outboxController: OutboxControllerImpl - - @BeforeEach - fun setUp() { - mockMvc = - MockMvcBuilders.standaloneSetup(outboxController).build() - } - - @Test - fun `outbox GETに501を返す`() { - mockMvc - .get("/outbox") - .asyncDispatch() - .andDo { print() } - .andExpect { status { isNotImplemented() } } - } - - @Test - fun `user-outbox GETに501を返す`() { - mockMvc - .get("/users/hoge/outbox") - .asyncDispatch() - .andDo { print() } - .andExpect { status { isNotImplemented() } } - } - - @Test - fun `outbox POSTに501を返す`() { - mockMvc - .post("/outbox") - .asyncDispatch() - .andDo { print() } - .andExpect { status { isNotImplemented() } } - } - - @Test - fun `user-outbox POSTに501を返す`() { - mockMvc - .post("/users/hoge/outbox") - .asyncDispatch() - .andDo { print() } - .andExpect { status { isNotImplemented() } } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/webfinger/WebFingerControllerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/webfinger/WebFingerControllerTest.kt deleted file mode 100644 index a55770d4..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/interfaces/api/webfinger/WebFingerControllerTest.kt +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.interfaces.api.webfinger - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.activitypub.domain.model.webfinger.WebFinger -import dev.usbharu.hideout.activitypub.service.webfinger.WebFingerApiService -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.BeforeEach -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.doReturn -import org.mockito.kotlin.doThrow -import org.mockito.kotlin.eq -import org.mockito.kotlin.whenever -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get -import org.springframework.test.web.servlet.result.MockMvcResultHandlers.print -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import utils.UserBuilder - -@ExtendWith(MockitoExtension::class) -class WebFingerControllerTest { - - private lateinit var mockMvc: MockMvc - - @Mock - private lateinit var webFingerApiService: WebFingerApiService - - @Mock - private lateinit var applicationConfig: ApplicationConfig - - @InjectMocks - private lateinit var webFingerController: WebFingerController - - @BeforeEach - fun setUp() { - this.mockMvc = MockMvcBuilders.standaloneSetup(webFingerController).build() - } - - @Test - fun `webfinger 存在するacctを指定したとき200 OKでWebFingerのレスポンスが返ってくる`() = runTest { - - val user = UserBuilder.localUserOf() - whenever( - webFingerApiService.findByNameAndDomain( - eq("hoge"), - eq("example.com") - ) - ).doReturn(user) - - val contentAsString = mockMvc.perform(get("/.well-known/webfinger?resource=acct:hoge@example.com")) - .andDo(print()) - .andExpect(status().isOk()) - .andReturn() - .response - .contentAsString - - val objectMapper = jacksonObjectMapper() - - val readValue = objectMapper.readValue(contentAsString) - - val expected = WebFinger( - subject = "acct:${user.name}@${user.domain}", - listOf( - WebFinger.Link( - "self", - "application/activity+json", - user.url - ) - ) - ) - - assertThat(readValue).isEqualTo(expected) - } - - @Test - fun `webfinger 存在しないacctを指定したとき404 Not Foundが返ってくる`() = runTest { - whenever( - webFingerApiService.findByNameAndDomain( - eq("fuga"), - eq("example.com") - ) - ).doThrow(UserNotFoundException::class) - - mockMvc.perform(get("/.well-known/webfinger?resource=acct:fuga@example.com")) - .andDo(print()) - .andExpect(status().isNotFound) - } - - @Test - fun `webfinger acctとして解釈できない場合は400 Bad Requestが返ってくる`() { - mockMvc.perform(get("/.well-known/webfinger?resource=@hello@aa@aab@aaa")) - .andDo(print()) - .andExpect(status().isBadRequest) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/activity/accept/ApAcceptProcessorTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/activity/accept/ApAcceptProcessorTest.kt deleted file mode 100644 index f211ffff..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/activity/accept/ApAcceptProcessorTest.kt +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.service.activity.accept - -import dev.usbharu.hideout.activitypub.domain.exception.IllegalActivityPubObjectException -import dev.usbharu.hideout.activitypub.domain.model.Accept -import dev.usbharu.hideout.activitypub.domain.model.Follow -import dev.usbharu.hideout.activitypub.domain.model.Like -import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext -import dev.usbharu.hideout.activitypub.service.common.ActivityType -import dev.usbharu.hideout.application.config.ActivityPubConfig -import dev.usbharu.httpsignature.common.HttpHeaders -import dev.usbharu.httpsignature.common.HttpMethod -import dev.usbharu.httpsignature.common.HttpRequest -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.DynamicTest -import org.junit.jupiter.api.DynamicTest.dynamicTest -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestFactory -import org.junit.jupiter.api.assertThrows -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.* -import utils.TestTransaction -import utils.UserBuilder -import java.net.URL - - -@ExtendWith(MockitoExtension::class) -class ApAcceptProcessorTest { - - @Mock - private lateinit var actorRepository: ActorRepository - - @Mock - private lateinit var relationshipService: RelationshipService - - @Spy - private val transaction = TestTransaction - - @InjectMocks - private lateinit var apAcceptProcessor: ApAcceptProcessor - - @Test - fun `internalProcess objectがFollowの場合フォローを承認する`() = runTest { - - val json = """""" - val objectMapper = ActivityPubConfig().objectMapper() - val jsonNode = objectMapper.readTree(json) - - val accept = Accept( - apObject = Follow( - apObject = "https://example.com", - actor = "https://remote.example.com" - ), - actor = "https://example.com" - ) - val activity = ActivityPubProcessContext( - accept, jsonNode, HttpRequest( - URL("https://example.com"), - HttpHeaders(emptyMap()), HttpMethod.POST - ), null, true - ) - - val user = UserBuilder.localUserOf() - whenever(actorRepository.findByUrl(eq("https://example.com"))).doReturn(user) - val remoteUser = UserBuilder.remoteUserOf() - whenever(actorRepository.findByUrl(eq("https://remote.example.com"))).doReturn(remoteUser) - - apAcceptProcessor.internalProcess(activity) - - verify(relationshipService, times(1)).acceptFollowRequest(eq(user.id), eq(remoteUser.id), eq(false)) - } - - @Test - fun `internalProcess objectがFollow以外の場合IllegalActivityPubObjecExceptionが発生する`() = runTest { - val json = """""" - val objectMapper = ActivityPubConfig().objectMapper() - val jsonNode = objectMapper.readTree(json) - - val accept = Accept( - apObject = Like( - apObject = "https://example.com", - actor = "https://remote.example.com", - content = "", - id = "" - ), - actor = "https://example.com" - ) - val activity = ActivityPubProcessContext( - accept, jsonNode, HttpRequest( - URL("https://example.com"), - HttpHeaders(emptyMap()), HttpMethod.POST - ), null, true - ) - - assertThrows { - apAcceptProcessor.internalProcess(activity) - } - } - - @Test - fun `isSupproted Acceptにはtrue`() { - val actual = apAcceptProcessor.isSupported(ActivityType.Accept) - assertThat(actual).isTrue() - } - - @TestFactory - fun `isSupported Accept以外にはfalse`(): List { - return ActivityType - .values() - .filterNot { it == ActivityType.Accept } - .map { - dynamicTest("isSupported $it にはfalse") { - - val actual = apAcceptProcessor.isSupported(it) - assertThat(actual).isFalse() - } - } - } - - @Test - fun `type Acceptのclassjavaが返ってくる`() { - assertThat(apAcceptProcessor.type()).isEqualTo(Accept::class.java) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/activity/follow/APSendFollowServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/activity/follow/APSendFollowServiceImplTest.kt deleted file mode 100644 index ab8fee9d..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/activity/follow/APSendFollowServiceImplTest.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.service.activity.follow - -import dev.usbharu.hideout.activitypub.domain.model.Follow -import dev.usbharu.hideout.activitypub.service.common.APRequestService -import dev.usbharu.hideout.application.config.ApplicationConfig -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Test -import org.mockito.kotlin.eq -import org.mockito.kotlin.mock -import org.mockito.kotlin.times -import org.mockito.kotlin.verify -import utils.UserBuilder -import java.net.URL - -class APSendFollowServiceImplTest { - @Test - fun `sendFollow フォローするユーザーのinboxにFollowオブジェクトが送られる`() = runTest { - val apRequestService = mock() - val applicationConfig = ApplicationConfig(URL("https://example.com")) - val apSendFollowServiceImpl = APSendFollowServiceImpl(apRequestService, applicationConfig) - - val sendFollowDto = SendFollowDto( - UserBuilder.localUserOf(), - UserBuilder.remoteUserOf() - ) - apSendFollowServiceImpl.sendFollow(sendFollowDto) - - val value = Follow( - apObject = sendFollowDto.followTargetActorId.url, - actor = sendFollowDto.actorId.url, - id = "${applicationConfig.url}/follow/${sendFollowDto.actorId.id}/${sendFollowDto.followTargetActorId.id}" - ) - verify(apRequestService, times(1)).apPost( - eq(sendFollowDto.followTargetActorId.inbox), - eq(value), - eq(sendFollowDto.actorId) - ) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APRequestServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APRequestServiceImplTest.kt deleted file mode 100644 index e8243f53..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APRequestServiceImplTest.kt +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.service.common - -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.activitypub.domain.Constant -import dev.usbharu.hideout.activitypub.domain.model.Follow -import dev.usbharu.hideout.activitypub.domain.model.StringOrObject -import dev.usbharu.hideout.application.config.ActivityPubConfig -import dev.usbharu.hideout.util.Base64Util -import dev.usbharu.httpsignature.common.HttpHeaders -import dev.usbharu.httpsignature.common.HttpMethod -import dev.usbharu.httpsignature.common.HttpRequest -import dev.usbharu.httpsignature.sign.HttpSignatureSigner -import dev.usbharu.httpsignature.sign.Signature -import io.ktor.client.* -import io.ktor.client.engine.mock.* -import io.ktor.util.* -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import org.mockito.kotlin.any -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.eq -import org.mockito.kotlin.mock -import utils.UserBuilder -import java.net.URL -import java.security.MessageDigest -import java.time.format.DateTimeFormatter -import java.util.* - - -class APRequestServiceImplTest { - @Test - fun `apGet signerがnullのとき署名なしリクエストをする`() = runTest { - val dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - val apRequestServiceImpl = APRequestServiceImpl( - HttpClient(MockEngine { - assertTrue(it.headers.contains("Date")) - assertTrue(it.headers.contains("Accept")) - assertFalse(it.headers.contains("Signature")) - assertDoesNotThrow { - dateTimeFormatter.parse(it.headers["Date"]) - } - respond("""{"type":"Follow","object": "https://example.com","actor": "https://example.com"}""") - }), - ActivityPubConfig().objectMapper(), - mock(), - dateTimeFormatter - ) - - val responseClass = Follow( - apObject = "https://example.com", - actor = "https://example.com" - ) - apRequestServiceImpl.apGet("https://example.com", responseClass = responseClass::class.java) - } - - @Test - fun `apGet signerがnullではないがprivateKeyがnullのとき署名なしリクエストをする`() = runTest { - val dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - val apRequestServiceImpl = APRequestServiceImpl( - HttpClient(MockEngine { - assertTrue(it.headers.contains("Date")) - assertTrue(it.headers.contains("Accept")) - assertFalse(it.headers.contains("Signature")) - assertDoesNotThrow { - dateTimeFormatter.parse(it.headers["Date"]) - } - respond("""{"type":"Follow","object": "https://example.com","actor": "https://example.com"}""") - }), - ActivityPubConfig().objectMapper(), - mock(), - dateTimeFormatter - ) - - val responseClass = Follow( - apObject = "https://example.com", - actor = "https://example.com" - ) - apRequestServiceImpl.apGet( - "https://example.com", - UserBuilder.remoteUserOf(), - responseClass = responseClass::class.java - ) - } - - @Test - fun `apGet signerとprivatekeyがnullではないとき署名付きリクエストをする`() = runTest { - val dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - val httpSignatureSigner = mock { - onBlocking { - sign( - any(), - any(), - eq(listOf("(request-target)", "date", "host", "accept")) - ) - } doReturn Signature( - HttpRequest(URL("https://example.com"), HttpHeaders(mapOf()), HttpMethod.GET), "", "" - ) - } - val apRequestServiceImpl = APRequestServiceImpl( - HttpClient(MockEngine { - assertTrue(it.headers.contains("Date")) - assertTrue(it.headers.contains("Accept")) - assertTrue(it.headers.contains("Signature")) - assertDoesNotThrow { - dateTimeFormatter.parse(it.headers["Date"]) - } - respond("""{"type":"Follow","object": "https://example.com","actor": "https://example.com"}""") - }), - ActivityPubConfig().objectMapper(), - httpSignatureSigner, - dateTimeFormatter - ) - - val responseClass = Follow( - apObject = "https://example.com", - actor = "https://example.com" - ) - apRequestServiceImpl.apGet( - "https://example.com", - UserBuilder.localUserOf( - privateKey = "-----BEGIN PRIVATE KEY-----\n" + - "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJhNETcFVoZW36\n" + - "pDiaaUDa1FsWGqULUa6jDWYbMXFirbbceJEfvaasac+E8VUQ3krrEhYBArntB1do\n" + - "1Zq/MpI97WaQefwrBmjJwjYglB8AHF1RRqFlJ0aABMBvuHiIzuTPv4dLS4+pJQWl\n" + - "iE9TKsxXgUrEdWLmpSukZpyiWnrgFtJ8322LXRuL9+O4ivns1JfozbrHTprI4ohe\n" + - "6taZJX1mhGBXQT+U/UrEILk+z70P2rrwxwerdO7s6nkkC3ieJWdi924/AopDlg12\n" + - "8udubLPbpWVVrHbSKviUr3VKBKGe4xmvO7hqpGwKmctaXRVPjh/ue2mCIzv3qyxQ\n" + - "3n2Xyhb3AgMBAAECggEAGddiSC/bg+ud0spER+i/XFBm7cq052KuFlKdiVcpxxGn\n" + - "pVYApiVXvjxDVDTuR5950/MZxz9mQDL0zoi1s1b00eQjhttdrta/kT/KWRslboo0\n" + - "nTuFbsc+jyQM2Ua6jjCZvto8qzchUPtiYfu80Floor/9qnuzFwiPNCHEbD1WDG4m\n" + - "fLuH+INnGY6eRF+pgly1dykGs18DaR3vC9CWOqR9PWH+p/myksVymR5adKauMc+l\n" + - "gjLaeB1YjnzXnHYLqwtCgh053kedPG/xZZwq48YNP5npSBIHsd9g8JIPVNOOc6+s\n" + - "bbFqD9aQQxG/WaA5hxHRupLkKGjE6lw4SnVYzKMZIQKBgQDryFa3qzJIBrCQQa0r\n" + - "6YlmZeeCQ8mQL8d0gY0Ixo9Gm2/9J71m/oBkhOqnS6Z5e5UHS5iVaqM7sIOZ2Ony\n" + - "kPADAtxUsk71Il+z+JgyN3OQ+DROLREi2TIWS523hbtN7e/fRFs7KoN6cH7IeF13\n" + - "3pphg9+WWRGX7y1zMd1puY/gSwKBgQDazFrAt/oZbnDhkX350OdIybz62OHNyuZv\n" + - "UX9fFl9i93SF+UhOpJ8YvDJtfLEJUkwO+V3TB+we1OlOYMTqir5M8GFn6YDotwxB\n" + - "r6eT886UpJgtJwswwwW2yaXo7zXaeg3ovRE8RJ4y++Mhuqeq3ajIo7xlhQjzBDEf\n" + - "ZAqasSWwhQKBgQC0VbUlo1XAywUOQH0/oc4KOJS6CDjJBBIsZM3G0X9SBJ7B5Dwz\n" + - "4yG2QAbtT6oTLldMjiA036vbgmUVLVe5w+sekniMexhy2wiRsOhPOCQ20+/Ffyil\n" + - "G7P4Y3tMm4cn0n1tqW2RsjF/Wz1M/OqYPPSc8uz2pEcVisSbX582Nsv5QwKBgEuy\n" + - "vAtFG6BE14UTIzSVFA/YzCs1choTAtqspZauVN4WoxffASdESU7zfbbnlxCUin/7\n" + - "wnxKl2SrYPSfAkHrMp/H4stivBjHi9QGA8JqbaR7tbKZeYOrVYTCC0alzEoERF+r\n" + - "WhUx4FHfV9vJikzRV53jGEE/X7NEVgJ4SDrw4wtJAoGAAMJ2kOIL3HSQPd8csXeU\n" + - "nkxLNzBsFpF76LVmLdzJttlr8HWBjLP/EJFQZFzuf5Hd38cLUOWWD3FRZVw0dUcN\n" + - "RSqfIYT4yDc/9GSRb6rOkdmBUWpTsrZjXBo0MC3p1QE6sNO8JfvmxHTSAe8apBh/\n" + - "gaYuQGh0lNa23HwwFoJxuoc=\n" + - "-----END PRIVATE KEY-----" - ), - responseClass = responseClass::class.java - ) - } - - @Test - fun `apPost bodyがnullでないときcontextにactivitystreamのURLを追加する`() = runTest { - val dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - val apRequestServiceImpl = APRequestServiceImpl(HttpClient(MockEngine { - val readValue = ActivityPubConfig().objectMapper().readValue(it.body.toByteArray()) - - assertThat(readValue.context).containsAll(Constant.context) - - respondOk("{}") - }), ActivityPubConfig().objectMapper(), mock(), dateTimeFormatter) - - val body = Follow( - apObject = "https://example.com", - actor = "https://example.com" - ) - apRequestServiceImpl.apPost("https://example.com", body, null) - } - - @Test - fun `apPost bodyがnullのときリクエストボディは空`() = runTest { - val dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - val apRequestServiceImpl = APRequestServiceImpl(HttpClient(MockEngine { - - assertEquals(0, it.body.toByteArray().size) - - respondOk("{}") - }), ActivityPubConfig().objectMapper(), mock(), dateTimeFormatter) - - apRequestServiceImpl.apPost("https://example.com", null, null) - } - - @Test - fun `apPost signerがnullのとき署名なしリクエストをする`() = runTest { - val dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - val apRequestServiceImpl = APRequestServiceImpl(HttpClient(MockEngine { - val src = it.body.toByteArray() - val readValue = ActivityPubConfig().objectMapper().readValue(src) - - assertThat(readValue.context).contains(StringOrObject("https://www.w3.org/ns/activitystreams")) - - val map = it.headers.toMap() - assertThat(map).containsKey("Date") - .containsKey("Digest") - .containsKey("Accept") - .doesNotContainKey("Signature") - - assertDoesNotThrow { - dateTimeFormatter.parse(it.headers["Date"]) - } - val messageDigest = MessageDigest.getInstance("SHA-256") - val digest = Base64Util.encode(messageDigest.digest(src)) - - assertEquals(digest, it.headers["Digest"].orEmpty().split("256=").last()) - - respondOk("{}") - }), ActivityPubConfig().objectMapper(), mock(), dateTimeFormatter) - - val body = Follow( - apObject = "https://example.com", - actor = "https://example.com" - ) - apRequestServiceImpl.apPost("https://example.com", body, null) - } - - @Test - fun `apPost signerがnullではないがprivatekeyがnullのとき署名なしリクエストをする`() = runTest { - val dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - val apRequestServiceImpl = APRequestServiceImpl(HttpClient(MockEngine { - val src = it.body.toByteArray() - val readValue = ActivityPubConfig().objectMapper().readValue(src) - - assertThat(readValue.context).contains(StringOrObject("https://www.w3.org/ns/activitystreams")) - - val map = it.headers.toMap() - assertThat(map).containsKey("Date") - .containsKey("Digest") - .containsKey("Accept") - .doesNotContainKey("Signature") - - val messageDigest = MessageDigest.getInstance("SHA-256") - val digest = Base64Util.encode(messageDigest.digest(src)) - - assertEquals(digest, it.headers["Digest"].orEmpty().split("256=").last()) - - respondOk("{}") - }), ActivityPubConfig().objectMapper(), mock(), dateTimeFormatter) - - val body = Follow( - apObject = "https://example.com", - actor = "https://example.com" - ) - apRequestServiceImpl.apPost("https://example.com", body, UserBuilder.remoteUserOf()) - } - - @Test - fun `apPost signerがnullではないとき署名付きリクエストをする`() = runTest { - val dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - val httpSignatureSigner = mock { - onBlocking { - sign( - any(), - any(), - eq(listOf("(request-target)", "date", "host", "digest")) - ) - } doReturn Signature( - HttpRequest(URL("https://example.com"), HttpHeaders(mapOf()), HttpMethod.POST), "", "" - ) - } - val apRequestServiceImpl = APRequestServiceImpl(HttpClient(MockEngine { - val src = it.body.toByteArray() - val readValue = ActivityPubConfig().objectMapper().readValue(src) - - assertThat(readValue.context).contains(StringOrObject("https://www.w3.org/ns/activitystreams")) - - val map = it.headers.toMap() - assertThat(map).containsKey("Date") - .containsKey("Digest") - .containsKey("Accept") - .containsKey("Signature") - - val messageDigest = MessageDigest.getInstance("SHA-256") - val digest = Base64Util.encode(messageDigest.digest(src)) - - assertEquals(digest, it.headers["Digest"].orEmpty().split("256=").last()) - - respondOk("{}") - }), ActivityPubConfig().objectMapper(), httpSignatureSigner, dateTimeFormatter) - - val body = Follow( - apObject = "https://example.com", - actor = "https://example.com" - ) - apRequestServiceImpl.apPost( - "https://example.com", body, UserBuilder.localUserOf( - privateKey = "-----BEGIN PRIVATE KEY-----\n" + - "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1+pj+/t5WwU6P\n" + - "OiaAKfOHCUVMdOR5e2Jp0BUYfAFpim27pLsHRXVjdzs+D4gvDnQWC0FMltPyBldk\n" + - "gjisNMtTKgTTsYhlLlSi+yRDZvIQyH4b7xSX0hCeflTrTkt18ZldBRPfMHE0KSho\n" + - "mm3Lc7ubF32YzGoo3A3qEVDAR9dVQOnt/GXLiN4RHoStX+y5UiP6B4s49nyEwuLm\n" + - "+HE4ph3Loqn0dTEL4cEuI8ZX51J3mTKT3rmMo0wCXXOm8gD2Fu7hYEdr9ulWF8GO\n" + - "yVe7Miu9prbBlY/r4skdXc5o6uE8tsPT88Ly9lSr3xqbmn1/EhyqBRdcyoj28C65\n" + - "cThO38jvAgMBAAECggEAFbOaXkJ3smHgI/17zOnz1EU7QehovMIFlPfPJDnZk0QC\n" + - "XQ/CjBXw71kvM/H3PCFdn6lc8qzD/sdZ0a8j4glzu+m1ZKd1zBcv2bXYd79Fm9HF\n" + - "FEC5NHfFKpmHN/6AykJzFyA9Y+7reRx1aLAN6ubU1ySAgmHSQSgo8qJ4/k0y9UQS\n" + - "EbjxQL5ziXuxRBMn7InLUGLl5UfCC0V1R8MZQAe+fApKDXMQ0LHSJUg1A365PyhV\n" + - "seotqvhurHH3UVHf5n0/sFeqp2hI4ymR3cs4kd8IuNIXE7afh+89IyuVKMvJh+iQ\n" + - "ZGO1RL0v0mNtUpI81agSrrQ4LRBjSkP+5s5PdXTrSQKBgQD2lwMXLylhQzhRyhLx\n" + - "sSPRf9mKDUcretwA5Fh9GuAurKOz7SvIdzrUPFYUTUKSTwk8mVRRamkFtJ8IOB7Z\n" + - "MLenlFqxs4XrNGBcZxut5cPv68xn2F00Y4HwX9xmEi+vniNVrDpdVLxEoVfm1pBk\n" + - "02ZHCcfYVN0t8dnvXvlL+eJSqQKBgQC87GMoMvFnWgT23wdXtQH+F+gQAMUrkMWz\n" + - "Ld2uRwuSVQArgp+YgnwWMlYlFp/QIW90t7UVmf6bHIplO5bL2OwayIO1r/WxD1eN\n" + - "RLrFIeDbtCZWQTHUypnWtl+9lrh/RrCjZo/sZFl07OSIKgGM37j9taG6Nv6fV7gv\n" + - "T0q6eDCV1wKBgGh3CUQlIq6lv5JGvUfO95GlTA+EGIZ/Af0Ov74gSKD9Wky7STUf\n" + - "7bhD52OqZ218NjmJ64KiReO45TaiL89rKCLCYrmtiCpgggIjXEKLeDqH9ox3yOSM\n" + - "01t2APTs926629VLpV4sq6WXhJmyhHFybX3i0tr++MSiFOWnoo1hS1QhAoGAfVY6\n" + - "ppW9kDqppnrqrSZ6Lu//VnacWL3QW4JnWtLpe2iHF1auuQiAeF1mx25OEk/MWNvz\n" + - "+GPVBWUW7/hrn8vHQDGdJ/GYB6LNC/z4CAbk3f2TnY/dFnZfP5J4zBftSQtF7vIB\n" + - "M+yTaL4tE6UCqEpYuYFBzX/kxyP0Hvb09eb9HLsCgYEArFSgWpaLbADcWd+ygWls\n" + - "LNfch1Yl2bnqXKz1Dnw3J4l2gbVNcABXQLrB6upjtkytxj4ae66Sio7nf+dB5yJ6\n" + - "NVY7i4C0JrniY2OvLnuz2bKpaTgMPJxyZqGQ6Vu2b3x9WhcpiI83SCuCUgBKxjh/\n" + - "qEGv2ZqFfnNVrz5RXLHBoG4=\n" + - "-----END PRIVATE KEY-----" - ) - ) - } - - @Test - fun `apPost responseClassを指定した場合はjsonでシリアライズされる`() = runTest { - val dateTimeFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - val apRequestServiceImpl = APRequestServiceImpl(HttpClient(MockEngine { - val src = it.body.toByteArray() - val readValue = ActivityPubConfig().objectMapper().readValue(src) - - assertThat(readValue.context).contains(StringOrObject("https://www.w3.org/ns/activitystreams")) - - respondOk(src.decodeToString()) - }), ActivityPubConfig().objectMapper(), mock(), dateTimeFormatter) - - val body = Follow( - apObject = "https://example.com", - actor = "https://example.com" - ) - val actual = apRequestServiceImpl.apPost("https://example.com", body, null, body::class.java) - - assertThat(body).isEqualTo(actual) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APResourceResolveServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APResourceResolveServiceImplTest.kt deleted file mode 100644 index bb96522a..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APResourceResolveServiceImplTest.kt +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.service.common - -import dev.usbharu.hideout.core.service.resource.InMemoryCacheManager -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.junit.jupiter.MockitoExtension -import org.mockito.kotlin.* -import utils.UserBuilder -import dev.usbharu.hideout.activitypub.domain.model.objects.Object as APObject - -@ExtendWith(MockitoExtension::class) - -class APResourceResolveServiceImplTest { - - @Test - fun `単純な一回のリクエスト`() = runTest { - - - val actorRepository = mock() - - val user = UserBuilder.localUserOf() - whenever(actorRepository.findById(any())) doReturn user - - val apRequestService = mock { - onBlocking { - apGet( - eq("https"), - eq(user), - eq(APObject::class.java) - ) - } doReturn APObject( - emptyList() - ) - } - val apResourceResolveService = - APResourceResolveServiceImpl(apRequestService, actorRepository, InMemoryCacheManager()) - - apResourceResolveService.resolve("https", 0) - - verify(apRequestService, times(1)).apGet(eq("https"), eq(user), eq(APObject::class.java)) - } - - @Test - fun 複数回の同じリクエストが重複して発行されない() = runTest { - - - val actorRepository = mock() - - val user = UserBuilder.localUserOf() - whenever(actorRepository.findById(any())) doReturn user - - val apRequestService = mock { - onBlocking { - apGet( - eq("https"), - eq(user), - eq(APObject::class.java) - ) - } doReturn APObject( - emptyList() - ) - } - val apResourceResolveService = - APResourceResolveServiceImpl(apRequestService, actorRepository, InMemoryCacheManager()) - - apResourceResolveService.resolve("https", 0) - apResourceResolveService.resolve("https", 0) - apResourceResolveService.resolve("https", 0) - apResourceResolveService.resolve("https", 0) - - verify(apRequestService, times(1)).apGet( - eq("https"), - eq(user), - eq(APObject::class.java) - ) - } - - @Test - fun 複数回の同じリクエストが同時に発行されても重複して発行されない() = runTest { - - - val actorRepository = mock() - val user = UserBuilder.localUserOf() - - whenever(actorRepository.findById(any())) doReturn user - - - val apRequestService = mock { - onBlocking { - apGet( - eq("https"), - eq(user), - eq(APObject::class.java) - ) - } doReturn APObject( - emptyList() - ) - } - val apResourceResolveService = - APResourceResolveServiceImpl(apRequestService, actorRepository, InMemoryCacheManager()) - - repeat(10) { - awaitAll( - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - async { apResourceResolveService.resolve("https", 0) }, - ) - } - - verify(apRequestService, times(1)).apGet( - eq("https"), - eq(user), - eq(APObject::class.java) - ) - } - - @Test - fun 関係のないリクエストは発行する() = runTest { - - val actorRepository = mock() - - val user = UserBuilder.localUserOf() - whenever(actorRepository.findById(any())).doReturn( - user - ) - - val apRequestService = mock { - onBlocking { - apGet( - any(), - eq(user), - eq(APObject::class.java) - ) - } doReturn APObject( - emptyList() - ) - } - - val apResourceResolveService = - APResourceResolveServiceImpl(apRequestService, actorRepository, InMemoryCacheManager()) - - apResourceResolveService.resolve("abcd", 0) - apResourceResolveService.resolve("1234", 0) - apResourceResolveService.resolve("aaaa", 0) - - verify(apRequestService, times(3)).apGet( - any(), - eq(user), - eq(APObject::class.java) - ) - } - - -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APServiceImplTest.kt deleted file mode 100644 index b924baeb..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APServiceImplTest.kt +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.activitypub.service.common - -import dev.usbharu.hideout.activitypub.domain.exception.JsonParseException -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.mockito.kotlin.mock -import utils.JsonObjectMapper.objectMapper -import kotlin.test.assertEquals - -class APServiceImplTest { - @Test - fun `parseActivity 正常なActivityをパースできる`() { - val apServiceImpl = APServiceImpl( - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - val activityType = apServiceImpl.parseActivity("""{"type": "Follow"}""") - - assertEquals(ActivityType.Follow, activityType) - } - - @Test - fun `parseActivity Typeが配列のActivityをパースできる`() { - val apServiceImpl = APServiceImpl( - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - val activityType = apServiceImpl.parseActivity("""{"type": ["Follow"]}""") - - assertEquals(ActivityType.Follow, activityType) - } - - @Test - fun `parseActivity Typeが配列で関係ない物が入っていてもパースできる`() { - val apServiceImpl = APServiceImpl( - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - val activityType = apServiceImpl.parseActivity("""{"type": ["Hello","Follow"]}""") - - assertEquals(ActivityType.Follow, activityType) - } - - @Test - fun `parseActivity jsonとして解釈できない場合JsonParseExceptionがthrowされる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - assertThrows { - apServiceImpl.parseActivity("""hoge""") - } - } - - @Test - fun `parseActivity 空の場合JsonParseExceptionがthrowされる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - assertThrows { - apServiceImpl.parseActivity("") - } - } - - @Test - fun `parseActivity jsonにtypeプロパティがない場合JsonParseExceptionがthrowされる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - assertThrows { - apServiceImpl.parseActivity("""{"actor": "https://example.com"}""") - } - } - - @Test - fun `parseActivity typeが配列でないときtypeが未定義の場合IllegalArgumentExceptionがthrowされる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - assertThrows { - apServiceImpl.parseActivity("""{"type": "Hoge"}""") - } - } - - @Test - fun `parseActivity typeが配列のとき定義済みのtypeを見つけられなかった場合IllegalArgumentExceptionがthrowされる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - assertThrows { - apServiceImpl.parseActivity("""{"type": ["Hoge","Fuga"]}""") - } - } - - @Test - fun `parseActivity typeが空の場合IllegalArgumentExceptionがthrowされる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - assertThrows { - apServiceImpl.parseActivity("""{"type": ""}""") - } - } - - @Test - fun `parseActivity typeに指定されている文字の判定がcase-insensitiveで行われる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - val activityType = apServiceImpl.parseActivity("""{"type": "FoLlOw"}""") - - assertEquals(ActivityType.Follow, activityType) - } - - @Test - fun `parseActivity typeが配列のとき指定されている文字の判定がcase-insensitiveで行われる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - val activityType = apServiceImpl.parseActivity("""{"type": ["HoGE","fOllOw"]}""") - - assertEquals(ActivityType.Follow, activityType) - } - - @Test - fun `parseActivity activityがarrayのときJsonParseExceptionがthrowされる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - assertThrows { - apServiceImpl.parseActivity("""[{"type": "Follow"},{"type": "Accept"}]""") - } - } - - @Test - fun `parseActivity activityがvalueのときJsonParseExceptionがthrowされる`() { - val apServiceImpl = APServiceImpl( - - objectMapper = objectMapper, owlProducer = mock() - ) - - //language=JSON - assertThrows { - apServiceImpl.parseActivity(""""hoge"""") - } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/APNoteServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/APNoteServiceImplTest.kt deleted file mode 100644 index 33e745a8..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/APNoteServiceImplTest.kt +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:OptIn(ExperimentalCoroutinesApi::class) @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") - -package dev.usbharu.hideout.activitypub.service.objects.note - -import dev.usbharu.hideout.activitypub.domain.exception.FailedToGetActivityPubResourceException -import dev.usbharu.hideout.activitypub.domain.model.Image -import dev.usbharu.hideout.activitypub.domain.model.Key -import dev.usbharu.hideout.activitypub.domain.model.Note -import dev.usbharu.hideout.activitypub.domain.model.Person -import dev.usbharu.hideout.activitypub.query.AnnounceQueryService -import dev.usbharu.hideout.activitypub.query.NoteQueryService -import dev.usbharu.hideout.activitypub.service.common.APResourceResolveService -import dev.usbharu.hideout.activitypub.service.objects.emoji.EmojiService -import dev.usbharu.hideout.activitypub.service.objects.note.APNoteServiceImpl.Companion.public -import dev.usbharu.hideout.activitypub.service.objects.user.APUserService -import dev.usbharu.hideout.application.config.CharacterLimit -import dev.usbharu.hideout.application.config.HtmlSanitizeConfig -import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService -import dev.usbharu.hideout.core.service.media.MediaService -import dev.usbharu.hideout.core.service.post.DefaultPostContentFormatter -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.plugins.* -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.client.utils.* -import io.ktor.http.* -import io.ktor.http.content.* -import io.ktor.util.* -import io.ktor.util.date.* -import jakarta.validation.Validation -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.Job -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -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.* -import utils.PostBuilder -import utils.UserBuilder -import java.time.Instant - -@ExtendWith(MockitoExtension::class) -class APNoteServiceImplTest { - - @Mock - private lateinit var postRepository: PostRepository - - @Mock - private lateinit var apUserService: APUserService - - @Mock - private lateinit var postService: PostService - - @Mock - private lateinit var apResourceResolverService: APResourceResolveService - - @Spy - private val postBuilder: Post.PostBuilder = Post.PostBuilder( - CharacterLimit(), DefaultPostContentFormatter(HtmlSanitizeConfig().policy()), - Validation.buildDefaultValidatorFactory().validator - ) - - @Mock - private lateinit var noteQueryService: NoteQueryService - - @Mock - private lateinit var mediaService: MediaService - - @Mock - private lateinit var emojiService: EmojiService - - @Mock - private lateinit var announceQueryService: AnnounceQueryService - - @InjectMocks - private lateinit var apNoteServiceImpl: APNoteServiceImpl - - @Test - fun `fetchNote(String,String) ノートが既に存在する場合はDBから取得したものを返す`() = runTest { - val url = "https://example.com/note" - val post = PostBuilder.of() - - val user = UserBuilder.localUserOf(id = post.actorId) - val expected = Note( - id = post.apId, - attributedTo = user.url, - content = post.text, - published = Instant.ofEpochMilli(post.createdAt).toString(), - to = listOfNotNull(public, user.followers), - sensitive = post.sensitive, - cc = listOfNotNull(public, user.followers), - inReplyTo = null - ) - - whenever(noteQueryService.findByApid(eq(url))).doReturn(expected to post) - - val actual = apNoteServiceImpl.fetchNote(url) - - assertEquals(expected, actual) - } - - @Test - fun `fetchNote(String,String) ノートがDBに存在しない場合リモートに取得しにいく`() = runTest { - val url = "https://example.com/note" - val post = PostBuilder.of() - - - val user = UserBuilder.localUserOf(id = post.actorId) - - val note = Note( - id = post.apId, - attributedTo = user.url, - content = post.text, - published = Instant.ofEpochMilli(post.createdAt).toString(), - to = listOfNotNull(public, user.followers), - sensitive = post.sensitive, - cc = listOfNotNull(public, user.followers), - inReplyTo = null - ) - - whenever(apResourceResolverService.resolve(eq(url), any(), isNull())).doReturn(note) - - whenever(noteQueryService.findByApid(eq(url))).doReturn(null) - - val person = Person( - name = user.name, - id = user.url, - preferredUsername = user.name, - summary = user.description, - inbox = user.inbox, - outbox = user.outbox, - url = user.url, - icon = Image( - type = emptyList(), - mediaType = "image/png", - url = user.url + "/icon.png" - ), - publicKey = Key( - id = user.keyId, - owner = user.url, - publicKeyPem = user.publicKey - ), - endpoints = mapOf("sharedInbox" to "https://example.com/inbox"), - followers = user.followers, - following = user.following, - manuallyApprovesFollowers = false - - ) - - whenever( - apUserService.fetchPersonWithEntity( - eq(note.attributedTo), - isNull(), - anyOrNull() - ) - ).doReturn(person to user) - - whenever(postRepository.generateId()).doReturn(TwitterSnowflakeIdGenerateService.generateId()) - - val actual = apNoteServiceImpl.fetchNote(url) - - assertEquals(note, actual) - } - - @OptIn(InternalAPI::class) - @Test - fun `fetchNote(String,String) ノートをリモートから取得した際にエラーが返ってきたらFailedToGetActivityPubResourceExceptionがthrowされる`() = - runTest { - val url = "https://example.com/note" - val responseData = HttpResponseData( - HttpStatusCode.BadRequest, - GMTDate(), - Headers.Empty, - HttpProtocolVersion.HTTP_1_1, - NullBody, - Dispatchers.IO - ) - whenever(apResourceResolverService.resolve(eq(url), any(), isNull())).doThrow( - ClientRequestException( - DefaultHttpResponse( - HttpClientCall( - HttpClient(), HttpRequestData( - Url("http://example.com"), - HttpMethod.Get, - Headers.Empty, - EmptyContent, - Job(null), - Attributes() - ), responseData - ), responseData - ), "" - ) - ) - - whenever(noteQueryService.findByApid(eq(url))).doReturn(null) - - assertThrows { apNoteServiceImpl.fetchNote(url) } - - } - - @Test - fun `fetchNote(Note,String) DBに無いNoteは保存される`() = runTest { - val user = UserBuilder.localUserOf() - val generateId = TwitterSnowflakeIdGenerateService.generateId() - val post = PostBuilder.of(id = generateId, userId = user.id) - - whenever(postRepository.generateId()).doReturn(generateId) - - val person = Person( - name = user.name, - id = user.url, - preferredUsername = user.name, - summary = user.name, - inbox = user.inbox, - outbox = user.outbox, - url = user.url, - icon = Image( - mediaType = "image/png", - url = user.url + "/icon.png" - ), - publicKey = Key( - id = user.keyId, - owner = user.url, - publicKeyPem = user.publicKey - ), - endpoints = mapOf("sharedInbox" to "https://example.com/inbox"), - following = user.following, - followers = user.followers - ) - - whenever(apUserService.fetchPersonWithEntity(eq(user.url), anyOrNull(), anyOrNull())).doReturn(person to user) - - whenever(noteQueryService.findByApid(eq(post.apId))).doReturn(null) - - val note = Note( - id = post.apId, - attributedTo = user.url, - content = post.text, - published = Instant.ofEpochMilli(post.createdAt).toString(), - to = listOfNotNull(public, user.followers), - sensitive = post.sensitive, - cc = listOfNotNull(public, user.followers), - inReplyTo = null - ) - - - val fetchNote = apNoteServiceImpl.fetchNote(note, null) - verify(postService, times(1)).createRemote( - eq( - PostBuilder.of( - id = generateId, userId = user.id, createdAt = post.createdAt - ) - ) - ) - assertEquals(note, fetchNote) - } - - @Test - fun `fetchNote DBに存在する場合取得して返す`() = runTest { - - val user = UserBuilder.localUserOf() - val post = PostBuilder.of(userId = user.id) - - val note = Note( - id = post.apId, - attributedTo = user.url, - content = post.text, - published = Instant.ofEpochMilli(post.createdAt).toString(), - to = listOfNotNull(public, user.followers), - sensitive = post.sensitive, - cc = listOfNotNull(public, user.followers), - inReplyTo = null - ) - - whenever(noteQueryService.findByApid(post.apId)).doReturn(note to post) - - val fetchNote = apNoteServiceImpl.fetchNote(note, null) - assertEquals(note, fetchNote) - } - - -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/ap/ContextDeserializerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/ap/ContextDeserializerTest.kt deleted file mode 100644 index 5a21e241..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/ap/ContextDeserializerTest.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.ap - -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import dev.usbharu.hideout.activitypub.domain.model.Follow - -class ContextDeserializerTest { - - @org.junit.jupiter.api.Test - fun deserialize() { - //language=JSON - val s = """ - { - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - { - "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", - "sensitive": "as:sensitive", - "Hashtag": "as:Hashtag", - "quoteUrl": "as:quoteUrl", - "toot": "http://joinmastodon.org/ns#", - "Emoji": "toot:Emoji", - "featured": "toot:featured", - "discoverable": "toot:discoverable", - "schema": "http://schema.org#", - "PropertyValue": "schema:PropertyValue", - "value": "schema:value", - "misskey": "https://misskey-hub.net/ns#", - "_misskey_content": "misskey:_misskey_content", - "_misskey_quote": "misskey:_misskey_quote", - "_misskey_reaction": "misskey:_misskey_reaction", - "_misskey_votes": "misskey:_misskey_votes", - "_misskey_talk": "misskey:_misskey_talk", - "isCat": "misskey:isCat", - "vcard": "http://www.w3.org/2006/vcard/ns#" - } - ], - "id": "https://test-misskey-v12.usbharu.dev/follows/9bg1zu54y7/9cydqvpjcn", - "type": "Follow", - "actor": "https://test-misskey-v12.usbharu.dev/users/9bg1zu54y7", - "object": "https://test-hideout.usbharu.dev/users/test3" -} - -""" - val readValue = jacksonObjectMapper().enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).readValue(s) - println(readValue) - println(readValue.actor) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/ap/ContextSerializerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/ap/ContextSerializerTest.kt deleted file mode 100644 index 4500bc95..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/ap/ContextSerializerTest.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.ap - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import dev.usbharu.hideout.activitypub.domain.model.Accept -import dev.usbharu.hideout.activitypub.domain.model.Follow -import org.junit.jupiter.api.Test - -class ContextSerializerTest { - - @Test - fun serialize() { - val accept = Accept( - actor = "bbb", - apObject = Follow( - apObject = "ddd", - actor = "aaa" - ) - ) - val writeValueAsString = jacksonObjectMapper().writeValueAsString(accept) - println(writeValueAsString) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedPaginationExtensionKtTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedPaginationExtensionKtTest.kt deleted file mode 100644 index 6e57f239..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/ExposedPaginationExtensionKtTest.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.infrastructure.exposed - -import org.assertj.core.api.Assertions.assertThat -import org.jetbrains.exposed.sql.* -import org.jetbrains.exposed.sql.transactions.transaction -import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test - -class ExposedPaginationExtensionKtTest { - - @BeforeEach - fun setUp(): Unit = transaction { - val map = (1..100).map { it to it.toString() } - - ExposePaginationTestTable.batchInsert(map){ - this[ExposePaginationTestTable.id] = it.first.toLong() - this[ExposePaginationTestTable.name] = it.second - } - } - - @AfterEach - fun tearDown():Unit = transaction { - ExposePaginationTestTable.deleteAll() - } - - @Test - fun パラメーター無しでの取得(): Unit = transaction { - val pagination: PaginationList = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(), ExposePaginationTestTable.id) - - assertThat(pagination.next).isEqualTo(100) - assertThat(pagination.prev).isEqualTo(81) - assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(100) - assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(81) - assertThat(pagination).size().isEqualTo(20) - } - - @Test - fun maxIdを指定して取得(): Unit = transaction { - val pagination: PaginationList = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(maxId = 100), ExposePaginationTestTable.id) - - assertThat(pagination.next).isEqualTo(99) - assertThat(pagination.prev).isEqualTo(80) - assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(99) - assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(80) - assertThat(pagination).size().isEqualTo(20) - } - - @Test - fun sinceIdを指定して取得(): Unit = transaction { - val pagination: PaginationList = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(sinceId = 15), ExposePaginationTestTable.id) - - assertThat(pagination.next).isEqualTo(100) - assertThat(pagination.prev).isEqualTo(81) - assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(100) - assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(81) - assertThat(pagination).size().isEqualTo(20) - } - - @Test - fun minIdを指定して取得():Unit = transaction { - val pagination: PaginationList = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(minId = 45), ExposePaginationTestTable.id) - - assertThat(pagination.next).isEqualTo(65) - assertThat(pagination.prev).isEqualTo(46) - assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(65) - assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(46) - assertThat(pagination).size().isEqualTo(20) - } - - @Test - fun maxIdとsinceIdを指定して取得(): Unit = transaction { - val pagination: PaginationList = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(maxId = 45, sinceId = 34), ExposePaginationTestTable.id) - - assertThat(pagination.next).isEqualTo(44) - assertThat(pagination.prev).isEqualTo(35) - assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(44) - assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(35) - assertThat(pagination).size().isEqualTo(10) - } - - @Test - fun maxIdとminIdを指定して取得():Unit = transaction { - val pagination: PaginationList = ExposePaginationTestTable.selectAll().limit(20).withPagination(Page.of(maxId = 54, minId = 45), ExposePaginationTestTable.id) - - assertThat(pagination.next).isEqualTo(53) - assertThat(pagination.prev).isEqualTo(46) - assertThat(pagination.first()[ExposePaginationTestTable.id]).isEqualTo(53) - assertThat(pagination.last()[ExposePaginationTestTable.id]).isEqualTo(46) - assertThat(pagination).size().isEqualTo(8) - } - - @Test - fun limitを指定して取得():Unit = transaction { - val pagination: PaginationList = ExposePaginationTestTable.selectAll().withPagination(Page.of(limit = 30), ExposePaginationTestTable.id) - assertThat(pagination).size().isEqualTo(30) - } - - @Test - fun 結果が0件の場合はprevとnextがnullになる():Unit = transaction { - val pagination = ExposePaginationTestTable.selectAll().where { ExposePaginationTestTable.id.isNull() } - .withPagination(Page.of(), ExposePaginationTestTable.id) - - assertThat(pagination).isEmpty() - assertThat(pagination.next).isNull() - assertThat(pagination.prev).isNull() - } - - object ExposePaginationTestTable : Table(){ - val id = long("id") - val name = varchar("name",100) - - override val primaryKey: PrimaryKey - get() = PrimaryKey(id) - } - - companion object { - private lateinit var database: Database - - @JvmStatic - @BeforeAll - fun beforeAll(): Unit { - database = Database.connect( - url = "jdbc:h2:mem:test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4;", - driver = "org.h2.Driver", - user = "sa", - password = "" - ) - - transaction(database) { - SchemaUtils.create(ExposePaginationTestTable) - SchemaUtils.createMissingTablesAndColumns(ExposePaginationTestTable) - } - } - } -} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PageTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PageTest.kt deleted file mode 100644 index a0c4bba7..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PageTest.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.infrastructure.exposed - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class PageTest { - @Test - fun minIdが指定されているとsinceIdは無視される() { - val page = Page.of(1, 2, 3, 4) - - assertThat(page.maxId).isEqualTo(1) - assertThat(page.sinceId).isNull() - assertThat(page.minId).isEqualTo(3) - assertThat(page.limit).isEqualTo(4) - } - - @Test - fun minIdがnullのときはsinceIdが使われる() { - val page = Page.of(1, 2, null, 4) - - assertThat(page.maxId).isEqualTo(1) - assertThat(page.minId).isNull() - assertThat(page.sinceId).isEqualTo(2) - assertThat(page.limit).isEqualTo(4) - } -} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PaginationListKtTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PaginationListKtTest.kt deleted file mode 100644 index af4db171..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/infrastructure/exposed/PaginationListKtTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.infrastructure.exposed - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class PaginationListKtTest { - @Test - fun `toHttpHeader nextとprevがnullでない場合両方作成される`() { - val paginationList = PaginationList(emptyList(), 1, 2) - - val httpHeader = - paginationList.toHttpHeader({ "https://example.com?max_id=$it" }, { "https://example.com?min_id=$it" }) - - assertThat(httpHeader).isEqualTo("; rel=\"next\", ; rel=\"prev\"") - } - - @Test - fun `toHttpHeader nextがnullなら片方だけ作成される`() { - val paginationList = PaginationList(emptyList(), 1,null) - - val httpHeader = - paginationList.toHttpHeader({ "https://example.com?max_id=$it" }, { "https://example.com?min_id=$it" }) - - assertThat(httpHeader).isEqualTo("; rel=\"next\"") - } - - @Test - fun `toHttpHeader prevがnullなら片方だけ作成される`() { - val paginationList = PaginationList(emptyList(), null,2) - - val httpHeader = - paginationList.toHttpHeader({ "https://example.com?max_id=$it" }, { "https://example.com?min_id=$it" }) - - assertThat(httpHeader).isEqualTo("; rel=\"prev\"") - } - - @Test - fun `toHttpHeader 両方nullならnullが返ってくる`() { - val paginationList = PaginationList(emptyList(), null, null) - - - val httpHeader = - paginationList.toHttpHeader({ "https://example.com?max_id=$it" }, { "https://example.com?min_id=$it" }) - - assertThat(httpHeader).isNull() - } -} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/service/id/TwitterSnowflakeIdGenerateServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/service/id/TwitterSnowflakeIdGenerateServiceTest.kt deleted file mode 100644 index eb09683c..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/service/id/TwitterSnowflakeIdGenerateServiceTest.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.application.service.id - -// import kotlinx.coroutines.NonCancellable.message -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -class TwitterSnowflakeIdGenerateServiceTest { - @Test - fun noDuplicateTest() = runBlocking { - val mutex = Mutex() - val mutableListOf = mutableListOf() - coroutineScope { - repeat(500000) { - launch(Dispatchers.IO) { - val id = TwitterSnowflakeIdGenerateService.generateId() - mutex.withLock { - mutableListOf.add(id) - } - } - } - } - - assertEquals(0, mutableListOf.size - mutableListOf.toSet().size) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/service/init/MetaServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/service/init/MetaServiceImplTest.kt deleted file mode 100644 index 532f6403..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/application/service/init/MetaServiceImplTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:OptIn(ExperimentalCoroutinesApi::class) - -package dev.usbharu.hideout.application.service.init - -import dev.usbharu.hideout.core.domain.exception.NotInitException -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.mockito.kotlin.* -import utils.TestTransaction -import java.util.* -import kotlin.test.assertEquals - -class MetaServiceImplTest { - @Test - fun `getMeta メタデータを取得できる`() = runTest { - val meta = Meta("1.0.0", Jwt(UUID.randomUUID(), "sdfsdjk", "adafda")) - val metaRepository = mock { - onBlocking { get() } doReturn meta - } - val metaService = MetaServiceImpl(metaRepository, TestTransaction) - val actual = metaService.getMeta() - assertEquals(meta, actual) - } - - @Test - fun `getMeta メタデータが無いときはNotInitExceptionがthrowされる`() = runTest { - val metaRepository = mock { - onBlocking { get() } doReturn null - } - val metaService = MetaServiceImpl(metaRepository, TestTransaction) - assertThrows { metaService.getMeta() } - } - - @Test - fun `updateMeta メタデータを保存できる`() = runTest { - val meta = Meta("1.0.1", Jwt(UUID.randomUUID(), "sdfsdjk", "adafda")) - val metaRepository = mock { - onBlocking { save(any()) } doReturn Unit - } - val metaServiceImpl = MetaServiceImpl(metaRepository, TestTransaction) - metaServiceImpl.updateMeta(meta) - argumentCaptor { - verify(metaRepository).save(capture()) - assertEquals(meta, firstValue) - } - } - - @Test - fun `getJwtMeta Jwtメタデータを取得できる`() = runTest { - val meta = Meta("1.0.0", Jwt(UUID.randomUUID(), "sdfsdjk", "adafda")) - val metaRepository = mock { - onBlocking { get() } doReturn meta - } - val metaService = MetaServiceImpl(metaRepository, TestTransaction) - val actual = metaService.getJwtMeta() - assertEquals(meta.jwt, actual) - } - - @Test - fun `getJwtMeta メタデータが無いときはNotInitExceptionがthrowされる`() = runTest { - val metaRepository = mock { - onBlocking { get() } doReturn null - } - val metaService = MetaServiceImpl(metaRepository, TestTransaction) - assertThrows { metaService.getJwtMeta() } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorTest.kt deleted file mode 100644 index 573dd862..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/ActorTest.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.usbharu.hideout.core.domain.model.actor - -import org.junit.jupiter.api.Test -import utils.UserBuilder - -class ActorTest { - @Test - fun validator() { - org.junit.jupiter.api.assertThrows { - UserBuilder.localUserOf(name = "うんこ") - } - } -} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActor2Factory.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActor2Factory.kt index 28faa6a3..220b4056 100644 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActor2Factory.kt +++ b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/domain/model/actor/TestActor2Factory.kt @@ -1,13 +1,14 @@ package dev.usbharu.hideout.core.domain.model.actor import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService +import dev.usbharu.hideout.core.domain.model.emoji.EmojiId import dev.usbharu.hideout.core.domain.model.instance.InstanceId import dev.usbharu.hideout.core.domain.model.shared.Domain import kotlinx.coroutines.runBlocking import java.net.URI import java.time.Instant -object TestActor2Factory : Actor.Actor2Factory() { +object TestActor2Factory { private val idGenerateService = TwitterSnowflakeIdGenerateService fun create( @@ -32,14 +33,18 @@ object TestActor2Factory : Actor.Actor2Factory() { postCount: Int = 0, lastPostDate: Instant? = null, suspend: Boolean = false, + alsoKnownAs: Set = emptySet(), + moveTo: ActorId? = null, + emojiIds: Set = emptySet(), + deleted: Boolean = false, ): Actor { return runBlocking { - super.internalCreate( + Actor( id = ActorId(id), name = ActorName(actorName), domain = Domain(domain), - screenName = TestActorScreenNameFactory.create(actorScreenName), - description = TestActorDescriptionFactory.create(description), + screenName = ActorScreenName(actorScreenName), + description = ActorDescription(description), inbox = inbox, outbox = outbox, url = uri, @@ -54,8 +59,12 @@ object TestActor2Factory : Actor.Actor2Factory() { followersCount = ActorRelationshipCount(followersCount), followingCount = ActorRelationshipCount(followingCount), postsCount = ActorPostsCount(postCount), - lastPostDate = lastPostDate, - suspend = suspend + lastPostAt = lastPostDate, + suspend = suspend, + alsoKnownAs = alsoKnownAs, + moveTo = moveTo, + emojiIds = emojiIds, + deleted = deleted, ) } } @@ -63,20 +72,4 @@ object TestActor2Factory : Actor.Actor2Factory() { private fun generateId(): Long = runBlocking { idGenerateService.generateId() } -} - -object TestActorScreenNameFactory : ActorScreenName.ActorScreenNameFactory() { - fun create(name: String): ActorScreenName { - return runBlocking { - super.create(name, emptyList()) - } - } -} - -object TestActorDescriptionFactory : ActorDescription.ActorDescriptionFactory() { - fun create(description: String): ActorDescription { - return runBlocking { - super.create(description, emptyList()) - } - } } \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureHeaderCheckerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureHeaderCheckerTest.kt deleted file mode 100644 index 4a150e10..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/infrastructure/springframework/httpsignature/HttpSignatureHeaderCheckerTest.kt +++ /dev/null @@ -1,110 +0,0 @@ -package dev.usbharu.hideout.core.infrastructure.springframework.httpsignature - -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.util.Base64Util -import org.intellij.lang.annotations.Language -import org.junit.jupiter.api.Assertions.assertDoesNotThrow -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import java.net.URI -import java.security.MessageDigest -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter -import java.util.* - -class HttpSignatureHeaderCheckerTest { - - val format = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) - - @Test - fun `checkDate 未来はダメ`() { - val httpSignatureHeaderChecker = - HttpSignatureHeaderChecker(ApplicationConfig(URI.create("http://example.com").toURL())) - - val s = ZonedDateTime.now().plusDays(1).format(format) - - assertThrows { - httpSignatureHeaderChecker.checkDate(s) - } - } - - - @Test - fun `checkDate 過去はOK`() { - val httpSignatureHeaderChecker = - HttpSignatureHeaderChecker(ApplicationConfig(URI.create("http://example.com").toURL())) - - val s = ZonedDateTime.now().minusHours(1).format(format) - - assertDoesNotThrow { - httpSignatureHeaderChecker.checkDate(s) - } - } - - @Test - fun `checkDate 86400秒以上昔はダメ`() { - val httpSignatureHeaderChecker = - HttpSignatureHeaderChecker(ApplicationConfig(URI.create("http://example.com").toURL())) - - val s = ZonedDateTime.now().minusSeconds(86401).format(format) - - assertThrows { - httpSignatureHeaderChecker.checkDate(s) - } - } - - @Test - fun `checkHost 大文字小文字の違いはセーフ`() { - val httpSignatureHeaderChecker = - HttpSignatureHeaderChecker(ApplicationConfig(URI.create("https://example.com").toURL())) - - assertDoesNotThrow { - httpSignatureHeaderChecker.checkHost("example.com") - httpSignatureHeaderChecker.checkHost("EXAMPLE.COM") - } - } - - @Test - fun `checkHost サブドメインはダメ`() { - val httpSignatureHeaderChecker = - HttpSignatureHeaderChecker(ApplicationConfig(URI.create("https://example.com").toURL())) - - assertThrows { - httpSignatureHeaderChecker.checkHost("follower.example.com") - } - } - - @Test - fun `checkDigest リクエストボディが同じなら何もしない`() { - val httpSignatureHeaderChecker = - HttpSignatureHeaderChecker(ApplicationConfig(URI.create("https://example.com").toURL())) - - - val sha256 = MessageDigest.getInstance("SHA-256") - - @Language("JSON") val requestBody = """{"@context":"","type":"hoge"}""" - - val digest = Base64Util.encode(sha256.digest(requestBody.toByteArray())) - - assertDoesNotThrow { - httpSignatureHeaderChecker.checkDigest(requestBody.toByteArray(), "SHA-256=" + digest) - } - } - - @Test - fun `checkDigest リクエストボディがちょっとでも違うとダメ`() { - val httpSignatureHeaderChecker = - HttpSignatureHeaderChecker(ApplicationConfig(URI.create("https://example.com").toURL())) - - - val sha256 = MessageDigest.getInstance("SHA-256") - - @Language("JSON") val requestBody = """{"type":"hoge","@context":""}""" - @Language("JSON") val requestBody2 = """{"@context":"","type":"hoge"}""" - val digest = Base64Util.encode(sha256.digest(requestBody.toByteArray())) - - assertThrows { - httpSignatureHeaderChecker.checkDigest(requestBody2.toByteArray(), digest) - } - } -} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/filter/MuteProcessServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/filter/MuteProcessServiceImplTest.kt deleted file mode 100644 index b6ae6af4..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/filter/MuteProcessServiceImplTest.kt +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.filter - -import dev.usbharu.hideout.core.domain.model.filter.FilterAction -import dev.usbharu.hideout.core.domain.model.filter.FilterMode -import dev.usbharu.hideout.core.domain.model.filter.FilterType -import dev.usbharu.hideout.core.domain.model.filterkeyword.FilterKeyword -import dev.usbharu.hideout.core.query.model.FilterQueryModel -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import utils.PostBuilder - -class MuteProcessServiceImplTest { - @Test - fun 単純な文字列にマッチする() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(text = "mute test") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "mute", - FilterMode.NONE - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isEqualTo(FilterResult(filterQueryModel, "mute")) - } - - @Test - fun 複数の文字列でマッチする() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(text = "mute test") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "mate", - FilterMode.NONE - ), - FilterKeyword( - 1, - 1, - "mata", - FilterMode.NONE - ), - FilterKeyword( - 1, - 1, - "mute", - FilterMode.NONE - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isEqualTo(FilterResult(filterQueryModel, "mute")) - } - - @Test - fun 単語にマッチする() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(text = "mute test") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "mute", - FilterMode.WHOLE_WORD - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isEqualTo(FilterResult(filterQueryModel, "mute")) - } - - @Test - fun 単語以外にはマッチしない() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(text = "mutetest") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "mute", - FilterMode.WHOLE_WORD - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isNull() - } - - @Test - fun 複数の単語にマッチする() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(text = "mute test") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "mate", - FilterMode.WHOLE_WORD - ), - FilterKeyword( - 1, - 1, - "mata", - FilterMode.WHOLE_WORD - ), - FilterKeyword( - 1, - 1, - "mute", - FilterMode.WHOLE_WORD - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isEqualTo(FilterResult(filterQueryModel, "mute")) - } - - @Test - fun 正規表現も使える() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(text = "mute test") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "e\\st", - FilterMode.REGEX - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isEqualTo(FilterResult(filterQueryModel, "e t")) - } - - @Test - fun cw文字にマッチする() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(overview = "mute test", text = "hello") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "e\\st", - FilterMode.REGEX - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isEqualTo(FilterResult(filterQueryModel, "e t")) - } - - @Test - fun 文字列と単語と正規表現を同時に使える() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(text = "mute test") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "e\\st", - FilterMode.REGEX - ), - FilterKeyword( - 2, - 1, - "mute", - FilterMode.NONE - ), - FilterKeyword( - 3, - 1, - "test", - FilterMode.WHOLE_WORD - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isEqualTo(FilterResult(filterQueryModel, "mute")) - } - - @Test - fun 複数の投稿を処理できる() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "mute", - FilterMode.NONE - ) - ) - ) - val posts = listOf( - PostBuilder.of(text = "mute"), PostBuilder.of(text = "mutes"), PostBuilder.of(text = "hoge") - ) - val actual = muteProcessServiceImpl.processMutes( - posts, - FilterType.entries.toList(), - listOf( - filterQueryModel - ) - ) - - assertThat(actual) - .hasSize(2) - .containsEntry(posts[0], FilterResult(filterQueryModel, "mute")) - .containsEntry(posts[1], FilterResult(filterQueryModel, "mute")) - - } - - @Test - fun 何もマッチしないとnullが返ってくる() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(text = "mute test") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "fuga", - FilterMode.NONE - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isNull() - } - - @Test - fun Cwで何もマッチしないと本文を確認する() = runTest { - val muteProcessServiceImpl = MuteProcessServiceImpl() - - val post = PostBuilder.of(overview = "hage", text = "mute test") - - val filterQueryModel = FilterQueryModel( - 1, - 2, - "mute test", - FilterType.entries, - FilterAction.warn, - listOf( - FilterKeyword( - 1, - 1, - "fuga", - FilterMode.NONE - ) - ) - ) - val actual = muteProcessServiceImpl.processMute( - post, FilterType.entries.toList(), listOf( - filterQueryModel - ) - ) - - assertThat(actual).isNull() - } - -} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/filter/MuteServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/filter/MuteServiceImplTest.kt deleted file mode 100644 index f37310a4..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/filter/MuteServiceImplTest.kt +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.filter - -import dev.usbharu.hideout.core.domain.model.filter.* -import dev.usbharu.hideout.core.domain.model.filterkeyword.FilterKeywordRepository -import dev.usbharu.hideout.core.query.model.FilterQueryModel -import dev.usbharu.hideout.core.query.model.FilterQueryService -import kotlinx.coroutines.test.runTest -import org.assertj.core.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 org.mockito.kotlin.* - -@ExtendWith(MockitoExtension::class) -class MuteServiceImplTest { - - @Mock - private lateinit var filterRepository: FilterRepository - - @Mock - private lateinit var filterKeywordRepository: FilterKeywordRepository - - @Mock - private lateinit var filterQueryService: FilterQueryService - - @InjectMocks - private lateinit var muteServiceImpl: MuteServiceImpl - - @Test - fun createFilter() = runTest { - whenever(filterRepository.generateId()).doReturn(1) - whenever(filterKeywordRepository.generateId()).doReturn(1) - - whenever(filterRepository.save(any())).doAnswer { it.arguments[0]!! as Filter } - - val createFilter = muteServiceImpl.createFilter( - title = "hoge", - context = listOf(FilterType.home, FilterType.public), - action = FilterAction.warn, - keywords = listOf( - FilterKeyword( - "fuga", - FilterMode.NONE - ) - ), - loginUser = 1 - ) - - assertThat(createFilter).isEqualTo( - FilterQueryModel( - 1, - 1, - "hoge", - listOf(FilterType.home, FilterType.public), - FilterAction.warn, - keywords = listOf( - dev.usbharu.hideout.core.domain.model.filterkeyword.FilterKeyword(1, 1, "fuga", FilterMode.NONE) - ) - ) - ) - } - - @Test - fun getFilters() = runTest { - whenever(filterQueryService.findByUserIdAndType(any(), any())).doReturn( - listOf( - FilterQueryModel( - 1, - 1, - "hoge", - listOf(FilterType.home), - FilterAction.warn, - listOf( - dev.usbharu.hideout.core.domain.model.filterkeyword.FilterKeyword( - 1, - 1, - "fuga", - FilterMode.NONE - ) - ) - ) - ) - ) - - muteServiceImpl.getFilters(1, listOf(FilterType.home)) - } - - @Test - fun `getFilters 何も指定しない`() = runTest { - whenever(filterQueryService.findByUserIdAndType(any(), eq(emptyList()))).doReturn(emptyList()) - - muteServiceImpl.getFilters(1) - } -} \ No newline at end of file diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/media/ApatcheTikaFileTypeDeterminationServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/media/ApatcheTikaFileTypeDeterminationServiceTest.kt deleted file mode 100644 index ee3aee68..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/media/ApatcheTikaFileTypeDeterminationServiceTest.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.media - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import kotlin.io.path.toPath - -class ApatcheTikaFileTypeDeterminationServiceTest { - @Test - fun png() { - val apatcheTikaFileTypeDeterminationService = ApatcheTikaFileTypeDeterminationService() - - val mimeType = apatcheTikaFileTypeDeterminationService.fileType( - String.javaClass.classLoader.getResource("400x400.png").toURI().toPath(), "400x400.png" - ) - - assertThat(mimeType.type).isEqualTo("image") - assertThat(mimeType.subtype).isEqualTo("png") - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/media/LocalFileSystemMediaDataStoreTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/media/LocalFileSystemMediaDataStoreTest.kt deleted file mode 100644 index 580c64c4..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/media/LocalFileSystemMediaDataStoreTest.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.media - -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.application.config.LocalStorageConfig -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import java.net.URL -import java.nio.file.Path -import java.util.* -import kotlin.io.path.readBytes -import kotlin.io.path.toPath - -class LocalFileSystemMediaDataStoreTest { - - private val path = String.javaClass.classLoader.getResource("400x400.png")?.toURI()?.toPath()!! - - @Test - fun `save inputStreamを使用して正常に保存できる`() = runTest { - val applicationConfig = ApplicationConfig(URL("https://example.com")) - val storageConfig = LocalStorageConfig("files", null) - - val localFileSystemMediaDataStore = LocalFileSystemMediaDataStore(applicationConfig, storageConfig) - - val fileInputStream = path.readBytes() - - assertThat(fileInputStream.size).isNotEqualTo(0) - - val mediaSave = MediaSave( - "test-media-1${UUID.randomUUID()}.png", - "", - fileInputStream, - fileInputStream - ) - - val save = localFileSystemMediaDataStore.save(mediaSave) - - assertThat(save).isInstanceOf(SuccessSavedMedia::class.java) - - save as SuccessSavedMedia - - assertThat(Path.of("files").toAbsolutePath().resolve(save.name)) - .exists() - .hasSize(fileInputStream.size.toLong()) - assertThat(Path.of("files").toAbsolutePath().resolve("thumbnail-" + save.name)) - .exists() - .hasSize(fileInputStream.size.toLong()) - } - - @Test - fun 一時ファイルを使用して正常に保存できる() = runTest { - val applicationConfig = ApplicationConfig(URL("https://example.com")) - val storageConfig = LocalStorageConfig("files", null) - - val localFileSystemMediaDataStore = LocalFileSystemMediaDataStore(applicationConfig, storageConfig) - - val fileInputStream = path.readBytes() - - assertThat(fileInputStream.size).isNotEqualTo(0) - - val saveRequest = MediaSaveRequest( - "test-media-2${UUID.randomUUID()}.png", - "", - path, - path - ) - - val save = localFileSystemMediaDataStore.save(saveRequest) - - assertThat(save).isInstanceOf(SuccessSavedMedia::class.java) - - save as SuccessSavedMedia - - assertThat(Path.of("files").toAbsolutePath().resolve(save.name)) - .exists() - .hasSize(fileInputStream.size.toLong()) - assertThat(Path.of("files").toAbsolutePath().resolve("thumbnail-" + save.name)) - .exists() - .hasSize(fileInputStream.size.toLong()) - } - - @Test - fun idを使用して削除できる() = runTest { - val applicationConfig = ApplicationConfig(URL("https://example.com")) - val storageConfig = LocalStorageConfig("files", null) - - val localFileSystemMediaDataStore = LocalFileSystemMediaDataStore(applicationConfig, storageConfig) - - val fileInputStream = path.readBytes() - - assertThat(fileInputStream.size).isNotEqualTo(0) - - val saveRequest = MediaSaveRequest( - "test-media-2${UUID.randomUUID()}.png", - "", - path, - path - ) - - val save = localFileSystemMediaDataStore.save(saveRequest) - - assertThat(save).isInstanceOf(SuccessSavedMedia::class.java) - - save as SuccessSavedMedia - - assertThat(Path.of("files").toAbsolutePath().resolve(save.name)) - .exists() - .hasSize(fileInputStream.size.toLong()) - assertThat(Path.of("files").toAbsolutePath().resolve("thumbnail-" + save.name)) - .exists() - .hasSize(fileInputStream.size.toLong()) - - - localFileSystemMediaDataStore.delete(save.name) - - assertThat(Path.of("files").toAbsolutePath().resolve(save.name)) - .doesNotExist() - assertThat(Path.of("files").toAbsolutePath().resolve("thumbnail-" + save.name)) - .doesNotExist() - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/media/MediaServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/media/MediaServiceImplTest.kt deleted file mode 100644 index affa4b36..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/media/MediaServiceImplTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.media - - -import org.junit.jupiter.api.Test - -class MediaServiceImplTest { - @Test - fun png画像をアップロードできる() { - - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/FollowNotificationRequestTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/FollowNotificationRequestTest.kt deleted file mode 100644 index dcbcceb9..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/FollowNotificationRequestTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.notification - -import dev.usbharu.hideout.core.domain.model.notification.Notification -import org.assertj.core.api.Assertions -import org.junit.jupiter.api.Test -import java.time.Instant - -class FollowNotificationRequestTest { - - @Test - fun buildNotification() { - val createdAt = Instant.now() - val actual = FollowNotificationRequest(1, 2).buildNotification(1, createdAt) - - Assertions.assertThat(actual).isEqualTo( - Notification( - id = 1, - type = "follow", - userId = 1, - sourceActorId = 2, - postId = null, - text = null, - reactionId = null, - createdAt = createdAt - ) - ) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/FollowRequestNotificationRequestTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/FollowRequestNotificationRequestTest.kt deleted file mode 100644 index 0e577ffa..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/FollowRequestNotificationRequestTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.notification - -import dev.usbharu.hideout.core.domain.model.notification.Notification -import org.assertj.core.api.Assertions -import org.junit.jupiter.api.Test -import java.time.Instant - -class FollowRequestNotificationRequestTest { - - @Test - fun buildNotification() { - val createdAt = Instant.now() - val actual = FollowRequestNotificationRequest(1, 2).buildNotification(1, createdAt) - - Assertions.assertThat(actual).isEqualTo( - Notification( - id = 1, - type = "follow-request", - userId = 1, - sourceActorId = 2, - postId = null, - text = null, - reactionId = null, - createdAt = createdAt - ) - ) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/MentionNotificationRequestTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/MentionNotificationRequestTest.kt deleted file mode 100644 index 5bc72946..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/MentionNotificationRequestTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.notification - -import dev.usbharu.hideout.core.domain.model.notification.Notification -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import java.time.Instant - -class MentionNotificationRequestTest { - - @Test - fun buildNotification() { - val createdAt = Instant.now() - val actual = MentionNotificationRequest(1, 2, 3).buildNotification(1, createdAt) - - assertThat(actual).isEqualTo( - Notification( - id = 1, - type = "mention", - userId = 1, - sourceActorId = 2, - postId = 3, - text = null, - reactionId = null, - createdAt = createdAt - ) - ) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/NotificationServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/NotificationServiceImplTest.kt deleted file mode 100644 index c1daea13..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/NotificationServiceImplTest.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.notification - -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService -import dev.usbharu.hideout.core.domain.model.notification.Notification -import dev.usbharu.hideout.core.domain.model.notification.NotificationRepository -import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository -import kotlinx.coroutines.test.runTest -import org.assertj.core.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 org.mockito.kotlin.* -import utils.UserBuilder -import java.net.URL - -@ExtendWith(MockitoExtension::class) -class NotificationServiceImplTest { - - - @Mock - private lateinit var relationshipNotificationManagementService: RelationshipNotificationManagementService - - @Mock - private lateinit var relationshipRepository: RelationshipRepository - - @Spy - private val notificationStoreList: MutableList = mutableListOf() - - @Mock - private lateinit var notificationRepository: NotificationRepository - - @Mock - private lateinit var actorRepository: ActorRepository - - @Mock - private lateinit var postRepository: PostRepository - - @Mock - private lateinit var reactionRepository: ReactionRepository - - @Spy - private val applicationConfig = ApplicationConfig(URL("https://example.com")) - - @InjectMocks - private lateinit var notificationServiceImpl: NotificationServiceImpl - - @Test - fun `publishNotifi ローカルユーザーへの通知を発行する`() = runTest { - - val actor = UserBuilder.localUserOf(domain = "example.com") - - whenever(actorRepository.findById(eq(1))).doReturn(actor) - - val id = TwitterSnowflakeIdGenerateService.generateId() - - whenever(notificationRepository.generateId()).doReturn(id) - - whenever(notificationRepository.save(any())).doAnswer { it.arguments[0] as Notification } - - - val actual = notificationServiceImpl.publishNotify(PostNotificationRequest(1, 2, 3)) - - assertThat(actual).isNotNull() - - verify(notificationRepository, times(1)).save(any()) - } - - @Test - fun `publishNotify ユーザーが存在しないときは発行しない`() = runTest { - val actual = notificationServiceImpl.publishNotify(PostNotificationRequest(1, 2, 3)) - - assertThat(actual).isNull() - } - - @Test - fun `publishNotify ユーザーがリモートユーザーの場合は発行しない`() = runTest { - val actor = UserBuilder.remoteUserOf(domain = "remote.example.com") - - whenever(actorRepository.findById(eq(1))).doReturn(actor) - - val actual = notificationServiceImpl.publishNotify(PostNotificationRequest(1, 2, 3)) - - assertThat(actual).isNull() - } - - @Test - fun unpublishNotify() = runTest { - notificationServiceImpl.unpublishNotify(1) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/PostNotificationRequestTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/PostNotificationRequestTest.kt deleted file mode 100644 index bc5bee91..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/PostNotificationRequestTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.notification - -import dev.usbharu.hideout.core.domain.model.notification.Notification -import org.assertj.core.api.Assertions -import org.junit.jupiter.api.Test -import java.time.Instant - -class PostNotificationRequestTest { - - @Test - fun buildNotification() { - val createdAt = Instant.now() - val actual = PostNotificationRequest(1, 2, 3).buildNotification(1, createdAt) - - Assertions.assertThat(actual).isEqualTo( - Notification( - id = 1, - type = "post", - userId = 1, - sourceActorId = 2, - postId = 3, - text = null, - reactionId = null, - createdAt = createdAt - ) - ) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/ReactionNotificationRequestTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/ReactionNotificationRequestTest.kt deleted file mode 100644 index 87483dcd..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/ReactionNotificationRequestTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.notification - -import dev.usbharu.hideout.core.domain.model.notification.Notification -import org.assertj.core.api.Assertions -import org.junit.jupiter.api.Test -import java.time.Instant - -class ReactionNotificationRequestTest { - - @Test - fun buildNotification() { - val createdAt = Instant.now() - val actual = ReactionNotificationRequest(1, 2, 3, 4).buildNotification(1, createdAt) - - Assertions.assertThat(actual).isEqualTo( - Notification( - id = 1, - type = "reaction", - userId = 1, - sourceActorId = 2, - postId = 3, - text = null, - reactionId = 4, - createdAt = createdAt - ) - ) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/RelationshipNotificationManagementServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/RelationshipNotificationManagementServiceImplTest.kt deleted file mode 100644 index 30508ea1..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/RelationshipNotificationManagementServiceImplTest.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.notification - -import dev.usbharu.hideout.domain.mastodon.model.generated.Relationship -import org.junit.jupiter.api.Test -import kotlin.test.assertTrue - -class RelationshipNotificationManagementServiceImplTest { - @Test - fun `sendNotification ミューとしていない場合送信する`() { - val notification = RelationshipNotificationManagementServiceImpl().sendNotification( - Relationship( - 1, - 2, - false, - false, - false, - false, - false - ), PostNotificationRequest(1, 2, 3) - ) - - assertTrue(notification) - - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/RepostNotificationRequestTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/RepostNotificationRequestTest.kt deleted file mode 100644 index b50f9551..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/notification/RepostNotificationRequestTest.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.notification - -import dev.usbharu.hideout.core.domain.model.notification.Notification -import org.assertj.core.api.Assertions -import org.junit.jupiter.api.Test -import java.time.Instant - -class RepostNotificationRequestTest { - - @Test - fun buildNotification() { - val createdAt = Instant.now() - val actual = RepostNotificationRequest(1, 2, 3).buildNotification(1, createdAt) - - Assertions.assertThat(actual).isEqualTo( - Notification( - id = 1, - type = "repost", - userId = 1, - sourceActorId = 2, - postId = 3, - text = null, - reactionId = null, - createdAt = createdAt - ) - ) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/post/DefaultPostContentFormatterTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/post/DefaultPostContentFormatterTest.kt deleted file mode 100644 index 8725dd63..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/post/DefaultPostContentFormatterTest.kt +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.post - -import dev.usbharu.hideout.application.config.HtmlSanitizeConfig -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class DefaultPostContentFormatterTest { - val defaultPostContentFormatter = DefaultPostContentFormatter(HtmlSanitizeConfig().policy()) - - @Test - fun pタグがpタグになる() { - //language=HTML - val html = """

hoge

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

", "hoge")) - } - - @Test - fun hタグがpタグになる() { - //language=HTML - val html = """

hoge

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

", "hoge")) - } - - @Test - fun pタグのネストは破棄される() { - //language=HTML - val html = """

hoge

fuga

piyo

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

fuga

piyo

", "hoge\n\nfuga\n\npiyo")) - } - - @Test - fun spanタグは無視される() { - //language=HTML - val html = """

hoge

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

", "hoge")) - } - - @Test - fun `2連続改行は段落に変換される`() { - //language=HTML - val html = """

hoge

fuga

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

fuga

", "hoge\n\nfuga")) - } - - @Test - fun iタグは無視される() { - //language=HTML - val html = """

hoge

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

", "hoge")) - } - - @Test - fun aタグはhrefの中身のみ引き継がれる() { - //language=HTML - val html = """

hoge

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

", "hoge")) - } - - @Test - fun aタグの中のspanは無視される() { - //language=HTML - val html = """

hoge

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

", "hoge")) - } - - @Test - fun brタグのコンテンツは改行になる() { - //language=HTML - val html = """

hoge
fuga

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge
fuga

", "hoge\nfuga")) - } - - @Test - fun いきなりテキストが来たらpタグで囲む() { - //language=HTML - val html = """hoge""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

", "hoge")) - } - - @Test - fun bodyタグが含まれていた場合消す() { - //language=HTML - val html = """

hoge

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo(FormattedPostContent("

hoge

", "hoge")) - } - - @Test - fun pタグの中のspanは無視される() { - //language=HTML - val html = - """

@testuser14 tes

""" - - val actual = defaultPostContentFormatter.format(html) - - assertThat(actual).isEqualTo( - FormattedPostContent( - "

@testuser14 tes

", - "@testuser14 tes" - ) - ) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImplTest.kt deleted file mode 100644 index 8d7c1676..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImplTest.kt +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.post - -import dev.usbharu.hideout.activitypub.service.activity.create.ApSendCreateService -import dev.usbharu.hideout.activitypub.service.activity.delete.APSendDeleteService -import dev.usbharu.hideout.application.config.CharacterLimit -import dev.usbharu.hideout.application.config.HtmlSanitizeConfig -import dev.usbharu.hideout.core.domain.exception.resource.DuplicateException -import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository -import jakarta.validation.Validation -import kotlinx.coroutines.test.runTest -import org.assertj.core.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.Mockito -import org.mockito.Mockito.mockStatic -import org.mockito.Spy -import org.mockito.junit.jupiter.MockitoExtension -import org.mockito.kotlin.* -import utils.PostBuilder -import utils.UserBuilder -import java.time.Instant - -@ExtendWith(MockitoExtension::class) -class PostServiceImplTest { - - @Mock - private lateinit var postRepository: PostRepository - - @Mock - private lateinit var actorRepository: ActorRepository - - @Mock - private lateinit var timelineService: TimelineService - @Spy - private var postBuilder: Post.PostBuilder = Post.PostBuilder( - CharacterLimit(), DefaultPostContentFormatter( - HtmlSanitizeConfig().policy() - ), Validation.buildDefaultValidatorFactory().validator - ) - - @Mock - private lateinit var apSendCreateService: ApSendCreateService - - @Mock - private lateinit var reactionRepository: ReactionRepository - - @Mock - private lateinit var apSendDeleteService: APSendDeleteService - - @InjectMocks - private lateinit var postServiceImpl: PostServiceImpl - - @Test - fun `createLocal 正常にpostを作成できる`() = runTest { - - val now = Instant.now() - val post = PostBuilder.of(createdAt = now.toEpochMilli()) - - whenever(postRepository.save(eq(post))).doReturn(post) - whenever(postRepository.generateId()).doReturn(post.id) - whenever(actorRepository.findById(eq(post.actorId))).doReturn(UserBuilder.localUserOf(id = post.actorId)) - whenever(timelineService.publishTimeline(eq(post), eq(true))).doReturn(Unit) - - mockStatic(Instant::class.java, Mockito.CALLS_REAL_METHODS).use { - - it.`when`(Instant::now).doReturn(now) - val createLocal = postServiceImpl.createLocal( - PostCreateDto( - post.text, - post.overview, - post.visibility, - post.repostId, - post.replyId, - post.actorId, - post.mediaIds - ) - ) - - assertThat(createLocal).isEqualTo(post) - } - - verify(postRepository, times(1)).save(eq(post)) - verify(timelineService, times(1)).publishTimeline(eq(post), eq(true)) - verify(apSendCreateService, times(1)).createNote(eq(post)) - } - - @Test - fun `createRemote 正常にリモートのpostを作成できる`() = runTest { - val post = PostBuilder.of() - - whenever(actorRepository.findById(eq(post.actorId))).doReturn(UserBuilder.remoteUserOf(id = post.actorId)) - whenever(postRepository.save(eq(post))).doReturn(post) - whenever(timelineService.publishTimeline(eq(post), eq(false))).doReturn(Unit) - - - val createLocal = postServiceImpl.createRemote(post) - - assertThat(createLocal).isEqualTo(post) - - - verify(postRepository, times(1)).save(eq(post)) - verify(timelineService, times(1)).publishTimeline(eq(post), eq(false)) - } - - @Test - fun `createRemote 既に作成されていた場合はそのまま帰す`() = runTest { - val post = PostBuilder.of() - - whenever(actorRepository.findById(eq(post.actorId))).doReturn(UserBuilder.remoteUserOf(id = post.actorId)) - whenever(postRepository.save(eq(post))).doAnswer { throw DuplicateException() } - whenever(postRepository.findByApId(eq(post.apId))).doReturn(post) - - val createLocal = postServiceImpl.createRemote(post) - - assertThat(createLocal).isEqualTo(post) - - verify(postRepository, times(1)).save(eq(post)) - verify(timelineService, times(0)).publishTimeline(any(), any()) - } - - @Test - fun `createRemote 既に作成されていることを検知出来ずタイムラインにpush出来なかった場合何もしない`() = runTest { - val post = PostBuilder.of() - - whenever(actorRepository.findById(eq(post.actorId))).doReturn(UserBuilder.remoteUserOf(id = post.actorId)) - whenever(postRepository.save(eq(post))).doReturn(post) - whenever(timelineService.publishTimeline(eq(post), eq(false))).doThrow(DuplicateException::class) - whenever(postRepository.findByApId(eq(post.apId))).doReturn(post) - - val createLocal = postServiceImpl.createRemote(post) - - assertThat(createLocal).isEqualTo(post) - - verify(postRepository, times(1)).save(eq(post)) - verify(timelineService, times(1)).publishTimeline(eq(post), eq(false)) - } - - @Test - fun `deleteLocal Deleteが配送される`() = runTest { - val post = PostBuilder.of() - - val localUserOf = UserBuilder.localUserOf() - - whenever(actorRepository.findById(eq(post.actorId))).doReturn(localUserOf) - - postServiceImpl.deleteLocal(post) - - verify(reactionRepository, times(1)).deleteByPostId(eq(post.id)) - verify(postRepository, times(1)).save(eq(post.delete())) - verify(apSendDeleteService, times(1)).sendDeleteNote(eq(post)) - verify(actorRepository, times(1)).save(eq(localUserOf.decrementPostsCount())) - } - - @Test - fun `deleteLocal 削除済み投稿は何もしない`() = runTest { - val delete = PostBuilder.of().delete() - - postServiceImpl.deleteLocal(delete) - - verify(reactionRepository, never()).deleteByPostId(any()) - verify(postRepository, never()).save(any()) - verify(apSendDeleteService, never()).sendDeleteNote(any()) - verify(actorRepository, never()).save(any()) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/reaction/ReactionServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/reaction/ReactionServiceImplTest.kt deleted file mode 100644 index c02bfa10..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/reaction/ReactionServiceImplTest.kt +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.reaction - - -import dev.usbharu.hideout.activitypub.service.activity.like.APReactionService -import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService -import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji -import dev.usbharu.hideout.core.domain.model.reaction.Reaction -import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository -import dev.usbharu.hideout.core.service.notification.NotificationService -import kotlinx.coroutines.test.runTest -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.* -import utils.PostBuilder - -@ExtendWith(MockitoExtension::class) -class ReactionServiceImplTest { - - @Mock - private lateinit var notificationService: NotificationService - - @Mock - private lateinit var postRepository: PostRepository - - @Mock - private lateinit var reactionRepository: ReactionRepository - - @Mock - private lateinit var apReactionService: APReactionService - - @InjectMocks - private lateinit var reactionServiceImpl: ReactionServiceImpl - - @Test - fun `receiveReaction リアクションが存在しないとき保存する`() = runTest { - - val post = PostBuilder.of() - - whenever(reactionRepository.existByPostIdAndActor(eq(post.id), eq(post.actorId))).doReturn( - false - ) - whenever(postRepository.findById(eq(post.id))).doReturn(post) - whenever(reactionRepository.save(any())).doAnswer { it.arguments[0] as Reaction } - - val generateId = TwitterSnowflakeIdGenerateService.generateId() - whenever(reactionRepository.generateId()).doReturn(generateId) - - reactionServiceImpl.receiveReaction(UnicodeEmoji("❤"), post.actorId, post.id) - - verify(reactionRepository, times(1)).save(eq(Reaction(generateId, UnicodeEmoji("❤"), post.id, post.actorId))) - } - - - @Test - fun `receiveReaction リアクションが既に作成されている場合削除して新しく作成`() = runTest { - val post = PostBuilder.of() - whenever(reactionRepository.existByPostIdAndActor(eq(post.id), eq(post.actorId))).doReturn( - true - ) - whenever(postRepository.findById(eq(post.id))).doReturn(post) - whenever(reactionRepository.save(any())).doAnswer { it.arguments[0] as Reaction } - val generateId = TwitterSnowflakeIdGenerateService.generateId() - - whenever(reactionRepository.generateId()).doReturn(generateId) - - reactionServiceImpl.receiveReaction(UnicodeEmoji("❤"), post.actorId, post.id) - - verify(reactionRepository, times(1)).deleteByPostIdAndActorId(post.id, post.actorId) - verify(reactionRepository, times(1)).save(Reaction(generateId, UnicodeEmoji("❤"), post.id, post.actorId)) - } - - @Test - fun `sendReaction リアクションが存在しないとき保存して配送する`() = runTest { - val post = PostBuilder.of() - whenever(reactionRepository.findByPostIdAndActorIdAndEmojiId(eq(post.id), eq(post.actorId), eq(0))).doReturn( - null - ) - whenever(postRepository.findById(eq(post.id))).doReturn(post) - whenever(reactionRepository.save(any())).doAnswer { it.arguments[0] as Reaction } - val generateId = TwitterSnowflakeIdGenerateService.generateId() - whenever(reactionRepository.generateId()).doReturn(generateId) - - reactionServiceImpl.sendReaction(UnicodeEmoji("❤"), post.actorId, post.id) - - verify(reactionRepository, times(1)).save(eq(Reaction(generateId, UnicodeEmoji("❤"), post.id, post.actorId))) - verify(apReactionService, times(1)).reaction(eq(Reaction(generateId, UnicodeEmoji("❤"), post.id, post.actorId))) - } - - @Test - fun `sendReaction リアクションが存在するときは削除して保存して配送する`() = runTest { - val post = PostBuilder.of() - val id = TwitterSnowflakeIdGenerateService.generateId() - whenever(reactionRepository.findByPostIdAndActorIdAndEmojiId(eq(post.id), eq(post.actorId), eq(0))).doReturn( - Reaction(id, UnicodeEmoji("❤"), post.id, post.actorId) - ) - whenever(postRepository.findById(eq(post.id))).doReturn(post) - whenever(reactionRepository.save(any())).doAnswer { it.arguments[0] as Reaction } - val generateId = TwitterSnowflakeIdGenerateService.generateId() - whenever(reactionRepository.generateId()).doReturn(generateId) - - reactionServiceImpl.sendReaction(UnicodeEmoji("❤"), post.actorId, post.id) - - - verify(reactionRepository, times(1)).delete(eq(Reaction(id, UnicodeEmoji("❤"), post.id, post.actorId))) - verify(reactionRepository, times(1)).save(eq(Reaction(generateId, UnicodeEmoji("❤"), post.id, post.actorId))) - verify(apReactionService, times(1)).removeReaction(eq(Reaction(id, UnicodeEmoji("❤"), post.id, post.actorId))) - verify(apReactionService, times(1)).reaction(eq(Reaction(generateId, UnicodeEmoji("❤"), post.id, post.actorId))) - } - - @Test - fun `removeReaction リアクションが存在する場合削除して配送`() = runTest { - val post = PostBuilder.of() - whenever(reactionRepository.findByPostIdAndActorIdAndEmojiId(eq(post.id), eq(post.actorId), eq(0))).doReturn( - Reaction(0, UnicodeEmoji("❤"), post.id, post.actorId) - ) - - reactionServiceImpl.removeReaction(post.actorId, post.id) - - verify(reactionRepository, times(1)).delete(eq(Reaction(0, UnicodeEmoji("❤"), post.id, post.actorId))) - verify(apReactionService, times(1)).removeReaction(eq(Reaction(0, UnicodeEmoji("❤"), post.id, post.actorId))) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/relationship/RelationshipServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/relationship/RelationshipServiceImplTest.kt deleted file mode 100644 index acff5e20..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/relationship/RelationshipServiceImplTest.kt +++ /dev/null @@ -1,795 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.relationship - -import dev.usbharu.hideout.activitypub.service.activity.accept.ApSendAcceptService -import dev.usbharu.hideout.activitypub.service.activity.follow.APSendFollowService -import dev.usbharu.hideout.activitypub.service.activity.reject.ApSendRejectService -import dev.usbharu.hideout.activitypub.service.activity.undo.APSendUndoService -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.core.service.notification.NotificationService -import dev.usbharu.hideout.domain.mastodon.model.generated.Relationship -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -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.* -import utils.UserBuilder -import java.net.URL - -@ExtendWith(MockitoExtension::class) -class RelationshipServiceImplTest { - - - @Mock - private lateinit var notificationService: NotificationService - - @Spy - private val applicationConfig = ApplicationConfig(URL("https://example.com")) - - @Mock - private lateinit var relationshipRepository: RelationshipRepository - - @Mock - private lateinit var apSendFollowService: APSendFollowService - - @Mock - private lateinit var apSendAcceptService: ApSendAcceptService - - @Mock - private lateinit var apSendRejectService: ApSendRejectService - - @Mock - private lateinit var apSendUndoService: APSendUndoService - - @Mock - private lateinit var actorRepository: ActorRepository - - @InjectMocks - private lateinit var relationshipServiceImpl: RelationshipServiceImpl - - @Test - fun `followRequest ローカルの場合followRequestフラグがtrueで永続化される`() = runTest { - whenever(actorRepository.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com")) - - relationshipServiceImpl.followRequest(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = false, - followRequest = true, - ignoreFollowRequestToTarget = false - ) - ) - ) - } - - @Test - fun `followRequest リモートの場合Followアクティビティが配送される`() = runTest { - val localUser = UserBuilder.localUserOf(domain = "example.com") - whenever(actorRepository.findById(eq(1234))).doReturn(localUser) - val remoteUser = UserBuilder.remoteUserOf(domain = "remote.example.com") - whenever(actorRepository.findById(eq(5678))).doReturn(remoteUser) - - relationshipServiceImpl.followRequest(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = false, - followRequest = true, - ignoreFollowRequestToTarget = false - ) - ) - ) - - verify(apSendFollowService, times(1)).sendFollow(eq(SendFollowDto(localUser, remoteUser))) - } - - @Test - fun `followRequest ブロックされている場合フォローリクエスト出来ない`() = runTest { - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn(null) - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = true, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.followRequest(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `followRequest ブロックしている場合フォローリクエスト出来ない`() = runTest { - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = true, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.followRequest(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `followRequest 既にフォローしている場合は念の為フォロー承認を自動で行う`() = runTest { - val remoteUser = UserBuilder.remoteUserOf(domain = "remote.example.com") - whenever(actorRepository.findById(eq(1234))).doReturn(remoteUser) - val localUser = UserBuilder.localUserOf(domain = "example.com") - whenever(actorRepository.findById(eq(5678))).doReturn(localUser) - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.followRequest(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - - verify(apSendAcceptService, times(1)).sendAcceptFollow(eq(localUser), eq(remoteUser)) - verify(apSendFollowService, never()).sendFollow(any()) - } - - @Test - fun `followRequest フォローリクエスト無視の場合は無視する`() = runTest { - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = true - ) - ) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.followRequest(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `block ローカルユーザーの場合永続化される`() = runTest { - whenever(actorRepository.findById(eq(1234))).doReturn(UserBuilder.localUserOf(domain = "example.com")) - whenever(actorRepository.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com")) - - relationshipServiceImpl.block(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = true, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - } - - @Test - fun `block リモートユーザーの場合永続化されて配送される`() = runTest { - val localUser = UserBuilder.localUserOf(domain = "example.com") - whenever(actorRepository.findById(eq(1234))).doReturn(localUser) - val remoteUser = UserBuilder.remoteUserOf(domain = "remote.example.com") - whenever(actorRepository.findById(eq(5678))).doReturn(remoteUser) - - relationshipServiceImpl.block(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = true, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - } - - @Test - fun `acceptFollowRequest ローカルユーザーの場合永続化される`() = runTest { - whenever(actorRepository.findById(eq(1234))).doReturn(UserBuilder.localUserOf(domain = "example.com")) - whenever(actorRepository.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com")) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = false, - muting = false, - followRequest = true, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.acceptFollowRequest(1234, 5678, false) - - verify(relationshipRepository, times(1)).save( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - verify(apSendAcceptService, never()).sendAcceptFollow(any(), any()) - } - - @Test - fun `acceptFollowRequest リモートユーザーの場合永続化されて配送される`() = runTest { - val localUser = UserBuilder.localUserOf(domain = "example.com") - whenever(actorRepository.findById(eq(1234))).doReturn(localUser) - val remoteUser = UserBuilder.remoteUserOf(domain = "remote.example.com") - whenever(actorRepository.findById(eq(5678))).doReturn(remoteUser) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = false, - muting = false, - followRequest = true, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.acceptFollowRequest(1234, 5678, false) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - - verify(apSendAcceptService, times(1)).sendAcceptFollow(eq(localUser), eq(remoteUser)) - } - - @Test - fun `acceptFollowRequest Relationshipが存在しないときは何もしない`() = runTest { - relationshipServiceImpl.acceptFollowRequest(1234, 5678, false) - - verify(apSendAcceptService, never()).sendAcceptFollow(any(), any()) - } - - @Test - fun `acceptFollowRequest フォローリクエストが存在せずforceがfalseのとき何もしない`() = runTest { - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - 5678, 1234, false, false, false, false, false - ) - ) - - relationshipServiceImpl.acceptFollowRequest(1234, 5678, false) - - verify(apSendAcceptService, never()).sendAcceptFollow(any(), any()) - } - - @Test - fun `acceptFollowRequest フォローリクエストが存在せずforceがtrueのときフォローを承認する`() = runTest { - whenever(actorRepository.findById(eq(1234))).doReturn(UserBuilder.localUserOf(domain = "example.com")) - whenever(actorRepository.findById(eq(5678))).doReturn(UserBuilder.remoteUserOf(domain = "remote.example.com")) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - 5678, 1234, false, false, false, false, false - ) - ) - - relationshipServiceImpl.acceptFollowRequest(1234, 5678, true) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - } - - @Test - fun `acceptFollowRequest ブロックしている場合は何もしない`() = runTest { - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - 5678, 1234, false, true, false, true, false - ) - ) - - assertThrows { - relationshipServiceImpl.acceptFollowRequest(1234, 5678, false) - } - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `acceptFollowRequest ブロックされている場合は何もしない`() = runTest { - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - 1234, 5678, false, false, false, true, false - ) - ) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - 5678, 1234, false, true, false, true, false - ) - ) - - assertThrows { - relationshipServiceImpl.acceptFollowRequest(1234, 5678, false) - } - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `rejectFollowRequest ローカルユーザーの場合永続化される`() = runTest { - whenever(actorRepository.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com")) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = false, - muting = false, - followRequest = true, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.rejectFollowRequest(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - - verify(apSendRejectService, never()).sendRejectFollow(any(), any()) - } - - @Test - fun `rejectFollowRequest リモートユーザーの場合永続化されて配送される`() = runTest { - val localUser = UserBuilder.localUserOf(domain = "example.com") - whenever(actorRepository.findById(eq(1234))).doReturn(localUser) - - val remoteUser = UserBuilder.remoteUserOf(domain = "remote.example.com") - whenever(actorRepository.findById(eq(5678))).doReturn(remoteUser) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = false, - muting = false, - followRequest = true, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.rejectFollowRequest(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - - verify(apSendRejectService, times(1)).sendRejectFollow(eq(localUser), eq(remoteUser)) - } - - @Test - fun `rejectFollowRequest Relationshipが存在しないとき何もしない`() = runTest { - - relationshipServiceImpl.rejectFollowRequest(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `rejectFollowRequest フォローリクエストが存在しない場合何もしない`() = runTest { - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.rejectFollowRequest(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `ignoreFollowRequest 永続化される`() = runTest { - relationshipServiceImpl.ignoreFollowRequest(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 5678, - targetActorId = 1234, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = true - ) - ) - ) - } - - @Test - fun `unfollow ローカルユーザーの場合永続化される`() = runTest { - whenever(actorRepository.findById(eq(1234))).doReturn(UserBuilder.remoteUserOf(domain = "remote.example.com")) - whenever(actorRepository.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com")) - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.unfollow(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - - verify(apSendUndoService, never()).sendUndoFollow(any(), any()) - } - - @Test - fun `unfollow リモートユーザー場合永続化されて配送される`() = runTest { - val localUser = UserBuilder.localUserOf(domain = "example.com") - whenever(actorRepository.findById(eq(1234))).doReturn(localUser) - - val remoteUser = UserBuilder.remoteUserOf(domain = "remote.example.com") - whenever(actorRepository.findById(eq(5678))).doReturn(remoteUser) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.unfollow(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - - verify(apSendUndoService, times(1)).sendUndoFollow(eq(localUser), eq(remoteUser)) - } - - @Test - fun `unfollow Relationshipが存在しないときは何もしない`() = runTest { - relationshipServiceImpl.unfollow(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `unfollow フォローしていなかった場合は何もしない`() = runTest { - whenever(actorRepository.findById(eq(1234))).doReturn(UserBuilder.localUserOf(id = 1234)) - whenever(actorRepository.findById(eq(5678))).doReturn(UserBuilder.localUserOf(id = 5678)) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.unfollow(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `unblock ローカルユーザーの場合永続化される`() = runTest { - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = true, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.unblock(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - } - - @Test - fun `unblock リモートユーザーの場合永続化されて配送される`() = runTest { - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = true, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.unblock(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - 1234, - 5678, - false, - false, - false, - false, - false - ) - ) - ) - } - - @Test - fun `unblock Relationshipがない場合何もしない`() = runTest { - relationshipServiceImpl.unblock(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `unblock ブロックしていない場合は何もしない`() = runTest { - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.unblock(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } - - @Test - fun `mute ミュートが永続化される`() = runTest { - relationshipServiceImpl.mute(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = true, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - } - - @Test - fun `unmute 永続化される`() = runTest { - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = true, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - relationshipServiceImpl.unmute(1234, 5678) - - verify(relationshipRepository, times(1)).save( - eq( - Relationship( - actorId = 1234, - targetActorId = 5678, - following = false, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - ) - } - - @Test - fun `unmute Relationshipが存在しない場合は何もしない`() = runTest { - relationshipServiceImpl.unmute(1234, 5678) - - verify(relationshipRepository, never()).save(any()) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/resource/KtorResourceResolveServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/resource/KtorResourceResolveServiceTest.kt deleted file mode 100644 index a170e13e..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/resource/KtorResourceResolveServiceTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.resource - -import dev.usbharu.hideout.application.config.MediaConfig -import dev.usbharu.hideout.core.domain.exception.media.RemoteMediaFileSizeException -import io.ktor.client.* -import io.ktor.client.engine.mock.* -import io.ktor.http.* -import io.ktor.http.HttpHeaders.ContentLength -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.InjectMocks -import org.mockito.Spy -import org.mockito.junit.jupiter.MockitoExtension - -@ExtendWith(MockitoExtension::class) -class KtorResourceResolveServiceTest { - - @Spy - private val httpClient: HttpClient = HttpClient(MockEngine { - when (it.url.encodedPath) { - "/over-size-limit" -> { - respond(ByteArray(1000), HttpStatusCode.OK, Headers.build { - append(ContentLength, "1000") - }) - } - - else -> { - respond("Not Found", HttpStatusCode.NotFound) - } - } - }) { - expectSuccess = true - } - - @Spy - private val cacheManager: CacheManager = InMemoryCacheManager() - - @Spy - private val mediaConfig: MediaConfig = MediaConfig() - - @InjectMocks - private lateinit var ktorResourceResolveService: KtorResourceResolveService - - @Test - fun ファイルサイズ制限を超えたときRemoteMediaFileSizeExceptionが発生する() = runTest { - ktorResourceResolveService.sizeLimit = 100L - assertThrows { - ktorResourceResolveService.resolve("https://example.com/over-size-limit") - } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/timeline/TimelineServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/timeline/TimelineServiceTest.kt deleted file mode 100644 index 71c05e4a..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/timeline/TimelineServiceTest.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.core.service.timeline - -import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService -import dev.usbharu.hideout.core.domain.model.post.Visibility -import kotlinx.coroutines.test.runTest -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentCaptor -import org.mockito.Captor -import org.mockito.InjectMocks -import org.mockito.Mock -import org.mockito.junit.jupiter.MockitoExtension -import org.mockito.kotlin.* -import utils.PostBuilder -import utils.UserBuilder - -@ExtendWith(MockitoExtension::class) -class TimelineServiceTest { - - @Mock - private lateinit var followerQueryService: FollowerQueryService - - @Mock - private lateinit var actorRepository: ActorRepository - - @Mock - private lateinit var timelineRepository: TimelineRepository - - @InjectMocks - private lateinit var timelineService: TimelineService - - @Captor - private lateinit var captor: ArgumentCaptor> - - @Test - fun `publishTimeline ローカルの投稿はローカルのフォロワーと投稿者のタイムラインに追加される`() = runTest { - val post = PostBuilder.of() - val listOf = listOf(UserBuilder.localUserOf(), UserBuilder.localUserOf()) - val localUserOf = UserBuilder.localUserOf(id = post.actorId) - - whenever(followerQueryService.findFollowersById(eq(post.actorId))).doReturn(listOf) - whenever(actorRepository.findById(eq(post.actorId))).doReturn(localUserOf) - whenever(timelineRepository.generateId()).doReturn(TwitterSnowflakeIdGenerateService.generateId()) - - - timelineService.publishTimeline(post, true) - - verify(timelineRepository).saveAll(capture(captor)) - val timelineList = captor.value - - assertThat(timelineList).hasSize(4).anyMatch { it.userId == post.actorId } - } - - @Test - fun `publishTimeline リモートの投稿はローカルのフォロワーのタイムラインに追加される`() = runTest { - val post = PostBuilder.of() - val listOf = listOf(UserBuilder.localUserOf(), UserBuilder.localUserOf()) - - whenever(followerQueryService.findFollowersById(eq(post.actorId))).doReturn(listOf) - whenever(timelineRepository.generateId()).doReturn(TwitterSnowflakeIdGenerateService.generateId()) - - - timelineService.publishTimeline(post, false) - - verify(timelineRepository).saveAll(capture(captor)) - val timelineList = captor.value - - assertThat(timelineList).hasSize(3) - } - - @Test - fun `publishTimeline パブリック投稿はパブリックタイムラインにも追加される`() = runTest { - val post = PostBuilder.of() - val listOf = listOf(UserBuilder.localUserOf(), UserBuilder.localUserOf()) - - whenever(followerQueryService.findFollowersById(eq(post.actorId))).doReturn(listOf) - whenever(timelineRepository.generateId()).doReturn(TwitterSnowflakeIdGenerateService.generateId()) - - - timelineService.publishTimeline(post, false) - - verify(timelineRepository).saveAll(capture(captor)) - val timelineList = captor.value - - assertThat(timelineList).hasSize(3).anyMatch { it.userId == 0L } - } - - @Test - fun `publishTimeline パブリック投稿ではない場合はローカルのフォロワーのみに追加される`() = runTest { - val post = PostBuilder.of(visibility = Visibility.UNLISTED) - val listOf = listOf(UserBuilder.localUserOf(), UserBuilder.localUserOf()) - - whenever(followerQueryService.findFollowersById(eq(post.actorId))).doReturn(listOf) - whenever(timelineRepository.generateId()).doReturn(TwitterSnowflakeIdGenerateService.generateId()) - - - timelineService.publishTimeline(post, false) - - verify(timelineRepository).saveAll(capture(captor)) - val timelineList = captor.value - - assertThat(timelineList).hasSize(2).noneMatch { it.userId == 0L } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/user/ActorServiceTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/user/ActorServiceTest.kt deleted file mode 100644 index feb0cc4f..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/core/service/user/ActorServiceTest.kt +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@file:OptIn(ExperimentalCoroutinesApi::class) - -package dev.usbharu.hideout.core.service.user - -import dev.usbharu.hideout.activitypub.service.activity.delete.APSendDeleteService -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.application.config.CharacterLimit -import dev.usbharu.hideout.core.domain.model.deletedActor.DeletedActorRepository -import dev.usbharu.hideout.core.domain.model.instance.Instance -import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository -import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository -import dev.usbharu.owl.producer.api.OwlProducer -import jakarta.validation.Validation -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentMatchers.anyString -import org.mockito.InjectMocks -import org.mockito.Mock -import org.mockito.Spy -import org.mockito.junit.jupiter.MockitoExtension -import org.mockito.kotlin.* -import utils.TestApplicationConfig.testApplicationConfig -import java.net.URL -import java.security.KeyPairGenerator -import java.time.Instant -import kotlin.test.assertEquals -import kotlin.test.assertNull - -@ExtendWith(MockitoExtension::class) -class ActorServiceTest { - - @Mock - private lateinit var actorRepository: ActorRepository - - @Mock - private lateinit var userAuthService: UserAuthService - - @Spy - private val actorBuilder = Actor.UserBuilder( - CharacterLimit(), - ApplicationConfig(URL("https://example.com")), - Validation.buildDefaultValidatorFactory().validator - ) - - @Spy - private val applicationConfig: ApplicationConfig = testApplicationConfig.copy(private = false) - - @Mock - private lateinit var instanceService: InstanceService - - @Mock - private lateinit var userDetailRepository: UserDetailRepository - - @Mock - private lateinit var deletedActorRepository: DeletedActorRepository - - @Mock - private lateinit var reactionRepository: ReactionRepository - - @Mock - private lateinit var relationshipRepository: RelationshipRepository - - @Mock - private lateinit var postService: PostService - - @Mock - private lateinit var apSendDeleteService: APSendDeleteService - - @Mock - private lateinit var postRepository: PostRepository - - @Mock - private lateinit var owlProducer: OwlProducer - - @InjectMocks - private lateinit var userService: UserServiceImpl - - @Test - fun `createLocalUser ローカルユーザーを作成できる`() = runTest { - - val generateKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair() - whenever(actorRepository.nextId()).doReturn(110001L) - whenever(userAuthService.hash(anyString())).doReturn("hashedPassword") - whenever(userAuthService.generateKeyPair()).doReturn(generateKeyPair) - - - - userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test")) - verify(actorRepository, times(1)).save(any()) - argumentCaptor { - verify(actorRepository, times(1)).save(capture()) - assertEquals("test", firstValue.name) - assertEquals("testUser", firstValue.screenName) - assertEquals("XXXXXXXXXXXXX", firstValue.description) - assertEquals(110001L, firstValue.id) - assertEquals("https://example.com/users/test", firstValue.url) - assertEquals("example.com", firstValue.domain) - assertEquals("https://example.com/users/test/inbox", firstValue.inbox) - assertEquals("https://example.com/users/test/outbox", firstValue.outbox) - assertEquals(generateKeyPair.public.toPem(), firstValue.publicKey) - assertEquals(generateKeyPair.private.toPem(), firstValue.privateKey) - } - } - - @Test - fun `createLocalUser applicationconfig privateがtrueのときアカウントを作成できない`() = runTest { - whenever(applicationConfig.private).thenReturn(true) - - assertThrows { - userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test")) - } - - } - - @Test - fun `createRemoteUser リモートユーザーを作成できる`() = runTest { - - whenever(actorRepository.nextId()).doReturn(113345L) - whenever(instanceService.fetchInstance(eq("https://remote.example.com"), isNull())).doReturn( - Instance( - 12345L, - "", - "", - "https://remote.example.com", - "https://remote.example.com/favicon.ico", - null, - "unknown", - "", - false, - false, - "", - Instant.now() - ) - ) - - val user = RemoteUserCreateDto( - name = "test", - domain = "remote.example.com", - screenName = "testUser", - description = "test user", - inbox = "https://remote.example.com/inbox", - outbox = "https://remote.example.com/outbox", - url = "https://remote.example.com", - publicKey = "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----", - keyId = "a", - following = "", - followers = "", - sharedInbox = null, - locked = false - ) - userService.createRemoteUser(user) - verify(actorRepository, times(1)).save(any()) - argumentCaptor { - verify(actorRepository, times(1)).save(capture()) - assertEquals("test", firstValue.name) - assertEquals("testUser", firstValue.screenName) - assertEquals("test user", firstValue.description) - assertEquals(113345L, firstValue.id) - assertEquals("https://remote.example.com", firstValue.url) - assertEquals("remote.example.com", firstValue.domain) - assertEquals("https://remote.example.com/inbox", firstValue.inbox) - assertEquals("https://remote.example.com/outbox", firstValue.outbox) - assertEquals("-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----", firstValue.publicKey) - assertNull(firstValue.privateKey) - } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/domain/model/NotificationTypeTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/domain/model/NotificationTypeTest.kt deleted file mode 100644 index 1dd7e5b2..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/domain/model/NotificationTypeTest.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.mastodon.domain.model - -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.Arguments.arguments -import org.junit.jupiter.params.provider.MethodSource -import org.junit.jupiter.params.provider.ValueSource -import java.util.stream.Stream -import kotlin.test.assertEquals -import kotlin.test.assertNull - -class NotificationTypeTest { - @ParameterizedTest - @MethodSource("parseSuccessProvider") - fun parseに成功する(s: String, notificationType: NotificationType) { - assertEquals(notificationType, NotificationType.parse(s)) - } - - @ParameterizedTest - @ValueSource(strings = ["hoge", "fuga", "0x1234", "follow_reject", "test", "mentiooon", "emoji_reaction", "reaction"]) - fun parseに失敗する(s: String) { - assertNull(NotificationType.parse(s)) - } - - companion object { - @JvmStatic - fun parseSuccessProvider(): Stream { - return Stream.of( - arguments("mention", NotificationType.mention), - arguments("status", NotificationType.status), - arguments("reblog", NotificationType.reblog), - arguments("follow", NotificationType.follow), - arguments("follow_request", NotificationType.follow_request), - arguments("favourite", NotificationType.favourite), - arguments("poll", NotificationType.poll), - arguments("update", NotificationType.update), - arguments("admin.sign_up", NotificationType.admin_sign_up), - arguments("admin.report", NotificationType.admin_report), - arguments("servered_relationships", NotificationType.severed_relationships) - ) - } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/account/MastodonAccountApiControllerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/account/MastodonAccountApiControllerTest.kt deleted file mode 100644 index 9ecb49ff..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/account/MastodonAccountApiControllerTest.kt +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.mastodon.interfaces.api.account - -import dev.usbharu.hideout.application.config.ActivityPubConfig -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder -import dev.usbharu.hideout.domain.mastodon.model.generated.AccountSource -import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccount -import dev.usbharu.hideout.domain.mastodon.model.generated.Role -import dev.usbharu.hideout.mastodon.service.account.AccountApiService -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -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.doReturn -import org.mockito.kotlin.eq -import org.mockito.kotlin.whenever -import org.springframework.http.MediaType -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.oauth2.jwt.Jwt -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.get -import org.springframework.test.web.servlet.post -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import utils.TestTransaction -import java.net.URL - -@ExtendWith(MockitoExtension::class) -class MastodonAccountApiControllerTest { - - private lateinit var mockMvc: MockMvc - - @Spy - private val loginUserContextHolder = OAuth2JwtLoginUserContextHolder() - - @Spy - private lateinit var testTransaction: TestTransaction - - @Mock - private lateinit var accountApiService: AccountApiService - - @Spy - private val applicationConfig: ApplicationConfig = ApplicationConfig(URL("https://example.com")) - - @InjectMocks - private lateinit var mastodonAccountApiController: MastodonAccountApiController - - @BeforeEach - fun setUp() { - mockMvc = MockMvcBuilders.standaloneSetup(mastodonAccountApiController).build() - } - - @Test - fun `apiV1AccountsVerifyCredentialsGet JWTで認証時に200が返ってくる`() = runTest { - - val createEmptyContext = SecurityContextHolder.createEmptyContext() - createEmptyContext.authentication = JwtAuthenticationToken( - Jwt.withTokenValue("a").header("alg", "RS236").claim("uid", "1234").build() - ) - SecurityContextHolder.setContext(createEmptyContext) - val credentialAccount = CredentialAccount( - id = "", - username = "", - acct = "", - url = "", - displayName = "", - note = "", - avatar = "", - avatarStatic = "", - header = "", - headerStatic = "", - locked = false, - fields = emptyList(), - emojis = emptyList(), - bot = false, - group = false, - discoverable = true, - createdAt = "", - lastStatusAt = "", - statusesCount = 0, - followersCount = 0, - source = AccountSource( - note = "", - fields = emptyList(), - privacy = AccountSource.Privacy.public, - sensitive = false, - followRequestsCount = 0 - ), - noindex = false, - moved = false, - suspendex = false, - limited = false, - followingCount = 0, - role = Role(0, "ADMIN", "", 0, false) - ) - whenever(accountApiService.verifyCredentials(eq(1234))).doReturn(credentialAccount) - - val objectMapper = ActivityPubConfig().objectMapper() - - mockMvc - .get("/api/v1/accounts/verify_credentials") - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(credentialAccount)) } } - } - - @Test - fun `apiV1AccountsVerifyCredentialsGet POSTは405が返ってくる`() { - mockMvc.post("/api/v1/accounts/verify_credentials") - .andExpect { status { isMethodNotAllowed() } } - } - - @Test - fun `apiV1AccountsPost GETは405が返ってくる`() { - mockMvc.get("/api/v1/accounts") - .andExpect { status { isMethodNotAllowed() } } - } - - @Test - fun `apiV1AccountsPost アカウント作成成功時302とアカウントのurlが返ってくる`() { - mockMvc - .post("/api/v1/accounts") { - contentType = MediaType.APPLICATION_FORM_URLENCODED - param("username", "hoge") - param("password", "very_secure_password") - param("email", "email@example.com") - param("agreement", "true") - param("locale", "true") - }.asyncDispatch() - .andExpect { header { string("location", "/users/hoge") } } - .andExpect { status { isFound() } } - } - - @Test - fun `apiV1AccountsIdFollowPost フォロー成功時は200が返ってくる`() { - val createEmptyContext = SecurityContextHolder.createEmptyContext() - createEmptyContext.authentication = JwtAuthenticationToken( - Jwt.withTokenValue("a").header("alg", "RS236").claim("uid", "1234").build() - ) - SecurityContextHolder.setContext(createEmptyContext) - mockMvc - .post("/api/v1/accounts/1/follow") { - contentType = MediaType.APPLICATION_JSON - } - .asyncDispatch() - .andExpect { status { isOk() } } - - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/apps/MastodonAppsApiControllerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/apps/MastodonAppsApiControllerTest.kt deleted file mode 100644 index fca0dce0..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/apps/MastodonAppsApiControllerTest.kt +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.mastodon.interfaces.api.apps - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import dev.usbharu.hideout.domain.mastodon.model.generated.Application -import dev.usbharu.hideout.domain.mastodon.model.generated.AppsRequest -import dev.usbharu.hideout.generate.JsonOrFormModelMethodProcessor -import dev.usbharu.hideout.mastodon.service.app.AppApiService -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -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.doReturn -import org.mockito.kotlin.eq -import org.mockito.kotlin.whenever -import org.springframework.http.MediaType -import org.springframework.http.converter.HttpMessageConverter -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.post -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import org.springframework.web.method.annotation.ModelAttributeMethodProcessor -import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - -@ExtendWith(MockitoExtension::class) -class MastodonAppsApiControllerTest { - - @Mock - private lateinit var appApiService: AppApiService - - @InjectMocks - private lateinit var mastodonAppsApiController: MastodonAppsApiController - - private lateinit var mockMvc: MockMvc - - @BeforeEach - fun setUp() { - mockMvc = MockMvcBuilders.standaloneSetup(mastodonAppsApiController).setCustomArgumentResolvers( - JsonOrFormModelMethodProcessor( - ModelAttributeMethodProcessor(false), RequestResponseBodyMethodProcessor( - mutableListOf>( - MappingJackson2HttpMessageConverter() - ) - ) - ) - ).build() - } - - @Test - fun `apiV1AppsPost JSONで作成に成功したら200が返ってくる`() = runTest { - - val appsRequest = AppsRequest( - "test", - "https://example.com", - "write", - null - ) - val application = Application( - "test", - "", - null, - "safdash;", - "aksdhgoa" - ) - - whenever(appApiService.createApp(eq(appsRequest))).doReturn(application) - - val objectMapper = jacksonObjectMapper() - val writeValueAsString = objectMapper.writeValueAsString(appsRequest) - - mockMvc - .post("/api/v1/apps") { - contentType = MediaType.APPLICATION_JSON - content = writeValueAsString - } - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(application)) } } - } - - @Test - fun `apiV1AppsPost FORMで作成に成功したら200が返ってくる`() = runTest { - - val appsRequest = AppsRequest( - "test", - "https://example.com", - "write", - null - ) - val application = Application( - "test", - "", - null, - "safdash;", - "aksdhgoa" - ) - - whenever(appApiService.createApp(eq(appsRequest))).doReturn(application) - - val objectMapper = jacksonObjectMapper() - - mockMvc - .post("/api/v1/apps") { - contentType = MediaType.APPLICATION_FORM_URLENCODED - param("client_name", "test") - param("redirect_uris", "https://example.com") - param("scopes", "write") - } - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(application)) } } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/instance/MastodonInstanceApiControllerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/instance/MastodonInstanceApiControllerTest.kt deleted file mode 100644 index bca820da..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/instance/MastodonInstanceApiControllerTest.kt +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.mastodon.interfaces.api.instance - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import dev.usbharu.hideout.domain.mastodon.model.generated.* -import dev.usbharu.hideout.mastodon.service.instance.InstanceApiService -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -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.doReturn -import org.mockito.kotlin.whenever -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.get -import org.springframework.test.web.servlet.post -import org.springframework.test.web.servlet.setup.MockMvcBuilders - -@ExtendWith(MockitoExtension::class) -class MastodonInstanceApiControllerTest { - - @Mock - private lateinit var instanceApiService: InstanceApiService - - @InjectMocks - private lateinit var mastodonInstanceApiController: MastodonInstanceApiController - - private lateinit var mockMvc: MockMvc - - @BeforeEach - fun setUp() { - mockMvc = MockMvcBuilders.standaloneSetup(mastodonInstanceApiController).build() - } - - @Test - fun `apiV1InstanceGet GETしたら200が返ってくる`() = runTest { - - val v1Instance = V1Instance( - uri = "https://example.com", - title = "hideout", - shortDescription = "test", - description = "test instance", - email = "test@example.com", - version = "0.0.1", - urls = V1InstanceUrls(streamingApi = "https://example.com/atreaming"), - stats = V1InstanceStats(userCount = 1, statusCount = 0, domainCount = 0), - thumbnail = "https://example.com", - languages = emptyList(), - registrations = false, - approvalRequired = false, - invitesEnabled = false, - configuration = V1InstanceConfiguration( - accounts = V1InstanceConfigurationAccounts(0), - V1InstanceConfigurationStatuses(100, 4, 23), - V1InstanceConfigurationMediaAttachments(emptyList(), 100, 100, 100, 100, 100), - V1InstanceConfigurationPolls( - 10, 10, 10, 10 - ) - ), - contactAccount = Account( - id = "", - username = "", - acct = "", - url = "", - displayName = "", - note = "", - avatar = "", - avatarStatic = "", - header = "", - headerStatic = "", - locked = false, - fields = emptyList(), - emojis = emptyList(), - bot = false, - group = false, - discoverable = true, - createdAt = "", - lastStatusAt = "", - statusesCount = 0, - followersCount = 0, - noindex = false, - moved = false, - suspendex = false, - limited = false, - followingCount = 0 - ), - emptyList() - ) - whenever(instanceApiService.v1Instance()).doReturn(v1Instance) - - val objectMapper = jacksonObjectMapper() - - mockMvc - .get("/api/v1/instance") - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(objectMapper)) } } - } - - @Test - fun `apiV1InstanceGet POSTしたら405が返ってくる`() { - mockMvc - .post("/api/v1/instance") - .andExpect { status { isMethodNotAllowed() } } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/media/MastodonMediaApiControllerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/media/MastodonMediaApiControllerTest.kt deleted file mode 100644 index 24e79604..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/media/MastodonMediaApiControllerTest.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.mastodon.interfaces.api.media - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import dev.usbharu.hideout.domain.mastodon.model.generated.MediaAttachment -import dev.usbharu.hideout.mastodon.service.media.MediaApiService -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -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.doReturn -import org.mockito.kotlin.whenever -import org.springframework.mock.web.MockMultipartFile -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.multipart -import org.springframework.test.web.servlet.setup.MockMvcBuilders - -@ExtendWith(MockitoExtension::class) -class MastodonMediaApiControllerTest { - - @Mock - private lateinit var mediaApiService: MediaApiService - - @InjectMocks - private lateinit var mastodonMediaApiController: MastodonMediaApiController - - private lateinit var mockMvc: MockMvc - - @BeforeEach - fun setUp() { - mockMvc = MockMvcBuilders.standaloneSetup(mastodonMediaApiController).build() - } - - @Test - fun `apiV1MediaPost ファイルとサムネイルをアップロードできる`() = runTest { - - val mediaAttachment = MediaAttachment( - id = "1234", - type = MediaAttachment.Type.image, - url = "https://example.com", - previewUrl = "https://example.com", - remoteUrl = "https://example.com", - description = "pngImageStream", - blurhash = "", - textUrl = "https://example.com" - ) - whenever(mediaApiService.postMedia(any())).doReturn(mediaAttachment) - - val objectMapper = jacksonObjectMapper() - - mockMvc - .multipart("/api/v1/media") { - file(MockMultipartFile("file", "test.png", "image/png", "jpgImageStream".toByteArray())) - file(MockMultipartFile("thumbnail", "thumbnail.png", "image/png", "pngImageStream".toByteArray())) - param("description", "jpgImage") - param("focus", "") - } - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(mediaAttachment)) } } - } - - @Test - fun `apiV1MediaPost ファイルだけをアップロードできる`() = runTest { - - val mediaAttachment = MediaAttachment( - id = "1234", - type = MediaAttachment.Type.image, - url = "https://example.com", - previewUrl = "https://example.com", - remoteUrl = "https://example.com", - description = "pngImageStream", - blurhash = "", - textUrl = "https://example.com" - ) - whenever(mediaApiService.postMedia(any())).doReturn(mediaAttachment) - - val objectMapper = jacksonObjectMapper() - - mockMvc - .multipart("/api/v1/media") { - file(MockMultipartFile("file", "test.png", "image/png", "jpgImageStream".toByteArray())) - param("description", "jpgImage") - param("focus", "") - } - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(mediaAttachment)) } } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/status/MastodonStatusesApiControllerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/status/MastodonStatusesApiControllerTest.kt deleted file mode 100644 index ff2047ea..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/status/MastodonStatusesApiControllerTest.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.mastodon.interfaces.api.status - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder -import dev.usbharu.hideout.domain.mastodon.model.generated.Account -import dev.usbharu.hideout.domain.mastodon.model.generated.Status -import dev.usbharu.hideout.generate.JsonOrFormModelMethodProcessor -import dev.usbharu.hideout.mastodon.service.status.StatusesApiService -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -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.doReturn -import org.mockito.kotlin.eq -import org.mockito.kotlin.whenever -import org.springframework.http.MediaType -import org.springframework.http.converter.HttpMessageConverter -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.oauth2.jwt.Jwt -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.post -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import org.springframework.web.method.annotation.ModelAttributeMethodProcessor -import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - -@ExtendWith(MockitoExtension::class) -class MastodonStatusesApiControllerTest { - - @Spy - private val loginUserContextHolder = OAuth2JwtLoginUserContextHolder() - - @Mock - private lateinit var statusesApiService: StatusesApiService - - @InjectMocks - private lateinit var mastodonStatusesApiController: MastodonStatusesApiContoller - - private lateinit var mockMvc: MockMvc - - @BeforeEach - fun setUp() { - mockMvc = MockMvcBuilders.standaloneSetup(mastodonStatusesApiController).setCustomArgumentResolvers( - JsonOrFormModelMethodProcessor( - ModelAttributeMethodProcessor(false), RequestResponseBodyMethodProcessor( - mutableListOf>( - MappingJackson2HttpMessageConverter() - ) - ) - ) - ).build() - } - - @Test - fun `apiV1StatusesPost JWT認証時POSTすると投稿できる`() = runTest { - val createEmptyContext = SecurityContextHolder.createEmptyContext() - createEmptyContext.authentication = JwtAuthenticationToken( - Jwt.withTokenValue("a").header("alg", "RS236").claim("uid", "1234").build() - ) - SecurityContextHolder.setContext(createEmptyContext) - val status = Status( - id = "", - uri = "", - createdAt = "", - account = Account( - id = "", - username = "", - acct = "", - url = "", - displayName = "", - note = "", - avatar = "", - avatarStatic = "", - header = "", - headerStatic = "", - locked = false, - fields = emptyList(), - emojis = emptyList(), - bot = false, - group = false, - discoverable = true, - createdAt = "", - lastStatusAt = "", - statusesCount = 0, - followersCount = 0, - noindex = false, - moved = false, - suspendex = false, - limited = false, - followingCount = 0 - ), - content = "", - visibility = Status.Visibility.public, - sensitive = false, - spoilerText = "", - mediaAttachments = emptyList(), - mentions = emptyList(), - tags = emptyList(), - emojis = emptyList(), - reblogsCount = 0, - favouritesCount = 0, - repliesCount = 0, - url = "https://example.com", - inReplyToId = null, - inReplyToAccountId = null, - language = "ja_JP", - text = "Test", - editedAt = null - - ) - - val objectMapper = jacksonObjectMapper() - - val statusesRequest = StatusesRequest() - - statusesRequest.status = "hello" - - whenever(statusesApiService.postStatus(eq(statusesRequest), eq(1234))).doReturn(status) - - mockMvc - .post("/api/v1/statuses") { - contentType = MediaType.APPLICATION_JSON - content = objectMapper.writeValueAsString(statusesRequest) - } - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(status)) } } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/timeline/MastodonTimelineApiControllerTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/timeline/MastodonTimelineApiControllerTest.kt deleted file mode 100644 index 8302d0cf..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/timeline/MastodonTimelineApiControllerTest.kt +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.mastodon.interfaces.api.timeline - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList -import dev.usbharu.hideout.core.infrastructure.springframework.security.OAuth2JwtLoginUserContextHolder -import dev.usbharu.hideout.domain.mastodon.model.generated.Account -import dev.usbharu.hideout.domain.mastodon.model.generated.Status -import dev.usbharu.hideout.mastodon.service.timeline.TimelineApiService -import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.BeforeEach -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.* -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.security.oauth2.jwt.Jwt -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.get -import org.springframework.test.web.servlet.post -import org.springframework.test.web.servlet.setup.MockMvcBuilders -import java.net.URL - -@ExtendWith(MockitoExtension::class) -class MastodonTimelineApiControllerTest { - - @Spy - private val loginUserContextHolder = OAuth2JwtLoginUserContextHolder() - - @Mock - private lateinit var timelineApiService: TimelineApiService - - @Spy - private val applicationConfig: ApplicationConfig = ApplicationConfig(URL("https://example.com")) - - @InjectMocks - private lateinit var mastodonTimelineApiController: MastodonTimelineApiController - - private lateinit var mockMvc: MockMvc - - @BeforeEach - fun setUp() { - mockMvc = MockMvcBuilders.standaloneSetup(mastodonTimelineApiController).build() - } - - val statusList = PaginationList( - listOf( - Status( - id = "", - uri = "", - createdAt = "", - account = Account( - id = "", - username = "", - acct = "", - url = "", - displayName = "", - note = "", - avatar = "", - avatarStatic = "", - header = "", - headerStatic = "", - locked = false, - fields = emptyList(), - emojis = emptyList(), - bot = false, - group = false, - discoverable = true, - createdAt = "", - lastStatusAt = "", - statusesCount = 0, - followersCount = 0, - noindex = false, - moved = false, - suspendex = false, - limited = false, - followingCount = 0 - ), - content = "", - visibility = Status.Visibility.public, - sensitive = false, - spoilerText = "", - mediaAttachments = emptyList(), - mentions = emptyList(), - tags = emptyList(), - emojis = emptyList(), - reblogsCount = 0, - favouritesCount = 0, - repliesCount = 0, - url = "https://example.com", - inReplyToId = null, - inReplyToAccountId = null, - language = "ja_JP", - text = "Test", - editedAt = null - - ), - Status( - id = "", - uri = "", - createdAt = "", - account = Account( - id = "", - username = "", - acct = "", - url = "", - displayName = "", - note = "", - avatar = "", - avatarStatic = "", - header = "", - headerStatic = "", - locked = false, - fields = emptyList(), - emojis = emptyList(), - bot = false, - group = false, - discoverable = true, - createdAt = "", - lastStatusAt = "", - statusesCount = 0, - followersCount = 0, - noindex = false, - moved = false, - suspendex = false, - limited = false, - followingCount = 0 - ), - content = "", - visibility = Status.Visibility.public, - sensitive = false, - spoilerText = "", - mediaAttachments = emptyList(), - mentions = emptyList(), - tags = emptyList(), - emojis = emptyList(), - reblogsCount = 0, - favouritesCount = 0, - repliesCount = 0, - url = "https://example.com", - inReplyToId = null, - inReplyToAccountId = null, - language = "ja_JP", - text = "Test", - editedAt = null - - ) - ), null, null - ) - - @Test - fun `apiV1TimelineHogeGet JWT認証でログインじ200が返ってくる`() = runTest { - - val createEmptyContext = SecurityContextHolder.createEmptyContext() - createEmptyContext.authentication = JwtAuthenticationToken( - Jwt.withTokenValue("a").header("alg", "RS236").claim("uid", "1234").build() - ) - SecurityContextHolder.setContext(createEmptyContext) - - whenever( - timelineApiService.homeTimeline( - eq(1234), - any() - ) - ).doReturn(statusList) - - val objectMapper = jacksonObjectMapper() - - mockMvc - .get("/api/v1/timelines/home?max_id=123456&since_id=1234567&min_id=54321&limit=20") - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(statusList)) } } - } - - @Test - fun `apiV1TimelineHomeGet パラメーターがなくても取得できる`() = runTest { - val createEmptyContext = SecurityContextHolder.createEmptyContext() - createEmptyContext.authentication = JwtAuthenticationToken( - Jwt.withTokenValue("a").header("alg", "RS236").claim("uid", "1234").build() - ) - SecurityContextHolder.setContext(createEmptyContext) - - whenever( - timelineApiService.homeTimeline( - eq(1234), - any() - ) - ).doReturn(statusList) - - val objectMapper = jacksonObjectMapper() - - mockMvc - .get("/api/v1/timelines/home") - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(statusList)) } } - } - - @Test - fun `apiV1TimelineHomeGet POSTには405を返す`() { - mockMvc - .post("/api/v1/timelines/home?max_id=123456&since_id=1234567&min_id=54321&limit=20") - .andExpect { status { isMethodNotAllowed() } } - } - - @Test - fun `apiV1TimelinePublicGet GETで200が返ってくる`() = runTest { - whenever( - timelineApiService.publicTimeline( - localOnly = eq(false), - remoteOnly = eq(true), - mediaOnly = eq(false), - any() - ) - ).doAnswer { - println(it.arguments.joinToString()) - statusList - } - - val objectMapper = jacksonObjectMapper() - - mockMvc - .get("/api/v1/timelines/public?local=false&remote=true&only_media=false&max_id=1234&since_id=12345&min_id=4321&limit=20") - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(statusList)) } } - } - - @Test - fun `apiV1TimelinePublicGet POSTで405が返ってくる`() { - mockMvc.post("/api/v1/timelines/public") - .andExpect { status { isMethodNotAllowed() } } - } - - @Test - fun `apiV1TimelinePublicGet パラメーターがなくても取得できる`() = runTest { - whenever( - timelineApiService.publicTimeline( - localOnly = eq(false), - remoteOnly = eq(false), - mediaOnly = eq(false), - any() - ) - ).doAnswer { - println(it.arguments.joinToString()) - statusList - } - - val objectMapper = jacksonObjectMapper() - - mockMvc - .get("/api/v1/timelines/public") - .asyncDispatch() - .andExpect { status { isOk() } } - .andExpect { content { json(objectMapper.writeValueAsString(statusList)) } } - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/service/account/AccountApiServiceImplTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/service/account/AccountApiServiceImplTest.kt deleted file mode 100644 index 0640f8ba..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/mastodon/service/account/AccountApiServiceImplTest.kt +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.mastodon.service.account - -import dev.usbharu.hideout.application.infrastructure.exposed.Page -import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList -import dev.usbharu.hideout.core.application.shared.Transaction -import dev.usbharu.hideout.core.service.media.MediaService -import dev.usbharu.hideout.domain.mastodon.model.generated.Account -import dev.usbharu.hideout.domain.mastodon.model.generated.Relationship -import dev.usbharu.hideout.domain.mastodon.model.generated.Status -import dev.usbharu.hideout.mastodon.query.StatusQueryService -import kotlinx.coroutines.test.runTest -import org.assertj.core.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 org.mockito.kotlin.* -import utils.TestTransaction - -@ExtendWith(MockitoExtension::class) -class AccountApiServiceImplTest { - - @Mock - private lateinit var accountService: AccountService - - @Mock - private lateinit var userService: UserService - - @Mock - private lateinit var actorRepository: ActorRepository - - @Mock - private lateinit var followerQueryService: FollowerQueryService - - @Mock - private lateinit var statusQueryService: StatusQueryService - - @Spy - private val transaction: Transaction = TestTransaction - - @Mock - private lateinit var relationshipService: RelationshipService - - @Mock - private lateinit var relationshipRepository: RelationshipRepository - - @Mock - private lateinit var mediaService: MediaService - - @InjectMocks - private lateinit var accountApiServiceImpl: AccountApiServiceImpl - - private val statusList = PaginationList( - listOf( - Status( - id = "", - uri = "", - createdAt = "", - account = Account( - id = "", - username = "", - acct = "", - url = "", - displayName = "", - note = "", - avatar = "", - avatarStatic = "", - header = "", - headerStatic = "", - locked = false, - fields = emptyList(), - emojis = emptyList(), - bot = false, - group = false, - discoverable = true, - createdAt = "", - lastStatusAt = "", - statusesCount = 0, - followersCount = 0, - noindex = false, - moved = false, - suspendex = false, - limited = false, - followingCount = 0 - ), - content = "", - visibility = Status.Visibility.public, - sensitive = false, - spoilerText = "", - mediaAttachments = emptyList(), - mentions = emptyList(), - tags = emptyList(), - emojis = emptyList(), - reblogsCount = 0, - favouritesCount = 0, - repliesCount = 0, - url = "https://example.com", - inReplyToId = null, - inReplyToAccountId = null, - language = "ja_JP", - text = "Test", - editedAt = null - ) - ), null, null - ) - - @Test - fun `accountsStatuses 非ログイン時は非公開投稿を見れない`() = runTest { - val userId = 1234L - - whenever( - statusQueryService.accountsStatus( - accountId = eq(userId), - onlyMedia = eq(false), - excludeReplies = eq(false), - excludeReblogs = eq(false), - pinned = eq(false), - tagged = isNull(), - includeFollowers = eq(false), - page = any() - ) - ).doReturn( - statusList - ) - - - val accountsStatuses = accountApiServiceImpl.accountsStatuses( - userid = userId, - onlyMedia = false, - excludeReplies = false, - excludeReblogs = false, - pinned = false, - tagged = null, - loginUser = null, - Page.of() - ) - - assertThat(accountsStatuses).hasSize(1) - - verify(followerQueryService, never()).alreadyFollow(any(), any()) - } - - @Test - fun `accountsStatuses ログイン時フォロワーじゃない場合は非公開投稿を見れない`() = runTest { - val userId = 1234L - val loginUser = 1L - whenever( - statusQueryService.accountsStatus( - accountId = eq(userId), - onlyMedia = eq(false), - excludeReplies = eq(false), - excludeReblogs = eq(false), - pinned = eq(false), - tagged = isNull(), - includeFollowers = eq(false), - page = any() - ) - ).doReturn(statusList) - - val accountsStatuses = accountApiServiceImpl.accountsStatuses( - userid = userId, - onlyMedia = false, - excludeReplies = false, - excludeReblogs = false, - pinned = false, - tagged = null, - loginUser = loginUser, - Page.of() - ) - - assertThat(accountsStatuses).hasSize(1) - } - - @Test - fun `accountsStatuses ログイン時フォロワーの場合は非公開投稿を見れる`() = runTest { - val userId = 1234L - val loginUser = 2L - whenever( - statusQueryService.accountsStatus( - accountId = eq(userId), - onlyMedia = eq(false), - excludeReplies = eq(false), - excludeReblogs = eq(false), - pinned = eq(false), - tagged = isNull(), - includeFollowers = eq(true), - page = any() - ) - ).doReturn(statusList) - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(loginUser), eq(userId))).doReturn( - dev.usbharu.hideout.core.domain.model.relationship.Relationship( - actorId = loginUser, - targetActorId = userId, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - - val accountsStatuses = accountApiServiceImpl.accountsStatuses( - userid = userId, - onlyMedia = false, - excludeReplies = false, - excludeReblogs = false, - pinned = false, - tagged = null, - loginUser = loginUser, - Page.of() - ) - - assertThat(accountsStatuses).hasSize(1) - } - - @Test - fun `follow 未フォローの場合フォローリクエストが発生する`() = runTest { - val userId = 1234L - val followeeId = 1L - - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(followeeId), eq(userId))).doReturn( - dev.usbharu.hideout.core.domain.model.relationship.Relationship( - actorId = followeeId, - targetActorId = userId, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(userId), eq(followeeId))).doReturn( - dev.usbharu.hideout.core.domain.model.relationship.Relationship( - actorId = userId, - targetActorId = followeeId, - following = true, - blocking = false, - muting = false, - followRequest = false, - ignoreFollowRequestToTarget = false - ) - ) - - - val follow = accountApiServiceImpl.follow(userId, followeeId) - - val expected = Relationship( - id = followeeId.toString(), - following = true, - showingReblogs = true, - notifying = false, - followedBy = true, - blocking = false, - blockedBy = false, - muting = false, - mutingNotifications = false, - requested = false, - domainBlocking = false, - endorsed = false, - note = "" - ) - assertThat(follow).isEqualTo(expected) - - verify(relationshipService, times(1)).followRequest(eq(userId), eq(followeeId)) - } - - @Test - fun `relationships idが長すぎたら省略する`() = runTest { - - val relationships = accountApiServiceImpl.relationships( - userid = 1234L, - id = (1..30L).toList(), - withSuspended = false - ) - - assertThat(relationships).hasSize(20) - } - - @Test - fun `relationships id0の場合即時return`() = runTest { - val relationships = accountApiServiceImpl.relationships( - userid = 1234L, - id = emptyList(), - withSuspended = false - ) - - assertThat(relationships).hasSize(0) - verify(followerQueryService, never()).alreadyFollow(any(), any()) - } - - @Test - fun `relationships idに指定されたアカウントの関係を取得する`() = runTest { - - val relationships = accountApiServiceImpl.relationships( - userid = 1234L, - id = (1..15L).toList(), - withSuspended = false - ) - - assertThat(relationships).hasSize(15) - } -} diff --git a/hideout-core/src/test/kotlin/dev/usbharu/hideout/util/EmojiUtilTest.kt b/hideout-core/src/test/kotlin/dev/usbharu/hideout/util/EmojiUtilTest.kt deleted file mode 100644 index 937f7e8b..00000000 --- a/hideout-core/src/test/kotlin/dev/usbharu/hideout/util/EmojiUtilTest.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.usbharu.hideout.util - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource - -class EmojiUtilTest { - - @Test - fun 絵文字を判定できる() { - val emoji = "❤" - val actual = EmojiUtil.isEmoji(emoji) - - assertThat(actual).isTrue() - } - - @Test - fun ただの文字を判定できる() { - val moji = "blobblinkhyper" - val actual = EmojiUtil.isEmoji(moji) - - assertThat(actual).isFalse() - } - - @ParameterizedTest - @ValueSource(strings = ["❤", "🌄", "🤗", "⛺", "🧑‍🤝‍🧑", "🖐🏿"]) - fun `絵文字判定`(s: String) { - val actual = EmojiUtil.isEmoji(s) - - assertThat(actual).isTrue() - } - - @ParameterizedTest - @ValueSource(strings = ["™", "㍂", "㌠"]) - fun `文字判定`(s: String) { - val actual = EmojiUtil.isEmoji(s) - - assertThat(actual).isFalse() - } -} diff --git a/hideout-core/src/test/kotlin/utils/JsonObjectMapper.kt b/hideout-core/src/test/kotlin/utils/JsonObjectMapper.kt deleted file mode 100644 index 41cb81c3..00000000 --- a/hideout-core/src/test/kotlin/utils/JsonObjectMapper.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package utils - -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.annotation.JsonSetter -import com.fasterxml.jackson.annotation.Nulls -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper - -object JsonObjectMapper { - val objectMapper: com.fasterxml.jackson.databind.ObjectMapper = - jacksonObjectMapper().enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY) - .setSerializationInclusion(JsonInclude.Include.NON_EMPTY) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - - init { - objectMapper.configOverride(List::class.java).setSetterInfo( - JsonSetter.Value.forValueNulls( - Nulls.AS_EMPTY - ) - ) - } -} diff --git a/hideout-core/src/test/kotlin/utils/PostBuilder.kt b/hideout-core/src/test/kotlin/utils/PostBuilder.kt deleted file mode 100644 index 41b9f746..00000000 --- a/hideout-core/src/test/kotlin/utils/PostBuilder.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package utils - -import dev.usbharu.hideout.application.config.CharacterLimit -import dev.usbharu.hideout.application.config.HtmlSanitizeConfig -import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService -import dev.usbharu.hideout.core.domain.model.post.Visibility -import dev.usbharu.hideout.core.service.post.DefaultPostContentFormatter -import jakarta.validation.Validation -import kotlinx.coroutines.runBlocking -import java.time.Instant - -object PostBuilder { - - private val postBuilder = - Post.PostBuilder( - CharacterLimit(), - DefaultPostContentFormatter(HtmlSanitizeConfig().policy()), - Validation.buildDefaultValidatorFactory().validator - ) - - private val idGenerator = TwitterSnowflakeIdGenerateService - - fun of( - id: Long = generateId(), - userId: Long = generateId(), - overview: String? = null, - text: String = "Hello World", - createdAt: Long = Instant.now().toEpochMilli(), - visibility: Visibility = Visibility.PUBLIC, - url: String = "https://example.com/users/$userId/posts/$id", - ): Post { - return postBuilder.of( - id = id, - actorId = userId, - overview = overview, - content = text, - createdAt = createdAt, - visibility = visibility, - url = url, - ) - } - - private fun generateId(): Long = runBlocking { - idGenerator.generateId() - } -} diff --git a/hideout-core/src/test/kotlin/utils/TestApplicationConfig.kt b/hideout-core/src/test/kotlin/utils/TestApplicationConfig.kt deleted file mode 100644 index 699e8777..00000000 --- a/hideout-core/src/test/kotlin/utils/TestApplicationConfig.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package utils - -import dev.usbharu.hideout.application.config.ApplicationConfig -import java.net.URL - -object TestApplicationConfig { - val testApplicationConfig = ApplicationConfig(URL("https://example.com")) -} diff --git a/hideout-core/src/test/kotlin/utils/UserBuilder.kt b/hideout-core/src/test/kotlin/utils/UserBuilder.kt deleted file mode 100644 index fd929c81..00000000 --- a/hideout-core/src/test/kotlin/utils/UserBuilder.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2024 usbharu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package utils - -import dev.usbharu.hideout.application.config.ApplicationConfig -import dev.usbharu.hideout.application.config.CharacterLimit -import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService -import jakarta.validation.Validation -import kotlinx.coroutines.runBlocking -import java.net.URL -import java.time.Instant - -object UserBuilder { - private val actorBuilder = Actor.UserBuilder( - CharacterLimit(), ApplicationConfig(URL("https://example.com")), - Validation.buildDefaultValidatorFactory().validator - ) - - private val idGenerator = TwitterSnowflakeIdGenerateService - - fun localUserOf( - id: Long = generateId(), - name: String = "test-user-$id", - domain: String = "example.com", - screenName: String = name, - description: String = "This user is test user.", - inbox: String = "https://$domain/users/$id/inbox", - outbox: String = "https://$domain/users/$id/outbox", - url: String = "https://$domain/users/$id", - publicKey: String = "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----", - privateKey: String = "-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----", - createdAt: Instant = Instant.now(), - keyId: String = "https://$domain/users/$id#pubkey", - followers: String = "https://$domain/users/$id/followers", - following: String = "https://$domain/users/$id/following", - ): Actor { - return actorBuilder.of( - id = id, - name = name, - domain = domain, - screenName = screenName, - description = description, - inbox = inbox, - outbox = outbox, - url = url, - publicKey = publicKey, - privateKey = privateKey, - createdAt = createdAt, - keyId = keyId, - followers = followers, - following = following, - locked = false, - instance = 0 - ) - } - - fun remoteUserOf( - id: Long = generateId(), - name: String = "test-user-$id", - domain: String = "remote.example.com", - screenName: String = name, - description: String = "This user is test user.", - inbox: String = "https://$domain/$id/inbox", - outbox: String = "https://$domain/$id/outbox", - url: String = "https://$domain/$id/", - publicKey: String = "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----", - createdAt: Instant = Instant.now(), - keyId: String = "https://$domain/$id#pubkey", - followers: String = "https://$domain/$id/followers", - following: String = "https://$domain/$id/following", - instanceId: Long = generateId(), - ): Actor { - return actorBuilder.of( - id = id, - name = name, - domain = domain, - screenName = screenName, - description = description, - inbox = inbox, - outbox = outbox, - url = url, - publicKey = publicKey, - privateKey = null, - createdAt = createdAt, - keyId = keyId, - followers = followers, - following = following, - locked = false, - instance = instanceId - ) - } - - private fun generateId(): Long = runBlocking { - idGenerator.generateId() - } -}