Appium Test Execution on a Remote Device
Frank Moyer
Mobile test automation teams often face the challenge of orchestrating test executions when device capacity runs out. A common question arises: Should the device lab platform itself queue up incoming test requests until a device is available, or should such logic be handled at the CI/CD or automation framework level?
In this post, we’ll explore the concept of device queuing, discuss why Kobiton (and other platforms) may prefer not to provide an enforced queue, how Kobiton’s Device Reservation feature offers an alternative, and show you how to implement an effective polling strategy in your CI/CD pipelines—complete with code snippets for GitLab CI.
Device Queuing is a mechanism by which test sessions that exceed the current device capacity are placed in a waiting line until a device becomes free. When all devices are busy:
While a built-in queue sounds convenient, it can come with downsides, including hidden timeouts, unintended bottlenecks, and reduced flexibility to prioritize or reroute tests.
Although automatic queuing is useful in some scenarios, it can introduce complexities:
Kobiton’s philosophy is to give you full control over how your tests are queued and retried:

While Kobiton does not implement a first-in, first-out queue for devices, it does provide a Device Reservation feature that allows you to reserve specific devices in advance. This can be particularly beneficial for critical or high-priority test suites that must have guaranteed access to a device at a specific time.
Important Note: Reserved devices that are left idle mean fewer devices are available to the general pool. Striking a balance between reserved and non-reserved devices is key to avoiding overall device underutilization.
Even with Device Reservation, you may still need to handle concurrency for non-reserved devices. Below is the general approach for setting up CI/CD-level polling:
Note: Replace “<BASE64_ENCODED_CREDS>” with your actual Kobiton authorization header (Basic Auth token) or whatever credentials your organization uses.
5.1 GitLab CI/CD Example
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
[crayon-691ff50e2e73f188064442 inline="true" ]<span class="line"><span style="color: #FAD000">stages</span><span style="color: #E1EFFF">:</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">check_devices</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">run_tests</span></span> <span class="line"></span> <span class="line"><span style="color: #FAD000">check_devices</span><span style="color: #E1EFFF">:</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FAD000">stage</span><span style="color: #E1EFFF">:</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">check_devices</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FAD000">image</span><span style="color: #E1EFFF">:</span><span style="color: #FFFFFF"> </span><span style="color: #FAD000">alpine</span><span style="color: #E1EFFF">:</span><span style="color: #FF628C">3</span><span style="color: #9EFFFF">.</span><span style="color: #FF628C">16</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FAD000">script</span><span style="color: #E1EFFF">:</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">apk</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">add</span><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">--</span><span style="color: #9EFFFF">no</span><span style="color: #FF9D00">-</span><span style="color: #9EFFFF">cache</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">curl</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">jq</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">|</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">max_retries</span><span style="color: #FF9D00">=</span><span style="color: #FF628C">5</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">wait_interval</span><span style="color: #FF9D00">=</span><span style="color: #FF628C">30</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">device_available</span><span style="color: #FF9D00">=</span><span style="color: #FF628C">false</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">for</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">i</span><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">in</span><span style="color: #FFFFFF"> </span><span style="color: #FAD000">$</span><span style="color: #E1EFFF">(</span><span style="color: #9EFFFF">seq</span><span style="color: #FFFFFF"> </span><span style="color: #FF628C">1</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">$max_retries</span><span style="color: #E1EFFF">);</span><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">do</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">available_count</span><span style="color: #FF9D00">=</span><span style="color: #FAD000">$</span><span style="color: #E1EFFF">(</span><span style="color: #9EFFFF">curl</span><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #9EFFFF">s</span><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #9EFFFF">X</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">GET</span><span style="color: #FFFFFF"> </span><span style="color: #92FC79">"</span><span style="color: #A5FF90">https://api.kobiton.com/v1/devices</span><span style="color: #92FC79">"</span><span style="color: #FFFFFF"> \</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #9EFFFF">H</span><span style="color: #FFFFFF"> </span><span style="color: #92FC79">"</span><span style="color: #A5FF90">Authorization: Basic <BASE64_ENCODED_CREDS></span><span style="color: #92FC79">"</span><span style="color: #FFFFFF"> \</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">|</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">jq</span><span style="color: #FFFFFF"> </span><span style="color: #92FC79">'</span><span style="color: #A5FF90">[.devices[] | select(.isAvailable == true)] | length</span><span style="color: #92FC79">'</span><span style="color: #E1EFFF">)</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">if</span><span style="color: #9EFFFF"> </span><span style="color: #E1EFFF">[</span><span style="color: #9EFFFF"> </span><span style="color: #92FC79">"</span><span style="color: #A5FF90">$available_count</span><span style="color: #92FC79">"</span><span style="color: #9EFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #9EFFFF">gt </span><span style="color: #FF628C">0</span><span style="color: #9EFFFF"> </span><span style="color: #E1EFFF">];</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">then</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">echo</span><span style="color: #FFFFFF"> </span><span style="color: #92FC79">"</span><span style="color: #A5FF90">Device is available.</span><span style="color: #92FC79">"</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">device_available</span><span style="color: #FF9D00">=</span><span style="color: #FF628C">true</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">break</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">else</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">echo</span><span style="color: #FFFFFF"> </span><span style="color: #92FC79">"</span><span style="color: #A5FF90">No available device. Retrying in $wait_interval seconds...</span><span style="color: #92FC79">"</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">sleep</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">$wait_interval</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">fi</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">done</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">if</span><span style="color: #9EFFFF"> </span><span style="color: #E1EFFF">[</span><span style="color: #9EFFFF"> </span><span style="color: #92FC79">"</span><span style="color: #A5FF90">$device_available</span><span style="color: #92FC79">"</span><span style="color: #9EFFFF"> </span><span style="color: #FF9D00">=</span><span style="color: #9EFFFF"> </span><span style="color: #FF628C">false</span><span style="color: #9EFFFF"> </span><span style="color: #E1EFFF">];</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">then</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">echo</span><span style="color: #FFFFFF"> </span><span style="color: #92FC79">"</span><span style="color: #A5FF90">No device became available after $max_retries retries.</span><span style="color: #92FC79">"</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">exit</span><span style="color: #FFFFFF"> </span><span style="color: #FF628C">1</span></span> <span class="line"></span> <span class="line"><span style="color: #FAD000">run_tests</span><span style="color: #E1EFFF">:</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FAD000">stage</span><span style="color: #E1EFFF">:</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">run_tests</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FAD000">script</span><span style="color: #E1EFFF">:</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #FFFFFF"> </span><span style="color: #9EFFFF">echo</span><span style="color: #FFFFFF"> </span><span style="color: #92FC79">"</span><span style="color: #A5FF90">Running tests...</span><span style="color: #92FC79">"</span></span> <span class="line"></span> <span class="line"><span style="color: #FFFFFF"> </span><span style="color: #FF9D00">-</span><span style="color: #FFFFFF"> # </span><span style="color: #9EFFFF">e</span><span style="color: #E1EFFF">.</span><span style="color: #FAD000">g</span><span style="color: #E1EFFF">.,</span><span style="color: #FFFFFF"> </span><span style="color: #92FC79">"</span><span style="color: #A5FF90">mvn test</span><span style="color: #92FC79">"</span></span> |
While these examples illustrate a straightforward polling mechanism, you can adapt them to better suit your organization:
Platform-level device queuing might sound attractive, but it can bring rigid timeouts, hidden bottlenecks, and reduced flexibility. Implementing CI/CD-level queuing or polling for mobile test automation places you in full control—letting you tailor the concurrency logic to your unique workflow and keep an eye on performance bottlenecks directly in your pipelines.
By leveraging Kobiton’s API alongside features like Device Reservation and your existing CI/CD pipeline, you can seamlessly manage when and how to run tests. The result is a more optimized automation flow, reduced risk of contention for devices, and confidence that critical tests will always have a device ready when they need it. Give Kobiton a try today!
