10 files changed
+1286
-149
No files matched your search
@@ -28,7 +28,7 @@ class AccountConnectorRepositoryTest {
|
||||
runTest {
|
||||
val calls = mutableListOf<Pair<String, Map<String, Any>>>()
|
||||
val repo =
|
||||
HermesAccountConnectorRepository { method, params ->
|
||||
accountRepo { method, params ->
|
||||
calls += method to params
|
||||
operationFixture()
|
||||
}
|
||||
@@ -57,7 +57,7 @@ class AccountConnectorRepositoryTest {
|
||||
runTest {
|
||||
val calls = mutableListOf<Pair<String, Map<String, Any>>>()
|
||||
val repo =
|
||||
HermesAccountConnectorRepository { method, params ->
|
||||
accountRepo { method, params ->
|
||||
calls += method to params
|
||||
operationFixture()
|
||||
}
|
||||
@@ -92,7 +92,7 @@ class AccountConnectorRepositoryTest {
|
||||
runTest {
|
||||
val calls = mutableListOf<Pair<String, Map<String, Any>>>()
|
||||
val repo =
|
||||
HermesAccountConnectorRepository { method, params ->
|
||||
accountRepo { method, params ->
|
||||
calls += method to params
|
||||
when (method) {
|
||||
WsMethods.CONNECTORS_CATALOG -> {
|
||||
@@ -165,7 +165,7 @@ class AccountConnectorRepositoryTest {
|
||||
|
||||
@Test fun `policy keeps member revision separate from effective and respects inherited rules`() =
|
||||
runTest {
|
||||
val repo = HermesAccountConnectorRepository { _, _ -> policyFixture() }
|
||||
val repo = accountRepo { _, _ -> policyFixture() }
|
||||
val policy = (repo.policy() as AccountConnectorResult.Success).value
|
||||
assertEquals("effective-revision", policy.revision)
|
||||
assertEquals("01ARZ3NDEKTSV4RRFFQ69G5FAV", policy.member?.revision)
|
||||
@@ -180,7 +180,7 @@ class AccountConnectorRepositoryTest {
|
||||
runTest {
|
||||
val calls = mutableListOf<Pair<String, Map<String, Any>>>()
|
||||
val repo =
|
||||
HermesAccountConnectorRepository { method, params ->
|
||||
accountRepo { method, params ->
|
||||
calls += method to params
|
||||
if (method == WsMethods.CONNECTORS_POLICY_GET) {
|
||||
policyFixture()
|
||||
@@ -208,10 +208,13 @@ class AccountConnectorRepositoryTest {
|
||||
|
||||
@Test fun `malformed authorization does not look like a successful connect`() =
|
||||
runTest {
|
||||
val repo = HermesAccountConnectorRepository { _, _ -> mapOf("status" to "initiated") }
|
||||
val repo = accountRepo { _, _ -> mapOf("status" to "initiated") }
|
||||
assertTrue(repo.connect(listOf("drive")) is AccountConnectorResult.Failure)
|
||||
}
|
||||
|
||||
private fun accountRepo(handler: suspend (String, Map<String, Any>) -> Any?) =
|
||||
HermesAccountConnectorRepository(rpc = handler, caller = fakeCaller(handler))
|
||||
|
||||
private fun operationFixture() =
|
||||
mapOf(
|
||||
"op_id" to "op-a",
|
||||
|
||||
@@ -34,11 +34,12 @@ class ConnectorRepositoryTest {
|
||||
|
||||
val repo =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { method, params ->
|
||||
recordedMethod = method
|
||||
recordedParams = params
|
||||
mapOf("available" to true, "connectors" to emptyList<Map<String, Any>>())
|
||||
},
|
||||
caller =
|
||||
fakeCaller { method, params ->
|
||||
recordedMethod = method
|
||||
recordedParams = params
|
||||
mapOf("available" to true, "connectors" to emptyList<Map<String, Any>>())
|
||||
},
|
||||
)
|
||||
|
||||
val result = repo.listConnectors("sess-abc-123")
|
||||
@@ -61,17 +62,18 @@ class ConnectorRepositoryTest {
|
||||
|
||||
val repo =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { method, params ->
|
||||
recordedMethod = method
|
||||
recordedParams = params
|
||||
mapOf(
|
||||
"results" to
|
||||
listOf(
|
||||
mapOf("connector" to "linear", "status" to "initiated"),
|
||||
),
|
||||
"summary" to mapOf("total" to 1, "initiated" to 1),
|
||||
)
|
||||
},
|
||||
caller =
|
||||
fakeCaller { method, params ->
|
||||
recordedMethod = method
|
||||
recordedParams = params
|
||||
mapOf(
|
||||
"results" to
|
||||
listOf(
|
||||
mapOf("connector" to "linear", "status" to "initiated"),
|
||||
),
|
||||
"summary" to mapOf("total" to 1, "initiated" to 1),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
val result =
|
||||
@@ -103,16 +105,17 @@ class ConnectorRepositoryTest {
|
||||
|
||||
val repo =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, params ->
|
||||
recordedParams = params
|
||||
mapOf(
|
||||
"results" to
|
||||
listOf(
|
||||
mapOf("connector" to "slack", "status" to "active"),
|
||||
),
|
||||
"summary" to mapOf("total" to 1, "active" to 1),
|
||||
)
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, params ->
|
||||
recordedParams = params
|
||||
mapOf(
|
||||
"results" to
|
||||
listOf(
|
||||
mapOf("connector" to "slack", "status" to "active"),
|
||||
),
|
||||
"summary" to mapOf("total" to 1, "active" to 1),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
repo.connect(sessionId = "sess-789", connectors = listOf("slack"))
|
||||
@@ -125,10 +128,11 @@ class ConnectorRepositoryTest {
|
||||
var rpcCalled = false
|
||||
val repo =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
rpcCalled = true
|
||||
null
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
rpcCalled = true
|
||||
null
|
||||
},
|
||||
)
|
||||
|
||||
val r1 = repo.listConnectors("")
|
||||
@@ -147,10 +151,11 @@ class ConnectorRepositoryTest {
|
||||
var rpcCalled = false
|
||||
val repo =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
rpcCalled = true
|
||||
null
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
rpcCalled = true
|
||||
null
|
||||
},
|
||||
)
|
||||
|
||||
// Blank session_id
|
||||
@@ -172,10 +177,11 @@ class ConnectorRepositoryTest {
|
||||
var rpcCalled = false
|
||||
val repo =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
rpcCalled = true
|
||||
null
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
rpcCalled = true
|
||||
null
|
||||
},
|
||||
)
|
||||
|
||||
// Invalid slugs: uppercase, starting with hyphen/underscore, containing spaces/symbols
|
||||
@@ -210,9 +216,10 @@ class ConnectorRepositoryTest {
|
||||
runBlocking {
|
||||
val repo =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
throw CancellationException("coroutine cancelled")
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
throw CancellationException("coroutine cancelled")
|
||||
},
|
||||
)
|
||||
|
||||
try {
|
||||
@@ -236,13 +243,14 @@ class ConnectorRepositoryTest {
|
||||
// 4031 CONNECTORS_UNAVAILABLE
|
||||
val repo4031 =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Connectors unavailable",
|
||||
code = 4031,
|
||||
data = JsonObject(mapOf("reason" to JsonPrimitive("CONNECTORS_UNAVAILABLE"))),
|
||||
)
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Connectors unavailable",
|
||||
code = 4031,
|
||||
data = JsonObject(mapOf("reason" to JsonPrimitive("CONNECTORS_UNAVAILABLE"))),
|
||||
)
|
||||
},
|
||||
)
|
||||
val r4031 = repo4031.listConnectors("sess-1")
|
||||
assertTrue(r4031 is ConnectorListResult.Error)
|
||||
@@ -251,13 +259,14 @@ class ConnectorRepositoryTest {
|
||||
// 4001 NOT_OWNER
|
||||
val repo4001 =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Session not owned",
|
||||
code = 4001,
|
||||
data = JsonObject(mapOf("reason" to JsonPrimitive("NOT_OWNER"))),
|
||||
)
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Session not owned",
|
||||
code = 4001,
|
||||
data = JsonObject(mapOf("reason" to JsonPrimitive("NOT_OWNER"))),
|
||||
)
|
||||
},
|
||||
)
|
||||
val r4001 = repo4001.connect("sess-1", listOf("linear"))
|
||||
assertTrue(r4001 is ConnectorConnectResult.Error)
|
||||
@@ -266,13 +275,14 @@ class ConnectorRepositoryTest {
|
||||
// 5033 UNSUPPORTED_RUNTIME
|
||||
val repo5033 =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Compute host required",
|
||||
code = 5033,
|
||||
data = JsonObject(mapOf("reason" to JsonPrimitive("UNSUPPORTED_RUNTIME"))),
|
||||
)
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Compute host required",
|
||||
code = 5033,
|
||||
data = JsonObject(mapOf("reason" to JsonPrimitive("UNSUPPORTED_RUNTIME"))),
|
||||
)
|
||||
},
|
||||
)
|
||||
val r5033 = repo5033.connect("sess-1", listOf("linear"))
|
||||
assertTrue(r5033 is ConnectorConnectResult.Error)
|
||||
@@ -281,13 +291,14 @@ class ConnectorRepositoryTest {
|
||||
// 5034 INVALID_CONNECTOR_RESPONSE
|
||||
val repo5034 =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Invalid connector response",
|
||||
code = 5034,
|
||||
data = JsonObject(mapOf("reason" to JsonPrimitive("INVALID_CONNECTOR_RESPONSE"))),
|
||||
)
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Invalid connector response",
|
||||
code = 5034,
|
||||
data = JsonObject(mapOf("reason" to JsonPrimitive("INVALID_CONNECTOR_RESPONSE"))),
|
||||
)
|
||||
},
|
||||
)
|
||||
val r5034 = repo5034.connect("sess-1", listOf("linear"))
|
||||
assertTrue(r5034 is ConnectorConnectResult.Error)
|
||||
@@ -296,13 +307,14 @@ class ConnectorRepositoryTest {
|
||||
// -32601 Unsupported backend
|
||||
val repo32601 =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Method not found",
|
||||
code = -32601,
|
||||
data = null,
|
||||
)
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
throw HermesWsClient.HermesRpcException(
|
||||
message = "Method not found",
|
||||
code = -32601,
|
||||
data = null,
|
||||
)
|
||||
},
|
||||
)
|
||||
val r32601 = repo32601.listConnectors("sess-1")
|
||||
assertTrue(r32601 is ConnectorListResult.Error)
|
||||
@@ -314,9 +326,10 @@ class ConnectorRepositoryTest {
|
||||
runBlocking {
|
||||
val repo =
|
||||
HermesConnectorRepository(
|
||||
rpcRequest = { _, _ ->
|
||||
throw java.io.IOException("Connection reset by peer")
|
||||
},
|
||||
caller =
|
||||
fakeCaller { _, _ ->
|
||||
throw java.io.IOException("Connection reset by peer")
|
||||
},
|
||||
)
|
||||
|
||||
val rList = repo.listConnectors("sess-1")
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.m57.hermescontrol.data.ws
|
||||
|
||||
import com.m57.hermescontrol.data.remote.OkHttpProvider
|
||||
import com.m57.hermescontrol.data.ws.contract.RpcMethod
|
||||
import com.m57.hermescontrol.data.ws.contract.TypedRpcCaller
|
||||
|
||||
/**
|
||||
* Test double for [TypedRpcCaller]: encodes the typed params exactly as the wire would, hands the
|
||||
* resulting map to [handler] together with the method name, and returns its value as a JsonElement.
|
||||
*/
|
||||
internal fun fakeCaller(handler: suspend (String, Map<String, Any>) -> Any?): TypedRpcCaller =
|
||||
object : TypedRpcCaller {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <P, R> call(
|
||||
method: RpcMethod<P, R>,
|
||||
params: P,
|
||||
): R {
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(method.params, params)
|
||||
val map = (encoded.toAny() as? Map<String, Any>).orEmpty()
|
||||
return ConnectorParser.toJsonElement(handler(method.name, map)) as R
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
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.ConnectorOwner
|
||||
import com.m57.hermescontrol.data.ws.contract.ConnectorsConnectParams
|
||||
import com.m57.hermescontrol.data.ws.contract.ConnectorsListParams
|
||||
import com.m57.hermescontrol.data.ws.contract.ConnectorsPolicySetParams
|
||||
import com.m57.hermescontrol.data.ws.contract.HermesRpcCaller
|
||||
import com.m57.hermescontrol.data.ws.contract.RpcMethods
|
||||
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.buildJsonArray
|
||||
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 HermesWsClientConnectorsTest {
|
||||
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 typedCallConnectorsConnectEncodesOwnerAccountReconnectTrueAndReturnsRawServerJsonUntouched() {
|
||||
val opened = CountDownLatch(1)
|
||||
val captured = CountDownLatch(1)
|
||||
val frameRef = AtomicReference<JsonObject?>(null)
|
||||
|
||||
val serverResultJson =
|
||||
buildJsonObject {
|
||||
put("op_id", "op-connect-123")
|
||||
put("status", "running")
|
||||
}
|
||||
|
||||
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 == "connectors.connect") {
|
||||
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.CONNECTORS_CONNECT,
|
||||
ConnectorsConnectParams(
|
||||
owner = ConnectorOwner.account(),
|
||||
connectors = listOf("slack", "github"),
|
||||
reconnect = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
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("connectors.connect", (frame["method"] as? JsonPrimitive)?.content)
|
||||
|
||||
val params = frame["params"] as? JsonObject
|
||||
val expectedParams =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"owner",
|
||||
buildJsonObject {
|
||||
put("type", "account")
|
||||
},
|
||||
)
|
||||
put(
|
||||
"connectors",
|
||||
buildJsonArray {
|
||||
add(JsonPrimitive("slack"))
|
||||
add(JsonPrimitive("github"))
|
||||
},
|
||||
)
|
||||
put("reconnect", true)
|
||||
}
|
||||
assertEquals(expectedParams, params)
|
||||
assertEquals(true, (params?.get("reconnect") as? JsonPrimitive)?.booleanOrNull)
|
||||
assertFalse(params?.containsKey("profile") ?: true)
|
||||
assertEquals(serverResultJson, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun typedCallConnectorsPolicySetEncodesNestedChangeWithArrayAndReturnsRawServerJsonUntouched() {
|
||||
val opened = CountDownLatch(1)
|
||||
val captured = CountDownLatch(1)
|
||||
val frameRef = AtomicReference<JsonObject?>(null)
|
||||
|
||||
val serverResultJson =
|
||||
buildJsonObject {
|
||||
put("revision", 5)
|
||||
put("applied", 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 == "connectors.policy.set") {
|
||||
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 nestedChange =
|
||||
buildJsonObject {
|
||||
put("policy", "whitelist")
|
||||
put(
|
||||
"allowed_connectors",
|
||||
buildJsonArray {
|
||||
add(JsonPrimitive("notion"))
|
||||
add(JsonPrimitive("linear"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"rules",
|
||||
buildJsonObject {
|
||||
put("require_auth", true)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
val result: JsonElement =
|
||||
runBlocking {
|
||||
HermesWsClient.call(
|
||||
RpcMethods.CONNECTORS_POLICY_SET,
|
||||
ConnectorsPolicySetParams(
|
||||
change = nestedChange,
|
||||
expectedRevision = "4",
|
||||
profile = "team-profile",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
assertTrue("Frame must reach the server", captured.await(5, TimeUnit.SECONDS))
|
||||
val frame = requireNotNull(frameRef.get())
|
||||
|
||||
assertEquals("connectors.policy.set", (frame["method"] as? JsonPrimitive)?.content)
|
||||
|
||||
val params = frame["params"] as? JsonObject
|
||||
val expectedParams =
|
||||
buildJsonObject {
|
||||
put("change", nestedChange)
|
||||
put("expected_revision", "4")
|
||||
put("profile", "team-profile")
|
||||
}
|
||||
assertEquals(expectedParams, params)
|
||||
assertEquals(nestedChange, params?.get("change"))
|
||||
assertEquals(serverResultJson, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hermesRpcCallerCallDelegatesToHermesWsClientCallAndEncodesFrameParamsUntouched() {
|
||||
val opened = CountDownLatch(1)
|
||||
val captured = CountDownLatch(1)
|
||||
val frameRef = AtomicReference<JsonObject?>(null)
|
||||
|
||||
val serverResultJson =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"connectors",
|
||||
buildJsonArray {
|
||||
add(
|
||||
buildJsonObject {
|
||||
put("id", "c1")
|
||||
put("status", "connected")
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
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 == "connectors.list") {
|
||||
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 {
|
||||
HermesRpcCaller.call(
|
||||
RpcMethods.CONNECTORS_LIST,
|
||||
ConnectorsListParams(
|
||||
owner = ConnectorOwner.session("s1"),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
assertTrue("Frame must reach the server", captured.await(5, TimeUnit.SECONDS))
|
||||
val frame = requireNotNull(frameRef.get())
|
||||
|
||||
assertEquals("connectors.list", (frame["method"] as? JsonPrimitive)?.content)
|
||||
|
||||
val params = frame["params"] as? JsonObject
|
||||
val expectedParams =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"owner",
|
||||
buildJsonObject {
|
||||
put("type", "session")
|
||||
put("session_id", "s1")
|
||||
},
|
||||
)
|
||||
}
|
||||
assertEquals(expectedParams, params)
|
||||
assertEquals(serverResultJson, result)
|
||||
}
|
||||
}
|
||||
@@ -316,17 +316,6 @@ class RawRpcParamsRatchetTest {
|
||||
*/
|
||||
val BASELINE: List<String> =
|
||||
listOf(
|
||||
"data/ws/AccountConnectorRepository.kt::CONNECTORS_ACCOUNTS",
|
||||
"data/ws/AccountConnectorRepository.kt::CONNECTORS_ACCOUNTS_REMOVE",
|
||||
"data/ws/AccountConnectorRepository.kt::CONNECTORS_CATALOG",
|
||||
"data/ws/AccountConnectorRepository.kt::CONNECTORS_CONNECT",
|
||||
"data/ws/AccountConnectorRepository.kt::CONNECTORS_LIST",
|
||||
"data/ws/AccountConnectorRepository.kt::CONNECTORS_OPERATION_STATUS",
|
||||
"data/ws/AccountConnectorRepository.kt::CONNECTORS_POLICY_GET",
|
||||
"data/ws/AccountConnectorRepository.kt::CONNECTORS_POLICY_SET",
|
||||
"data/ws/AccountConnectorRepository.kt::CONNECTORS_TOOLS",
|
||||
"data/ws/ConnectorRepository.kt::CONNECTORS_CONNECT",
|
||||
"data/ws/ConnectorRepository.kt::CONNECTORS_LIST",
|
||||
"data/ws/HermesWsClient.kt::CLIENT_CAPABILITIES",
|
||||
"data/ws/ModelOptionsRepository.kt::MODEL_OPTIONS",
|
||||
"data/ws/PluginManageRepository.kt::PLUGINS_MANAGE",
|
||||
|
||||
@@ -0,0 +1,539 @@
|
||||
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.JsonPrimitive
|
||||
import kotlinx.serialization.json.buildJsonArray
|
||||
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.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class ConnectorsTypesTest {
|
||||
@Test
|
||||
fun connectorOwnerAccountEncodesToTypeAccountWithoutSessionId() {
|
||||
val owner = ConnectorOwner.account()
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorOwner.serializer(), owner)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("type", "account")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("type"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorOwnerSessionEncodesToTypeSessionAndSessionId() {
|
||||
val owner = ConnectorOwner.session("s1")
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorOwner.serializer(), owner)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("type", "session")
|
||||
put("session_id", "s1")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("type", "session_id"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsListParamsEncodesOwnerAndProfileWhenProfileProvided() {
|
||||
val params = ConnectorsListParams(owner = ConnectorOwner.account(), profile = "work")
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsListParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"owner",
|
||||
buildJsonObject {
|
||||
put("type", "account")
|
||||
},
|
||||
)
|
||||
put("profile", "work")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("owner", "profile"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsListParamsOmitsProfileWhenNull() {
|
||||
val params = ConnectorsListParams(owner = ConnectorOwner.session("s1"), profile = null)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsListParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"owner",
|
||||
buildJsonObject {
|
||||
put("type", "session")
|
||||
put("session_id", "s1")
|
||||
},
|
||||
)
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("owner"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsConnectParamsEncodesAllFieldsWhenPresent() {
|
||||
val params =
|
||||
ConnectorsConnectParams(
|
||||
owner = ConnectorOwner.account(),
|
||||
connectors = listOf("slack", "github"),
|
||||
reconnect = true,
|
||||
profile = "personal",
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsConnectParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"owner",
|
||||
buildJsonObject {
|
||||
put("type", "account")
|
||||
},
|
||||
)
|
||||
put(
|
||||
"connectors",
|
||||
buildJsonArray {
|
||||
add(JsonPrimitive("slack"))
|
||||
add(JsonPrimitive("github"))
|
||||
},
|
||||
)
|
||||
put("reconnect", true)
|
||||
put("profile", "personal")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("owner", "connectors", "reconnect", "profile"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsConnectParamsEncodesExplicitFalseForReconnect() {
|
||||
val params =
|
||||
ConnectorsConnectParams(
|
||||
owner = ConnectorOwner.session("s2"),
|
||||
connectors = listOf("jira"),
|
||||
reconnect = false,
|
||||
profile = null,
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsConnectParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"owner",
|
||||
buildJsonObject {
|
||||
put("type", "session")
|
||||
put("session_id", "s2")
|
||||
},
|
||||
)
|
||||
put(
|
||||
"connectors",
|
||||
buildJsonArray {
|
||||
add(JsonPrimitive("jira"))
|
||||
},
|
||||
)
|
||||
put("reconnect", false)
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("owner", "connectors", "reconnect"), (encoded as JsonObject).keys)
|
||||
assertFalse((encoded as JsonObject).containsKey("profile"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsConnectParamsOmitsNullReconnectAndProfile() {
|
||||
val params =
|
||||
ConnectorsConnectParams(
|
||||
owner = ConnectorOwner.account(),
|
||||
connectors = emptyList(),
|
||||
reconnect = null,
|
||||
profile = null,
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsConnectParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"owner",
|
||||
buildJsonObject {
|
||||
put("type", "account")
|
||||
},
|
||||
)
|
||||
put("connectors", buildJsonArray {})
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("owner", "connectors"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsOperationStatusParamsEncodesAllFieldsWhenPresent() {
|
||||
val params =
|
||||
ConnectorsOperationStatusParams(
|
||||
owner = ConnectorOwner.session("sess-1"),
|
||||
opId = "op-99",
|
||||
profile = "work",
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsOperationStatusParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"owner",
|
||||
buildJsonObject {
|
||||
put("type", "session")
|
||||
put("session_id", "sess-1")
|
||||
},
|
||||
)
|
||||
put("op_id", "op-99")
|
||||
put("profile", "work")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("owner", "op_id", "profile"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsOperationStatusParamsOmitsNullProfile() {
|
||||
val params =
|
||||
ConnectorsOperationStatusParams(
|
||||
owner = ConnectorOwner.account(),
|
||||
opId = "op-100",
|
||||
profile = null,
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsOperationStatusParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put(
|
||||
"owner",
|
||||
buildJsonObject {
|
||||
put("type", "account")
|
||||
},
|
||||
)
|
||||
put("op_id", "op-100")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("owner", "op_id"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsCatalogParamsEncodesProfileWhenPresent() {
|
||||
val params = ConnectorsCatalogParams(profile = "default")
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsCatalogParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("profile", "default")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("profile"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsCatalogParamsOmitsNullProfileResultingInEmptyJsonObject() {
|
||||
val params = ConnectorsCatalogParams(profile = null)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsCatalogParams.serializer(), params)
|
||||
|
||||
val expected = buildJsonObject {}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertTrue((encoded as JsonObject).isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsAccountsParamsEncodesAllFieldsWhenPresent() {
|
||||
val params = ConnectorsAccountsParams(connector = "google", profile = "work")
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsAccountsParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("connector", "google")
|
||||
put("profile", "work")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("connector", "profile"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsAccountsParamsOmitsNullFieldsResultingInEmptyJsonObject() {
|
||||
val params = ConnectorsAccountsParams(connector = null, profile = null)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsAccountsParams.serializer(), params)
|
||||
|
||||
val expected = buildJsonObject {}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertTrue((encoded as JsonObject).isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsAccountsParamsEncodesConnectorOnlyWhenProfileNull() {
|
||||
val params = ConnectorsAccountsParams(connector = "github", profile = null)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsAccountsParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("connector", "github")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("connector"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsAccountsRemoveParamsEncodesConnectionIdAndProfile() {
|
||||
val params = ConnectorsAccountsRemoveParams(connectionId = "conn-123", profile = "work")
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsAccountsRemoveParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("connection_id", "conn-123")
|
||||
put("profile", "work")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("connection_id", "profile"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsAccountsRemoveParamsOmitsNullProfile() {
|
||||
val params = ConnectorsAccountsRemoveParams(connectionId = "conn-456", profile = null)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsAccountsRemoveParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("connection_id", "conn-456")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("connection_id"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsPolicyGetParamsEncodesProfileWhenPresent() {
|
||||
val params = ConnectorsPolicyGetParams(profile = "custom-profile")
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsPolicyGetParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("profile", "custom-profile")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("profile"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsPolicyGetParamsOmitsNullProfileResultingInEmptyJsonObject() {
|
||||
val params = ConnectorsPolicyGetParams(profile = null)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsPolicyGetParams.serializer(), params)
|
||||
|
||||
val expected = buildJsonObject {}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertTrue((encoded as JsonObject).isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsPolicySetParamsEncodesNestedChangeWithArraysUntouched() {
|
||||
val nestedChange =
|
||||
buildJsonObject {
|
||||
put("action", "allow")
|
||||
put(
|
||||
"tools",
|
||||
buildJsonArray {
|
||||
add(JsonPrimitive("gmail.send"))
|
||||
add(JsonPrimitive("gmail.list"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"scope",
|
||||
buildJsonObject {
|
||||
put("level", "read-write")
|
||||
put(
|
||||
"allowed_users",
|
||||
buildJsonArray {
|
||||
add(JsonPrimitive("alice"))
|
||||
add(JsonPrimitive("bob"))
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
val params =
|
||||
ConnectorsPolicySetParams(
|
||||
change = nestedChange,
|
||||
expectedRevision = "4",
|
||||
profile = "work",
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsPolicySetParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("change", nestedChange)
|
||||
put("expected_revision", "4")
|
||||
put("profile", "work")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("change", "expected_revision", "profile"), (encoded as JsonObject).keys)
|
||||
assertEquals(nestedChange, (encoded as JsonObject)["change"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsPolicySetParamsOmitsNullProfile() {
|
||||
val change = buildJsonObject { put("enabled", true) }
|
||||
val params =
|
||||
ConnectorsPolicySetParams(
|
||||
change = change,
|
||||
expectedRevision = "1",
|
||||
profile = null,
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsPolicySetParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("change", change)
|
||||
put("expected_revision", "1")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("change", "expected_revision"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsToolsParamsEncodesAllFieldsWhenPresent() {
|
||||
val params =
|
||||
ConnectorsToolsParams(
|
||||
slug = "gmail",
|
||||
refresh = true,
|
||||
profile = "work",
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsToolsParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("slug", "gmail")
|
||||
put("refresh", true)
|
||||
put("profile", "work")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("slug", "refresh", "profile"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsToolsParamsEncodesExplicitFalseForRefresh() {
|
||||
val params =
|
||||
ConnectorsToolsParams(
|
||||
slug = "slack",
|
||||
refresh = false,
|
||||
profile = null,
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsToolsParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("slug", "slack")
|
||||
put("refresh", false)
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("slug", "refresh"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectorsToolsParamsOmitsNullRefreshAndProfile() {
|
||||
val params =
|
||||
ConnectorsToolsParams(
|
||||
slug = "github",
|
||||
refresh = null,
|
||||
profile = null,
|
||||
)
|
||||
val encoded = OkHttpProvider.json.encodeToJsonElement(ConnectorsToolsParams.serializer(), params)
|
||||
|
||||
val expected =
|
||||
buildJsonObject {
|
||||
put("slug", "github")
|
||||
}
|
||||
assertEquals(expected, encoded)
|
||||
assertTrue(encoded is JsonObject)
|
||||
assertEquals(setOf("slug"), (encoded as JsonObject).keys)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rpcMethodsRegistrationMatchesContract() {
|
||||
assertEquals("connectors.list", RpcMethods.CONNECTORS_LIST.name)
|
||||
assertEquals("connectors.connect", RpcMethods.CONNECTORS_CONNECT.name)
|
||||
assertEquals("connectors.operation.status", RpcMethods.CONNECTORS_OPERATION_STATUS.name)
|
||||
assertEquals("connectors.catalog", RpcMethods.CONNECTORS_CATALOG.name)
|
||||
assertEquals("connectors.accounts", RpcMethods.CONNECTORS_ACCOUNTS.name)
|
||||
assertEquals("connectors.accounts.remove", RpcMethods.CONNECTORS_ACCOUNTS_REMOVE.name)
|
||||
assertEquals("connectors.policy.get", RpcMethods.CONNECTORS_POLICY_GET.name)
|
||||
assertEquals("connectors.policy.set", RpcMethods.CONNECTORS_POLICY_SET.name)
|
||||
assertEquals("connectors.tools", RpcMethods.CONNECTORS_TOOLS.name)
|
||||
|
||||
assertTrue(RpcMethods.all.contains(RpcMethods.CONNECTORS_LIST))
|
||||
assertTrue(RpcMethods.all.contains(RpcMethods.CONNECTORS_CONNECT))
|
||||
assertTrue(RpcMethods.all.contains(RpcMethods.CONNECTORS_OPERATION_STATUS))
|
||||
assertTrue(RpcMethods.all.contains(RpcMethods.CONNECTORS_CATALOG))
|
||||
assertTrue(RpcMethods.all.contains(RpcMethods.CONNECTORS_ACCOUNTS))
|
||||
assertTrue(RpcMethods.all.contains(RpcMethods.CONNECTORS_ACCOUNTS_REMOVE))
|
||||
assertTrue(RpcMethods.all.contains(RpcMethods.CONNECTORS_POLICY_GET))
|
||||
assertTrue(RpcMethods.all.contains(RpcMethods.CONNECTORS_POLICY_SET))
|
||||
assertTrue(RpcMethods.all.contains(RpcMethods.CONNECTORS_TOOLS))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jsonElementPassthroughMethodsDecodeResultUntouched() {
|
||||
val arbitraryPayload =
|
||||
buildJsonObject {
|
||||
put("status", "ok")
|
||||
put(
|
||||
"items",
|
||||
buildJsonArray {
|
||||
add(JsonPrimitive("elem1"))
|
||||
add(JsonPrimitive("elem2"))
|
||||
},
|
||||
)
|
||||
put("nested", buildJsonObject { put("revision", 10) })
|
||||
}
|
||||
|
||||
val methods =
|
||||
listOf(
|
||||
RpcMethods.CONNECTORS_LIST,
|
||||
RpcMethods.CONNECTORS_CONNECT,
|
||||
RpcMethods.CONNECTORS_OPERATION_STATUS,
|
||||
RpcMethods.CONNECTORS_CATALOG,
|
||||
RpcMethods.CONNECTORS_ACCOUNTS,
|
||||
RpcMethods.CONNECTORS_ACCOUNTS_REMOVE,
|
||||
RpcMethods.CONNECTORS_POLICY_GET,
|
||||
RpcMethods.CONNECTORS_POLICY_SET,
|
||||
RpcMethods.CONNECTORS_TOOLS,
|
||||
)
|
||||
|
||||
for (method in methods) {
|
||||
val decoded: JsonElement =
|
||||
OkHttpProvider.json.decodeFromJsonElement(
|
||||
method.result,
|
||||
arbitraryPayload,
|
||||
)
|
||||
assertEquals("Method " + method.name + " must pass raw result untouched", arbitraryPayload, decoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user