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