Lampo is developed to run appium mobile automation scripts on mobile devices connected to remote machines. It also aims at allowing users to interact with remotely connected devices for manual testing.
Here, we have a master-slave architecture where anyone can attach their machines as slaves to master and share their devices with anyone within the organisation to use remotely and all the devices are managed centrally by the master application. These attached devices can be used for both automation and manual testing.
Note: Master and Slave can be installed on the same machine or separate machines. It is recommended to have it on separate machines.
- Use mobile devices for running automated tests using Appium and Selenium Grid.
- Use mobile devices for manual testing using OpenSTF.
- Currently limited to android devices for manual testing.
- Run automated tests on both android and iOS devices.
- Limiting devices to a team and avoid starvation when running automated tests.
- View summary of number of automated test session created by each team and duration .
- Video recording of test session using Flick.
- Host iOS and android app files from within the application.
Please follow the link for installing Oracle JDK 8 or link for AdoptJDK / Temurin.
Please follow the link for installing RabbitMQ.
For installation on Mac, run the following commands from terminal:
brew update
brew install rabbitmq
For enabling the rabbitmq service to run in background in Mac, run the following command:
brew services start rabbitmq
Run the following commands to create an user for remote connect:
rabbitmq-plugins enable rabbitmq_management
rabbitmqctl add_user connect connect
rabbitmqctl set_permissions -p / connect ".*" ".*" ".*"
rabbitmqctl set_user_tags connect administrator
Please follow the link for installing MongoDB Community Server.
For installation on Mac, run the following commands from terminal:
brew tap mongodb/brew
brew install mongodb-community
For enabling the mongodb service to run in background in Mac, run the following command:
brew services start mongodb-community
cd master && ./gradlew clean build bootWar
Once the application is built successfully, build/libs/master.war
will be created. Run the following command to start the master application:
java -jar build/libs/master.war
Note: Make sure rabbitmq and mongodb services are up and running.
This command can be run in background using the following command:
java -jar build/libs/master.war > master.log 2>&1 < /dev/null &
Property | Description | Default Value |
---|---|---|
custom.reap_sessions.enabled | reaping dead session that are not active or terminated | false |
custom.max_session_duration | maximum run time of each test session in seconds | 900 |
custom.session.wait_timeout | maximum duration of inactivity or idle timeout in seconds before a session is terminated | 180 |
custom.session.polling_timeout | maximum time to wait for allocation or finding a matching node with given capabilities | 300 |
cron.reap_long_running_sessions | cron expresssion for checking long running sessions | */30 * * * * ? |
cron.check_grid_service | cron expression for checking the health of grid service | */15 * * * * ? |
cron.reap_dead_sessions | cron expression for checking on the dead or inactive or terminated sessions | */15 * * * * ? |
custom.upload_dirs | directory to which the apps should be uploaded to when using the uploader | files |
Note: All the above configurations can be overridden by passing them when launching the application from commandline as well by prefixing --key=value or by sending as JVM argument (-Dkey=value).
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>lampo-master</string>
<key>ServiceDescription</key>
<string>Lampo Device Lab Master</string>
<key>UserName</key>
<string>lampo</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/usr/local/share/tools/lampo/master/master.bash</string>
<string>restart</string>
</array>
<key>RunAtLoad</key>
<true />
<key>KeepAlive</key>
<true />
<key>WorkingDirectory</key>
<string>/usr/local/share/tools/mobile-device-lab/master</string>
</dict>
</plist>
For enabling the service:
sudo launchctl load /Library/LaunchDaemons/lampo-master.plist
Sample master.bash
echo "--------- starting services ---------"
cd /usr/local/share/tools/mobile-device-lab/master
port=80
lsof -nti:$port | xargs kill -9
session_wait_timeout=900
java -Dserver.port=${port} -Dcustom.session.wait_timeout=${session_wait_timeout} -Dspring.main.allow-circular-references=true -jar master.war
Add the following content in /etc/systemd/system/lampo-master.service
Description=Lampo Device Lab Master
[Service]
User=root
WorkingDirectory=/usr/local/share/tools/lampo/master
ExecStart=/usr/local/share/tools/lampo/master/master.bash
SuccessExitStatus=143
TimeoutStopSec=10
Restart=always
RestartSec=15
[Install]
WantedBy=multi-user.target
For enabling and restarting the service
sudo systemctl enable lampo-master
sudo systemctl daemon-reload
sudo service lampo-master restart
Sample master.bash
echo "--------- starting services ---------"
cd /usr/local/share/tools/mobile-device-lab/master
port=80
fuser -k ${port}/tcp
session_wait_timeout=900
java -Dserver.port=${port} -Dcustom.session.wait_timeout=${session_wait_timeout} -Dspring.main.allow-circular-references=true -jar master.war
Please follow the link for installing Oracle JDK 8 or link for AdoptJDK / Temurin.
- Install Android Studio from https://developer.android.com/studio
- From SDK Manager → SDK Tools, install Android Emulator, Android SDK Platform-Tools, Android SDK Tools
- From AVD Manager → Create New Virtual Device, if required Once this installation is done, Android Studio is not required anymore. It can be removed.
Note:
Make sure ANDROID_HOME environment variable is set. To know the path, open Android Studio → Configure (appear on lower bottom corner) → SDK Manager → Copy Android SDK Location
Default Location for ANDROID_HOME is /opt/android-sdk which can by set as a soft link using
sudo ln -s /path/android-sdk /opt/android-sdk
Please follow the link to install nvm or execute the following commands from terminal.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
Depending on the profile file ~/.bash_profile, ~/.zshrc, ~/.profile, or ~/.bashrc, add the following code in that file:
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
Xcode can be installed from App Store or https://developer.apple.com/download/ on your Mac machine.
We will be using node version 14.5.0 for appium installation.
-
For installing node version 14.5.0, run the following command:
nvm install 14.5.0
Note:
-
Slave application is tested for node version 14.5.0, but higher version can also be used at own risk.
-
Changing the version of node from 14.5.0 willl require source code change of slave as well in
slave/src/main/resources/scripts/wd-session.bash
.
-
-
For switching to node version 14.5.0, run the following command:
nvm use --delete-prefix v14.5.0
-
For installing appium, please follow the link or execute the following commands from terminal:
npm -g install appium
-
For iOS devices on Mac:
brew install ideviceinstaller ios-deploy carthage
-
Optional Dependencies for iOS Devices:
brew tap facebook/fb brew install fbsimctl --HEAD
Flick offers video recording of mobile device. Run the following command for installing:
gem install flick
Flick supports android real devices, android emulators, iOS real devices only. iOS simulators are not supported.
Please follow the link for installing stf.
For installation on Mac, please run the following commands from terminal:
brew install rethinkdb graphicsmagick zeromq protobuf yasm pkg-config
For enabling the rethinkdb service to run in background in Mac, run the following command:
brew services start rethinkdb
For installing stf, run the following command;
nvm use --delete-prefix v8.16.1
npm install -g @devicefarmer/stf
Note: Node version 8.16.1 is being used for stf. Please check OpenSTF documentation to check if higher version of node can we used.
cd slave && ./gradlew clean build bootWar
Once the application is built, will be created build/libs/remote-slave-app.war. Run the following command to launch and attach the slave to master.
java -jar build/libs/remote-slave-app.war --master.host=127.0.0.1
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>lampo-slave</string>
<key>ServiceDescription</key>
<string>Lampo Device Lab Slave</string>
<key>UserName</key>
<string>lampo</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/usr/local/share/lampo/slave/slave.bash</string>
<string>restart</string>
</array>
<key>RunAtLoad</key>
<true />
<key>KeepAlive</key>
<true />
<key>WorkingDirectory</key>
<string>/usr/local/share/tools/lampo/slave</string>
</dict>
</plist>
For enabling the service:
sudo launchctl load /Library/LaunchDaemons/lampo-slave.plist
Sample slave.bash
echo "--------- starting services -----------"
cd /usr/local/share/tools/lampo/slave
adb kill-server && adb start-server
port=5353
lsof -nti:${port} | xargs kill -9
java -Dmaster.host=localhost -jar slave.war
Add the following content in /etc/systemd/system/lampo-slave.service
Description=Lampo Device Lab Slave
[Service]
User=root
WorkingDirectory=/usr/local/share/tools/lampo/slave
ExecStart=/usr/local/share/tools/lampo/master/slave.bash
SuccessExitStatus=143
TimeoutStopSec=10
Restart=always
RestartSec=15
[Install]
WantedBy=multi-user.target
For enabling and restarting the service
sudo systemctl enable lampo-slave
sudo systemctl daemon-reload
sudo service lampo-slave restart
Sample slave.bash
echo "--------- starting services -----------"
cd /usr/local/share/tools/lampo/slave
adb kill-server && adb start-server
port=5353
fuser -k ${port}/tcp
java -Dmaster.host=localhost -jar slave.war
Refer to the background service creation of master/slave and just change the script file to the following:
Sample stf.bash
node_version="14.5.0"
ip=localhost
quality=10
ps -ef | grep stf | grep -v bash | grep -v grep | awk '{print $2}' | tr -s '\n' ' ' | xargs kill -9
nvm use --delete-prefix v$node_version --silent
export SCREEN_JPEG_QUALITY=$quality
stf local --cleanup false --public-ip $ip
BASE_URL - http://localhost:80
For restricting devices by team, add the following:
curl -iX POST 'BASE_URL/team' --header 'content-type: application/json' \
--data '{
"name" : "common",
"jobs": {
"job_name": [ "device-udid" ]
},
"devices" : {
"android" : [
"device-udid"
],
"ios" : [
"device-udid"
]
}
}'
jobs
is optional, to restrict the devices to a team and a specific job.
device-udid
supports regex also.
curl -iX DELETE 'BASE_URL/team/<team-name>'
Custom Capabilities that needs to be additionally added.
| Capability | Description | |:-------------:|:-------------:|:-------------:| | realDevice | to allocate real device or emulator (for android) or simulator (for ios) | | deviceName | finding a matching device with the given name | | platformVersion | finding a matching device with the given platform version | | clearUserData | clear user data from the matched device identified by given package or bundle id | | udid | finding a matching device with the given udid (device unique id) | | brand | finding a matching device with the given brand | | session.wait_timeout | maximum timeout for finding a matching device | | ci.user | requestor name | | ci.requestor_ip | requestor IP | | ci.team_name | requestor team name that should match the configured | | ci.job_link | CI job name (like jenkins job name using environment variable BUILD_URL) | | session.request_id | requestor unique request ID | | session.record_video | whether to record the video using Flick |
URL url = http://LAMPO_HOST:4444/wd/hub
AppiumDriver<MobileElement> driver = new AppiumDriver<>(url, capabilities)
Note: 4444 is selenium grid port
Appium logs will be present at, http://LAMPO_HOST/device/logs/<request-id>
Incase video recording is enabled (using capability session.record_video is set to true) for the test session, video will be present at, http://LAMPO_HOST/device/videos/<request-id>
Once both the applications are started successfully, open http://localhost to view the dashboard that displays the connected devices. If no slaves is connected to the master or slave(s) is connected but no devices are connected to the slave, then "No Device Available" wil be shown.
This page automatically refreshes every 5 seconds.
- From the dashboard, we can upload and host the app and view them as well.
- Dashboard shows all the devices connected across the slave machines.
- Each device shows which team the device belongs to.
- Incase there is any active test session using the connected device, it will be grayed out and the job link will be showing up along with the jenkins slave machine IP and the username.
- Incase if someone accessing OpenSTF of any device, the person's name will be showing up.
-
For finding the summary on a specific date
curl BASE_URL/summary/find?date=10-05-2022
-
For finding the summary between specific dates
curl BASE_URL/summary/find_between?start=10-05-2022&end=16-05-2022
-
For finding the total summary between specific dates
curl BASE_URL/summary/total_between?start=10-05-2022&end=16-05-2022
- Make sure master and slave ports are able to communicate with each other.
- Sometime devices on STF becomes inaccessible, restart the STF service in that case.