fastlane-plugin-automated_test_emulator_run_xing 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d8cd0f05420fa809c04b87544ca487705e10d733
4
+ data.tar.gz: 33ee66983a168007a6e057f1d8cbaa2075e13052
5
+ SHA512:
6
+ metadata.gz: 5c2b067cff79db0c34b8b1a0418560977bcb73caa65dfb3dabeb7172247647a7fbe7d6cac7ca28a100ca363eb29b6e0e576f49e2cb6a709d0f580e38fca8d345
7
+ data.tar.gz: b6653040d8f95c5d68774e2af002a17f6bf59df5438e8c19680d719aca660af13134b606d9f296cac16e52856a06e394a41dba1c3eaf18ea1f47c21b9f1130a8
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Kamil Krzyk <krzyk.kamil@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # automated_test_emulator_run plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-automated_test_emulator_run)
4
+
5
+ <b>(article is deprecated - covered plugin version < 1.3.2 which doesn't support Build-Tools ver. >= 25.0.2)</b>
6
+ <br>See [blog post related to this plugin](https://medium.com/azimolabs/managing-android-virtual-devices-during-test-session-98a403acffc2#.upcmonil1). You can learn there how to create basic setup for this plugin step by step.
7
+
8
+ ## About automated_test_emulator_run
9
+
10
+ Starts any number of AVDs. AVDs are created and configured automatically according to user liking before instrumentation test process starts (started either via shell command or from gradle) and killed/deleted after test process finishes.
11
+
12
+ ## Getting Started
13
+
14
+ This project is a [fastlane](https://github.com/fastlane/fastlane) plugin.
15
+
16
+ 1. To get started with `fastlane-plugin-automated_test_emulator_run`, add it to your project by running:
17
+
18
+ ```bash
19
+ fastlane add_plugin automated_test_emulator_run
20
+ ```
21
+ 2. Create your \*.JSON config file to create AVD launch plan according to schema below/provided example.
22
+
23
+ 3. Wrap your test launch command with plugin and provide link to \*.JSON config.
24
+
25
+ ## Example of Fastfile
26
+
27
+ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
28
+
29
+ ## JSON config
30
+
31
+ What is JSON config?
32
+
33
+ It is a core of this plugin. User can specify any number of AVD devices in JSON file. Each AVD can be configured separately. Plugin will read JSON file and create fresh, new, untouched AVDs on host - use them in tests - and then delete them after test process finishes.
34
+
35
+ JSON file scheme:
36
+ ```
37
+ {
38
+ "avd_list":
39
+ [
40
+ {
41
+ "avd_name": "",
42
+
43
+ "create_avd_package": "",
44
+ "create_avd_device": "",
45
+ "create_avd_tag": "",
46
+ "create_avd_abi": "",
47
+ "create_avd_additional_options": "",
48
+ "create_avd_hardware_config_filepath": "",
49
+
50
+ "launch_avd_port": "",
51
+ "launch_avd_snapshot_filepath": "",
52
+ "launch_avd_launch_binary_name": "",
53
+ "launch_avd_additional_options": ""
54
+ }
55
+ ]
56
+ }
57
+ ```
58
+
59
+ Parameters:
60
+ <br>For official help refer to `avdmanager` binary file: `<sdk_root>/tools/bin/avdmanager create avd`
61
+ - `avd_name` - name of your AVD, avoid using spaces, this field is necessary
62
+ - `create_avd_package` - path to system image in example "system-images;android-23;google_apis;x86_64"
63
+ - `create_avd_device` - name of your device visible on `avdmanager list device` list
64
+ - `create_avd_tag` - the sys-img tag to use for the AVD. e.g. if you are using Google Apis then set it to "google_apis"
65
+ - `create_avd_abi` - abi for AVD e.g. "x86" or "x86_64" (https://developer.android.com/ndk/guides/abis.html)
66
+ - `create_avd_hardware_config_filepath` - path to config.ini file containing custom config for your AVD. After AVD is created this file will be copied into AVD location before it launches.
67
+ - `create_avd_additional_options` - if you think that you need something more you can just add your create parameters here (e.g. "--sdcard 128M", https://developer.android.com/studio/tools/help/android.html)
68
+ - `launch_avd_snapshot_filepath` - plugin might (if you set it) delete and re-create AVD before test start. That means all your permissions and settings will be lost on each emulator run. If you want to apply qemu image with saved AVD state you can put path to it in this field. It will be applied by using "-wipe-data -initdata <path to your file>"
69
+ - `launch_avd_launch_binary_name` - depending on your CPU architecture you need to choose binary file which should launch your AVD (e.g. "emulator", "emulator64-arm")
70
+ - `launch_avd_port` - port on which you wish your AVD should be launched, if you leave this field empty it will be assigned automatically
71
+ - `launch_avd_additional_options` - if you need more customization add your parameters here (e.g. "-gpu on -no-boot-anim -no-window", https://developer.android.com/studio/run/emulator-commandline.html)
72
+
73
+ Note:
74
+ - parameter `--path` is not supported, if you want to change directory to where your AVD are created edit your env variable ANDROID_SDK_HOME. Which is set to `~/.android/avd` by default.
75
+
76
+ Hints:
77
+ - <b> After change from `android` bin to `avdmanager` bin, default settings of AVD created from terminal has changed. No resolution is set. We highly recommend to use config.ini files which you can set to `create_avd_hardware_config_filepath` or specify resolution in `create_avd_additional_options`. </b>
78
+ - all fields need to be present in JSON, if you don't need any of the parameters just leave it empty
79
+ - pick even ports for your AVDs
80
+ - if you can't launch more than 2 AVDs be sure to check how much memory is your HAXM allowed to use (by default it is 2GB and that will allow you to launch around 2 AVDs) If you face any problems with freezing AVDs then be sure to reinstall your HAXM and allow it to use more of RAM (https://software.intel.com/en-us/android/articles/intel-hardware-accelerated-execution-manager)
81
+ - make sure you have all targets/abis installed on your PC if you want to use them (type in terminal: `android list targets`)
82
+ - we recommend adding `-gpu on` to your launching options for each device, it helps when working with many AVDs
83
+
84
+ Example:
85
+
86
+ [Example of complete JSON file can be found here.](fastlane/examples/AVD_setup.json)
87
+
88
+ ## Issues and Feedback
89
+
90
+ For any other issues and feedback about this plugin, please submit it to this repository.
91
+
92
+ ## Troubleshooting
93
+
94
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://github.com/fastlane/fastlane/blob/master/fastlane/docs/PluginsTroubleshooting.md) doc in the main `fastlane` repo.
95
+
96
+ ## Using `fastlane` Plugins
97
+
98
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Plugins.md).
99
+
100
+ ## About `fastlane`
101
+
102
+ `fastlane` is the easiest way to automate building and releasing your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
@@ -0,0 +1,13 @@
1
+ require 'fastlane/plugin/automated_test_emulator_run_xing/version'
2
+
3
+ module Fastlane
4
+ module AutomatedTestEmulatorRunXing
5
+ def self.all_classes
6
+ Dir[File.expand_path('**/{actions,factory,provider}/*.rb', File.dirname(__FILE__))]
7
+ end
8
+ end
9
+ end
10
+
11
+ Fastlane::AutomatedTestEmulatorRunXing.all_classes.each do |current|
12
+ require current
13
+ end
@@ -0,0 +1,493 @@
1
+ require 'open3'
2
+ require 'json'
3
+
4
+ module Fastlane
5
+ module Actions
6
+
7
+ class AutomatedTestEmulatorRunXingAction < Action
8
+ def self.run(params)
9
+ UI.message("The automated_test_emulator_run plugin is working!")
10
+
11
+ # Parse JSON with AVD launch confing to array of AVD_scheme objects
12
+ avd_schemes = Provider::AvdSchemeProvider.get_avd_schemes(params)
13
+
14
+ # ADB, AVD helper classes
15
+ adb_controller = Factory::AdbControllerFactory.get_adb_controller(params)
16
+ avd_controllers = []
17
+
18
+ # Create AVD_Controller class for each AVD_scheme
19
+ for i in 0...avd_schemes.length
20
+ avd_controller = Factory::AvdControllerFactory.get_avd_controller(params, avd_schemes[i])
21
+ avd_controllers << avd_controller
22
+
23
+ if params[:verbose]
24
+ # Checking for output files
25
+ if File.exists?(avd_controller.output_file.path)
26
+ UI.message([
27
+ "Successfully created tmp output file for AVD:",
28
+ avd_schemes[i].avd_name + ".",
29
+ "File: " + avd_controller.output_file.path].join(" ").green)
30
+ else
31
+ UI.message([
32
+ "Unable to create output file for AVD:",
33
+ avd_schemes[i].avd_name + ".",
34
+ "Output will be delegated to null and lost. Check your save/read permissions."].join(" ").red)
35
+ end
36
+ end
37
+ end
38
+
39
+ # Reseting wait states
40
+ all_avd_launched = false
41
+ adb_launch_complete = false
42
+ param_launch_complete = false
43
+
44
+ while(!all_avd_launched)
45
+ # Preparation
46
+ UI.message("Configuring environment in order to launch emulators: ".yellow)
47
+ UI.message("Getting avaliable AVDs".yellow)
48
+ devices = Action.sh(adb_controller.command_get_avds)
49
+
50
+ for i in 0...avd_schemes.length
51
+ unless devices.match(avd_schemes[i].avd_name).nil?
52
+ UI.message(["AVD with name '", avd_schemes[i].avd_name, "' currently exists."].join("").yellow)
53
+ if params[:AVD_recreate_new]
54
+ # Delete existing AVDs
55
+ UI.message("AVD_create_new parameter set to true.".yellow)
56
+ UI.message(["Deleting existing AVD with name:", avd_schemes[i].avd_name].join(" ").yellow)
57
+ Action.sh(avd_controllers[i].command_delete_avd)
58
+
59
+ # Re-create AVD
60
+ UI.message(["Re-creating new AVD."].join(" ").yellow)
61
+ Action.sh(avd_controllers[i].command_create_avd)
62
+ else
63
+ # Use existing AVD
64
+ UI.message("AVD_recreate_new parameter set to false.".yellow)
65
+ UI.message("Using existing AVD for tests.".yellow)
66
+ end
67
+ else
68
+ # Create AVD
69
+ UI.message(["AVD with name '", avd_schemes[i].avd_name, "' does not exist. Creating new AVD."].join("").yellow)
70
+ Action.sh(avd_controllers[i].command_create_avd)
71
+ end
72
+ end
73
+
74
+ # Restart ADB
75
+ if params[:ADB_restart]
76
+ UI.message("Restarting adb".yellow)
77
+ Action.sh(adb_controller.command_stop)
78
+ Action.sh(adb_controller.command_start)
79
+ else
80
+ UI.message("ADB won't be restarted. 'ADB_restart' set to false.".yellow)
81
+ end
82
+
83
+ # Applying custom configs (it's not done directly after create because 'cat' operation seems to fail overwrite)
84
+ for i in 0...avd_schemes.length
85
+ UI.message(["Attemting to apply custom config to ", avd_schemes[i].avd_name].join("").yellow)
86
+ if avd_controllers[i].command_apply_config_avd.eql? ""
87
+ UI.message(["No config file found for AVD '", avd_schemes[i].avd_name, "'. AVD won't have config.ini applied."].join("").yellow)
88
+ else
89
+ UI.message(["Config file found! Applying custom config to: ", avd_schemes[i].avd_name].join("").yellow)
90
+ Action.sh(avd_controllers[i].command_apply_config_avd)
91
+ end
92
+ end
93
+
94
+ # Launching AVDs
95
+ UI.message("Launching all AVDs at the same time.".yellow)
96
+ for i in 0...avd_controllers.length
97
+ Process.fork do
98
+ Action.sh(avd_controllers[i].command_start_avd)
99
+ end
100
+ end
101
+
102
+ # Wait for AVDs finish booting
103
+ UI.message("Waiting for AVDs to finish booting.".yellow)
104
+ UI.message("Performig wait for ADB boot".yellow)
105
+ adb_launch_complete = wait_for_emulator_boot_by_adb(adb_controller, avd_schemes, "#{params[:AVD_adb_launch_timeout]}")
106
+
107
+ # Wait for AVD params finish booting
108
+ if adb_launch_complete
109
+ UI.message("Wait for ADB boot completed with success".yellow)
110
+
111
+ if (params[:AVD_wait_for_bootcomplete] || params[:AVD_wait_for_boot_completed] || params[:AVD_wait_for_bootanim])
112
+ message = "Performing wait for params: "
113
+
114
+ if params[:AVD_wait_for_bootcomplete]
115
+ message += "'dev.bootcomplete', "
116
+ end
117
+
118
+ if params[:AVD_wait_for_boot_completed]
119
+ message += "'sys.boot_completed', "
120
+ end
121
+
122
+ if params[:AVD_wait_for_bootanim]
123
+ message += "'init.svc.bootanim', "
124
+ end
125
+
126
+ message = message[0...-2] + "."
127
+ UI.message(message.yellow)
128
+
129
+ param_launch_complete = wait_for_emulator_boot_by_params(params, adb_controller, avd_controllers, avd_schemes, "#{params[:AVD_param_launch_timeout]}")
130
+ else
131
+ UI.message("Wait for AVD launch params was turned off. Skipping...".yellow)
132
+ param_launch_complete = true
133
+ end
134
+ else
135
+ UI.message("Wait for ADB boot failed".yellow)
136
+ end
137
+
138
+ all_avd_launched = adb_launch_complete && param_launch_complete
139
+
140
+ # Deciding if AVD launch should be restarted
141
+ devices_output = Action.sh(adb_controller.command_get_devices)
142
+
143
+ devices = ""
144
+ devices_output.each_line do |line|
145
+ if line.include?("emulator-")
146
+ devices += line.sub(/\t/, " ")
147
+ end
148
+ end
149
+
150
+ if all_avd_launched
151
+ UI.message("AVDs Booted!".green)
152
+ else
153
+ for i in 0...avd_schemes.length
154
+ if params[:verbose]
155
+ # Display AVD output
156
+ if (File.exists?(avd_controllers[i].output_file.path))
157
+ UI.message(["Displaying log for AVD:", avd_schemes[i].avd_name].join(" ").red)
158
+ UI.message(avd_controllers[i].output_file.read.blue)
159
+ end
160
+ end
161
+
162
+ # Killing devices
163
+ unless devices.match(["emulator-", avd_schemes[i].launch_avd_port].join("")).nil?
164
+ Action.sh(avd_controllers[i].command_kill_device)
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ # Launching tests
171
+ shell_task = "#{params[:shell_task]}" unless params[:shell_task].nil?
172
+ gradle_task = "#{params[:gradle_task]}" unless params[:gradle_task].nil?
173
+ spoon_task = "#{params[:spoon_task]}" unless params[:spoon_task].nil?
174
+
175
+ UI.message("Starting tests".green)
176
+ begin
177
+ unless shell_task.nil?
178
+ UI.message("Using shell task.".green)
179
+ Action.sh(shell_task)
180
+ end
181
+
182
+ unless gradle_task.nil?
183
+ gradle = Helper::GradleHelper.new(gradle_path: Dir["./gradlew"].last)
184
+
185
+ UI.message("Using gradle task.".green)
186
+ gradle.trigger(task: params[:gradle_task], flags: params[:gradle_flags], serial: nil)
187
+ end
188
+
189
+ unless spoon_task.nil?
190
+ gradle = Helper::GradleHelper.new(gradle_path: Dir["./gradlew"].last)
191
+
192
+ UI.message("Using spoon task.".green)
193
+ ports = Array.new
194
+ spoon_devices = ""
195
+ for i in 0...avd_schemes.length
196
+ ports << avd_schemes[i].launch_avd_port
197
+ spoon_devices = spoon_devices + "-pSpoonDevice=emulator-" + avd_schemes[i].launch_avd_port + " "
198
+ end
199
+
200
+ gradle_flags = params[:gradle_flags]
201
+ gradle_flags = gradle_flags + spoon_devices
202
+
203
+ gradle.trigger(task: params[:gradle_task], flags: gradle_flags, serial: nil)
204
+ end
205
+ ensure
206
+ # Clean up
207
+ for i in 0...avd_schemes.length
208
+ # Kill all emulators
209
+ unless devices.match(["emulator-", avd_schemes[i].launch_avd_port].join("")).nil?
210
+ Action.sh(avd_controllers[i].command_kill_device)
211
+ end
212
+
213
+ if params[:verbose]
214
+ # Display AVD output
215
+ if (File.exists?(avd_controllers[i].output_file.path))
216
+ UI.message("Displaying log from AVD to console:".green)
217
+ UI.message(avd_controllers[i].output_file.read.blue)
218
+
219
+ UI.message("Removing temp file.".green)
220
+ avd_controllers[i].output_file.close
221
+ avd_controllers[i].output_file.unlink
222
+ end
223
+ end
224
+
225
+ # Delete AVDs
226
+ if params[:AVD_clean_after]
227
+ UI.message("AVD_clean_after param set to true. Deleting AVDs.".green)
228
+ Action.sh(avd_controllers[i].command_delete_avd)
229
+ else
230
+ UI.message("AVD_clean_after param set to false. Created AVDs won't be deleted.".green)
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ def self.wait_for_emulator_boot_by_adb(adb_controller, avd_schemes, timeout)
237
+ timeoutInSeconds= timeout.to_i
238
+ interval = 1000 * 10
239
+ startTime = Time.now
240
+ lastCheckTime = Time.now
241
+ launch_status_hash = Hash.new
242
+ device_visibility_hash = Hash.new
243
+
244
+ for i in 0...avd_schemes.length
245
+ device_name = ["emulator-", avd_schemes[i].launch_avd_port].join("")
246
+ launch_status_hash.store(device_name, false)
247
+ device_visibility_hash.store(device_name, false)
248
+ end
249
+
250
+ launch_status = false
251
+ loop do
252
+ currentTime = Time.now
253
+ if ((currentTime - lastCheckTime) * 1000) > interval
254
+ lastCheckTime = currentTime
255
+ devices_output = Action.sh(adb_controller.command_get_devices)
256
+
257
+ devices = ""
258
+ devices_output.each_line do |line|
259
+ if line.include?("emulator-")
260
+ devices += line.sub(/\t/, " ")
261
+ end
262
+ end
263
+
264
+ # Check if device is visible
265
+ all_devices_visible = true
266
+ device_visibility_hash.each do |name, is_visible|
267
+ unless (devices.match(name).nil? || is_visible)
268
+ device_visibility_hash[name] = true
269
+ end
270
+ all_devices_visible = false unless is_visible
271
+ end
272
+
273
+ # Check if device is booted
274
+ all_devices_booted = true
275
+ launch_status_hash.each do |name, is_booted|
276
+ unless (devices.match(name + " device").nil? || is_booted)
277
+ launch_status_hash[name] = true
278
+ end
279
+ all_devices_booted = false unless launch_status_hash[name]
280
+ end
281
+
282
+ # Quit if timeout reached
283
+ if ((currentTime - startTime) >= timeoutInSeconds)
284
+ UI.message(["AVD ADB loading took more than ", timeout, ". Attempting to re-launch."].join("").red)
285
+ launch_status = false
286
+ break
287
+ end
288
+
289
+ # Quit if all devices booted
290
+ if (all_devices_booted && all_devices_visible)
291
+ launch_status = true
292
+ break
293
+ end
294
+ end
295
+ end
296
+ return launch_status
297
+ end
298
+
299
+ def self.wait_for_emulator_boot_by_params(params, adb_controller, avd_controllers, avd_schemes, timeout)
300
+ timeout_in_seconds= timeout.to_i
301
+ interval = 1000 * 10
302
+ all_params_launched = false
303
+ start_time = last_scan_ended = Time.now
304
+ device_boot_statuses = Hash.new
305
+
306
+ loop do
307
+ current_time = Time.now
308
+
309
+ # Performing single scan over each device
310
+ if (((current_time - last_scan_ended) * 1000) >= interval || start_time == last_scan_ended)
311
+ for i in 0...avd_schemes.length
312
+ avd_schema = avd_schemes[i]
313
+ avd_controller = avd_controllers[i]
314
+ avd_param_boot_hash = Hash.new
315
+ avd_param_status_hash = Hash.new
316
+ avd_booted = false
317
+
318
+ # Retreiving device parameters according to config
319
+ if params[:AVD_wait_for_bootcomplete]
320
+ dev_bootcomplete, _stdeerr, _status = Open3.capture3([avd_controller.command_get_property, "dev.bootcomplete"].join(" "))
321
+ avd_param_boot_hash.store("dev.bootcomplete", dev_bootcomplete.strip.eql?("1"))
322
+ avd_param_status_hash.store("dev.bootcomplete", dev_bootcomplete)
323
+ end
324
+
325
+ if params[:AVD_wait_for_boot_completed]
326
+ sys_boot_completed, _stdeerr, _status = Open3.capture3([avd_controller.command_get_property, "sys.boot_completed"].join(" "))
327
+ avd_param_boot_hash.store("sys.boot_completed", sys_boot_completed.strip.eql?("1"))
328
+ avd_param_status_hash.store("sys.boot_completed", sys_boot_completed)
329
+ end
330
+
331
+ if params[:AVD_wait_for_bootanim]
332
+ bootanim, _stdeerr, _status = Open3.capture3([avd_controller.command_get_property, "init.svc.bootanim"].join(" "))
333
+ avd_param_boot_hash.store("init.svc.bootanim", bootanim.strip.eql?("stopped"))
334
+ avd_param_status_hash.store("init.svc.bootanim", bootanim)
335
+ end
336
+
337
+ # Checking for param statuses
338
+ avd_param_boot_hash.each do |name, is_booted|
339
+ if !is_booted
340
+ break
341
+ end
342
+ avd_booted = true
343
+ end
344
+ device_boot_statuses.store(avd_schema.avd_name, avd_booted)
345
+
346
+ # Plotting current wait results
347
+ device_log = "Device 'emulator-" + avd_schemes[i].launch_avd_port.to_s + "' launch status:"
348
+ UI.message(device_log.magenta)
349
+ avd_param_boot_hash.each do |name, is_booted|
350
+ device_log = "'" + name + "' - '" + avd_param_status_hash[name].strip + "' (launched: " + is_booted.to_s + ")"
351
+ UI.message(device_log.magenta)
352
+ end
353
+ end
354
+ last_scan_ended = Time.now
355
+ end
356
+
357
+ # Checking if wait doesn't last too long
358
+ if (current_time - start_time) >= timeout_in_seconds
359
+ UI.message(["AVD param loading took more than ", timeout, ". Attempting to re-launch."].join("").red)
360
+ all_params_launched = false
361
+ break
362
+ end
363
+
364
+ # Finishing wait with success if all params are loaded for every device
365
+ device_boot_statuses.each do |name, is_booted|
366
+ if !is_booted
367
+ break
368
+ end
369
+ all_params_launched = true
370
+ end
371
+ if all_params_launched
372
+ break
373
+ end
374
+ end
375
+ return all_params_launched
376
+ end
377
+
378
+ def self.available_options
379
+ [
380
+ #paths
381
+ FastlaneCore::ConfigItem.new(key: :AVD_path,
382
+ env_name: "AVD_PATH",
383
+ description: "The path to your android AVD directory (root). ANDROID_SDK_HOME by default",
384
+ default_value: (ENV['ANDROID_SDK_HOME'].nil? or ENV['ANDROID_SDK_HOME'].eql?("")) ? "~/.android/avd" : ENV['ANDROID_SDK_HOME'],
385
+ is_string: true,
386
+ optional: true),
387
+ FastlaneCore::ConfigItem.new(key: :AVD_setup_path,
388
+ env_name: "AVD_SETUP_PATH",
389
+ description: "Location to AVD_setup.json file which contains info about how many AVD should be launched and their configs",
390
+ is_string: true,
391
+ optional: false),
392
+ FastlaneCore::ConfigItem.new(key: :SDK_path,
393
+ env_name: "SDK_PATH",
394
+ description: "The path to your android sdk directory (root). ANDROID_HOME by default",
395
+ default_value: ENV['ANDROID_HOME'],
396
+ is_string: true,
397
+ optional: true),
398
+
399
+
400
+ #launch config params
401
+ FastlaneCore::ConfigItem.new(key: :AVD_param_launch_timeout,
402
+ env_name: "AVD_PARAM_LAUNCH_TIMEOUT",
403
+ description: "Timeout in seconds. Even though ADB might find all devices you still might want to wait for animations to finish and system to boot. Default 60 seconds",
404
+ default_value: 60,
405
+ is_string: true,
406
+ optional: true),
407
+ FastlaneCore::ConfigItem.new(key: :AVD_adb_launch_timeout,
408
+ env_name: "AVD_ADB_LAUNCH_TIMEOUT",
409
+ description: "Timeout in seconds. Wait until ADB finds all devices specified in config and sets their value to 'device'. Default 240 seconds",
410
+ default_value: 240,
411
+ is_string: true,
412
+ optional: true),
413
+ FastlaneCore::ConfigItem.new(key: :AVD_recreate_new,
414
+ env_name: "AVD_RECREATE_NEW",
415
+ description: "Allow to decide if AVDs from AVD_setup.json (in case they already exist) should be deleted and created from scratch",
416
+ default_value: true,
417
+ is_string: false,
418
+ optional: true),
419
+ FastlaneCore::ConfigItem.new(key: :AVD_clean_after,
420
+ env_name: "AVD_CLEAN_AFTER",
421
+ description: "Allow to decide if AVDs should be deleted from PC after test session ends",
422
+ default_value: true,
423
+ is_string: false,
424
+ optional: true),
425
+ FastlaneCore::ConfigItem.new(key: :ADB_restart,
426
+ env_name: "ADB_RESTART",
427
+ description: "Allows to switch adb restarting on/off",
428
+ default_value: true,
429
+ is_string: false,
430
+ optional: true),
431
+ FastlaneCore::ConfigItem.new(key: :AVD_wait_for_bootcomplete,
432
+ env_name: "AVD_BOOTCOMPLETE_WAIT",
433
+ description: "Allows to switch wait for 'dev.bootcomplete' AVD launch param on/off",
434
+ default_value: true,
435
+ is_string: false,
436
+ optional: true),
437
+ FastlaneCore::ConfigItem.new(key: :AVD_wait_for_boot_completed,
438
+ env_name: "AVD_BOOT_COMPLETED_WAIT",
439
+ description: "Allows to switch wait for 'sys.boot_completed' AVD launch param on/off",
440
+ default_value: true,
441
+ is_string: false,
442
+ optional: true),
443
+ FastlaneCore::ConfigItem.new(key: :AVD_wait_for_bootanim,
444
+ env_name: "ABD_BOOTANIM_WAIT",
445
+ description: "Allows to switch wait for 'init.svc.bootanim' AVD launch param on/off",
446
+ default_value: true,
447
+ is_string: false,
448
+ optional: true),
449
+
450
+ #launch commands
451
+ FastlaneCore::ConfigItem.new(key: :shell_task,
452
+ env_name: "SHELL_TASK",
453
+ description: "The shell command you want to execute",
454
+ conflicting_options: [:gradle_task],
455
+ is_string: true,
456
+ optional: true),
457
+ FastlaneCore::ConfigItem.new(key: :gradle_task,
458
+ env_name: "GRADLE_TASK",
459
+ description: "The gradle task you want to execute",
460
+ conflicting_options: [:shell_command],
461
+ is_string: true,
462
+ optional: true),
463
+ FastlaneCore::ConfigItem.new(key: :gradle_flags,
464
+ env_name: "GRADLE_FLAGS",
465
+ description: "All parameter flags you want to pass to the gradle command, e.g. `--exitcode --xml file.xml`",
466
+ conflicting_options: [:shell_command],
467
+ optional: true,
468
+ is_string: true),
469
+
470
+ #mode
471
+ FastlaneCore::ConfigItem.new(key: :verbose,
472
+ env_name: "AVD_VERBOSE",
473
+ description: "Allows to turn on/off mode verbose which displays output of AVDs",
474
+ default_value: false,
475
+ is_string: false,
476
+ optional: true),
477
+ ]
478
+ end
479
+
480
+ def self.description
481
+ "Starts AVD, based on AVD_setup.json file, before test launch and kills it after testing is done."
482
+ end
483
+
484
+ def self.authors
485
+ ["F1sherKK"]
486
+ end
487
+
488
+ def self.is_supported?(platform)
489
+ platform == :android
490
+ end
491
+ end
492
+ end
493
+ end
@@ -0,0 +1,55 @@
1
+ module Fastlane
2
+ module Factory
3
+
4
+ class ADB_Controller
5
+ attr_accessor :command_stop, :command_start, :command_get_devices, :command_wait_for_device, :command_get_avds
6
+ end
7
+
8
+ class AdbControllerFactory
9
+
10
+ def self.get_adb_controller(params)
11
+ UI.message(["Preparing commands for Android ADB"].join(" ").yellow)
12
+
13
+ # Get paths
14
+ path_sdk = "#{params[:SDK_path]}"
15
+ path_avdmanager_binary = path_sdk + "/tools/bin/avdmanager"
16
+ path_adb = path_sdk + "/platform-tools/adb"
17
+
18
+ # ADB shell command parts
19
+ sh_stop_adb = "kill-server"
20
+ sh_start_adb = "start-server"
21
+ sh_devices_adb = "devices"
22
+ sh_wait_for_device_adb = "wait-for-device"
23
+ sh_list_avd_adb = "list avd"
24
+
25
+ # Assemble ADB controller
26
+ adb_controller = ADB_Controller.new
27
+ adb_controller.command_stop = [
28
+ path_adb,
29
+ sh_stop_adb
30
+ ].join(" ")
31
+
32
+ adb_controller.command_start = [
33
+ path_adb,
34
+ sh_start_adb
35
+ ].join(" ")
36
+
37
+ adb_controller.command_get_devices = [
38
+ path_adb,
39
+ sh_devices_adb
40
+ ].join(" ")
41
+
42
+ adb_controller.command_wait_for_device = [
43
+ path_adb,
44
+ sh_wait_for_device_adb
45
+ ].join(" ")
46
+
47
+ adb_controller.command_get_avds = [
48
+ path_avdmanager_binary,
49
+ sh_list_avd_adb].join(" ").chomp
50
+
51
+ return adb_controller
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,129 @@
1
+ require 'tempfile'
2
+
3
+ module Fastlane
4
+ module Factory
5
+
6
+ class AVD_Controller
7
+ attr_accessor :command_create_avd, :command_start_avd, :command_delete_avd, :command_apply_config_avd, :command_get_property, :command_kill_device,
8
+ :output_file
9
+
10
+ def self.create_output_file(params)
11
+ output_file = Tempfile.new('emulator_output', '#{params[:AVD_path]}')
12
+ end
13
+ end
14
+
15
+ class AvdControllerFactory
16
+
17
+ def self.get_avd_controller(params, avd_scheme)
18
+ UI.message(["Preparing parameters and commands for emulator:", avd_scheme.avd_name].join(" ").yellow)
19
+
20
+ # Get paths
21
+ path_sdk = "#{params[:SDK_path]}"
22
+ path_avdmanager_binary = path_sdk + "/tools/bin/avdmanager"
23
+ path_adb = path_sdk + "/platform-tools/adb"
24
+ path_avd = "#{params[:AVD_path]}"
25
+
26
+ # Create AVD shell command parts
27
+ sh_create_answer_no = "echo \"no\" |"
28
+ sh_create_avd = "create avd"
29
+ sh_create_avd_name = ["--name \"", avd_scheme.avd_name, "\""].join("")
30
+ sh_create_avd_package = ["--package \"", avd_scheme.create_avd_package, "\""].join("")
31
+
32
+ if avd_scheme.create_avd_device.eql? ""
33
+ sh_create_avd_device = ""
34
+ else
35
+ sh_create_avd_device = ["--device \"", avd_scheme.create_avd_device, "\""].join("")
36
+ end
37
+
38
+ if avd_scheme.create_avd_abi.eql? ""
39
+ sh_create_avd_abi = ""
40
+ else
41
+ sh_create_avd_abi = ["--abi ", avd_scheme.create_avd_abi].join("")
42
+ end
43
+
44
+ if avd_scheme.create_avd_tag.eql? ""
45
+ sh_create_avd_tag = ""
46
+ else
47
+ sh_create_avd_tag = ["--tag ", avd_scheme.create_avd_tag].join("")
48
+ end
49
+
50
+ sh_create_avd_additional_options = avd_scheme.create_avd_additional_options
51
+ sh_create_config_loc = "#{path_avd}/#{avd_scheme.avd_name}.avd/config.ini"
52
+
53
+ # Launch AVD shell command parts
54
+ sh_launch_emulator_binary = [path_sdk, "/emulator/", avd_scheme.launch_avd_launch_binary_name].join("")
55
+ sh_launch_avd_name = ["-avd ", avd_scheme.avd_name].join("")
56
+ sh_launch_avd_additional_options = avd_scheme.launch_avd_additional_options
57
+ sh_launch_avd_port = ["-port", avd_scheme.launch_avd_port].join(" ")
58
+
59
+ if avd_scheme.launch_avd_snapshot_filepath.eql? ""
60
+ sh_launch_avd_snapshot = ""
61
+ else
62
+ sh_launch_avd_snapshot = ["-wipe-data -initdata ", avd_scheme.launch_avd_snapshot_filepath].join("")
63
+ end
64
+
65
+ # Re-create AVD shell command parts
66
+ sh_delete_avd = ["delete avd -n ", avd_scheme.avd_name].join("")
67
+
68
+ # ADB related shell command parts
69
+ sh_specific_device = "-s"
70
+ sh_device_name_adb = ["emulator-", avd_scheme.launch_avd_port].join("")
71
+ sh_get_property = "shell getprop"
72
+ sh_kill_device = "emu kill"
73
+
74
+ # Assemble AVD controller
75
+ avd_controller = AVD_Controller.new
76
+ avd_controller.command_create_avd = [
77
+ sh_create_answer_no,
78
+ path_avdmanager_binary,
79
+ sh_create_avd,
80
+ sh_create_avd_name,
81
+ sh_create_avd_package,
82
+ sh_create_avd_device,
83
+ sh_create_avd_tag,
84
+ sh_create_avd_abi,
85
+ sh_create_avd_additional_options].join(" ")
86
+
87
+ avd_controller.output_file = Tempfile.new('emulator_output')
88
+ avd_output = File.exists?(avd_controller.output_file) ? ["&>", avd_controller.output_file.path, "&"].join("") : "&>/dev/null &"
89
+
90
+ avd_controller.command_start_avd = [
91
+ sh_launch_emulator_binary,
92
+ sh_launch_avd_port,
93
+ sh_launch_avd_name,
94
+ sh_launch_avd_snapshot,
95
+ sh_launch_avd_additional_options,
96
+ avd_output].join(" ")
97
+
98
+ avd_controller.command_delete_avd = [
99
+ path_avdmanager_binary,
100
+ sh_delete_avd].join(" ")
101
+
102
+ if path_avd.nil? || (avd_scheme.create_avd_hardware_config_filepath.eql? "")
103
+ avd_controller.command_apply_config_avd = ""
104
+ else
105
+ avd_controller.command_apply_config_avd = [
106
+ "cat",
107
+ avd_scheme.create_avd_hardware_config_filepath,
108
+ ">",
109
+ sh_create_config_loc].join(" ")
110
+ end
111
+
112
+ avd_controller.command_get_property = [
113
+ path_adb,
114
+ sh_specific_device,
115
+ sh_device_name_adb,
116
+ sh_get_property].join(" ")
117
+
118
+ avd_controller.command_kill_device = [
119
+ path_adb,
120
+ sh_specific_device,
121
+ sh_device_name_adb,
122
+ sh_kill_device,
123
+ "&>/dev/null"].join(" ")
124
+
125
+ return avd_controller
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,173 @@
1
+ module Fastlane
2
+ module Provider
3
+
4
+ class AVD_scheme
5
+ attr_accessor :avd_name, :create_avd_package, :create_avd_device, :create_avd_tag, :create_avd_abi, :create_avd_hardware_config_filepath, :create_avd_additional_options,
6
+ :launch_avd_port, :launch_avd_launch_binary_name, :launch_avd_additional_options, :launch_avd_snapshot_filepath
7
+ end
8
+
9
+ class AvdSchemeProvider
10
+
11
+ def self.get_avd_schemes(params)
12
+
13
+ # Read JSON into string variable
14
+ avd_setup_json = read_avd_setup(params)
15
+ if avd_setup_json.nil?
16
+ throw_error("Unable to read AVD_setup.json. Check JSON file structure or file path.")
17
+ end
18
+
19
+ # Read JSON into Hash
20
+ avd_setup = JSON.parse(avd_setup_json)
21
+ avd_hash_list = avd_setup['avd_list']
22
+
23
+ # Create AVD_scheme objects and fill them with data
24
+ avd_scheme_list = []
25
+ for i in 0...avd_hash_list.length
26
+ avd_hash = avd_hash_list[i]
27
+
28
+ avd_scheme = AVD_scheme.new
29
+ avd_scheme.avd_name = avd_hash['avd_name']
30
+
31
+ avd_scheme.create_avd_package = avd_hash['create_avd_package']
32
+ avd_scheme.create_avd_device = avd_hash['create_avd_device']
33
+ avd_scheme.create_avd_tag = avd_hash['create_avd_tag']
34
+ avd_scheme.create_avd_abi = avd_hash['create_avd_abi']
35
+ avd_scheme.create_avd_hardware_config_filepath = avd_hash['create_avd_hardware_config_filepath']
36
+
37
+ avd_scheme.launch_avd_port = avd_hash['launch_avd_port']
38
+ avd_scheme.launch_avd_launch_binary_name = avd_hash['launch_avd_launch_binary_name']
39
+ avd_scheme.launch_avd_additional_options = avd_hash['launch_avd_additional_options']
40
+ avd_scheme.launch_avd_snapshot_filepath = avd_hash['launch_avd_snapshot_filepath']
41
+
42
+ errors = check_avd_fields(avd_scheme)
43
+ unless errors.empty?
44
+ error_log = "Error! Fields not found in JSON: \n"
45
+ errors.each { |error| error_log += error + "\n" }
46
+ throw_error(error_log)
47
+ end
48
+
49
+ avd_scheme_list << avd_scheme
50
+ end
51
+
52
+ # Prepare list of open ports for AVD_schemes without ports set in JSON
53
+ avaliable_ports = get_unused_even_tcp_ports(5556, 5586, avd_scheme_list)
54
+
55
+ # Fill empty AVD_schemes with open ports
56
+ for i in 0...avd_scheme_list.length
57
+ avd_scheme = avd_scheme_list[i]
58
+ if avd_scheme.launch_avd_port.eql? ""
59
+ avd_scheme.launch_avd_port = avaliable_ports[0]
60
+ $Ports << avd_scheme.launch_avd_port
61
+ avaliable_ports.delete(avaliable_ports[0])
62
+ end
63
+ end
64
+
65
+ return avd_scheme_list
66
+ end
67
+
68
+ def self.get_unused_even_tcp_ports(min_port, max_port, avd_scheme_list)
69
+ if min_port % 2 != 0
70
+ min_port += 1
71
+ end
72
+
73
+ if max_port % 2 != 0
74
+ max_port += 1
75
+ end
76
+
77
+ avaliable_ports = []
78
+ reserved_ports = []
79
+
80
+ # Gather ports requested in JSON config
81
+ for i in 0...avd_scheme_list.length
82
+ avd_scheme = avd_scheme_list[i]
83
+ unless avd_scheme.launch_avd_port.eql? ""
84
+ reserved_ports << avd_scheme.launch_avd_port
85
+ end
86
+ end
87
+
88
+ # Find next open port which wasn't reserved in JSON config
89
+ port = min_port
90
+ for i in 0...avd_scheme_list.length
91
+
92
+ while port < max_port do
93
+ if !system("lsof -i:#{port}", out: '/dev/null')
94
+
95
+ is_port_reserved = false
96
+ for j in 0...reserved_ports.length
97
+ if reserved_ports[j].eql?(port.to_s)
98
+ is_port_reserved = true
99
+ break
100
+ end
101
+ end
102
+
103
+ if is_port_reserved
104
+ port = port + 2
105
+ break
106
+ end
107
+
108
+ avaliable_ports << port
109
+ port = port + 2
110
+ break
111
+ else
112
+ port = port + 2
113
+ end
114
+ end
115
+ end
116
+
117
+ return avaliable_ports
118
+ end
119
+
120
+ def self.read_avd_setup(params)
121
+ if File.exists?(File.expand_path("#{params[:AVD_setup_path]}"))
122
+ file = File.open(File.expand_path("#{params[:AVD_setup_path]}"), "rb")
123
+ json = file.read
124
+ file.close
125
+ return json
126
+ else
127
+ return nil
128
+ end
129
+ end
130
+
131
+ def self.check_avd_fields(avd_scheme)
132
+ errors = []
133
+
134
+ if avd_scheme.avd_name.nil?
135
+ errors.push("avd_name not found")
136
+ end
137
+ if avd_scheme.create_avd_package.nil?
138
+ errors.push("create_avd_package not found")
139
+ end
140
+ if avd_scheme.create_avd_device.nil?
141
+ errors.push("create_avd_device not found")
142
+ end
143
+ if avd_scheme.create_avd_tag.nil?
144
+ errors.push("create_avd_tag not found")
145
+ end
146
+ if avd_scheme.create_avd_abi.nil?
147
+ errors.push("create_avd_abi not found")
148
+ end
149
+ if avd_scheme.create_avd_hardware_config_filepath.nil?
150
+ errors.push("create_avd_hardware_config_filepath not found")
151
+ end
152
+ if avd_scheme.launch_avd_snapshot_filepath.nil?
153
+ errors.push("launch_avd_snapshot_filepath not found")
154
+ end
155
+ if avd_scheme.launch_avd_launch_binary_name.nil?
156
+ errors.push("launch_avd_launch_binary_name not found")
157
+ end
158
+ if avd_scheme.launch_avd_port.nil?
159
+ errors.push("launch_avd_port not found")
160
+ end
161
+ if avd_scheme.launch_avd_additional_options.nil?
162
+ errors.push("launch_avd_additional_options not found")
163
+ end
164
+ return errors
165
+ end
166
+
167
+ def self.throw_error(message)
168
+ UI.message("Error: ".red + message.red)
169
+ raise Exception, "Lane was stopped by plugin"
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module AutomatedTestEmulatorRunXing
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-automated_test_emulator_run_xing
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Hartwich
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fastlane
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 1.98.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 1.98.0
97
+ description:
98
+ email: hartwich.daniel@gmail.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - LICENSE
104
+ - README.md
105
+ - lib/fastlane/plugin/automated_test_emulator_run_xing.rb
106
+ - lib/fastlane/plugin/automated_test_emulator_run_xing/actions/automated_test_emulator_run_xing_action.rb
107
+ - lib/fastlane/plugin/automated_test_emulator_run_xing/factory/adb_controller_factory.rb
108
+ - lib/fastlane/plugin/automated_test_emulator_run_xing/factory/avd_controller_factory.rb
109
+ - lib/fastlane/plugin/automated_test_emulator_run_xing/provider/avd_setup_provider.rb
110
+ - lib/fastlane/plugin/automated_test_emulator_run_xing/version.rb
111
+ homepage: https://github.com/dhartwich1991/fastlane-plugin-automated-test-emulator-run
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.5.1
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Starts n AVDs based on JSON file config. AVDs are created and configured
135
+ according to user liking before instrumentation test process (started either via
136
+ shell command or gradle) and killed/deleted after test process finishes.
137
+ test_files: []