specjour 0.2.5 → 0.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/History.markdown +51 -20
  2. data/README.markdown +53 -26
  3. data/Rakefile +3 -5
  4. data/VERSION +1 -1
  5. data/bin/specjour +1 -48
  6. data/lib/specjour/cli.rb +97 -0
  7. data/lib/specjour/configuration.rb +73 -0
  8. data/lib/specjour/connection.rb +1 -1
  9. data/lib/specjour/cucumber/distributed_formatter.rb +2 -5
  10. data/lib/specjour/cucumber/preloader.rb +13 -0
  11. data/lib/specjour/cucumber.rb +3 -2
  12. data/lib/specjour/db_scrub.rb +8 -1
  13. data/lib/specjour/dispatcher.rb +99 -36
  14. data/lib/specjour/manager.rb +63 -37
  15. data/lib/specjour/printer.rb +33 -11
  16. data/lib/specjour/quiet_fork.rb +11 -0
  17. data/lib/specjour/rspec/distributed_formatter.rb +4 -15
  18. data/lib/specjour/rspec/preloader.rb +8 -0
  19. data/lib/specjour/rspec.rb +1 -0
  20. data/lib/specjour/rsync_daemon.rb +1 -1
  21. data/lib/specjour/socket_helper.rb +28 -0
  22. data/lib/specjour/worker.rb +42 -25
  23. data/lib/specjour.rb +13 -5
  24. data/spec/spec_helper.rb +12 -0
  25. data/spec/specjour/cli_spec.rb +104 -0
  26. data/spec/specjour/configuration_spec.rb +112 -0
  27. data/spec/{cpu_spec.rb → specjour/cpu_spec.rb} +0 -0
  28. data/spec/{manager_spec.rb → specjour/manager_spec.rb} +2 -2
  29. data/spec/specjour/printer_spec.rb +101 -0
  30. data/spec/{rsync_daemon_spec.rb → specjour/rsync_daemon_spec.rb} +2 -0
  31. data/spec/specjour_spec.rb +13 -2
  32. data/specjour.gemspec +33 -26
  33. metadata +69 -31
  34. data/lib/specjour/cucumber/dispatcher.rb +0 -18
  35. data/lib/specjour/cucumber/printer.rb +0 -9
  36. data/lib/specjour/socket_helpers.rb +0 -11
  37. data/lib/specjour/tasks/dispatch.rake +0 -21
  38. data/lib/specjour/tasks/specjour.rb +0 -1
  39. data/rails/init.rb +0 -6
  40. data/spec/lib/specjour/worker_spec.rb +0 -14
data/lib/specjour.rb CHANGED
@@ -7,32 +7,35 @@ autoload :Timeout, 'timeout'
7
7
  autoload :Benchmark, 'benchmark'
8
8
  autoload :Logger, 'logger'
9
9
  autoload :Socket, 'socket'
10
+ autoload :StringIO, 'stringio'
10
11
 
11
12
  module Specjour
13
+ autoload :CLI, 'specjour/cli'
12
14
  autoload :CPU, 'specjour/cpu'
15
+ autoload :Configuration, 'specjour/configuration'
13
16
  autoload :Connection, 'specjour/connection'
17
+ autoload :DbScrub, 'specjour/db_scrub'
14
18
  autoload :Dispatcher, 'specjour/dispatcher'
15
19
  autoload :Manager, 'specjour/manager'
16
20
  autoload :OpenStruct, 'ostruct'
17
21
  autoload :Printer, 'specjour/printer'
18
22
  autoload :Protocol, 'specjour/protocol'
23
+ autoload :QuietFork, 'specjour/quiet_fork'
19
24
  autoload :RsyncDaemon, 'specjour/rsync_daemon'
20
- autoload :SocketHelpers, 'specjour/socket_helpers'
25
+ autoload :SocketHelper, 'specjour/socket_helper'
21
26
  autoload :Worker, 'specjour/worker'
22
27
 
23
28
  autoload :Cucumber, 'specjour/cucumber'
24
29
  autoload :Rspec, 'specjour/rspec'
25
30
 
26
- VERSION = "0.2.5".freeze
27
-
28
- class Error < StandardError; end
31
+ VERSION = "0.3.0.rc1".freeze
29
32
 
30
33
  def self.logger
31
34
  @logger ||= new_logger
32
35
  end
33
36
 
34
37
  def self.new_logger(level = Logger::UNKNOWN)
35
- @logger = Logger.new $stdout
38
+ @logger = Logger.new $stderr
36
39
  @logger.level = level
37
40
  @logger
38
41
  end
@@ -40,4 +43,9 @@ module Specjour
40
43
  def self.log?
41
44
  logger.level != Logger::UNKNOWN
42
45
  end
46
+
47
+ Error = Class.new(StandardError)
48
+ PROGRAM_NAME = $PROGRAM_NAME # keep a reference of the original program name
49
+
50
+ GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
43
51
  end
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,18 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require 'specjour'
4
4
  require 'spec/autorun'
5
5
 
6
+ class NullObject
7
+ def method_missing(name, *args)
8
+ self
9
+ end
10
+ end
11
+
12
+ begin
13
+ Specjour::DbScrub
14
+ rescue LoadError
15
+ $stderr.puts "DbScrub failed to load properly, that's okay though"
16
+ end
17
+
6
18
  Spec::Runner.configure do |config|
7
19
  config.mock_with :rr
8
20
  end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ describe Specjour::CLI do
4
+ let(:fake_pid) { 100_000_000 }
5
+ before do
6
+ stub(Specjour::CPU).cores.returns(27)
7
+ stub(Specjour::Dispatcher).new.returns(stub!)
8
+ stub(Specjour::Manager).new.returns(stub!)
9
+ stub(Specjour::Worker).new.returns(stub!)
10
+ end
11
+
12
+ describe "#listen" do
13
+ let(:manager) { NullObject.new }
14
+
15
+ before do
16
+ stub(Dir).pwd { '/home/someone/foo-bar' }
17
+ end
18
+
19
+ def manager_receives_options(options)
20
+ expected_options = hash_including(options)
21
+ mock(Specjour::Manager).new(expected_options).returns(manager)
22
+ end
23
+
24
+ it "defaults workers to system cores" do
25
+ manager_receives_options("worker_size" => 27)
26
+ Specjour::CLI.start %w(listen -p none)
27
+ end
28
+
29
+ it "accepts an array of projects to listen to" do
30
+ manager_receives_options("registered_projects" => %w(one two three))
31
+ Specjour::CLI.start %w(listen --projects one two three)
32
+ end
33
+
34
+ it "listens to the current path by default" do
35
+ manager_receives_options("registered_projects" => %w(foo-bar))
36
+ Specjour::CLI.start %w(listen)
37
+ end
38
+ end
39
+
40
+ describe "#dispatch" do
41
+ let(:dispatcher) { NullObject.new }
42
+
43
+ def dispatcher_receives_options(options)
44
+ expected_options = hash_including(options)
45
+ mock(Specjour::Dispatcher).new(expected_options).returns(dispatcher)
46
+ end
47
+
48
+ it "defaults path to the current directory" do
49
+ stub(Dir).pwd.returns("eh")
50
+ dispatcher_receives_options("project_path" => "eh")
51
+ Specjour::CLI.start %w(dispatch)
52
+ end
53
+
54
+ it "defaults workers to system cores" do
55
+ dispatcher_receives_options("worker_size" => 27)
56
+ Specjour::CLI.start %w(dispatch)
57
+ end
58
+
59
+ it "accepts a project alias" do
60
+ dispatcher_receives_options("project_alias" => "eh")
61
+ Specjour::CLI.start %w(dispatch --alias eh)
62
+ end
63
+ end
64
+
65
+ describe "#work" do
66
+ it "starts a worker with the required parameters" do
67
+ worker = NullObject.new
68
+ args = {'project_path' => "eh", 'printer_uri' => "specjour://1.1.1.1:12345", 'number' => 1, 'task' => 'run_tests'}
69
+ mock(Specjour::Worker).new(hash_including(args)).returns(worker)
70
+ Specjour::CLI.start %w(work --project-path eh --printer-uri specjour://1.1.1.1:12345 --number 1 --task run_tests)
71
+ end
72
+ end
73
+
74
+ describe "#handle_logging" do
75
+ before do
76
+ stub(subject).options.returns({})
77
+ end
78
+
79
+ it "enables logging" do
80
+ subject.options['log'] = true
81
+ mock(Specjour).new_logger(Logger::DEBUG).returns(stub!)
82
+ subject.send(:handle_logging)
83
+ end
84
+
85
+ it "doesn't enable logging" do
86
+ dont_allow(Specjour).new_logger
87
+ subject.send(:handle_logging)
88
+ end
89
+ end
90
+
91
+ describe "#prepare" do
92
+ let(:dispatcher) { NullObject.new }
93
+
94
+ def dispatcher_receives_options(options)
95
+ expected_options = hash_including(options)
96
+ mock(Specjour::Dispatcher).new(expected_options).returns(dispatcher)
97
+ end
98
+
99
+ it "sets the worker task to 'prepare'" do
100
+ dispatcher_receives_options("worker_task" => "prepare")
101
+ Specjour::CLI.start %w(prepare)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ module RailsAndActiveRecordDefined
4
+ def self.extended(base)
5
+ base.class_eval do
6
+ before do
7
+ Object.const_set(:Rails, Module.new)
8
+ Object.const_set(:ActiveRecord, Module.new)
9
+ ActiveRecord.const_set(:Base, Class.new)
10
+ end
11
+
12
+ after do
13
+ Object.send(:remove_const, :ActiveRecord)
14
+ Object.send(:remove_const, :Rails)
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ describe Specjour::Configuration do
21
+ subject do
22
+ Specjour::Configuration
23
+ end
24
+
25
+ before { subject.reset }
26
+
27
+ describe "#before_fork" do
28
+ context "default proc" do
29
+ context "ActiveRecord defined" do
30
+ extend RailsAndActiveRecordDefined
31
+ it "disconnects from the database" do
32
+ mock(ActiveRecord::Base).remove_connection
33
+ subject.before_fork.call
34
+ end
35
+ end
36
+
37
+ context "bundler installed" do
38
+ before do
39
+ mock(subject).system("which bundle") { true }
40
+ end
41
+
42
+ context "when gems not satisfied" do
43
+ before do
44
+ mock(subject).system("bundle check") { false }
45
+ end
46
+
47
+ it "runs 'bundle install'" do
48
+ mock(subject).system('bundle install')
49
+ subject.before_fork.call
50
+ end
51
+ end
52
+
53
+ context "when gems are satisfied" do
54
+ before do
55
+ mock(subject).system("bundle check") { true }
56
+ end
57
+
58
+ it "doesn't run 'bundle install'" do
59
+ dont_allow(subject).system('bundle install')
60
+ subject.before_fork.call
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ context "custom proc" do
67
+ it "runs block" do
68
+ subject.before_fork = lambda { :custom_before }
69
+ subject.before_fork.call.should == :custom_before
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#after_fork" do
75
+ it "defaults to nothing" do
76
+ subject.after_fork.call.should be_nil
77
+ end
78
+
79
+ it "runs the block" do
80
+ subject.after_fork = lambda { :custom_after }
81
+ subject.after_fork.call.should == :custom_after
82
+ end
83
+
84
+ context "ActiveRecord defined" do
85
+ extend RailsAndActiveRecordDefined
86
+ it "scrubs the db" do
87
+ mock(Specjour::DbScrub).scrub
88
+ subject.after_fork.call
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "#prepare" do
94
+ it "defaults to nothing" do
95
+ subject.prepare.call.should be_nil
96
+ end
97
+
98
+ it "runs the block" do
99
+ subject.prepare = lambda { :custom_preparation }
100
+ subject.prepare.call.should == :custom_preparation
101
+ end
102
+
103
+ context "ActiveRecord defined" do
104
+ extend RailsAndActiveRecordDefined
105
+ it "drops then scrubs the db" do
106
+ mock(Specjour::DbScrub).drop
107
+ mock(Specjour::DbScrub).scrub
108
+ subject.prepare.call
109
+ end
110
+ end
111
+ end
112
+ end
File without changes
@@ -2,8 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  describe Specjour::Manager do
4
4
  describe "#available_for?" do
5
- it "is available for all projects by default" do
6
- subject.available_for?(rand.to_s).should be_true
5
+ it "isn't available for all projects by default" do
6
+ subject.available_for?(rand.to_s).should be_false
7
7
  end
8
8
 
9
9
  it "is available for one project" do
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe Specjour::Printer do
4
+ subject do
5
+ Specjour::Printer.new []
6
+ end
7
+
8
+ describe "#exit_status" do
9
+ let(:rspec_report) { Object.new }
10
+ let(:cucumber_report) { Object.new }
11
+
12
+ context "when cucumber_report is nil" do
13
+ context "and rspec_report has true exit status" do
14
+ before do
15
+ stub(rspec_report).exit_status { true }
16
+ subject.instance_variable_set(:@rspec_report, rspec_report)
17
+ end
18
+
19
+ it "has a true exit status" do
20
+ subject.exit_status.should be_true
21
+ end
22
+ end
23
+
24
+ context "and rspec_report has false exit status" do
25
+ before do
26
+ stub(rspec_report).exit_status { false }
27
+ subject.instance_variable_set(:@rspec_report, rspec_report)
28
+ end
29
+
30
+ it "has a true exit status" do
31
+ subject.exit_status.should be_false
32
+ end
33
+ end
34
+ end
35
+
36
+ context "when rspec report is nil" do
37
+ context "and cucumber_report has true exit status" do
38
+ before do
39
+ stub(cucumber_report).exit_status { true }
40
+ subject.instance_variable_set(:@cucumber_report, cucumber_report)
41
+ end
42
+
43
+ it "has a true exit status" do
44
+ subject.exit_status.should be_true
45
+ end
46
+ end
47
+
48
+ context "and cucumber_report has false exit status" do
49
+ before do
50
+ stub(cucumber_report).exit_status { false }
51
+ subject.instance_variable_set(:@cucumber_report, cucumber_report)
52
+ end
53
+
54
+ it "has a true exit status" do
55
+ subject.exit_status.should be_false
56
+ end
57
+ end
58
+ end
59
+
60
+ context "when both rspec and cucumber reports exists" do
61
+ context "and rspec exit status is false" do
62
+ before do
63
+ stub(rspec_report).exit_status { false }
64
+ stub(cucumber_report).exit_status { true }
65
+ subject.instance_variable_set(:@cucumber_report, cucumber_report)
66
+ subject.instance_variable_set(:@rspec_report, rspec_report)
67
+ end
68
+
69
+ it "returns false" do
70
+ subject.exit_status.should be_false
71
+ end
72
+ end
73
+
74
+ context "and cucumber exit status is false" do
75
+ before do
76
+ stub(rspec_report).exit_status { true }
77
+ stub(cucumber_report).exit_status { false }
78
+ subject.instance_variable_set(:@cucumber_report, cucumber_report)
79
+ subject.instance_variable_set(:@rspec_report, rspec_report)
80
+ end
81
+
82
+ it "returns false" do
83
+ subject.exit_status.should be_false
84
+ end
85
+ end
86
+
87
+ context "both cucumber and rspec exit status are true" do
88
+ before do
89
+ stub(rspec_report).exit_status { true }
90
+ stub(cucumber_report).exit_status { true }
91
+ subject.instance_variable_set(:@cucumber_report, cucumber_report)
92
+ subject.instance_variable_set(:@rspec_report, rspec_report)
93
+ end
94
+
95
+ it "returns false" do
96
+ subject.exit_status.should be_true
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -11,6 +11,8 @@ describe Specjour::RsyncDaemon do
11
11
  stub(Dir).chdir
12
12
  stub(File).open
13
13
  stub(File).read
14
+ stub(FileUtils).rm
15
+ stub(Process).kill
14
16
  end
15
17
 
16
18
  specify { subject.config_directory.should == '/tmp/seasonal/.specjour' }
@@ -1,5 +1,16 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
+
3
+ class CustomException < RuntimeError
4
+ end
5
+
6
+ def boo
7
+ raise CustomException, 'fails'
8
+ end
2
9
 
3
10
  describe Specjour do
4
- it "lives"
11
+ it "pends as an example"
12
+
13
+ it "fails as an example" do
14
+ boo
15
+ end
5
16
  end
data/specjour.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{specjour}
8
- s.version = "0.2.5"
8
+ s.version = "0.3.0.rc1"
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sandro Turriate"]
12
- s.date = %q{2010-05-13}
12
+ s.date = %q{2010-07-12}
13
13
  s.default_executable = %q{specjour}
14
14
  s.description = %q{Distribute your spec suite amongst your LAN via Bonjour.}
15
15
  s.email = %q{sandro.turriate@gmail.com}
@@ -28,48 +28,52 @@ Gem::Specification.new do |s|
28
28
  "VERSION",
29
29
  "bin/specjour",
30
30
  "lib/specjour.rb",
31
+ "lib/specjour/cli.rb",
32
+ "lib/specjour/configuration.rb",
31
33
  "lib/specjour/connection.rb",
32
34
  "lib/specjour/cpu.rb",
33
35
  "lib/specjour/cucumber.rb",
34
- "lib/specjour/cucumber/dispatcher.rb",
35
36
  "lib/specjour/cucumber/distributed_formatter.rb",
36
37
  "lib/specjour/cucumber/final_report.rb",
37
- "lib/specjour/cucumber/printer.rb",
38
+ "lib/specjour/cucumber/preloader.rb",
38
39
  "lib/specjour/db_scrub.rb",
39
40
  "lib/specjour/dispatcher.rb",
40
41
  "lib/specjour/manager.rb",
41
42
  "lib/specjour/printer.rb",
42
43
  "lib/specjour/protocol.rb",
44
+ "lib/specjour/quiet_fork.rb",
43
45
  "lib/specjour/rspec.rb",
44
46
  "lib/specjour/rspec/distributed_formatter.rb",
45
47
  "lib/specjour/rspec/final_report.rb",
46
48
  "lib/specjour/rspec/marshalable_rspec_failure.rb",
49
+ "lib/specjour/rspec/preloader.rb",
47
50
  "lib/specjour/rsync_daemon.rb",
48
- "lib/specjour/socket_helpers.rb",
49
- "lib/specjour/tasks/dispatch.rake",
50
- "lib/specjour/tasks/specjour.rb",
51
+ "lib/specjour/socket_helper.rb",
51
52
  "lib/specjour/worker.rb",
52
- "rails/init.rb",
53
- "spec/cpu_spec.rb",
54
- "spec/lib/specjour/worker_spec.rb",
55
- "spec/manager_spec.rb",
56
- "spec/rsync_daemon_spec.rb",
57
53
  "spec/spec.opts",
58
54
  "spec/spec_helper.rb",
55
+ "spec/specjour/cli_spec.rb",
56
+ "spec/specjour/configuration_spec.rb",
57
+ "spec/specjour/cpu_spec.rb",
58
+ "spec/specjour/manager_spec.rb",
59
+ "spec/specjour/printer_spec.rb",
60
+ "spec/specjour/rsync_daemon_spec.rb",
59
61
  "spec/specjour_spec.rb",
60
62
  "specjour.gemspec"
61
63
  ]
62
64
  s.homepage = %q{http://github.com/sandro/specjour}
63
65
  s.rdoc_options = ["--charset=UTF-8"]
64
66
  s.require_paths = ["lib"]
65
- s.rubygems_version = %q{1.3.6}
67
+ s.rubygems_version = %q{1.3.7}
66
68
  s.summary = %q{Distribute your spec suite amongst your LAN via Bonjour.}
67
69
  s.test_files = [
68
- "spec/cpu_spec.rb",
69
- "spec/lib/specjour/worker_spec.rb",
70
- "spec/manager_spec.rb",
71
- "spec/rsync_daemon_spec.rb",
72
- "spec/spec_helper.rb",
70
+ "spec/spec_helper.rb",
71
+ "spec/specjour/cli_spec.rb",
72
+ "spec/specjour/configuration_spec.rb",
73
+ "spec/specjour/cpu_spec.rb",
74
+ "spec/specjour/manager_spec.rb",
75
+ "spec/specjour/printer_spec.rb",
76
+ "spec/specjour/rsync_daemon_spec.rb",
73
77
  "spec/specjour_spec.rb"
74
78
  ]
75
79
 
@@ -77,25 +81,28 @@ Gem::Specification.new do |s|
77
81
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
78
82
  s.specification_version = 3
79
83
 
80
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
84
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
81
85
  s.add_runtime_dependency(%q<dnssd>, ["= 1.3.1"])
82
86
  s.add_runtime_dependency(%q<rspec>, [">= 0"])
87
+ s.add_runtime_dependency(%q<thor>, ["= 0.13.6"])
83
88
  s.add_development_dependency(%q<rspec>, ["= 1.3.0"])
84
- s.add_development_dependency(%q<rr>, ["= 0.10.11"])
85
- s.add_development_dependency(%q<yard>, ["= 0.5.3"])
89
+ s.add_development_dependency(%q<rr>, [">= 0.10.11"])
90
+ s.add_development_dependency(%q<yard>, [">= 0.5.3"])
86
91
  else
87
92
  s.add_dependency(%q<dnssd>, ["= 1.3.1"])
88
93
  s.add_dependency(%q<rspec>, [">= 0"])
94
+ s.add_dependency(%q<thor>, ["= 0.13.6"])
89
95
  s.add_dependency(%q<rspec>, ["= 1.3.0"])
90
- s.add_dependency(%q<rr>, ["= 0.10.11"])
91
- s.add_dependency(%q<yard>, ["= 0.5.3"])
96
+ s.add_dependency(%q<rr>, [">= 0.10.11"])
97
+ s.add_dependency(%q<yard>, [">= 0.5.3"])
92
98
  end
93
99
  else
94
100
  s.add_dependency(%q<dnssd>, ["= 1.3.1"])
95
101
  s.add_dependency(%q<rspec>, [">= 0"])
102
+ s.add_dependency(%q<thor>, ["= 0.13.6"])
96
103
  s.add_dependency(%q<rspec>, ["= 1.3.0"])
97
- s.add_dependency(%q<rr>, ["= 0.10.11"])
98
- s.add_dependency(%q<yard>, ["= 0.5.3"])
104
+ s.add_dependency(%q<rr>, [">= 0.10.11"])
105
+ s.add_dependency(%q<yard>, [">= 0.5.3"])
99
106
  end
100
107
  end
101
108