refactor(#1375): typed params for subscription.*, usage.bars and vault.* (#1386)

This commit is contained in:
m57 authored and GitHub committed 2026-09-29 19:21:14 +03:00
1 parent 717b5b0361
commit 60c13f10ce
7 files changed
+933 -46

No files matched your search

@@ -0,0 +1,431 @@
package com.m57.hermescontrol.data.ws
import android.util.Log
import com.m57.hermescontrol.data.local.AuthManager
import com.m57.hermescontrol.data.remote.CookieManager
import com.m57.hermescontrol.data.remote.DashboardSessionTokenRefresher
import com.m57.hermescontrol.data.remote.OkHttpProvider
import com.m57.hermescontrol.data.remote.buildFakePersistentCookieJar
import com.m57.hermescontrol.data.ws.contract.EmptyParams
import com.m57.hermescontrol.data.ws.contract.RpcMethods
import com.m57.hermescontrol.data.ws.contract.SubscriptionChangeParams
import com.m57.hermescontrol.data.ws.contract.VaultLockParams
import com.m57.hermescontrol.data.ws.contract.VaultUnlockParams
import io.mockk.coEvery
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.booleanOrNull
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReference
class HermesWsClientBillingVaultTest {
private lateinit var mockWebServer: MockWebServer
@Before
fun setUp() {
mockkStatic(Log::class)
every { Log.d(any<String>(), any<String>()) } returns 0
every { Log.i(any<String>(), any<String>()) } returns 0
every { Log.w(any<String>(), any<String>()) } returns 0
every { Log.w(any<String>(), any<String>(), any<Throwable>()) } returns 0
every { Log.e(any<String>(), any<String>(), any()) } returns 0
mockWebServer = MockWebServer()
mockWebServer.start()
mockkObject(AuthManager)
every { AuthManager.wsUrl() } returns mockWebServer.url("/").toString().replace("http://", "ws://")
every { AuthManager.isAutoReconnect() } returns false
every { AuthManager.getSessionCookie() } returns null
every { AuthManager.serverStore } returns
mockk<com.m57.hermescontrol.data.config.ServerStore>().also {
every { it.getLatestState() } returns
com.m57.hermescontrol.data.config
.ServerStoreState()
}
CookieManager.setJarForTest(buildFakePersistentCookieJar())
mockkObject(DashboardSessionTokenRefresher)
coEvery { DashboardSessionTokenRefresher.refreshAsync() } returns null
every { DashboardSessionTokenRefresher.refresh() } returns null
HermesWsClient.disconnect(clearPendingMessages = true)
HermesWsClient.releaseExternalActivityConnectionLease()
HermesWsClient.releaseBackgroundConnectionLease()
HermesWsClient.setAppForeground(true)
AuthManager.resetAuthStateForTest()
}
@After
fun tearDown() {
AuthManager.resetAuthStateForTest()
HermesWsClient.releaseExternalActivityConnectionLease()
HermesWsClient.releaseBackgroundConnectionLease()
HermesWsClient.disconnect(clearPendingMessages = true)
runBlocking {
withTimeoutOrNull(5000) {
HermesWsClient.connectionStatus.first { it == ConnectionStatus.DISCONNECTED }
}
}
runCatching { mockWebServer.shutdown() }
unmockkAll()
}
private fun connectClient() {
HermesWsClient.connect()
runBlocking {
withTimeout(5000) { HermesWsClient.connectionStatus.first { it == ConnectionStatus.CONNECTED } }
}
}
@Test
fun typedCallSubscriptionChangeEncodesOnlyNonNullFieldsAndReturnsRawServerJsonUntouched() {
val opened = CountDownLatch(1)
val captured = CountDownLatch(1)
val frameRef = AtomicReference<JsonObject?>(null)
val serverResultJson =
buildJsonObject {
put("status", "ok")
put("subscription_id", "sub-12345")
put("scheduled_cancellation", false)
}
mockWebServer.enqueue(
MockResponse().withWebSocketUpgrade(
object : WebSocketListener() {
override fun onOpen(
webSocket: WebSocket,
response: Response,
) = opened.countDown()
override fun onMessage(
webSocket: WebSocket,
text: String,
) {
val json = OkHttpProvider.json.parseToJsonElement(text) as? JsonObject ?: return
val name = (json["method"] as? JsonPrimitive)?.content
if (name == "subscription.change") {
frameRef.set(json)
captured.countDown()
val id = (json["id"] as? JsonPrimitive)?.content ?: "1"
webSocket.send(
"""{"jsonrpc":"2.0","id":"$id","result":$serverResultJson}""",
)
}
}
},
),
)
connectClient()
assertTrue(opened.await(5, TimeUnit.SECONDS))
val result: JsonElement =
runBlocking {
HermesWsClient.call(
RpcMethods.SUBSCRIPTION_CHANGE,
SubscriptionChangeParams(
subscriptionTypeId = null,
cancel = false,
),
)
}
assertTrue("Frame must reach the server", captured.await(5, TimeUnit.SECONDS))
val frame = requireNotNull(frameRef.get())
assertFalse("Outgoing frames have NO jsonrpc field", frame.containsKey("jsonrpc"))
assertEquals("subscription.change", (frame["method"] as? JsonPrimitive)?.content)
val params = frame["params"] as? JsonObject
val expectedParams =
buildJsonObject {
put("cancel", false)
}
assertEquals(expectedParams, params)
assertEquals(false, (params?.get("cancel") as? JsonPrimitive)?.booleanOrNull)
assertFalse(params?.containsKey("subscription_type_id") ?: true)
assertEquals(serverResultJson, result)
}
@Test
fun typedCallVaultUnlockPutsNameAndPasswordOnWireAndReturnsRawServerJsonUntouched() {
val opened = CountDownLatch(1)
val captured = CountDownLatch(1)
val frameRef = AtomicReference<JsonObject?>(null)
val serverResultJson =
buildJsonObject {
put("unlocked", true)
put("expires_in", 3600)
}
mockWebServer.enqueue(
MockResponse().withWebSocketUpgrade(
object : WebSocketListener() {
override fun onOpen(
webSocket: WebSocket,
response: Response,
) = opened.countDown()
override fun onMessage(
webSocket: WebSocket,
text: String,
) {
val json = OkHttpProvider.json.parseToJsonElement(text) as? JsonObject ?: return
val name = (json["method"] as? JsonPrimitive)?.content
if (name == "vault.unlock") {
frameRef.set(json)
captured.countDown()
val id = (json["id"] as? JsonPrimitive)?.content ?: "1"
webSocket.send(
"""{"jsonrpc":"2.0","id":"$id","result":$serverResultJson}""",
)
}
}
},
),
)
connectClient()
assertTrue(opened.await(5, TimeUnit.SECONDS))
val result: JsonElement =
runBlocking {
HermesWsClient.call(
RpcMethods.VAULT_UNLOCK,
VaultUnlockParams(
name = "op-work",
password = "super-secret-pass",
),
)
}
assertTrue("Frame must reach the server", captured.await(5, TimeUnit.SECONDS))
val frame = requireNotNull(frameRef.get())
assertEquals("vault.unlock", (frame["method"] as? JsonPrimitive)?.content)
val params = frame["params"] as? JsonObject
val expectedParams =
buildJsonObject {
put("name", "op-work")
put("password", "super-secret-pass")
}
assertEquals(expectedParams, params)
assertEquals(serverResultJson, result)
}
@Test
fun typedCallVaultLockWithNamePutsNameOnWireAndReturnsRawServerJsonUntouched() {
val opened = CountDownLatch(1)
val captured = CountDownLatch(1)
val frameRef = AtomicReference<JsonObject?>(null)
val serverResultJson =
buildJsonObject {
put("locked", true)
put("vault", "op-work")
}
mockWebServer.enqueue(
MockResponse().withWebSocketUpgrade(
object : WebSocketListener() {
override fun onOpen(
webSocket: WebSocket,
response: Response,
) = opened.countDown()
override fun onMessage(
webSocket: WebSocket,
text: String,
) {
val json = OkHttpProvider.json.parseToJsonElement(text) as? JsonObject ?: return
val name = (json["method"] as? JsonPrimitive)?.content
if (name == "vault.lock") {
frameRef.set(json)
captured.countDown()
val id = (json["id"] as? JsonPrimitive)?.content ?: "1"
webSocket.send(
"""{"jsonrpc":"2.0","id":"$id","result":$serverResultJson}""",
)
}
}
},
),
)
connectClient()
assertTrue(opened.await(5, TimeUnit.SECONDS))
val result: JsonElement =
runBlocking {
HermesWsClient.call(
RpcMethods.VAULT_LOCK,
VaultLockParams(name = "op-work"),
)
}
assertTrue("Frame must reach the server", captured.await(5, TimeUnit.SECONDS))
val frame = requireNotNull(frameRef.get())
assertEquals("vault.lock", (frame["method"] as? JsonPrimitive)?.content)
val params = frame["params"] as? JsonObject
val expectedParams =
buildJsonObject {
put("name", "op-work")
}
assertEquals(expectedParams, params)
assertEquals(serverResultJson, result)
}
@Test
fun typedCallVaultLockWithoutNameLeavesParamsAbsentOrEmptyAndReturnsRawServerJsonUntouched() {
val opened = CountDownLatch(1)
val captured = CountDownLatch(1)
val frameRef = AtomicReference<JsonObject?>(null)
val serverResultJson =
buildJsonObject {
put("locked_all", true)
}
mockWebServer.enqueue(
MockResponse().withWebSocketUpgrade(
object : WebSocketListener() {
override fun onOpen(
webSocket: WebSocket,
response: Response,
) = opened.countDown()
override fun onMessage(
webSocket: WebSocket,
text: String,
) {
val json = OkHttpProvider.json.parseToJsonElement(text) as? JsonObject ?: return
val name = (json["method"] as? JsonPrimitive)?.content
if (name == "vault.lock") {
frameRef.set(json)
captured.countDown()
val id = (json["id"] as? JsonPrimitive)?.content ?: "1"
webSocket.send(
"""{"jsonrpc":"2.0","id":"$id","result":$serverResultJson}""",
)
}
}
},
),
)
connectClient()
assertTrue(opened.await(5, TimeUnit.SECONDS))
val result: JsonElement =
runBlocking {
HermesWsClient.call(
RpcMethods.VAULT_LOCK,
VaultLockParams(name = null),
)
}
assertTrue("Frame must reach the server", captured.await(5, TimeUnit.SECONDS))
val frame = requireNotNull(frameRef.get())
assertEquals("vault.lock", (frame["method"] as? JsonPrimitive)?.content)
val params = frame["params"] as? JsonObject
assertTrue(
"vault.lock with null name carries no params",
params == null || params.isEmpty(),
)
assertEquals(serverResultJson, result)
}
@Test
fun typedCallEmptyParamsMethodLeavesParamsAbsentOrEmptyAndReturnsRawServerJsonUntouched() {
val opened = CountDownLatch(1)
val captured = CountDownLatch(1)
val frameRef = AtomicReference<JsonObject?>(null)
val serverResultJson =
buildJsonObject {
put("status", "active")
put("tier", "standard")
put("valid_until", "2026-12-31T23:59:59Z")
}
mockWebServer.enqueue(
MockResponse().withWebSocketUpgrade(
object : WebSocketListener() {
override fun onOpen(
webSocket: WebSocket,
response: Response,
) = opened.countDown()
override fun onMessage(
webSocket: WebSocket,
text: String,
) {
val json = OkHttpProvider.json.parseToJsonElement(text) as? JsonObject ?: return
val name = (json["method"] as? JsonPrimitive)?.content
if (name == "subscription.state") {
frameRef.set(json)
captured.countDown()
val id = (json["id"] as? JsonPrimitive)?.content ?: "1"
webSocket.send(
"""{"jsonrpc":"2.0","id":"$id","result":$serverResultJson}""",
)
}
}
},
),
)
connectClient()
assertTrue(opened.await(5, TimeUnit.SECONDS))
val result: JsonElement =
runBlocking {
HermesWsClient.call(
RpcMethods.SUBSCRIPTION_STATE,
EmptyParams,
)
}
assertTrue("Frame must reach the server", captured.await(5, TimeUnit.SECONDS))
val frame = requireNotNull(frameRef.get())
assertEquals("subscription.state", (frame["method"] as? JsonPrimitive)?.content)
val params = frame["params"] as? JsonObject
assertTrue(
"subscription.state with EmptyParams carries no params",
params == null || params.isEmpty(),
)
assertEquals(serverResultJson, result)
}
}
@@ -325,12 +325,6 @@ class RawRpcParamsRatchetTest {
"data/ws/AccountConnectorRepository.kt::CONNECTORS_POLICY_GET",
"data/ws/AccountConnectorRepository.kt::CONNECTORS_POLICY_SET",
"data/ws/AccountConnectorRepository.kt::CONNECTORS_TOOLS",
"data/ws/BillingRepository.kt::SUBSCRIPTION_CHANGE",
"data/ws/BillingRepository.kt::SUBSCRIPTION_PREVIEW",
"data/ws/BillingRepository.kt::SUBSCRIPTION_RESUME",
"data/ws/BillingRepository.kt::SUBSCRIPTION_STATE",
"data/ws/BillingRepository.kt::SUBSCRIPTION_UPGRADE",
"data/ws/BillingRepository.kt::USAGE_BARS",
"data/ws/ConnectorRepository.kt::CONNECTORS_CONNECT",
"data/ws/ConnectorRepository.kt::CONNECTORS_LIST",
"data/ws/HermesWsClient.kt::CLIENT_CAPABILITIES",
@@ -341,11 +335,6 @@ class RawRpcParamsRatchetTest {
"data/ws/ProjectsSource.kt::PROJECTS_LIST",
"data/ws/SubagentRepository.kt::SUBAGENT_LIST",
"data/ws/SubagentRepository.kt::SUBAGENT_TAIL",
"data/ws/VaultRepository.kt::VAULT_LIST",
"data/ws/VaultRepository.kt::VAULT_LOCK",
"data/ws/VaultRepository.kt::VAULT_SOURCES",
"data/ws/VaultRepository.kt::VAULT_SOURCE_SET",
"data/ws/VaultRepository.kt::VAULT_UNLOCK",
"ui/bots/BotsViewModel.kt::PROFILES_CONFIGURE",
"ui/bots/BotsViewModel.kt::PROFILES_CONFIGURE",
"ui/bots/BotsViewModel.kt::PROFILES_CONFIGURE",
@@ -0,0 +1,333 @@
package com.m57.hermescontrol.data.ws.contract
import com.m57.hermescontrol.data.remote.OkHttpProvider
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.put
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
class BillingVaultTypesTest {
@Test
fun emptyParamsEncodesToEmptyJsonObject() {
val params = EmptyParams
val encoded = OkHttpProvider.json.encodeToJsonElement(EmptyParams.serializer(), params)
val expected = buildJsonObject {}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertTrue((encoded as JsonObject).isEmpty())
}
@Test
fun subscriptionPreviewParamsEncodesSubscriptionTypeIdWhenPresent() {
val params = SubscriptionPreviewParams(subscriptionTypeId = "pro-monthly")
val encoded = OkHttpProvider.json.encodeToJsonElement(SubscriptionPreviewParams.serializer(), params)
val expected =
buildJsonObject {
put("subscription_type_id", "pro-monthly")
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("subscription_type_id"), (encoded as JsonObject).keys)
}
@Test
fun subscriptionPreviewParamsOmitsNullSubscriptionTypeId() {
val params = SubscriptionPreviewParams(subscriptionTypeId = null)
val encoded = OkHttpProvider.json.encodeToJsonElement(SubscriptionPreviewParams.serializer(), params)
val expected = buildJsonObject {}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertTrue((encoded as JsonObject).isEmpty())
}
@Test
fun subscriptionChangeParamsEncodesAllFieldsWhenPresent() {
val params =
SubscriptionChangeParams(
subscriptionTypeId = "tier-2",
cancel = true,
)
val encoded = OkHttpProvider.json.encodeToJsonElement(SubscriptionChangeParams.serializer(), params)
val expected =
buildJsonObject {
put("subscription_type_id", "tier-2")
put("cancel", true)
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("subscription_type_id", "cancel"), (encoded as JsonObject).keys)
}
@Test
fun subscriptionChangeParamsEncodesExplicitFalseForCancel() {
val params =
SubscriptionChangeParams(
subscriptionTypeId = "tier-1",
cancel = false,
)
val encoded = OkHttpProvider.json.encodeToJsonElement(SubscriptionChangeParams.serializer(), params)
val expected =
buildJsonObject {
put("subscription_type_id", "tier-1")
put("cancel", false)
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("subscription_type_id", "cancel"), (encoded as JsonObject).keys)
}
@Test
fun subscriptionChangeParamsOmitsOnlyNullFields() {
val paramsOnlyCancel = SubscriptionChangeParams(subscriptionTypeId = null, cancel = false)
val encodedOnlyCancel =
OkHttpProvider.json.encodeToJsonElement(SubscriptionChangeParams.serializer(), paramsOnlyCancel)
val expectedOnlyCancel =
buildJsonObject {
put("cancel", false)
}
assertEquals(expectedOnlyCancel, encodedOnlyCancel)
assertTrue(encodedOnlyCancel is JsonObject)
assertEquals(setOf("cancel"), (encodedOnlyCancel as JsonObject).keys)
val paramsOnlyType = SubscriptionChangeParams(subscriptionTypeId = "tier-3", cancel = null)
val encodedOnlyType =
OkHttpProvider.json.encodeToJsonElement(SubscriptionChangeParams.serializer(), paramsOnlyType)
val expectedOnlyType =
buildJsonObject {
put("subscription_type_id", "tier-3")
}
assertEquals(expectedOnlyType, encodedOnlyType)
assertTrue(encodedOnlyType is JsonObject)
assertEquals(setOf("subscription_type_id"), (encodedOnlyType as JsonObject).keys)
val paramsEmpty = SubscriptionChangeParams(subscriptionTypeId = null, cancel = null)
val encodedEmpty =
OkHttpProvider.json.encodeToJsonElement(SubscriptionChangeParams.serializer(), paramsEmpty)
val expectedEmpty = buildJsonObject {}
assertEquals(expectedEmpty, encodedEmpty)
assertTrue(encodedEmpty is JsonObject)
assertTrue((encodedEmpty as JsonObject).isEmpty())
}
@Test
fun subscriptionUpgradeParamsEncodesSubscriptionTypeIdWhenPresent() {
val params = SubscriptionUpgradeParams(subscriptionTypeId = "enterprise-yearly")
val encoded = OkHttpProvider.json.encodeToJsonElement(SubscriptionUpgradeParams.serializer(), params)
val expected =
buildJsonObject {
put("subscription_type_id", "enterprise-yearly")
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("subscription_type_id"), (encoded as JsonObject).keys)
}
@Test
fun subscriptionUpgradeParamsOmitsNullSubscriptionTypeId() {
val params = SubscriptionUpgradeParams(subscriptionTypeId = null)
val encoded = OkHttpProvider.json.encodeToJsonElement(SubscriptionUpgradeParams.serializer(), params)
val expected = buildJsonObject {}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertTrue((encoded as JsonObject).isEmpty())
}
@Test
fun vaultSourceSetParamsEncodesAllFieldsWhenPresent() {
val params =
VaultSourceSetParams(
name = "1password",
enabled = true,
)
val encoded = OkHttpProvider.json.encodeToJsonElement(VaultSourceSetParams.serializer(), params)
val expected =
buildJsonObject {
put("name", "1password")
put("enabled", true)
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("name", "enabled"), (encoded as JsonObject).keys)
}
@Test
fun vaultSourceSetParamsEncodesExplicitFalseForEnabled() {
val params =
VaultSourceSetParams(
name = "bitwarden",
enabled = false,
)
val encoded = OkHttpProvider.json.encodeToJsonElement(VaultSourceSetParams.serializer(), params)
val expected =
buildJsonObject {
put("name", "bitwarden")
put("enabled", false)
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("name", "enabled"), (encoded as JsonObject).keys)
}
@Test
fun vaultSourceSetParamsOmitsNullFields() {
val params = VaultSourceSetParams(name = "keepass", enabled = null)
val encoded = OkHttpProvider.json.encodeToJsonElement(VaultSourceSetParams.serializer(), params)
val expected =
buildJsonObject {
put("name", "keepass")
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("name"), (encoded as JsonObject).keys)
val paramsEmpty = VaultSourceSetParams(name = null, enabled = null)
val encodedEmpty =
OkHttpProvider.json.encodeToJsonElement(VaultSourceSetParams.serializer(), paramsEmpty)
val expectedEmpty = buildJsonObject {}
assertEquals(expectedEmpty, encodedEmpty)
assertTrue(encodedEmpty is JsonObject)
assertTrue((encodedEmpty as JsonObject).isEmpty())
}
@Test
fun vaultUnlockParamsEncodesAllFieldsWhenPresent() {
val params =
VaultUnlockParams(
name = "local-vault",
password = "secret-password",
)
val encoded = OkHttpProvider.json.encodeToJsonElement(VaultUnlockParams.serializer(), params)
val expected =
buildJsonObject {
put("name", "local-vault")
put("password", "secret-password")
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("name", "password"), (encoded as JsonObject).keys)
}
@Test
fun vaultUnlockParamsOmitsNullFields() {
val params = VaultUnlockParams(name = "local-vault", password = null)
val encoded = OkHttpProvider.json.encodeToJsonElement(VaultUnlockParams.serializer(), params)
val expected =
buildJsonObject {
put("name", "local-vault")
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("name"), (encoded as JsonObject).keys)
val paramsEmpty = VaultUnlockParams(name = null, password = null)
val encodedEmpty =
OkHttpProvider.json.encodeToJsonElement(VaultUnlockParams.serializer(), paramsEmpty)
val expectedEmpty = buildJsonObject {}
assertEquals(expectedEmpty, encodedEmpty)
assertTrue(encodedEmpty is JsonObject)
assertTrue((encodedEmpty as JsonObject).isEmpty())
}
@Test
fun vaultLockParamsEncodesEmptyJsonObjectWhenNameNull() {
val params = VaultLockParams(name = null)
val encoded = OkHttpProvider.json.encodeToJsonElement(VaultLockParams.serializer(), params)
val expected = buildJsonObject {}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertTrue((encoded as JsonObject).isEmpty())
}
@Test
fun vaultLockParamsEncodesNameWhenSet() {
val params = VaultLockParams(name = "primary-vault")
val encoded = OkHttpProvider.json.encodeToJsonElement(VaultLockParams.serializer(), params)
val expected =
buildJsonObject {
put("name", "primary-vault")
}
assertEquals(expected, encoded)
assertTrue(encoded is JsonObject)
assertEquals(setOf("name"), (encoded as JsonObject).keys)
}
@Test
fun rpcMethodsRegistrationMatchesContract() {
assertEquals("subscription.state", RpcMethods.SUBSCRIPTION_STATE.name)
assertEquals("usage.bars", RpcMethods.USAGE_BARS.name)
assertEquals("subscription.resume", RpcMethods.SUBSCRIPTION_RESUME.name)
assertEquals("vault.list", RpcMethods.VAULT_LIST.name)
assertEquals("vault.sources", RpcMethods.VAULT_SOURCES.name)
assertEquals("subscription.preview", RpcMethods.SUBSCRIPTION_PREVIEW.name)
assertEquals("subscription.change", RpcMethods.SUBSCRIPTION_CHANGE.name)
assertEquals("subscription.upgrade", RpcMethods.SUBSCRIPTION_UPGRADE.name)
assertEquals("vault.source.set", RpcMethods.VAULT_SOURCE_SET.name)
assertEquals("vault.unlock", RpcMethods.VAULT_UNLOCK.name)
assertEquals("vault.lock", RpcMethods.VAULT_LOCK.name)
assertTrue(RpcMethods.all.contains(RpcMethods.SUBSCRIPTION_STATE))
assertTrue(RpcMethods.all.contains(RpcMethods.USAGE_BARS))
assertTrue(RpcMethods.all.contains(RpcMethods.SUBSCRIPTION_RESUME))
assertTrue(RpcMethods.all.contains(RpcMethods.VAULT_LIST))
assertTrue(RpcMethods.all.contains(RpcMethods.VAULT_SOURCES))
assertTrue(RpcMethods.all.contains(RpcMethods.SUBSCRIPTION_PREVIEW))
assertTrue(RpcMethods.all.contains(RpcMethods.SUBSCRIPTION_CHANGE))
assertTrue(RpcMethods.all.contains(RpcMethods.SUBSCRIPTION_UPGRADE))
assertTrue(RpcMethods.all.contains(RpcMethods.VAULT_SOURCE_SET))
assertTrue(RpcMethods.all.contains(RpcMethods.VAULT_UNLOCK))
assertTrue(RpcMethods.all.contains(RpcMethods.VAULT_LOCK))
}
@Test
fun jsonElementPassthroughMethodsDecodeResultUntouched() {
val arbitraryPayload =
buildJsonObject {
put("tier", "pro")
put("credits", 4200)
put("details", buildJsonObject { put("active", true) })
}
val methods =
listOf(
RpcMethods.SUBSCRIPTION_STATE,
RpcMethods.USAGE_BARS,
RpcMethods.SUBSCRIPTION_RESUME,
RpcMethods.VAULT_LIST,
RpcMethods.VAULT_SOURCES,
RpcMethods.SUBSCRIPTION_PREVIEW,
RpcMethods.SUBSCRIPTION_CHANGE,
RpcMethods.SUBSCRIPTION_UPGRADE,
RpcMethods.VAULT_SOURCE_SET,
RpcMethods.VAULT_UNLOCK,
RpcMethods.VAULT_LOCK,
)
for (method in methods) {
val decoded: JsonElement =
OkHttpProvider.json.decodeFromJsonElement(
method.result,
arbitraryPayload,
)
assertEquals("Method ${method.name} must pass raw result untouched", arbitraryPayload, decoded)
}
}
}