actr-cli 0.3.1

Command line tool for Actor-RTC framework projects
Documentation
package {{PACKAGE_NAME}}

import android.content.Context
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import stream_server.StreamClientOuterClass.ClientStartStreamRequest
import stream_server.StreamClientOuterClass.ClientStartStreamResponse
import io.actor_rtc.actr.PayloadType
import io.actor_rtc.actr.dsl.*
import java.io.File
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith

/**
 * {{PROJECT_NAME_PASCAL}} DataStream Integration Test
 *
 * This test verifies the DataStream transfer to the remote StreamEchoServer.
 * The server should be running remotely before executing this test.
 *
 * Architecture:
 * ```
 * UnifiedWorkload
 *   ├── UnifiedHandler (implements StreamClientHandler)
 *   │     ├── start_stream() - locally trigger stream transfer
 *   │     └── prepare_client_stream() - server callback to register data stream receiver
 *   └── UnifiedDispatcher
 *         ├── local routes -> StreamClientDispatcher -> handler methods
 *         └── remote routes -> ctx.callRaw() -> remote actors
 * ```
 */
@RunWith(AndroidJUnit4::class)
class DataStreamIntegrationTest {

    companion object {
        private const val TAG = "DataStreamIntegrationTest"
    }

    private fun getContext(): Context {
        return InstrumentationRegistry.getInstrumentation().targetContext
    }

    private fun copyAssetToInternalStorage(assetName: String): String {
        // Source: Test Assets (src/androidTest/assets)
        val sourceContext = InstrumentationRegistry.getInstrumentation().context
        val inputStream = sourceContext.assets.open(assetName)

        // Destination: App Files Dir (standard app storage)
        val destContext = InstrumentationRegistry.getInstrumentation().targetContext
        val outputFile = File(destContext.filesDir, assetName)

        outputFile.parentFile?.mkdirs()
        inputStream.use { input ->
            outputFile.outputStream().use { output -> input.copyTo(output) }
        }
        return outputFile.absolutePath
    }

    /**
     * Test DataStream transfer to remote server
     *
     * This test:
     * 1. Creates a UnifiedWorkload with MyUnifiedHandler
     * 2. Calls StartStream RPC which discovers server and sends data
     * 3. Verifies the transfer was accepted
     *
     * Prerequisites:
     * - StreamEchoServer must be running remotely
     * - Signaling server must be accessible
     */
    @Test
    fun testDataStreamTransfer(): Unit = runBlocking {
        Log.i(TAG, "=== Starting DataStream Integration Test ===")
        val clientConfigPath = copyAssetToInternalStorage("manifest.toml")
        // manifest.lock.toml is required by the runtime now
        copyAssetToInternalStorage("manifest.lock.toml")
        var clientRef: ActrRef? = null

        try {
            val clientSystem = createActrNode(clientConfigPath)

            // Create UnifiedWorkload with handler
            val handler = MyUnifiedHandler()
            val clientWorkload = UnifiedWorkload(handler)

            val clientNode = clientSystem.attach(clientWorkload)
            clientRef = clientNode.start()
            Log.i(TAG, "Client started: ${clientRef.actorId().serialNumber}")

            // Wait for onStart to complete (auto-discover remote services)
            delay(2000)

            // ==================== Test DataStream Transfer ====================
            Log.i(TAG, "")
            Log.i(TAG, "==================== DataStream Transfer ====================")

            Log.i(TAG, "📞 Calling StartStream via UnifiedDispatcher (local service)...")
            val startStreamRequest = ClientStartStreamRequest.newBuilder()
                .setClientId("android-test-client")
                .setStreamId("test-stream-${System.currentTimeMillis()}")
                .setMessageCount(3)
                .build()

            val startStreamResponsePayload = clientRef.call(
                "stream_server.StreamClient.StartStream",
                PayloadType.RPC_RELIABLE,
                startStreamRequest.toByteArray(),
                30000L
            )

            val startStreamResponse = ClientStartStreamResponse.parseFrom(startStreamResponsePayload)
            Log.i(TAG, "📬 StartStream Response: accepted=${startStreamResponse.accepted}, message=${startStreamResponse.message}")

            assertTrue("Stream transfer should be accepted", startStreamResponse.accepted)
            Log.i(TAG, "✅ DataStream StartStream Test PASSED")

            // Wait for data stream messages to be sent (3 messages * 1 second each)
            Log.i(TAG, "⏳ Waiting for data stream messages to be sent...")
            delay(4000)

            // ==================== Summary ====================
            Log.i(TAG, "")
            Log.i(TAG, "==================== Test Summary ====================")
            Log.i(TAG, "✅ DataStream Transfer - PASSED")
            Log.i(TAG, "")
            Log.i(TAG, "=== DataStream Integration Test PASSED ===")
        } finally {
            try {
                clientRef?.shutdown()
                clientRef?.awaitShutdown()
            } catch (e: Exception) {
                Log.w(TAG, "Error during shutdown: ${e.message}")
            }
        }
    }
}