gorgon 0.3.0 → 0.3.1

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.
data/Gemfile.lock CHANGED
@@ -1,14 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gorgon (0.3.0)
4
+ gorgon (0.3.1)
5
5
  amqp (~> 0.9.7)
6
6
  awesome_print
7
7
  bunny (~> 0.8.0)
8
8
  colorize (~> 0.5.8)
9
9
  open4 (~> 1.3.0)
10
10
  ruby-progressbar (~> 1.0.1)
11
- test-unit
12
11
  uuidtools (~> 2.1.3)
13
12
  yajl-ruby (~> 1.1.0)
14
13
 
@@ -49,4 +48,5 @@ PLATFORMS
49
48
  DEPENDENCIES
50
49
  gorgon!
51
50
  rake
52
- rspec
51
+ rspec (~> 2.11.0)
52
+ test-unit
data/gorgon.gemspec CHANGED
@@ -18,15 +18,15 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- s.add_development_dependency "rspec"
22
21
  s.add_development_dependency "rake"
22
+ s.add_development_dependency "test-unit"
23
+ s.add_development_dependency "rspec", '~>2.11.0'
23
24
 
24
25
  s.add_runtime_dependency "amqp", '~>0.9.7'
25
26
  s.add_runtime_dependency "awesome_print"
26
27
  s.add_runtime_dependency "open4", '~>1.3.0'
27
28
  s.add_runtime_dependency "yajl-ruby", '~>1.1.0'
28
29
  s.add_runtime_dependency "uuidtools", '~>2.1.3'
29
- s.add_runtime_dependency "test-unit"
30
30
  s.add_runtime_dependency "bunny", '~>0.8.0'
31
31
  s.add_runtime_dependency "ruby-progressbar", '~>1.0.1'
32
32
  s.add_runtime_dependency "colorize", '~>0.5.8'
@@ -0,0 +1,49 @@
1
+ require 'rspec/core/formatters/base_formatter'
2
+ require 'json'
3
+
4
+ module RSpec
5
+ module Core
6
+ module Formatters
7
+ class GorgonRspecFormatter < BaseFormatter
8
+ attr_reader :output
9
+
10
+ def initialize(output)
11
+ super
12
+ @failures = []
13
+ end
14
+
15
+ def message(message)
16
+ @failures += message unless @failures.empty?
17
+ end
18
+
19
+ def stop
20
+ super
21
+ failures = examples.select { |e| e.execution_result[:status] == "failed" }
22
+
23
+ @failures += failures.map do |failure|
24
+ {
25
+ :test_name => "#{failure.full_description}: " \
26
+ "line #{failure.metadata[:line_number]}",
27
+ :description => failure.description,
28
+ :full_description => failure.full_description,
29
+ :status => failure.execution_result[:status],
30
+ :file_path => failure.metadata[:file_path],
31
+ :line_number => failure.metadata[:line_number],
32
+ }.tap do |hash|
33
+ if e=failure.exception
34
+ hash[:class] = e.class.name
35
+ hash[:message] = e.message
36
+ hash[:location] = e.backtrace
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def close
43
+ output.write @failures.to_json
44
+ output.close if IO === output && output != $stdout
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -8,10 +8,15 @@ LOADING_MSG = "Loading environment and workers..."
8
8
  RUNNING_MSG = "Running files:"
9
9
  LEGEND_MSG = "Legend:\nF - failure files count\nH - number of hosts that have run files\nW - number of workers running files"
10
10
 
11
+ PROGRESS_BAR_REFRESH_RATE = 0.5
12
+ # - because the resolution of the elapsed time is one second, we use the nyquist frequency of 0.5 seconds
13
+ # http://en.wikipedia.org/wiki/Nyquist_frequency
14
+
11
15
  class ProgressBarView
12
16
  def initialize job_state
13
17
  @job_state = job_state
14
18
  @job_state.add_observer(self)
19
+ @timer = EventMachine::PeriodicTimer.new(PROGRESS_BAR_REFRESH_RATE) { update_elapsed_time }
15
20
  end
16
21
 
17
22
  def show
@@ -50,6 +55,11 @@ class ProgressBarView
50
55
  end
51
56
  end
52
57
 
58
+ def update_elapsed_time
59
+ @timer.cancel if @finished
60
+ @progress_bar.refresh if @progress_bar
61
+ end
62
+
53
63
  private
54
64
  def gorgon_crashed? payload
55
65
  payload[:type] == "crash" && payload[:action] != "finish"
@@ -70,7 +80,7 @@ private
70
80
  bar = "%w>%i".colorize(colors[:bar])
71
81
  title = "%t".colorize(colors[:title])
72
82
 
73
- "#{title} | [#{bar}] %c/%C %e"
83
+ "#{title} | [#{bar}] %c/%C %a"
74
84
  end
75
85
 
76
86
  def terminal_size
@@ -124,10 +134,11 @@ private
124
134
  end
125
135
 
126
136
  def build_fail_message_from_hash failure
127
- result = "#{'Test name'.yellow}: #{failure[:test_name]}"
128
- result << "\n#{'Message:'.yellow} \n#{failure[:message]}" if failure[:message]
137
+ result = "#{'Test name'.light_yellow}: #{failure[:test_name]}"
138
+ result << "\n#{failure[:class].red}" if failure[:class]
139
+ result << "\n#{'Message:'.light_yellow} \n\t#{failure[:message]}" if failure[:message]
129
140
  if failure[:location]
130
- result << "\n#{'In:'.yellow} \n\t"
141
+ result << "\n#{'In:'.light_yellow} \n\t"
131
142
  result << failure[:location].join("\n\t")
132
143
  end
133
144
  result
@@ -0,0 +1,27 @@
1
+ require 'rspec'
2
+ require 'stringio'
3
+ require "yajl"
4
+
5
+ require_relative "gorgon_rspec_formatter"
6
+
7
+ class RspecRunner
8
+ class << self
9
+ def run_file(filename)
10
+ args = [
11
+ '-f', 'RSpec::Core::Formatters::GorgonRspecFormatter',
12
+ filename
13
+ ]
14
+
15
+ err, out = StringIO.new, StringIO.new
16
+
17
+ RSpec::Core::Runner.run(args, err, out)
18
+ out.rewind
19
+
20
+ Yajl::Parser.new(:symbolize_keys => true).parse(out.read)
21
+ end
22
+
23
+ def runner
24
+ :rspec
25
+ end
26
+ end
27
+ end
@@ -28,7 +28,7 @@ class Test::Unit::TestCase
28
28
  end
29
29
  end
30
30
 
31
- class TestRunner
31
+ class TestUnitRunner
32
32
  def self.run_file(filename)
33
33
  GorgonTestCases.clear_cases!
34
34
  load filename
@@ -47,4 +47,8 @@ class TestRunner
47
47
 
48
48
  output
49
49
  end
50
+
51
+ def self.runner
52
+ :test_unit
53
+ end
50
54
  end
@@ -1,3 +1,3 @@
1
1
  module Gorgon
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
data/lib/gorgon/worker.rb CHANGED
@@ -3,24 +3,24 @@ require "gorgon/amqp_service"
3
3
  require 'gorgon/callback_handler'
4
4
  require "gorgon/g_logger"
5
5
  require 'gorgon/job_definition'
6
- require "gorgon/testunit_runner"
7
6
 
8
7
  require "uuidtools"
9
8
  require "awesome_print"
10
9
  require "socket"
11
10
 
12
- module WorkUnit
13
- def self.run_file filename
11
+ module TestRunner
12
+ def self.run_file filename, test_runner
14
13
  start_t = Time.now
15
14
 
16
15
  begin
17
- failures = TestRunner.run_file(filename)
16
+ failures = test_runner.run_file(filename)
18
17
  length = Time.now - start_t
19
18
 
20
19
  if failures.empty?
21
- results = {:failures => [], :type => :pass, :time => length}
20
+ results = {:failures => [], :type => :pass, :runner => test_runner.runner, :time => length}
22
21
  else
23
- results = {:failures => failures, :type => :fail, :time => length}
22
+ results = {:failures => failures, :type => :fail, :runner => test_runner.runner,
23
+ :time => length}
24
24
  end
25
25
  rescue Exception => e
26
26
  results = {:failures => ["Exception: #{e.message}\n#{e.backtrace.join("\n")}"], :type => :crash, :time => (Time.now - start_t)}
@@ -51,7 +51,6 @@ class Worker
51
51
  :file_queue_name => job_definition.file_queue_name,
52
52
  :reply_exchange_name => job_definition.reply_exchange_name,
53
53
  :worker_id => worker_id,
54
- :test_runner => WorkUnit,
55
54
  :callback_handler => callback_handler,
56
55
  :log_file => config[:log_file]
57
56
  }
@@ -79,7 +78,6 @@ class Worker
79
78
  @file_queue_name = params[:file_queue_name]
80
79
  @reply_exchange_name = params[:reply_exchange_name]
81
80
  @worker_id = params[:worker_id]
82
- @test_runner = params[:test_runner]
83
81
  @callback_handler = params[:callback_handler]
84
82
  end
85
83
 
@@ -116,7 +114,13 @@ class Worker
116
114
  end
117
115
 
118
116
  def run_file(filename)
119
- @test_runner.run_file(filename)
117
+ if filename =~ /_spec.rb$/i
118
+ require_relative "rspec_runner"
119
+ TestRunner.run_file(filename, RspecRunner)
120
+ else
121
+ require_relative "testunit_runner"
122
+ TestRunner.run_file(filename, TestUnitRunner)
123
+ end
120
124
  end
121
125
 
122
126
  def make_start_message(filename)
@@ -0,0 +1,63 @@
1
+ require 'gorgon/gorgon_rspec_formatter'
2
+
3
+ BaseFormatter = RSpec::Core::Formatters::GorgonRspecFormatter
4
+
5
+ describe RSpec::Core::Formatters::GorgonRspecFormatter do
6
+ let(:example) {stub("Example", :description => "description",
7
+ :full_description => "Full_Description",
8
+ :metadata => {:file_path => "path/to/file", :line_number => 2},
9
+ :execution_result => {:status => "passed"}, :exception => nil)}
10
+ let(:fail_example) {stub("Example", :description => "description",
11
+ :full_description => "Full_Description",
12
+ :metadata => {:file_path => "path/to/file", :line_number => 2},
13
+ :execution_result => {:status => "failed"}, :exception => nil)}
14
+
15
+ let(:exception) { stub("Exception", :class => Object, :message => "some msg",
16
+ :backtrace => "backtrace")}
17
+
18
+ let(:output) { stub("StringIO", :write => nil, :close => nil) }
19
+
20
+ before do
21
+ @formatter = BaseFormatter.new(output)
22
+ end
23
+
24
+ it "returns an array of hashes when there are failures" do
25
+ @formatter.stub!(:examples).and_return([example, fail_example])
26
+
27
+ expected_result = [{:test_name => "Full_Description: line 2", :description => "description",
28
+ :full_description => "Full_Description", :status => "failed",
29
+ :file_path => "path/to/file", :line_number => 2}]
30
+ output.should_receive(:write).with(expected_result.to_json)
31
+ @formatter.stop
32
+ @formatter.close
33
+ end
34
+
35
+ it "returns an empty array when all examples pass" do
36
+ @formatter.stub!(:examples).and_return([example, example])
37
+
38
+ output.should_receive(:write).with("[]")
39
+ @formatter.stop
40
+ @formatter.close
41
+ end
42
+
43
+ it "returns an empty array when all examples are pending" do
44
+ example.stub!(:execution_result).and_return(:status => "pending")
45
+ @formatter.stub!(:examples).and_return([example, example])
46
+
47
+ output.should_receive(:write).with("[]")
48
+ @formatter.stop
49
+ @formatter.close
50
+ end
51
+
52
+ it "returns exception details if there is an exception" do
53
+ fail_example.stub!(:exception).and_return(exception)
54
+ @formatter.stub!(:examples).and_return([fail_example])
55
+ expected_result = [{:test_name => "Full_Description: line 2", :description => "description",
56
+ :full_description => "Full_Description", :status => "failed",
57
+ :file_path => "path/to/file", :line_number => 2, :class => Object.name,
58
+ :message => "some msg", :location => "backtrace"}]
59
+ output.should_receive(:write).with(expected_result.to_json)
60
+ @formatter.stop
61
+ @formatter.close
62
+ end
63
+ end
@@ -2,6 +2,10 @@ require 'gorgon/progress_bar_view'
2
2
  require 'gorgon/job_state'
3
3
 
4
4
  describe ProgressBarView do
5
+ before do
6
+ EventMachine::PeriodicTimer.stub(:new)
7
+ end
8
+
5
9
  describe "#initialize" do
6
10
  it "adds itself to observers of job_state" do
7
11
  job_state = JobState.new 1
@@ -0,0 +1,41 @@
1
+ require 'gorgon/rspec_runner'
2
+
3
+ describe RspecRunner do
4
+
5
+ subject {RspecRunner}
6
+ it {should respond_to(:run_file).with(1).argument}
7
+ it {should respond_to(:runner).with(0).argument}
8
+
9
+ describe "#run_file" do
10
+ before do
11
+ RSpec::Core::Runner.stub(:run)
12
+ end
13
+
14
+ it "uses Rspec runner to run filename and uses the correct options" do
15
+ RSpec::Core::Runner.should_receive(:run).with(["-f",
16
+ "RSpec::Core::Formatters::GorgonRspecFormatter",
17
+ "file"], anything, anything)
18
+ RspecRunner.run_file "file"
19
+ end
20
+
21
+ it "passes StringIO's (or something similar) to rspec runner" do
22
+ RSpec::Core::Runner.should_receive(:run).with(anything,
23
+ duck_type(:read, :write, :close),
24
+ duck_type(:read, :write, :close))
25
+ RspecRunner.run_file "file"
26
+ end
27
+
28
+ it "parses the output of the Runner and returns it" do
29
+ str_io = stub("StringIO", :rewind => nil, :read => :content)
30
+ StringIO.stub!(:new).and_return(str_io)
31
+ Yajl::Parser.any_instance.should_receive(:parse).with(:content).and_return :result
32
+ RspecRunner.run_file("file").should == :result
33
+ end
34
+ end
35
+
36
+ describe "#runner" do
37
+ it "returns :rspec" do
38
+ RspecRunner.runner.should == :rspec
39
+ end
40
+ end
41
+ end
data/spec/worker_spec.rb CHANGED
@@ -14,7 +14,7 @@ end
14
14
  describe Worker do
15
15
  WORKER_ID = 1
16
16
  let(:file_queue) { double("Queue") }
17
- let(:reply_exchange) { double("Exchange") }
17
+ let(:reply_exchange) { double("Exchange", :publish => nil) }
18
18
  let(:fake_amqp) { fake_amqp = FakeAmqp.new file_queue, reply_exchange }
19
19
  let(:test_runner) { double("Test Runner") }
20
20
  let(:callback_handler) { stub("Callback Handler", :before_start => nil, :after_complete => nil) }
@@ -28,7 +28,6 @@ describe Worker do
28
28
  :file_queue_name => "queue",
29
29
  :reply_exchange_name => "exchange",
30
30
  :worker_id => WORKER_ID,
31
- :test_runner => test_runner,
32
31
  :callback_handler => callback_handler,
33
32
  :log_file => "path/to/log_file"
34
33
  }
@@ -73,7 +72,6 @@ few lines of output and send it to originator. Order matters" do
73
72
 
74
73
  it "creates a new worker" do
75
74
  JobDefinition.stub!(:new).and_return job_definition
76
- stub_const("WorkUnit", test_runner)
77
75
  Worker.should_receive(:new).with(params)
78
76
  Worker.build 1, config
79
77
  end
@@ -81,14 +79,15 @@ few lines of output and send it to originator. Order matters" do
81
79
 
82
80
  describe '#work' do
83
81
  before do
82
+ stub_const("TestRunner", test_runner)
84
83
  Worker.any_instance.stub(:initialize_logger)
84
+ @worker = Worker.new params
85
85
  end
86
86
 
87
87
  it 'should do nothing if the file queue is empty' do
88
88
  file_queue.should_receive(:pop).and_return(nil)
89
89
 
90
- worker = Worker.new params
91
- worker.work
90
+ @worker.work
92
91
  end
93
92
 
94
93
  it "should send start message when file queue is not empty" do
@@ -100,11 +99,9 @@ few lines of output and send it to originator. Order matters" do
100
99
  end
101
100
  reply_exchange.should_receive(:publish).with(any_args())
102
101
 
103
- test_runner.should_receive(:run_file).with("testfile1").and_return({:type => :pass, :time => 0})
102
+ test_runner.stub!(:run_file).and_return({:type => :pass, :time => 0})
104
103
 
105
- worker = Worker.new params
106
-
107
- worker.work
104
+ @worker.work
108
105
  end
109
106
 
110
107
  it "should send finish message when test run is successful" do
@@ -117,11 +114,9 @@ few lines of output and send it to originator. Order matters" do
117
114
  msg[:filename].should == 'testfile1'
118
115
  end
119
116
 
120
- test_runner.should_receive(:run_file).with('testfile1').and_return({:type => :pass, :time => 0})
121
-
122
- worker = Worker.new params
117
+ test_runner.stub!(:run_file).and_return({:type => :pass, :time => 0})
123
118
 
124
- worker.work
119
+ @worker.work
125
120
  end
126
121
 
127
122
  it "should send finish message when test run has failures" do
@@ -137,31 +132,36 @@ few lines of output and send it to originator. Order matters" do
137
132
  msg[:failures].should == failures
138
133
  end
139
134
 
140
- test_runner.should_receive(:run_file).and_return({:type => :fail, :time => 0, :failures => failures})
141
-
142
- worker = Worker.new params
135
+ test_runner.stub!(:run_file).and_return({:type => :fail, :time => 0, :failures => failures})
143
136
 
144
- worker.work
137
+ @worker.work
145
138
  end
146
139
 
147
140
  it "should notify the callback framework that it has started" do
148
141
  file_queue.stub(:pop => nil)
149
142
  callback_handler.should_receive(:before_start)
150
143
 
151
- worker = Worker.new params
152
-
153
- worker.work
144
+ @worker.work
154
145
  end
155
146
 
156
147
  it "should notify the callback framework when it finishes" do
157
148
  file_queue.stub(:pop => nil)
158
149
  callback_handler.should_receive(:after_complete)
159
150
 
160
- worker = Worker.new params
151
+ @worker.work
152
+ end
161
153
 
162
- worker.work
154
+ it "runs file using TestUnitRunner when test is unit test" do
155
+ file_queue.stub!(:pop).and_return("file_test.rb", nil)
156
+ test_runner.should_receive(:run_file).with("file_test.rb", TestUnitRunner).and_return({})
157
+ @worker.work
163
158
  end
164
159
 
160
+ it "runs file using RspecRunner when file is a spec (finishes in _spec.rb)" do
161
+ file_queue.stub!(:pop).and_return("file_spec.rb", nil)
162
+ test_runner.should_receive(:run_file).with("file_spec.rb", RspecRunner).and_return({})
163
+ @worker.work
164
+ end
165
165
  end
166
166
 
167
167
  private
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gorgon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,10 +13,10 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2012-10-03 00:00:00.000000000 Z
16
+ date: 2012-10-05 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
- name: rspec
19
+ name: rake
20
20
  requirement: !ruby/object:Gem::Requirement
21
21
  none: false
22
22
  requirements:
@@ -32,7 +32,7 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  - !ruby/object:Gem::Dependency
35
- name: rake
35
+ name: test-unit
36
36
  requirement: !ruby/object:Gem::Requirement
37
37
  none: false
38
38
  requirements:
@@ -47,6 +47,22 @@ dependencies:
47
47
  - - ! '>='
48
48
  - !ruby/object:Gem::Version
49
49
  version: '0'
50
+ - !ruby/object:Gem::Dependency
51
+ name: rspec
52
+ requirement: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ version: 2.11.0
58
+ type: :development
59
+ prerelease: false
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 2.11.0
50
66
  - !ruby/object:Gem::Dependency
51
67
  name: amqp
52
68
  requirement: !ruby/object:Gem::Requirement
@@ -127,22 +143,6 @@ dependencies:
127
143
  - - ~>
128
144
  - !ruby/object:Gem::Version
129
145
  version: 2.1.3
130
- - !ruby/object:Gem::Dependency
131
- name: test-unit
132
- requirement: !ruby/object:Gem::Requirement
133
- none: false
134
- requirements:
135
- - - ! '>='
136
- - !ruby/object:Gem::Version
137
- version: '0'
138
- type: :runtime
139
- prerelease: false
140
- version_requirements: !ruby/object:Gem::Requirement
141
- none: false
142
- requirements:
143
- - - ! '>='
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
146
  - !ruby/object:Gem::Dependency
147
147
  name: bunny
148
148
  requirement: !ruby/object:Gem::Requirement
@@ -220,6 +220,7 @@ files:
220
220
  - lib/gorgon/g_logger.rb
221
221
  - lib/gorgon/gem_command_handler.rb
222
222
  - lib/gorgon/gem_service.rb
223
+ - lib/gorgon/gorgon_rspec_formatter.rb
223
224
  - lib/gorgon/host_state.rb
224
225
  - lib/gorgon/job.rb
225
226
  - lib/gorgon/job_definition.rb
@@ -231,6 +232,7 @@ files:
231
232
  - lib/gorgon/ping_service.rb
232
233
  - lib/gorgon/pipe_forker.rb
233
234
  - lib/gorgon/progress_bar_view.rb
235
+ - lib/gorgon/rspec_runner.rb
234
236
  - lib/gorgon/source_tree_syncer.rb
235
237
  - lib/gorgon/testunit_runner.rb
236
238
  - lib/gorgon/version.rb
@@ -241,6 +243,7 @@ files:
241
243
  - spec/failures_printer_spec.rb
242
244
  - spec/gem_command_handler_spec.rb
243
245
  - spec/gem_service_spec.rb
246
+ - spec/gorgon_rspec_formatter_spec.rb
244
247
  - spec/host_state_spec.rb
245
248
  - spec/job_definition_spec.rb
246
249
  - spec/job_state_spec.rb
@@ -251,6 +254,7 @@ files:
251
254
  - spec/ping_service_spec.rb
252
255
  - spec/pipe_forker_spec.rb
253
256
  - spec/progress_bar_view_spec.rb
257
+ - spec/rspec_runner_spec.rb
254
258
  - spec/source_tree_syncer_spec.rb
255
259
  - spec/worker_manager_spec.rb
256
260
  - spec/worker_spec.rb