fastlane-plugin-automated_test_emulator_run 0.5.16 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d20910735d239a742e4b85f5b1aca3ad68a30db4
4
- data.tar.gz: b938c98f800c87dbe949e4f2d7faccd4f4259de1
3
+ metadata.gz: 5719e5040624f349907cc2c01d6c7030c3827d01
4
+ data.tar.gz: 061d66711e351773c997e350f7c3b53c7326a0bc
5
5
  SHA512:
6
- metadata.gz: 604fd356c0bcd108a04d4efb2a8f5dcd1e299a409be537d032a1a227ae13e8f726d54a0a1998342eeb7d5f1be123a26d5b40f1cdecadea45f8b15142e12c6f25
7
- data.tar.gz: 7b82e7698f12687e787deef708c3f0b62bfeae22d08b26b853ac89e70db323e5702a6f1ffe591e32a9ec54928ba7a8feee0d6a65b1e4dbbdfb9da4067d2d6995
6
+ metadata.gz: 115cbc0163872401a1c40a69d2a1d17a8b96f5c9933cfee62015a4d3c9cb1273cb8ac4bf6f45115b0d0a546d99b87d72d0428de98021c1fa81a4e91df177a17c
7
+ data.tar.gz: a7fb87f8726d0abd1ff80deb01403227894953eee782efd78e64ed4ee38d0c89933f69c7f9fa04b53d394e643837204dea70ede1e5c6b6c543676b9d75a76382
data/README.md CHANGED
@@ -2,39 +2,77 @@
2
2
 
3
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
4
 
5
- ## Getting Started
5
+ ## About automated_test_emulator_run
6
6
 
7
- This project is a [fastlane](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-automated_test_emulator_run`, add it to your project by running:
7
+ 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.
8
8
 
9
- ```bash
10
- fastlane add_plugin automated_test_emulator_run
11
- ```
9
+ ## Getting Started
12
10
 
13
- ## About automated_test_emulator_run
11
+ This project is a [fastlane](https://github.com/fastlane/fastlane) plugin.
14
12
 
15
- Allows to wrap gradle task or shell command that runs integrated tests that prepare and starts single AVD before test run. After tests are finished, emulator is killed and deleted.
13
+ 1. To get started with `fastlane-plugin-automated_test_emulator_run`, add it to your project by running:
16
14
 
17
- **Note to author:** Add a more detailed description about this plugin here. If your plugin contains multiple actions, make sure to mention them here.
15
+ ```bash
16
+ fastlane add_plugin automated_test_emulator_run
17
+ ```
18
+ 2. Create your \*.JSON config file to create AVD launch plan according to schema below/provided example.
18
19
 
19
- ## Example
20
+ 3. Wrap your test launch command with plugin and provide link to \*.JSON config.
20
21
 
21
- 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`.
22
+ ## Example of Fastfile
22
23
 
23
- **Note to author:** Please set up a sample project to make it easy for users to explore what your plugin does. Provide everything that is necessary to try out the plugin in this project (including a sample Xcode/Android project if necessary)
24
+ 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`.
24
25
 
25
- ## Run tests for this plugin
26
+ ## JSON config
26
27
 
27
- To run both the tests, and code style validation, run
28
+ What is JSON config?
28
29
 
29
- ```
30
- rake
31
- ```
30
+ 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.
32
31
 
33
- To automatically fix many of the styling issues, use
32
+ JSON file scheme:
34
33
  ```
35
- rubocop -a
34
+ {
35
+ "avd_list":
36
+ [
37
+ {
38
+ "avd_name": "",
39
+
40
+ "create_avd_target": "",
41
+ "create_avd_abi": "",
42
+ "create_avd_hardware_config_filepath": "",
43
+ "create_avd_additional_options": "",
44
+
45
+ "launch_avd_snapshot_filepath": "",
46
+ "launch_avd_launch_binary_name": "",
47
+ "launch_avd_port": "",
48
+ "launch_avd_additional_options": ""
49
+ }
50
+ ]
51
+ }
36
52
  ```
37
53
 
54
+ Parameters:
55
+ - `avd_name` - name of your AVD, avoid using spaces, this file is necessary
56
+ - `create_avd_target` - Android target api level (https://developer.android.com/guide/topics/manifest/uses-sdk-element.html)
57
+ - `create_avd_abi` - CPU architecture used by AVD (https://developer.android.com/ndk/guides/abis.html)
58
+ - `create_avd_hardware_config_filepath` - path to config.ini file containing custom config for your AVD device. After AVD is created this file will be copied into AVD location before it launches.
59
+ - `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)
60
+ - `launch_avd_snapshot_filepath` - plugin will 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>"
61
+ - `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", "emulator64-x86")
62
+ - `launch_avd_port` - port on which you wish your AVD should be launched, if you leave this field empty it will be assigned automatically
63
+ - `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)
64
+
65
+ Hints:
66
+
67
+ - all fields need to be present in JSON, if you don't need any of the parameters just leave it empty
68
+ - pick even ports for your AVDs
69
+ - 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)
70
+ - make sure you have all targets/abis installed on your PC if you want to use them (type in terminal: `android list targets`)
71
+
72
+ Example:
73
+
74
+ [Example of complete JSON file can be found here.](fastlane/examples/AVD_setup.json)
75
+
38
76
  ## Issues and Feedback
39
77
 
40
78
  For any other issues and feedback about this plugin, please submit it to this repository.
@@ -2,15 +2,14 @@ require 'fastlane/plugin/automated_test_emulator_run/version'
2
2
 
3
3
  module Fastlane
4
4
  module AutomatedTestEmulatorRun
5
- # Return all .rb files inside the "actions" and "helper" directory
6
5
  def self.all_classes
7
- Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
6
+ Dir[File.expand_path('**/{actions,factory,provider}/*.rb', File.dirname(__FILE__))]
8
7
  end
9
8
  end
10
9
  end
11
10
 
12
- # By default we want to import all available actions and helpers
13
- # A plugin can contain any number of actions and plugins
14
11
  Fastlane::AutomatedTestEmulatorRun.all_classes.each do |current|
15
12
  require current
16
13
  end
14
+
15
+
@@ -1,268 +1,232 @@
1
1
  require 'open3'
2
- require 'tempfile'
2
+ require 'json'
3
3
 
4
4
  module Fastlane
5
5
  module Actions
6
- module SharedValues
7
- end
8
6
 
9
- class AutomatedTestEmulatorRunAction < Action
7
+ class AutomatedTestEmulatorRunAction < Action
8
+ def self.run(params)
9
+ UI.message("The automated_test_emulator_run plugin is working!")
10
10
 
11
- def self.run(params)
12
- gradle = Helper::GradleHelper.new(gradle_path: Dir["./gradlew"].last)
11
+ # Parse JSON with AVD launch confing to array of AVD_scheme objects
12
+ avd_schemes = Provider::AvdSchemeProvider.get_avd_schemes(params)
13
13
 
14
- UI.message("The automated_test_emulator_run plugin is working!")
14
+ # ADB, AVD helper classes
15
+ adb_controller = Factory::AdbControllerFactory.get_adb_controller(params)
16
+ avd_controllers = []
15
17
 
16
- # Find unused port
17
- port = getUnusedTcpPort
18
- if params[:avd_port].nil?
19
- port = getUnusedTcpPort
20
- UI.message(["Open port found", port].join(" ").yellow)
21
- else
22
- port = "#{params[:avd_port]}"
23
- UI.message(["Port set by user to:", port].join(" ").yellow)
24
- end
25
-
26
- # Set up params
27
- UI.message("Preparing parameters...".yellow)
28
-
29
- # AVD general params
30
- sdkRoot = "#{params[:sdk_path]}"
31
- avd_name = "--name \"#{params[:avd_name]}\""
32
-
33
- # AVD create params
34
- target_id = "--target \"#{params[:target_id]}\""
35
- avd_abi = "--abi #{params[:avd_abi]}" unless params[:avd_abi].nil?
36
- avd_tag = "--tag #{params[:avd_tag]}" unless params[:avd_tag].nil?
37
- avd_create_options = params[:avd_create_options] unless params[:avd_create_options].nil?
38
-
39
- # AVD start params
40
- emulator_binary = "#{params[:emulator_binary]}"
41
- avd_initdata = "-wipe-data -initdata #{params[:initdata_snapshot_path]}" unless params[:initdata_snapshot_path].nil?
42
- avd_port = ["-port", port].join(" ")
43
- avd_start_options = params[:avd_start_options] unless params[:avd_start_options].nil?
44
-
45
- # Set up commands
46
- UI.message("Setting up run commands".yellow)
47
- create_avd_command = ["echo \"no\" |", sdkRoot + "/tools/android", "create avd", avd_name, target_id, avd_abi, avd_tag, avd_create_options].join(" ")
48
- get_devices_command = sdkRoot + "/tools/android list avd".chomp
49
- start_avd_command = [sdkRoot + "/tools/" + emulator_binary, avd_port, "-avd #{params[:avd_name]}", avd_initdata, avd_start_options, "&>/dev/null &"].join(" ")
50
- shell_command = "#{params[:shell_command]}" unless params[:shell_command].nil?
51
- gradle_task = "#{params[:gradle_task]}" unless params[:gradle_task].nil?
52
-
53
- # Recreating AVD
54
- UI.message("Creating AVD...".yellow)
55
- createEmulator(get_devices_command, create_avd_command, params, sdkRoot)
56
-
57
- # Starting AVD
58
- UI.message("Starting AVD....".yellow)
59
- launchEmulator(start_avd_command, get_devices_command, create_avd_command, sdkRoot, port, params)
60
-
61
- UI.message("Starting tests".green)
62
- begin
63
- unless shell_command.nil?
64
- UI.message("Using shell command".green)
65
- Action.sh(shell_command)
18
+ # Create AVD_Controller class for each AVD_scheme
19
+ for i in 0..(avd_schemes.length - 1)
20
+ avd_scheme = avd_schemes[i]
21
+ avd_controller = Factory::AvdControllerFactory.get_avd_controller(params, avd_scheme)
22
+ avd_controllers << avd_controller
66
23
  end
67
24
 
68
- unless gradle_task.nil?
69
- UI.message("Using gradle task".green)
70
- gradle.trigger(task: params[:gradle_task], flags: params[:gradle_flags], serial: nil)
71
- end
72
- end
25
+ all_avd_launched = false
73
26
 
74
- waitFor_emulatorStop(sdkRoot, port, params)
75
- end
27
+ while(!all_avd_launched)
76
28
 
77
- def self.getUnusedTcpPort
78
- min_port = 5556
79
- max_port = 5586
29
+ # Preparation
30
+ UI.message("Configuring environment in order to launch emulators: ".yellow)
31
+
32
+ UI.message("Getting avaliable AVDs".yellow)
33
+ devices = Action.sh(adb_controller.command_get_avds)
34
+
35
+ for i in 0..(avd_schemes.length - 1)
36
+ avd_scheme = avd_schemes[i]
37
+ avd_controller = avd_controllers[i]
38
+
39
+ # Delete existing AVDs
40
+ if !devices.match(avd_scheme.avd_name).nil?
41
+ UI.message(["Deleting existing AVD with name:", avd_scheme.avd_name].join(" ").yellow)
42
+ Action.sh(avd_controller.command_delete_avd)
43
+ end
80
44
 
81
- port = min_port
82
- while port < max_port do
83
- unless system(["lsof -i:", port].join(""), out: '/dev/null')
84
- break
85
- end
86
- port +=1
87
- end
88
- return port
89
- end
45
+ # Re-create deleted AVDs
46
+ UI.message("Creating new AVD".yellow)
47
+ Action.sh(avd_controller.command_create_avd)
48
+ end
90
49
 
91
- def self.createEmulator(get_devices_command, create_avd_command, params, sdkRoot)
92
- UI.message("Getting avaliable devices".yellow)
93
- devices = Action.sh(get_devices_command)
50
+ # Restart ADB
51
+ UI.message("Restarting adb".yellow)
52
+ Action.sh(adb_controller.command_stop)
53
+ Action.sh(adb_controller.command_start)
54
+
55
+ # Applying custom configs (it's not done directly after create because 'cat' operation seems to fail overwrite)
56
+ for i in 0..(avd_schemes.length - 1)
57
+ avd_scheme = avd_schemes[i]
58
+ avd_controller = avd_controllers[i]
59
+
60
+ UI.message(["Attemting to apply custom config to ", avd_scheme.avd_name].join("").yellow)
61
+ if avd_controller.command_apply_config_avd.eql? ""
62
+ UI.message(["No config file found for AVD '", avd_scheme.avd_name, "'. AVD won't have config.ini applied."].join("").yellow)
63
+ else
64
+ UI.message(["Config file found! Applying custom config to: ", avd_scheme.avd_name].join("").yellow)
65
+ Action.sh(avd_controller.command_apply_config_avd)
66
+ end
67
+ end
94
68
 
95
- unless devices.match(/#{params[:avd_name]}/).nil?
96
- UI.message("Deleting existing AVD to create fresh one".yellow)
97
- Action.sh(sdkRoot + "/tools/android delete avd -n #{params[:avd_name]}")
98
- end
69
+ # Launching AVDs
70
+ UI.message("Launching all AVDs at the same time".yellow)
71
+ for i in 0..(avd_schemes.length - 1)
72
+ avd_scheme = avd_schemes[i]
73
+ avd_controller = avd_controllers[i]
99
74
 
100
- Action.sh(create_avd_command)
101
- end
75
+ Action.sh(avd_controller.command_start_avd)
76
+ end
102
77
 
103
- def self.launchEmulator(start_avd_command, get_devices_command, create_avd_command, sdkRoot, port, params)
104
- restart_adb(sdkRoot)
105
- Action.sh(start_avd_command)
106
- waitFor_emulatorBoot(start_avd_command, get_devices_command, create_avd_command, sdkRoot, port, params)
107
- end
78
+ # Wait for AVDs finish booting
79
+ UI.message("Waiting for AVDs to finish booting".yellow)
80
+ boot_status = []
81
+ for i in 0..(avd_schemes.length - 1)
82
+ boot_status << false
83
+ end
108
84
 
109
- def self.waitFor_emulatorBoot(start_avd_command, get_devices_command, create_avd_command, sdkRoot, port, params)
110
- UI.message("Waiting for emulator to finish booting.....".yellow)
111
- startParams = "#{params[:avd_start_options]}"
112
-
113
- if startParams.include? "-no-window"
114
- Action.sh(sdkRoot + "/platform-tools/adb wait-for-device")
115
- Action.sh(sdkRoot + "/platform-tools/adb devices")
116
- return true
117
- else
118
- timeoutInSeconds= 150.0
119
- startTime = Time.now
120
- loop do
121
- dev_bootcomplete, _stdeerr, _status = Open3.capture3(sdkRoot + ["/platform-tools/adb -s emulator-", port].join("") + " shell getprop dev.bootcomplete")
122
- sys_boot_completed, _stdeerr, _status = Open3.capture3(sdkRoot + ["/platform-tools/adb -s emulator-", port].join("") + " shell getprop sys.boot_completed")
123
- bootanim, _stdeerr, _status = Open3.capture3(sdkRoot + ["/platform-tools/adb -s emulator-", port].join("") + " shell getprop init.svc.bootanim")
124
- currentTime = Time.now
125
-
126
- if (currentTime - startTime) >= timeoutInSeconds
127
- UI.message("Emulator loading took more than 2 minutes 30 seconds. Restarting emulator launch until.".yellow)
128
- adb_devices_result = Action.sh(sdkRoot + "/platform-tools/adb devices")
129
- if adb_devices_result.include? "offline"
130
- kill_emulator(sdkRoot, port, params)
131
-
132
- delayInSeconds = 20.0
133
- sleep(delayInSeconds)
134
-
135
- delete_emulator(sdkRoot, port, params)
136
-
137
- createEmulator(get_devices_command, create_avd_command, params, sdkRoot)
138
-
139
- launchEmulator(start_avd_command, get_devices_command, create_avd_command, sdkRoot, port, params)
85
+ UI.message("Performing wait for params: dev.bootcomplete, sys.boot_completed, init.svc.bootanim".yellow)
86
+ for i in 0..(avd_schemes.length - 1)
87
+ avd_controller = avd_controllers[i]
88
+ status = wait_for_emulator_boot(adb_controller, avd_controller)
89
+
90
+ if (!status)
91
+ all_avd_launched = false
140
92
  break
141
93
  end
142
- return false
94
+ all_avd_launched = true
143
95
  end
144
96
 
145
- if (dev_bootcomplete.strip == "1" && sys_boot_completed.strip == "1" && bootanim.strip == "stopped")
146
- UI.message("Emulator Booted!".green)
147
- return true
97
+ # Deciding if AVD launch should be restarted
98
+ devices = Action.sh(adb_controller.command_get_devices)
99
+ if all_avd_launched
100
+ UI.message("AVDs Booted!".green)
101
+ else
102
+ for i in 0..(avd_schemes.length - 1)
103
+ avd_scheme = avd_schemes[i]
104
+ avd_controller = avd_controllers[i]
105
+
106
+ # Kill all emulators
107
+ if !devices.match(["emulator-", avd_scheme.launch_avd_port].join("")).nil?
108
+ Action.sh(avd_controller.command_kill_device)
109
+ end
110
+ end
148
111
  end
112
+
149
113
  end
150
- end
151
- end
152
114
 
153
- def self.restart_adb(sdkRoot)
154
- UI.message("Restarting adb..".green)
155
- Action.sh(sdkRoot + "/platform-tools/adb kill-server")
156
- Action.sh(sdkRoot + "/platform-tools/adb start-server")
157
- end
115
+ # Launching tests
116
+ gradle = Helper::GradleHelper.new(gradle_path: Dir["./gradlew"].last)
158
117
 
159
- def self.kill_emulator(sdkRoot, port, params)
160
- UI.message("Shutting down emulator...".green)
161
- Action.sh(sdkRoot + "/platform-tools/adb -s " + ["emulator-", port].join("") + " emu kill &>/dev/null")
162
- end
118
+ shell_task = "#{params[:shell_task]}" unless params[:shell_task].nil?
119
+ gradle_task = "#{params[:gradle_task]}" unless params[:gradle_task].nil?
163
120
 
164
- def self.delete_emulator(sdkRoot, port, params)
165
- UI.message("Deleting emulator....".green)
166
- Action.sh(sdkRoot + "/tools/android delete avd -n #{params[:avd_name]}")
167
- end
121
+ UI.message("Starting tests".green)
122
+ begin
123
+ unless shell_task.nil?
124
+ UI.message("Using shell task".green)
125
+ Action.sh(shell_task)
126
+ end
168
127
 
169
- def self.waitFor_emulatorStop(sdkRoot, port, params)
170
- kill_emulator(sdkRoot, port, params)
128
+ unless gradle_task.nil?
129
+ UI.message("Using gradle task".green)
130
+ gradle.trigger(task: params[:gradle_task], flags: params[:gradle_flags], serial: nil)
131
+ end
132
+ ensure
133
+ # Clean up
134
+ for i in 0..(avd_schemes.length - 1)
135
+ avd_scheme = avd_schemes[i]
136
+ avd_controller = avd_controllers[i]
137
+
138
+ # Kill all emulators
139
+ if !devices.match(["emulator-", avd_scheme.launch_avd_port].join("")).nil?
140
+ Action.sh(avd_controller.command_kill_device)
141
+ end
171
142
 
172
- delayInSeconds = 20.0
173
- sleep(delayInSeconds)
143
+ # Delete AVDs
144
+ Action.sh(avd_controller.command_delete_avd)
145
+ end
146
+ end
174
147
 
175
- delete_emulator(sdkRoot, port, params)
176
- end
148
+ end
149
+
150
+ def self.wait_for_emulator_boot(adb_controller, avd_controller)
151
+ timeoutInSeconds= 240.0
152
+ startTime = Time.now
177
153
 
178
- def self.available_options
154
+ launch_status = false
155
+ loop do
156
+ dev_bootcomplete, _stdeerr, _status = Open3.capture3([avd_controller.command_get_property, "dev.bootcomplete"].join(" "))
157
+ sys_boot_completed, _stdeerr, _status = Open3.capture3([avd_controller.command_get_property, "sys.boot_completed"].join(" "))
158
+ bootanim, _stdeerr, _status = Open3.capture3([avd_controller.command_get_property, "init.svc.bootanim"].join(" "))
159
+ currentTime = Time.now
160
+
161
+ if (currentTime - startTime) >= timeoutInSeconds
162
+ UI.message("AVD loading took more than 4 minutes. Restarting launch".red)
163
+ launch_status = false
164
+ break
165
+ end
166
+
167
+ if (dev_bootcomplete.strip == "1" && sys_boot_completed.strip == "1" && bootanim.strip == "stopped")
168
+ launch_status = true
169
+ break
170
+ end
171
+ end
172
+ return launch_status
173
+ end
174
+
175
+ def self.available_options
179
176
  [
180
- FastlaneCore::ConfigItem.new(key: :avd_name,
181
- env_name: "AVD_NAME",
182
- description: "Name of the avd to be created",
183
- is_string: true,
184
- optional: false),
185
- FastlaneCore::ConfigItem.new(key: :target_id,
186
- env_name: "TARGET_ID",
187
- description: "Target id of the avd to be created, get list of installed target by running command 'android list targets'",
188
- is_string: true,
189
- optional: false),
190
- FastlaneCore::ConfigItem.new(key: :avd_create_options,
191
- env_name: "AVD_CREATE_OPTIONS",
192
- description: "Other avd options, used during avd creation, in the form of a <option>=<value> list, i.e \"--scale 96dpi --dpi-device 160\"",
193
- is_string: true,
194
- optional: true),
195
- FastlaneCore::ConfigItem.new(key: :avd_abi,
196
- env_name: "AVD_ABI",
197
- description: "The ABI to use for the AVD. The default is to auto-select the ABI if the platform has only one ABI for its system images",
177
+ #paths
178
+ FastlaneCore::ConfigItem.new(key: :AVD_path,
179
+ env_name: "AVD_PATH",
180
+ description: "The path to your android AVD directory (root). HOME/.android/avd by default",
198
181
  is_string: true,
182
+ default_value: ENV['HOME'] + '/.android/avd',
199
183
  optional: true),
200
- FastlaneCore::ConfigItem.new(key: :avd_tag,
201
- env_name: "AVD_TAG",
202
- description: "The sys-img tag to use for the AVD. The default is to auto-select if the platform has only one tag for its system images",
184
+ FastlaneCore::ConfigItem.new(key: :AVD_setup_path,
185
+ env_name: "AVD_SETUP_PATH",
186
+ description: "Location to AVD_setup.json file which contains info about how many AVD should be launched and their configs",
203
187
  is_string: true,
204
- optional: true),
205
- FastlaneCore::ConfigItem.new(key: :sdk_path,
188
+ optional: false),
189
+ FastlaneCore::ConfigItem.new(key: :SDK_path,
206
190
  env_name: "SDK_PATH",
207
191
  description: "The path to your android sdk directory (root). ANDROID_HOME by default",
208
192
  is_string: true,
209
193
  default_value: ENV['ANDROID_HOME'],
210
194
  optional: true),
211
195
 
212
- FastlaneCore::ConfigItem.new(key: :shell_command,
213
- env_name: "SHELL_COMMAND",
214
- description: "The shell command you want to execute",
215
- is_string: true,
216
- conflicting_options: [:gradle_task],
217
- optional: true),
196
+
197
+ #launch commands
198
+ FastlaneCore::ConfigItem.new(key: :shell_task,
199
+ env_name: "SHELL_TASK",
200
+ description: "The shell command you want to execute",
201
+ is_string: true,
202
+ conflicting_options: [:gradle_task],
203
+ optional: true),
218
204
  FastlaneCore::ConfigItem.new(key: :gradle_task,
219
- env_name: "GRADLE_TASK",
220
- description: "The gradle task you want to execute",
221
- is_string: true,
222
- conflicting_options: [:shell_command],
223
- optional: true),
205
+ env_name: "GRADLE_TASK",
206
+ description: "The gradle task you want to execute",
207
+ is_string: true,
208
+ conflicting_options: [:shell_command],
209
+ optional: true),
224
210
  FastlaneCore::ConfigItem.new(key: :gradle_flags,
225
- env_name: "GRADLE_FLAGS",
226
- description: "All parameter flags you want to pass to the gradle command, e.g. `--exitcode --xml file.xml`",
227
- optional: true,
228
- conflicting_options: [:shell_command],
229
- is_string: true),
230
-
231
- FastlaneCore::ConfigItem.new(key: :emulator_binary,
232
- env_name: "EMULATOR_BINARY",
233
- description: "Emulator binary file you would like to use in order to start emulator",
234
- is_string: true,
235
- default_value: "emulator",
236
- optional: true),
237
- FastlaneCore::ConfigItem.new(key: :avd_port,
238
- env_name: "AVD_PORT",
239
- description: "Possible to specify port on which emulator should run",
240
- is_string: true,
241
- optional: true),
242
- FastlaneCore::ConfigItem.new(key: :avd_start_options,
243
- env_name: "AVD_START_OPTIONS",
244
- description: "Additonal run parameters e.g. gpu, audio, boot animation",
245
- is_string: true,
246
- optional: true),
247
- FastlaneCore::ConfigItem.new(key: :initdata_snapshot_path,
248
- env_name: "INIT_DATA_PATH",
249
- description: "The path to userdata-qemu which will be used to initialize AVD status",
250
- is_string: true,
251
- optional: true),
211
+ env_name: "GRADLE_FLAGS",
212
+ description: "All parameter flags you want to pass to the gradle command, e.g. `--exitcode --xml file.xml`",
213
+ optional: true,
214
+ conflicting_options: [:shell_command],
215
+ is_string: true),
252
216
  ]
253
- end
217
+ end
254
218
 
255
- def self.description
256
- "Starts single emulator before running tests."
257
- end
219
+ def self.description
220
+ "Starts AVD, based on AVD_setup.json file, before test launch and kills it after testing is done."
221
+ end
258
222
 
259
- def self.authors
260
- ["joshrlesch, modified by F1sherKK"]
261
- end
223
+ def self.authors
224
+ ["F1sherKK"]
225
+ end
262
226
 
263
- def self.is_supported?(platform)
264
- platform == :android
227
+ def self.is_supported?(platform)
228
+ platform == :android
229
+ end
265
230
  end
266
- end
267
231
  end
268
232
  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_android_binary = path_sdk + "/tools/android"
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_android_binary,
49
+ sh_list_avd_adb].join(" ").chomp
50
+
51
+ return adb_controller
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,109 @@
1
+ module Fastlane
2
+ module Factory
3
+
4
+ class AVD_Controller
5
+ attr_accessor :command_create_avd, :command_start_avd, :command_delete_avd, :command_apply_config_avd, :command_get_property, :command_kill_device
6
+ end
7
+
8
+ class AvdControllerFactory
9
+
10
+ def self.get_avd_controller(params, avd_scheme)
11
+ UI.message(["Preparing parameters and commands for emulator:", avd_scheme.avd_name].join(" ").yellow)
12
+
13
+ # Get paths
14
+ path_sdk = "#{params[:SDK_path]}"
15
+ path_android_binary = path_sdk + "/tools/android"
16
+ path_adb = path_sdk + "/platform-tools/adb"
17
+ path_avd = "#{params[:AVD_path]}"
18
+
19
+ # Create AVD shell command parts
20
+ sh_create_answer_no = "echo \"no\" |"
21
+ sh_create_avd = "create avd"
22
+ sh_create_avd_name = ["--name \"", avd_scheme.avd_name, "\""].join("")
23
+ sh_create_avd_additional_options = avd_scheme.create_avd_additional_options
24
+ sh_create_config_loc = "#{path_avd}/#{avd_scheme.avd_name}.avd/config.ini"
25
+
26
+ if avd_scheme.create_avd_target.eql? ""
27
+ sh_create_avd_target = ""
28
+ else
29
+ sh_create_avd_target = ["--target \"", avd_scheme.create_avd_target, "\""].join("")
30
+ end
31
+
32
+ if avd_scheme.create_avd_abi.eql? ""
33
+ sh_create_avd_abi = ""
34
+ else
35
+ sh_create_avd_abi = ["--abi ", avd_scheme.create_avd_abi].join("")
36
+ end
37
+
38
+ # Launch AVD shell command parts
39
+ sh_launch_emulator_binray = [path_sdk, "/tools/", avd_scheme.launch_avd_launch_binary_name].join("")
40
+ sh_launch_avd_name = ["-avd ", avd_scheme.avd_name].join("")
41
+ sh_launch_avd_additional_options = avd_scheme.launch_avd_additional_options
42
+ sh_launch_avd_port = ["-port", avd_scheme.launch_avd_port].join(" ")
43
+
44
+ if avd_scheme.launch_avd_snapshot_filepath.eql? ""
45
+ sh_launch_avd_snapshot = ""
46
+ else
47
+ sh_launch_avd_snapshot = ["-wipe-data -initdata ", avd_scheme.launch_avd_snapshot_filepath].join("")
48
+ end
49
+
50
+ # Re-create AVD shell command parts
51
+ sh_delete_avd = ["delete avd -n ", avd_scheme.avd_name].join("")
52
+
53
+ # ADB related shell command parts
54
+ sh_specific_device = "-s"
55
+ sh_device_name_adb = ["emulator-", avd_scheme.launch_avd_port].join("")
56
+ sh_get_property = "shell getprop"
57
+ sh_kill_device = "emu kill"
58
+
59
+ # Assemble AVD controller
60
+ avd_controller = AVD_Controller.new
61
+ avd_controller.command_create_avd = [
62
+ sh_create_answer_no,
63
+ path_android_binary,
64
+ sh_create_avd,
65
+ sh_create_avd_name,
66
+ sh_create_avd_target,
67
+ sh_create_avd_abi,
68
+ sh_create_avd_additional_options].join(" ")
69
+
70
+ avd_controller.command_start_avd = [
71
+ sh_launch_emulator_binray,
72
+ sh_launch_avd_port,
73
+ sh_launch_avd_name,
74
+ sh_launch_avd_snapshot,
75
+ sh_launch_avd_additional_options,
76
+ "&>/dev/null &"].join(" ")
77
+
78
+ avd_controller.command_delete_avd = [
79
+ path_android_binary,
80
+ sh_delete_avd].join(" ")
81
+
82
+ if path_avd.nil? || (avd_scheme.create_avd_hardware_config_filepath.eql? "")
83
+ avd_controller.command_apply_config_avd = ""
84
+ else
85
+ avd_controller.command_apply_config_avd = [
86
+ "cat",
87
+ avd_scheme.create_avd_hardware_config_filepath,
88
+ ">",
89
+ sh_create_config_loc].join(" ")
90
+ end
91
+
92
+ avd_controller.command_get_property = [
93
+ path_adb,
94
+ sh_specific_device,
95
+ sh_device_name_adb,
96
+ sh_get_property].join(" ")
97
+
98
+ avd_controller.command_kill_device = [
99
+ path_adb,
100
+ sh_specific_device,
101
+ sh_device_name_adb,
102
+ sh_kill_device,
103
+ "&>/dev/null"].join(" ")
104
+
105
+ return avd_controller
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,167 @@
1
+ module Fastlane
2
+ module Provider
3
+
4
+ class AVD_scheme
5
+ attr_accessor :avd_name, :create_avd_target, :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 - 1)
26
+ avd_hash = avd_hash_list[i]
27
+
28
+ avd_scheme = AVD_scheme.new
29
+ avd_scheme.avd_name = avd_hash['avd_name']
30
+ avd_scheme.create_avd_target = avd_hash['create_avd_target']
31
+ avd_scheme.create_avd_abi = avd_hash['create_avd_abi']
32
+ avd_scheme.create_avd_hardware_config_filepath = avd_hash['create_avd_hardware_config_filepath']
33
+ avd_scheme.create_avd_additional_options = avd_hash['create_avd_additional_options']
34
+ avd_scheme.launch_avd_port = avd_hash['launch_avd_port']
35
+ avd_scheme.launch_avd_launch_binary_name = avd_hash['launch_avd_launch_binary_name']
36
+ avd_scheme.launch_avd_additional_options = avd_hash['launch_avd_additional_options']
37
+ avd_scheme.launch_avd_snapshot_filepath = avd_hash['launch_avd_snapshot_filepath']
38
+
39
+ errors = check_avd_fields(avd_scheme)
40
+ unless errors.empty?
41
+ error_log = "Error! Fields not found in JSON: \n"
42
+ errors.each { |error| error_log += error + "\n" }
43
+ throw_error(error_log)
44
+ end
45
+
46
+ avd_scheme_list << avd_scheme
47
+ end
48
+
49
+ # Prepare list of open ports for AVD_schemes without ports set in JSON
50
+ avaliable_ports = get_unused_even_tcp_ports(5556, 5586, avd_scheme_list)
51
+
52
+ # Fill empty AVD_schemes with open ports
53
+ for i in 0..(avd_scheme_list.length - 1)
54
+ avd_scheme = avd_scheme_list[i]
55
+ if avd_scheme.launch_avd_port.eql? ""
56
+ avd_scheme.launch_avd_port = avaliable_ports[0]
57
+ avaliable_ports.delete(avaliable_ports[0])
58
+ end
59
+ end
60
+
61
+ return avd_scheme_list
62
+ end
63
+
64
+ def self.get_unused_even_tcp_ports(min_port, max_port, avd_scheme_list)
65
+ if min_port % 2 != 0
66
+ min_port += 1
67
+ end
68
+
69
+ if max_port % 2 != 0
70
+ max_port += 1
71
+ end
72
+
73
+ avaliable_ports = []
74
+ reserved_ports = []
75
+
76
+ # Gather ports requested in JSON config
77
+ for i in 0..(avd_scheme_list.length - 1)
78
+ avd_scheme = avd_scheme_list[i]
79
+ unless avd_scheme.launch_avd_port.eql? ""
80
+ reserved_ports << avd_scheme.launch_avd_port
81
+ end
82
+ end
83
+
84
+ # Find next open port which wasn't reserved in JSON config
85
+ port = min_port
86
+ for i in 0..(avd_scheme_list.length - 1)
87
+
88
+ while port < max_port do
89
+ if !system("lsof -i:#{port}", out: '/dev/null')
90
+
91
+ is_port_reserved = false
92
+ for j in 0..(reserved_ports.length - 1)
93
+ if reserved_ports[j].eql?(port.to_s)
94
+ is_port_reserved = true
95
+ break
96
+ end
97
+ end
98
+
99
+ if is_port_reserved
100
+ port = port + 2
101
+ break
102
+ end
103
+
104
+ avaliable_ports << port
105
+ port = port + 2
106
+ break
107
+ else
108
+ port = port + 2
109
+ end
110
+ end
111
+ end
112
+
113
+ return avaliable_ports
114
+ end
115
+
116
+ def self.read_avd_setup(params)
117
+ if File.exists?(File.expand_path("#{params[:AVD_setup_path]}"))
118
+ file = File.open(File.expand_path("#{params[:AVD_setup_path]}"), "rb")
119
+ json = file.read
120
+ file.close
121
+ return json
122
+ else
123
+ return nil
124
+ end
125
+ end
126
+
127
+ def self.check_avd_fields(avd_scheme)
128
+ errors = []
129
+
130
+ if avd_scheme.avd_name.nil?
131
+ errors.push("avd_name not found")
132
+ end
133
+ if avd_scheme.create_avd_target.nil?
134
+ errors.push("create_avd_target not found")
135
+ end
136
+ if avd_scheme.create_avd_abi.nil?
137
+ errors.push("create_avd_abi not found")
138
+ end
139
+ if avd_scheme.create_avd_hardware_config_filepath.nil?
140
+ errors.push("create_avd_hardware_config_filepath not found")
141
+ end
142
+ if avd_scheme.create_avd_additional_options.nil?
143
+ errors.push("create_avd_additional_options not found")
144
+ end
145
+ if avd_scheme.launch_avd_snapshot_filepath.nil?
146
+ errors.push("launch_avd_snapshot_filepath not found")
147
+ end
148
+ if avd_scheme.launch_avd_launch_binary_name.nil?
149
+ errors.push("launch_avd_launch_binary_name not found")
150
+ end
151
+ if avd_scheme.launch_avd_port.nil?
152
+ errors.push("launch_avd_port not found")
153
+ end
154
+ if avd_scheme.launch_avd_additional_options.nil?
155
+ errors.push("launch_avd_additional_options not found")
156
+ end
157
+
158
+ return errors
159
+ end
160
+
161
+ def self.throw_error(message)
162
+ UI.message("Error: ".red + message.red)
163
+ raise Exception, "Lane was stopped by plugin"
164
+ end
165
+ end
166
+ end
167
+ end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module AutomatedTestEmulatorRun
3
- VERSION = "0.5.16"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-automated_test_emulator_run
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.16
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kamil Krzyk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-07 00:00:00.000000000 Z
11
+ date: 2016-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -104,7 +104,9 @@ files:
104
104
  - README.md
105
105
  - lib/fastlane/plugin/automated_test_emulator_run.rb
106
106
  - lib/fastlane/plugin/automated_test_emulator_run/actions/automated_test_emulator_run_action.rb
107
- - lib/fastlane/plugin/automated_test_emulator_run/helper/automated_test_emulator_run_helper.rb
107
+ - lib/fastlane/plugin/automated_test_emulator_run/factory/adb_controller_factory.rb
108
+ - lib/fastlane/plugin/automated_test_emulator_run/factory/avd_controller_factory.rb
109
+ - lib/fastlane/plugin/automated_test_emulator_run/provider/avd_setup_provider.rb
108
110
  - lib/fastlane/plugin/automated_test_emulator_run/version.rb
109
111
  homepage: https://github.com/AzimoLabs/fastlane-plugin-automated-test-emulator-run
110
112
  licenses:
@@ -129,7 +131,7 @@ rubyforge_project:
129
131
  rubygems_version: 2.5.1
130
132
  signing_key:
131
133
  specification_version: 4
132
- summary: Allows to wrap gradle task or shell command that runs integrated tests that
133
- prepare and starts single AVD before test run. After tests are finished, emulator
134
- is killed and deleted.
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.
135
137
  test_files: []
@@ -1,12 +0,0 @@
1
- module Fastlane
2
- module Helper
3
- class AutomatedTestEmulatorRunHelper
4
- # class methods that you define here become available in your action
5
- # as `Helper::AutomatedTestEmulatorRunHelper.your_method`
6
- #
7
- def self.show_message
8
- UI.message("Hello from the automated_test_emulator_run plugin helper!")
9
- end
10
- end
11
- end
12
- end