flatware-cucumber 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: af10de976bd3f5ab9978612d0eca4303fce90326
4
+ data.tar.gz: 06c0102f0d981ac87c918a77a346b35abd9dbd8f
5
+ SHA512:
6
+ metadata.gz: f54ab4f38b3b837151349f8d453ef39f27a3855fada7cffd042c07c0afc7e54c60cf2f806f4725896d7c0a8311d87fd0f6ad96eee5103e212ed91e54f53304be
7
+ data.tar.gz: 1f3b63d49b7ffb911bfc49fec675f9e8b54e87b9756716d48a85dd64e862f185dce981955c6d8de32d774daa2e103f18d5a579edc92c0083a2a690835343bbfc
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Brian Dunn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # Flatware [![Build Status][travis-badge]][travis] [![Code Climate][code-climate-badge]][code-climate]
2
+
3
+ [travis-badge]: https://travis-ci.org/briandunn/flatware.svg?branch=master
4
+ [travis]: http://travis-ci.org/briandunn/flatware
5
+ [code-climate-badge]: https://codeclimate.com/github/briandunn/flatware.png
6
+ [code-climate]: https://codeclimate.com/github/briandunn/flatware
7
+
8
+ Flatware parallelizes your test suite to significantly reduce test time.
9
+
10
+ ## Requirements
11
+
12
+ * ZeroMQ > 4.0
13
+
14
+ ## Installation
15
+
16
+ ### ZeroMQ
17
+
18
+ #### Linux Ubuntu
19
+
20
+ ```sh
21
+ sudo apt-get install -qq libzmq3-dev
22
+ ```
23
+
24
+ (Never you mind the 3. This package contains ZMQ version 4.)
25
+
26
+ #### Mac OSX
27
+
28
+ Ruby FFI isn't getting along with the latest ZMQ formula. A tweaked verson is available in the Hashrocket tap.
29
+
30
+ ```sh
31
+ brew tap hashrocket/formulas
32
+ brew install hashrocket/formulas/zeromq
33
+ brew install zeromq
34
+ ```
35
+
36
+ ### Flatware
37
+
38
+ Add the runners you need to your Gemfile:
39
+
40
+ ```ruby
41
+ gem 'flatware-rspec' # one
42
+ gem 'flatware-cucumber' # or both
43
+ ```
44
+
45
+ then run
46
+
47
+ ```sh
48
+ bundle install
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ ### Cucumber
54
+
55
+ To run your entire suite with the default cucumber options, add the `flatware-cucumber` gem and just:
56
+
57
+ ```sh
58
+ $ flatware cucumber
59
+ ```
60
+
61
+ ### RSpec
62
+
63
+ To run your entire suite with the default rspec options add the `flatware-rspec` gem and just:
64
+
65
+ ```sh
66
+ $ flatware rspec
67
+ ```
68
+
69
+ ### Options
70
+
71
+ If you'd like to limit the number of forked workers, you can pass the 'w' flag:
72
+
73
+ ```sh
74
+ $ flatware -w 3
75
+ ```
76
+
77
+ You can also pass most cucumber/rspec options to Flatware. For example, to run only
78
+ features that are not tagged 'javascript', you can:
79
+
80
+ ```sh
81
+ $ flatware cucumber -t ~@javascript
82
+ ```
83
+
84
+ Additionally, for either cucumber or rspec you can specify a directory:
85
+
86
+ ```sh
87
+ $ flatware rspec spec/features
88
+ ```
89
+
90
+ ## Typical Usage in a Rails App
91
+
92
+ Add the following to your `config/database.yml`:
93
+
94
+ ```yml
95
+ test:
96
+ database: foo_test
97
+ ```
98
+
99
+ becomes:
100
+
101
+ ```yml
102
+ test:
103
+ database: foo_test<%=ENV['TEST_ENV_NUMBER']%>
104
+ ```
105
+
106
+ Run the following:
107
+
108
+ ```sh
109
+ $ rake db:setup # if not already done
110
+ $ flatware fan rake db:test:prepare
111
+ ```
112
+
113
+ Now you are ready to rock:
114
+
115
+ ```sh
116
+ $ flatware rspec && flatware cucumber
117
+ ```
118
+
119
+ ## Planned Features
120
+
121
+ * Use heuristics to run your slowest tests first
122
+
123
+ ## Design Goals
124
+
125
+ ### Maintainable
126
+
127
+ * Fully test at an integration level. Don't be afraid to change the code. If you
128
+ break it you'll know.
129
+ * Couple as loosely as possible, and only to the most stable/public bits of
130
+ Cucumber and RSpec.
131
+
132
+ ### Minimal
133
+
134
+ * Projects define their own preparation scripts
135
+ * Only distribute to local cores (for now)
136
+
137
+ ### Robust
138
+
139
+ * Depend on a dedicated messaging library
140
+ * Be accountable for completed work; provide progress report regardless of
141
+ completing the suite.
142
+
143
+ ## Tinkering
144
+
145
+ Flatware integration tests use [aruba][a]. In order to get a demo cucumber project you
146
+ can add the `@no-clobber` tag to `features/flatware.feature` and run the test
147
+ with `cucumber features/flatware.feature`. Now you should have a `./tmp/aruba`
148
+ directory. CD there and `flatware` will be in your path so you can tinker away.
149
+
150
+ ## How it works
151
+
152
+ Flatware relies on a message passing system to enable concurrency.
153
+ The main process declares a worker for each cpu in the computer. Each
154
+ worker forks from the main process and is then assigned a portion of the
155
+ test suite. As the worker runs the test suite it sends progress
156
+ messages to the main process. These messages are collected and when
157
+ the last worker is finished the main process provides a report on the
158
+ collected progress messages.
159
+
160
+ ## Resources
161
+
162
+ To learn more about the messaging system that Flatware uses, take a look at the
163
+ [excellent ZeroMQ guide][z].
164
+
165
+ [z]: http://zguide.zeromq.org/page:all
166
+ [a]: https://github.com/cucumber/aruba
167
+
168
+ ## Contributing to Flatware
169
+
170
+ Do whatever you want. I'd love to help make sure Flatware meets your needs.
171
+
172
+ ## About
173
+
174
+ [![Hashrocket logo](https://hashrocket.com/hashrocket_logo.svg)](https://hashrocket.com)
175
+
176
+ Flatware is supported by the team at [Hashrocket](https://hashrocket.com), a multidisciplinary design & development consultancy. If you'd like to [work with us](https://hashrocket.com/contact-us/hire-us) or [join our team](https://hashrocket.com/contact-us/jobs), don't hesitate to get in touch.
@@ -0,0 +1 @@
1
+ require 'flatware/cucumber'
@@ -0,0 +1,28 @@
1
+ module Flatware
2
+ module Cucumber
3
+ class Checkpoint
4
+ attr_reader :steps, :scenarios
5
+ def initialize(steps, scenarios)
6
+ @steps, @scenarios = serialize_steps(steps), serialize_scenarios(scenarios)
7
+ end
8
+
9
+ def failures?
10
+ scenarios.any? &:failed?
11
+ end
12
+
13
+ private
14
+
15
+ def serialize_steps(steps)
16
+ steps.map do |step|
17
+ StepResult.new step.status, step.exception
18
+ end
19
+ end
20
+
21
+ def serialize_scenarios(scenarios)
22
+ scenarios.map do |scenario|
23
+ ScenarioResult.new scenario.status, scenario.file_colon_line, scenario.name, scenario.exception
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ require 'flatware/cli'
2
+
3
+ module Flatware
4
+ class CLI
5
+ worker_option
6
+ method_option 'dispatch-endpoint', type: :string, default: 'ipc://dispatch'
7
+ method_option 'sink-endpoint', type: :string, default: 'ipc://task'
8
+ desc "cucumber [FLATWARE_OPTS] [CUCUMBER_ARGS]", "parallelizes cucumber with custom arguments"
9
+ def cucumber(*args)
10
+ config = Cucumber.configure args
11
+
12
+ unless config.jobs.any?
13
+ puts "Please create some feature files in the #{config.feature_dir} directory."
14
+ exit 1
15
+ end
16
+
17
+ Flatware.verbose = options[:log]
18
+ Worker.spawn count: workers, runner: Cucumber, dispatch: options['dispatch-endpoint'], sink: options['sink-endpoint']
19
+ start_sink jobs: config.jobs, workers: workers, formatter: Flatware::Cucumber::Formatters::Console.new($stdout, $stderr)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,66 @@
1
+ require 'cucumber'
2
+ require 'flatware/sink'
3
+ require 'ostruct'
4
+ module Flatware
5
+ module Cucumber
6
+ class Formatter
7
+ Checkpoint = Struct.new :steps, :scenarios do
8
+ def failures?
9
+ scenarios.any? &:failed?
10
+ end
11
+ end
12
+
13
+ Scenario = Struct.new :name, :file_colon_line, :status do
14
+ def failed?
15
+ status == :failed
16
+ end
17
+
18
+ def failed_outside_step?
19
+ false
20
+ end
21
+ end
22
+
23
+ def initialize(config)
24
+ config.on_event :after_test_case, &method(:on_after_test_case)
25
+ config.on_event :after_test_step, &method(:on_after_test_step)
26
+ config.on_event :finished_testing, &method(:on_finished_testing)
27
+ config.on_event :step_match, &method(:on_step_match)
28
+ reset
29
+ end
30
+
31
+ private
32
+
33
+ def reset
34
+ @steps = []
35
+ @scenarios = []
36
+ @matched_steps = Set.new
37
+ end
38
+
39
+ attr_reader :steps, :scenarios, :matched_steps
40
+
41
+ def on_after_test_case(event)
42
+ scenarios << Scenario.new(event.test_case.name, event.test_case.location.to_s, event.result.to_sym)
43
+ end
44
+
45
+ def on_step_match(event)
46
+ @matched_steps << event.step_match.location.to_s
47
+ end
48
+
49
+ def on_after_test_step(event)
50
+ if really_a_step?(event.test_step) or event.result.undefined?
51
+ steps << StepResult.new(event.result.to_sym, event.result.failed? && event.result.exception)
52
+ Sink::client.progress Result.new event.result.to_sym
53
+ end
54
+ end
55
+
56
+ def on_finished_testing(*)
57
+ Sink::client.checkpoint Checkpoint.new steps, scenarios
58
+ reset
59
+ end
60
+
61
+ def really_a_step?(step)
62
+ matched_steps.include?(step.action_location.to_s)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,48 @@
1
+ require 'flatware/cucumber/formatters/console/summary'
2
+ require 'cucumber/formatter/console'
3
+
4
+ module Flatware::Cucumber::Formatters
5
+ class Console
6
+ #for format_string
7
+ include ::Cucumber::Formatter::Console
8
+
9
+ FORMATS = {
10
+ passed: '.',
11
+ failed: 'F',
12
+ undefined: 'U',
13
+ pending: 'P',
14
+ skipped: '-'
15
+ }
16
+
17
+ STATUSES = FORMATS.keys
18
+
19
+ attr_reader :out, :err
20
+
21
+ def initialize(stdout, stderr)
22
+ @out, @err = stdout, stderr
23
+ end
24
+
25
+ def progress(result)
26
+ out.print format result.progress
27
+ end
28
+
29
+ def summarize(checkpoints)
30
+ steps = checkpoints.flat_map(&:steps)
31
+ scenarios = checkpoints.flat_map(&:scenarios)
32
+ Summary.new(steps, scenarios, out).summarize
33
+ end
34
+
35
+ def summarize_remaining(remaining_jobs)
36
+ out.puts
37
+ out.puts "The following features have not been run:"
38
+ for job in remaining_jobs
39
+ out.puts job.id
40
+ end
41
+ end
42
+
43
+ private
44
+ def format(status)
45
+ format_string FORMATS[status], status
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,66 @@
1
+ require 'cucumber/formatter/console'
2
+ require 'flatware/cucumber/formatters/console'
3
+ require 'flatware/cucumber/checkpoint'
4
+
5
+ module Flatware::Cucumber::Formatters
6
+ class Console
7
+ class Summary
8
+ include ::Cucumber::Formatter::Console
9
+ attr_reader :io, :steps, :scenarios
10
+
11
+ def initialize(steps, scenarios=[], io=StringIO.new)
12
+ @io = io
13
+ @steps = steps
14
+ @scenarios = scenarios
15
+ end
16
+
17
+ def summarize
18
+ 2.times { io.puts }
19
+ print_failures(steps, 'step')
20
+ print_failures(scenarios.select(&:failed_outside_step?), 'scenario')
21
+ print_failed_scenarios scenarios
22
+ print_counts 'scenario', scenarios
23
+ print_counts 'step', steps
24
+ end
25
+
26
+ private
27
+
28
+ def print_failed_scenarios(scenarios)
29
+ return unless scenarios.any? &with_status(:failed)
30
+
31
+ io.puts format_string "Failing Scenarios:", :failed
32
+ scenarios.select(&with_status(:failed)).sort_by(&:file_colon_line).each do |scenario|
33
+ io.puts format_string(scenario.file_colon_line, :failed) + format_string(" # Scenario: " + scenario.name, :comment)
34
+ end
35
+ io.puts
36
+ end
37
+
38
+ def print_failures(collection, label)
39
+ failures = collection.select(&with_status(:failed))
40
+ print_elements failures, :failed, pluralize(label, failures.size)
41
+ end
42
+
43
+ def print_counts(label, collection)
44
+ io.puts pluralize(label, collection.size) + count_summary(collection)
45
+ end
46
+
47
+ def pluralize(word, number)
48
+ "#{number} #{number == 1 ? word : word + 's'}"
49
+ end
50
+
51
+ def with_status(status)
52
+ proc {|r| r.status == status}
53
+ end
54
+
55
+ def count_summary(results)
56
+ return "" unless results.any?
57
+ status_counts = STATUSES.map do |status|
58
+ count = results.select(&with_status(status)).size
59
+ format_string "#{count} #{status}", status if count > 0
60
+ end.compact.join ", "
61
+
62
+ " (#{status_counts})"
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,27 @@
1
+ module Flatware
2
+ module Cucumber
3
+ class Result
4
+ attr_reader :progress, :worker
5
+
6
+ def initialize(progress)
7
+ @progress = progress
8
+ @worker = ENV['TEST_ENV_NUMBER'].to_i
9
+ end
10
+
11
+ class << self
12
+ def step(*args)
13
+ step = StepResult.new *args
14
+ new step.progress, [step]
15
+ end
16
+
17
+ def status(status)
18
+ new status
19
+ end
20
+
21
+ def background(status, exception)
22
+ new '', [StepResult.new(status, exception)]
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ require 'cucumber'
2
+
3
+ module Flatware
4
+ module Cucumber
5
+ class Runtime < ::Cucumber::Runtime
6
+
7
+ attr_accessor :configuration, :loader
8
+ attr_reader :out, :err
9
+ attr_reader :visitor
10
+
11
+ def initialize(out=StringIO.new, err=out)
12
+ @out, @err = out, err
13
+ super(default_configuration)
14
+ load_step_definitions
15
+ @results = Results.new(configuration)
16
+ end
17
+
18
+ def default_configuration
19
+ config = ::Cucumber::Cli::Configuration.new
20
+ config.parse! []
21
+ config
22
+ end
23
+
24
+ def run(feature_files=[], options=[])
25
+ @loader = nil
26
+ options = Array(feature_files) + %w[--format Flatware::Cucumber::Formatter] + options
27
+
28
+ configure(::Cucumber::Cli::Main.new(options, out, err).configuration)
29
+
30
+ self.visitor = configuration.build_tree_walker(self)
31
+ visitor.visit_features(features)
32
+ results
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ require 'flatware/serialized_exception'
2
+ module Flatware
3
+ module Cucumber
4
+ class ScenarioResult
5
+ attr_reader :status, :file_colon_line, :name
6
+ def initialize(status, file_colon_line, name, e)
7
+ @status = status
8
+ @file_colon_line = file_colon_line
9
+ @name = name
10
+ @exception = SerializedException.new(e.class, e.message, e.backtrace) if e
11
+ @failed_outside_step = false
12
+ end
13
+
14
+ def passed?
15
+ status == :passed
16
+ end
17
+
18
+ def failed?
19
+ status == :failed
20
+ end
21
+
22
+ def failed_outside_step!(file_colon_line)
23
+ @failed_outside_step = file_colon_line
24
+ end
25
+
26
+ def failed_outside_step?
27
+ !!@failed_outside_step
28
+ end
29
+
30
+ def exception
31
+ @exception.tap do |e|
32
+ e.backtrace = e.backtrace.grep(Regexp.new(Dir.pwd)).map { |line| line[Dir.pwd.size..-1] }
33
+ e.backtrace = e.backtrace + [@failed_outside_step] if failed_outside_step?
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ require 'flatware/serialized_exception'
2
+ module Flatware
3
+ module Cucumber
4
+ class StepResult
5
+ attr_reader :status, :exception
6
+
7
+ def initialize(status, exception)
8
+ @status, @exception = status, (serialized(exception) if exception)
9
+ end
10
+
11
+ def passed?
12
+ status == :passed
13
+ end
14
+
15
+ def failed?
16
+ status == :failed
17
+ end
18
+
19
+ def progress
20
+ Cucumber::ProgressString.format(status)
21
+ end
22
+
23
+ private
24
+ def serialized(e)
25
+ e.backtrace and e.backtrace.unshift e.backtrace.shift.sub(Dir.pwd, '.')
26
+ SerializedException.new(e.class, e.message, e.backtrace)
27
+ end
28
+ end
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flatware-cucumber
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Dunn
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: flatware
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.4.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.4.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: cucumber
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ description: A distributed cucumber runner
42
+ email: brian@hashrocket.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files:
46
+ - LICENSE.txt
47
+ - README.md
48
+ files:
49
+ - LICENSE.txt
50
+ - README.md
51
+ - lib/flatware-cucumber.rb
52
+ - lib/flatware/cucumber/checkpoint.rb
53
+ - lib/flatware/cucumber/cli.rb
54
+ - lib/flatware/cucumber/formatter.rb
55
+ - lib/flatware/cucumber/formatters/console.rb
56
+ - lib/flatware/cucumber/formatters/console/summary.rb
57
+ - lib/flatware/cucumber/result.rb
58
+ - lib/flatware/cucumber/runtime.rb
59
+ - lib/flatware/cucumber/scenario_result.rb
60
+ - lib/flatware/cucumber/step_result.rb
61
+ homepage: http://github.com/briandunn/flatware
62
+ licenses:
63
+ - MIT
64
+ metadata: {}
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '2.1'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 2.6.8
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: A distributed cucumber runner
85
+ test_files: []