[CONSOLE] Integration Test (#1741)

* [CONSOLE] Realtime Test Unit

* Rename to IntegrationTest; IDEA Debugging support

* External Plugins support

* Simply redesign
This commit is contained in:
微莹·纤绫 2021-12-18 22:59:43 +08:00 committed by GitHub
parent 6f55816b08
commit 8d6b4b4970
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 786 additions and 0 deletions

View File

@ -0,0 +1,35 @@
# Console - Integration Test
Mirai Console 一体化测试单元 (目前仅内部测试)
---
## 使用 Integration Test Framework
TODO
### 添加一个新测试
#### 创建 Integration Test 测试点
创建一个新的子测试单元并继承 `AbstractTestPoint`
- 在其 `beforeConsoleStartup()` 准备测试环境 (如写入配置文件, etc)
- 在其 `onConsoleStartSuccessfully()` 检查插件相关行为是否正确
然后在 `MiraiConsoleIntegrationTestLauncher.points` 添加新单元的完整类路径
----
## Mirai Console Internal Testing
### 添加一个新测试 (CONSOLE 内部测试)
`test/testpoints` 添加新测试点,
然后在 [`MiraiConsoleIntegrationTestBootstrap.kt`](test/MiraiConsoleIntegrationTestBootstrap.kt)
添加相关单元
### 创建配套子插件
`testers` 创建新的文件夹即可创建新的配套插件, 可用于测试插件依赖, etc

View File

@ -0,0 +1,94 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("UnusedImport")
import java.util.Base64
plugins {
kotlin("jvm")
kotlin("plugin.serialization")
id("java")
}
version = Versions.console
description = "Mirai Console Backend Real-Time Testing Unit"
kotlin {
explicitApiWarning()
}
dependencies {
api(project(":mirai-core-api"))
api(project(":mirai-core-utils"))
api(project(":mirai-console-compiler-annotations"))
api(project(":mirai-console"))
api(project(":mirai-console-terminal"))
api(`kotlin-stdlib-jdk8`)
api(`kotlinx-atomicfu-jvm`)
api(`kotlinx-coroutines-core-jvm`)
api(`kotlinx-serialization-core-jvm`)
api(`kotlinx-serialization-json-jvm`)
api(`kotlin-reflect`)
api(`kotlin-test-junit5`)
api(`yamlkt-jvm`)
api(`jetbrains-annotations`)
api(`caller-finder`)
api(`kotlinx-coroutines-jdk8`)
val asmVersion = Versions.asm
fun asm(module: String) = "org.ow2.asm:asm-$module:$asmVersion"
api(asm("tree"))
api(asm("util"))
api(asm("commons"))
}
val subplugins = mutableListOf<TaskProvider<Jar>>()
val mcit_test = tasks.named<Test>("test")
mcit_test.configure {
val test0 = this
doFirst {
// For IDEA Debugging
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
val extArgs = test0.jvmArgs!!.asSequence().map { extArg ->
Base64.getEncoder().encodeToString(extArg.toByteArray())
}.joinToString(",")
test0.jvmArgs = mutableListOf()
test0.environment("IT_ARGS", extArgs)
// For plugins coping
val jars = subplugins.asSequence()
.map { it.get() }
.flatMap { it.outputs.files.files.asSequence() }
.toList()
test0.environment("IT_PLUGINS", jars.size)
jars.forEachIndexed { index, jar ->
test0.environment("IT_PLUGINS_$index", jar.absolutePath)
}
}
}
rootProject.allprojects {
if (project.path.removePrefix(":").startsWith("mirai-console.integration-test.tp.")) {
project.afterEvaluate {
val tk = tasks.named<Jar>("jar")
subplugins.add(tk)
mcit_test.configure { dependsOn(tk) }
}
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.console.integrationtest
/**
* IntegrationTest 测试单元
*
* 每个被注册的单元都会在 console 启动的各个阶段调用相关的函数, 可以在相关函数执行测试代码
*
* ## 注册单元
*
* 每个单元都需要被注册, 即被添加进 [MiraiConsoleIntegrationTestLauncher.points]
*
* @see MiraiConsoleIntegrationTestLauncher
* @see AbstractTestPointAsPlugin
*/
public abstract class AbstractTestPoint {
/**
* 本函数会在 console 启动前调用, 可以在此处进行环境配置
*/
protected open fun beforeConsoleStartup() {}
/**
* 本函数会在 console 启动成功后立即调用, 可进行环境检查, 命令执行测试, 或更多
*/
protected open fun onConsoleStartSuccessfully() {}
// access
internal companion object {
internal fun AbstractTestPoint.internalOSS() {
onConsoleStartSuccessfully()
}
internal fun AbstractTestPoint.internalBCS() {
beforeConsoleStartup()
}
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.console.integrationtest
import net.mamoe.mirai.console.extension.PluginComponentStorage
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
/**
* IntegrationTest 测试单元 (Plugin mode)
*
* 该单元除了拥有 [AbstractTestPoint] 具有的功能之外, 还可以直接模拟一个插件的行为.
*
* 在此单元里, 可以像写正常的 console 插件一样在此写测试时插件
*/
public abstract class AbstractTestPointAsPlugin : AbstractTestPoint() {
protected abstract fun newPluginDescription(): JvmPluginDescription
protected open fun KotlinPlugin.onInit() {}
protected open fun KotlinPlugin.onLoad0(storage: PluginComponentStorage) {}
protected open fun KotlinPlugin.onEnable0() {}
protected open fun KotlinPlugin.onDisable0() {}
@Suppress("unused")
@PublishedApi
internal abstract class TestPointPluginImpl(
private val impl: AbstractTestPointAsPlugin
) : KotlinPlugin(impl.newPluginDescription()) {
init {
impl.apply { onInit() }
}
@PublishedApi
internal constructor(
impl: Class<out AbstractTestPointAsPlugin>
) : this(impl.kotlin.objectInstance ?: impl.newInstance())
override fun onDisable() {
impl.apply { onDisable0() }
}
override fun onEnable() {
impl.apply { onEnable0() }
}
override fun PluginComponentStorage.onLoad() {
impl.apply { onLoad0(this@onLoad) }
}
}
}

View File

@ -0,0 +1,148 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:JvmName("IntegrationTestBootstrap")
package net.mamoe.console.integrationtest
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.runBlocking
import net.mamoe.console.integrationtest.AbstractTestPoint.Companion.internalBCS
import net.mamoe.console.integrationtest.AbstractTestPoint.Companion.internalOSS
import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.terminal.ConsoleTerminalExperimentalApi
import net.mamoe.mirai.console.terminal.ConsoleTerminalSettings
import net.mamoe.mirai.console.terminal.MiraiConsoleTerminalLoader
import net.mamoe.mirai.utils.cast
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import java.io.File
import java.io.FileOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import kotlin.system.exitProcess
/**
* 入口点为 /test/MiraiConsoleIntegrationTestBootstrap.kt 并非此函数(文件),
* 不要直接执行此函数
*/
@OptIn(ConsoleTerminalExperimentalApi::class)
@PublishedApi
internal fun main() {
// PRE CHECK
kotlin.run {
if (!System.getenv("MIRAI_CONSOLE_INTEGRATION_TEST").orEmpty().toBoolean()) {
error("Don't launch IntegrationTestBootstrap directly. See /test/MiraiConsoleIntegrationTestBootstrap.kt")
}
}
// @context: env.testunit = true
// @context: env.inJUnitProcess = false
// @context: env.exitProcessSafety = true
// @context: process.type = sandbox
// @context: process.cwd = /mirai-console/backend/build/rttu
// @context: process.timeout = 5min
ConsoleTerminalSettings.setupAnsi = false
ConsoleTerminalSettings.noConsole = true
val testUnits: List<AbstractTestPoint> = readStringListFromEnv("IT_POINTS").asSequence()
.onEach { println("[MCIT] Loading test point: $it") }
.map { Class.forName(it) }
.map { it.kotlin.objectInstance ?: it.newInstance() }
.map { it.cast<AbstractTestPoint>() }
.toList()
File("plugins").mkdirs()
prepareConsole()
testUnits.forEach { (it as? AbstractTestPointAsPlugin)?.generatePluginJar() }
testUnits.forEach { it.internalBCS() }
MiraiConsoleTerminalLoader.startAsDaemon()
if (!MiraiConsole.isActive) {
error("Failed to start console")
}
// I/main: mirai-console started successfully.
testUnits.forEach { it.internalOSS() }
runBlocking {
MiraiConsole.job.cancelAndJoin()
}
exitProcess(0)
}
private fun File.mkparents(): File = apply { parentFile?.mkdirs() }
private fun prepareConsole() {
File("config/Console/Logger.yml").mkparents().writeText(
"""
defaultPriority: ALL
loggers:
Bot: ALL
"""
)
readStringListFromEnv("IT_PLUGINS").forEach { path ->
val jarFile = File(path)
val target = File("plugins/${jarFile.name}").mkparents()
jarFile.copyTo(target, overwrite = true)
println("[MCIT] Copied external plugin: $jarFile")
}
}
private fun AbstractTestPointAsPlugin.generatePluginJar() {
val simpleName = this.javaClass.simpleName
val point = this
val jarFile = File("plugins").resolve("$simpleName.jar")
// PluginMainPoint: net.mamoe.console.integrationtestAbstractTestPointAsPlugin$TestPointPluginImpl
jarFile.mkparents()
ZipOutputStream(
FileOutputStream(jarFile).buffered()
).use { zipOutputStream ->
// META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin
zipOutputStream.putNextEntry(
ZipEntry(
"META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin"
)
)
val delegateClassName = "net.mamoe.console.integrationtest.tpd.$simpleName"
zipOutputStream.write(delegateClassName.toByteArray())
// MainClass
val internalClassName = delegateClassName.replace('.', '/')
zipOutputStream.putNextEntry(ZipEntry("$internalClassName.class"))
val classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS)
val superName = "net/mamoe/console/integrationtest/AbstractTestPointAsPlugin\$TestPointPluginImpl"
classWriter.visit(
Opcodes.V1_8,
Opcodes.ACC_PUBLIC,
internalClassName,
null,
superName,
null
)
classWriter.visitMethod(
Opcodes.ACC_PUBLIC,
"<init>", "()V", null, null
)!!.let { initMethod ->
initMethod.visitVarInsn(Opcodes.ALOAD, 0)
initMethod.visitLdcInsn(Type.getType(point.javaClass))
initMethod.visitMethodInsn(Opcodes.INVOKESPECIAL, superName, "<init>", "(Ljava/lang/Class;)V", false)
initMethod.visitInsn(Opcodes.RETURN)
initMethod.visitMaxs(0, 0)
initMethod.visitEnd()
}
zipOutputStream.write(classWriter.toByteArray())
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.console.integrationtest
import net.mamoe.mirai.utils.lateinitMutableProperty
import java.io.File
import java.io.OutputStream
import java.io.PrintStream
import java.lang.management.ManagementFactory
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.concurrent.thread
// TODO: 不完整, 还无法完全公开, 目前仅允许 console 内部使用
/**
* MiraiConsoleIntegrationTest 启动器
*/
public class MiraiConsoleIntegrationTestLauncher {
/** java.exe 路径 */
public var javaexec: String by lateinitMutableProperty { findJavaExec() }
/**
* 测试环境运行目录, **每次启动前会直接删除该文件夹的内容**(IMPORTANT)
*/
public var workingDir: File = File("mirai-console-integration-test")
/** 额外 JVM 参数 */
public var vmoptions: MutableList<String> = mutableListOf()
/** 额外环境变量 */
public var extraEnvironment: MutableMap<String, String> = mutableMapOf()
/** 类路径, 需要包含 MiraiConsoleIntegrationTest Framework */
public var classpath: String by lateinitMutableProperty { ManagementFactory.getRuntimeMXBean().classPath }
/** 标准输出重定向位置 */
public var output: OutputStream = System.out
/** 标准错误重定向位置 */
public var error: OutputStream = System.err
/** [MiraiConsoleIntegrationTestLauncher] 启动日志的输出 */
public var log: PrintStream = System.out
/** 测试单元完整类名, 需要可以在 [classpath] 中找到 */
public var points: MutableCollection<String> = mutableListOf()
/** 测试环境的额外插件, 为文件路径, 相对于 [workingDir] */
public var plugins: MutableCollection<String> = mutableListOf()
public fun launch() {
workingDir.deleteRecursively()
workingDir.mkdirs()
val isDebugging = vmoptions.any { it.startsWith("-agentlib:") }
val builder = ProcessBuilder(
javaexec,
*vmoptions.toTypedArray(),
"-cp", classpath,
"net.mamoe.console.integrationtest.IntegrationTestBootstrap",
)
.directory(workingDir)
// .inheritIO() // No output in idea
val env = builder.environment()
env.putAll(extraEnvironment)
env["MIRAI_CONSOLE_INTEGRATION_TEST"] = "true"
saveStringListToEnv("IT_PLUGINS", plugins, env)
saveStringListToEnv("IT_POINTS", points, env)
log.println("[MCIT] Launching IntegrationTest")
log.println("[MCIT] `- Arguments: ${builder.command().joinToString(" ")}")
log.println("[MCIT] `- Directory: ${builder.directory().absoluteFile}")
log.println("[MCIT] `- Debugging: $isDebugging")
if (isDebugging) {
log.println("[MCIT] Running in debug mode. Watchdog thread will not start")
}
val process = builder.start()
val timedOut = AtomicBoolean(false)
val watchdog = thread {
if (isDebugging) return@thread
try {
Thread.sleep(TimeUnit.MINUTES.toMillis(5))
timedOut.set(true)
process.destroyForcibly()
} catch (ignored: InterruptedException) {
}
}
thread { process.inputStream.copyTo(output) }
thread { process.errorStream.copyTo(error) }
val rsp = process.waitFor()
if (timedOut.get()) {
error("Mirai console daemon timed out")
}
watchdog.interrupt()
if (rsp != 0) error("Rsp $rsp")
}
}
private fun findJavaExec(): String {
findJavaExec0()?.let { return it.absolutePath }
System.err.println("[MCIT] WARNING: Unable to determine the current runtime executable path.")
System.err.println("[MCIT] WARNING: Using default executable to launch test unit")
return "java"
}
private fun findJavaExec0(): File? {
val ext = if ("windows" in System.getProperty("os.name").lowercase()) {
".exe"
} else ""
val javaHome = File(System.getProperty("java.home"))
javaHome.resolve("bin/java$ext").takeIf { it.exists() }?.let { return it }
javaHome.resolve("java$ext").takeIf { it.exists() }?.let { return it }
javaHome.resolve("jre/bin/java$ext").takeIf { it.exists() }?.let { return it }
javaHome.resolve("jre/java$ext").takeIf { it.exists() }?.let { return it }
return null
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.console.integrationtest
internal fun readStringListFromEnv(key: String): MutableList<String> {
val size = System.getenv(key)!!.toInt()
val rsp = mutableListOf<String>()
for (i in 0 until size) {
rsp.add(System.getenv("${key}_$i")!!)
}
return rsp
}
internal fun saveStringListToEnv(key: String, value: Collection<String>, env: MutableMap<String, String>) {
env[key] = value.size.toString()
value.forEachIndexed { index, v ->
env["${key}_$index"] = v
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.console.integrationtest
import net.mamoe.console.integrationtest.testpoints.DoNothingPoint
import net.mamoe.console.integrationtest.testpoints.MCITBSelfAssertions
import org.junit.jupiter.api.Test
import java.io.File
import java.lang.management.ManagementFactory
import java.util.*
import kotlin.reflect.KClass
class MiraiConsoleIntegrationTestBootstrap {
@Test
fun bootstrap() {
/*
implementation note:
不使用 @TempDir 是为了保存最后一次失败快照, 便于 debug
*/
val workingDir = File("build/IntegrationTest") // mirai-console/backend/integration-test/build/IntegrationTest
val launcher = MiraiConsoleIntegrationTestLauncher()
launcher.workingDir = workingDir
launcher.plugins = readStringListFromEnv("IT_PLUGINS")
launcher.points = listOf<Any>(
DoNothingPoint,
MCITBSelfAssertions,
).asSequence().map { v ->
when (v) {
is Class<*> -> v
is KClass<*> -> v.java
else -> v.javaClass
}
}.map { it.name }.toMutableList()
launcher.vmoptions = mutableListOf(
*ManagementFactory.getRuntimeMXBean().inputArguments.filterNot {
it.startsWith("-Djava.security.manager=")
}.toTypedArray(),
*System.getenv("IT_ARGS")!!.splitToSequence(",").map {
Base64.getDecoder().decode(it).decodeToString()
}.filter { it.isNotEmpty() }.toList().toTypedArray()
)
launcher.launch()
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.console.integrationtest.testpoints
import net.mamoe.console.integrationtest.AbstractTestPointAsPlugin
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
import net.mamoe.mirai.utils.info
/*
DoNothingPoint: Example
*/
internal object DoNothingPoint : AbstractTestPointAsPlugin() {
var enableCalled = false
override fun newPluginDescription(): JvmPluginDescription {
return JvmPluginDescription(
id = "net.mamoe.testpoint.do-nothing",
version = "1.1.0",
name = "DoNothing",
)
}
override fun KotlinPlugin.onEnable0() {
logger.info { "DoNothing.onEnable() called" }
enableCalled = true
}
override fun KotlinPlugin.onDisable0() {
logger.info { "DoNothing.onDisable() called" }
}
override fun onConsoleStartSuccessfully() {
assert(enableCalled) {
"DoNothing.onEnable() not called."
}
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.console.integrationtest.testpoints
import net.mamoe.console.integrationtest.AbstractTestPointAsPlugin
import net.mamoe.mirai.console.plugin.PluginManager
import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.description
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
import kotlin.test.*
/*
MCITBSelfAssertions: 用于检查 Integration Test 可以正常加载 AbstractTestPointAsPlugin 外部测试插件
*/
internal object MCITBSelfAssertions : AbstractTestPointAsPlugin() {
override fun newPluginDescription(): JvmPluginDescription {
return JvmPluginDescription(
id = "net.mamoe.testpoint.mirai-console-self-assertions",
version = "1.0.0",
name = "MCITBSelfAssertions",
)
}
var called = false
override fun KotlinPlugin.onEnable0() {
called = true
assertFails { error("") }
assertTrue { true }
assertFalse { false }
assertFailsWith<InternalError> { throw InternalError("") }
assertEquals("", "")
assertSame(this, this)
}
override fun onConsoleStartSuccessfully() {
assertTrue(called, "Mirai Console IntegrationTestBootstrap Internal Error")
assertTrue("MCITSelfTestPlugin not found") {
PluginManager.plugins.any { it.description.id == "net.mamoe.tester.mirai-console-self-test" }
}
}
}

View File

@ -0,0 +1 @@
build.gradle.kts

View File

@ -0,0 +1 @@
net.mamoe.console.integrationtest.ep.mcitselftest.MCITSelfTestPlugin

View File

@ -0,0 +1,33 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.console.integrationtest.ep.mcitselftest
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
import net.mamoe.mirai.utils.info
import kotlin.test.assertTrue
/*
MCITSelfTestPlugin: 用于测试 Integration-test 可正常加载
@see /test/testpoints/MCITBSelfAssertions
*/
public object MCITSelfTestPlugin : KotlinPlugin(
JvmPluginDescription(
id = "net.mamoe.tester.mirai-console-self-test",
version = "1.0.0",
name = "MCITSelfTestPlugin",
)
) {
override fun onEnable() {
logger.info { "MCITSelfTestPlugin.onEnable() called" }
assertTrue { true }
}
}

View File

@ -0,0 +1,13 @@
# Integration Test - Sub Testers
Integration Test 的测试插件, 放置在本文件夹内的全部插件均为 console 内部测试用插件
如果您不是正在修改 mirai-console, 则不需要阅读此文件及此模块
---
创建新测试插件只需要在本文件夹创建新的目录, 然后重载 (Reimport gradle projects)
如果需要添加新的依赖, 请在 [`IntegrationTest/build.gradle.kts`](../build.gradle.kts) 添加相关依赖 (使用 `testApi`) 并标注哪个测试框架使用此依赖, 为何使用此依赖
如果需要自定义 `build.gradle.kts`, 请在 IDEA 右键 `build.gradle.kts` 并选择 `Git > Add File`

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("UnusedImport")
plugins {
kotlin("jvm")
kotlin("plugin.serialization")
id("java")
}
version = "0.0.0"
kotlin {
explicitApiWarning()
}
dependencies {
api(project(":mirai-console.integration-test"))
}

View File

@ -52,6 +52,34 @@ includeConsoleProject(":mirai-console-compiler-annotations", "tools/compiler-ann
includeConsoleProject(":mirai-console", "backend/mirai-console")
includeConsoleProject(":mirai-console.codegen", "backend/codegen")
includeConsoleProject(":mirai-console-terminal", "frontend/mirai-console-terminal")
// region mirai-console.integration-test
includeConsoleProject(":mirai-console.integration-test", "backend/integration-test")
val consoleIntegrationTestSubPluginBuildGradleKtsTemplate by lazy {
rootProject.projectDir
.resolve("mirai-console/backend/integration-test/testers")
.resolve("tester.template.gradle.kts")
.readText()
}
@Suppress("SimpleRedundantLet")
fun includeConsoleITPlugin(path: File) {
path.resolve("build.gradle.kts").takeIf { !it.isFile }?.let { initScript ->
initScript.writeText(consoleIntegrationTestSubPluginBuildGradleKtsTemplate)
}
val projectPath = ":mirai-console.integration-test.tp.${path.name}"
include(projectPath)
project(projectPath).projectDir = path
}
rootProject.projectDir
.resolve("mirai-console/backend/integration-test/testers")
.listFiles()?.asSequence().orEmpty()
.filter { it.isDirectory }
.forEach { includeConsoleITPlugin(it) }
// endregion
includeConsoleProject(":mirai-console-compiler-common", "tools/compiler-common")
includeConsoleProject(":mirai-console-intellij", "tools/intellij-plugin")
includeConsoleProject(":mirai-console-gradle", "tools/gradle-plugin")