I try to develop script to launch armeabi-v7a emulator and execute gradle connectedAndroidTest task to run android device tests targeted to my app.
I wrote script which successfully check required emulator target and download and install it if it is missed and then launch emulator. All these points work well. But After I launch emulator I have to wait until it will be completely booted.
I guess my problem is that I cannot rightful detect that emulator was completely finish his boot operation and is ready to install apps as well.
According to suggestions in web we can use two following system properties to detect complete boot, it is
init.svc.bootanim - state of boot animation
sys.boot_completed - system state of boot operation
We can revise them by calling
adb -e shell getprop init.svc.bootanim and adb -e shell getprop init.svc.bootanim accordingly
I figured out that sys.boot_completed more reliable than init.svc.bootanim, but anyway I wait both of them. But it does not help, because if after waiting device boot I start connectedAndroidTest task after running about 4 minutes it fails with next exception
Unable to install /Users/busylee/temp/TestRun/app/build/outputs/apk/debug/app-debug.apk
com.android.ddmlib.InstallException
at com.android.ddmlib.Device.installRemotePackage(Device.java:1011)
at com.android.ddmlib.Device.installPackage(Device.java:911)
...
Caused by: com.android.ddmlib.ShellCommandUnresponsiveException
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:557)
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:383)
...
But if I wait for a while it completes. Which I guess means that I do not wait something before install test app.
Do you have any ideas what I can rely on while waiting an emulator start?
Related
TL;DR: I can run only 1 test against a certain device, then every other attempt to connect my app to an ADB session, manually or via an Appium server call, fails. How do I resolve this so that I can resume automated testing?
The Appium desired_capabilities for my device includes noReset = True. All other desired_capabilities except device identifiers are shared among and work for all my other devices.
This error was not observed until I added driver.reset() to one of my tests. Removing that line of code has not resolved this issue. Because of this, I suspect that Appium is not the root cause of this error, but rather highlighted it. My desired capabilities are:
`
'platformName': 'Android',
'platformVersion': '8.0',
'deviceName': 'WVGA_API_26',
'avd': 'WVGA_API_26',
'app_package': 'com.ferly.ferly',
'app_activity': 'host.exp.exponent.experience.ShellAppActivity',
'app_wait_package': 'com.ferly.ferly',
'automationName': 'UiAutomator2',
'noReset': 'true',`
Attempting to initialize any driver session that uses the affected device gives the following error in Appium:
WebDriverException: Message: An unknown server-side error occurred while processing the command. Original error: Cannot start the 'com.ferly.ferly' application. Visit https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/android/activity-startup.md for troubleshooting. Original error: Error executing adbExec. Original error: 'Command 'C:\Users\Jeff\AppData\Local\Android\sdk\platform-tools\adb.exe -P 5037 -s emulator-5558 shell am start -W -n com.ferly.ferly/host.exp.exponent.experience.ShellAppActivity -S' timed out after 20000ms'. Try to increase the 20000ms adb execution timeout represented by 'adbExecTimeout' capability
Running the command in my Windows shell: C:\Users\<user>\AppData\Local\Android\sdk\platform-tools\adb.exe -P 5037 -s emulator-5556 shell am start -W -n com.ferly.ferly/host.exp.exponent.experience.ShellAppActivity -S, where emulator-5556 is the affected device, gives the following output:
Stopping: com.ferly.ferly
Starting: Intent { cmp=com.ferly.ferly/host.exp.exponent.experience.ShellAppActivity }
^C (manual break after 2 minutes of waiting.)
On my emulator, the app opens and can be used as I expect, but the adb session does not recognize that the app is opened.
Running the same command, but for an unaffected device, say emulator-5558, succeeds with this output:
Stopping: com.ferly.ferly
Starting: Intent { cmp=com.ferly.ferly/host.exp.exponent.experience.ShellAppActivity }
Warning: Activity not started, its current task has been brought to the front
Status: ok
ThisTime: 0
TotalTime: 0
WaitTime: 872
Complete
Workarounds: Uninstalling the Appium Settings app on the affected device after every test allows one test to be run on that device.
What is the core issue I'm facing and how do I solve it? If it matters, my test scripts are all written in Python.
I have increased the time out to 600 seconds as below.
driver.manage().timeouts().implicitlyWait(600, TimeUnit.SECONDS);
The issue seems to have fixed for me.
I started an Android emulator using the following shell command:
emulator -avd TEST_AVD
The emulator starts just fine, but the shell script never finishes executing. It just hangs there even after the emulator has completed startup. I have tried with a number of other arguments that I could find, but nothing could quite do what I want it to. How do I know, or stop the shell command, when the emulator is ready to go?
I am setting up our Jenkins CI to use a Jenkinsfile to start the emulator, and then run a series of gradle commands. In short, I'd like to do this:
sh "emulator -avd TEST_AVD"
sh "./gradlew clean test spoon"
However, I don't want to run the gradle tasks until the emulator has finished startup, and I can't figure out how to do that in the terminal.
If you want to do something after you start the emulator you should start it in the background
emulator -avd TEST_AVD &
adb wait-for-device
# other stuff here
adb can wait for a device over a transport to be in a particular state
adb wait-for[-<transport>]-<state>
- wait for device to be in the given state:
device, recovery, sideload, or bootloader
Transport is: usb, local or any [default=any]
To wait until device (or emulator) boots, you can do something like this (as was already answered by Пионерка):
adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;'
Basically:
Wait for device/emulator to be in adb device state
Open shell & sleep in 1 second intervals until the sys.boot_completed property becomes true
If anybody would be interested what Android Studio does, when running emulator, the answer is this class:
If device is online, then it is ready. No need to go to further steps.
Checks system property adb shell getprop dev.bootcomplete until it is equal to 1
For API 23+ devices runs command to unlock screen: adb shell wm dismiss-keyguard
Waits 1 second.
I have a Jenkins job that starts a Robotium test from command line:
adb shell am instrument -w com.foo.tests/android.test.InstrumentationTestRunner
Sometimes the test run gets stuck. When I abort the Jenkins job, it does not stop the Robotium test run. I may have to cancel the test execution manually from the device before running another Jenkins job.
How do I stop the test execution? I cannot just uninstall the application under test with adb uninstall since it has active device admin.
You can cancel the previous Robotium test by starting another test one with a made-up test name:
adb shell am instrument -e class com.foo.tests#dummyTestName com.foo.tests/android.test.InstrumentationTestRunner
What about this:
adb shell am force-stop <PACKAGE>
You can clear the app data,like this
adb shell pm clear com.foo.tests
We are developing a ruby script that executes a bunch of shell commands to launch the emulator and run some calabash tests.
PID = fork do
Signal.trap('HUP') { puts 'PROCESS ENDED'; exit }
exec 'emulator -avd TestDevice1'
end
fork do
sleep(55)
exec 'adb shell input keyevent 82'
end
fork do
sleep(60)
exec 'calabash-android run ~/MyApp/MyApp.apk'
Process.Kill('HUP', PID)
end
We are currently using sleep commands so that the calabash tests don't run until the emulator is fully ready. This is not ideal. Is there an Android command to check if the device is ready? By that I mean Android has booted up and the lock screen is displayed.
The most reliable way I have found to detect if the emulator is ready for use, and for Calabash to start the installation process, is to detect when the bootanim has stopped.
You can check whether the emulator has finished booting manually with using ADB in a terminal:
adb shell getprop init.svc.bootanim
I have the following in a Rake command as part of a Calabash test suite which does the trick:
booting = ''
while booting != 'stopped'
booting = `adb shell getprop init.svc.bootanim`.strip
puts 'Waiting for emulator to boot'
sleep 2
end
Hope it works for you!
I'm using the emulator by command-line for our continuous integration server for our android application. With that approach we can test all Android Versions automatically. For the automatic installation and testing we are using the property "dev.bootcomplete", which is provided by the android emulator. Unfortunately we don't get it always. After a newly created emulator we are retrieving it, but when the emulator is several times used it do'nt throw it again...
Has Anybody an idea?
Commands/ results:
[user#mob_ci ~]$ adb shell getprop dev.bootcomplete
error: device offline
[user#mob_ci ~]$ adb shell getprop dev.bootcomplete
1
I use hudson as a ci server, for hudson there is a android plugin which manages the emulator, it even creates the emulator for you if you want.
I would either check if "error: device offline" happens and then run
adb kill-server
adb start-server
or
shutdown the emulator after each build, as it's not necessary that the emulator runs all the time or do the tests run all the time ?
hope this helps :)