cukeq 0.0.1.dev
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/.autotest +1 -0
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +73 -0
- data/Rakefile +68 -0
- data/VERSION +1 -0
- data/bin/cukeq +34 -0
- data/features/cukeq.feature +15 -0
- data/features/example1.feature +1 -0
- data/features/example2.feature +1 -0
- data/features/step_definitions/cukeq_steps.rb +22 -0
- data/features/support/cukeq_helper.rb +73 -0
- data/features/support/env.rb +13 -0
- data/features/support/report_app.rb +36 -0
- data/lib/cukeq.rb +45 -0
- data/lib/cukeq/broker.rb +65 -0
- data/lib/cukeq/em/system3.rb +53 -0
- data/lib/cukeq/job_clearer.rb +19 -0
- data/lib/cukeq/master.rb +146 -0
- data/lib/cukeq/reporter.rb +22 -0
- data/lib/cukeq/runner.rb +63 -0
- data/lib/cukeq/scenario_exploder.rb +32 -0
- data/lib/cukeq/scenario_runner.rb +134 -0
- data/lib/cukeq/scm.rb +51 -0
- data/lib/cukeq/scm/git_bridge.rb +36 -0
- data/lib/cukeq/scm/shell_svn_bridge.rb +65 -0
- data/lib/cukeq/scm/svn_bridge.rb +77 -0
- data/lib/cukeq/slave.rb +114 -0
- data/lib/cukeq/webapp.rb +38 -0
- data/spec/cukeq/broker_spec.rb +78 -0
- data/spec/cukeq/cukeq_spec.rb +10 -0
- data/spec/cukeq/master_spec.rb +153 -0
- data/spec/cukeq/reporter_spec.rb +29 -0
- data/spec/cukeq/runner_spec.rb +11 -0
- data/spec/cukeq/scenario_exploder_spec.rb +17 -0
- data/spec/cukeq/scenario_runner_spec.rb +32 -0
- data/spec/cukeq/scm/git_bridge_spec.rb +52 -0
- data/spec/cukeq/scm/svn_bridge_spec.rb +5 -0
- data/spec/cukeq/scm_spec.rb +48 -0
- data/spec/cukeq/slave_spec.rb +86 -0
- data/spec/cukeq/webapp_spec.rb +37 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +12 -0
- metadata +228 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe CukeQ::Master do
|
4
|
+
def mock_master
|
5
|
+
CukeQ::Master.new(
|
6
|
+
mock("CukeQ::Broker").as_null_object,
|
7
|
+
mock("CukeQ::WebApp").as_null_object,
|
8
|
+
mock("CukeQ::Scm", :working_copy => ".").as_null_object,
|
9
|
+
mock("CukeQ::Reporter").as_null_object,
|
10
|
+
mock("CukeQ::Exploder").as_null_object
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def running_master
|
15
|
+
master = mock_master
|
16
|
+
master.broker.stub!(:start).and_yield
|
17
|
+
master.start
|
18
|
+
|
19
|
+
master
|
20
|
+
end
|
21
|
+
|
22
|
+
describe ".configured_instance" do
|
23
|
+
it "sets up defaults if --broker is not given" do
|
24
|
+
master = CukeQ::Master.configured_instance(
|
25
|
+
%w[-s git://example.com -r http://cukereports.com]
|
26
|
+
)
|
27
|
+
|
28
|
+
master.broker.host.should == 'localhost'
|
29
|
+
master.broker.port.should == 5672
|
30
|
+
master.broker.user.should == 'cukeq-master'
|
31
|
+
master.broker.pass.should == 'cukeq123'
|
32
|
+
master.broker.vhost.should == '/cukeq'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "adds defaults if the --broker argument is incomplete" do
|
36
|
+
master = CukeQ::Master.configured_instance(
|
37
|
+
%w[--broker amqp://otherhost:9000 -s git://example.com -r http://cukereports.com]
|
38
|
+
)
|
39
|
+
|
40
|
+
master.broker.host.should == 'otherhost'
|
41
|
+
master.broker.port.should == 9000
|
42
|
+
master.broker.user.should == 'cukeq-master'
|
43
|
+
master.broker.pass.should == 'cukeq123'
|
44
|
+
master.broker.vhost.should == '/cukeq'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "sets up defaults if --webapp is not given" do
|
48
|
+
master = CukeQ::Master.configured_instance(
|
49
|
+
%w[-s git://example.com -r http://cukereports.com]
|
50
|
+
)
|
51
|
+
|
52
|
+
master.webapp.uri.host.should == '0.0.0.0'
|
53
|
+
master.webapp.uri.port.should == 9292
|
54
|
+
end
|
55
|
+
|
56
|
+
it "uses the given --webapp" do
|
57
|
+
master = CukeQ::Master.configured_instance(
|
58
|
+
%w[-s git://example.com -r http://cukereports.com -w http://example.com]
|
59
|
+
)
|
60
|
+
|
61
|
+
master.webapp.uri.host.should == 'example.com'
|
62
|
+
master.webapp.uri.port.should == 80
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe ".execute" do
|
67
|
+
it "starts the configured instance" do
|
68
|
+
args = %w[some args]
|
69
|
+
master = mock_master
|
70
|
+
|
71
|
+
CukeQ::Master.should_receive(:configured_instance).with(args).and_return(master)
|
72
|
+
master.should_receive(:start)
|
73
|
+
|
74
|
+
CukeQ::Master.execute(args)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#start" do
|
79
|
+
it "updates, subscribes to the results queue and runs the webapp" do
|
80
|
+
master = CukeQ::Master.new(mock("CukeQ::Broker"), mock("CukeQ::WebApp"), mock("CukeQ::Scm"), nil, nil)
|
81
|
+
|
82
|
+
master.scm.should_receive(:update).and_yield
|
83
|
+
master.broker.should_receive(:start).and_yield
|
84
|
+
master.should_receive(:subscribe)
|
85
|
+
master.webapp.should_receive(:run)
|
86
|
+
|
87
|
+
master.start
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#run" do
|
92
|
+
it "sends the payload to the exploder" do
|
93
|
+
data = { 'features' => ["some.feature:10", "another.feature:12"] }
|
94
|
+
master = running_master
|
95
|
+
|
96
|
+
master.exploder.should_receive(:explode).with(data['features']).and_return([])
|
97
|
+
master.run(data)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "publishes the exploded scenarios on the jobs queue" do
|
101
|
+
jobs = %w[job1 job2 job3 job4]
|
102
|
+
master = running_master
|
103
|
+
|
104
|
+
master.exploder.stub!(:explode).and_yield(jobs)
|
105
|
+
master.broker.should_receive(:publish).exactly(4).times
|
106
|
+
|
107
|
+
master.run({})
|
108
|
+
end
|
109
|
+
|
110
|
+
it "adds a run_id and scm info to the job payload" do
|
111
|
+
jobs = ["job1"]
|
112
|
+
master = running_master
|
113
|
+
|
114
|
+
master.exploder.stub!(:explode).and_yield(jobs)
|
115
|
+
master.scm.stub!(:current_revision).and_return("abadbabe")
|
116
|
+
master.scm.stub!(:url).and_return("git://github.com/jarib/cukeq.git")
|
117
|
+
|
118
|
+
master.broker.should_receive(:publish).with do |queue, json|
|
119
|
+
payload = JSON.parse(json)
|
120
|
+
|
121
|
+
payload['scm']['revision'].should == "abadbabe"
|
122
|
+
payload['scm']['url'].should == "git://github.com/jarib/cukeq.git"
|
123
|
+
payload['run']['id'].should == 1
|
124
|
+
payload['run']['no_of_units'].should == 1
|
125
|
+
end
|
126
|
+
|
127
|
+
master.run({'run_id' => 1})
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#result" do
|
132
|
+
it "sends the result to the reporter" do
|
133
|
+
result = {:some => 'data'}
|
134
|
+
master = running_master
|
135
|
+
master.reporter.should_receive(:report).with(result)
|
136
|
+
|
137
|
+
master.result(result)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "#subscribe" do
|
142
|
+
it "should subscribe to the results queue and process the result" do
|
143
|
+
master = running_master
|
144
|
+
result = '{"some": "result"}'
|
145
|
+
|
146
|
+
master.broker.should_receive(:subscribe).with(:results).and_yield(result)
|
147
|
+
master.should_receive(:result).with("some" => "result")
|
148
|
+
|
149
|
+
master.subscribe
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe CukeQ::Reporter do
|
4
|
+
|
5
|
+
def reporter
|
6
|
+
@reporter ||= CukeQ::Reporter.new(URI.parse("http://example.com/some/path"))
|
7
|
+
end
|
8
|
+
|
9
|
+
it "POSTs results to the given URL" do
|
10
|
+
expected_params = {
|
11
|
+
:host => "example.com",
|
12
|
+
:port => 80,
|
13
|
+
:verb => 'POST',
|
14
|
+
:request => '/some/path',
|
15
|
+
:content => '{"some":"result"}'
|
16
|
+
}
|
17
|
+
|
18
|
+
EM::P::HttpClient.should_receive(:request).with(expected_params)
|
19
|
+
reporter.report("some" => "result")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "catches and logs EM errors" do
|
23
|
+
reporter.should_receive(:log)
|
24
|
+
EM::P::HttpClient.stub!(:request).and_raise(RuntimeError)
|
25
|
+
|
26
|
+
reporter.report(nil)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe CukeQ::ScenarioExploder do
|
4
|
+
|
5
|
+
def exploder
|
6
|
+
CukeQ::ScenarioExploder.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns the parsed features" do
|
10
|
+
# our IO.popen call doesn't work well with rspec - probably a race condition since
|
11
|
+
# it only fails on RCR
|
12
|
+
pending
|
13
|
+
|
14
|
+
# units = exploder.explode("features/example1.feature")
|
15
|
+
# units.first.should == {"file" => "features/example1.feature"}
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe CukeQ::ScenarioRunner do
|
4
|
+
|
5
|
+
def runner
|
6
|
+
@runner ||= CukeQ::ScenarioRunner.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns an error if the job is incorrect" do
|
10
|
+
runner.run({}) do |result|
|
11
|
+
result[:success].should be_false
|
12
|
+
result[:error].should_not be_empty
|
13
|
+
result[:backtrace].should_not be_empty
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "creates a configured and updated Scm instance" do
|
18
|
+
job = {'scm' => {'url' => 'git://example.com/foo/bar', 'revision' => 'some-revision'}}
|
19
|
+
|
20
|
+
CukeQ::Scm.should_receive(:new).with(job['scm']['url']).and_return(mock_scm = mock("scm"))
|
21
|
+
mock_scm.should_receive(:current_revision).and_return 'another-revision'
|
22
|
+
mock_scm.should_receive(:update).and_yield
|
23
|
+
|
24
|
+
runner.scm_for(job).should == mock_scm
|
25
|
+
end
|
26
|
+
|
27
|
+
# important.
|
28
|
+
it "executes the given job" do
|
29
|
+
pending
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path("../../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe CukeQ::Scm::GitBridge do
|
4
|
+
include FileUtils
|
5
|
+
|
6
|
+
GIT_URL = "git://example.com"
|
7
|
+
WORKING_COPY = "spec-scm-repo"
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
rm_rf WORKING_COPY
|
11
|
+
end
|
12
|
+
|
13
|
+
def mock_repo
|
14
|
+
@mock_repo ||= mock("Git::Base").as_null_object
|
15
|
+
end
|
16
|
+
|
17
|
+
def bridge
|
18
|
+
@bridge ||= CukeQ::Scm::GitBridge.new(GIT_URL, WORKING_COPY)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "clones the repo of it doesn't exist" do
|
22
|
+
Git.stub!(:open)
|
23
|
+
Git.should_receive(:clone).with(GIT_URL, WORKING_COPY)
|
24
|
+
bridge.repo
|
25
|
+
end
|
26
|
+
|
27
|
+
it "does not clone the repo if it already exists" do
|
28
|
+
Git.stub!(:open)
|
29
|
+
Git.should_receive(:clone).never
|
30
|
+
|
31
|
+
mkdir WORKING_COPY
|
32
|
+
bridge.repo
|
33
|
+
end
|
34
|
+
|
35
|
+
it "fetches the current revision" do
|
36
|
+
bridge.stub!(:repo).and_return(mock_repo)
|
37
|
+
mock_repo.should_receive(:revparse).with("HEAD").and_return("rev")
|
38
|
+
|
39
|
+
bridge.current_revision.should == "rev"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "updates the working copy" do
|
43
|
+
bridge.stub!(:repo).and_return(mock_repo)
|
44
|
+
|
45
|
+
mock_repo.should_receive(:reset_hard)
|
46
|
+
mock_repo.should_receive(:pull)
|
47
|
+
|
48
|
+
bridge.update {}
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe CukeQ::Scm do
|
4
|
+
|
5
|
+
def scm(vcs, mock_bridge = false)
|
6
|
+
scm = case vcs
|
7
|
+
when :git
|
8
|
+
CukeQ::Scm.new("git://github.com/jarib/cukeq.git")
|
9
|
+
when :svn
|
10
|
+
CukeQ::Scm.new("svn://example.com/somerepo/trunk")
|
11
|
+
else
|
12
|
+
raise "unknown vcs: #{vcs.inspect}"
|
13
|
+
end
|
14
|
+
|
15
|
+
if mock_bridge
|
16
|
+
scm.instance_variable_set("@bridge", mock("scm-bridge"))
|
17
|
+
end
|
18
|
+
|
19
|
+
scm
|
20
|
+
end
|
21
|
+
|
22
|
+
it "replaces special characters in the working copy dir" do
|
23
|
+
scm(:git).working_copy.should_not =~ /[^A-z_\/.]/
|
24
|
+
end
|
25
|
+
|
26
|
+
it "creates the correct bridge" do
|
27
|
+
scm(:git).bridge.should be_kind_of(CukeQ::Scm::GitBridge)
|
28
|
+
scm(:svn).bridge.should be_kind_of(CukeQ::Scm::SvnBridge)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "understands http urls" do
|
32
|
+
CukeQ::Scm.new("http://github.com/foo/bar.git").bridge.should be_kind_of(CukeQ::Scm::GitBridge)
|
33
|
+
CukeQ::Scm.new("https://svn.example.com/foo/bar").bridge.should be_kind_of(CukeQ::Scm::SvnBridge)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "forwards update() to the bridge" do
|
37
|
+
scm = scm(:git, true)
|
38
|
+
scm.bridge.should_receive(:update).and_yield
|
39
|
+
scm.update {}
|
40
|
+
end
|
41
|
+
|
42
|
+
it "forwards current_revision() to the bridge" do
|
43
|
+
scm = scm(:git, true)
|
44
|
+
scm.bridge.should_receive(:current_revision)
|
45
|
+
scm.current_revision
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe CukeQ::Slave do
|
4
|
+
|
5
|
+
def mock_slave
|
6
|
+
CukeQ::Slave.new(
|
7
|
+
mock("CukeQ::Broker").as_null_object,
|
8
|
+
mock("CukeQ::ScenarioRunner").as_null_object
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def running_slave
|
13
|
+
slave = mock_slave
|
14
|
+
slave.broker.stub!(:start).and_yield
|
15
|
+
|
16
|
+
slave
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".configured_instance" do
|
20
|
+
it "sets up defaults if --broker is not given" do
|
21
|
+
slave = CukeQ::Slave.configured_instance
|
22
|
+
|
23
|
+
slave.broker.host.should == 'localhost'
|
24
|
+
slave.broker.port.should == 5672
|
25
|
+
slave.broker.user.should == 'cukeq-slave'
|
26
|
+
slave.broker.pass.should == 'cukeq123'
|
27
|
+
slave.broker.vhost.should == '/cukeq'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "adds defaults if the --broker argument is incomplete" do
|
31
|
+
slave = CukeQ::Slave.configured_instance(%w[--broker amqp://otherhost:9000])
|
32
|
+
|
33
|
+
slave.broker.host.should == 'otherhost'
|
34
|
+
slave.broker.port.should == 9000
|
35
|
+
slave.broker.user.should == 'cukeq-slave'
|
36
|
+
slave.broker.pass.should == 'cukeq123'
|
37
|
+
slave.broker.vhost.should == '/cukeq'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe ".execute" do
|
42
|
+
it "starts the configured instance" do
|
43
|
+
args = %w[some args]
|
44
|
+
slave = mock_slave
|
45
|
+
|
46
|
+
CukeQ::Slave.should_receive(:configured_instance).with(args).and_return(slave)
|
47
|
+
slave.should_receive(:start)
|
48
|
+
|
49
|
+
CukeQ::Slave.execute(args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#start" do
|
54
|
+
it "subscribes to the jobs queue" do
|
55
|
+
slave = mock_slave
|
56
|
+
slave.broker.should_receive(:start).and_yield
|
57
|
+
slave.should_receive(:poll)
|
58
|
+
|
59
|
+
slave.start
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#job" do
|
64
|
+
it "runs each job with the scenario runner and publishes each result on the results queue" do
|
65
|
+
slave = running_slave
|
66
|
+
job = {:some => 'job'}
|
67
|
+
result = {:some => 'result'}
|
68
|
+
|
69
|
+
slave.scenario_runner.should_receive(:run).with(job).and_yield(result)
|
70
|
+
slave.should_receive(:publish).with(result)
|
71
|
+
|
72
|
+
slave.job(job)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#publish" do
|
77
|
+
it "it publishes the message on the results queue" do
|
78
|
+
slave = running_slave
|
79
|
+
message = {:run => "some message"}
|
80
|
+
|
81
|
+
slave.broker.should_receive(:publish).with(:results, message.to_json)
|
82
|
+
slave.publish(message)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|