rubotium 0.0.4 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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