Class: Fastlane::Actions::InstrumentedTestsAction

Inherits:
Action
  • Object
show all
Defined in:
lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb

Class Method Summary collapse

Class Method Details

.authorsObject



217
218
219
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 217

def self.authors
  ["joshrlesch", "lexxdark"]
end

.available_optionsObject



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 147

def self.available_options
  [
    FastlaneCore::ConfigItem.new(key: :avd_name,
                                 env_name: "AVD_NAME",
                                 description: "Name of the avd to be created",
                                 is_string: true,
                                 optional: false),
    FastlaneCore::ConfigItem.new(key: :avd_abi,
                                 env_name: "AVD_ABI",
                                 description: "The ABI to use for the AVD (e.g. google_apis/x86)",
                                 is_string: true,
                                 optional: false),
    FastlaneCore::ConfigItem.new(key: :avd_package,
                                 env_name: "AVD_PACKAGE",
                                 description: "Package path of the system image for this AVD (e.g. 'system-images;android-19;google_apis;x86')",
                                 is_string: true,
                                 optional: false),
    FastlaneCore::ConfigItem.new(key: :avd_port,
                                 env_name: "AVD_PORT",
                                 description: "The port used for communication with the emulator. If not set it is randomly selected",
                                 is_string: false,
                                 optional: true),
    FastlaneCore::ConfigItem.new(key: :boot_timeout,
                                 env_name: "BOOT_TIMEOUT",
                                 description: "Number of seconds to wait for the emulator to boot",
                                 is_string: false,
                                 optional: true,
                                 default_value: 500),
    FastlaneCore::ConfigItem.new(key: :emulator_options,
                                 env_name: "EMULATOR_OPTIONS",
                                 description: "Other options passed to the emulator command ('emulator -avd AVD_NAME ...')." +
                                     "Defaults are '-gpu on' when AVD_HIDE is false and '-no-window' otherwise. " +
                                     "For macs running the CI you might want to use '-no-audio -no-window'",
                                 is_string: true,
                                 optional: true),
    FastlaneCore::ConfigItem.new(key: :sdk_path,
                                 env_name: "ANDROID_HOME",
                                 description: "The path to your android sdk directory",
                                 is_string: true,
                                 default_value: ENV['ANDROID_HOME'],
                                 optional: true),
    FastlaneCore::ConfigItem.new(key: :flags,
                                 env_name: "FL_GRADLE_FLAGS",
                                 description: "All parameter flags you want to pass to the gradle command, e.g. `--exitcode --xml file.xml`",
                                 optional: true,
                                 is_string: true),
    FastlaneCore::ConfigItem.new(key: :task,
                                 env_name: "FL_GRADLE_TASK",
                                 description: "The gradle task you want to execute",
                                 is_string: true,
                                 optional: true,
                                 default_value: "connectedCheck"),
    FastlaneCore::ConfigItem.new(key: :project_dir,
                                 env_name: 'FL_GRADLE_PROJECT_DIR',
                                 description: 'The root directory of the gradle project. Defaults to `.`',
                                 default_value: '.',
                                 is_string: true),
    FastlaneCore::ConfigItem.new(key: :avd_hide,
                                 env_name: "AVD_HIDE",
                                 description: "Specifies whether the emulator should be hidden or not (defaults to true)",
                                 default_value: true,
                                 is_string: false,
                                 optional: true)
  ]
end

.close_emulator_streams(params) ⇒ Object



126
127
128
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 126

def self.close_emulator_streams(params)
  @emulator_output.close
end

.create_emulator(params) ⇒ Object



50
51
52
53
54
55
56
57
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 50

def self.create_emulator(params)
  avd_name = "--name '#{params[:avd_name]}'"
  avd_package = "--package #{params[:avd_package]}"
  avd_abi = "--abi #{params[:avd_abi]}"
  create_avd = ["echo no | #{params[:sdk_path]}/tools/bin/avdmanager", "create avd", avd_package, avd_name, avd_abi]
  UI.important("Creating AVD...")
  Action.sh(create_avd)
end

.delete_old_emulators(params) ⇒ Object



42
43
44
45
46
47
48
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 42

def self.delete_old_emulators(params)
  devices = `#{params[:sdk_path]}/tools/android list avd`.chomp

  unless devices.match(/#{params[:avd_name]}/).nil?
    Action.sh("#{params[:sdk_path]}/tools/android delete avd -n #{params[:avd_name]}")
  end
end

.descriptionObject



135
136
137
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 135

def self.description
  "Run android instrumented tests via a gradle command againts a newly created avd"
end

.detailsObject



139
140
141
142
143
144
145
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 139

def self.details
  [
    "Instrumented tests need a emulator or real device to execute against.",
    "This action will check for a specific avd and created, wait for full boot,",
    "run gradle command, then deleted that avd on each run."
  ].join("\n")
end

.execute_gradle(params) ⇒ Object



130
131
132
133
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 130

def self.execute_gradle(params)
  Fastlane::Actions::GradleAction.run(task: params[:task], flags: params[:flags], project_dir: params[:project_dir],
                                      serial: @android_serial, print_command: true, print_command_output: true)
end

.is_supported?(platform) ⇒ Boolean

Returns:

  • (Boolean)


221
222
223
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 221

def self.is_supported?(platform)
  platform == :android
end


119
120
121
122
123
124
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 119

def self.print_emulator_output(params)
  UI.error("Error while trying to execute instrumentation tests. Output from emulator:")
  @emulator_output.readlines.each do |line|
    UI.error(line.gsub(/\r|\n/, " "))
  end
end

.return_valueObject



213
214
215
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 213

def self.return_value
  "The output from the test execution."
end

.run(params) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 10

def self.run(params)
  setup_parameters(params)
  delete_old_emulators(params)
  begin
    begin
      create_emulator(params)
      start_emulator(params)

      wait_emulator_boot(params)
      execute_gradle(params)
    ensure
      stop_emulator(params)
    end

  rescue Exception => e
    print_emulator_output(params)
    raise e
  ensure
    close_emulator_streams(params)
  end
end

.setup_parameters(params) ⇒ Object



32
33
34
35
36
37
38
39
40
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 32

def self.setup_parameters(params)
  # port must be an even integer number between 5554 and 5680
  params[:avd_port]=Random.rand(15)*2+5554 if params[:avd_port].nil?
  raise ":avd_port must be at least 5554" if params[:avd_port]<5554
  raise ":avd_port must be lower than 5584" if params[:avd_port]>5584
  raise ":avd_port must be an even number" if params[:avd_port]%2 != 0

  @android_serial="emulator-#{params[:avd_port]}"
end

.start_emulator(params) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 59

def self.start_emulator(params)
  UI.important("Starting AVD...")
  ui_args = "-gpu on"
  ui_args << " -no-window" if params[:avd_hide]
  ui_args << " #{params[:emulator_options]}" if params[:emulator_options] != nil
  start_avd = ["#{params[:sdk_path]}/tools/emulator", "-avd #{params[:avd_name]}", "#{ui_args}", "-port #{params[:avd_port]}" ].join(" ")

  UI.command(start_avd)
  stdin, @emulator_output, @emulator_thread = Open3.popen2e(start_avd)
  stdin.close
end

.stop_emulator(params) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 99

def self.stop_emulator(params)
  begin
    UI.important("Shutting down emulator...")
    adb = Helper::AdbHelper.new(adb_path: "#{params[:sdk_path]}/platform-tools/adb")
    adb.trigger(command: "emu kill", serial: @android_serial)
  rescue
    UI.message("Emulator is not listening for our commands...")
    UI.message("Current status of emulator process is: #{@emulator_thread.status}")

    if @emulator_thread != nil && @emulator_thread.status != true && @emulator_thread.status != false
      UI.important("Emulator still running... Killing PID #{@emulator_thread.pid}!")
      Process.kill("KILL", @emulator_thread.pid)
    end

  end

  UI.important("Deleting emulator...")
  Action.sh("#{params[:sdk_path]}/tools/android delete avd -n #{params[:avd_name]}")
end

.wait_emulator_boot(params) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/fastlane/plugin/instrumented_tests/actions/instrumented_tests_action.rb', line 71

def self.wait_emulator_boot(params)
  timeout = Time.now + params[:boot_timeout]
  UI.important("Waiting for emulator to finish booting... May take a few minutes...")

  adb_path = "#{params[:sdk_path]}/platform-tools/adb"
  raise "Unable to find adb in #{adb_path}" unless File.file?(adb_path)
  loop do
    boot_complete_cmd = "ANDROID_SERIAL=#{@android_serial} #{adb_path} shell getprop sys.boot_completed" 
    stdout, _stdeerr, _status = Open3.capture3(boot_complete_cmd)

    if @emulator_thread != nil && (@emulator_thread.status == false || @emulator_thread.status == true)
      UI.error("Emulator unexpectedly quit!")
      raise "Emulator unexpectedly quit"
    end

    if (Time.now > timeout)
      UI.error("Waited #{params[:boot_timeout]} seconds for emulator to boot without success")
      raise "Emulator didn't boot"
    end

    if stdout.strip == "1"
      UI.success("Emulator Booted!")
      break
    end
    sleep(1)
  end
end