test: inboxにアクセスしてきたユーザーを取得するe2eテストを追加

This commit is contained in:
usbharu 2023-12-03 10:18:27 +09:00
parent e52064c330
commit faff15f559
7 changed files with 282 additions and 4 deletions

View File

@ -0,0 +1,18 @@
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Users
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.selectAll
object AssertionUtil {
fun assertUserExist(username: String, domain: String): Boolean {
val selectAll = Users.selectAll()
println(selectAll.fetchSize)
println(selectAll.toList().size)
selectAll.map { "@${it[Users.name]}@${it[Users.domain]}" }.forEach { println(it) }
return Users.select { Users.name eq username and (Users.domain eq domain) }.empty().not()
}
}

View File

@ -9,4 +9,20 @@ object KarateUtil {
.karateEnv("dev") .karateEnv("dev")
} }
} }
fun e2eTest(path: String, scenario: String = "", properties: Map<String, String>, clazz: Class<*>): Karate {
val run = Karate.run(path)
val karate = if (scenario.isEmpty()) {
run
} else {
run.scenarioName(scenario)
}
var relativeTo = karate.relativeTo(clazz)
properties.map { relativeTo = relativeTo.systemProperty(it.key, it.value) }
return relativeTo.karateEnv("dev")
}
} }

View File

@ -0,0 +1,91 @@
package federation
import AssertionUtil
import KarateUtil
import com.intuit.karate.core.MockServer
import com.intuit.karate.junit5.Karate
import dev.usbharu.hideout.SpringApplication
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.flywaydb.core.Flyway
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.TestFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.server.LocalServerPort
import org.springframework.transaction.annotation.Transactional
import java.net.MalformedURLException
import java.net.URL
@SpringBootTest(
classes = [SpringApplication::class],
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
@Transactional
class InboxCommonTest {
@LocalServerPort
private var port = ""
@Karate.Test
@TestFactory
fun `inboxにHTTP Signature付きのリクエストがあったらリモートに取得しに行く`(): Karate {
return KarateUtil.e2eTest(
"InboxCommonTest",
"inboxにHTTP Signature付きのリクエストがあったらリモートに取得しに行く",
mapOf(
"karate.port" to port,
"karate.remotePort" to _remotePort
),
javaClass
)
}
companion object {
lateinit var server: MockServer
lateinit var _remotePort: String
@JvmStatic
fun assertUserExist(username: String, domain: String) = runBlocking {
val s = try {
val url = URL(domain)
url.host + ":" + url.port.toString().takeIf { it != "-1" }.orEmpty()
} catch (e: MalformedURLException) {
domain
}
var check = false
repeat(10) {
delay(1000)
check = AssertionUtil.assertUserExist(username, s) or check
if (check) {
return@repeat
}
}
assertTrue(check, "User @$username@$s not exist.")
}
@JvmStatic
fun getRemotePort(): String = _remotePort
@BeforeAll
@JvmStatic
fun beforeAll(@Autowired flyway: Flyway) {
server = MockServer.feature("classpath:federation/InboxxCommonMockServerTest.feature").http(0).build()
_remotePort = server.port.toString()
flyway.clean()
flyway.migrate()
}
@AfterAll
@JvmStatic
fun afterAll() {
server.stop()
}
}
}

View File

@ -1,6 +1,6 @@
hideout: hideout:
url: "https://localhost:8080" url: "https://localhost:8080"
use-mongodb: true use-mongodb: false
security: security:
jwt: jwt:
generate: true generate: true
@ -22,7 +22,7 @@ spring:
clean-disabled: false clean-disabled: false
datasource: datasource:
driver-class-name: org.h2.Driver driver-class-name: org.h2.Driver
url: "jdbc:h2:mem:test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true" url: "jdbc:h2:./e2e-test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4"
username: "" username: ""
password: password:
data: data:

View File

@ -0,0 +1,22 @@
Feature: Inbox Common Test
Background:
* url baseUrl
Scenario: inboxにHTTP Signature付きのリクエストがあったらリモートに取得しに行く
* def inbox =
"""
{ "type": "Follow" }
"""
Given path `/inbox`
And request inbox
# And header Signature = 'keyId="'+ remoteUrl +'/users/test-user#pubkey", algorithm="rsa-sha256", headers="(request-target)", signature="a"'
And header Signature = 'keyId="'+ remoteUrl +'/users/test-user#pubkey", algorithm="rsa-sha256", headers="(request-target) date host digest", signature="FfpkmBogW70FMo94yovGpl15L/m4bDjVIFb9mSZUstPE3H00nHiqNsjAq671qFMJsGOO1uWfLEExcdvzwTiC3wuHShzingvxQUbTgcgRTRZcHbtrOZxT8hYHGndpCXGv/NOLkfXDtZO9v5u0fnA2yJFokzyPHOPJ1cJliWlXP38Bl/pO4H5rBLQBZKpM2jYIjMyI78G2rDXNHEeGrGiyfB5SKb3H6zFQL+X9QpXUI4n0f07VsnwaDyp63oUopmzNUyBEuSqB+8va/lbfcWwrxpZnKGzQRZ+VBcV7jDoKGNOP9/O1xEI2CwB8sh+h6KVHdX3EQEvO1slaaLzcwRRqrQ=="'
When method post
Then status 202
* def assertInbox = Java.type(`federation.InboxCommonTest`)
And assertInbox.assertUserExist('test-user',remoteUrl)

View File

@ -0,0 +1,126 @@
Feature: InboxCommonMockServer
Background:
* def assertInbox = Java.type(`federation.InboxCommonTest`)
Scenario: pathMatches('/users/test-user') && methodIs('get')
* def remoteUrl = 'http://localhost:' + assertInbox.getRemotePort()
* def userUrl = remoteUrl + '/users/test-user'
* def person =
"""
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"toot": "http://joinmastodon.org/ns#",
"featured": {
"@id": "toot:featured",
"@type": "@id"
},
"featuredTags": {
"@id": "toot:featuredTags",
"@type": "@id"
},
"alsoKnownAs": {
"@id": "as:alsoKnownAs",
"@type": "@id"
},
"movedTo": {
"@id": "as:movedTo",
"@type": "@id"
},
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value",
"discoverable": "toot:discoverable",
"Device": "toot:Device",
"Ed25519Signature": "toot:Ed25519Signature",
"Ed25519Key": "toot:Ed25519Key",
"Curve25519Key": "toot:Curve25519Key",
"EncryptedMessage": "toot:EncryptedMessage",
"publicKeyBase64": "toot:publicKeyBase64",
"deviceId": "toot:deviceId",
"claim": {
"@type": "@id",
"@id": "toot:claim"
},
"fingerprintKey": {
"@type": "@id",
"@id": "toot:fingerprintKey"
},
"identityKey": {
"@type": "@id",
"@id": "toot:identityKey"
},
"devices": {
"@type": "@id",
"@id": "toot:devices"
},
"messageFranking": "toot:messageFranking",
"messageType": "toot:messageType",
"cipherText": "toot:cipherText",
"suspended": "toot:suspended",
"focalPoint": {
"@container": "@list",
"@id": "toot:focalPoint"
}
}
],
"id": #(userUrl),
"type": "Person",
"following": #(userUrl + '/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": "test-user",
"name": "test-user",
"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"
}
}
"""
* def response = person

View File

@ -7,18 +7,23 @@ function fn() {
} }
let config; let config;
if (env === 'test') { if (env === 'test') {
let remotePort = karate.properties['karate.remotePort'] || '8081'
config = { config = {
baseUrl: 'https://test-hideout.usbharu.dev' baseUrl: 'https://test-hideout.usbharu.dev',
remoteUrl: 'http://localhost:' + remotePort
} }
} else if (env === 'dev') { } else if (env === 'dev') {
let port = karate.properties['karate.port'] || '8080' let port = karate.properties['karate.port'] || '8080'
let remotePort = karate.properties['karate.remotePort'] || '8081'
config = { config = {
baseUrl: 'http://localhost:' + port baseUrl: 'http://localhost:' + port,
remoteUrl: 'http://localhost:' + remotePort
} }
} else { } else {
throw 'Unknown environment [' + env + '].' throw 'Unknown environment [' + env + '].'
} }
// don't waste time waiting for a connection or if servers don't respond within 0,3 seconds // don't waste time waiting for a connection or if servers don't respond within 0,3 seconds
karate.configure('connectTimeout', 1000); karate.configure('connectTimeout', 1000);
karate.configure('readTimeout', 1000); karate.configure('readTimeout', 1000);
return config; return config;