I am trying to get calabash-android running within travis. calabash-android works fine within my machine without any problems. I have the following travis.yml:
language: android
jdk: oraclejdk8
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- $HOME/.gradle/daemon
- $HOME/.gradle/native
env:
global:
# wait up to 10 minutes for adb to connect to emulator
- ADB_INSTALL_TIMEOUT=20
- SLAVE_AAPT_TIMEOUT=40
android:
components:
- platform-tools
- tools
- build-tools-23.0.3
- android-23
- extra-android-support
- extra-android-m2repository
- extra-google-m2repository
- sys-img-armeabi-v7a-android-23
before_install:
# install ruby 2.0.0
- rvm install 2.0.0
# install calabash-android
- gem install calabash-android
before_script:
- echo no | android create avd --force --name test --target android-23 --abi armeabi-v7a
- emulator -avd test -no-skin -no-audio -no-window -no-boot-anim &
- android-wait-for-emulator
- adb shell settings put global window_animation_scale 0 &
- adb shell settings put global transition_animation_scale 0 &
- adb shell settings put global animator_duration_scale 0 &
- adb shell input keyevent 82 & #for unlocking as "powerkey"
- sleep 3 # give screen some time to become unlocked
- ./gradlew clean assembleDebug -PdisablePreDex --continue --stacktrace
script:
- calabash-android resign /home/travis/build/app/build/outputs/apk/app-debug.apk
- calabash-android run /home/travis/build/app/build/outputs/apk/app-debug.apk
It works with the 1st scenario of the feature and then once it starts 2nd scenario, it shows this error:
App did not start (RuntimeError)
./features/support/app_life_cycle_hooks.rb:5:in `Before'
Any ideas? or suggestion?
Delete -no-boot-anim option, android-wait-for-emulator script depends on boot animation to detect when the emulator is ready.
This is a great explanation I recommend: Detecting when emulator is ready to be used
The second step is to wait for emulator to fully boot, so it can be
used to run some code. This turned out to be the most tricky part.
Especially for emulators with API Level 11+ (11-14 at the time of
writing).
First, emulator should connect to adb and will be listed as “offline”.
In this state emulator does not accept any shell commands. And nothing
can be done in this state. This part is usually very stable and I
haven’t seen the case when emulator was started but never connected to
adb. Of course if some error occurs, it won’t connect to adb. So
timeout should be used here to detect abnormal delays or hangs.
Next state device goes to called “device” state. This is when device
is booting. As soon as it had booted, device goes to “online” state.
This is when system starts booting and normal operation of emulator
goes in.
From the moment device goes to “device” state, adb shell can be used
to execute different commands on device and query some useful
information about its state.
I’ve found several properties that should be tracked in order to
reliably detect when device is ready. The first property is called
dev.bootcompleted. As soon as device completes booting this property
will be set to 1.
After dev.bootcompleted is 1, next property called sys.boot_completed
should be tracked. It will be set to 1 as soon as system completed
booting (this is usually when BOOT_COMPLETED broadcast is sent). This
property is only set on emulators with API Level 9 or higher. On 8 and
lower this property is never used (and shouldn’t be tracked).
But emulator is still not ready, even when sys.boot_completed is set
to 1. You’ll notice that boot animation will still run for some
(significant) period of time. And only then UI will appear. But
luckily there is a way to detect this event too. For this we need to
track value of init.svc.bootanim property. This property keeps state
of boot animation service, that will be stopped as soon as UI appears.
In other words, as soon as init.svc.bootanim has value stopped, its
safe to assume that emulator is running and ready to be used.
Using -no-boot-anim the value is stopped before your emulator is fully-booted:
# Originally written by Ralf Kistner <ralf#embarkmobile.com>, but placed in the public domain
set +e
bootanim=""
failcounter=0
timeout_in_sec=360
until [[ "$bootanim" =~ "stopped" ]]; do
bootanim=`adb -e shell getprop init.svc.bootanim 2>&1 &`
if [[ "$bootanim" =~ "device not found" || "$bootanim" =~ "device offline"
|| "$bootanim" =~ "running" ]]; then
let "failcounter += 1"
echo "Waiting for emulator to start"
if [[ $failcounter -gt timeout_in_sec ]]; then
echo "Timeout ($timeout_in_sec seconds) reached; failed to start emulator"
exit 1
fi
fi
sleep 1
done
echo "Emulator is ready"
Now I was doubting due to the first scenario works (I never used calabash-android) but I see that it doesn't depend on the emulator being ready:
calabash-android - What does resign do?
The resign is used if you need to sign the app to match your keystore.
Copied from GitHub docs
https://github.com/calabash/calabash-android/wiki/Running-Calabash-Android
Instead of resigning you could also consider copying your debug
keystore to your folder.
The apk calabash android runs must be signed with the same keystore as
the test-server.
Use the command: calabash-android resign <apk> to resign your application.
Building the test-server using calabash-android build will build the
test-server and sign it with the same key as the application you are
testing.
The second scenario does it:
Running test
To run your test: calabash-android run <apk>
Calabash-android will install an instrumentation along with your app
when executing the app. We call this instrumentation for "test
server". The "test server" has special permission that allows it to
interact very closely with your app during test. Everytime you test a
new binary or use an upgraded version of calabash a new test server
will be build. The test server is an intrumentation that will run
along with your app on the device to execute the test.
Perhaps exist other issues in this case but fixed the same issue here deleting -no-boot-anim.
Related
I use a Genymotion android emulator for my automated Xamarin UI tests through the bash commands.
The issue is that the emulator is killed by the test runner app after tests are done. So this causes some kind of corruption on the emulator's virtual device file, I suppose.
When I try to start the emulator next time using the same script, I get the following error from Genymotion:
After clicking the update button, Genymotion dashboard opens. Then I can run the emulator by double clicking. But, I cannot do these steps through the shell.
If I could figure out what Genymotion does to repair the emulator, I would do the same thing in the shell script.
Here is my script to run the GM emulator;
cd $HOME
emulatorId=$(VBoxManage list vms | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})" | shuf -n 1)
open -a /Applications/Genymotion.app/Contents/MacOS/player.app --args --vm-name $emulatorId
sleep 5
adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done; input keyevent 82'
After this command is executed I run my tests like following;
dotnet test Droid.UI.test.dll
Any solution or workaround for skipping this prompt is highly appreciated,
Thanks!
Your script completely overrides the launchpad; that's the problem. Why not use gmtool? It has been designed especially for this type of use.
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?
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.
If i run instrumentation tests on my local emulator they run 10 out of 10 times perfectly but when I try to run the same tests on an AVD in Travis CI, I randomly get
FAILED java.lang.RuntimeException: Could not launch intent Intent { } within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen. Or the activity is doing network calls on creation? See the threaddump logs. For your reference the last time the event queue was idle before your activity launch request was xxxxxxx and now the last time the queue went idle was: xxxxxxxxx. If these numbers are the same your activity might be hogging the event queue.
I have tried removing all progress bars and everything but still its an issue that is only happening randomly and on Travis.
My travis.yml looks like this:
env:
global:
- ANDROID_TARGET=android-19
- ANDROID_ABI=armeabi-v7a
before_script:
- android list targets
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
- emulator -avd test -no-skin -no-audio -no-window -no-boot-anim &
- android-wait-for-emulator
- adb shell input keyevent 82 &
script:
- ./gradlew jacocoTestReport assembleAndroidTest connectedCheck zipalignRelease
If you want to use android-wait-for-emulator script, please remove the -no-boot-anim option it depends on to detect when emulator is ready.
Alternatively, replace the android-wait-for-emulator script by a fixed sleep time like this:
- sleep 300
- adb shell input keyevent 82 &
You need to choose the sleep time based on each API boot duration.
I have a problem and I do not know how to solve it.
How to know exactly the state of the emulator: not working, loaded, device
I'm creating a build of the application on the server using TeamCity.
It describes the steps of the assembly build.
The first step is launching the emulator with the bash script:
Step 1: Emulator start
Runner type: Command Line (Simple command execution)
Custom script:
#!/bin/bash
DEVICES=`adb devices`
echo $DEVICES
if [[ $DEVICES == *emulator*device* ]]
then
echo "Emulator has already been running"
else
if [[ $DEVICES == *emulator* ]]
then
adb emu kill
echo "All previous emulator were killed"
fi
echo "Launching new emulator..."
emulator #Emul -no-window &
adb wait-for-device
sleep 60 #android os should start completely
echo "Emulator launched"
adb devices
fi
The problem is that the emulator upon hanging.
The script hangs on the statement: “adb wait-for-device”
And does not continue its execution.
And the build process does not continue. And then everything builds in TeamCity crash.
Have to manually connect via VNC and restart emulator.
Can you tell as well:
or to receive information from the emulator on his condition;
(more than the right decision “adb wait-for-device ” )
or how to catch the time delay signal processing response and restart the script is executed within the TeamCity
Thank you for your attention to the issue
It show only two step of Emulater.
1.Online
2.offline
to know stage of Emulator... Type following command.
C:\path to sdks\adb devices
It will show whether your emulator is active or not and show number of active emulator.