diff --git a/.github/workflows/agent.yaml b/.github/workflows/agent.yaml index 175dbfe..a625ec5 100644 --- a/.github/workflows/agent.yaml +++ b/.github/workflows/agent.yaml @@ -22,7 +22,7 @@ concurrency: jobs: agent-build: name: "Agent build & test" - runs-on: macos-26 + runs-on: ubuntu-latest timeout-minutes: 45 permissions: contents: read @@ -58,6 +58,27 @@ jobs: run: ./gradlew validateScreenshotTest -PGEMINI_API_KEY=dummy_key working-directory: agent + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Setup GMD + run: | + ./gradlew :app:pixel7Api37Setup \ + --info \ + -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true \ + -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" + working-directory: agent + + - name: Run instrumentation tests + run: | + ./gradlew :app:pixel7Api37StandardDebugAndroidTest -PGEMINI_API_KEY=dummy_key \ + -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true \ + -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" + working-directory: agent + - name: Build Debug and Release APKs run: ./gradlew assembleDebug assembleRelease -PGEMINI_API_KEY=dummy_key working-directory: agent @@ -67,18 +88,3 @@ jobs: with: name: agent-apks path: agent/app/build/outputs/apk/**/*.apk - -# - name: Setup GMD -# run: | -# ./gradlew :app:pixel7Api35Setup \ -# --info \ -# -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true \ -# -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" -# working-directory: agent -# -# - name: Run instrumentation tests -# run: | -# ./gradlew :app:pixel7Api35Check -PGEMINI_API_KEY=dummy_key \ -# -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true \ -# -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" -# working-directory: agent diff --git a/agent/app/build.gradle.kts b/agent/app/build.gradle.kts index b195067..efc15db 100644 --- a/agent/app/build.gradle.kts +++ b/agent/app/build.gradle.kts @@ -91,10 +91,10 @@ android { } managedDevices { localDevices { - create("pixel7Api35") { + create("pixel7Api37") { device = "Pixel 7" - apiLevel = 35 - systemImageSource = "aosp-atd" + apiLevel = 37 + systemImageSource = "google_apis" } } } diff --git a/agent/app/src/androidTest/java/com/example/appfunctions/agent/domain/GetAppFunctionStatesUseCaseTest.kt b/agent/app/src/androidTest/java/com/example/appfunctions/agent/domain/GetAppFunctionStatesUseCaseTest.kt index 8819ed6..01c2f70 100644 --- a/agent/app/src/androidTest/java/com/example/appfunctions/agent/domain/GetAppFunctionStatesUseCaseTest.kt +++ b/agent/app/src/androidTest/java/com/example/appfunctions/agent/domain/GetAppFunctionStatesUseCaseTest.kt @@ -16,6 +16,7 @@ package com.example.appfunctions.agent.domain import android.content.Context +import android.os.ParcelFileDescriptor import androidx.appfunctions.AppFunctionManager import androidx.appfunctions.AppFunctionName import androidx.test.core.app.ApplicationProvider @@ -25,6 +26,7 @@ import com.example.appfunctions.agent.data.FakeAppFunctionService import com.example.appfunctions.agent.domain.appfunction.GetAppFunctionStatesUseCase import kotlinx.coroutines.runBlocking import org.junit.Assert.assertTrue +import org.junit.Assert.fail import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -42,9 +44,29 @@ class GetAppFunctionStatesUseCaseTest { useCase = GetAppFunctionStatesUseCase(appFunctionManager) // Adopt shell permission identity - InstrumentationRegistry.getInstrumentation() - .uiAutomation - .adoptShellPermissionIdentity("android.permission.EXECUTE_APP_FUNCTIONS") + val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation + uiAutomation.adoptShellPermissionIdentity("android.permission.EXECUTE_APP_FUNCTIONS") + + waitForFakeFunctionIndexed() + } + + private fun waitForFakeFunctionIndexed() { + val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation + val command = "cmd app_function list-app-functions --package ${context.packageName}" + var output = "" + val timeoutMs = 10_000L + val startTime = System.currentTimeMillis() + while (System.currentTimeMillis() - startTime < timeoutMs) { + output = + ParcelFileDescriptor.AutoCloseInputStream( + uiAutomation.executeShellCommand(command), + ).bufferedReader().use { it.readText() } + if (output.contains("fakeFunction")) { + return + } + Thread.sleep(500) + } + fail("Timed out waiting for fakeFunction to be indexed. Output of '$command': $output") } @Test diff --git a/agent/app/src/androidTest/java/com/example/appfunctions/agent/domain/GetAppFunctionsUseCaseTest.kt b/agent/app/src/androidTest/java/com/example/appfunctions/agent/domain/GetAppFunctionsUseCaseTest.kt index eae86a9..74d0e77 100644 --- a/agent/app/src/androidTest/java/com/example/appfunctions/agent/domain/GetAppFunctionsUseCaseTest.kt +++ b/agent/app/src/androidTest/java/com/example/appfunctions/agent/domain/GetAppFunctionsUseCaseTest.kt @@ -16,6 +16,7 @@ package com.example.appfunctions.agent.domain import android.content.Context +import android.os.ParcelFileDescriptor import androidx.appfunctions.AppFunctionManager import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -28,6 +29,7 @@ import com.example.appfunctions.agent.domain.appfunction.GetAppFunctionsUseCase import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking import org.junit.Assert.assertTrue +import org.junit.Assert.fail import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -55,6 +57,27 @@ class GetAppFunctionsUseCaseTest { InstrumentationRegistry.getInstrumentation() .uiAutomation .adoptShellPermissionIdentity("android.permission.EXECUTE_APP_FUNCTIONS") + + waitForFakeFunctionIndexed() + } + + private fun waitForFakeFunctionIndexed() { + val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation + val command = "cmd app_function list-app-functions --package ${context.packageName}" + var output = "" + val timeoutMs = 10_000L + val startTime = System.currentTimeMillis() + while (System.currentTimeMillis() - startTime < timeoutMs) { + output = + ParcelFileDescriptor.AutoCloseInputStream( + uiAutomation.executeShellCommand(command), + ).bufferedReader().use { it.readText() } + if (output.contains("fakeFunction")) { + return + } + Thread.sleep(500) + } + fail("Timed out waiting for fakeFunction to be indexed. Output of '$command': $output") } @Test