parallel_calabash 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +29 -4
- data/bin/parallel_calabash +4 -0
- data/lib/parallel_calabash.rb +4 -2
- data/lib/parallel_calabash/feature_grouper.rb +38 -2
- data/lib/parallel_calabash/result_formatter.rb +2 -2
- data/lib/parallel_calabash/version.rb +1 -1
- data/spec/lib/parallel_calabash/feature_grouper_spec.rb +89 -0
- data/spec/lib/parallel_calabash/runner_spec.rb +25 -0
- data/spec/test_data/features/aaa.feature +43 -0
- data/spec/test_data/features/bbb.feature +19 -0
- data/spec/test_data/features/ccc.feature +14 -0
- data/spec/test_data/features/ddd.feature +10 -0
- data/spec/test_data/features/eee.feature +7 -0
- data/spec/test_data/features/fff.feature +0 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3cc74523250c60f0398e05a6c48f836440f25a6
|
4
|
+
data.tar.gz: 83f6df11b48c1f1bd8a005aed355f3eaf9a91cd3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 381b18478ffaa24329d6bbeb26834e479cbe1270606a1a401416562b84f61ec8d6b0eb229fbd4281927a7bbad7901d91057705fc7712d5da2fa277b3b6da096d
|
7
|
+
data.tar.gz: 95cbc60ccee529eb91c750604081c1c9ea99bb1bd8b1f57df8261dcc3fee872805535dea1518b236d90a1d0f4898b2c09c5da30200df292db6c2cac6eebdc8d3
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
-
#
|
1
|
+
# calabash parallel execution
|
2
2
|
|
3
|
-
|
3
|
+
## NOTE: This is not yet tested on windows.
|
4
|
+
|
5
|
+
|
6
|
+
Run calabash-android tests in parallel on multiple connected devices. This is inspired by parallel_tests https://rubygems.org/gems/parallel_tests
|
7
|
+
|
8
|
+
eg. bundle exec parallel_calabash -a my.apk -o'--format pretty' features/ --serialize-stdout
|
4
9
|
|
5
10
|
## Installation
|
6
11
|
|
@@ -12,7 +17,7 @@ gem 'parallel_calabash'
|
|
12
17
|
|
13
18
|
And then execute:
|
14
19
|
|
15
|
-
$ bundle
|
20
|
+
$ bundle install
|
16
21
|
|
17
22
|
Or install it yourself as:
|
18
23
|
|
@@ -20,7 +25,27 @@ Or install it yourself as:
|
|
20
25
|
|
21
26
|
## Usage
|
22
27
|
|
23
|
-
|
28
|
+
Usage: parallel_calabash [options]
|
29
|
+
|
30
|
+
Example: parallel_calabash -a my.apk -o 'cucumber_opts_like_tags_profile_etc_here' features/
|
31
|
+
|
32
|
+
|
33
|
+
-h, --help Show this message
|
34
|
+
-v, --version Show version
|
35
|
+
-a, --apk apk_path apk file path
|
36
|
+
-o, --cucumber_opts '[OPTIONS]' execute with those cucumber options
|
37
|
+
|
38
|
+
-d distribution_tag, divide features into groups as per occurrence of given tag
|
39
|
+
--distribution-tag
|
40
|
+
--serialize-stdout Serialize stdout output show output only after process completion
|
41
|
+
|
42
|
+
## REPROTING
|
43
|
+
|
44
|
+
use ENV['TEST_PROCESS_NUMBER'] environment variable in your ruby scripts to find out the process number. you can use this for reporting purpose.
|
45
|
+
|
46
|
+
eg. modify default profile in cucumber.yml as below to get different report from different process
|
47
|
+
|
48
|
+
default: --format html --out reports/Automation_report_<%= ENV['TEST_PROCESS_NUMBER'] %>.html --format pretty
|
24
49
|
|
25
50
|
## Contributing
|
26
51
|
|
data/bin/parallel_calabash
CHANGED
@@ -25,6 +25,10 @@ def parse_arguments(arguments)
|
|
25
25
|
options[:apk_path] = apk_path
|
26
26
|
end
|
27
27
|
|
28
|
+
opts.on("-d", "--distribution-tag distribution_tag", "divide features into groups as per occurrence of given tag") do |distribution_tag|
|
29
|
+
options[:distribution_tag] = distribution_tag
|
30
|
+
end
|
31
|
+
|
28
32
|
opts.on("-o", "--cucumber_opts '[OPTIONS]'", "execute with those cucumber options") do |cucumber_opts|
|
29
33
|
options[:cucumber_options] = cucumber_opts
|
30
34
|
end
|
data/lib/parallel_calabash.rb
CHANGED
@@ -26,7 +26,7 @@ module ParallelCalabash
|
|
26
26
|
|
27
27
|
test_results = nil
|
28
28
|
report_time_taken do
|
29
|
-
groups = FeatureGrouper.feature_groups(options[:feature_folder], number_of_processes)
|
29
|
+
groups = FeatureGrouper.feature_groups(options[:feature_folder], number_of_processes,options[:distribution_tag])
|
30
30
|
puts "#{number_of_processes} processes for #{groups.flatten.size} features"
|
31
31
|
test_results = Parallel.map(groups, :in_threads => groups.size) do |group|
|
32
32
|
Runner.run_tests(group, groups.index(group), options)
|
@@ -44,7 +44,9 @@ module ParallelCalabash
|
|
44
44
|
def report_time_taken
|
45
45
|
start = Time.now
|
46
46
|
yield
|
47
|
-
|
47
|
+
time_in_sec = Time.now - start
|
48
|
+
mm, ss = time_in_sec.divmod(60)
|
49
|
+
puts "\nTook #{mm} Minutes, #{ss.round(2)} Seconds"
|
48
50
|
end
|
49
51
|
|
50
52
|
end
|
@@ -3,7 +3,11 @@ module ParallelCalabash
|
|
3
3
|
|
4
4
|
class << self
|
5
5
|
|
6
|
-
def feature_groups(feature_folder, group_size)
|
6
|
+
def feature_groups(feature_folder, group_size,weighing_factor = nil)
|
7
|
+
weighing_factor.nil? ? feature_groups_by_feature_files(feature_folder, group_size) : feature_groups_by_weight(feature_folder, group_size,weighing_factor)
|
8
|
+
end
|
9
|
+
|
10
|
+
def feature_groups_by_feature_files(feature_folder, group_size)
|
7
11
|
files = feature_files_in_folder feature_folder
|
8
12
|
min_number_files_per_group = files.size/group_size
|
9
13
|
remaining_number_of_files = files.size % group_size
|
@@ -19,13 +23,45 @@ module ParallelCalabash
|
|
19
23
|
groups.reject(&:empty?)
|
20
24
|
end
|
21
25
|
|
22
|
-
def feature_files_in_folder
|
26
|
+
def feature_files_in_folder(feature_dir)
|
23
27
|
if File.directory?(feature_dir.first)
|
24
28
|
files = Dir[File.join(feature_dir, "**{,/*/**}/*")].uniq
|
25
29
|
files.grep(/\.feature$/)
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
33
|
+
def weight_of_feature(feature_file, weighing_factor)
|
34
|
+
content = File.read(feature_file)
|
35
|
+
content.scan(/#{weighing_factor}\b/).size
|
36
|
+
end
|
37
|
+
|
38
|
+
def features_with_weights(feature_dir, weighing_factor)
|
39
|
+
files = feature_files_in_folder feature_dir
|
40
|
+
features_and_weight = []
|
41
|
+
files.each do |file|
|
42
|
+
features_and_weight << {:feature => file, :weight => weight_of_feature(file, weighing_factor)}
|
43
|
+
end
|
44
|
+
features_and_weight
|
45
|
+
end
|
46
|
+
|
47
|
+
def feature_groups_by_weight(feature_folder, group_size, weighing_factor)
|
48
|
+
features = features_with_weights feature_folder, weighing_factor
|
49
|
+
feature_groups = Array.new(group_size).map{|e| e = []}
|
50
|
+
features.each do |feature|
|
51
|
+
feature_groups[index_of_lightest_group(feature_groups)] << feature
|
52
|
+
end
|
53
|
+
feature_groups.map{|group| group.map{|feature_hash| feature_hash[:feature]}}
|
54
|
+
end
|
55
|
+
|
56
|
+
def index_of_lightest_group feature_groups
|
57
|
+
lightest = feature_groups.min { |x, y| weight_of_group(x) <=> weight_of_group(y) }
|
58
|
+
index = feature_groups.index(lightest)
|
59
|
+
end
|
60
|
+
|
61
|
+
def weight_of_group group
|
62
|
+
group.inject(0) { |sum, b| sum + b[:weight] }
|
63
|
+
end
|
64
|
+
|
29
65
|
end
|
30
66
|
|
31
67
|
end
|
@@ -22,7 +22,7 @@ module ParallelCalabash
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def summarize_results(results)
|
25
|
-
output = []
|
25
|
+
output = ["\n\n************ FINAL SUMMARY ************"]
|
26
26
|
|
27
27
|
failing_scenarios = results.grep(failing_scenario_regex)
|
28
28
|
if failing_scenarios.any?
|
@@ -69,7 +69,7 @@ module ParallelCalabash
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def failing_scenario_regex
|
72
|
-
/^cucumber features\/.+:\d+/
|
72
|
+
/^cucumber .*features\/.+:\d+/
|
73
73
|
end
|
74
74
|
|
75
75
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'parallel_calabash/feature_grouper'
|
4
|
+
|
5
|
+
describe ParallelCalabash::FeatureGrouper do
|
6
|
+
|
7
|
+
describe :feature_files_in_folder do
|
8
|
+
it 'should find all feature files path in the given folder' do
|
9
|
+
expect(ParallelCalabash::FeatureGrouper.feature_files_in_folder ['spec/test_data/features']).to eq \
|
10
|
+
["spec/test_data/features/aaa.feature", "spec/test_data/features/bbb.feature", "spec/test_data/features/ccc.feature", "spec/test_data/features/ddd.feature", "spec/test_data/features/eee.feature", "spec/test_data/features/fff.feature"]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe :feature_groups do
|
15
|
+
|
16
|
+
it 'should group all features in only one group' do
|
17
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups(['spec/test_data/features'], 1)).to eq \
|
18
|
+
[["spec/test_data/features/aaa.feature", "spec/test_data/features/bbb.feature", "spec/test_data/features/ccc.feature", "spec/test_data/features/ddd.feature", "spec/test_data/features/eee.feature", "spec/test_data/features/fff.feature"]]
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should divide features in 2 groups' do
|
22
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups(['spec/test_data/features'], 2)).to eq \
|
23
|
+
[["spec/test_data/features/aaa.feature", "spec/test_data/features/bbb.feature", "spec/test_data/features/ccc.feature"], ["spec/test_data/features/ddd.feature", "spec/test_data/features/eee.feature", "spec/test_data/features/fff.feature"]]
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should divide features in 3 groups' do
|
27
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups(['spec/test_data/features'], 3)).to eq \
|
28
|
+
[["spec/test_data/features/aaa.feature", "spec/test_data/features/bbb.feature"], ["spec/test_data/features/ccc.feature", "spec/test_data/features/ddd.feature"], ["spec/test_data/features/eee.feature", "spec/test_data/features/fff.feature"]]
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should divide features in 4 groups' do
|
32
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups(['spec/test_data/features'], 4)).to eq \
|
33
|
+
[["spec/test_data/features/aaa.feature", "spec/test_data/features/eee.feature"], ["spec/test_data/features/bbb.feature", "spec/test_data/features/fff.feature"], ["spec/test_data/features/ccc.feature"], ["spec/test_data/features/ddd.feature"]]
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should divide features in 5 groups' do
|
37
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups(['spec/test_data/features'], 5)).to eq \
|
38
|
+
[["spec/test_data/features/aaa.feature", "spec/test_data/features/fff.feature"], ["spec/test_data/features/bbb.feature"], ["spec/test_data/features/ccc.feature"], ["spec/test_data/features/ddd.feature"], ["spec/test_data/features/eee.feature"]]
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe :feature_weight do
|
44
|
+
it 'should find number of occurrence of given tag in feature' do
|
45
|
+
expect(ParallelCalabash::FeatureGrouper.weight_of_feature('spec/test_data/features/aaa.feature', '@tag1')).to eq 14
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should find number of occurrence of given tag in feature' do
|
49
|
+
expect(ParallelCalabash::FeatureGrouper.weight_of_feature('spec/test_data/features/bbb.feature', '@tag1')).to eq 5
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe :features_with_weights do
|
54
|
+
it 'should give all features along with their weights' do
|
55
|
+
expect(ParallelCalabash::FeatureGrouper.features_with_weights(['spec/test_data/features'], '@tag1')).to eq \
|
56
|
+
[{:feature => "spec/test_data/features/aaa.feature", :weight => 14}, {:feature => "spec/test_data/features/bbb.feature", :weight => 5}, {:feature => "spec/test_data/features/ccc.feature", :weight => 4}, {:feature => "spec/test_data/features/ddd.feature", :weight => 3}, {:feature => "spec/test_data/features/eee.feature", :weight => 2}, {:feature => "spec/test_data/features/fff.feature", :weight => 0}]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
describe :feature_groups_by_weight do
|
62
|
+
it 'should groups all features equally into 2 groups per their weight' do
|
63
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups_by_weight(['spec/test_data/features'], 2, '@tag1')).to eq \
|
64
|
+
[["spec/test_data/features/aaa.feature", "spec/test_data/features/fff.feature"], ["spec/test_data/features/bbb.feature", "spec/test_data/features/ccc.feature", "spec/test_data/features/ddd.feature", "spec/test_data/features/eee.feature"]]
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should groups all features equally into 3 groups as per their weight' do
|
68
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups_by_weight(['spec/test_data/features'], 3, '@tag1')).to eq \
|
69
|
+
[["spec/test_data/features/aaa.feature"], ["spec/test_data/features/bbb.feature", "spec/test_data/features/eee.feature", "spec/test_data/features/fff.feature"], ["spec/test_data/features/ccc.feature", "spec/test_data/features/ddd.feature"]]
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should groups all features equally into 4 groups as per their weight' do
|
73
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups_by_weight(['spec/test_data/features'], 4, '@tag1')).to eq \
|
74
|
+
[["spec/test_data/features/aaa.feature"], ["spec/test_data/features/bbb.feature"], ["spec/test_data/features/ccc.feature", "spec/test_data/features/fff.feature"], ["spec/test_data/features/ddd.feature", "spec/test_data/features/eee.feature"]]
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should groups all features equally into 5 groups as per their weight' do
|
78
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups_by_weight(['spec/test_data/features'], 5, '@tag1')).to eq \
|
79
|
+
[["spec/test_data/features/aaa.feature"], ["spec/test_data/features/bbb.feature"], ["spec/test_data/features/ccc.feature"], ["spec/test_data/features/ddd.feature"], ["spec/test_data/features/eee.feature", "spec/test_data/features/fff.feature"]]
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should groups all features equally into 6 groups as per their weight' do
|
83
|
+
expect(ParallelCalabash::FeatureGrouper.feature_groups_by_weight(['spec/test_data/features'], 6, '@tag1')).to eq \
|
84
|
+
[["spec/test_data/features/aaa.feature"], ["spec/test_data/features/bbb.feature"], ["spec/test_data/features/ccc.feature"], ["spec/test_data/features/ddd.feature"], ["spec/test_data/features/eee.feature"], ["spec/test_data/features/fff.feature"]]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'parallel_calabash'
|
3
|
+
|
4
|
+
describe ParallelCalabash::Runner do
|
5
|
+
describe :command_for_process do
|
6
|
+
it 'should return command with env variables' do
|
7
|
+
ParallelCalabash::AdbHelper.should_receive(:device_for_process).with(0).and_return("5555")
|
8
|
+
expect(ParallelCalabash::Runner.command_for_process(0, 'base_command')).to eq \
|
9
|
+
"AUTOTEST=1;export AUTOTEST ADB_DEVICE_ARG=5555;export ADB_DEVICE_ARG TEST_PROCESS_NUMBER=1;export TEST_PROCESS_NUMBER;base_command"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
describe :execute_command_for_process do
|
15
|
+
it 'should execute the command with correct env variables set and return exit status 0 when command gets executed successfully' do
|
16
|
+
ParallelCalabash::AdbHelper.should_receive(:device_for_process).with(3).and_return("DEVICE3")
|
17
|
+
expect(ParallelCalabash::Runner.execute_command_for_process(3,'echo $ADB_DEVICE_ARG;echo $TEST_PROCESS_NUMBER',true)).to eq ({:stdout=>"DEVICE3\n4\n", :exit_status=>0})
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should return exit status of 1' do
|
21
|
+
expect(ParallelCalabash::Runner.execute_command_for_process(3,"ruby -e 'exit(1)'",true)).to eq ({:stdout=>"", :exit_status=>1})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
Feature: aaa feature
|
2
|
+
|
3
|
+
@tag1
|
4
|
+
Scenario:
|
5
|
+
|
6
|
+
@tag1
|
7
|
+
Scenario:
|
8
|
+
|
9
|
+
@tag1
|
10
|
+
Scenario:
|
11
|
+
|
12
|
+
@tag1
|
13
|
+
Scenario:
|
14
|
+
|
15
|
+
@tag1
|
16
|
+
Scenario:
|
17
|
+
|
18
|
+
@tag1
|
19
|
+
Scenario:
|
20
|
+
|
21
|
+
@tag1
|
22
|
+
Scenario:
|
23
|
+
|
24
|
+
@tag1
|
25
|
+
Scenario:
|
26
|
+
|
27
|
+
@tag1
|
28
|
+
Scenario:
|
29
|
+
|
30
|
+
@tag1
|
31
|
+
Scenario:
|
32
|
+
|
33
|
+
@tag1
|
34
|
+
Scenario:
|
35
|
+
|
36
|
+
@tag1
|
37
|
+
Scenario:
|
38
|
+
|
39
|
+
@tag1
|
40
|
+
Scenario:
|
41
|
+
|
42
|
+
@tag1
|
43
|
+
Scenario:
|
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallel_calabash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rajdeep
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,7 +75,15 @@ files:
|
|
75
75
|
- lib/parallel_calabash/runner.rb
|
76
76
|
- lib/parallel_calabash/version.rb
|
77
77
|
- parallel_calabash.gemspec
|
78
|
+
- spec/lib/parallel_calabash/feature_grouper_spec.rb
|
79
|
+
- spec/lib/parallel_calabash/runner_spec.rb
|
78
80
|
- spec/spec_helper.rb
|
81
|
+
- spec/test_data/features/aaa.feature
|
82
|
+
- spec/test_data/features/bbb.feature
|
83
|
+
- spec/test_data/features/ccc.feature
|
84
|
+
- spec/test_data/features/ddd.feature
|
85
|
+
- spec/test_data/features/eee.feature
|
86
|
+
- spec/test_data/features/fff.feature
|
79
87
|
homepage: https://github.com/rajdeepv/parallel_calabash
|
80
88
|
licenses:
|
81
89
|
- MIT
|
@@ -101,4 +109,12 @@ signing_key:
|
|
101
109
|
specification_version: 4
|
102
110
|
summary: calabash android tests in parallel
|
103
111
|
test_files:
|
112
|
+
- spec/lib/parallel_calabash/feature_grouper_spec.rb
|
113
|
+
- spec/lib/parallel_calabash/runner_spec.rb
|
104
114
|
- spec/spec_helper.rb
|
115
|
+
- spec/test_data/features/aaa.feature
|
116
|
+
- spec/test_data/features/bbb.feature
|
117
|
+
- spec/test_data/features/ccc.feature
|
118
|
+
- spec/test_data/features/ddd.feature
|
119
|
+
- spec/test_data/features/eee.feature
|
120
|
+
- spec/test_data/features/fff.feature
|