diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index ad94fb5ea..d5f65630c 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -305,7 +305,7 @@ steps: concurrency_group: 'bitbar-web' concurrency_method: eager - - label: 'BitBar app-automate - Android 10' + - label: 'BitBar app-automate - Android' timeout_in_minutes: 20 depends_on: - "appium-test-fixture" @@ -321,7 +321,7 @@ steps: command: - "--app=build/outputs/apk/release/app-release.apk" - "--farm=bb" - - "--device=ANDROID_10" + - "--device=ANDROID_10|ANDROID_11|ANDROID_12|ANDROID_13" - "--fail-fast" - "--no-tunnel" - "--aws-public-ip" diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bd176a75..b3692c0f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Enhancements +- Allow a list of BitBar device groups to be selected from [529](https://github.com/bugsnag/maze-runner/pull/529) + +# 7.29.0 - 2023/05/09 + +## Enhancements + - Update appium capabilities for appium 2.0 compatibility [512](https://github.com/bugsnag/maze-runner/pull/512) - Add support for Edge latest on BrowserStack [528](https://github.com/bugsnag/maze-runner/pull/528) diff --git a/docs/Device_Mode.md b/docs/Device_Mode.md index ad047ddeb..6353df26a 100644 --- a/docs/Device_Mode.md +++ b/docs/Device_Mode.md @@ -41,7 +41,7 @@ bundle exec maze-runner features/smoke_tests \ --fail-fast ``` -In the case of BitBar, the `--device` option maps directly to the name of either a device, or a device group configured in the BitBar dashboard. +For BitBar, the `--device` option maps directly to the name of either a device, or a device group configured in the BitBar dashboard. Multiple device groups can also be listed, separated by a pipe. Maze Runner will select an available device from them at random. E.g. `--device=ANDROID_10|ANDROID_11`. ## Appium client modes diff --git a/lib/maze/client/appium/bb_devices.rb b/lib/maze/client/appium/bb_devices.rb index 74dd5722c..4d49e300d 100644 --- a/lib/maze/client/appium/bb_devices.rb +++ b/lib/maze/client/appium/bb_devices.rb @@ -9,24 +9,25 @@ module Appium class BitBarDevices class << self # Uses the BitBar API to find an available device from the group name given, or a device of that name - # @param device_or_group_name [String] Name of the device, or device group for which to find an available device + # @param device_or_group_names [String] Name of the device, or device group(s) for which to find an available + # device. Multiple device group names can be separated by a pipe. # @return Capabilities hash for the available device - def get_available_device(device_or_group_name) + def get_available_device(device_or_group_names) api_client = BitBarApiClient.new(Maze.config.access_key) - device_group_id = api_client.get_device_group_id(device_or_group_name) - if device_group_id + device_group_ids = api_client.get_device_group_ids(device_or_group_names) + if device_group_ids # Device group found - find a free device in it - $logger.debug "Got group id #{device_group_id} for #{device_or_group_name}" - group_count, device = api_client.find_device_in_group(device_group_id) + $logger.debug "Got group ids #{device_group_ids} for #{device_or_group_names}" + group_count, device = api_client.find_device_in_groups(device_group_ids) if device.nil? # TODO: Retry rather than fail, see PLAT-7377 Maze::Helper.error_exit 'There are no devices available' else - $logger.info "#{group_count} device(s) currently available in group '#{device_or_group_name}'" + $logger.info "#{group_count} device(s) currently available in group(s) '#{device_or_group_names}'" end else # See if there is a device with the given name - device = api_client.find_device device_or_group_name + device = api_client.find_device device_or_group_names end device_name = device['displayName'] diff --git a/lib/maze/client/bb_api_client.rb b/lib/maze/client/bb_api_client.rb index bbd63eeca..70ff59466 100644 --- a/lib/maze/client/bb_api_client.rb +++ b/lib/maze/client/bb_api_client.rb @@ -20,30 +20,38 @@ def get_device_list_for_group(device_group_id) query_api(path) end - # Get the id of a device group given its name - def get_device_group_id(device_group_name) + # Get the id(s) of a one or more device groups given their names. Multiple device group names should be separated + # by a pipe (which is directly supported by the BitBar API) + def get_device_group_ids(device_group_names) query = { - 'filter': "displayName_eq_#{device_group_name}" + 'filter': "displayName_in_#{device_group_names}" } device_groups = query_api('device-groups', query) if device_groups['data'].nil? || device_groups['data'].size == 0 nil else - device_groups['data'][0]['id'] + device_groups['data'].map { |group| group['id'] } end end - def find_device_in_group(device_group_id) - path = "device-groups/#{device_group_id}/devices" - query = { - 'filter': "online_eq_true" - } - all_devices = query_api(path, query) + def find_device_in_groups(device_group_ids) + all_devices = [] + device_group_ids.each do |group_id| + path = "device-groups/#{group_id}/devices" + query = { + 'filter': "online_eq_true" + } + all_devices += query_api(path, query)['data'] + end + + $logger.debug "All available devices in group(s) #{device_group_ids}: #{JSON.pretty_generate(all_devices)}" + filtered_devices = all_devices.reject { |device| device['locked'] } - $logger.debug "All available devices in group #{device_group_id}: #{JSON.pretty_generate(all_devices)}" - Maze::Plugins::DatadogMetricsPlugin.send_gauge('bitbar.device.available', all_devices['data'].size, [Maze.config.device]) - filtered_devices = all_devices['data'].reject { |device| device['locked'] } - Maze::Plugins::DatadogMetricsPlugin.send_gauge('bitbar.device.unlocked', filtered_devices.size, [Maze.config.device]) + # Only send gauges to DataDog for single device groups + if device_group_ids.size == 1 + Maze::Plugins::DatadogMetricsPlugin.send_gauge('bitbar.device.available', all_devices.size, [Maze.config.device]) + Maze::Plugins::DatadogMetricsPlugin.send_gauge('bitbar.device.unlocked', filtered_devices.size, [Maze.config.device]) + end return filtered_devices.size, filtered_devices.sample end