rubotium 0.0.7 → 0.0.17
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.
- checksums.yaml +4 -4
- data/.travis.yml +11 -0
- data/README.md +4 -0
- data/bin/rubotium +7 -1
- data/lib/rubotium/adb/commands/command.rb +35 -3
- data/lib/rubotium/adb/commands/logcat_command.rb +24 -0
- data/lib/rubotium/adb/commands/push_command.rb +24 -0
- data/lib/rubotium/adb/commands.rb +2 -0
- data/lib/rubotium/adb/parsers/test_results_parser.rb +3 -1
- data/lib/rubotium/apk/aapt.rb +9 -0
- data/lib/rubotium/apk/android_apk.rb +10 -6
- data/lib/rubotium/apk.rb +1 -0
- data/lib/rubotium/device.rb +13 -1
- data/lib/rubotium/devices.rb +15 -3
- data/lib/rubotium/formatters/html_formatter.css +97 -0
- data/lib/rubotium/formatters/html_formatter.rb +181 -0
- data/lib/rubotium/screencast/recorder.rb +43 -0
- data/lib/rubotium/screencast.rb +1 -0
- data/lib/rubotium/test_result.rb +4 -0
- data/lib/rubotium/test_results.rb +107 -0
- data/lib/rubotium/test_runners/instrumentation_test_runner.rb +12 -2
- data/lib/rubotium/tests_runner.rb +13 -5
- data/lib/rubotium/version.rb +1 -1
- data/lib/rubotium.rb +24 -7
- data/rubotium.gemspec +2 -3
- data/spec/lib/rubotium/adb/adb_result_parser_spec.rb +4 -4
- data/spec/lib/rubotium/adb/commands/command_spec.rb +40 -0
- data/spec/lib/rubotium/adb/parsers/test_results_parser_spec.rb +5 -5
- data/spec/lib/rubotium/apk/android_apk_spec.rb +25 -4
- data/spec/lib/rubotium/device_spec.rb +22 -7
- data/spec/lib/rubotium/tests_runner_spec.rb +1 -0
- data/test.rb +39 -8
- metadata +22 -40
@@ -13,6 +13,113 @@ module Rubotium
|
|
13
13
|
json
|
14
14
|
end
|
15
15
|
|
16
|
+
def group_by_failures
|
17
|
+
TestSuites.new(
|
18
|
+
group_by_package.map{|name, test_results|
|
19
|
+
TestSuite.new(name, test_results)
|
20
|
+
}.sort_by{|test_suite|
|
21
|
+
test_suite.state
|
22
|
+
})
|
23
|
+
end
|
24
|
+
|
16
25
|
attr_reader :results
|
17
26
|
end
|
27
|
+
|
28
|
+
class TestSuites
|
29
|
+
def initialize(test_suites)
|
30
|
+
@test_suites = test_suites
|
31
|
+
end
|
32
|
+
|
33
|
+
def time
|
34
|
+
test_suites.map(&:time).inject(&:+).to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def each
|
38
|
+
test_suites.each{|suite|
|
39
|
+
yield(suite)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def total
|
44
|
+
sum_of(:tests_count)
|
45
|
+
end
|
46
|
+
|
47
|
+
def passed
|
48
|
+
sum_of(:passed_count)
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
def errored
|
53
|
+
sum_of(:error_count)
|
54
|
+
end
|
55
|
+
|
56
|
+
def failed
|
57
|
+
sum_of(:failures_count)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
attr_reader :test_suites
|
62
|
+
|
63
|
+
def sum_of(value)
|
64
|
+
select_suites_with(value).inject(&:+)
|
65
|
+
end
|
66
|
+
|
67
|
+
def select_suites_with(value)
|
68
|
+
test_suites.map(&value).compact
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class TestSuite
|
73
|
+
attr_reader :name
|
74
|
+
|
75
|
+
def initialize(name, test_cases)
|
76
|
+
@name = name
|
77
|
+
@test_cases = test_cases
|
78
|
+
end
|
79
|
+
|
80
|
+
def failures_count
|
81
|
+
@failures ||= count_by(:failed?).to_i
|
82
|
+
end
|
83
|
+
|
84
|
+
def error_count
|
85
|
+
@errors ||= count_by(:errored?).to_i
|
86
|
+
end
|
87
|
+
|
88
|
+
def passed_count
|
89
|
+
@passed_count ||= count_by(:passed?).to_i
|
90
|
+
end
|
91
|
+
|
92
|
+
def state
|
93
|
+
return (failures_count + error_count > 0) ? 'failed' : 'passed'
|
94
|
+
end
|
95
|
+
|
96
|
+
def time
|
97
|
+
@time ||= sum_of(:time)
|
98
|
+
end
|
99
|
+
|
100
|
+
def tests_count
|
101
|
+
@tests_count ||= test_cases.count
|
102
|
+
end
|
103
|
+
|
104
|
+
def each_test
|
105
|
+
test_cases.each{|test_case|
|
106
|
+
yield(test_case)
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
attr_reader :test_cases
|
112
|
+
|
113
|
+
def count_by(value)
|
114
|
+
test_cases
|
115
|
+
.select(&value)
|
116
|
+
.count
|
117
|
+
end
|
118
|
+
|
119
|
+
def sum_of(value_to_sum)
|
120
|
+
test_cases
|
121
|
+
.map(&value_to_sum)
|
122
|
+
.inject(&:+)
|
123
|
+
end
|
124
|
+
end
|
18
125
|
end
|
@@ -8,14 +8,24 @@ module Rubotium
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def run_test(runnable_test)
|
11
|
-
|
12
|
-
|
11
|
+
device.clean_logcat
|
12
|
+
result = execute(instrument_command(runnable_test))
|
13
|
+
File.open("results/logs/#{runnable_test.name}.log", 'w+') do |file|
|
14
|
+
file.write device.logcat
|
15
|
+
end
|
16
|
+
Rubotium::TestResult.new(result , runnable_test)
|
13
17
|
end
|
14
18
|
|
15
19
|
private
|
16
20
|
|
17
21
|
attr_reader :device, :test_package
|
18
22
|
|
23
|
+
def execute(command)
|
24
|
+
Rubotium::Adb::Parsers::TestResultsParser.new(device.shell(command))
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
19
29
|
def instrument_command (runnable_test)
|
20
30
|
"am instrument -w -r -e class #{runnable_test.name} #{test_package.name}/#{test_package.test_runner}"
|
21
31
|
end
|
@@ -7,6 +7,7 @@ module Rubotium
|
|
7
7
|
@tests_package = tests_package
|
8
8
|
@tests_runner = tests_package.test_runner
|
9
9
|
@options = options
|
10
|
+
@clear = options[:clear]
|
10
11
|
@test_number = 0
|
11
12
|
end
|
12
13
|
|
@@ -15,7 +16,7 @@ module Rubotium
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def tests_to_execute
|
18
|
-
|
19
|
+
tests_queue.count
|
19
20
|
end
|
20
21
|
|
21
22
|
def tests_results
|
@@ -25,16 +26,19 @@ module Rubotium
|
|
25
26
|
def run_tests
|
26
27
|
fill_tests_queue
|
27
28
|
Parallel.each(devices, :in_threads => devices.count) { |device|
|
28
|
-
|
29
|
-
test = next_test
|
29
|
+
while(test = next_test)
|
30
30
|
memory_monitor = Rubotium::Memory::Monitor.new(device, { :interval => 1 })
|
31
31
|
memory_monitor.start
|
32
32
|
display_test_progress
|
33
33
|
result = test_runner(device).run_test(test)
|
34
34
|
if(result.failed? || result.errored?)
|
35
|
+
screencast = Rubotium::Recorder.new(device.serial)
|
36
|
+
screencast.start(test.name)
|
35
37
|
result = test_runner(device).run_test(test)
|
38
|
+
screencast.stop
|
36
39
|
end
|
37
40
|
results.push(result)
|
41
|
+
clear_if_required(device)
|
38
42
|
memory_monitor.stop_and_save(memory_results_file(test))
|
39
43
|
end
|
40
44
|
}
|
@@ -47,7 +51,7 @@ module Rubotium
|
|
47
51
|
|
48
52
|
private
|
49
53
|
|
50
|
-
attr_reader :devices, :tests_package, :tests
|
54
|
+
attr_reader :devices, :tests_package, :tests, :clear
|
51
55
|
|
52
56
|
def memory_results_file(test)
|
53
57
|
File.open("results/memory_logs/#{test.name}.json", 'w+')
|
@@ -58,7 +62,7 @@ module Rubotium
|
|
58
62
|
end
|
59
63
|
|
60
64
|
def next_test
|
61
|
-
tests_queue.pop
|
65
|
+
tests_queue.pop(true) rescue nil
|
62
66
|
end
|
63
67
|
|
64
68
|
def fill_tests_queue
|
@@ -69,6 +73,10 @@ module Rubotium
|
|
69
73
|
@queue ||= Queue.new
|
70
74
|
end
|
71
75
|
|
76
|
+
def clear_if_required(device)
|
77
|
+
device.shell("pm clear #{clear}") if clear
|
78
|
+
end
|
79
|
+
|
72
80
|
def test_runner(device)
|
73
81
|
Rubotium::TestRunners::InstrumentationTestRunner.new(device, tests_package)
|
74
82
|
end
|
data/lib/rubotium/version.rb
CHANGED
data/lib/rubotium.rb
CHANGED
@@ -6,6 +6,8 @@ require 'rubotium/device'
|
|
6
6
|
require 'rubotium/devices'
|
7
7
|
require 'rubotium/tests_runner'
|
8
8
|
require 'rubotium/formatters/junit_formatter'
|
9
|
+
require 'rubotium/screencast'
|
10
|
+
require 'rubotium/formatters/html_formatter'
|
9
11
|
require 'rubotium/runnable_test'
|
10
12
|
require 'rubotium/package'
|
11
13
|
require 'rubotium/memory'
|
@@ -38,32 +40,43 @@ module Rubotium
|
|
38
40
|
raise RuntimeError, "Empty configuration" if opts.empty?
|
39
41
|
raise Errno::ENOENT, "Tests apk does not exist" if !File.exist?(opts[:tests_apk_path])
|
40
42
|
raise Errno::ENOENT, "App apk does not exist" if !File.exist?(opts[:app_apk_path])
|
43
|
+
if !opts[:helper_apk_path].nil?
|
44
|
+
raise Errno::ENOENT, "Helper apk does not exist" if !File.exist?(opts[:helper_apk_path])
|
45
|
+
end
|
41
46
|
|
42
47
|
logger.level = Logger::INFO
|
43
48
|
|
44
49
|
startTime = Time.now
|
45
|
-
FileUtils.mkdir_p('results')
|
50
|
+
FileUtils.mkdir_p('results/logs')
|
46
51
|
FileUtils.mkdir_p('results/memory_logs')
|
52
|
+
FileUtils.mkdir_p('results/screencasts')
|
47
53
|
FileUtils.mkdir_p('screens')
|
48
54
|
FileUtils.mkdir_p('logs')
|
49
55
|
|
50
56
|
application_package = Rubotium::Package.new(opts[:app_apk_path])
|
51
57
|
tests_package = Rubotium::Package.new(opts[:tests_apk_path], opts[:runner])
|
58
|
+
helper_package = Rubotium::Package.new(opts[:helper_apk_path])
|
52
59
|
|
53
|
-
devices = Devices.new(:name => opts[:device_matcher]).all
|
60
|
+
devices = Devices.new(:name => opts[:device_matcher], :sdk => opts[:device_sdk], :serial=> opts[:serial]).all
|
54
61
|
|
55
62
|
devices = Parallel.map(devices, :in_threads => devices.count) {|device|
|
56
63
|
device.uninstall application_package.name
|
57
64
|
device.install application_package.path
|
58
65
|
device.uninstall tests_package.name
|
59
66
|
device.install tests_package.path
|
67
|
+
if !opts[:helper_apk_path].nil?
|
68
|
+
device.uninstall helper_package.name
|
69
|
+
device.install helper_package.path
|
70
|
+
end
|
71
|
+
device.shell('mkdir /sdcard/screencasts')
|
60
72
|
device
|
61
73
|
}
|
62
74
|
|
63
|
-
test_suites = Rubotium::TestCasesReader.new(devices.first, tests_package).read_tests
|
75
|
+
test_suites = Rubotium::TestCasesReader.new(devices.first, tests_package, { :annotation=>opts[:annotation]}).read_tests
|
76
|
+
|
64
77
|
puts "There are #{test_suites.count} tests to run"
|
65
78
|
|
66
|
-
runner = Rubotium::TestsRunner.new(devices, test_suites, tests_package, {:
|
79
|
+
runner = Rubotium::TestsRunner.new(devices, test_suites, tests_package, {annotation: opts[:annotation], clear: application_package.name})
|
67
80
|
runner.run_tests
|
68
81
|
|
69
82
|
FileUtils.mkdir_p(['screens', 'logs'])
|
@@ -71,16 +84,20 @@ module Rubotium
|
|
71
84
|
devices.each{|device|
|
72
85
|
device.pull('/sdcard/Robotium-Screenshots')
|
73
86
|
device.pull('/sdcard/RobotiumLogs')
|
74
|
-
device.
|
75
|
-
device.shell('rm -R /sdcard/
|
87
|
+
device.pull('/sdcard/screencasts')
|
88
|
+
device.shell('rm -R /sdcard/Robotium-Screenshots')
|
89
|
+
device.shell('rm -R /sdcard/RobotiumLogs')
|
90
|
+
device.shell('rm -R /sdcard/screencasts')
|
91
|
+
device.shell('reboot')
|
76
92
|
}
|
77
93
|
FileUtils.mv(Dir.glob('*.jpg'), 'screens')
|
78
94
|
FileUtils.mv(Dir.glob('*.log'), 'logs')
|
95
|
+
FileUtils.mv(Dir.glob('*.mp4'), 'results/screencasts')
|
79
96
|
|
80
97
|
puts "Tests took: #{Time.at(Time.now-startTime).utc.strftime("%H:%M:%S")}"
|
81
98
|
|
82
99
|
Formatters::JunitFormatter.new(runner.tests_results.group_by_package, opts[:report])
|
83
|
-
|
100
|
+
Formatters::HtmlFormatter.new(runner.tests_results.group_by_failures, 'results/index.html')
|
84
101
|
end
|
85
102
|
|
86
103
|
def logger
|
data/rubotium.gemspec
CHANGED
@@ -21,12 +21,11 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.5"
|
22
22
|
spec.add_development_dependency "simplecov", "0.8.2"
|
23
23
|
spec.add_development_dependency "coveralls", "0.7.0"
|
24
|
-
spec.add_development_dependency "rspec", "2.
|
25
|
-
|
24
|
+
spec.add_development_dependency "rspec", "3.2.0"
|
25
|
+
|
26
26
|
spec.add_development_dependency "rake"
|
27
27
|
|
28
28
|
spec.add_dependency 'builder', '3.2.2'
|
29
29
|
spec.add_dependency 'trollop', '2.0'
|
30
30
|
spec.add_dependency 'parallel', '0.9.2'
|
31
|
-
spec.add_dependency 'dex2jar', '0.0.6'
|
32
31
|
end
|
@@ -135,13 +135,13 @@ describe Rubotium::Adb::TestResultParser do
|
|
135
135
|
let(:parsed_result) { parser.new(Fixtures::Adb.gingerbread_exception, package, "") }
|
136
136
|
|
137
137
|
it 'should behave as error case' do
|
138
|
-
|
139
|
-
|
138
|
+
|
139
|
+
|
140
140
|
end
|
141
141
|
|
142
142
|
it 'should know the error reason' do
|
143
|
-
|
144
|
-
|
143
|
+
|
144
|
+
|
145
145
|
end
|
146
146
|
end
|
147
147
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rubotium::Adb::Commands::Command do
|
4
|
+
let(:subject) { described_class.new(serial) }
|
5
|
+
let(:adb_command) { 'the command' }
|
6
|
+
let(:result) { 'result' }
|
7
|
+
let(:command_to_run) { double(Object) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
expect(Rubotium::CMD).to receive(:run_command).with(shell_command) { result }
|
11
|
+
expect(command_to_run).to receive(:executable_command).at_least(:once) { adb_command }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when nil serial is defined' do
|
15
|
+
let(:serial) { nil }
|
16
|
+
let(:shell_command) { "adb #{adb_command}" }
|
17
|
+
|
18
|
+
it 'executes the command without a serial' do
|
19
|
+
expect(subject.execute(command_to_run)).to eq result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when "" serial is defined' do
|
24
|
+
let(:serial) { '' }
|
25
|
+
let(:shell_command) { "adb #{adb_command}" }
|
26
|
+
|
27
|
+
it 'executes the command without a serial' do
|
28
|
+
expect(subject.execute(command_to_run)).to eq result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when a real serial is defined' do
|
33
|
+
let(:serial) { '01234567' }
|
34
|
+
let(:shell_command) { "adb -s #{serial} #{adb_command}" }
|
35
|
+
|
36
|
+
it 'executes the command with a serial' do
|
37
|
+
expect(subject.execute(command_to_run)).to eq result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -13,7 +13,7 @@ describe Rubotium::Adb::Parsers::TestResultsParser do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'should return time' do
|
16
|
-
expect(parser.time).to eql(
|
16
|
+
expect(parser.time).to eql(0.142)
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'should not have error message' do
|
@@ -33,7 +33,7 @@ describe Rubotium::Adb::Parsers::TestResultsParser do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'should return time' do
|
36
|
-
expect(parser.time).to eql(
|
36
|
+
expect(parser.time).to eql(16.79)
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'should not have error message' do
|
@@ -53,7 +53,7 @@ describe Rubotium::Adb::Parsers::TestResultsParser do
|
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'should return time = 0' do
|
56
|
-
expect(parser.time).to eql(
|
56
|
+
expect(parser.time).to eql(0.0)
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'should return error message' do
|
@@ -75,7 +75,7 @@ describe Rubotium::Adb::Parsers::TestResultsParser do
|
|
75
75
|
end
|
76
76
|
|
77
77
|
it 'should return time = 0' do
|
78
|
-
expect(parser.time).to eql(
|
78
|
+
expect(parser.time).to eql(0.0)
|
79
79
|
end
|
80
80
|
|
81
81
|
it 'should return error message' do
|
@@ -97,7 +97,7 @@ describe Rubotium::Adb::Parsers::TestResultsParser do
|
|
97
97
|
end
|
98
98
|
|
99
99
|
it 'should return time = 0' do
|
100
|
-
expect(parser.time).to eql(
|
100
|
+
expect(parser.time).to eql(0.0)
|
101
101
|
end
|
102
102
|
|
103
103
|
it 'should return error message' do
|
@@ -4,14 +4,16 @@ require 'spec_helper'
|
|
4
4
|
require "pp"
|
5
5
|
|
6
6
|
describe Rubotium::Apk::AndroidApk do
|
7
|
+
let(:aapt) {double(Rubotium::Apk::Aapt)}
|
7
8
|
|
8
9
|
sample_file_path = File.dirname(__FILE__) + "/mock/sample.apk"
|
9
10
|
sample2_file_path = File.dirname(__FILE__) + "/mock/BarcodeScanner4.2.apk"
|
10
11
|
icon_not_set_file_path = File.dirname(__FILE__) + "/mock/UECExpress.apk"
|
11
12
|
dummy_file_path = File.dirname(__FILE__) + "/mock/dummy.apk"
|
12
13
|
|
14
|
+
|
13
15
|
context 'with non existing apk' do
|
14
|
-
let(:apk) { described_class.new('dummy.apk') }
|
16
|
+
let(:apk) { described_class.new(aapt, 'dummy.apk') }
|
15
17
|
|
16
18
|
it "should raise exception" do
|
17
19
|
expect{apk}.to raise_exception(Errno::ENOENT)
|
@@ -19,17 +21,36 @@ describe Rubotium::Apk::AndroidApk do
|
|
19
21
|
end
|
20
22
|
|
21
23
|
context 'with not readable apk' do
|
22
|
-
let(:apk) { described_class.new(dummy_file_path) }
|
24
|
+
let(:apk) { described_class.new(aapt, dummy_file_path) }
|
23
25
|
|
24
26
|
it 'should raise exception' do
|
25
|
-
expect
|
27
|
+
expect(aapt).to receive(:dump).and_return "W/zipro (77199): Error opening archive spec/lib/rubotium/apk/mock/dummy.apk: Invalid file
|
28
|
+
ERROR: dump failed because assets could not be loaded"
|
29
|
+
expect{apk.package_name}.to raise_error(RuntimeError)
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
29
33
|
context 'with valid apk file' do
|
30
|
-
let(:apk) { described_class.new(sample_file_path) }
|
34
|
+
let(:apk) { described_class.new(aapt, sample_file_path) }
|
31
35
|
|
32
36
|
it 'should read package_name' do
|
37
|
+
expect(aapt).to receive(:dump).and_return "package: name='com.example.sample' versionCode='1' versionName='1.0' platformBuildVersionName=''
|
38
|
+
sdkVersion:'7'
|
39
|
+
targetSdkVersion:'15'
|
40
|
+
application-label:'sample'
|
41
|
+
application-label-ja:'g'
|
42
|
+
application-icon-160:'res/drawable-mdpi/ic_launcher.png'
|
43
|
+
application-icon-240:'res/drawable-hdpi/ic_launcher.png'
|
44
|
+
application-icon-320:'res/drawable-xhdpi/ic_launcher.png'
|
45
|
+
application: label='sample' icon='res/drawable-mdpi/ic_launcher.png'
|
46
|
+
application-debuggable
|
47
|
+
feature-group: label=''
|
48
|
+
uses-feature: name='android.hardware.touchscreen'
|
49
|
+
uses-implied-feature: name='android.hardware.touchscreen' reason='default feature for all apps'
|
50
|
+
supports-screens: 'small' 'normal' 'large' 'xlarge'
|
51
|
+
supports-any-density: 'true'
|
52
|
+
locales: '--_--' 'ja'
|
53
|
+
densities: '160' '240' '320'"
|
33
54
|
expect(apk.package_name).to eql 'com.example.sample'
|
34
55
|
end
|
35
56
|
|
@@ -1,12 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
let(:device) { described_class.new('12345') }
|
5
|
-
let(:command) { double(Rubotium::Adb::Commands::Command)}
|
6
|
-
before do
|
7
|
-
device.stub(:adb_command).and_return(command)
|
8
|
-
end
|
9
|
-
|
3
|
+
shared_examples 'a Rubotium::Device' do
|
10
4
|
it 'installs package on device' do
|
11
5
|
path_to_apk = 'path/to/apk'
|
12
6
|
expect(command).to receive(:install).with(path_to_apk)
|
@@ -36,3 +30,24 @@ describe Rubotium::Device do
|
|
36
30
|
device.shell(getprop)
|
37
31
|
end
|
38
32
|
end
|
33
|
+
|
34
|
+
describe Rubotium::Device do
|
35
|
+
let(:device) { described_class.new(serial) }
|
36
|
+
let(:command) { double(Rubotium::Adb::Commands::Command)}
|
37
|
+
|
38
|
+
before do
|
39
|
+
device.stub(:adb_command).and_return(command)
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when a serial is provided' do
|
43
|
+
let(:serial) { '12345' }
|
44
|
+
|
45
|
+
it_behaves_like 'a Rubotium::Device'
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when no serial is provided' do
|
49
|
+
let(:serial) { nil }
|
50
|
+
|
51
|
+
it_behaves_like 'a Rubotium::Device'
|
52
|
+
end
|
53
|
+
end
|
@@ -21,6 +21,7 @@ describe Rubotium::TestsRunner do
|
|
21
21
|
|
22
22
|
context 'when running tests' do
|
23
23
|
before do
|
24
|
+
runner.stub(:memory_results_file).and_return Tempfile.new('memory_monitor')
|
24
25
|
device1.stub(:shell)
|
25
26
|
device2.stub(:shell)
|
26
27
|
runner.stub(:test_runner).and_return(test_runner)
|
data/test.rb
CHANGED
@@ -1,11 +1,42 @@
|
|
1
|
-
require
|
1
|
+
require "observer"
|
2
2
|
|
3
|
-
|
3
|
+
class Ticker ### Periodically fetch a stock price.
|
4
|
+
include Observable
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
Parallel.map(b, :in_processes => 10){|executor|
|
8
|
-
until(q.empty?)
|
9
|
-
puts q.pop
|
6
|
+
def test_changed(msg)
|
7
|
+
changed
|
10
8
|
end
|
11
|
-
|
9
|
+
|
10
|
+
def test_notify(msg)
|
11
|
+
notify_observers(msg)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Observer
|
16
|
+
def initialize(ticker, name)
|
17
|
+
@ticker = ticker
|
18
|
+
@name = name
|
19
|
+
ticker.add_observer(self)
|
20
|
+
end
|
21
|
+
|
22
|
+
def unsubscribe
|
23
|
+
@ticker.delete_observer(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
def update(*args)
|
27
|
+
puts @name
|
28
|
+
p *args
|
29
|
+
end
|
30
|
+
|
31
|
+
def message_missing(*args)
|
32
|
+
puts @name
|
33
|
+
p args
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
ticker = Ticker.new()
|
40
|
+
observer = Observer.new(ticker, "observer1")
|
41
|
+
|
42
|
+
|