rubotium 0.0.4 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/bin/rubotium +4 -2
  4. data/lib/rubotium/adb/commands/command.rb +55 -0
  5. data/lib/rubotium/adb/commands/install_command.rb +19 -0
  6. data/lib/rubotium/adb/commands/instrument_command.rb +27 -0
  7. data/lib/rubotium/adb/commands/memory_command.rb +19 -0
  8. data/lib/rubotium/adb/commands/pull_command.rb +19 -0
  9. data/lib/rubotium/adb/commands/shell_command.rb +21 -0
  10. data/lib/rubotium/adb/commands/uninstall_command.rb +19 -0
  11. data/lib/rubotium/adb/commands.rb +7 -0
  12. data/lib/rubotium/adb/devices.rb +15 -6
  13. data/lib/rubotium/adb/parsers/procrank.rb +51 -0
  14. data/lib/rubotium/adb/parsers/single_test_result_parser.rb +61 -0
  15. data/lib/rubotium/adb/parsers/test_results_parser.rb +69 -0
  16. data/lib/rubotium/adb/parsers.rb +3 -0
  17. data/lib/rubotium/adb/test_result_parser.rb +5 -4
  18. data/lib/rubotium/adb.rb +3 -5
  19. data/lib/rubotium/apk/android_apk.rb +102 -0
  20. data/lib/rubotium/apk.rb +2 -2
  21. data/lib/rubotium/cmd.rb +1 -1
  22. data/lib/rubotium/device.rb +19 -33
  23. data/lib/rubotium/devices.rb +27 -14
  24. data/lib/rubotium/formatters/junit_formatter.rb +10 -11
  25. data/lib/rubotium/memory/data_point.rb +63 -0
  26. data/lib/rubotium/memory/monitor.rb +65 -0
  27. data/lib/rubotium/memory.rb +8 -0
  28. data/lib/rubotium/package.rb +7 -4
  29. data/lib/rubotium/runnable_test.rb +13 -0
  30. data/lib/rubotium/test_cases_reader.rb +32 -0
  31. data/lib/rubotium/test_result.rb +52 -0
  32. data/lib/rubotium/test_results.rb +18 -0
  33. data/lib/rubotium/test_runners/instrumentation_test_runner.rb +24 -0
  34. data/lib/rubotium/tests_runner.rb +80 -0
  35. data/lib/rubotium/version.rb +1 -1
  36. data/lib/rubotium.rb +54 -41
  37. data/rubotium.gemspec +0 -1
  38. data/spec/fixtures/adb_raw_result.rb +138 -0
  39. data/spec/fixtures/adb_raw_results.rb +153 -0
  40. data/spec/fixtures/adb_results.rb +4 -0
  41. data/spec/lib/rubotium/adb/adb_devices_spec.rb +43 -12
  42. data/spec/lib/rubotium/adb/adb_result_parser_spec.rb +22 -7
  43. data/spec/lib/rubotium/adb/adb_shell_spec.rb +11 -6
  44. data/spec/lib/rubotium/adb/parsers/procrank_spec.rb +61 -0
  45. data/spec/lib/rubotium/adb/parsers/single_test_result_parser_spec.rb +116 -0
  46. data/spec/lib/rubotium/adb/parsers/test_results_parser_spec.rb +108 -0
  47. data/spec/lib/rubotium/apk/android_apk_spec.rb +37 -0
  48. data/spec/lib/rubotium/apk/mock/BarcodeScanner4.2.apk +0 -0
  49. data/spec/lib/rubotium/apk/mock/UECExpress.apk +0 -0
  50. data/spec/lib/rubotium/apk/mock/dummy.apk +1 -0
  51. data/spec/lib/rubotium/apk/mock/sample.apk +0 -0
  52. data/spec/lib/rubotium/device_spec.rb +38 -0
  53. data/spec/lib/rubotium/devices_spec.rb +41 -24
  54. data/spec/lib/rubotium/memory/data_point_spec.rb +42 -0
  55. data/spec/lib/rubotium/memory/monitor_spec.rb +6 -0
  56. data/spec/lib/rubotium/tests_runner_spec.rb +47 -0
  57. data/spec/spec_helper.rb +2 -0
  58. data/test.rb +11 -0
  59. metadata +62 -41
  60. data/lib/rubotium/adb/command.rb +0 -21
  61. data/lib/rubotium/adb/install_command.rb +0 -17
  62. data/lib/rubotium/adb/instrumentation.rb +0 -36
  63. data/lib/rubotium/adb/uninstall_command.rb +0 -17
  64. data/lib/rubotium/apk/converter.rb +0 -22
  65. data/lib/rubotium/grouper.rb +0 -40
  66. data/lib/rubotium/jar_reader.rb +0 -70
  67. data/lib/rubotium/runable_test.rb +0 -11
  68. data/lib/rubotium/test_case.rb +0 -6
  69. data/lib/rubotium/test_suite.rb +0 -12
  70. data/spec/lib/rubotium/adb/adb_instrumentation_spec.rb +0 -32
  71. data/spec/lib/rubotium/grouper_spec.rb +0 -56
  72. data/spec/lib/rubotium/jar_reader_spec.rb +0 -58
@@ -1,49 +1,35 @@
1
1
  module Rubotium
2
2
  class Device
3
- attr_accessor :testsuite
4
- attr_reader :serial, :results
5
- def initialize(serial, test_runner)
6
- @runner = test_runner
7
- @retry = 1
8
- @serial = serial
9
- @results = {}
10
- @command = Rubotium::Adb::Command.new(serial)
3
+ attr_reader :serial
4
+ def initialize(serial)
5
+ @serial = serial
11
6
  end
12
7
 
13
- def test_runner_name= name
14
- runner.test_runner = name
15
- end
16
-
17
- def test_package_name= name
18
- runner.test_package_name = name
8
+ def name
9
+ @name ||= adb_command.shell('getprop ro.product.model').strip
19
10
  end
20
11
 
21
12
  def install(apk_path)
22
- command.execute(Rubotium::Adb::InstallCommand.new(apk_path))
13
+ adb_command.install(apk_path)
23
14
  end
24
15
 
25
16
  def uninstall(package_name)
26
- command.execute(Rubotium::Adb::UninstallCommand.new(package_name))
17
+ adb_command.uninstall(package_name)
18
+ end
19
+
20
+ def pull(path)
21
+ adb_command.pull(path)
27
22
  end
28
23
 
29
- def run_tests
30
- raise(NoTestSuiteError, "Please setup test suite before running tests") if testsuite.nil?
31
- puts "Running tests"
32
- testsuite.each{|runable_test|
33
- @results[runable_test.package_name] = [] if(@results[runable_test.package_name].nil?)
34
- puts runable_test.name
35
- run_count = 0
36
- puts "TEST: #{runable_test.name}"
37
- while ((result = runner.run_test(runable_test)) && (result.failed? || result.errored?) && run_count < @retry ) do
38
- puts "RERUNNING TEST: #{runable_test.name}, STATUS: #{result.status}"
39
- run_count += 1
40
- end
41
- puts "FINISHED with status: #{result.status}"
42
- @results[runable_test.package_name].push(result)
43
- }
24
+ def shell(command)
25
+ adb_command.shell(command)
44
26
  end
45
27
 
46
28
  private
47
- attr_reader :runner, :command
29
+ attr_reader :command
30
+
31
+ def adb_command
32
+ @command ||= Rubotium::Adb::Commands::Command.new(serial)
33
+ end
48
34
  end
49
- end
35
+ end
@@ -1,25 +1,38 @@
1
1
  module Rubotium
2
2
  class Devices
3
- def initialize(device_matcher = '')
4
- @attached_devices = Adb::Devices.new.list
5
- @matched = matched_devices device_matcher
3
+ def initialize(options = {})
4
+ @match_serial = options[:serial] || ''
5
+ @match_name = options[:name] || ''
6
6
  end
7
7
 
8
8
  def all
9
9
  raise NoDevicesError if attached_devices.empty?
10
- raise NoMatchedDevicesError if matched.empty?
11
- matched.map{|device|
12
- Device.new(device, Adb::Instrumentation.new(device))
13
- }
10
+ raise NoMatchedDevicesError if matched_by_name.empty?
11
+ (matched_by_name + matched_by_serial).uniq
14
12
  end
15
13
 
16
14
  private
17
- attr_reader :matched, :attached_devices
15
+ attr_reader :matched, :attached_devices, :match_name, :match_serial
16
+
17
+ def attached_devices
18
+ @attached_devices ||= adb_devices.attached
19
+ end
20
+
21
+ def matched_by_serial
22
+ attached_devices.select { |device|
23
+ device.serial.eql? match_serial
24
+ }
25
+ end
26
+
27
+ def matched_by_name
28
+ attached_devices.select { |device|
29
+ device.name.include? match_name
30
+ }
31
+ end
32
+
33
+ def adb_devices
34
+ Adb::Devices.new
35
+ end
18
36
 
19
- def matched_devices(device_matcher)
20
- device_matcher ? attached_devices.select{|device|
21
- device.include? device_matcher
22
- } : attached_devices
23
- end
24
37
  end
25
- end
38
+ end
@@ -4,22 +4,21 @@ module Rubotium
4
4
  module Formatters
5
5
  class JunitFormatter
6
6
  attr_reader :xml
7
- def initialize(device, path_to_file)
8
- @device_serial = device.serial
9
- @results = device.results
7
+ def initialize(results, path_to_file)
8
+ @results = results
10
9
  @report_file_path = path_to_file
11
10
 
12
11
  @xml = Builder::XmlMarkup.new :target => ensure_io(report_path), :indent => 2
13
12
 
14
13
  xml.testsuites do
15
- results.each{|_, tests|
16
- start_test_suite(tests)
14
+ results.each{|package_name, tests|
15
+ start_test_suite(package_name, tests)
17
16
  }
18
17
  end
19
18
  end
20
19
  private
21
20
  attr_reader :report_file_path, :device_serial, :results
22
- def start_test_suite(tests)
21
+ def start_test_suite(package_name, tests)
23
22
  failures = get_failures(tests)
24
23
  errors = get_errors(tests)
25
24
  tests_time = get_tests_time(tests)
@@ -27,7 +26,7 @@ module Rubotium
27
26
  params = {
28
27
  :errors => errors,
29
28
  :failures => failures,
30
- :name => device_serial,
29
+ :name => package_name,
31
30
  :tests => tests_count,
32
31
  :time => tests_time,
33
32
  :timestamp => Time.now
@@ -41,13 +40,13 @@ module Rubotium
41
40
  end
42
41
 
43
42
  def print_testcase(test)
44
- xml.testcase(:classname=>test.package_name, :name=>test.test_name, :time=>test.time) do
43
+ xml.testcase(:classname=> test.class_name, :name=>test.test_name, :time=>test.time) do
45
44
  has_failures(test)
46
45
  has_errors(test)
47
46
  end
48
47
  end
49
48
 
50
- def has_failures(test)
49
+ def has_failures(test)
51
50
  if test.failed?
52
51
  xml.failure :message=>"", :type=>"" do
53
52
  xml.cdata! test.stack_trace
@@ -80,7 +79,7 @@ module Rubotium
80
79
  end
81
80
 
82
81
  def report_path
83
- "#{device_serial}_#{report_file_path}"
82
+ report_file_path
84
83
  end
85
84
 
86
85
  def ensure_io(path_to_file)
@@ -88,4 +87,4 @@ module Rubotium
88
87
  end
89
88
  end
90
89
  end
91
- end
90
+ end
@@ -0,0 +1,63 @@
1
+ require 'json'
2
+ module Rubotium
3
+ module Memory
4
+ class DataPoint
5
+ attr_reader :time
6
+
7
+ def initialize(time, data_struct)
8
+ @time = time
9
+ @data_struct = data_struct
10
+ end
11
+
12
+ def pid
13
+ parsed_result.pid
14
+ end
15
+
16
+ def vss
17
+ parsed_result.vss
18
+ end
19
+
20
+ def rss
21
+ parsed_result.rss
22
+ end
23
+
24
+ def pss
25
+ parsed_result.pss
26
+ end
27
+
28
+ def uss
29
+ parsed_result.uss
30
+ end
31
+
32
+ def cmdline
33
+ parsed_result.cmdline
34
+ end
35
+
36
+ def to_s
37
+ to_json.to_json
38
+ end
39
+
40
+ def to_json
41
+ {
42
+ :time => time,
43
+ :pid => pid,
44
+ :vss => vss,
45
+ :rss => rss,
46
+ :uss => uss,
47
+ :cmd => cmdline
48
+ }
49
+ end
50
+
51
+ private
52
+ attr_reader :data_struct
53
+
54
+ def parsed_result
55
+ @parsed_result ||= parser.parse
56
+ end
57
+
58
+ def parser
59
+ Rubotium::Adb::Parsers::Procrank.new(data_struct)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,65 @@
1
+ require_relative 'data_point'
2
+
3
+ module Rubotium
4
+ module Memory
5
+ class Monitor
6
+ def initialize(device, opts = {})
7
+ @device = device
8
+ @process_name = opts.delete(:process_name) || nil
9
+ @interval = opts.delete(:interval) || 0
10
+ end
11
+
12
+ def start
13
+ @should_pool_memory = !!process_name
14
+ start_probing_memory
15
+ end
16
+
17
+ def stop_and_save(io)
18
+ stop
19
+ io.write("[#{data_points.join(',')}]")
20
+ reset
21
+ end
22
+
23
+ def stop
24
+ @should_pool_memory = false
25
+ start_probing_memory.join
26
+ Rubotium.logger.debug("Memory collector stopped")
27
+ end
28
+
29
+ def data_points
30
+ data.clone
31
+ end
32
+
33
+ def reset
34
+ @data = []
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :device, :interval, :process_name
40
+ attr_accessor :should_pool_memory
41
+
42
+ def start_probing_memory
43
+ @pooling_thread ||= Thread.new do
44
+ while @should_pool_memory do
45
+ data.push(DataPoint.new(time, probe_memory))
46
+ sleep interval
47
+ end
48
+ end
49
+ end
50
+
51
+ def data
52
+ @data ||= []
53
+ end
54
+
55
+ def time
56
+ Time.at(Time.now).strftime("%H:%M:%S")
57
+ end
58
+
59
+ def probe_memory
60
+ device.shell(Rubotium::Adb::Commands::MemoryCommand.new(process_name).executable_command)
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'memory/data_point'
2
+ require_relative 'memory/monitor'
3
+
4
+ module Rubotium
5
+ module Memory
6
+
7
+ end
8
+ end
@@ -1,9 +1,8 @@
1
- require 'android_apk'
2
-
3
1
  module Rubotium
4
2
  class Package
5
- def initialize(package_path)
3
+ def initialize(package_path, test_runner = '')
6
4
  @package_path = package_path
5
+ @test_runner = test_runner || 'android.test.InstrumentationTestRunner'
7
6
  end
8
7
 
9
8
  def valid?
@@ -26,11 +25,15 @@ module Rubotium
26
25
  analyzed_package.version_code
27
26
  end
28
27
 
28
+ def test_runner
29
+ @test_runner
30
+ end
31
+
29
32
  private
30
33
  attr_reader :package_path
31
34
 
32
35
  def analyzed_package
33
- @analyzed_package ||= AndroidApk.analyze(package_path)
36
+ @analyzed_package ||= Rubotium::Apk::AndroidApk.new(package_path)
34
37
  end
35
38
  end
36
39
  end
@@ -0,0 +1,13 @@
1
+ module Rubotium
2
+ class RunnableTest
3
+ attr_reader :package_name, :test_name
4
+ def initialize(package_name, test_name)
5
+ @package_name = package_name
6
+ @test_name = test_name
7
+ end
8
+
9
+ def name
10
+ "#{package_name}##{test_name}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,32 @@
1
+ module Rubotium
2
+ class TestCasesReader
3
+ def initialize(device, test_package, options = {})
4
+ @device = device
5
+ @test_package = test_package
6
+ @annotation = options.delete(:annotation)
7
+ end
8
+
9
+ def read_tests
10
+ result = device.shell(instrument_command)
11
+ Rubotium::Adb::Parsers::TestResultsParser.new(result).test_results.map{|test|
12
+ create_runnable_test(test)
13
+ }
14
+ end
15
+
16
+ def create_runnable_test(test)
17
+ Rubotium::RunnableTest.new(test.class_name, test.test_name)
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :device, :test_package, :annotation
23
+
24
+ def instrument_command
25
+ "am instrument -w -r -e log true #{with_annotation} #{test_package.name}/#{test_package.test_runner}"
26
+ end
27
+
28
+ def with_annotation
29
+ annotation ? "-e annotation #{annotation}" : ''
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,52 @@
1
+ module Rubotium
2
+ class TestResult
3
+
4
+ attr_reader :stack_trace, :time, :error_message, :status, :test_name, :class_name, :device
5
+
6
+ def initialize(test_results_parser, runnable_test)
7
+ @parsed_result = test_results_parser
8
+ @class_name = runnable_test.package_name
9
+ @test_name = runnable_test.test_name
10
+ end
11
+
12
+ def stack_trace
13
+ if(failed_run?)
14
+ parsed_result.message
15
+ else
16
+ test_case.stack_trace
17
+ end
18
+ end
19
+
20
+ def failed?
21
+ failed_run? || test_case.failed?
22
+ end
23
+
24
+ def passed?
25
+ not failed_run? and test_case.passed?
26
+ end
27
+
28
+ def errored?
29
+ failed_run? || test_case.errored?
30
+ end
31
+
32
+ def error_message
33
+ stack_trace
34
+ end
35
+
36
+ def time
37
+ parsed_result.time
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :parsed_result
43
+
44
+ def failed_run?
45
+ parsed_result.failed?
46
+ end
47
+
48
+ def test_case
49
+ parsed_result.test_results.first
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,18 @@
1
+ module Rubotium
2
+ class TestResults
3
+ def initialize(results)
4
+ @results = results
5
+ end
6
+
7
+ def group_by_package
8
+ json = {}
9
+ results.each{|result|
10
+ json[result.class_name] = [] unless json[result.class_name]
11
+ json[result.class_name].push(result)
12
+ }
13
+ json
14
+ end
15
+
16
+ attr_reader :results
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ module Rubotium
2
+ module TestRunners
3
+ class InstrumentationTestRunner
4
+ def initialize(device, test_package, options = {})
5
+ @device = device
6
+ @test_package = test_package
7
+ @annotations = options.delete(:annotation)
8
+ end
9
+
10
+ def run_test(runnable_test)
11
+ result = device.shell(instrument_command(runnable_test))
12
+ Rubotium::TestResult.new(Rubotium::Adb::Parsers::TestResultsParser.new(result), runnable_test)
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :device, :test_package
18
+
19
+ def instrument_command (runnable_test)
20
+ "am instrument -w -r -e class #{runnable_test.name} #{test_package.name}/#{test_package.test_runner}"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,80 @@
1
+ require 'parallel'
2
+ module Rubotium
3
+ class TestsRunner
4
+ def initialize(devices, tests, tests_package, options = {})
5
+ @devices = devices
6
+ @tests = tests
7
+ @tests_package = tests_package
8
+ @tests_runner = tests_package.test_runner
9
+ @options = options
10
+ @test_number = 0
11
+ end
12
+
13
+ def tests_count
14
+ tests.count
15
+ end
16
+
17
+ def tests_to_execute
18
+ tests_queue.count
19
+ end
20
+
21
+ def tests_results
22
+ Rubotium::TestResults.new(results)
23
+ end
24
+
25
+ def run_tests
26
+ fill_tests_queue
27
+ Parallel.each(devices, :in_threads => devices.count) { |device|
28
+ until tests_queue.empty?
29
+ test = next_test
30
+ memory_monitor = Rubotium::Memory::Monitor.new(device, { :interval => 1 })
31
+ memory_monitor.start
32
+ display_test_progress
33
+ result = test_runner(device).run_test(test)
34
+ if(result.failed? || result.errored?)
35
+ result = test_runner(device).run_test(test)
36
+ end
37
+ results.push(result)
38
+ memory_monitor.stop_and_save(memory_results_file(test))
39
+ end
40
+ }
41
+ end
42
+
43
+ def display_test_progress
44
+ @test_number += 1
45
+ puts "Running test: #{@test_number} out of #{tests_count}"
46
+ end
47
+
48
+ private
49
+
50
+ attr_reader :devices, :tests_package, :tests
51
+
52
+ def memory_results_file(test)
53
+ File.open("results/memory_logs/#{test.name}.json", 'w+')
54
+ end
55
+
56
+ def results
57
+ @results ||= []
58
+ end
59
+
60
+ def next_test
61
+ tests_queue.pop
62
+ end
63
+
64
+ def fill_tests_queue
65
+ tests.map { |test| tests_queue.push(test) }
66
+ end
67
+
68
+ def tests_queue
69
+ @queue ||= Queue.new
70
+ end
71
+
72
+ def test_runner(device)
73
+ Rubotium::TestRunners::InstrumentationTestRunner.new(device, tests_package)
74
+ end
75
+
76
+ def retrying_test_runner
77
+ Rubotium::TestRunners::RetryingTestRunner.new(device, test)
78
+ end
79
+ end
80
+ end
@@ -1,3 +1,3 @@
1
1
  module Rubotium
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.7"
3
3
  end