gorgon 0.3.0 → 0.3.1

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