diff --git a/.buildsystem/deploy-github.sh b/.buildsystem/deploy-github.sh index 9d96df437..2980e730e 100755 --- a/.buildsystem/deploy-github.sh +++ b/.buildsystem/deploy-github.sh @@ -16,19 +16,12 @@ if [ -z "$GPG_PASSPHRASE" ]; then exit 1 fi -ATASK="" -DTASK="" -for i in ":adam" ":android-junit4" ":android-testrunner-contract"; do - ATASK="$ATASK $i:assemble" - DTASK="$DTASK $i:publishDefaultPublicationToGitHubRepository" -done - if [ -n "$GIT_TAG_NAME" ]; then echo "on a tag -> deploy release version $GIT_TAG_NAME" - ./gradlew $ATASK -PreleaseMode=RELEASE - ./gradlew $DTASK -PreleaseMode=RELEASE + ./gradlew assemble -PreleaseMode=RELEASE + ./gradlew publishDefaultPublicationToGitHubRepository -PreleaseMode=RELEASE else echo "not on a tag -> deploy snapshot version" - ./gradlew $ATASK -PreleaseMode=SNAPSHOT - ./gradlew $DTASK -PreleaseMode=SNAPSHOT + ./gradlew assemble -PreleaseMode=SNAPSHOT + ./gradlew publishDefaultPublicationToGitHubRepository -PreleaseMode=SNAPSHOT fi diff --git a/.buildsystem/deploy-sonatype.sh b/.buildsystem/deploy-sonatype.sh index 8487e8541..73001156f 100755 --- a/.buildsystem/deploy-sonatype.sh +++ b/.buildsystem/deploy-sonatype.sh @@ -16,21 +16,12 @@ if [ -z "$GPG_PASSPHRASE" ]; then exit 1 fi -ATASK="" -DTASK="" -for i in ":adam" ":android-junit4" ":android-testrunner-contract"; do - ATASK="$ATASK $i:assemble" - DTASK="$DTASK $i:publishDefaultPublicationToOSSHRRepository" -done - -echo "Value of TEST_ENVVAR is $TEST_ENVVAR" - if [ -z "$GIT_TAG_NAME" ]; then echo "not on a tag -> deploy snapshot version" - ./gradlew $ATASK -PreleaseMode=SNAPSHOT - ./gradlew $DTASK -PreleaseMode=SNAPSHOT + ./gradlew assemble -PreleaseMode=SNAPSHOT + ./gradlew publishDefaultPublicationToOSSHRRepository -PreleaseMode=SNAPSHOT else echo "on a tag -> deploy release version $GIT_TAG_NAME" - ./gradlew $ATASK -PreleaseMode=RELEASE - ./gradlew $DTASK -PreleaseMode=RELEASE + ./gradlew assemble -PreleaseMode=RELEASE + ./gradlew publishDefaultPublicationToOSSHRRepository -PreleaseMode=RELEASE fi diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a45f98b4e..d16bbcfac 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,7 +11,7 @@ jobs: java-version: 1.8 - uses: malinskiy/action-android/install-sdk@release/0.1.1 - name: build & test - run: ./gradlew :adam:test :adam:jacocoTestReport :android-junit4:build :android-testrunner-contract:build + run: ./gradlew assemble test jacocoTestReport - name: archive test results if: failure() run: (cd adam/build/reports/tests/test; zip -r -X ../../../../../test-result.zip .) diff --git a/adam/build.gradle.kts b/adam/build.gradle.kts index da4ac37a6..db3e597c3 100644 --- a/adam/build.gradle.kts +++ b/adam/build.gradle.kts @@ -168,6 +168,7 @@ dependencies { testImplementation(TestLibraries.imageComparison) testImplementation(kotlin("reflect", version = Versions.kotlin)) testImplementation(TestLibraries.coroutinesDebug) + testImplementation(project(":server:server-stub-junit4")) integrationTestImplementation(TestLibraries.coroutinesDebug) integrationTestImplementation(TestLibraries.assertk) diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/Feature.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/Feature.kt index 83e6f4987..8e8398959 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/Feature.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/Feature.kt @@ -99,6 +99,8 @@ enum class Feature { */ SENDRECV_V2_DRY_RUN_SEND; + fun value() = name.toLowerCase() + companion object { /** * see adb/transport.cpp for up-to-date list diff --git a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/FileEntry.kt b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/FileEntry.kt index 1aa412324..2c3a5989b 100644 --- a/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/FileEntry.kt +++ b/adam/src/main/kotlin/com/malinskiy/adam/request/sync/model/FileEntry.kt @@ -61,5 +61,5 @@ data class FileEntryV2( val ctime: Instant, override val name: String? = null ) : FileEntry() { - override fun exists() = error == 3025.toUInt() + override fun exists() = !(size == 0.toULong() && mode == 0.toUInt() && mtime.epochSecond == 0L) } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientTest.kt index 280992700..c74d339c3 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/AndroidDebugBridgeClientTest.kt @@ -23,114 +23,76 @@ import com.malinskiy.adam.exception.RequestValidationException import com.malinskiy.adam.request.ComplexRequest import com.malinskiy.adam.request.ValidationResponse import com.malinskiy.adam.request.shell.v1.ShellCommandRequest -import com.malinskiy.adam.server.AndroidDebugBridgeServer +import com.malinskiy.adam.server.junit4.AdbServerRule import com.malinskiy.adam.transport.Socket -import io.ktor.utils.io.close import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class AndroidDebugBridgeClientTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test(expected = RequestRejectedException::class) fun testRequestRejection() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.FAIL) - - val response = "0013something-somethingx0".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.reject("something-something") } val output = client.execute(ShellCommandRequest("xx"), serial = "serial") assertThat(output.output).isEqualTo("something-something") assertThat(output.exitCode).isEqualTo(0) - - server.dispose() } } @Test(expected = RequestRejectedException::class) fun testRequestRejectionDuringHandshake() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:xx;echo x$?") - output.respond(Const.Message.FAIL) - - val response = "0013something-somethingx0".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectShell { "xx;echo x$?" }.reject("something-somethingx0") } client.execute(ShellCommandRequest("xx"), serial = "serial") - server.dispose() } } @Test(expected = RequestRejectedException::class) fun testRequestRejectionDuringHandshakeWithNoMessage() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:xx;echo x\$?") + expectShell { "xx;echo x\$?" } output.respond(Const.Message.FAIL) - - val response = "XXXXx".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + output.respondStringRaw("XXXXx") } client.execute(ShellCommandRequest("xx"), serial = "serial") - server.dispose() } } @Test(expected = RequestRejectedException::class) fun testRequestRejectionAndUnexpectedMessageLength() { runBlocking { - val server = AndroidDebugBridgeServer() + server.session { + expectCmd { "host:transport:serial" } - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") output.respond(Const.Message.FAIL) - - val response = "XXXXsomething-something".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + output.respondStringRaw("XXXXsomething-something") } val output = client.execute(ShellCommandRequest("xx"), serial = "serial") assertThat(output.output).isEqualTo("something-something") - - server.dispose() } } @Test(expected = RequestValidationException::class) fun testRequestValidation() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { _, _ -> - } - client.execute(object : ComplexRequest() { override fun validate() = ValidationResponse(false, "Fake") override suspend fun readElement(socket: Socket): String { @@ -141,7 +103,6 @@ class AndroidDebugBridgeClientTest { TODO("Not yet implemented") } }, serial = "serial") - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/GetSinglePropRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/GetSinglePropRequestTest.kt index a783a3856..bbe8eefef 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/GetSinglePropRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/GetSinglePropRequestTest.kt @@ -18,14 +18,20 @@ package com.malinskiy.adam.request import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const import com.malinskiy.adam.request.prop.GetSinglePropRequest -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class GetSinglePropRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testGetX() { assertThat(String(GetSinglePropRequest("x").serialize(), Const.DEFAULT_TRANSPORT_ENCODING)) @@ -35,25 +41,15 @@ class GetSinglePropRequestTest { @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:getprop prop1;echo x$?") - output.respond(Const.Message.OKAY) - - val response = "testingx0".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectShell { "getprop prop1;echo x$?" } + .accept() + .respond("testingx0") } val version = client.execute(GetSinglePropRequest("prop1"), serial = "serial") assertThat(version).isEqualTo("testing") - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/abb/AbbExecRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/abb/AbbExecRequestTest.kt index 6010d0464..15fe7d4b0 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/abb/AbbExecRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/abb/AbbExecRequestTest.kt @@ -23,7 +23,7 @@ import assertk.assertions.isTrue import com.malinskiy.adam.Const import com.malinskiy.adam.extension.toRequestString import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import kotlinx.coroutines.runBlocking import org.junit.Rule diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/adbd/RestartAdbdRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/adbd/RestartAdbdRequestTest.kt index 2191da52c..885cfeb17 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/adbd/RestartAdbdRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/adbd/RestartAdbdRequestTest.kt @@ -18,17 +18,22 @@ package com.malinskiy.adam.request.adbd import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test /** * Restarts the on device adbd */ class RestartAdbdRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerializeRootMode() { val bytes = RestartAdbdRequest(RootAdbdMode).serialize() @@ -56,25 +61,14 @@ class RestartAdbdRequestTest { @Test fun testReturnsResultString() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val cmd = input.receiveCommand() - assertThat(cmd).isEqualTo("root:") - output.respondOkay() - - output.respondStringRaw("adbd cannot run as root in production builds") - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "root:" }.accept() + resondRestartAdbd("adbd cannot run as root in production builds") } val output = client.execute(RestartAdbdRequest(RootAdbdMode), "serial") assertThat(output).isEqualTo("adbd cannot run as root in production builds") - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/async/AsyncDeviceMonitorRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/async/AsyncDeviceMonitorRequestTest.kt index b2b8dd6d6..f2be20241 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/async/AsyncDeviceMonitorRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/async/AsyncDeviceMonitorRequestTest.kt @@ -18,33 +18,28 @@ package com.malinskiy.adam.request.async import assertk.assertThat import assertk.assertions.containsExactly -import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.request.device.AsyncDeviceMonitorRequest import com.malinskiy.adam.request.device.Device import com.malinskiy.adam.request.device.DeviceState -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close -import kotlinx.coroutines.channels.receiveOrNull +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class AsyncDeviceMonitorRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:track-devices") - output.respond(Const.Message.OKAY) - - var response = ("0016emulator-5554\toffline\n").toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - response = ("0015emulator-5554\tdevice\n").toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:track-devices" }.accept() + respondAsyncDeviceMonitor("emulator-5554", "offline") + respondAsyncDeviceMonitor("emulator-5554", "device") } val updates = client.execute(AsyncDeviceMonitorRequest(), scope = this) @@ -53,8 +48,6 @@ class AsyncDeviceMonitorRequestTest { update = updates.receiveOrNull() assertThat(update!!).containsExactly(Device("emulator-5554", DeviceState.DEVICE)) updates.cancel() - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequestTest.kt index 38f6b6677..2c24220fc 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/device/FetchDeviceFeaturesRequestTest.kt @@ -21,7 +21,7 @@ import assertk.assertions.containsExactly import assertk.assertions.isEqualTo import com.malinskiy.adam.Const import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import kotlinx.coroutines.runBlocking import org.junit.Test diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/device/ListDevicesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/device/ListDevicesRequestTest.kt index a5aea20f7..58555859a 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/device/ListDevicesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/device/ListDevicesRequestTest.kt @@ -18,39 +18,38 @@ package com.malinskiy.adam.request.device import assertk.assertThat import assertk.assertions.containsExactly -import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ListDevicesRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:devices") - output.respond(Const.Message.OKAY) - - val response = ("00FA" + - "emulator-5554\toffline\n" + - "emulator-5556\tbootloader\n" + - "emulator-5558\tdevice\n" + - "emulator-5560\thost\n" + - "emulator-5562\trecovery\n" + - "emulator-5564\trescue\n" + - "emulator-5566\tsideload\n" + - "emulator-5568\tunauthorized\n" + - "emulator-5570\tauthorizing\n" + - "emulator-5572\tconnecting\n" + - "emulator-5574\twtf\n" - ).toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:devices" }.accept() + respondListDevices( + mapOf( + "emulator-5554" to "offline", + "emulator-5556" to "bootloader", + "emulator-5558" to "device", + "emulator-5560" to "host", + "emulator-5562" to "recovery", + "emulator-5564" to "rescue", + "emulator-5566" to "sideload", + "emulator-5568" to "unauthorized", + "emulator-5570" to "authorizing", + "emulator-5572" to "connecting", + "emulator-5574" to "wtf", + ) + ) } val version = client.execute(ListDevicesRequest()) @@ -67,8 +66,6 @@ class ListDevicesRequestTest { Device("emulator-5572", DeviceState.CONNECTING), Device("emulator-5574", DeviceState.UNKNOWN) ) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/emu/EmulatorCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/emu/EmulatorCommandRequestTest.kt index 29d5b20b4..472185fbe 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/emu/EmulatorCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/emu/EmulatorCommandRequestTest.kt @@ -18,8 +18,7 @@ package com.malinskiy.adam.request.emu import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.server.EmulatorConsoleServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.stub.EmulatorConsoleServer import kotlinx.coroutines.runBlocking import org.junit.Test @@ -38,7 +37,6 @@ class EmulatorCommandRequestTest { output.respond("Android console commands:") input.receiveExit() - output.close() } val output = client.execute(EmulatorCommandRequest("help", consoleAddr, authToken = "token")) diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequestTest.kt index ffd5d7a2d..e815a7dea 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/ListPortForwardsRequestTest.kt @@ -19,24 +19,26 @@ package com.malinskiy.adam.request.forwarding import assertk.assertThat import assertk.assertions.containsExactly import assertk.assertions.isEqualTo -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.junit4.AdbServerRule import io.ktor.utils.io.discard import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ListPortForwardsRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host-serial:xx:list-forward") - output.respondOkay() + server.session { + expectCmd { "host-serial:xx:list-forward" }.accept() - output.respondStringV1( + respondListPortForwards( """ xx tcp:80 tcp:80 xx local:/tmp/socket localabstract:namedsocket @@ -47,8 +49,8 @@ class ListPortForwardsRequestTest { """.trimIndent() ) + input.discard() - output.close() } val output = client.execute(ListPortForwardsRequest("xx")) @@ -64,8 +66,6 @@ class ListPortForwardsRequestTest { assertThat(output.first().serial).isEqualTo("xx") assertThat(output.first().localSpec).isEqualTo(LocalTcpPortSpec(80)) assertThat(output.first().remoteSpec).isEqualTo(RemoteTcpPortSpec(80)) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/PortForwardRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/PortForwardRequestTest.kt index b2c761119..cfd0926a3 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/PortForwardRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/forwarding/PortForwardRequestTest.kt @@ -18,14 +18,20 @@ package com.malinskiy.adam.request.forwarding import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const import com.malinskiy.adam.exception.RequestRejectedException -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class PortForwardRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerializeDefault() { val bytes = PortForwardRequest(LocalTcpPortSpec(80), RemoteTcpPortSpec(80), "emulator-5554").serialize() @@ -50,42 +56,25 @@ class PortForwardRequestTest { @Test fun testRead() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val forwardCmd = input.receiveCommand() - assertThat(forwardCmd).isEqualTo("host-serial:serial:forward:tcp:0;tcp:8080") - output.respond(Const.Message.OKAY) - - output.respond(Const.Message.OKAY) - output.respondStringV1("7070") - output.close() + server.session { + expectCmd { "host-serial:serial:forward:tcp:0;tcp:8080" }.accept() + respondPortForward(true, 7070) } val output = client.execute(PortForwardRequest(LocalTcpPortSpec(0), RemoteTcpPortSpec(8080), "serial")) assertThat(output).isEqualTo(7070) - - server.dispose() } } @Test(expected = RequestRejectedException::class) fun testReadFailure() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val forwardCmd = input.receiveCommand() - assertThat(forwardCmd).isEqualTo("host-serial:serial:forward:tcp:0;tcp:8080") - output.respond(Const.Message.OKAY) - - output.respond(Const.Message.FAIL) - output.respondStringV1("7070") - output.close() + server.session { + expectCmd { "host-serial:serial:forward:tcp:0;tcp:8080" }.accept() + respondPortForward(false) } - val output = client.execute(PortForwardRequest(LocalTcpPortSpec(0), RemoteTcpPortSpec(8080), "serial")) - server.dispose() + client.execute(PortForwardRequest(LocalTcpPortSpec(0), RemoteTcpPortSpec(8080), "serial")) } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequestTest.kt index 5f86439e5..1a812510c 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/ScreenCaptureRequestTest.kt @@ -21,11 +21,10 @@ import assertk.assertions.isEqualTo import com.github.romankh3.image.comparison.ImageComparison import com.github.romankh3.image.comparison.ImageComparisonUtil import com.github.romankh3.image.comparison.model.ImageComparisonResult -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.exception.UnsupportedImageProtocolException import com.malinskiy.adam.extension.newFileWithExtension -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import io.ktor.utils.io.writeIntLittleEndian import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -42,28 +41,19 @@ class ScreenCaptureRequestTest { @JvmField val temp = TemporaryFolder() + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testProtocol1() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(1) - - val sample = File(javaClass.getResource("/fixture/screencap_1.bin").toURI()).readBytes() - output.writeFully(sample, 0, 48) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 48, sample.size - 48) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV2(File(javaClass.getResource("/fixture/screencap_1.bin").toURI())) } val adapter = RawImageScreenCaptureAdapter() @@ -89,33 +79,17 @@ class ScreenCaptureRequestTest { val expected = ImageIO.read(File(javaClass.getResource("/fixture/screencap_1.png").toURI())) compare(expected, actualImage) - - server.dispose() } } @Test fun testProtocol16bit() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(1) - - val sample = File(javaClass.getResource("/fixture/screencap_2.bin").toURI()).readBytes() - output.writeFully(sample, 0, 48) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 48, sample.size - 48) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV2(File(javaClass.getResource("/fixture/screencap_2.bin").toURI())) } val adapter = RawImageScreenCaptureAdapter() @@ -141,32 +115,16 @@ class ScreenCaptureRequestTest { val expected = ImageIO.read(File(javaClass.getResource("/fixture/screencap_2.png").toURI())) compare(expected, actualImage) - - server.dispose() } } @Test fun `test with buffered image adapter`() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(1) - - val sample = File(javaClass.getResource("/fixture/screencap_1.bin").toURI()).readBytes() - output.writeFully(sample, 0, 48) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 48, sample.size - 48) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV2(File(javaClass.getResource("/fixture/screencap_1.bin").toURI())) } val adapter = BufferedImageScreenCaptureAdapter() @@ -183,24 +141,13 @@ class ScreenCaptureRequestTest { var comparisonResult = compare(expected, actual!!) assertThat(comparisonResult.differencePercent).isEqualTo(0.0f) - server.listen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(1) - - val sample = File(javaClass.getResource("/fixture/screencap_1.bin").toURI()).readBytes() - output.writeFully(sample, 0, 48) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 48, sample.size - 48) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV2(File(javaClass.getResource("/fixture/screencap_1.bin").toURI())) } + measureTimeMillis { actual = client.execute(ScreenCaptureRequest(adapter), serial = "serial") }.let { println("Read image with buffer reuse in ${it}ms") } @@ -209,8 +156,6 @@ class ScreenCaptureRequestTest { ImageIO.write(actual, "png", createTempFile2) comparisonResult = compare(expected, actual!!) assertThat(comparisonResult.differencePercent).isEqualTo(0.0f) - - server.dispose() } /** @@ -219,25 +164,11 @@ class ScreenCaptureRequestTest { */ @Test fun `test with buffered image adapter 16 bit`() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(1) - - val sample = File(javaClass.getResource("/fixture/screencap_2.bin").toURI()).readBytes() - output.writeFully(sample, 0, 48) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 48, sample.size - 48) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV2(File(javaClass.getResource("/fixture/screencap_2.bin").toURI())) } val adapter = BufferedImageScreenCaptureAdapter() @@ -254,24 +185,13 @@ class ScreenCaptureRequestTest { var comparisonResult = compare(expected, actual!!) assertThat(comparisonResult.differencePercent).isEqualTo(0.0f) - server.listen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(1) - - val sample = File(javaClass.getResource("/fixture/screencap_2.bin").toURI()).readBytes() - output.writeFully(sample, 0, 48) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 48, sample.size - 48) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV2(File(javaClass.getResource("/fixture/screencap_2.bin").toURI())) } + measureTimeMillis { actual = client.execute(ScreenCaptureRequest(adapter), serial = "serial") }.let { println("Read image with buffer reuse in ${it}ms") } @@ -280,32 +200,15 @@ class ScreenCaptureRequestTest { ImageIO.write(actual, "png", createTempFile2) comparisonResult = compare(expected, actual!!) assertThat(comparisonResult.differencePercent).isEqualTo(0.0f) - - - server.dispose() } @Test fun `test with buffered image adapter unaligned 32 bit `() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(1) - - val sample = File(javaClass.getResource("/fixture/screencap_1_unaligned.bin").toURI()).readBytes() - output.writeFully(sample, 0, 48) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 48, sample.size - 48) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV2(File(javaClass.getResource("/fixture/screencap_1_unaligned.bin").toURI())) } val adapter = BufferedImageScreenCaptureAdapter() @@ -322,24 +225,13 @@ class ScreenCaptureRequestTest { var comparisonResult = compare(expected, actual!!) assertThat(comparisonResult.differencePercent).isEqualTo(0.0f) - server.listen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(1) - - val sample = File(javaClass.getResource("/fixture/screencap_1_unaligned.bin").toURI()).readBytes() - output.writeFully(sample, 0, 48) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 48, sample.size - 48) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV2(File(javaClass.getResource("/fixture/screencap_1_unaligned.bin").toURI())) } + measureTimeMillis { actual = client.execute(ScreenCaptureRequest(adapter), serial = "serial") }.let { println("Read image with buffer reuse in ${it}ms") } @@ -348,31 +240,15 @@ class ScreenCaptureRequestTest { ImageIO.write(actual, "png", createTempFile2) comparisonResult = compare(expected, actual!!) assertThat(comparisonResult.differencePercent).isEqualTo(0.0f) - - server.dispose() } @Test fun `test with buffered image adapter with srgb color model`() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(2) - - val sample = File(javaClass.getResource("/fixture/screencap_3.bin").toURI()).readBytes() - output.writeFully(sample, 0, 52) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 52, sample.size - 52) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV3(File(javaClass.getResource("/fixture/screencap_3.bin").toURI())) } val adapter = BufferedImageScreenCaptureAdapter() @@ -389,23 +265,11 @@ class ScreenCaptureRequestTest { var comparisonResult = compare(expected, actual!!) assertThat(comparisonResult.differencePercent).isEqualTo(0.0f) - server.listen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) - - //Extended version - output.writeIntLittleEndian(2) - - val sample = File(javaClass.getResource("/fixture/screencap_3.bin").toURI()).readBytes() - output.writeFully(sample, 0, 52) - assertThat(input.readByte()).isEqualTo(0.toByte()) - output.writeFully(sample, 52, sample.size - 52) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectFramebuffer() + .accept() + .respondScreencaptureV3(File(javaClass.getResource("/fixture/screencap_3.bin").toURI())) } measureTimeMillis { actual = client.execute(ScreenCaptureRequest(adapter), serial = "serial") @@ -415,31 +279,20 @@ class ScreenCaptureRequestTest { ImageIO.write(actual, "png", createTempFile2) comparisonResult = compare(expected, actual!!) assertThat(comparisonResult.differencePercent).isEqualTo(0.0f) - - server.dispose() } @Test(expected = UnsupportedImageProtocolException::class) fun testProtocolUnsupported() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("framebuffer:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "framebuffer:" }.accept() - //Extended version + //Unsupported version output.writeIntLittleEndian(99) - output.close() } client.execute(ScreenCaptureRequest(RawImageScreenCaptureAdapter()), serial = "serial") - server.dispose() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/screencapture/BufferedImageScreenCaptureAdapterTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/screencapture/BufferedImageScreenCaptureAdapterTest.kt index 8110d621e..ecb3466c6 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/screencapture/BufferedImageScreenCaptureAdapterTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/framebuffer/screencapture/BufferedImageScreenCaptureAdapterTest.kt @@ -17,7 +17,7 @@ package com.malinskiy.adam.request.framebuffer.screencapture import com.malinskiy.adam.request.framebuffer.BufferedImageScreenCaptureAdapter -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import kotlinx.coroutines.runBlocking import org.junit.Test diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequestTest.kt index 0e8571386..63e6dcd63 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/ListMdnsServicesRequestTest.kt @@ -21,7 +21,7 @@ import assertk.assertions.containsExactly import assertk.assertions.isEqualTo import com.malinskiy.adam.Const import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import kotlinx.coroutines.runBlocking import org.junit.Test diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequestTest.kt index 6b9e2dfb2..884dd20de 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/mdns/MdnsCheckRequestTest.kt @@ -20,7 +20,7 @@ import assertk.assertThat import assertk.assertions.isEqualTo import com.malinskiy.adam.Const import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import kotlinx.coroutines.runBlocking import org.junit.Test diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/ConnectDeviceRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/ConnectDeviceRequestTest.kt index acab86417..905905dd5 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/ConnectDeviceRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/ConnectDeviceRequestTest.kt @@ -18,13 +18,19 @@ package com.malinskiy.adam.request.misc import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ConnectDeviceRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { val bytes = ConnectDeviceRequest("123.123.123.123").serialize() @@ -40,21 +46,13 @@ class ConnectDeviceRequestTest { @Test fun testReturnsResultString() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val cmd = input.receiveCommand() - assertThat(cmd).isEqualTo("host:connect:123.123.123.123:8888") - output.respondOkay() - - output.respondStringV1("connected to 123.123.123.123:8888") - output.close() + server.session { + expectCmd { "host:connect:123.123.123.123:8888" }.accept() + respondConnectDevice("connected to 123.123.123.123:8888") } val output = client.execute(ConnectDeviceRequest("123.123.123.123", 8888)) assertThat(output).isEqualTo("connected to 123.123.123.123:8888") - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequestTest.kt index 54b3aba94..858e6dfe7 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/DisconnectDeviceRequestTest.kt @@ -18,13 +18,19 @@ package com.malinskiy.adam.request.misc import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class DisconnectDeviceRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { val bytes = DisconnectDeviceRequest("123.123.123.123").serialize() @@ -46,21 +52,13 @@ class DisconnectDeviceRequestTest { @Test fun testReturnsResultString() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val cmd = input.receiveCommand() - assertThat(cmd).isEqualTo("host:disconnect:123.123.123.123:8888") - output.respondOkay() - - output.respondStringV1("disconnected 123.123.123.123") - output.close() + server.session { + expectCmd { "host:disconnect:123.123.123.123:8888" }.accept() + respondDisconnectDevice("disconnected 123.123.123.123") } val output = client.execute(DisconnectDeviceRequest("123.123.123.123", 8888)) assertThat(output).isEqualTo("disconnected 123.123.123.123") - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequestTest.kt index fbde962b2..ded64dca1 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/FetchHostFeaturesRequestTest.kt @@ -22,7 +22,7 @@ import assertk.assertions.isEqualTo import com.malinskiy.adam.Const import com.malinskiy.adam.extension.toRequestString import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import kotlinx.coroutines.runBlocking import org.junit.Test @@ -55,4 +55,4 @@ class FetchHostFeaturesRequestTest { } } } -} \ No newline at end of file +} diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/GetAdbServerVersionRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/GetAdbServerVersionRequestTest.kt index ee5d66938..fd585dcb9 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/GetAdbServerVersionRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/GetAdbServerVersionRequestTest.kt @@ -18,30 +18,29 @@ package com.malinskiy.adam.request.misc import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class GetAdbServerVersionRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperVersion() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:version") - output.respond(Const.Message.OKAY) - - val version = ("0002" + 41.toString(16)).toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(version, 0, version.size) + server.session { + expectAdbServerVersion() + .accept() + .respondAdbServerVersion(41) } val version = client.execute(GetAdbServerVersionRequest()) assertThat(version).isEqualTo(41) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/PairDeviceRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/PairDeviceRequestTest.kt index 611e3b545..a325ddf6d 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/PairDeviceRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/PairDeviceRequestTest.kt @@ -18,13 +18,19 @@ package com.malinskiy.adam.request.misc import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class PairDeviceRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { val bytes = PairDeviceRequest("10.0.0.2:39567", "123456").serialize() @@ -33,20 +39,12 @@ class PairDeviceRequestTest { @Test fun testResponse() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val cmd = input.receiveCommand() - assertThat(cmd).isEqualTo("host:pair:123456:10.0.0.2:39567") - output.respondOkay() - - output.respondStringV1("Successfully paired to 10.0.0.2:39567 [guid=adb-serial-hYG6sO]") - output.close() + server.session { + expectCmd { "host:pair:123456:10.0.0.2:39567" }.accept() + respondPairDevice("Successfully paired to 10.0.0.2:39567 [guid=adb-serial-hYG6sO]") } val output = client.execute(PairDeviceRequest("10.0.0.2:39567", "123456")) assertThat(output).isEqualTo("Successfully paired to 10.0.0.2:39567 [guid=adb-serial-hYG6sO]") - - server.dispose() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/ReconnectRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/ReconnectRequestTest.kt index 6de19a0b7..a690cce46 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/ReconnectRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/ReconnectRequestTest.kt @@ -18,15 +18,21 @@ package com.malinskiy.adam.request.misc import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.extension.toRequestString import com.malinskiy.adam.request.HostTarget import com.malinskiy.adam.request.SerialTarget -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ReconnectRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { val bytes = ReconnectRequest().serialize() @@ -47,38 +53,23 @@ class ReconnectRequestTest { @Test fun testResponse() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val cmd = input.receiveCommand() - assertThat(cmd).isEqualTo("host:reconnect-offline") - output.respondOkay() - - output.respondStringV1("reconnecting emulator-5554 [offline]") - output.close() + server.session { + expectCmd { "host:reconnect-offline" }.accept() + respondReconnectOffline("reconnecting emulator-5554 [offline]") } val output = client.execute(ReconnectRequest(reconnectTarget = Offline, target = HostTarget)) assertThat(output).isEqualTo("reconnecting emulator-5554 [offline]") - - server.dispose() } @Test fun testResponseForSingleTarget() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val cmd = input.receiveCommand() - assertThat(cmd).isEqualTo("host-serial:serial:reconnect") - output.respondOkay() - output.respondStringRaw("done") - output.close() + server.session { + expectCmd { "host-serial:serial:reconnect" }.accept() + respondReconnectSingleDevice("done") } val output = client.execute(ReconnectRequest(reconnectTarget = Device, target = SerialTarget("serial"))) assertThat(output).isEqualTo("done") - - server.dispose() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/RemountPartitionsRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/RemountPartitionsRequestTest.kt index 02c22f7a7..22bb6a98a 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/misc/RemountPartitionsRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/misc/RemountPartitionsRequestTest.kt @@ -18,14 +18,19 @@ package com.malinskiy.adam.request.misc import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class RemountPartitionsRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { assertThat(RemountPartitionsRequest().serialize().toRequestString()).isEqualTo("0008remount:") @@ -40,26 +45,14 @@ class RemountPartitionsRequestTest { @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("remount:") - output.respondOkay() - - val response = "something-something".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "remount:" }.accept() + respondRemountPartitions { "something-something" } } val output = client.execute(RemountPartitionsRequest(), serial = "serial") assertThat(output).isEqualTo("something-something") - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/LegacySideloadRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/LegacySideloadRequestTest.kt index d358161d0..c091d3e8d 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/LegacySideloadRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/LegacySideloadRequestTest.kt @@ -20,9 +20,9 @@ import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isTrue -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.AndroidDebugBridgeServer +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking import org.junit.Rule import org.junit.Test @@ -34,6 +34,11 @@ class LegacySideloadRequestTest { @JvmField val temp = TemporaryFolder() + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { assertThat(LegacySideloadRequest(temp.newFile()).serialize().toRequestString()).isEqualTo("000Asideload:0") @@ -44,26 +49,16 @@ class LegacySideloadRequestTest { runBlocking { val fixture = File(SideloadRequestTest::class.java.getResource("/fixture/sample.yaml").file) - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sideload:614") - output.respond(Const.Message.OKAY) - - input.receiveBytes(614) - output.respondOkay() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectLegacySideload(614) + .receive(614) + .okay() } val request = LegacySideloadRequest(fixture) val result = client.execute(request, "serial") assertThat(result).isTrue() - - server.dispose() } } @@ -72,26 +67,16 @@ class LegacySideloadRequestTest { runBlocking { val fixture = File(SideloadRequestTest::class.java.getResource("/fixture/sample.yaml").file) - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sideload:614") - output.respond(Const.Message.OKAY) - - input.receiveBytes(614) - output.respondFail("something-something") + server.session { + expectCmd { "host:transport:serial" }.accept() + expectLegacySideload(614) + .receive(614) + .fail("something-something") } val request = LegacySideloadRequest(fixture) val result = client.execute(request, "serial") assertThat(result).isFalse() - - server.dispose() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/PmListRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/PmListRequestTest.kt index e0c7eda97..950a34d2e 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/PmListRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/PmListRequestTest.kt @@ -18,63 +18,45 @@ package com.malinskiy.adam.request.pkg import assertk.assertThat import assertk.assertions.containsExactly -import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class PmListRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:pm list packages;echo x$?") - output.respond(Const.Message.OKAY) - - val response = "package:test.packagex0".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectShell { "pm list packages;echo x$?" } + .accept() + .respond("package:test.packagex0") } val output = client.execute(PmListRequest(), serial = "serial") assertThat(output).containsExactly(Package("test.package")) - - server.dispose() } } @Test fun testReturnsProperContentWithPath() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:pm list packages -f;echo x$?") - output.respond(Const.Message.OKAY) - - val response = "package:/data/app/x=test.packagex0\n\n".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectShell { "pm list packages -f;echo x$?" } + .accept() + .respond("package:/data/app/x=test.packagex0\n\n") } val output = client.execute(PmListRequest(includePath = true), serial = "serial") assertThat(output).containsExactly(Package("test.package", "/data/app/x")) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/SideloadRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/SideloadRequestTest.kt index 2f1cd0011..20af29315 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/SideloadRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/SideloadRequestTest.kt @@ -20,9 +20,10 @@ import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isFalse import assertk.assertions.isTrue +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.AndroidDebugBridgeServer +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking import org.junit.Rule import org.junit.Test @@ -31,6 +32,10 @@ import java.io.File import java.nio.ByteBuffer class SideloadRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client @Rule @JvmField @@ -49,24 +54,17 @@ class SideloadRequestTest { fixture.appendBytes(ByteArray(65536) { 1.toByte() }) fixture.appendBytes(ByteArray(14) { 2.toByte() }) - val server = AndroidDebugBridgeServer() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sideload-host:131086:65536" }.accept() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sideload-host:131086:65536") - output.respond(Const.Message.OKAY) - - output.respondStringRaw("00000000") + respondSideloadChunkRequested("00000000") val chunk1 = input.receiveBytes(Const.MAX_FILE_PACKET_LENGTH) - output.respondStringRaw("00000001") + respondSideloadChunkRequested("00000001") val chunk2 = input.receiveBytes(Const.MAX_FILE_PACKET_LENGTH) - output.respondStringRaw("00000000") + respondSideloadChunkRequested("00000000") val chunk1Replay = input.receiveBytes(Const.MAX_FILE_PACKET_LENGTH) - output.respondStringRaw("00000002") + respondSideloadChunkRequested("00000002") val chunk3 = input.receiveBytes(14) assertThat(chunk1).isEqualTo(chunk1Replay) @@ -87,8 +85,6 @@ class SideloadRequestTest { val request = SideloadRequest(fixture) val result = client.execute(request, "serial") assertThat(result).isTrue() - - server.dispose() } } @@ -96,16 +92,10 @@ class SideloadRequestTest { fun testTransferFailure() { runBlocking { val fixture = File(SideloadRequestTest::class.java.getResource("/fixture/sample.yaml").file) - val server = AndroidDebugBridgeServer() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sideload-host:614:65536") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sideload-host:614:65536" }.accept() output.respondFailFail() } @@ -113,8 +103,6 @@ class SideloadRequestTest { val request = SideloadRequest(fixture) val result = client.execute(request, "serial") assertThat(result).isFalse() - - server.dispose() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequestTest.kt index d4c0054a4..32c210d13 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/AddSessionRequestTest.kt @@ -22,7 +22,7 @@ import com.malinskiy.adam.Const import com.malinskiy.adam.exception.RequestRejectedException import com.malinskiy.adam.extension.toRequestString import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import kotlinx.coroutines.runBlocking import org.junit.Test diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequestTest.kt index 58615e3c8..5472689ad 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateIndividualPackageSessionRequestTest.kt @@ -23,7 +23,7 @@ import com.malinskiy.adam.exception.RequestRejectedException import com.malinskiy.adam.extension.newFileWithExtension import com.malinskiy.adam.extension.toRequestString import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import kotlinx.coroutines.runBlocking import org.junit.Rule diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequestTest.kt index 8e880cbe8..3d46e41a0 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/CreateMultiPackageSessionRequestTest.kt @@ -26,7 +26,7 @@ import com.malinskiy.adam.extension.newFileWithExtension import com.malinskiy.adam.extension.toRequestString import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.ValidationResponse -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import io.ktor.utils.io.ByteChannelSequentialJVM import io.ktor.utils.io.ByteWriteChannel diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequestTest.kt index a2c26da20..8004697ee 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/InstallCommitRequestTest.kt @@ -22,7 +22,7 @@ import com.malinskiy.adam.Const import com.malinskiy.adam.exception.RequestRejectedException import com.malinskiy.adam.extension.toRequestString import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import kotlinx.coroutines.runBlocking import org.junit.Test diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequestTest.kt index 9e89175e6..717008c65 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/pkg/multi/WriteIndividualPackageRequestTest.kt @@ -23,7 +23,7 @@ import com.malinskiy.adam.exception.RequestRejectedException import com.malinskiy.adam.extension.newFileWithExtension import com.malinskiy.adam.extension.toRequestString import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import io.ktor.util.cio.writeChannel import io.ktor.utils.io.ByteReadChannel diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/prop/GetPropRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/prop/GetPropRequestTest.kt index c36fcc911..1d5e31e53 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/prop/GetPropRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/prop/GetPropRequestTest.kt @@ -19,13 +19,19 @@ package com.malinskiy.adam.request.prop import assertk.assertThat import assertk.assertions.contains import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class GetPropRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testGetAll() { assertThat(String(GetPropRequest().serialize(), Const.DEFAULT_TRANSPORT_ENCODING)) @@ -35,26 +41,15 @@ class GetPropRequestTest { @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:getprop;echo x$?") - output.respond(Const.Message.OKAY) - - val response = "[testing]: [testing]\r\r\nx0".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectShell { "getprop;echo x$?" } + .accept() + .respond("[testing]: [testing]\r\r\nx0") } val version = client.execute(GetPropRequest(), serial = "serial") assertThat(version).contains("testing", "testing") - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequestTest.kt index 7ae216159..65d8c6582 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ListReversePortForwardsRequestTest.kt @@ -19,33 +19,32 @@ package com.malinskiy.adam.request.reverse import assertk.assertThat import assertk.assertions.containsExactly import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.request.forwarding.LocalTcpPortSpec import com.malinskiy.adam.request.forwarding.LocalUnixSocketPortSpec import com.malinskiy.adam.request.forwarding.RemoteAbstractPortSpec import com.malinskiy.adam.request.forwarding.RemoteFilesystemPortSpec import com.malinskiy.adam.request.forwarding.RemoteReservedPortSpec import com.malinskiy.adam.request.forwarding.RemoteTcpPortSpec -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ListReversePortForwardsRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:xx") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:xx" }.accept() + expectCmd { "reverse:list-forward" }.accept() - val reverseCmd = input.receiveCommand() - assertThat(reverseCmd).isEqualTo("reverse:list-forward") - output.respond(Const.Message.OKAY) - output.respondStringV1( + respondListPortForwards( """ xx tcp:80 tcp:80 xx localabstract:namedsocket local:/tmp/socket @@ -54,7 +53,6 @@ class ListReversePortForwardsRequestTest { """.trimIndent() ) - output.close() } val output = client.execute(ListReversePortForwardsRequest(), serial = "xx") @@ -68,8 +66,6 @@ class ListReversePortForwardsRequestTest { assertThat(output.first().serial).isEqualTo("xx") assertThat(output.first().remoteSpec).isEqualTo(LocalTcpPortSpec(80)) assertThat(output.first().localSpec).isEqualTo(RemoteTcpPortSpec(80)) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequestTest.kt index 9c9601119..db72a683f 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/reverse/ReversePortForwardRequestTest.kt @@ -18,17 +18,23 @@ package com.malinskiy.adam.request.reverse import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const import com.malinskiy.adam.exception.RequestRejectedException import com.malinskiy.adam.request.forwarding.LocalTcpPortSpec import com.malinskiy.adam.request.forwarding.PortForwardingMode import com.malinskiy.adam.request.forwarding.RemoteTcpPortSpec -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ReversePortForwardRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerializeDefault() { val bytes = ReversePortForwardRequest(RemoteTcpPortSpec(80), LocalTcpPortSpec(80)).serialize() @@ -52,49 +58,27 @@ class ReversePortForwardRequestTest { @Test fun testRead() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val hostCmd = input.receiveCommand() - assertThat(hostCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val forwardCmd = input.receiveCommand() - assertThat(forwardCmd).isEqualTo("reverse:forward:tcp:8080;tcp:0") - output.respond(Const.Message.OKAY) - - output.respond(Const.Message.OKAY) - output.respondStringV1("7070") - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "reverse:forward:tcp:8080;tcp:0" }.accept() + respondPortForward(true, 7070) } val output = client.execute(ReversePortForwardRequest(RemoteTcpPortSpec(8080), LocalTcpPortSpec(0)), "serial") assertThat(output).isEqualTo(7070) - - server.dispose() } } @Test(expected = RequestRejectedException::class) fun testReadFailure() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val hostCmd = input.receiveCommand() - assertThat(hostCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val forwardCmd = input.receiveCommand() - assertThat(forwardCmd).isEqualTo("reverse:forward:tcp:8080;tcp:0") - - output.respond(Const.Message.FAIL) - output.respondStringV1("7070") - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "reverse:forward:tcp:8080;tcp:0" }.accept() + respondPortForward(false) } - val output = client.execute(ReversePortForwardRequest(RemoteTcpPortSpec(8080), LocalTcpPortSpec(0)), "serial") - server.dispose() + client.execute(ReversePortForwardRequest(RemoteTcpPortSpec(8080), LocalTcpPortSpec(0)), "serial") } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/security/SetDmVerityCheckingRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/security/SetDmVerityCheckingRequestTest.kt index 72e1ac867..bd053979e 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/security/SetDmVerityCheckingRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/security/SetDmVerityCheckingRequestTest.kt @@ -18,14 +18,19 @@ package com.malinskiy.adam.request.security import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.extension.toRequestString -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class SetDmVerityCheckingRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { assertThat(SetDmVerityCheckingRequest(false).serialize().toRequestString()).isEqualTo("000Fdisable-verity:") @@ -34,25 +39,14 @@ class SetDmVerityCheckingRequestTest { @Test fun testRead() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val cmd = input.receiveCommand() - assertThat(cmd).isEqualTo("disable-verity:") - output.respondOkay() - - output.respondStringRaw("Success") - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "disable-verity:" }.accept() + respondSetDmVerityChecking("Success") } val output = client.execute(SetDmVerityCheckingRequest(false), "serial") assertThat(output).isEqualTo("Success") - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequestTest.kt index 6dbf3629d..03fb3334a 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ChanneledShellCommandRequestTest.kt @@ -18,32 +18,27 @@ package com.malinskiy.adam.request.shell.v1 import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ChanneledShellCommandRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:emulator-5554") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:logcat -v") - output.respond(Const.Message.OKAY) - - var response = "something-something".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - response = "something2-something2".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:emulator-5554" }.accept() + expectShell { "logcat -v" } + .accept() + .respond("something-something") + .respond("something2-something2") } val updates = client.execute(ChanneledShellCommandRequest("logcat -v"), scope = this, serial = "emulator-5554") @@ -54,7 +49,6 @@ class ChanneledShellCommandRequestTest { } assertThat(stringBuffer.toString()).isEqualTo("something-somethingsomething2-something2") - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequestTest.kt index 4f1039eeb..fab2afb46 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v1/ShellCommandRequestTest.kt @@ -18,65 +18,48 @@ package com.malinskiy.adam.request.shell.v1 import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ShellCommandRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:xx;echo x$?") - output.respondOkay() - - val response = "something-somethingx1".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectShell { "xx;echo x$?" } + .accept() + .respond("something-somethingx1") } val output = client.execute(ShellCommandRequest("xx"), serial = "serial") assertThat(output.output).isEqualTo("something-something") assertThat(output.exitCode).isEqualTo(1) - - server.dispose() } } @Test fun testReturnsNonStrippedStdout() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:xx;echo x$?") - output.respond(Const.Message.OKAY) - - val response = "something-something\nx1".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectShell { "xx;echo x$?" } + .accept() + .respond("something-something\nx1") } val output = client.execute(ShellCommandRequest("xx"), serial = "serial") assertThat(output.output).isEqualTo("something-something\n") assertThat(output.exitCode).isEqualTo(1) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequestTest.kt index 20486c965..b79e2e413 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ChanneledShellCommandRequestTest.kt @@ -18,45 +18,40 @@ package com.malinskiy.adam.request.shell.v2 import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.junit4.AdbServerRule import io.ktor.utils.io.discard import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext +import org.junit.Rule import org.junit.Test class ChanneledShellCommandRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell,v2,raw:echo foo; echo bar >&2; exit 17") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "shell,v2,raw:echo foo; echo bar >&2; exit 17" }.accept() - val stdin = input.receiveShellV2Stdin() - assertThat(stdin).isEqualTo("cafebabe") + expectShellV2Stdin("cafebabe") + expectShellV2StdinClose() - input.receiveShellV2StdinClose() + respondShellV2Stdout("fo") + respondShellV2Stderr("ba") + respondShellV2Stdout("o\n") + respondShellV2WindowSizeChange() + respondShellV2Invalid() + respondShellV2Stderr("r\n") + respondShellV2Exit(17) - output.respondShellV2Stdout("fo") - output.respondShellV2Stderr("ba") - output.respondShellV2Stdout("o\n") - output.respondShellV2WindowSizeChange() - output.respondShellV2Invalid() - output.respondShellV2Stderr("r\n") - output.respondShellV2Exit(17) - - output.close() input.discard() } @@ -84,8 +79,6 @@ class ChanneledShellCommandRequestTest { assertThat(stdoutBuffer.toString()).isEqualTo("foo\n") assertThat(stderrBuffer.toString()).isEqualTo("bar\n") assertThat(exitCode).isEqualTo(17) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequestTest.kt index fbed1cdf2..c97b02410 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/shell/v2/ShellCommandRequestTest.kt @@ -18,35 +18,31 @@ package com.malinskiy.adam.request.shell.v2 import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.exception.RequestValidationException -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ShellCommandRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsNonStrippedStdout() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell,v2,raw:echo foo; echo bar >&2; exit 17") - output.respond(Const.Message.OKAY) - - output.respondShellV2Stdout("fo") - output.respondShellV2Stderr("ba") - output.respondShellV2Stdout("o\n") - output.respondShellV2Stderr("r\n") - output.respondShellV2Exit(17) - - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "shell,v2,raw:echo foo; echo bar >&2; exit 17" }.accept() + + respondShellV2Stdout("fo") + respondShellV2Stderr("ba") + respondShellV2Stdout("o\n") + respondShellV2Stderr("r\n") + respondShellV2Exit(17) } @@ -54,8 +50,6 @@ class ShellCommandRequestTest { assertThat(output.stdout).isEqualTo("foo\n") assertThat(output.stderr).isEqualTo("bar\n") assertThat(output.exitCode).isEqualTo(17) - - server.dispose() } } @@ -81,29 +75,16 @@ class ShellCommandRequestTest { private fun runUnsupportedTestMessage(messageType: MessageType) { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell,v2,raw:echo foo; echo bar >&2; exit 17") - output.respond(Const.Message.OKAY) - + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "shell,v2,raw:echo foo; echo bar >&2; exit 17" }.accept() output.writeByte(messageType.toValue().toByte()) - - output.close() } - val output = client.execute(ShellCommandRequest("echo foo; echo bar >&2; exit 17"), serial = "serial") assertThat(output.stdout).isEqualTo("foo\n") assertThat(output.stderr).isEqualTo("bar\n") assertThat(output.exitCode).isEqualTo(17) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/ListFilesRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/ListFilesRequestTest.kt index 885d4e06d..c5dd79634 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/ListFilesRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/ListFilesRequestTest.kt @@ -20,28 +20,27 @@ import assertk.assertThat import assertk.assertions.containsExactly import assertk.assertions.isEqualTo import assertk.assertions.isNull -import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class ListFilesRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:ls -l /sdcard/;echo x$?") - output.respond(Const.Message.OKAY) - - val response = """ + server.session { + expectCmd { "host:transport:serial" }.accept() + expectShell { "ls -l /sdcard/;echo x$?" } + .accept() + .respond( + """ total 88 -rwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 Alarms brwxrwx--x 4 root sdcard_rw 4096 2020-10-24 16:29 Android @@ -52,9 +51,8 @@ class ListFilesRequestTest { drwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 Ringtones Orwxrwx--x 2 root sdcard_rw 4096 2020-10-24 16:29 XXX x0 - """.trimIndent().toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + """.trimIndent() + ) } val files = client.execute(ListFilesRequest("/sdcard/"), serial = "serial") @@ -155,8 +153,6 @@ class ListFilesRequestTest { assertThat(files.first().size).isEqualTo(4096L) assertThat(files.first().time).isEqualTo("16:29") assertThat(files.first().type).isEqualTo(AndroidFileType.REGULAR_FILE) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequestTest.kt index 36a2b6da2..8a8d87167 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatListFileRequestTest.kt @@ -18,49 +18,42 @@ package com.malinskiy.adam.request.sync.compat import assertk.assertThat import assertk.assertions.containsExactly -import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.sync.model.FileEntryV1 import com.malinskiy.adam.request.sync.model.FileEntryV2 -import com.malinskiy.adam.server.AndroidDebugBridgeServer +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test import java.time.Instant class CompatListFileRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testV1() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val listPath = input.receiveList() - assertThat(listPath).isEqualTo("/sdcard/") - output.respondList( + expectList { "/sdcard/" } + respondList( 420, 123, 1589042331, "some-file" - ) - output.respondDone() + ).done() } val list = client.execute( CompatListFileRequest("/sdcard/", emptyList()), "serial" ) - - server.dispose() - assertThat(list).containsExactly( FileEntryV1( name = "some-file", @@ -74,20 +67,12 @@ class CompatListFileRequestTest { @Test fun testV2() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) - - val listPath = input.receiveListV2() - assertThat(listPath).isEqualTo("/sdcard/") - output.respondListV2( + expectListV2 { "/sdcard/" } + respondListV2( name = "some-file", mode = 123, size = 420, @@ -100,14 +85,12 @@ class CompatListFileRequestTest { atime = 1589042331, mtime = 1589042332, ctime = 1589042333 - ) - output.respondDone() + ).done() } val list = client.execute( CompatListFileRequest("/sdcard/", listOf(Feature.LS_V2)), "serial" ) - server.dispose() assertThat(list).containsExactly( FileEntryV2( diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatPullFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatPullFileRequestTest.kt index 20976ef33..3ab3a4eee 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatPullFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatPullFileRequestTest.kt @@ -18,12 +18,10 @@ package com.malinskiy.adam.request.sync.compat import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import io.ktor.utils.io.discard -import kotlinx.coroutines.channels.receiveOrNull import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -36,6 +34,11 @@ class CompatPullFileRequestTest { @JvmField val temp = TemporaryFolder() + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testV1() { runBlocking { @@ -43,29 +46,17 @@ class CompatPullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val recvPath = input.receiveRecv() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv { "/sdcard/testfile" } + .respondFile(fixture) + .respondDoneDone() - output.respondData(fixture.readBytes()) - output.respondDone() - output.respondDone() - - output.close() input.discard() } @@ -78,8 +69,6 @@ class CompatPullFileRequestTest { } assertThat(progress).isEqualTo(1.0) - - server.dispose() }.join() assertThat(tempFile.readBytes()).isEqualTo(fixture.readBytes()) @@ -93,29 +82,17 @@ class CompatPullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + expectRecv2 { "/sdcard/testfile" } + .respondFile(fixture) + .respondDoneDone() - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) - - val recvPath = input.receiveRecv2() - assertThat(recvPath).isEqualTo("/sdcard/testfile") - - output.respondData(fixture.readBytes()) - output.respondDone() - output.respondDone() - - output.close() input.discard() } @@ -127,8 +104,6 @@ class CompatPullFileRequestTest { progress = update } assertThat(progress).isEqualTo(1.0) - - server.dispose() }.join() assertThat(tempFile.readBytes()).isEqualTo(fixture.readBytes()) diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatPushFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatPushFileRequestTest.kt index 45a530081..7c2aa902d 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatPushFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatPushFileRequestTest.kt @@ -18,12 +18,10 @@ package com.malinskiy.adam.request.sync.compat import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import io.ktor.utils.io.discard -import kotlinx.coroutines.channels.receiveOrNull import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -36,6 +34,11 @@ class CompatPushFileRequestTest { @JvmField val temp = TemporaryFolder() + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testV1() { runBlocking { @@ -43,26 +46,16 @@ class CompatPushFileRequestTest { val receiveFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - + server.session { + expectCmd { "host:transport:serial" }.accept() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + expectCmd { "sync:" }.accept() - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) - - val receiveCmd = input.receiveSend() - assertThat(receiveCmd).isEqualTo("/sdcard/testfile,511") - input.receiveFile(receiveFile) - output.respond(Const.Message.OKAY) + expectSend { "/sdcard/testfile,511" } + .receiveFile(receiveFile) + .done() input.discard() - - output.close() } val request = CompatPushFileRequest(fixture, "/sdcard/testfile", emptyList(), this) @@ -74,7 +67,6 @@ class CompatPushFileRequestTest { } assertThat(progress).isEqualTo(1.0) - server.dispose() }.join() assertThat(receiveFile.readBytes()).isEqualTo(fixture.readBytes()) @@ -88,25 +80,15 @@ class CompatPushFileRequestTest { var receiveFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + expectSendV2("/sdcard/testfile", "777", 0) + .receiveFile(receiveFile) + .done() - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) - - val (receiveCmd, mode, flags) = input.receiveSendV2() - assertThat(receiveCmd).isEqualTo("/sdcard/testfile") - assertThat(mode.toString(8)).isEqualTo("777") - assertThat(flags).isEqualTo(0) - - input.receiveFile(receiveFile) - output.respond(Const.Message.OKAY) - output.close() + input.discard() } val request = CompatPushFileRequest(fixture, "/sdcard/testfile", listOf(Feature.SENDRECV_V2), this) @@ -118,7 +100,6 @@ class CompatPushFileRequestTest { } assertThat(progress).isEqualTo(1.0) - server.dispose() }.join() assertThat(receiveFile.readBytes()).isEqualTo(fixture.readBytes()) diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequestTest.kt index df6bb8643..f722fd777 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/compat/CompatStatFileRequestTest.kt @@ -18,36 +18,31 @@ package com.malinskiy.adam.request.sync.compat import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.sync.model.FileEntryV1 import com.malinskiy.adam.request.sync.model.FileEntryV2 -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test import java.time.Instant class CompatStatFileRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testV1() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val receiveStat = input.receiveStat() - assertThat(receiveStat).isEqualTo("/sdcard/testfile") - - output.respondStat(128, 0x744, 10000) - output.close() + expectStat { "/sdcard/testfile" } + respondStat(128, 0x744, 10000) } val result = client.execute(CompatStatFileRequest("/sdcard/testfile", emptyList()), serial = "serial") @@ -55,29 +50,18 @@ class CompatStatFileRequestTest { assertThat(output.mtime).isEqualTo(Instant.ofEpochSecond(10000)) assertThat(output.mode).isEqualTo(0x744.toUInt()) assertThat(output.size).isEqualTo(128.toUInt()) - - server.dispose() } } @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("sync:") - output.respond(Const.Message.OKAY) - - val receiveStat = input.receiveStatV2() - assertThat(receiveStat).isEqualTo("/sdcard/testfile") - - output.respondStatV2( + expectStatV2 { "/sdcard/testfile" } + respondStatV2( mode = 123, size = 420, error = 0, @@ -90,7 +74,6 @@ class CompatStatFileRequestTest { mtime = 1589042332, ctime = 1589042333 ) - output.close() } val result = client.execute(CompatStatFileRequest("/sdcard/testfile", listOf(Feature.STAT_V2)), serial = "serial") @@ -110,8 +93,6 @@ class CompatStatFileRequestTest { ctime = Instant.ofEpochSecond(1589042333) ) ) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequestTest.kt index 8339afd4b..919aae4cc 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/ListFileRequestTest.kt @@ -19,36 +19,33 @@ package com.malinskiy.adam.request.sync.v1 import assertk.assertThat import assertk.assertions.containsExactly import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.request.sync.model.FileEntryV1 -import com.malinskiy.adam.server.AndroidDebugBridgeServer +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test import java.time.Instant class ListFileRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val listPath = input.receiveList() - assertThat(listPath).isEqualTo("/sdcard/") - output.respondList( + expectList { "/sdcard/" } + respondList( 420, 123, 1589042331, "some-file" - ) - output.respondDone() + ).done() } val list = client.execute( @@ -56,8 +53,6 @@ class ListFileRequestTest { ) - server.dispose() - assertThat(list).containsExactly( FileEntryV1( name = "some-file", diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequestTest.kt index 43d6229c5..c01a92f87 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PullFileRequestTest.kt @@ -18,14 +18,13 @@ package com.malinskiy.adam.request.sync.v1 import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const import com.malinskiy.adam.exception.PullFailedException import com.malinskiy.adam.exception.UnsupportedSyncProtocolException -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import io.ktor.utils.io.discard import io.ktor.utils.io.writeIntLittleEndian -import kotlinx.coroutines.channels.receiveOrNull import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -39,6 +38,11 @@ class PullFileRequestTest { @JvmField val temp = TemporaryFolder() + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { assertThat(String(PullFileRequest("/sdcard/testfile", File("/tmp/testfile")).serialize(), Const.DEFAULT_TRANSPORT_ENCODING)) @@ -52,29 +56,17 @@ class PullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val recvPath = input.receiveRecv() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv { "/sdcard/testfile" } + .respondFile(fixture) + .respondDoneDone() - output.respondData(fixture.readBytes()) - output.respondDone() - output.respondDone() - - output.close() input.discard() } @@ -87,8 +79,6 @@ class PullFileRequestTest { } assertThat(progress).isEqualTo(1.0) - - server.dispose() }.join() assertThat(tempFile.readBytes()).isEqualTo(fixture.readBytes()) @@ -102,33 +92,22 @@ class PullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) - - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) - - val recvPath = input.receiveRecv() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv { "/sdcard/testfile" } val fileBytes = fixture.readBytes().asSequence().chunked(100) val iterator = fileBytes.iterator() while (iterator.hasNext()) { output.respondData(iterator.next().toByteArray()) } - output.respondDone() - output.respondDone() + output.respondDoneDone() - output.close() input.discard() } @@ -141,8 +120,6 @@ class PullFileRequestTest { } assertThat(progress).isEqualTo(1.0) - - server.dispose() }.join() assertThat(tempFile.readBytes()).isEqualTo(fixture.readBytes()) @@ -155,28 +132,17 @@ class PullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) - - val recvPath = input.receiveRecv() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv { "/sdcard/testfile" } output.respond(Const.Message.FAIL) - val message = "lorem ipsum" - output.writeIntLittleEndian(message.length) - output.respondData(message.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING)) + output.respondStringV2("lorem ipsum") } val request = PullFileRequest("/sdcard/testfile", tempFile) @@ -186,8 +152,6 @@ class PullFileRequestTest { while (!execute.isClosedForReceive) { progress = execute.receiveOrNull() ?: break } - - server.dispose() }.join() } @@ -197,23 +161,14 @@ class PullFileRequestTest { val fixture = File(PullFileRequestTest::class.java.getResource("/fixture/sample.yaml").file) val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val recvPath = input.receiveRecv() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv { "/sdcard/testfile" } output.respond(Const.Message.DATA) output.writeIntLittleEndian(Const.MAX_FILE_PACKET_LENGTH + 1) @@ -226,8 +181,6 @@ class PullFileRequestTest { while (!execute.isClosedForReceive) { progress = execute.receiveOrNull() ?: break } - - server.dispose() }.join() } } @@ -239,23 +192,14 @@ class PullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) - - val recvPath = input.receiveRecv() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv { "/sdcard/testfile" } output.respond(Const.Message.SEND_V1) output.respond(Const.Message.SEND_V1) @@ -268,8 +212,6 @@ class PullFileRequestTest { while (!execute.isClosedForReceive) { progress = execute.receiveOrNull() ?: break } - - server.dispose() }.join() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequestTest.kt index 08eb7d0ad..0b2f50b67 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/PushFileRequestTest.kt @@ -18,11 +18,10 @@ package com.malinskiy.adam.request.sync.v1 import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const import com.malinskiy.adam.exception.PushFailedException -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close -import kotlinx.coroutines.channels.receiveOrNull +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -36,6 +35,11 @@ class PushFileRequestTest { @JvmField val temp = TemporaryFolder() + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { val testFile = temp.newFile("adam") @@ -52,22 +56,13 @@ class PushFileRequestTest { val receiveFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) - - val receiveCmd = input.receiveSend() - assertThat(receiveCmd).isEqualTo("/sdcard/testfile,511") - input.receiveFile(receiveFile) - output.respond(Const.Message.OKAY) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() + + expectSend { "/sdcard/testfile,511" } + .receiveFile(receiveFile) + .done() } val request = PushFileRequest(fixture, "/sdcard/testfile") @@ -79,7 +74,6 @@ class PushFileRequestTest { } assertThat(progress).isEqualTo(1.0) - server.dispose() }.join() assertThat(receiveFile!!.readBytes()).isEqualTo(fixture.readBytes()) @@ -93,25 +87,14 @@ class PushFileRequestTest { val receiveFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) - - val receiveCmd = input.receiveSend() - assertThat(receiveCmd).isEqualTo("/sdcard/testfile,511") - input.receiveFile(receiveFile) - output.respond(Const.Message.FAIL) - val s = "CAFEBABE" - output.writeFully("0008".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING), 0, 4) - output.writeFully(s.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING), 0, s.length) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + + expectCmd { "sync:" }.accept() + + expectSend { "/sdcard/testfile,511" } + .receiveFile(receiveFile) + .fail("CAFEBABE") } val request = PushFileRequest(fixture, "/sdcard/testfile") @@ -121,7 +104,6 @@ class PushFileRequestTest { while (!execute.isClosedForReceive) { progress = execute.receiveOrNull() ?: break } - server.dispose() }.join() diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequestTest.kt index 0c2814e7f..43feebf62 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v1/StatFileRequestTest.kt @@ -18,42 +18,35 @@ package com.malinskiy.adam.request.sync.v1 import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test import java.time.Instant class StatFileRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val receiveStat = input.receiveStat() - assertThat(receiveStat).isEqualTo("/sdcard/testfile") - - output.respondStat(128, 0x744, 10000) - output.close() + expectStat { "/sdcard/testfile" } + respondStat(128, 0x744, 10000) } val output = client.execute(StatFileRequest("/sdcard/testfile"), serial = "serial") assertThat(output.mtime).isEqualTo(Instant.ofEpochSecond(10000)) assertThat(output.mode).isEqualTo(0x744.toUInt()) assertThat(output.size).isEqualTo(128.toUInt()) - - server.dispose() } } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequestTest.kt index a6edb7970..de44697a7 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/ListFileRequestTest.kt @@ -19,31 +19,30 @@ package com.malinskiy.adam.request.sync.v2 import assertk.assertThat import assertk.assertions.containsExactly import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.sync.model.FileEntryV2 -import com.malinskiy.adam.server.AndroidDebugBridgeServer +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test import java.time.Instant class ListFileRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() = runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + expectCmd { "sync:" }.accept() - val listPath = input.receiveListV2() - assertThat(listPath).isEqualTo("/sdcard/") - output.respondListV2( + expectListV2 { "/sdcard/" } + respondListV2( name = "some-file", mode = 123, size = 420, @@ -63,7 +62,6 @@ class ListFileRequestTest { val list = client.execute( ListFileRequest("/sdcard/", listOf(Feature.LS_V2)), "serial" ) - server.dispose() assertThat(list).containsExactly( FileEntryV2( diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequestTest.kt index 36d11a9bb..fb42d58b0 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PullFileRequestTest.kt @@ -18,15 +18,14 @@ package com.malinskiy.adam.request.sync.v2 import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const import com.malinskiy.adam.exception.PullFailedException import com.malinskiy.adam.exception.UnsupportedSyncProtocolException import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import io.ktor.utils.io.discard import io.ktor.utils.io.writeIntLittleEndian -import kotlinx.coroutines.channels.receiveOrNull import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -40,6 +39,11 @@ class PullFileRequestTest { @JvmField val temp = TemporaryFolder() + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { assertThat( @@ -58,29 +62,17 @@ class PullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) - - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val recvPath = input.receiveRecv2() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - output.respondData(fixture.readBytes()) - output.respondDone() - output.respondDone() + expectRecv2 { "/sdcard/testfile" } + .respondFile(fixture) + .respondDoneDone() - output.close() input.discard() } @@ -94,8 +86,6 @@ class PullFileRequestTest { } assertThat(progress).isEqualTo(1.0) - - server.dispose() }.join() assertThat(tempFile.readBytes()).isEqualTo(fixture.readBytes()) @@ -109,30 +99,21 @@ class PullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val recvPath = input.receiveRecv2() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv2 { "/sdcard/testfile" } val fileBytes = fixture.readBytes().asSequence().chunked(100) val iterator = fileBytes.iterator() while (iterator.hasNext()) { output.respondData(iterator.next().toByteArray()) } - output.respondDone() - output.respondDone() + output.respondDoneDone() } val request = @@ -145,8 +126,6 @@ class PullFileRequestTest { } assertThat(progress).isEqualTo(1.0) - - server.dispose() }.join() assertThat(tempFile.readBytes()).isEqualTo(fixture.readBytes()) @@ -159,28 +138,17 @@ class PullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) - - val recvPath = input.receiveRecv2() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv2 { "/sdcard/testfile" } output.respond(Const.Message.FAIL) - val message = "lorem ipsum" - output.writeIntLittleEndian(message.length) - output.respondData(message.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING)) + output.respondStringV2("lorem ipsum") } val request = PullFileRequest("/sdcard/testfile", tempFile, listOf(Feature.SENDRECV_V2)) @@ -190,8 +158,6 @@ class PullFileRequestTest { while (!execute.isClosedForReceive) { progress = execute.receiveOrNull() ?: break } - - server.dispose() }.join() } @@ -202,23 +168,14 @@ class PullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val recvPath = input.receiveRecv2() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv2 { "/sdcard/testfile" } output.respond(Const.Message.DATA) output.writeIntLittleEndian(Const.MAX_FILE_PACKET_LENGTH + 1) @@ -231,8 +188,6 @@ class PullFileRequestTest { while (!execute.isClosedForReceive) { progress = execute.receiveOrNull() ?: break } - - server.dispose() }.join() } } @@ -244,23 +199,14 @@ class PullFileRequestTest { val tempFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + expectStat { "/sdcard/testfile" } + respondStat(size = fixture.length().toInt()) - val statPath = input.receiveStat() - assertThat(statPath).isEqualTo("/sdcard/testfile") - output.respondStat(fixture.length().toInt()) - - val recvPath = input.receiveRecv2() - assertThat(recvPath).isEqualTo("/sdcard/testfile") + expectRecv2 { "/sdcard/testfile" } output.respond(Const.Message.SEND_V1) output.respond(Const.Message.SEND_V1) @@ -273,8 +219,6 @@ class PullFileRequestTest { while (!execute.isClosedForReceive) { progress = execute.receiveOrNull() ?: break } - - server.dispose() }.join() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequestTest.kt index 2a5012fcc..0968bc579 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/PushFileRequestTest.kt @@ -18,12 +18,11 @@ package com.malinskiy.adam.request.sync.v2 import assertk.assertThat import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const import com.malinskiy.adam.exception.PushFailedException import com.malinskiy.adam.request.Feature -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close -import kotlinx.coroutines.channels.receiveOrNull +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -37,6 +36,11 @@ class PushFileRequestTest { @JvmField val temp = TemporaryFolder() + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { val testFile = temp.newFile("adam") @@ -53,25 +57,13 @@ class PushFileRequestTest { val receiveFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val (receiveCmd, mode, flags) = input.receiveSendV2() - assertThat(receiveCmd).isEqualTo("/sdcard/testfile") - assertThat(mode.toString(8)).isEqualTo("777") - assertThat(flags).isEqualTo(0) - - input.receiveFile(receiveFile) - output.respond(Const.Message.OKAY) - output.close() + expectSendV2("/sdcard/testfile", "777", 0) + .receiveFile(receiveFile) + .done() } val request = PushFileRequest(fixture, "/sdcard/testfile", listOf(Feature.SENDRECV_V2)) @@ -83,7 +75,6 @@ class PushFileRequestTest { } assertThat(progress).isEqualTo(1.0) - server.dispose() }.join() @@ -98,28 +89,13 @@ class PushFileRequestTest { val receiveFile = temp.newFile() launch { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val actualCommand = input.receiveCommand() - assertThat(actualCommand).isEqualTo("sync:") - output.respond(Const.Message.OKAY) - - val (receiveCmd, mode, flags) = input.receiveSendV2() - assertThat(receiveCmd).isEqualTo("/sdcard/testfile") - assertThat(mode.toString(8)).isEqualTo("777") - assertThat(flags).isEqualTo(0) - - input.receiveFile(receiveFile) - output.respond(Const.Message.FAIL) - val s = "CAFEBABE" - output.writeFully("0008".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING), 0, 4) - output.writeFully(s.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING), 0, s.length) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() + + expectSendV2("/sdcard/testfile", "777", 0) + .receiveFile(receiveFile) + .fail("CAFEBABE") } val request = PushFileRequest(fixture, "/sdcard/testfile", listOf(Feature.SENDRECV_V2)) @@ -131,8 +107,6 @@ class PushFileRequestTest { } assertThat(receiveFile!!.readBytes()).isEqualTo(fixture.readBytes()) - - server.dispose() }.join() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequestTest.kt index 5d68e83a5..4e0309956 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/sync/v2/StatFileRequestTest.kt @@ -18,35 +18,31 @@ package com.malinskiy.adam.request.sync.v2 import assertk.assertThat import assertk.assertions.isEqualTo -import com.malinskiy.adam.Const +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.request.Feature import com.malinskiy.adam.request.sync.model.FileEntryV2 -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import io.ktor.utils.io.close +import com.malinskiy.adam.server.junit4.AdbServerRule import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test import java.time.Instant class StatFileRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testReturnsProperContent() { runBlocking { - val server = AndroidDebugBridgeServer() - - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("sync:") - output.respond(Const.Message.OKAY) + server.session { + expectCmd { "host:transport:serial" }.accept() + expectCmd { "sync:" }.accept() - val receiveStat = input.receiveStatV2() - assertThat(receiveStat).isEqualTo("/sdcard/testfile") - - output.respondStatV2( + expectStatV2 { "/sdcard/testfile" } + respondStatV2( mode = 123, size = 420, error = 0, @@ -59,7 +55,6 @@ class StatFileRequestTest { mtime = 1589042332, ctime = 1589042333 ) - output.close() } val output: FileEntryV2 = client.execute(StatFileRequest("/sdcard/testfile", listOf(Feature.STAT_V2)), serial = "serial") @@ -78,8 +73,6 @@ class StatFileRequestTest { ctime = Instant.ofEpochSecond(1589042333) ) ) - - server.dispose() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequestTest.kt b/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequestTest.kt index 1217f6b62..f7cd04ce4 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequestTest.kt +++ b/adam/src/test/kotlin/com/malinskiy/adam/request/testrunner/TestRunnerRequestTest.kt @@ -19,20 +19,26 @@ package com.malinskiy.adam.request.testrunner import assertk.assertThat import assertk.assertions.containsOnly import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.Const -import com.malinskiy.adam.server.AndroidDebugBridgeServer -import com.malinskiy.adam.server.StubSocket +import com.malinskiy.adam.server.junit4.AdbServerRule +import com.malinskiy.adam.server.stub.StubSocket import com.malinskiy.adam.transport.use import io.ktor.utils.io.ByteChannel import io.ktor.utils.io.close import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel.Factory.BUFFERED -import kotlinx.coroutines.channels.receiveOrNull import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import org.junit.Rule import org.junit.Test class TestRunnerRequestTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + @Test fun testSerialize() { val request = TestRunnerRequest( @@ -71,19 +77,11 @@ class TestRunnerRequestTest { fun testReturnsContentOnFailure() { runBlocking { launch { - val server = AndroidDebugBridgeServer() - val client = server.startAndListen { input, output -> - val transportCmd = input.receiveCommand() - assertThat(transportCmd).isEqualTo("host:transport:serial") - output.respond(Const.Message.OKAY) - - val shellCmd = input.receiveCommand() - assertThat(shellCmd).isEqualTo("shell:am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner") - output.respond(Const.Message.OKAY) - - val response = "something-something".toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - output.writeFully(response, 0, response.size) - output.close() + server.session { + expectCmd { "host:transport:serial" }.accept() + expectShell { "am instrument -w -r com.example.test/android.support.test.runner.AndroidJUnitRunner" } + .accept() + .respond("something-something") } val channel = client.execute( @@ -98,8 +96,6 @@ class TestRunnerRequestTest { } assertThat(events).containsOnly(TestRunFailed("No test results\nsomething-something")) - - server.dispose() }.join() } } diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 878eda419..3d80b9784 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -11,6 +11,8 @@ object Versions { val assertk = "0.19" val junit4 = "4.12" + val junit5 = "5.4.2" + val junit5commons = "1.7.2" val imageComparison = "4.3.0" val dokka = "1.4.20" val coroutinesDebug = "1.4.0" @@ -52,6 +54,8 @@ object AndroidX { object TestLibraries { val assertk = "com.willowtreeapps.assertk:assertk:${Versions.assertk}" val junit4 = "junit:junit:${Versions.junit4}" + val junit5 = "org.junit.jupiter:junit-jupiter-engine:${Versions.junit5}" + val junit5commons = "org.junit.platform:junit-platform-commons:${Versions.junit5commons}" val imageComparison = "com.github.romankh3:image-comparison:${Versions.imageComparison}" val coroutinesDebug = "org.jetbrains.kotlinx:kotlinx-coroutines-debug:${Versions.coroutinesDebug}" } diff --git a/server/server-stub-junit4/build.gradle.kts b/server/server-stub-junit4/build.gradle.kts new file mode 100644 index 000000000..4e8d1d483 --- /dev/null +++ b/server/server-stub-junit4/build.gradle.kts @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + kotlin("jvm") + id("jacoco") +} + +Deployment.initialize(project) + +tasks.jacocoTestReport { + reports { + xml.isEnabled = true + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class) { + kotlinOptions.jvmTarget = "1.8" + kotlinOptions.apiVersion = "1.4" +} + +dependencies { + api(project(":server:server-stub")) + implementation(TestLibraries.junit4) + implementation(Libraries.coroutines) + + testImplementation(TestLibraries.coroutinesDebug) +} diff --git a/server/server-stub-junit4/src/main/kotlin/com/malinskiy/adam/server/junit4/AdbServerRule.kt b/server/server-stub-junit4/src/main/kotlin/com/malinskiy/adam/server/junit4/AdbServerRule.kt new file mode 100644 index 000000000..d73600524 --- /dev/null +++ b/server/server-stub-junit4/src/main/kotlin/com/malinskiy/adam/server/junit4/AdbServerRule.kt @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.junit4 + +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.stub.AndroidDebugBridgeServer +import com.malinskiy.adam.server.stub.dsl.Session +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement + +class AdbServerRule : TestRule { + lateinit var server: AndroidDebugBridgeServer + val client: AndroidDebugBridgeClient + get() = server.client + + override fun apply(base: Statement, description: Description): Statement { + return object : Statement() { + override fun evaluate() { + server = AndroidDebugBridgeServer() + server.start() + + try { + base.evaluate() + } finally { + runBlocking { + withContext(NonCancellable) { + server.dispose() + } + } + } + } + } + } + + fun session(block: suspend Session.() -> Unit) { + server.session(block) + } +} + diff --git a/server/server-stub-junit4/src/test/kotlin/com/malinskiy/adam/server/junit4/AdbServerRuleTest.kt b/server/server-stub-junit4/src/test/kotlin/com/malinskiy/adam/server/junit4/AdbServerRuleTest.kt new file mode 100644 index 000000000..771c1fd98 --- /dev/null +++ b/server/server-stub-junit4/src/test/kotlin/com/malinskiy/adam/server/junit4/AdbServerRuleTest.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.junit4 + +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.request.misc.GetAdbServerVersionRequest +import kotlinx.coroutines.runBlocking +import org.junit.Rule +import org.junit.Test + +class AdbServerRuleTest { + @get:Rule + val server = AdbServerRule() + val client: AndroidDebugBridgeClient + get() = server.client + + @Test + fun test() { + server.session { + expectAdbServerVersion() + .accept() + .respondAdbServerVersion(41) + } + + runBlocking { + val version = client.execute(GetAdbServerVersionRequest()) + assert(version == 41) + } + } +} diff --git a/server/server-stub-junit5/build.gradle.kts b/server/server-stub-junit5/build.gradle.kts new file mode 100644 index 000000000..42bf1cc5d --- /dev/null +++ b/server/server-stub-junit5/build.gradle.kts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + kotlin("jvm") + id("jacoco") +} + +Deployment.initialize(project) + +tasks.jacocoTestReport { + reports { + xml.isEnabled = true + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class) { + kotlinOptions.jvmTarget = "1.8" + kotlinOptions.apiVersion = "1.4" +} + +dependencies { + api(project(":server:server-stub")) + implementation(TestLibraries.junit5) + implementation(TestLibraries.junit5commons) + implementation(kotlin("reflect", version = Versions.kotlin)) + implementation(Libraries.coroutines) + + testImplementation(TestLibraries.coroutinesDebug) +} diff --git a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbClient.kt b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbClient.kt new file mode 100644 index 000000000..068db20d8 --- /dev/null +++ b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbClient.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.junit5 + +@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.RUNTIME) +annotation class AdbClient diff --git a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServer.kt b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServer.kt new file mode 100644 index 000000000..6c798e109 --- /dev/null +++ b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServer.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.junit5 + +@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.RUNTIME) +annotation class AdbServer diff --git a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtension.kt b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtension.kt new file mode 100644 index 000000000..85f0b19b0 --- /dev/null +++ b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtension.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.junit5 + +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.server.stub.AndroidDebugBridgeServer +import com.malinskiy.adam.server.stub.dsl.Session +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext +import org.junit.jupiter.api.extension.AfterEachCallback +import org.junit.jupiter.api.extension.BeforeEachCallback +import org.junit.jupiter.api.extension.ExtensionContext +import kotlin.reflect.KMutableProperty +import kotlin.reflect.full.createType +import kotlin.reflect.full.hasAnnotation +import kotlin.reflect.full.isSubtypeOf +import kotlin.reflect.full.memberProperties + + +class AdbServerExtension : BeforeEachCallback, AfterEachCallback { + lateinit var server: AndroidDebugBridgeServer + val client: AndroidDebugBridgeClient + get() = server.client + + fun session(block: suspend Session.() -> Unit) { + server.listen { input, output -> + val session = Session(input, output) + block(session) + } + } + + override fun beforeEach(context: ExtensionContext) { + server = AndroidDebugBridgeServer() + server.start() + + setupServerField(context) + setupClientField(context) + } + + private fun setupServerField(context: ExtensionContext) { + val instance = context.testInstance.get() + instance::class.memberProperties + .filter { it.hasAnnotation() && it.returnType.isSubtypeOf(AndroidDebugBridgeServer::class.createType()) } + .filterIsInstance>() + .forEach { prop -> + prop.setter.call(instance, server) + } + } + + private fun setupClientField(context: ExtensionContext) { + val instance = context.testInstance.get() + instance::class.memberProperties + .filter { it.hasAnnotation() && it.returnType.isSubtypeOf(AndroidDebugBridgeClient::class.createType()) } + .filterIsInstance>() + .forEach { prop -> + prop.setter.call(instance, client) + } + } + + override fun afterEach(context: ExtensionContext?) { + runBlocking { + withContext(NonCancellable) { + server.dispose() + } + } + } +} + diff --git a/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbTest.kt b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbTest.kt new file mode 100644 index 000000000..f2a4d89c2 --- /dev/null +++ b/server/server-stub-junit5/src/main/kotlin/com/malinskiy/adam/server/junit5/AdbTest.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.junit5 + +import org.junit.jupiter.api.extension.ExtendWith +import java.lang.annotation.Inherited + +@Target(AnnotationTarget.CLASS) +@ExtendWith(AdbServerExtension::class) +@Inherited +@Retention(AnnotationRetention.RUNTIME) +annotation class AdbTest diff --git a/server/server-stub-junit5/src/test/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtensionTest.kt b/server/server-stub-junit5/src/test/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtensionTest.kt new file mode 100644 index 000000000..f17dadd22 --- /dev/null +++ b/server/server-stub-junit5/src/test/kotlin/com/malinskiy/adam/server/junit5/AdbServerExtensionTest.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.junit5 + +import assertk.assertThat +import assertk.assertions.isEqualTo +import com.malinskiy.adam.AndroidDebugBridgeClient +import com.malinskiy.adam.request.misc.GetAdbServerVersionRequest +import com.malinskiy.adam.request.shell.v1.ShellCommandRequest +import com.malinskiy.adam.server.stub.AndroidDebugBridgeServer +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(AdbServerExtension::class) +class AdbServerExtensionTest { + @AdbClient + lateinit var client: AndroidDebugBridgeClient + + @AdbServer + lateinit var server: AndroidDebugBridgeServer + + @Test + fun testX() { + server.session { + expectAdbServerVersion() + .accept() + .respondAdbServerVersion(41) + } + + runBlocking { + val version = client.execute(GetAdbServerVersionRequest()) + assert(version == 41) + } + } + + @Test + fun testMultisession() { + runBlocking { + server.multipleSessions { + serial("emulator-5554") { + session { + respondOkay() + expectShell { "echo 1;echo x$?" }.accept().respond("1x0") + } + session { + respondOkay() + expectShell { "echo 3;echo x$?" }.accept().respond("3x0") + } + } + serial("emulator-5556") { + session { + respondOkay() + expectShell { "echo 2;echo x$?" }.accept().respond("2x0") + } + session { + respondOkay() + expectShell { "echo 4;echo x$?" }.accept().respond("4x0") + } + } + } + + assertThat(client.execute(ShellCommandRequest("echo 1"), "emulator-5554").output).isEqualTo("1") + assertThat(client.execute(ShellCommandRequest("echo 2"), "emulator-5556").output).isEqualTo("2") + assertThat(client.execute(ShellCommandRequest("echo 3"), "emulator-5554").output).isEqualTo("3") + assertThat(client.execute(ShellCommandRequest("echo 4"), "emulator-5556").output).isEqualTo("4") + } + } +} diff --git a/server/server-stub/build.gradle.kts b/server/server-stub/build.gradle.kts new file mode 100644 index 000000000..ad6ecbc6a --- /dev/null +++ b/server/server-stub/build.gradle.kts @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + kotlin("jvm") + id("jacoco") +} + +Deployment.initialize(project) + +sourceSets { + create("integrationTest") { + compileClasspath += sourceSets.main.get().output + runtimeClasspath += sourceSets.main.get().output + } +} + +val integrationTestImplementation: Configuration by configurations.getting { + extendsFrom(configurations.implementation.get()) +} + +configurations["integrationTestRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get()) + +fun DependencyHandler.`integrationTestImplementation`(dependencyNotation: Any): Dependency? = + add("integrationTestImplementation", dependencyNotation) + + +val integrationTest = task("integrationTest") { + description = "Runs integration tests" + group = "verification" + + testClassesDirs = sourceSets["integrationTest"].output.classesDirs + classpath = sourceSets["integrationTest"].runtimeClasspath + shouldRunAfter("test") + + jacoco { + include("**") + } +} +integrationTest.outputs.upToDateWhen { false } + +val jacocoIntegrationTestReport = task("jacocoIntegrationTestReport") { + description = "Generates code coverage report for integrationTest task" + group = "verification" + reports { + xml.isEnabled = true + } + + executionData(integrationTest) + sourceSets(sourceSets.getByName("integrationTest")) + classDirectories.setFrom(sourceSets.getByName("main").output.classesDirs) +} +tasks.check { dependsOn(integrationTest, jacocoIntegrationTestReport) } + +tasks.jacocoTestReport { + reports { + xml.isEnabled = true + } +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class) { + kotlinOptions.jvmTarget = "1.8" + kotlinOptions.apiVersion = "1.4" +} + +dependencies { + implementation(kotlin("stdlib-jdk8", version = Versions.kotlin)) + implementation(Libraries.coroutines) + api(project(":adam")) + api(Libraries.ktorNetwork) + api(TestLibraries.assertk) + + testImplementation(TestLibraries.junit4) + testImplementation(TestLibraries.coroutinesDebug) + + integrationTestImplementation(TestLibraries.junit4) + integrationTestImplementation(TestLibraries.coroutinesDebug) +} diff --git a/adam/src/test/kotlin/com/malinskiy/adam/server/AndroidDebugBridgeServer.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/AndroidDebugBridgeServer.kt similarity index 60% rename from adam/src/test/kotlin/com/malinskiy/adam/server/AndroidDebugBridgeServer.kt rename to server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/AndroidDebugBridgeServer.kt index ce400ee41..c3fa5f75f 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/server/AndroidDebugBridgeServer.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/AndroidDebugBridgeServer.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Anton Malinskiy + * Copyright (C) 2021 Anton Malinskiy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,12 @@ * limitations under the License. */ -package com.malinskiy.adam.server +package com.malinskiy.adam.server.stub import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.AndroidDebugBridgeClientFactory +import com.malinskiy.adam.server.stub.dsl.Expectation +import com.malinskiy.adam.server.stub.dsl.Session import io.ktor.network.selector.ActorSelectorManager import io.ktor.network.sockets.ServerSocket import io.ktor.network.sockets.aSocket @@ -31,6 +33,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.async +import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.isActive import kotlinx.coroutines.newFixedThreadPoolContext import java.net.InetSocketAddress import kotlin.coroutines.CoroutineContext @@ -43,28 +47,60 @@ class AndroidDebugBridgeServer : CoroutineScope { override val coroutineContext: CoroutineContext get() = executionDispatcher + val client: AndroidDebugBridgeClient by lazy { + AndroidDebugBridgeClientFactory().apply { + port = this@AndroidDebugBridgeServer.port + }.build() + } + private val job = SupervisorJob() var port: Int = 0 lateinit var server: ServerSocket + lateinit var selector: ActorSelectorManager fun start(): AndroidDebugBridgeClient { val address = InetSocketAddress("127.0.0.1", port) - server = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().bind(address) + selector = ActorSelectorManager(Dispatchers.IO) + server = aSocket(selector).tcp().bind(address) port = server.localAddress.port - return AndroidDebugBridgeClientFactory().apply { - port = this@AndroidDebugBridgeServer.port - }.build() + return client } - suspend fun startAndListen(block: suspend (ServerReadChannel, ServerWriteChannel) -> Unit): AndroidDebugBridgeClient { - val client = start() - listen(block) - return client + fun session(block: suspend Session.() -> Unit) { + listen { input, output -> + val session = Session(input, output) + block(session) + } } - fun listen(block: suspend (ServerReadChannel, ServerWriteChannel) -> Unit) { + fun multipleSessions(block: suspend Expectation.() -> Unit) { + async(context = job) { + val expectation = Expectation() + block(expectation) + + while (isActive) { + val socket = server.accept() + val input = socket.openReadChannel().toServerReadChannel() + val output = socket.openWriteChannel(autoFlush = true).toServerWriteChannel() + + try { + val session = Session(input, output) + if (!expectation.select(session)) { + throw RuntimeException("No handler registered for request") + } + } catch (e: Throwable) { + e.printStackTrace() + } finally { + output.close() + socket.close() + } + } + } + } + + fun listen(block: suspend (input: ServerReadChannel, output: ServerWriteChannel) -> Unit) { async(context = job) { try { val socket = server.accept() @@ -88,8 +124,12 @@ class AndroidDebugBridgeServer : CoroutineScope { suspend fun dispose() { if (job.isActive) { job.complete() + job.children.iterator().forEach { + if (!it.isCancelled) job.cancelChildren() + } job.join() } + selector.close() } } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/server/ConsoleReadChannel.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleReadChannel.kt similarity index 96% rename from adam/src/test/kotlin/com/malinskiy/adam/server/ConsoleReadChannel.kt rename to server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleReadChannel.kt index 74ef641a0..6ddf4d21e 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/server/ConsoleReadChannel.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleReadChannel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.malinskiy.adam.server +package com.malinskiy.adam.server.stub import assertk.assertThat import assertk.assertions.isEqualTo diff --git a/adam/src/test/kotlin/com/malinskiy/adam/server/ConsoleWriteChannel.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleWriteChannel.kt similarity index 97% rename from adam/src/test/kotlin/com/malinskiy/adam/server/ConsoleWriteChannel.kt rename to server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleWriteChannel.kt index 4043826c9..026df0f08 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/server/ConsoleWriteChannel.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ConsoleWriteChannel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.malinskiy.adam.server +package com.malinskiy.adam.server.stub import io.ktor.utils.io.ByteWriteChannel import io.ktor.utils.io.writeStringUtf8 diff --git a/adam/src/test/kotlin/com/malinskiy/adam/server/EmulatorConsoleServer.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/EmulatorConsoleServer.kt similarity index 97% rename from adam/src/test/kotlin/com/malinskiy/adam/server/EmulatorConsoleServer.kt rename to server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/EmulatorConsoleServer.kt index cdefe2ebc..6c7ae1aa1 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/server/EmulatorConsoleServer.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/EmulatorConsoleServer.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Anton Malinskiy + * Copyright (C) 2021 Anton Malinskiy * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.malinskiy.adam.server +package com.malinskiy.adam.server.stub import com.malinskiy.adam.AndroidDebugBridgeClient import com.malinskiy.adam.AndroidDebugBridgeClientFactory diff --git a/adam/src/test/kotlin/com/malinskiy/adam/server/ServerReadChannel.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerReadChannel.kt similarity index 99% rename from adam/src/test/kotlin/com/malinskiy/adam/server/ServerReadChannel.kt rename to server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerReadChannel.kt index 24d9928ba..28c8f389d 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/server/ServerReadChannel.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerReadChannel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.malinskiy.adam.server +package com.malinskiy.adam.server.stub import assertk.assertThat import assertk.assertions.isEqualTo @@ -179,6 +179,8 @@ class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel when { header.contentEquals(Const.Message.DONE) -> { + channel.flush() + channel.close() return file } header.contentEquals(Const.Message.DATA) -> { @@ -188,8 +190,6 @@ class ServerReadChannel(private val delegate: ByteReadChannel) : ByteReadChannel } readFully(dataBuffer, 0, available) channel.writeFully(dataBuffer, 0, available) - channel.flush() - channel.close() } else -> throw RuntimeException("Something bad happened") } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/server/ServerWriteChannel.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerWriteChannel.kt similarity index 97% rename from adam/src/test/kotlin/com/malinskiy/adam/server/ServerWriteChannel.kt rename to server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerWriteChannel.kt index 7bd173e54..038a02556 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/server/ServerWriteChannel.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/ServerWriteChannel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.malinskiy.adam.server +package com.malinskiy.adam.server.stub import com.malinskiy.adam.Const import com.malinskiy.adam.request.shell.v2.MessageType @@ -142,6 +142,12 @@ class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChan writeFully(message.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING)) } + suspend fun respondStringV2(message: String) { + val bytes = message.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) + writeIntLittleEndian(bytes.size) + writeFully(bytes) + } + suspend fun respondStringRaw(message: String) { respond(message.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING)) } @@ -152,6 +158,10 @@ class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChan respondStringRaw(message) } + suspend fun respondShellV1(stdout: String) { + respondStringRaw(stdout) + } + suspend fun respondShellV2(stdout: String, stderr: String, exitCode: Int) { respondShellV2Stdout(stdout) respondShellV2Stderr(stderr) @@ -174,12 +184,6 @@ class ServerWriteChannel(private val delegate: ByteWriteChannel) : ByteWriteChan respondStringV2(stdout) } - suspend fun respondStringV2(message: String) { - val bytes = message.toByteArray(Const.DEFAULT_TRANSPORT_ENCODING) - writeIntLittleEndian(bytes.size) - writeFully(bytes) - } - suspend fun respondShellV2WindowSizeChange() { writeByte(MessageType.WINDOW_SIZE_CHANGE.toValue().toByte()) } diff --git a/adam/src/test/kotlin/com/malinskiy/adam/server/StubSocket.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/StubSocket.kt similarity index 92% rename from adam/src/test/kotlin/com/malinskiy/adam/server/StubSocket.kt rename to server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/StubSocket.kt index 30be6b959..dbc5b0960 100644 --- a/adam/src/test/kotlin/com/malinskiy/adam/server/StubSocket.kt +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/StubSocket.kt @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.malinskiy.adam.server +package com.malinskiy.adam.server.stub -import com.malinskiy.adam.log.AdamLogging import com.malinskiy.adam.transport.Socket import io.ktor.utils.io.ByteChannelSequentialJVM import io.ktor.utils.io.ByteReadChannel @@ -55,11 +54,8 @@ class StubSocket( writeChannel.close() readChannel.cancel() } catch (e: Exception) { - log.debug(e) { "Exception during cleanup. Ignoring" } + println("Exception during cleanup. Ignoring") + e.printStackTrace() } } - - companion object { - private val log = AdamLogging.logger {} - } } diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DeviceExpectation.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DeviceExpectation.kt new file mode 100644 index 000000000..184127b00 --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DeviceExpectation.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +data class DeviceExpectation( + val serialNo: String, + private val list: MutableList Unit> = mutableListOf() +) { + fun session(block: suspend Session.() -> Unit) { + list.add(block) + } + + suspend fun handle(session: Session) { + assert(list.size > 0) { "No handles registered for request" } + val head = list.removeAt(0) + head(session) + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DoneFailSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DoneFailSubSession.kt new file mode 100644 index 000000000..f09b9cd37 --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/DoneFailSubSession.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +class DoneFailSubSession(private val session: Session) { + suspend fun done() { + session.output.respondDone() + } + + suspend fun fail(message: String) { + session.output.respondFail(message) + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Expectation.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Expectation.kt new file mode 100644 index 000000000..5714a6920 --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Expectation.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +class Expectation { + private val handlers = mutableMapOf() + private var otherHandlers = mutableMapOf Unit>() + + fun serial(serialNo: String, block: DeviceExpectation.() -> Unit) { + val deviceExpectation = handlers[serialNo] ?: DeviceExpectation(serialNo) + handlers[serialNo] = deviceExpectation + block(deviceExpectation) + } + + fun other(transportString: String, block: suspend Session.() -> Unit) { + assert(!otherHandlers.contains(transportString)) { "Handler for $transportString already exists" } + otherHandlers[transportString] = block + } + + suspend fun select(session: Session): Boolean { + val transportCmd = session.input.receiveCommand() + return if (transportCmd.startsWith("host:transport:")) { + val serial = transportCmd.substringAfter("host:transport:") + handlers[serial]?.let { it.handle(session); true } ?: false + } else { + otherHandlers[transportCmd]?.invoke(session) ?: return false + return true + } + } +} + diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/FramebufferSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/FramebufferSubSession.kt new file mode 100644 index 000000000..d840cf841 --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/FramebufferSubSession.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +import java.io.File + +class FramebufferSubSession(private val session: Session) { + suspend fun accept(): FramebufferSubSession { + session.respondTransport(true) + return this + } + + suspend fun reject(message: String): FramebufferSubSession { + session.respondTransport(false, message) + return this + } + + suspend fun respondScreencaptureV2(replay: File) { + session.respondScreencaptureV2(replay) + } + + suspend fun respondScreencaptureV3(replay: File) { + session.respondScreencaptureV3(replay) + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/GetAdbServerSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/GetAdbServerSubSession.kt new file mode 100644 index 000000000..a354f64ab --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/GetAdbServerSubSession.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +class GetAdbServerSubSession(private val session: Session) { + suspend fun accept(): GetAdbServerSubSession { + session.respondTransport(true) + return this + } + + suspend fun reject(message: String): GetAdbServerSubSession { + session.respondTransport(false, message) + return this + } + + suspend fun respondAdbServerVersion(version: Int) { + session.respondAdbServerVersion(version) + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/LegacySideloadSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/LegacySideloadSubSession.kt new file mode 100644 index 000000000..c1cd0b27b --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/LegacySideloadSubSession.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +class LegacySideloadSubSession(private val session: Session) { + suspend fun receive(size: Int): LegacySideloadSubSession { + session.receiveBytes(614) + return this + } + + suspend fun okay() { + session.respondOkay() + } + + suspend fun fail(message: String) { + session.respondTransport(false, message) + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/OkayFailSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/OkayFailSubSession.kt new file mode 100644 index 000000000..891109d50 --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/OkayFailSubSession.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +open class OkayFailSubSession(private val session: Session) { + suspend fun accept(): OkayFailSubSession { + session.respondTransport(true) + return this + } + + suspend fun reject(message: String): OkayFailSubSession { + session.respondTransport(false, message) + return this + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ReceiveFileSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ReceiveFileSubSession.kt new file mode 100644 index 000000000..5888f39b3 --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ReceiveFileSubSession.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +import java.io.File + +class ReceiveFileSubSession(private val session: Session) { + suspend fun respondFile(fixture: File): ReceiveFileSubSession { + session.respondFile(fixture) + return this + } + + suspend fun respondDoneDone() { + session.output.respondDoneDone() + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileSubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileSubSession.kt new file mode 100644 index 000000000..8eb3cd5a3 --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileSubSession.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +import com.malinskiy.adam.Const +import java.io.File + +class SendFileSubSession(private val session: Session) { + suspend fun receiveFile(fixture: File): SendFileSubSession { + session.receiveFile(fixture) + return this + } + + suspend fun done() { + session.respondOkay() + } + + suspend fun fail(message: String) { + session.output.respond(Const.Message.FAIL) + session.output.respondStringV1(message) + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileV2SubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileV2SubSession.kt new file mode 100644 index 000000000..c69316d41 --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/SendFileV2SubSession.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +import com.malinskiy.adam.Const +import java.io.File + +class SendFileV2SubSession(private val session: Session) { + suspend fun receiveFile(fixture: File): SendFileV2SubSession { + session.receiveFile(fixture) + return this + } + + suspend fun done() { + session.respondOkay() + } + + suspend fun fail(message: String) { + session.output.respond(Const.Message.FAIL) + session.output.respondStringV2(message) + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Session.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Session.kt new file mode 100644 index 000000000..ca78d43ee --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/Session.kt @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +import assertk.assertThat +import assertk.assertions.isEqualTo +import com.malinskiy.adam.Const +import com.malinskiy.adam.server.stub.ServerReadChannel +import com.malinskiy.adam.server.stub.ServerWriteChannel +import io.ktor.utils.io.writeIntLittleEndian +import java.io.File + + +class Session(val input: ServerReadChannel, val output: ServerWriteChannel) { + suspend fun expectCmd(expected: () -> String): OkayFailSubSession { + val transportCmd = input.receiveCommand() + assertThat(transportCmd).isEqualTo(expected()) + + return OkayFailSubSession(session = this) + } + + suspend fun expectShell(expected: () -> String): ShellV1SubSession { + val transportCmd = input.receiveCommand() + assertThat(transportCmd).isEqualTo("shell:${expected()}") + return ShellV1SubSession(session = this) + } + + suspend fun respondTransport(success: Boolean, message: String? = null) { + output.respond( + when (success) { + true -> Const.Message.OKAY + false -> Const.Message.FAIL + } + ) + + if (!success && message != null) { + output.respondStringV1(message) + } + } + + suspend fun respondShellV1(stdout: String) { + output.respondShellV1(stdout) + } + + suspend fun expectFramebuffer(): FramebufferSubSession { + expectCmd { "framebuffer:" } + return FramebufferSubSession(this) + } + + suspend fun respondScreencaptureV2(replay: File) { + //Extended version + output.writeIntLittleEndian(1) + + val sample = replay.readBytes() + output.writeFully(sample, 0, 48) + assertThat(input.readByte()).isEqualTo(0.toByte()) + output.writeFully(sample, 48, sample.size - 48) + } + + suspend fun respondScreencaptureV3(replay: File) { + //Extended version + output.writeIntLittleEndian(2) + + val sample = replay.readBytes() + output.writeFully(sample, 0, 52) + assertThat(input.readByte()).isEqualTo(0.toByte()) + output.writeFully(sample, 52, sample.size - 52) + } + + suspend fun respondAdbServerVersion(x: Int) { + output.respondStringV1(x.toString(16)) + } + + suspend fun respondPairDevice(message: String) { + output.respondStringV1(message) + } + + suspend fun respondReconnectOffline(message: String) { + output.respondStringV1(message) + } + + suspend fun respondReconnectSingleDevice(message: String) { + output.respondStringRaw(message) + } + + suspend fun respondRemountPartitions(message: () -> String) { + output.respondStringRaw(message()) + } + + suspend fun respondSideloadChunkRequested(part: String) { + output.respondStringRaw(part) + } + + suspend fun respondPortForward(success: Boolean, port: Int? = null) { + output.respond( + when (success) { + true -> Const.Message.OKAY + false -> Const.Message.FAIL + } + ) + + if (success && port != null) { + output.respondStringV1(port.toString()) + } + } + + suspend fun respondSetDmVerityChecking(message: String) { + output.respondStringRaw(message) + } + + suspend fun expectShellV2Stdin(expected: String) { + val stdin = input.receiveShellV2Stdin() + assertThat(stdin).isEqualTo(expected) + } + + suspend fun expectShellV2StdinClose() { + input.receiveShellV2StdinClose() + } + + suspend fun respondShellV2Stdout(message: String) { + output.respondShellV2Stdout(message) + } + + suspend fun respondShellV2Exit(exitCode: Int) { + output.respondShellV2Exit(exitCode) + } + + suspend fun respondShellV2Stderr(stderr: String) { + output.respondShellV2Stderr(stderr) + } + + suspend fun respondShellV2WindowSizeChange() { + output.respondShellV2WindowSizeChange() + } + + suspend fun respondShellV2Invalid() { + output.respondShellV2Invalid() + } + + suspend fun expectStat(path: () -> String) { + val receiveStat = input.receiveStat() + assertThat(receiveStat).isEqualTo(path()) + } + + suspend fun respondStat(size: Int, mode: Int = 0, lastModified: Int = 0) { + output.respondStat(size, mode, lastModified) + } + + suspend fun respondStatV2( + mode: Int, + size: Int, + error: Int, + dev: Int, + ino: Int, + nlink: Int, + uid: Int, + gid: Int, + atime: Int, + mtime: Int, + ctime: Int + ) { + output.respondStatV2(mode, size, error, dev, ino, nlink, uid, gid, atime, mtime, ctime) + } + + suspend fun expectSend(message: () -> String): SendFileSubSession { + val receiveCmd = input.receiveSend() + assertThat(receiveCmd).isEqualTo(message()) + + return SendFileSubSession(this) + } + + suspend fun receiveFile(receiveFile: File) { + input.receiveFile(receiveFile) + } + + suspend fun expectSendV2(receiveCmd: String, mode: String, flags: Int): SendFileV2SubSession { + val (actualReceiveCmd, actualMode, actualFlags) = input.receiveSendV2() + assertThat(actualReceiveCmd).isEqualTo(receiveCmd) + assertThat(actualMode.toString(8)).isEqualTo(mode) + assertThat(actualFlags).isEqualTo(flags) + + return SendFileV2SubSession(this) + } + + suspend fun expectRecv(path: () -> String): ReceiveFileSubSession { + val recvPath = input.receiveRecv() + assertThat(recvPath).isEqualTo(path()) + return ReceiveFileSubSession(this) + } + + suspend fun respondFile(fixture: File) { + output.respondData(fixture.readBytes()) + } + + suspend fun expectRecv2(path: () -> String): ReceiveFileSubSession { + val recvPath = input.receiveRecv2() + assertThat(recvPath).isEqualTo(path()) + + return ReceiveFileSubSession(this) + } + + suspend fun expectList(path: () -> String) { + val listPath = input.receiveList() + assertThat(listPath).isEqualTo(path()) + } + + suspend fun respondList(size: Int, mode: Int = 0, lastModified: Int = 0, name: String): DoneFailSubSession { + output.respondList(size, mode, lastModified, name) + return DoneFailSubSession(this) + } + + suspend fun expectListV2(path: () -> String) { + val listPath = input.receiveListV2() + assertThat(listPath).isEqualTo(path()) + } + + suspend fun respondListV2( + name: String, + mode: Int = 0, + size: Int, + error: Int, + dev: Int, + ino: Int, + nlink: Int, + uid: Int, + gid: Int, + atime: Int, + mtime: Int, + ctime: Int + ): DoneFailSubSession { + output.respondListV2(name, mode, size, error, dev, ino, nlink, uid, gid, atime, mtime, ctime) + return DoneFailSubSession(this) + } + + suspend fun expectStatV2(path: () -> String) { + val receiveStat = input.receiveStatV2() + assertThat(receiveStat).isEqualTo(path()) + } + + suspend fun resondRestartAdbd(message: String) { + output.respondStringRaw(message) + } + + suspend fun respondAsyncDeviceMonitor(serial: String, state: String) { + output.respondStringV1("$serial\t$state\n") + } + + suspend fun respondListDevices(serialToState: Map) { + val response = serialToState.map { "${it.key}\t${it.value}\n" }.joinToString(separator = "") + output.respondStringV1(response) + } + + suspend fun respondListPortForwards(response: String) { + output.respondStringV1(response) + } + + + suspend fun respondConnectDevice(response: String) { + output.respondStringV1(response) + } + + suspend fun respondDisconnectDevice(response: String) { + output.respondStringV1(response) + } + + suspend fun respondOkay() { + output.respondOkay() + } + + suspend fun expectLegacySideload(size: Int): LegacySideloadSubSession { + expectCmd { "sideload:$size" }.accept() + return LegacySideloadSubSession(this) + } + + suspend fun receiveBytes(size: Int): ByteArray { + return input.receiveBytes(size) + } + + suspend fun expectAdbServerVersion(): GetAdbServerSubSession { + expectCmd { "host:version" } + return GetAdbServerSubSession(this) + } +} diff --git a/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV1SubSession.kt b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV1SubSession.kt new file mode 100644 index 000000000..6ba6fc3e9 --- /dev/null +++ b/server/server-stub/src/main/kotlin/com/malinskiy/adam/server/stub/dsl/ShellV1SubSession.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 Anton Malinskiy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.malinskiy.adam.server.stub.dsl + +class ShellV1SubSession(private val session: Session) { + suspend fun accept(): ShellV1SubSession { + session.respondOkay() + return this + } + + suspend fun respond(stdout: String): ShellV1SubSession { + session.respondShellV1(stdout) + return this + } + + suspend fun reject(message: String) { + session.respondTransport(false, message) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 85919988f..79c2485eb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -24,3 +24,6 @@ pluginManagement { include(":adam") include(":android-junit4") include(":android-testrunner-contract") +include(":server:server-stub") +include(":server:server-stub-junit4") +include(":server:server-stub-junit5")