Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add start session command to increase speed of tests #1902

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ jobs:
./download_apps
./install_apps
./run_tests
./run_start_session_test

- name: Upload ~/.maestro artifacts
uses: actions/upload-artifact@v4
Expand Down
69 changes: 69 additions & 0 deletions e2e/run_start_session_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env sh

set -eu

# The point of this test is to ensure that the 'maestro start-session' works correctly
# - Running it should reinstall Maestro APKs on device
# - Running 'maestro test' while a 'maestro start-session' is open should not reinstall Maestro APKs

command -v maestro >/dev/null 2>&1 || { echo "maestro is required" && exit 1; }

[ "$(basename "$PWD")" = "e2e" ] || { echo "must be run from e2e directory" && exit 1; }

get_maestro_apk_install_time() {
adb shell dumpsys package dev.mobile.maestro | grep "lastUpdateTime" | awk -F= '{print $2}'
}

start_maestro_session() {
LOG_FILE=$(mktemp)
MAX_TIMEOUT=60
START_TIME=$(date +%s)

# Start the Maestro session in the background and redirect output to logs.txt
echo "Starting Maestro session..."
maestro --device emulator-5554 start-session > "$LOG_FILE" 2>&1 &
MAESTRO_START_SESSION_PID=$!
trap "kill -9 $MAESTRO_START_SESSION_PID" EXIT

# Loop to check for the "Maestro session started." message
while true; do
if grep -q "Maestro session started." "$LOG_FILE"; then
echo "Maestro session started successfully."
break
fi
CURRENT_TIME=$(date +%s)
ELAPSED_TIME=$((CURRENT_TIME - START_TIME))

if [ "$ELAPSED_TIME" -ge "$MAX_TIMEOUT" ]; then
echo "Timed out waiting for Maestro session to start."
break
fi
sleep 1
done
}

# Test Start session doesn't reinstall APKs
PREVIOUS_INSTALL_TIME=$(get_maestro_apk_install_time)
start_maestro_session

# Ensure maestro start-session did reinstall APKs
AFTER_START_SESSION_INSTALL_TIME=$(get_maestro_apk_install_time)

if [ "$PREVIOUS_INSTALL_TIME" = "$AFTER_START_SESSION_INSTALL_TIME" ]; then
echo "'maestro start-session' didn't reinstall APKs while it should have"
exit 1
fi

# Ensure subsequent maestro test do not reinstall APKs
# We don't really care if the test fails or not since it should be taken care of in run_tests
maestro --device emulator-5554 test ./flows/nowinandroid/bookmarks.yaml || FAILED=true
AFTER_TEST_INSTALL_TIME=$(get_maestro_apk_install_time)

if [ "$AFTER_START_SESSION_INSTALL_TIME" != "$AFTER_TEST_INSTALL_TIME" ]; then
echo "'maestro test' reinstalled APKs while it shouldn't have"
exit 1
fi

echo $PREVIOUS_INSTALL_TIME
echo $AFTER_START_SESSION_INSTALL_TIME
echo $AFTER_TEST_INSTALL_TIME
3 changes: 2 additions & 1 deletion maestro-cli/src/main/java/maestro/cli/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ import kotlin.system.exitProcess
LogoutCommand::class,
BugReportCommand::class,
StudioCommand::class,
StartDeviceCommand::class
StartDeviceCommand::class,
StartSessionCommand::class
]
)
class App {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package maestro.cli.command

import maestro.cli.App
import maestro.cli.CliError
import maestro.cli.DisableAnsiMixin
import maestro.cli.ShowHelpMixin
import maestro.cli.device.Platform
import maestro.cli.session.MaestroSessionManager
import maestro.cli.util.DeviceConfigIos.device
import picocli.CommandLine
import picocli.CommandLine.Command

@Command(
name = "start-session",
description = [
"Setup Maestro session once, so you can run 'maestro test' faster since the setup is already done.",
],
hidden = true
)
class StartSessionCommand : Runnable {
@CommandLine.Mixin
var disableANSIMixin: DisableAnsiMixin? = null

@CommandLine.Mixin
var showHelpMixin: ShowHelpMixin? = null

@CommandLine.ParentCommand
private val parent: App? = null

override fun run() {
MaestroSessionManager.newSession(
host = parent?.host,
port = parent?.port,
driverHostPort = parent?.port,
deviceId = parent?.deviceId
) { session ->
/**
* As of now on iOS, the session gets started but this has no impact on subsequent tests
* running maestro test after the session would still install the XCTest runner
*/
if (session.device?.platform != Platform.ANDROID) {
throw CliError ("This command is only supported for Android devices.")
}

println("Maestro session started. Keep this running in the background.")
println("Run your tests with `maestro test <test.yaml>` in another terminal.")

while (!Thread.interrupted()) {
Thread.sleep(100)
}
}
}
}
3 changes: 0 additions & 3 deletions maestro-client/src/main/java/maestro/drivers/AndroidDriver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,6 @@ class AndroidDriver(
launchArguments: Map<String, Any>,
sessionId: UUID?,
) {
if(!open) // pick device flow, no open() invocation
open()
Comment on lines -197 to -198
Copy link
Author

@Almouro Almouro Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned, I had to remove 2 lines of code: I have to be honest, I didn't manage to understand their purpose. 😓
So I'd love some help from @sdfgsdfgd or @igorsmotto to know why they're needed. 🙏

I've tested maestro test -s 2 tests locally (including some launchApp) and didn't run into any issues, but likely I've missed something.

Here the issue is that since maestro test has found an active session, it didn't "open" the Android driver since it doesn't need to.
But this condition would force it to reopen when using launchApp which defeats the purpose of maestro start-session


if (!isPackageInstalled(appId)) {
throw IllegalArgumentException("Package $appId is not installed")
}
Expand Down
Loading