fastlane-plugin-saucectl 0.1.2 → 0.1.3.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'uri'
4
- require 'net/http'
5
- require 'open-uri'
6
- require 'json'
7
- require 'base64'
8
- require 'timeout'
9
- require 'fastlane_core/ui/ui'
10
- require 'fileutils'
11
-
12
- module Fastlane
13
- module Saucectl
14
- #
15
- # This class provides the functions required to interact with the saucectl api
16
- # for more information see: https://docs.saucelabs.com/dev/api/storage/
17
- #
18
- class Api
19
- UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
20
-
21
- def initialize(config)
22
- @config = config
23
- @encoded_auth_string = Base64.strict_encode64("#{@config[:sauce_username]}:#{@config[:sauce_access_key]}")
24
- @messages = YAML.load_file("#{__dir__}/../strings/messages.yml")
25
- end
26
-
27
- def available_devices
28
- path = 'v1/rdc/devices/available'
29
- https, url = build_http_request_for(path)
30
- request = Net::HTTP::Get.new(url)
31
- request['Authorization'] = "Basic #{@encoded_auth_string}"
32
- response = https.request(request)
33
- UI.user_error!("❌ Request failed: #{response.code} #{response.message}") unless response.kind_of?(Net::HTTPOK)
34
-
35
- JSON.parse(response.body)
36
- end
37
-
38
- def fetch_ios_devices
39
- devices = []
40
- get_devices = available_devices
41
- get_devices.each do |device|
42
- devices << device if device =~ /iPhone_.*/ || device =~ /iPad_.*/
43
- end
44
- devices
45
- end
46
-
47
- def fetch_android_devices
48
- devices = []
49
- get_devices = available_devices
50
- get_devices.each do |device|
51
- devices << device unless device =~ /iPhone_.*/ || device =~ /iPad_.*/
52
- end
53
- devices
54
- end
55
-
56
- def retrieve_all_apps
57
- UI.message("retrieving all apps for \"#{@config[:query]}\".")
58
- path = "v1/storage/files?q=#{@config[:query]}&kind=#{@config[:platform]}"
59
- https, url = build_http_request_for(path)
60
- request = Net::HTTP::Get.new(url)
61
- request['Authorization'] = "Basic #{@encoded_auth_string}"
62
- response = https.request(request)
63
-
64
- UI.user_error!("❌ Request failed: #{response.code} #{response.message}") unless response.kind_of?(Net::HTTPOK)
65
-
66
- response
67
- end
68
-
69
- def upload
70
- UI.message("⏳ Uploading \"#{@config[:app]}\" upload to Sauce Labs.")
71
- path = 'v1/storage/upload'
72
- https, url = build_http_request_for(path)
73
- request = Net::HTTP::Post.new(url)
74
- request['Authorization'] = "Basic #{@encoded_auth_string}"
75
- form_data = [['payload', File.open(@config[:file])], ['name', @config[:app]]]
76
- request.set_form(form_data, 'multipart/form-data')
77
- response = https.request(request)
78
- UI.success("✅ Successfully uploaded app to sauce labs: \n #{response.body}") if response.code.eql?('201')
79
- UI.user_error!("❌ Request failed: #{response.code} #{response.message}") unless response.code.eql?('201')
80
-
81
- response
82
- end
83
-
84
- def delete_app(path)
85
- https, url = build_http_request_for(path)
86
- request = Net::HTTP::Delete.new(url.path)
87
- request['Authorization'] = "Basic #{@encoded_auth_string}"
88
- response = https.request(request)
89
- UI.success("✅ Successfully deleted app from sauce labs storage: \n #{response.body}") if response.kind_of?(Net::HTTPOK)
90
- UI.user_error!("❌ Request failed: #{response.code} #{response.message}") unless response.kind_of?(Net::HTTPOK)
91
-
92
- response
93
- end
94
-
95
- def base_url_for_region
96
- case @config[:region]
97
- when 'eu' then base_url('eu-central-1')
98
- when 'us' then base_url('us-west-1')
99
- else UI.user_error!("#{@config[:region]} is an invalid region ❌. Available: #{@messages['supported_regions']}")
100
- end
101
- end
102
-
103
- def build_http_request_for(path)
104
- url = URI("#{base_url_for_region}/#{path}")
105
- https = Net::HTTP.new(url.host, url.port)
106
- https.use_ssl = true
107
- [https, url]
108
- end
109
-
110
- def base_url(region)
111
- "https://api.#{region}.saucelabs.com"
112
- end
113
- end
114
- end
115
- end
@@ -1,97 +0,0 @@
1
- require 'fileutils'
2
- require 'yaml'
3
- require 'uri'
4
- require 'net/http'
5
- require 'json'
6
- require 'base64'
7
- require 'open3'
8
- require_relative 'suites'
9
-
10
- module Fastlane
11
- module Saucectl
12
- #
13
- # This class creates saucectl config.yml file based on given specifications
14
- #
15
- class ConfigGenerator
16
- UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
17
-
18
- def initialize(config)
19
- @config = config
20
- end
21
-
22
- def base_config
23
- {
24
- 'apiVersion' => 'v1alpha',
25
- 'kind' => @config[:kind],
26
- 'retries' => @config[:retries],
27
- 'sauce' => {
28
- 'region' => set_region.to_s,
29
- 'concurrency' => @config[:max_concurrency_size],
30
- 'metadata' => {
31
- 'name' => "#{ENV['JOB_NAME']}-#{ENV['BUILD_NUMBER']}",
32
- 'build' => "Release #{ENV['CI_COMMIT_SHORT_SHA']}"
33
- }
34
- },
35
- (@config[:kind]).to_s => set_apps,
36
- 'artifacts' => {
37
- 'download' => {
38
- 'when' => 'always',
39
- 'match' => ['junit.xml'],
40
- 'directory' => './artifacts/'
41
- }
42
- },
43
- 'reporters' => {
44
- 'junit' => {
45
- 'enabled' => true
46
- }
47
- }
48
- }
49
- end
50
-
51
- def set_region
52
- case @config[:region]
53
- when 'eu'
54
- 'eu-central-1'
55
- else
56
- 'us-west-1'
57
- end
58
- end
59
-
60
- def set_apps
61
- {
62
- 'app' => @config[:app],
63
- 'testApp' => @config[:test_app]
64
- }
65
- end
66
-
67
- def create
68
- UI.message("Creating saucectl config .....🚕💨")
69
- file_name = 'config.yml'
70
- UI.user_error!("❌ Sauce Labs platform does not support virtual device execution for ios apps") if @config[:platform].eql?('ios') && @config[:emulators]
71
-
72
- config = base_config.merge(create_suite)
73
- out_file = File.new(file_name, 'w')
74
- out_file.puts(config.to_yaml)
75
- out_file.close
76
- creat_sauce_dir
77
- FileUtils.move(file_name, './.sauce')
78
- UI.message("Successfully created saucectl config ✅") if Dir.exist?('.sauce')
79
- UI.user_error!("Failed to create saucectl config ❌") unless Dir.exist?('.sauce')
80
- end
81
-
82
- def create_suite
83
- suite = Fastlane::Saucectl::Suites.new(@config)
84
- { 'suites' => if @config[:emulators]
85
- suite.create_virtual_device_suites
86
- else
87
- suite.create_real_device_suites
88
- end }
89
- end
90
-
91
- def creat_sauce_dir
92
- dirname = '.sauce'
93
- FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
94
- end
95
- end
96
- end
97
- end
@@ -1,93 +0,0 @@
1
- require "find"
2
- require "open3"
3
- require "json"
4
- require_relative "file_utils"
5
-
6
- module Fastlane
7
- module Saucectl
8
- # This class is responsible for creating test execution plans for android applications and will distribute tests
9
- # that will be be executed via the cloud provider.
10
- #
11
- class Espresso
12
- include FileUtils
13
- UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
14
-
15
- TEST_FUNCTION_REGEX = /([a-z]+[A-Z][a-zA-Z]+)[(][)]/.freeze
16
-
17
- def initialize(config)
18
- @config = config
19
- end
20
-
21
- def test_data
22
- test_details = []
23
- search_retrieve_test_classes(@config[:path_to_tests]).each do |f|
24
- next unless File.basename(f) =~ CLASS_NAME_REGEX
25
-
26
- test_details << { package: File.readlines(f).first.chomp.gsub("package ", "").gsub(";", ""),
27
- class: File.basename(f).gsub(FILE_TYPE_REGEX, ""),
28
- tests: tests_from(f) }
29
- end
30
-
31
- strip_empty(test_details)
32
- end
33
-
34
- def test_distribution
35
- test_distribution_check
36
- tests_arr = []
37
- case @config[:test_distribution]
38
- when "package"
39
- test_data.each { |type| tests_arr << type[:package] }
40
- when 'class', 'shard'
41
- test_data.each { |type| tests_arr << "#{type[:package]}.#{type[:class]}" }
42
- else
43
- test_data.each do |type|
44
- type[:tests].each { |test| tests_arr << "#{type[:package]}.#{type[:class]}##{test}" }
45
- end
46
- end
47
- tests_arr.uniq
48
- end
49
-
50
- def test_distribution_check
51
- return @config[:test_distribution] if @config[:test_distribution].kind_of?(Array)
52
-
53
- distribution_types = %w[class testCase package shard]
54
- unless distribution_types.include?(@config[:test_distribution]) || @config[:test_distribution].nil?
55
- UI.user_error!("#{@config[:test_distribution]} is not a valid method of test distribution")
56
- end
57
- end
58
-
59
- def strip_empty(test_details)
60
- tests = []
61
- test_details.each { |test| tests << test unless test[:tests].size.zero? }
62
- tests
63
- end
64
-
65
- def tests_from(path)
66
- stdout, = find(path, "@Test")
67
- test_cases = []
68
- stdout.split.each do |line|
69
- test_cases << line.match(TEST_FUNCTION_REGEX).to_s.gsub(/[()]/, "") if line =~ TEST_FUNCTION_REGEX
70
- end
71
- strip_skipped(path, test_cases)
72
- end
73
-
74
- def fetch_disabled_tests(path)
75
- stdout, = find(path, "@Ignore")
76
- test_cases = []
77
- stdout.split.each do |line|
78
- test_cases << line.match(TEST_FUNCTION_REGEX).to_s.gsub(/[()]/, "") if line =~ TEST_FUNCTION_REGEX
79
- end
80
- test_cases
81
- end
82
-
83
- def strip_skipped(path, tests)
84
- enabled_ui_tests = []
85
- skipped_tests = fetch_disabled_tests(path)
86
- tests.each do |test|
87
- enabled_ui_tests << test unless skipped_tests.include?(test)
88
- end
89
- enabled_ui_tests
90
- end
91
- end
92
- end
93
- end
@@ -1,27 +0,0 @@
1
- require "open3"
2
-
3
- # utility module for helper functions
4
- module FileUtils
5
- CLASS_NAME_REGEX = /(Spec|Specs|Test|Tests)/.freeze
6
- FILE_TYPE_REGEX = /(.swift|.kt|.java)/.freeze
7
-
8
- def read_file(name)
9
- raise "File not found: #{name}" unless File.exist?(name)
10
-
11
- File.read(name).split
12
- end
13
-
14
- def search_retrieve_test_classes(path)
15
- Find.find(path).select do |f|
16
- File.file?(f) if File.basename(f) =~ CLASS_NAME_REGEX
17
- end
18
- end
19
-
20
- def find(class_name, regex)
21
- syscall("find '#{class_name}' -type f -exec grep -h -C2 '#{regex}' {} +")
22
- end
23
-
24
- def syscall(*cmd)
25
- Open3.capture3(*cmd)
26
- end
27
- end
@@ -1,54 +0,0 @@
1
- require 'fastlane_core/ui/ui'
2
- require 'fastlane'
3
- require 'open-uri'
4
- require_relative 'file_utils'
5
-
6
- module Fastlane
7
- module Saucectl
8
- #
9
- # This class provides the functions required to install the saucectl binary
10
- #
11
- class Installer
12
- include FileUtils
13
- UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
14
-
15
- def install(version)
16
- timeout_in_seconds = 90
17
- Timeout.timeout(timeout_in_seconds) do
18
- download_saucectl_installer
19
- execute_saucectl_installer(version)
20
- UI.success("✅ Successfully installed saucectl runner binary 🚀")
21
- rescue OpenURI::HTTPError => e
22
- response = e.io
23
- UI.user_error!("❌ Failed to install saucectl binary: status #{response.status[0]}")
24
- end
25
- end
26
-
27
- def download_saucectl_installer
28
- URI.open('sauce', 'wb') do |file|
29
- file << URI.open('https://saucelabs.github.io/saucectl/install', ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE).read
30
- end
31
- end
32
-
33
- def execute_saucectl_installer(version)
34
- saucectl_version = version[:version].nil? ? '' : "v#{version[:version]}"
35
- status = system("sh sauce #{saucectl_version}")
36
- status == 1 ? UI.user_error!("❌ failed to install saucectl") : status
37
- executable = 'saucectl'
38
- FileUtils.mv("bin/#{executable}", executable) unless File.exist?(executable)
39
- end
40
-
41
- def system(*cmd)
42
- Open3.popen2e(*cmd) do |stdin, stdout_stderr, wait_thread|
43
- Thread.new do
44
- stdout_stderr.each do |out|
45
- UI.message(out)
46
- end
47
- end
48
- stdin.close
49
- wait_thread.value
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,39 +0,0 @@
1
- require 'fastlane'
2
- require 'open3'
3
- require 'fastlane_core/ui/ui'
4
- require_relative "file_utils"
5
-
6
- module Fastlane
7
- module Saucectl
8
- #
9
- # This class provides the ability to execute tests via configured specifications and capture the output of the sauce executable.
10
- #
11
- class Runner
12
- include FileUtils
13
- EXECUTABLE = 'saucectl'
14
- UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
15
-
16
- def execute
17
- unless File.exist?(EXECUTABLE)
18
- UI.user_error!("❌ sauce labs executable file does not exist! Expected sauce executable file to be located at:'#{Dir.pwd}/#{EXECUTABLE}'")
19
- end
20
-
21
- system("chmod +x #{EXECUTABLE}")
22
- system("./#{EXECUTABLE} run")
23
- end
24
-
25
- def system(*cmd)
26
- Open3.popen2e(*cmd) do |stdin, stdout_stderr, wait_thread|
27
- Thread.new do
28
- stdout_stderr.each do |out|
29
- message = out.gsub(/(?:\[[^\]].*\])|(?:\(\d{4}\))/, '')
30
- puts(message)
31
- end
32
- end
33
- stdin.close
34
- wait_thread.value
35
- end
36
- end
37
- end
38
- end
39
- end
@@ -1,46 +0,0 @@
1
- require 'uri'
2
- require 'net/http'
3
- require 'json'
4
- require_relative 'api'
5
-
6
- module Fastlane
7
- module Saucectl
8
- # This class provides the ability to store, delete, and retrieve data from the Sauce Labs Storage API
9
- class Storage
10
- def initialize(config)
11
- @config = config
12
- end
13
-
14
- # Get App Storage Files
15
- # @return the set of files that have been uploaded to Sauce Storage by the requester.
16
- def retrieve_all_apps
17
- api = Fastlane::Saucectl::Api.new(@config)
18
- api.retrieve_all_apps
19
- end
20
-
21
- # Delete app by the Sauce Labs identifier of the stored file. You can look up file IDs using the Get App Storage Files endpoint.
22
- # https://docs.saucelabs.com/dev/api/storage/#get-app-storage-files
23
- # @return json response containing the file id and the number of files deleted.
24
- def delete_app_with_file_id
25
- api = Fastlane::Saucectl::Api.new(@config)
26
- api.delete_app("v1/storage/files/#{@config[:app_id]}")
27
- end
28
-
29
- # Deletes the specified group of files from Sauce Storage.
30
- # The Sauce Labs identifier of the group of files. You can look up file IDs using the Get App Storage Groups endpoint.
31
- # https://docs.saucelabs.com/dev/api/storage/#get-app-storage-groups
32
- # @return json response containing the group ID and the number of files deleted.
33
- def delete_all_apps_for_group_id
34
- path = "v1/storage/files/#{@config[:group_id]}"
35
- api = Fastlane::Saucectl::Api.new(@config)
36
- api.delete_app(path)
37
- end
38
-
39
- # Uploads an application file to Sauce Storage for the purpose of mobile application testing
40
- # @return a unique file ID assigned to the app.
41
- def upload_app
42
- Fastlane::Saucectl::Api.new(@config).upload
43
- end
44
- end
45
- end
46
- end
@@ -1,219 +0,0 @@
1
- require 'base64'
2
- require 'fastlane'
3
- require 'fastlane_core/ui/ui'
4
- require_relative 'espresso'
5
- require_relative 'xctest'
6
-
7
- module Fastlane
8
- module Saucectl
9
- #
10
- # This class will create test suites based on user specified configuration properties
11
- #
12
- class Suites
13
- include FileUtils
14
-
15
- UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
16
-
17
- def initialize(config)
18
- @config = config
19
- end
20
-
21
- def create_test_plan
22
- check_kind
23
- if @config[:platform].casecmp('ios').zero?
24
- is_ios_reqs_satisfied?
25
- Fastlane::Saucectl::XCTest.new(@config)
26
- else
27
- Fastlane::Saucectl::Espresso.new(@config)
28
- end
29
- end
30
-
31
- def check_kind
32
- if @config[:platform].eql?('android')
33
- UI.user_error!("❌ #{@config[:kind]} is not a supported test framework for android. Use espresso") unless @config[:kind].eql?('espresso')
34
- else
35
- UI.user_error!("❌ #{@config[:kind]} is not a supported test framework for iOS. Use xcuitest") unless @config[:kind].eql?('xcuitest')
36
- end
37
- end
38
-
39
- def is_ios_reqs_satisfied?
40
- if @config[:test_target].nil? && @config[:test_plan].nil?
41
- UI.user_error!("❌ For ios you must specify test_target or test_plan")
42
- end
43
- end
44
-
45
- def test_distribution_array
46
- @config[:test_class] || create_test_plan.test_distribution
47
- end
48
-
49
- def suite_name(test_type)
50
- if ENV['JOB_NAME'].nil? && ENV['BUILD_NUMBER'].nil?
51
- "#{@config[:kind]}-#{test_type.split('.')[-1]}"
52
- else
53
- "#{ENV['JOB_NAME']}-#{ENV['BUILD_NUMBER']}-#{test_type.split('.')[-1]}"
54
- end
55
- end
56
-
57
- def create_virtual_device_suites
58
- if @config[:test_distribution] == 'shard'
59
- shard_virtual_device_suites
60
- elsif @config[:test_class]
61
- custom_test_classes
62
- else
63
- default_execution_suite
64
- end
65
- end
66
-
67
- def shard_virtual_device_suites
68
- UI.user_error!("❌ Cannot split #{@config[:test_distribution]}'s across virtual devices with a single emulator. \nPlease specify a minimum of two devices!") if @config[:emulators].size.eql?(1)
69
- test_suites = []
70
- arr = test_distribution_array
71
- shards = arr.each_slice((arr.size / @config[:emulators].size.to_f).round).to_a
72
- shards.each_with_index do |suite, i|
73
- test_suites << {
74
- 'name' => suite_name("shard #{i + 1}").downcase,
75
- 'testOptions' => default_test_options(suite)
76
- }.merge(virtual_device_options(@config[:emulators][i]))
77
- end
78
- test_suites
79
- end
80
-
81
- def shard_real_device_suites
82
- test_suites = []
83
- arr = test_distribution_array
84
- shards = arr.each_slice((arr.size / @config[:devices].size.to_f).round).to_a
85
- shards.each_with_index do |suite, i|
86
- test_suites << {
87
- 'name' => suite_name("shard #{i + 1}").downcase,
88
- 'testOptions' => default_test_options(suite)
89
- }.merge(real_device_options(@config[:devices][i]))
90
- end
91
- test_suites
92
- end
93
-
94
- def test_plan_suites
95
- test_suites = []
96
- @config[:devices].each do |device|
97
- test_suites << {
98
- 'name' => suite_name(@config[:test_plan].to_s).downcase,
99
- 'testOptions' => default_test_options(test_distribution_array)
100
- }.merge(real_device_options(device))
101
- end
102
- test_suites
103
- end
104
-
105
- def custom_test_classes
106
- test_suites = []
107
- devices = @config[:devices].nil? ? @config[:emulators] : @config[:devices]
108
- devices.each do |device|
109
- device_options = @config[:devices].nil? ? virtual_device_options(device) : real_device_options(device)
110
- test_classes = @config[:test_class].reject(&:empty?).join(',')
111
- test_suites << {
112
- 'name' => suite_name(device[:name]).downcase,
113
- 'testOptions' => default_test_options(test_classes.split(','))
114
- }.merge(device_options)
115
- end
116
- test_suites
117
- end
118
-
119
- def create_real_device_suites
120
- if !@config[:test_plan].nil? && @config[:test_distribution].eql?('class')
121
- test_plan_suites
122
- elsif @config[:test_distribution] == 'shard'
123
- shard_real_device_suites
124
- elsif @config[:test_class].kind_of?(Array)
125
- custom_test_classes
126
- else
127
- default_execution_suite
128
- end
129
- end
130
-
131
- def default_execution_suite
132
- type = @config[:annotation] ? 'annotation' : 'size'
133
- UI.user_error!("❌ execution by #{type} is not supported on the iOS platform!") if @config[:platform].eql?('ios') && (@config[:size] || @config[:annotation])
134
- is_real_device = @config[:devices]
135
- test_devices = @config[:devices] || @config[:emulators]
136
- test_suites = []
137
- if @config[:size] || @config[:annotation]
138
- test_devices.each do |device|
139
- test_suites << {
140
- 'name' => suite_name(@config[:size] || @config[:annotation]).downcase,
141
- 'testOptions' => default_test_options(@config[:size])
142
- }.merge(is_real_device ? real_device_options(device) : virtual_device_options(device))
143
- end
144
- else
145
- test_devices.each do |device|
146
- test_distribution_array.each do |test_type|
147
- test_suites << {
148
- 'name' => suite_name(test_type).downcase,
149
- 'testOptions' => default_test_options(test_type)
150
- }.merge(is_real_device ? real_device_options(device) : virtual_device_options(device))
151
- end
152
- end
153
- end
154
- test_suites
155
- end
156
-
157
- def virtual_device_options(device)
158
- platform_versions = device[:platform_versions].reject(&:empty?).join(',')
159
- { 'emulators' => [{ 'name' => device[:name],
160
- 'orientation' => device[:orientation],
161
- 'platformVersions' => platform_versions.split(',') }] }
162
- end
163
-
164
- def real_device_options(device)
165
- { 'devices' => [rdc_options(device)] }
166
- end
167
-
168
- def rdc_options(device)
169
- device_type_key = device.key?(:id) ? 'id' : 'name'
170
- name = device.key?(:id) ? device[:id] : device[:name]
171
-
172
- base_device_hash = {
173
- device_type_key => name,
174
- 'orientation' => device[:orientation]
175
- }.merge('options' => device_options(device))
176
-
177
- unless device[:platform_version].nil?
178
- base_device_hash = base_device_hash.merge({ 'platformVersion' => device[:platform_version] })
179
- end
180
-
181
- base_device_hash
182
- end
183
-
184
- def device_options(device)
185
- {
186
- 'carrierConnectivity' => device[:carrier_connectivity],
187
- 'deviceType' => device[:device_type].upcase!,
188
- 'private' => device[:private]
189
- }
190
- end
191
-
192
- def default_test_options(test_type)
193
- if @config[:platform] == 'android'
194
- test_option_type(test_type)
195
- else
196
- { 'class' => test_type }
197
- end
198
- end
199
-
200
- def test_option_type(test_type)
201
- if @config[:size] || @config[:annotation]
202
- key = @config[:size] ? 'size' : 'annotation'
203
- value = @config[:size] || @config[:annotation]
204
- { key => value }.merge(android_test_options)
205
- else
206
- test_option_type = @config[:test_distribution].eql?('package') ? 'package' : 'class'
207
- { test_option_type => test_type }.merge(android_test_options)
208
- end
209
- end
210
-
211
- def android_test_options
212
- {
213
- 'clearPackageData' => @config[:clear_data],
214
- 'useTestOrchestrator' => @config[:use_test_orchestrator]
215
- }
216
- end
217
- end
218
- end
219
- end