mirror of
https://github.com/LamGC/ScalaBot.git
synced 2025-07-01 12:57:24 +00:00
refactor(config): 将与配置相关的内容迁移到 scalabot-meta 模块.
通过将配置迁移到单独的模块, 可以方便使用其他程序扩展 ScaleBot, 而不仅仅是让 ScaleBot 成为扩展的平台. BREAKING CHANGE: 与配置有关的 Class 移动到了 scalabot-meta 模块. 目前仅所有配置类(以 `Config` 结尾的 Class)和相应的序列化类(以 `Serializer` 结尾的)都迁移到了 meta 模块, 但其工具方法则作为扩展函数保留在 app 模块中. 这么做的好处是为了方便其他应用(例如 ScalaBot 外部管理程序)根据需要生成配置文件. scalabot-meta 将会作为依赖项发布, 可根据需要获取 ScalaBot-meta 生成 ScalaBot 的配置. 此次改动普通用户无需迁移.
This commit is contained in:
30
scalabot-meta/build.gradle.kts
Normal file
30
scalabot-meta/build.gradle.kts
Normal file
@ -0,0 +1,30 @@
|
||||
plugins {
|
||||
kotlin("jvm") version "1.6.10"
|
||||
id("org.jetbrains.kotlinx.kover") version "0.5.1"
|
||||
}
|
||||
|
||||
group = "net.lamgc"
|
||||
version = "0.3.1"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val aetherVersion = "1.1.0"
|
||||
implementation("org.eclipse.aether:aether-api:$aetherVersion")
|
||||
implementation("org.eclipse.aether:aether-util:$aetherVersion")
|
||||
|
||||
implementation("org.telegram:telegrambots-meta:6.0.1")
|
||||
|
||||
implementation("com.google.code.gson:gson:2.9.0")
|
||||
|
||||
testImplementation(kotlin("test"))
|
||||
testImplementation("io.mockk:mockk:1.12.4")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||
}
|
||||
|
||||
tasks.getByName<Test>("test") {
|
||||
useJUnitPlatform()
|
||||
}
|
108
scalabot-meta/src/main/kotlin/Configs.kt
Normal file
108
scalabot-meta/src/main/kotlin/Configs.kt
Normal file
@ -0,0 +1,108 @@
|
||||
package net.lamgc.scalabot.config
|
||||
|
||||
import org.eclipse.aether.artifact.Artifact
|
||||
import org.eclipse.aether.repository.Authentication
|
||||
import org.eclipse.aether.repository.Proxy
|
||||
import org.telegram.telegrambots.meta.ApiConstants
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* 机器人帐号信息.
|
||||
* @property name 机器人名称, 建议与实际设定的名称相同.
|
||||
* @property token 机器人 API Token.
|
||||
* @property creatorId 机器人创建者, 管理机器人需要使用该信息.
|
||||
*/
|
||||
data class BotAccount(
|
||||
val name: String,
|
||||
val token: String,
|
||||
val creatorId: Long = -1
|
||||
) {
|
||||
|
||||
val id
|
||||
// 不要想着每次获取都要从 token 里取出有性能损耗.
|
||||
// 由于 Gson 解析方式, 如果不这么做, 会出现 token 设置前 id 初始化完成, 就只有"0"了,
|
||||
// 虽然能过单元测试, 但实际使用过程是不能正常用的.
|
||||
get() = token.substringBefore(":").toLong()
|
||||
}
|
||||
|
||||
/**
|
||||
* 机器人配置.
|
||||
* @property account 机器人帐号信息, 用于访问 API.
|
||||
* @property disableBuiltInAbility 是否禁用 AbilityBot 自带命令.
|
||||
* @property extensions 该机器人启用的扩展.
|
||||
* @property proxy 为该机器人单独设置的代理配置, 如无设置, 则使用 AppConfig 中的代理配置.
|
||||
*/
|
||||
data class BotConfig(
|
||||
val enabled: Boolean = true,
|
||||
val account: BotAccount,
|
||||
val disableBuiltInAbility: Boolean = false,
|
||||
val autoUpdateCommandList: Boolean = false,
|
||||
/*
|
||||
* 使用构件坐标来选择机器人所使用的扩展包.
|
||||
* 这么做的原因是我暂时没找到一个合适的方法来让开发者方便地设定自己的扩展 Id,
|
||||
* 而构件坐标(POM Reference 或者叫 GAV 坐标)是开发者创建 Maven/Gradle 项目时一定会设置的,
|
||||
* 所以就直接用了. :P
|
||||
*/
|
||||
val extensions: Set<Artifact>,
|
||||
val proxy: ProxyConfig? = ProxyConfig(),
|
||||
val baseApiUrl: String? = ApiConstants.BASE_URL
|
||||
)
|
||||
|
||||
enum class ProxyType {
|
||||
NO_PROXY,
|
||||
HTTP,
|
||||
SOCKS4,
|
||||
SOCKS5
|
||||
}
|
||||
|
||||
/**
|
||||
* 代理配置.
|
||||
* @property type 代理类型.
|
||||
* @property host 代理服务端地址.
|
||||
* @property port 代理服务端端口.
|
||||
*/
|
||||
data class ProxyConfig(
|
||||
val type: ProxyType = ProxyType.NO_PROXY,
|
||||
val host: String = "127.0.0.1",
|
||||
val port: Int = 1080
|
||||
)
|
||||
|
||||
data class MetricsConfig(
|
||||
val enable: Boolean = false,
|
||||
val port: Int = 9386,
|
||||
val bindAddress: String? = "0.0.0.0",
|
||||
val authenticator: UsernameAuthenticator? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* Maven 远端仓库配置.
|
||||
* @property url 仓库地址.
|
||||
* @property proxy 访问仓库所使用的代理, 仅支持 http/https 代理.
|
||||
* @property layout 仓库布局版本, Maven 2 及以上使用 `default`, Maven 1 使用 `legacy`.
|
||||
*/
|
||||
data class MavenRepositoryConfig(
|
||||
val id: String? = null,
|
||||
val url: URL,
|
||||
val proxy: Proxy? = null,
|
||||
val layout: String = "default",
|
||||
val enableReleases: Boolean = true,
|
||||
val enableSnapshots: Boolean = true,
|
||||
// 可能要设计个 type 来判断解析成什么类型的 Authentication.
|
||||
val authentication: Authentication? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* ScalaBot App 配置.
|
||||
*
|
||||
* App 配置信息与 BotConfig 分开, 分别存储在各自单独的文件中.
|
||||
* @property proxy Telegram API 代理配置.
|
||||
* @property metrics 运行指标数据配置. 可通过时序数据库记录运行数据.
|
||||
* @property mavenRepositories Maven 远端仓库配置.
|
||||
* @property mavenLocalRepository Maven 本地仓库路径. 相对于运行目录 (而不是 DATA_ROOT 目录)
|
||||
*/
|
||||
data class AppConfig(
|
||||
val proxy: ProxyConfig = ProxyConfig(),
|
||||
val metrics: MetricsConfig = MetricsConfig(),
|
||||
val mavenRepositories: List<MavenRepositoryConfig> = emptyList(),
|
||||
val mavenLocalRepository: String? = null
|
||||
)
|
26
scalabot-meta/src/main/kotlin/UsernameAuthenticator.kt
Normal file
26
scalabot-meta/src/main/kotlin/UsernameAuthenticator.kt
Normal file
@ -0,0 +1,26 @@
|
||||
package net.lamgc.scalabot.config
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.sun.net.httpserver.BasicAuthenticator
|
||||
|
||||
class UsernameAuthenticator(private val username: String, private val password: String) :
|
||||
BasicAuthenticator("metrics") {
|
||||
override fun checkCredentials(username: String?, password: String?): Boolean =
|
||||
this.username == username && this.password == password
|
||||
|
||||
fun toJsonObject(): JsonObject = JsonObject().apply {
|
||||
addProperty("username", username)
|
||||
addProperty("password", password)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other is UsernameAuthenticator && this.username == other.username && this.password == other.password
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = username.hashCode()
|
||||
result = 31 * result + password.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
166
scalabot-meta/src/main/kotlin/serializer/Serializer.kt
Normal file
166
scalabot-meta/src/main/kotlin/serializer/Serializer.kt
Normal file
@ -0,0 +1,166 @@
|
||||
package net.lamgc.scalabot.config.serializer
|
||||
|
||||
import com.google.gson.*
|
||||
import net.lamgc.scalabot.config.MavenRepositoryConfig
|
||||
import net.lamgc.scalabot.config.ProxyType
|
||||
import net.lamgc.scalabot.config.UsernameAuthenticator
|
||||
import org.eclipse.aether.artifact.Artifact
|
||||
import org.eclipse.aether.artifact.DefaultArtifact
|
||||
import org.eclipse.aether.repository.Authentication
|
||||
import org.eclipse.aether.repository.Proxy
|
||||
import org.eclipse.aether.util.repository.AuthenticationBuilder
|
||||
import java.lang.reflect.Type
|
||||
import java.net.URL
|
||||
|
||||
object ProxyTypeSerializer : JsonDeserializer<ProxyType>,
|
||||
JsonSerializer<ProxyType> {
|
||||
|
||||
override fun deserialize(
|
||||
json: JsonElement,
|
||||
typeOfT: Type?,
|
||||
context: JsonDeserializationContext?
|
||||
): ProxyType {
|
||||
if (json.isJsonNull) {
|
||||
return ProxyType.NO_PROXY
|
||||
}
|
||||
if (!json.isJsonPrimitive) {
|
||||
throw JsonParseException("Wrong configuration value type.")
|
||||
}
|
||||
val value = json.asString.trim()
|
||||
try {
|
||||
return ProxyType.valueOf(value.uppercase())
|
||||
} catch (e: IllegalArgumentException) {
|
||||
throw JsonParseException("Invalid value: $value")
|
||||
}
|
||||
}
|
||||
|
||||
override fun serialize(
|
||||
src: ProxyType,
|
||||
typeOfSrc: Type?,
|
||||
context: JsonSerializationContext?
|
||||
): JsonElement {
|
||||
return JsonPrimitive(src.toString())
|
||||
}
|
||||
}
|
||||
|
||||
object ArtifactSerializer : JsonSerializer<Artifact>, JsonDeserializer<Artifact> {
|
||||
override fun serialize(src: Artifact, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
|
||||
val gavBuilder = StringBuilder("${src.groupId}:${src.artifactId}")
|
||||
if (!src.extension.equals("jar")) {
|
||||
gavBuilder.append(':').append(src.extension)
|
||||
}
|
||||
if (src.classifier.isNotEmpty()) {
|
||||
gavBuilder.append(':').append(src.classifier)
|
||||
}
|
||||
return JsonPrimitive(gavBuilder.append(':').append(src.version).toString())
|
||||
}
|
||||
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type?, context: JsonDeserializationContext?): Artifact {
|
||||
if (!json.isJsonPrimitive) {
|
||||
throw JsonParseException("Wrong configuration value type.")
|
||||
}
|
||||
return DefaultArtifact(json.asString.trim())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object AuthenticationSerializer : JsonDeserializer<Authentication> {
|
||||
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Authentication {
|
||||
if (json !is JsonObject) {
|
||||
throw JsonParseException("Unsupported JSON type.")
|
||||
}
|
||||
val username = SerializerUtils.checkJsonKey(json, "username")
|
||||
val password = SerializerUtils.checkJsonKey(json, "password")
|
||||
val builder = AuthenticationBuilder()
|
||||
builder.addUsername(username)
|
||||
builder.addPassword(password)
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private object SerializerUtils {
|
||||
fun checkJsonKey(json: JsonObject, key: String): String {
|
||||
if (!json.has(key)) {
|
||||
throw JsonParseException("Required field does not exist: $key")
|
||||
} else if (!json.get(key).isJsonPrimitive) {
|
||||
throw JsonParseException("Wrong field `$key` type: ${json.get(key)::class.java}")
|
||||
}
|
||||
return json.get(key).asString
|
||||
}
|
||||
}
|
||||
|
||||
object MavenRepositoryConfigSerializer
|
||||
: JsonDeserializer<MavenRepositoryConfig> {
|
||||
|
||||
override fun deserialize(
|
||||
json: JsonElement,
|
||||
typeOfT: Type,
|
||||
context: JsonDeserializationContext
|
||||
): MavenRepositoryConfig {
|
||||
return when (json) {
|
||||
is JsonObject -> {
|
||||
MavenRepositoryConfig(
|
||||
id = json.get("id")?.asString,
|
||||
url = URL(SerializerUtils.checkJsonKey(json, "url")),
|
||||
proxy = if (json.has("proxy") && json.get("proxy").isJsonObject)
|
||||
context.deserialize<Proxy>(
|
||||
json.getAsJsonObject("proxy"), Proxy::class.java
|
||||
) else null,
|
||||
layout = json.get("layout")?.asString ?: "default",
|
||||
enableReleases = json.get("enableReleases")?.asBoolean ?: true,
|
||||
enableSnapshots = json.get("enableSnapshots")?.asBoolean ?: true,
|
||||
authentication = if (json.has("authentication") && json.get("authentication").isJsonObject)
|
||||
context.deserialize<Authentication>(
|
||||
json.getAsJsonObject("authentication"), Authentication::class.java
|
||||
) else null
|
||||
)
|
||||
}
|
||||
is JsonPrimitive -> {
|
||||
MavenRepositoryConfig(url = URL(json.asString))
|
||||
}
|
||||
else -> {
|
||||
throw JsonParseException("Unsupported Maven warehouse configuration type.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object UsernameAuthenticatorSerializer : JsonSerializer<UsernameAuthenticator>,
|
||||
JsonDeserializer<UsernameAuthenticator> {
|
||||
|
||||
override fun serialize(
|
||||
src: UsernameAuthenticator,
|
||||
typeOfSrc: Type?,
|
||||
context: JsonSerializationContext?
|
||||
): JsonElement {
|
||||
return src.toJsonObject()
|
||||
}
|
||||
|
||||
override fun deserialize(
|
||||
json: JsonElement,
|
||||
typeOfT: Type?,
|
||||
context: JsonDeserializationContext?
|
||||
): UsernameAuthenticator? {
|
||||
if (json.isJsonNull) {
|
||||
return null
|
||||
} else if (!json.isJsonObject) {
|
||||
throw JsonParseException("Invalid attribute value type.")
|
||||
}
|
||||
|
||||
val jsonObj = json.asJsonObject
|
||||
|
||||
if (jsonObj["username"]?.isJsonPrimitive != true) {
|
||||
throw JsonParseException("Invalid attribute value: username")
|
||||
} else if (jsonObj["password"]?.isJsonPrimitive != true) {
|
||||
throw JsonParseException("Invalid attribute value: password")
|
||||
}
|
||||
|
||||
if (jsonObj["username"].asString.isEmpty() || jsonObj["password"].asString.isEmpty()) {
|
||||
throw JsonParseException("`username` or `password` is empty.")
|
||||
}
|
||||
return UsernameAuthenticator(jsonObj["username"].asString, jsonObj["password"].asString)
|
||||
}
|
||||
|
||||
}
|
38
scalabot-meta/src/test/kotlin/BotAccountTest.kt
Normal file
38
scalabot-meta/src/test/kotlin/BotAccountTest.kt
Normal file
@ -0,0 +1,38 @@
|
||||
package net.lamgc.scalabot.config
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
internal class BotAccountTest {
|
||||
|
||||
@Test
|
||||
fun `id getter`() {
|
||||
val accountId = abs(Random().nextInt()).toLong()
|
||||
assertEquals(accountId, BotAccount("Test", "${accountId}:AAHErDroUTznQsOd_oZPJ6cQEj4Z5mGHO10", 0).id)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deserializerTest() {
|
||||
val accountId = abs(Random().nextInt()).toLong()
|
||||
val creatorId = abs(Random().nextInt()).toLong()
|
||||
val botAccountJsonObject = Gson().fromJson(
|
||||
"""
|
||||
{
|
||||
"name": "TestBot",
|
||||
"token": "${accountId}:AAHErDroUTznQsOd_oZPJ6cQEj4Z5mGHO10",
|
||||
"creatorId": $creatorId
|
||||
}
|
||||
""".trimIndent(), JsonObject::class.java
|
||||
)
|
||||
val botAccount = Gson().fromJson(botAccountJsonObject, BotAccount::class.java)
|
||||
assertEquals(botAccountJsonObject["name"].asString, botAccount.name)
|
||||
assertEquals(botAccountJsonObject["token"].asString, botAccount.token)
|
||||
assertEquals(accountId, botAccount.id, "BotAccount ID does not match expectations.")
|
||||
assertEquals(creatorId, botAccount.creatorId)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
@file:Suppress("PackageDirectoryMismatch")
|
||||
|
||||
package net.lamgc.scalabot.config.serializer
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParseException
|
||||
import com.google.gson.JsonPrimitive
|
||||
import org.eclipse.aether.artifact.DefaultArtifact
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
internal class ArtifactSerializerTest {
|
||||
|
||||
@Test
|
||||
fun badJsonType() {
|
||||
assertFailsWith<JsonParseException> { ArtifactSerializer.deserialize(JsonObject(), null, null) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Basic format serialization`() {
|
||||
val gav = "org.example.software:test:1.0.0-SNAPSHOT"
|
||||
val expectArtifact = DefaultArtifact(gav)
|
||||
val actualArtifact = DefaultArtifact(ArtifactSerializer.serialize(expectArtifact, null, null).asString)
|
||||
assertEquals(expectArtifact, actualArtifact)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Full format serialization`() {
|
||||
val gav = "org.example.software:test:war:javadoc:1.0.0-SNAPSHOT"
|
||||
val expectArtifact = DefaultArtifact(gav)
|
||||
val actualArtifact = DefaultArtifact(ArtifactSerializer.serialize(expectArtifact, null, null).asString)
|
||||
assertEquals(expectArtifact, actualArtifact)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deserialize() {
|
||||
val gav = "org.example.software:test:1.0.0-SNAPSHOT"
|
||||
val expectArtifact = DefaultArtifact(gav)
|
||||
val actualArtifact = ArtifactSerializer.deserialize(JsonPrimitive(gav), null, null)
|
||||
assertEquals(expectArtifact, actualArtifact)
|
||||
}
|
||||
}
|
322
scalabot-meta/src/test/kotlin/serializer/SerializersKtTest.kt
Normal file
322
scalabot-meta/src/test/kotlin/serializer/SerializersKtTest.kt
Normal file
@ -0,0 +1,322 @@
|
||||
package net.lamgc.scalabot.config.serializer
|
||||
|
||||
import com.google.gson.*
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import net.lamgc.scalabot.config.MavenRepositoryConfig
|
||||
import net.lamgc.scalabot.config.ProxyType
|
||||
import org.eclipse.aether.repository.Authentication
|
||||
import org.eclipse.aether.repository.AuthenticationContext
|
||||
import org.eclipse.aether.repository.Proxy
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Type
|
||||
import java.net.URL
|
||||
import kotlin.test.*
|
||||
|
||||
internal class SerializersKtTest {
|
||||
|
||||
private val instance: Any
|
||||
private val method: Method
|
||||
|
||||
init {
|
||||
val clazz = Class.forName("net.lamgc.scalabot.config.serializer.SerializerUtils")
|
||||
method = clazz.getDeclaredMethod("checkJsonKey", JsonObject::class.java, String::class.java)
|
||||
method.isAccessible = true
|
||||
instance = clazz.getDeclaredField("INSTANCE").apply {
|
||||
isAccessible = true
|
||||
}.get(null)
|
||||
}
|
||||
|
||||
private fun invoke(json: JsonObject, key: String): String {
|
||||
try {
|
||||
return method.invoke(instance, json, key) as String
|
||||
} catch (e: InvocationTargetException) {
|
||||
throw e.targetException
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Json key checker test`() {
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
invoke(JsonObject(), "NOT_EXIST_KEY")
|
||||
}
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
invoke(JsonObject().apply { add("NULL_KEY", JsonNull.INSTANCE) }, "NULL_KEY")
|
||||
}
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
invoke(JsonObject().apply { add("ARRAY_KEY", JsonArray()) }, "ARRAY_KEY")
|
||||
}
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
invoke(JsonObject().apply { add("OBJECT_KEY", JsonObject()) }, "OBJECT_KEY")
|
||||
}
|
||||
|
||||
val expectKey = "TEST"
|
||||
val expectString = "testString"
|
||||
val json = JsonObject().apply { addProperty(expectKey, expectString) }
|
||||
|
||||
assertEquals(expectString, invoke(json, expectKey))
|
||||
}
|
||||
}
|
||||
|
||||
internal class ProxyTypeSerializerTest {
|
||||
|
||||
@Test
|
||||
fun `serialize test`() {
|
||||
for (type in ProxyType.values()) {
|
||||
assertEquals(
|
||||
JsonPrimitive(type.name), ProxyTypeSerializer.serialize(type, null, null),
|
||||
"ProxyType 序列化结果与预期不符."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deserialize test`() {
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
ProxyTypeSerializer.deserialize(JsonObject(), null, null)
|
||||
}
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
ProxyTypeSerializer.deserialize(JsonArray(), null, null)
|
||||
}
|
||||
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
ProxyTypeSerializer.deserialize(JsonPrimitive("NOT_IN_ENUM_VALUE"), null, null)
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
ProxyType.NO_PROXY,
|
||||
ProxyTypeSerializer.deserialize(JsonNull.INSTANCE, null, null)
|
||||
)
|
||||
|
||||
for (type in ProxyType.values()) {
|
||||
assertEquals(
|
||||
type, ProxyTypeSerializer.deserialize(JsonPrimitive(type.name), null, null),
|
||||
"ProxyType 反序列化结果与预期不符."
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
type, ProxyTypeSerializer.deserialize(JsonPrimitive(" ${type.name} "), null, null),
|
||||
"ProxyType 反序列化时未对 Json 字符串进行修剪(trim)."
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class MavenRepositoryConfigSerializerTest {
|
||||
|
||||
@Test
|
||||
fun `unsupported json type deserialize test`() {
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
MavenRepositoryConfigSerializer.deserialize(
|
||||
JsonArray(),
|
||||
MavenRepositoryConfig::class.java,
|
||||
TestJsonDeserializationContext
|
||||
)
|
||||
}
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
MavenRepositoryConfigSerializer.deserialize(
|
||||
JsonNull.INSTANCE,
|
||||
MavenRepositoryConfig::class.java,
|
||||
TestJsonDeserializationContext
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `json primitive deserialize test`() {
|
||||
val expectRepoUrl = "https://repo.example.org/maven"
|
||||
val config = MavenRepositoryConfigSerializer.deserialize(
|
||||
JsonPrimitive(expectRepoUrl),
|
||||
MavenRepositoryConfig::class.java,
|
||||
TestJsonDeserializationContext
|
||||
)
|
||||
|
||||
assertNull(config.id)
|
||||
assertEquals(URL(expectRepoUrl), config.url)
|
||||
assertNull(config.proxy, "Proxy 默认值不为 null.")
|
||||
assertEquals("default", config.layout)
|
||||
assertTrue(config.enableReleases)
|
||||
assertTrue(config.enableSnapshots)
|
||||
assertNull(config.authentication)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `json object default deserialize test`() {
|
||||
val expectRepoUrl = "https://repo.example.org/maven"
|
||||
val jsonObject = JsonObject()
|
||||
jsonObject.addProperty("url", expectRepoUrl)
|
||||
val config = MavenRepositoryConfigSerializer.deserialize(
|
||||
jsonObject,
|
||||
MavenRepositoryConfig::class.java,
|
||||
TestJsonDeserializationContext
|
||||
)
|
||||
|
||||
assertNull(config.id)
|
||||
assertEquals(URL(expectRepoUrl), config.url)
|
||||
assertNull(config.proxy, "Proxy 默认值不为 null.")
|
||||
assertEquals("default", config.layout)
|
||||
assertTrue(config.enableReleases)
|
||||
assertTrue(config.enableSnapshots)
|
||||
assertNull(config.authentication)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `json object deserialize test`() {
|
||||
@Language("JSON5")
|
||||
val looksGoodJsonString = """
|
||||
{
|
||||
"id": "test-repository",
|
||||
"url": "https://repo.example.org/maven",
|
||||
"proxy": {
|
||||
"type": "http",
|
||||
"host": "127.0.1.1",
|
||||
"port": 10800
|
||||
},
|
||||
"layout": "default",
|
||||
"enableReleases": false,
|
||||
"enableSnapshots": true
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
val jsonObject = Gson().fromJson(looksGoodJsonString, JsonObject::class.java)
|
||||
var config = MavenRepositoryConfigSerializer.deserialize(
|
||||
jsonObject,
|
||||
MavenRepositoryConfig::class.java,
|
||||
TestJsonDeserializationContext
|
||||
)
|
||||
|
||||
assertEquals(jsonObject["id"].asString, config.id)
|
||||
assertEquals(URL(jsonObject["url"].asString), config.url)
|
||||
assertEquals(Proxy("http", "127.0.1.1", 10800), config.proxy)
|
||||
assertEquals(jsonObject["layout"].asString, config.layout)
|
||||
assertEquals(jsonObject["enableReleases"].asBoolean, config.enableReleases)
|
||||
assertEquals(jsonObject["enableSnapshots"].asBoolean, config.enableSnapshots)
|
||||
|
||||
// ------------------------------------
|
||||
|
||||
jsonObject.add("proxy", JsonNull.INSTANCE)
|
||||
jsonObject.remove("layout")
|
||||
|
||||
config = MavenRepositoryConfigSerializer.deserialize(
|
||||
jsonObject,
|
||||
MavenRepositoryConfig::class.java,
|
||||
TestJsonDeserializationContext
|
||||
)
|
||||
|
||||
assertEquals(jsonObject["id"].asString, config.id)
|
||||
assertEquals(URL(jsonObject["url"].asString), config.url)
|
||||
assertNull(config.proxy)
|
||||
assertEquals("default", config.layout)
|
||||
assertEquals(jsonObject["enableReleases"].asBoolean, config.enableReleases)
|
||||
assertEquals(jsonObject["enableSnapshots"].asBoolean, config.enableSnapshots)
|
||||
|
||||
// ------------------------------------
|
||||
|
||||
jsonObject.add("authentication", JsonArray())
|
||||
jsonObject.add("layout", mockk<JsonPrimitive> {
|
||||
every { asString }.returns(null)
|
||||
})
|
||||
|
||||
config = MavenRepositoryConfigSerializer.deserialize(
|
||||
jsonObject,
|
||||
MavenRepositoryConfig::class.java,
|
||||
TestJsonDeserializationContext
|
||||
)
|
||||
|
||||
assertEquals(jsonObject["id"].asString, config.id)
|
||||
assertEquals(URL(jsonObject["url"].asString), config.url)
|
||||
assertNull(config.proxy)
|
||||
assertEquals("default", config.layout)
|
||||
assertEquals(jsonObject["enableReleases"].asBoolean, config.enableReleases)
|
||||
assertEquals(jsonObject["enableSnapshots"].asBoolean, config.enableSnapshots)
|
||||
assertNull(config.authentication)
|
||||
|
||||
// ------------------------------------
|
||||
|
||||
jsonObject.add("authentication", JsonObject().apply {
|
||||
addProperty("username", "testUsername")
|
||||
addProperty("password", "testPassword")
|
||||
})
|
||||
|
||||
config = MavenRepositoryConfigSerializer.deserialize(
|
||||
jsonObject,
|
||||
MavenRepositoryConfig::class.java,
|
||||
TestJsonDeserializationContext
|
||||
)
|
||||
|
||||
assertEquals(jsonObject["id"].asString, config.id)
|
||||
assertEquals(URL(jsonObject["url"].asString), config.url)
|
||||
assertNull(config.proxy)
|
||||
assertEquals("default", config.layout)
|
||||
assertEquals(jsonObject["enableReleases"].asBoolean, config.enableReleases)
|
||||
assertEquals(jsonObject["enableSnapshots"].asBoolean, config.enableSnapshots)
|
||||
assertNotNull(config.authentication)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private object TestJsonDeserializationContext : JsonDeserializationContext {
|
||||
|
||||
private val gson = GsonBuilder()
|
||||
.registerTypeAdapter(Authentication::class.java, AuthenticationSerializer)
|
||||
.create()
|
||||
|
||||
override fun <T : Any?> deserialize(json: JsonElement, typeOfT: Type): T {
|
||||
return gson.fromJson(json, typeOfT)
|
||||
}
|
||||
}
|
||||
|
||||
internal class AuthenticationSerializerTest {
|
||||
|
||||
@Test
|
||||
fun `deserialize test`() {
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
AuthenticationSerializer.deserialize(
|
||||
JsonNull.INSTANCE,
|
||||
Authentication::class.java, TestJsonDeserializationContext
|
||||
)
|
||||
}
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
AuthenticationSerializer.deserialize(
|
||||
JsonArray(),
|
||||
Authentication::class.java, TestJsonDeserializationContext
|
||||
)
|
||||
}
|
||||
assertThrows(JsonParseException::class.java) {
|
||||
AuthenticationSerializer.deserialize(
|
||||
JsonPrimitive("A STRING"),
|
||||
Authentication::class.java, TestJsonDeserializationContext
|
||||
)
|
||||
}
|
||||
|
||||
val expectJsonObject = JsonObject().apply {
|
||||
addProperty("username", "testUsername")
|
||||
addProperty("password", "testPassword")
|
||||
}
|
||||
|
||||
val mockContext = mockk<AuthenticationContext> {
|
||||
every { put(any(), any()) }.answers { }
|
||||
}
|
||||
|
||||
val result = AuthenticationSerializer.deserialize(
|
||||
expectJsonObject,
|
||||
Authentication::class.java, TestJsonDeserializationContext
|
||||
)
|
||||
|
||||
assertNotNull(result)
|
||||
result.fill(mockContext, "username", null)
|
||||
result.fill(mockContext, "password", null)
|
||||
|
||||
verify {
|
||||
mockContext.put("username", "testUsername")
|
||||
mockContext.put("password", "testPassword".toCharArray())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package net.lamgc.scalabot.config.serializer
|
||||
|
||||
import com.google.gson.*
|
||||
import net.lamgc.scalabot.config.UsernameAuthenticator
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import kotlin.test.*
|
||||
|
||||
class UsernameAuthenticatorTest {
|
||||
|
||||
@Test
|
||||
fun checkCredentialsTest() {
|
||||
val authenticator = UsernameAuthenticator("testUser", "testPassword")
|
||||
assertTrue(authenticator.checkCredentials("testUser", "testPassword"))
|
||||
assertFalse(authenticator.checkCredentials("falseUser", "testPassword"))
|
||||
assertFalse(authenticator.checkCredentials("testUser", "falsePassword"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun toJsonObjectTest() {
|
||||
val authenticator = UsernameAuthenticator("testUser", "testPassword")
|
||||
val jsonObject = authenticator.toJsonObject()
|
||||
assertEquals("testUser", jsonObject["username"]?.asString)
|
||||
assertEquals("testPassword", jsonObject["password"]?.asString)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun equalsTest() {
|
||||
val authenticator = UsernameAuthenticator("testUser", "testPassword")
|
||||
assertEquals(authenticator, UsernameAuthenticator("testUser", "testPassword"))
|
||||
assertEquals(authenticator.hashCode(), UsernameAuthenticator("testUser", "testPassword").hashCode())
|
||||
assertNotEquals(authenticator, UsernameAuthenticator("testUser", "falsePassword"))
|
||||
assertNotEquals(authenticator.hashCode(), UsernameAuthenticator("testUser", "falsePassword").hashCode())
|
||||
assertNotEquals(authenticator, UsernameAuthenticator("falseUser", "testPassword"))
|
||||
assertNotEquals(authenticator.hashCode(), UsernameAuthenticator("falseUser", "testPassword").hashCode())
|
||||
assertNotEquals(authenticator, UsernameAuthenticator("falseUser", "falsePassword"))
|
||||
assertNotEquals(authenticator.hashCode(), UsernameAuthenticator("falseUser", "falsePassword").hashCode())
|
||||
assertFalse(authenticator.equals(null))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UsernameAuthenticatorSerializerTest {
|
||||
|
||||
@Test
|
||||
fun serializeTest() {
|
||||
val authenticator = UsernameAuthenticator("testUser", "testPassword")
|
||||
val jsonElement = UsernameAuthenticatorSerializer.serialize(authenticator, null, null)
|
||||
assertTrue(jsonElement.isJsonObject)
|
||||
val jsonObject = jsonElement.asJsonObject
|
||||
assertEquals("testUser", jsonObject["username"]?.asString)
|
||||
assertEquals("testPassword", jsonObject["password"]?.asString)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deserializeTest() {
|
||||
assertThrows<JsonParseException> {
|
||||
UsernameAuthenticatorSerializer.deserialize(JsonArray(), null, null)
|
||||
}
|
||||
assertThrows<JsonParseException> {
|
||||
UsernameAuthenticatorSerializer.deserialize(JsonPrimitive(""), null, null)
|
||||
}
|
||||
assertNull(UsernameAuthenticatorSerializer.deserialize(JsonNull.INSTANCE, null, null))
|
||||
assertThrows<JsonParseException> {
|
||||
UsernameAuthenticatorSerializer.deserialize(JsonObject().apply {
|
||||
addProperty("username", "testUser")
|
||||
}, null, null)
|
||||
}
|
||||
assertThrows<JsonParseException> {
|
||||
UsernameAuthenticatorSerializer.deserialize(JsonObject().apply {
|
||||
addProperty("username", "testUser")
|
||||
add("password", JsonArray())
|
||||
}, null, null)
|
||||
}
|
||||
assertThrows<JsonParseException> {
|
||||
UsernameAuthenticatorSerializer.deserialize(JsonObject().apply {
|
||||
addProperty("password", "testPassword")
|
||||
}, null, null)
|
||||
}
|
||||
assertThrows<JsonParseException> {
|
||||
UsernameAuthenticatorSerializer.deserialize(JsonObject().apply {
|
||||
add("username", JsonArray())
|
||||
addProperty("password", "testPassword")
|
||||
}, null, null)
|
||||
}
|
||||
assertThrows<JsonParseException> {
|
||||
UsernameAuthenticatorSerializer.deserialize(JsonObject().apply {
|
||||
addProperty("username", "")
|
||||
addProperty("password", "")
|
||||
}, null, null)
|
||||
}
|
||||
assertThrows<JsonParseException> {
|
||||
UsernameAuthenticatorSerializer.deserialize(JsonObject().apply {
|
||||
addProperty("username", "testUser")
|
||||
addProperty("password", "")
|
||||
}, null, null)
|
||||
}
|
||||
assertThrows<JsonParseException> {
|
||||
UsernameAuthenticatorSerializer.deserialize(JsonObject().apply {
|
||||
addProperty("username", "")
|
||||
addProperty("password", "testPassword")
|
||||
}, null, null)
|
||||
}
|
||||
|
||||
val authenticator = UsernameAuthenticatorSerializer.deserialize(JsonObject().apply {
|
||||
addProperty("username", "testUser")
|
||||
addProperty("password", "testPassword")
|
||||
}, null, null)
|
||||
assertNotNull(authenticator)
|
||||
|
||||
assertTrue(authenticator.checkCredentials("testUser", "testPassword"))
|
||||
assertFalse(authenticator.checkCredentials("falseUser", "testPassword"))
|
||||
assertFalse(authenticator.checkCredentials("testUser", "falsePassword"))
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user