flatware 0.3.2 → 0.4.0

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +83 -39
  3. data/lib/flatware-cucumber.rb +1 -0
  4. data/lib/flatware-rspec.rb +1 -0
  5. data/lib/flatware.rb +2 -10
  6. data/lib/flatware/broadcaster.rb +15 -0
  7. data/lib/flatware/cli.rb +10 -34
  8. data/lib/flatware/cucumber.rb +37 -12
  9. data/lib/flatware/cucumber/checkpoint.rb +28 -0
  10. data/lib/flatware/cucumber/cli.rb +22 -0
  11. data/lib/flatware/cucumber/formatter.rb +36 -84
  12. data/lib/flatware/{formatters/cucumber → cucumber/formatters}/console.rb +5 -3
  13. data/lib/flatware/{formatters/cucumber → cucumber/formatters}/console/summary.rb +3 -3
  14. data/lib/flatware/cucumber/result.rb +27 -0
  15. data/lib/flatware/cucumber/scenario_result.rb +38 -0
  16. data/lib/flatware/cucumber/step_result.rb +30 -0
  17. data/lib/flatware/poller.rb +2 -2
  18. data/lib/flatware/rspec.rb +28 -0
  19. data/lib/flatware/rspec/checkpoint.rb +29 -0
  20. data/lib/flatware/rspec/cli.rb +16 -0
  21. data/lib/flatware/rspec/example_notification.rb +21 -0
  22. data/lib/flatware/rspec/examples_notification.rb +24 -0
  23. data/lib/flatware/rspec/formatter.rb +50 -0
  24. data/lib/flatware/rspec/formatters/console.rb +33 -0
  25. data/lib/flatware/rspec/summary.rb +40 -0
  26. data/lib/flatware/serialized_exception.rb +12 -8
  27. data/lib/flatware/sink.rb +43 -33
  28. data/lib/flatware/socket.rb +89 -25
  29. data/lib/flatware/version.rb +1 -1
  30. data/lib/flatware/worker.rb +16 -9
  31. metadata +27 -55
  32. data/lib/flatware/checkpoint.rb +0 -28
  33. data/lib/flatware/checkpoint_handler.rb +0 -45
  34. data/lib/flatware/dispatcher.rb +0 -31
  35. data/lib/flatware/fireable.rb +0 -34
  36. data/lib/flatware/formatters.rb +0 -27
  37. data/lib/flatware/formatters/cucumber/http.rb +0 -83
  38. data/lib/flatware/result.rb +0 -25
  39. data/lib/flatware/scenario_decorator.rb +0 -22
  40. data/lib/flatware/scenario_result.rb +0 -36
  41. data/lib/flatware/step_result.rb +0 -27
@@ -1,113 +1,65 @@
1
- require 'flatware/checkpoint'
2
- require 'flatware/scenario_decorator'
1
+ require 'cucumber'
3
2
  require 'flatware/sink'
4
3
  require 'ostruct'
5
4
  module Flatware
6
5
  module Cucumber
7
6
  class Formatter
8
-
9
- def initialize(step_mother, *)
10
- @collector = Collector.new step_mother
11
- @scenarios = []
12
- @in_a_step = false
13
- end
14
-
15
- def after_features(*)
16
- checkpoint = collector.checkpoint
17
- scenarios.select(&:exception).map(&:file_colon_line).each do |file_colon_line|
18
- scenario = checkpoint.scenarios.detect do |scenario|
19
- scenario.file_colon_line == file_colon_line
20
- end
21
- scenario.failed_outside_step!(file_colon_line) if scenario
7
+ Checkpoint = Struct.new :steps, :scenarios do
8
+ def failures?
9
+ scenarios.any? &:failed?
22
10
  end
23
- Sink::client.checkpoint checkpoint
24
- end
25
-
26
- def after_step_result(_, _, _, status, *)
27
- send_progress(status)
28
- end
29
-
30
- def table_cell_value(_, status)
31
- send_progress(status) if status
32
11
  end
33
12
 
34
- def exception(exception, status)
35
- unless @in_a_step
36
- current_scenario.exception = exception
37
- send_progress(status)
13
+ Scenario = Struct.new :name, :file_colon_line, :status do
14
+ def failed?
15
+ status == :failed
38
16
  end
39
- end
40
-
41
- def respond_to?(x)
42
- super
43
- end
44
17
 
45
- def before_outline_table(*)
46
- @in_examples = true
47
- end
48
-
49
- def after_outline_table(*)
50
- @in_examples = false
18
+ def failed_outside_step?
19
+ false
20
+ end
51
21
  end
52
22
 
53
- def before_table_cell(*)
54
- @in_a_step = @in_examples
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
55
29
  end
56
30
 
57
- def after_table_cell(*)
58
- @in_a_step = ! @in_examples
59
- end
31
+ private
60
32
 
61
- def after_table_row(table_row)
62
- exception(table_row.exception, :failed) if table_row.exception
33
+ def reset
34
+ @steps = []
35
+ @scenarios = []
36
+ @matched_steps = Set.new
63
37
  end
64
38
 
65
- def before_step(*)
66
- @in_a_step = true
67
- end
39
+ attr_reader :steps, :scenarios, :matched_steps
68
40
 
69
- def after_step(*)
70
- @in_a_step = false
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)
71
43
  end
72
44
 
73
- def scenario_name(_, name, file_colon_line, *)
74
- scenarios.push OpenStruct.new file_colon_line: file_colon_line, name: name
45
+ def on_step_match(event)
46
+ @matched_steps << event.step_match.location.to_s
75
47
  end
76
48
 
77
- private
78
- attr_reader :collector, :scenarios
79
-
80
- def current_scenario
81
- scenarios.last
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
82
54
  end
83
55
 
84
- def send_progress(status)
85
- Sink::client.progress Result.new status
56
+ def on_finished_testing(*)
57
+ Sink::client.checkpoint Checkpoint.new steps, scenarios
58
+ reset
86
59
  end
87
60
 
88
- class Collector
89
- attr_reader :step_mother
90
- def initialize(step_mother)
91
- @step_mother = step_mother
92
- snapshot
93
- end
94
-
95
- def checkpoint
96
- Checkpoint.new(step_mother.steps - @ran_steps, decorate_scenarios(step_mother.scenarios - @ran_scenarios)).tap do
97
- snapshot
98
- end
99
- end
100
-
101
- private
102
-
103
- def snapshot
104
- @ran_steps = step_mother.steps.dup
105
- @ran_scenarios = step_mother.scenarios.dup
106
- end
107
-
108
- def decorate_scenarios(scenarios)
109
- scenarios.map { |scenario| ScenarioDecorator.new(scenario) }
110
- end
61
+ def really_a_step?(step)
62
+ matched_steps.include?(step.action_location.to_s)
111
63
  end
112
64
  end
113
65
  end
@@ -1,7 +1,7 @@
1
- require 'flatware/formatters/cucumber/console/summary'
1
+ require 'flatware/cucumber/formatters/console/summary'
2
2
  require 'cucumber/formatter/console'
3
3
 
4
- module Flatware::Formatters::Cucumber
4
+ module Flatware::Cucumber::Formatters
5
5
  class Console
6
6
  #for format_string
7
7
  include ::Cucumber::Formatter::Console
@@ -26,7 +26,9 @@ module Flatware::Formatters::Cucumber
26
26
  out.print format result.progress
27
27
  end
28
28
 
29
- def summarize(steps, scenarios)
29
+ def summarize(checkpoints)
30
+ steps = checkpoints.flat_map(&:steps)
31
+ scenarios = checkpoints.flat_map(&:scenarios)
30
32
  Summary.new(steps, scenarios, out).summarize
31
33
  end
32
34
 
@@ -1,8 +1,8 @@
1
1
  require 'cucumber/formatter/console'
2
- require 'flatware/formatters/cucumber/console'
3
- require 'flatware/checkpoint'
2
+ require 'flatware/cucumber/formatters/console'
3
+ require 'flatware/cucumber/checkpoint'
4
4
 
5
- module Flatware::Formatters::Cucumber
5
+ module Flatware::Cucumber::Formatters
6
6
  class Console
7
7
  class Summary
8
8
  include ::Cucumber::Formatter::Console
@@ -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,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
@@ -21,14 +21,14 @@ module Flatware
21
21
  def find_wrapped_socket
22
22
  ->(s) do
23
23
  sockets.find do |socket|
24
- socket.s == s
24
+ socket.socket == s
25
25
  end
26
26
  end
27
27
  end
28
28
 
29
29
  def register_sockets
30
30
  sockets.each do |socket|
31
- zmq_poller.register_readable socket.s
31
+ zmq_poller.register_readable socket.socket
32
32
  end
33
33
  end
34
34
  end
@@ -0,0 +1,28 @@
1
+ require 'rspec/core'
2
+ require 'rspec/expectations'
3
+ require 'flatware/rspec/cli'
4
+
5
+ module Flatware
6
+ module RSpec
7
+ require 'flatware/rspec/formatters/console'
8
+ require 'flatware/rspec/formatter'
9
+
10
+ def self.extract_jobs_from_args(args, workers:)
11
+
12
+ options = ::RSpec::Core::ConfigurationOptions.new(args)
13
+ configuration = ::RSpec::Core::Configuration.new
14
+ def configuration.command() 'rspec' end
15
+ options.configure(configuration)
16
+ configuration.files_to_run.uniq.map do |file|
17
+ Job.new(file, args)
18
+ end
19
+ end
20
+
21
+ def self.run(job, options={})
22
+ runner = ::RSpec::Core::Runner
23
+ def runner.trap_interrupt() end
24
+
25
+ runner.run(%w[--format Flatware::RSpec::Formatter] + Array(job), $stderr, $stdout)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ require 'flatware/rspec/examples_notification'
2
+
3
+ module Flatware
4
+ module RSpec
5
+ class Checkpoint
6
+ attr_reader :summary, :failures_notification
7
+
8
+ def initialize(summary, failures_notification)
9
+ @summary, @failures_notification = summary, ExamplesNotification.new(failures_notification.failure_notifications)
10
+ end
11
+
12
+ def +(other)
13
+ self.class.new summary + other.summary, failures_notification + other.failures_notification
14
+ end
15
+
16
+ def failures?
17
+ summary.failure_count > 0
18
+ end
19
+
20
+ def failure_notifications
21
+ failures_notification.failure_notifications
22
+ end
23
+
24
+ def fully_formatted_failed_examples(*args)
25
+ failures_notification.fully_formatted_failed_examples(*args)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,16 @@
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 "rspec [FLATWARE_OPTS]", "parallelizes rspec"
9
+ def rspec(*rspec_args)
10
+ jobs = RSpec.extract_jobs_from_args rspec_args, workers: workers
11
+ Flatware.verbose = options[:log]
12
+ Worker.spawn count: workers, runner: RSpec, dispatch: options['dispatch-endpoint'], sink: options['sink-endpoint']
13
+ start_sink jobs: jobs, workers: workers, formatter: Flatware::RSpec::Formatters::Console.new($stdout, $stderr)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ require 'rspec/core/formatters/console_codes'
2
+
3
+ module Flatware
4
+ module RSpec
5
+ class ExampleNotification
6
+ attr_reader :formatted
7
+ def initialize(notification)
8
+ @formatted = notification.fully_formatted '!', default_colorizer
9
+ end
10
+
11
+ def fully_formatted(i, _=nil)
12
+ formatted.sub '!', i.to_s
13
+ end
14
+
15
+ private
16
+ def default_colorizer
17
+ ::RSpec::Core::Formatters::ConsoleCodes
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ require 'flatware/rspec/example_notification'
2
+ module Flatware
3
+ module RSpec
4
+ class ExamplesNotification
5
+ attr_reader :failure_notifications
6
+
7
+ def initialize(failure_notifications)
8
+ @failure_notifications = failure_notifications.map(&ExampleNotification.method(:new))
9
+ end
10
+
11
+ def +(other)
12
+ self.class.new failure_notifications + other.failure_notifications
13
+ end
14
+
15
+ def fully_formatted_failed_examples(*)
16
+ formatted = "\n\nFailures:\n"
17
+ failure_notifications.each_with_index do |failure, index|
18
+ formatted << failure.fully_formatted(index.next)
19
+ end
20
+ formatted
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,50 @@
1
+ require 'flatware/rspec/checkpoint'
2
+ require 'flatware/rspec/summary'
3
+ require 'rspec/core/formatters/console_codes'
4
+
5
+ module Flatware
6
+ module RSpec
7
+ ProgressMessage = Struct.new(:progress)
8
+
9
+ class Formatter
10
+ attr_reader :summary, :output
11
+
12
+ def initialize(stdout)
13
+ @output = stdout
14
+ end
15
+
16
+ def example_passed(example)
17
+ send_progress :passed
18
+ end
19
+
20
+ def example_failed(example)
21
+ send_progress :failed
22
+ end
23
+
24
+ def example_pending(example)
25
+ send_progress :pending
26
+ end
27
+
28
+ def dump_summary(summary)
29
+ @summary = Summary.from_notification(summary)
30
+ end
31
+
32
+ def dump_failures(failure_notification)
33
+ @failure_notification = failure_notification
34
+ end
35
+
36
+ def close(*)
37
+ Sink::client.checkpoint Checkpoint.new(summary, @failure_notification)
38
+ @failure_notification = nil
39
+ end
40
+
41
+ private
42
+
43
+ def send_progress(status)
44
+ Sink::client.progress ProgressMessage.new status
45
+ end
46
+ end
47
+
48
+ ::RSpec::Core::Formatters.register Formatter, :example_passed, :example_failed, :example_pending, :dump_summary, :dump_failures, :close
49
+ end
50
+ end