pipes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +331 -0
- data/Rakefile +8 -0
- data/lib/pipes.rb +46 -0
- data/lib/pipes/resque_hooks.rb +18 -0
- data/lib/pipes/runner.rb +112 -0
- data/lib/pipes/stage_parser.rb +152 -0
- data/lib/pipes/store.rb +122 -0
- data/lib/pipes/utils.rb +7 -0
- data/lib/pipes/version.rb +3 -0
- data/pipes.gemspec +24 -0
- data/spec/mock_jobs.rb +58 -0
- data/spec/pipes/resque_hooks_spec.rb +22 -0
- data/spec/pipes/runner_spec.rb +110 -0
- data/spec/pipes/stage_parser_spec.rb +169 -0
- data/spec/pipes/store_spec.rb +181 -0
- data/spec/pipes/utils_spec.rb +14 -0
- data/spec/pipes_spec.rb +46 -0
- data/spec/spec_helper.rb +13 -0
- metadata +140 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pipes/resque_hooks'
|
3
|
+
|
4
|
+
describe Pipes::ResqueHooks do
|
5
|
+
class ResqueWorker
|
6
|
+
extend Pipes::ResqueHooks
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '.after_perform_pipes' do
|
10
|
+
it 'lets the Redis store know it is finished working' do
|
11
|
+
Pipes::Store.should_receive(:done)
|
12
|
+
ResqueWorker.after_perform_pipes
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.on_failure_pipes' do
|
17
|
+
it 'clears the current job, forfeiting any remaining stages' do
|
18
|
+
Pipes::Store.should_receive(:done)
|
19
|
+
ResqueWorker.on_failure_pipes(Exception.new)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mock_jobs'
|
3
|
+
|
4
|
+
describe Pipes::Runner do
|
5
|
+
|
6
|
+
describe '.run' do
|
7
|
+
|
8
|
+
let(:jobs) { [Writers::ContentWriter, Writers::AnotherContentWriter, Publishers::Publisher] }
|
9
|
+
let(:arg) { 'en-US' }
|
10
|
+
|
11
|
+
before do
|
12
|
+
Pipes.configure do |config|
|
13
|
+
config.stages do
|
14
|
+
content_writers [{Writers::ContentWriter => :publishers}]
|
15
|
+
publishers [Publishers::Publisher]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with dependency resolution turned off' do
|
21
|
+
|
22
|
+
let(:options) { {resolve: false} }
|
23
|
+
|
24
|
+
it 'adds a pipe for all the jobs and runs it, filtering out jobs that are not configured' do
|
25
|
+
pipe = [
|
26
|
+
{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: [arg]}]},
|
27
|
+
{name: :publishers, jobs: [{class: Publishers::Publisher, args: [arg]}]}
|
28
|
+
]
|
29
|
+
|
30
|
+
Pipes::Store.should_receive(:add_pipe).with(pipe, options)
|
31
|
+
Pipes::Runner.run(jobs, arg, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'can be turned off in the config' do
|
35
|
+
original = Pipes.resolve
|
36
|
+
Pipes.resolve = false
|
37
|
+
|
38
|
+
Pipes::Store.should_receive(:add_pipe).with([{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: []}]}], {})
|
39
|
+
Pipes::Runner.run(Writers::ContentWriter)
|
40
|
+
|
41
|
+
Pipes.resolve = original
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'accepts an array of strings of jobs' do
|
45
|
+
Pipes::Store.should_receive(:add_pipe).with([{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: []}]}], options)
|
46
|
+
Pipes::Runner.run(['Writers::ContentWriter'], options)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'accepts an array of symbols referring to stages' do
|
50
|
+
pipe = [
|
51
|
+
{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: []}]},
|
52
|
+
{name: :publishers, jobs: [{class: Publishers::Publisher, args: []}]}
|
53
|
+
]
|
54
|
+
|
55
|
+
Pipes::Store.should_receive(:add_pipe).with(pipe, options)
|
56
|
+
Pipes::Runner.run([:content_writers, :publishers], options)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'accepts a singular class' do
|
60
|
+
Pipes::Store.should_receive(:add_pipe).with([{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: []}]}], options)
|
61
|
+
Pipes::Runner.run(Writers::ContentWriter, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'accepts a singular string referring to a class' do
|
65
|
+
Pipes::Store.should_receive(:add_pipe).with([{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: []}]}], options)
|
66
|
+
Pipes::Runner.run('Writers::ContentWriter', options)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'accepts a symbol referring to a stage' do
|
70
|
+
Pipes::Store.should_receive(:add_pipe).with([{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: []}]}], options)
|
71
|
+
Pipes::Runner.run(:content_writers, options)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'with dependency resolution turned on' do
|
77
|
+
|
78
|
+
let(:options) { {resolve: true} }
|
79
|
+
let(:pipe) {
|
80
|
+
[
|
81
|
+
{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: []}]},
|
82
|
+
{name: :publishers, jobs: [{class: Publishers::Publisher, args: []}]}
|
83
|
+
]
|
84
|
+
}
|
85
|
+
|
86
|
+
it 'includes all dependencies of the provided job' do
|
87
|
+
Pipes::Store.should_receive(:add_pipe).with(pipe, options)
|
88
|
+
Pipes::Runner.run(Writers::ContentWriter, options)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'is the default' do
|
92
|
+
Pipes::Store.should_receive(:add_pipe).with(pipe, {})
|
93
|
+
Pipes::Runner.run(Writers::ContentWriter)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'can overwrite the value defined in the config' do
|
97
|
+
original = Pipes.resolve
|
98
|
+
Pipes.resolve = false
|
99
|
+
|
100
|
+
Pipes::Store.should_receive(:add_pipe).with(pipe, options)
|
101
|
+
Pipes::Runner.run(Writers::ContentWriter, options)
|
102
|
+
|
103
|
+
Pipes.resolve = original
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mock_jobs'
|
3
|
+
|
4
|
+
describe Pipes::StageParser do
|
5
|
+
subject { Pipes::StageParser }
|
6
|
+
|
7
|
+
describe '#stage_names' do
|
8
|
+
it 'returns the name of the stages, in the same order' do
|
9
|
+
stages = {
|
10
|
+
writers: [ Writers::ContentWriter ],
|
11
|
+
publishers: [ Publishers::Publisher ]
|
12
|
+
}
|
13
|
+
|
14
|
+
subject.new(stages).stage_names.should == [:writers, :publishers]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#jobs_in_stage' do
|
19
|
+
it 'returns all jobs for a given stage, without dependents' do
|
20
|
+
stages = {
|
21
|
+
writers: [ { Writers::ContentWriter => Publishers::Publisher } ],
|
22
|
+
publishers: [ Publishers::Publisher ]
|
23
|
+
}
|
24
|
+
|
25
|
+
subject.new(stages).jobs_in_stage(:writers).should == [Writers::ContentWriter]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#dependents_for' do
|
30
|
+
let(:stages) {
|
31
|
+
{
|
32
|
+
writers: [ { Writers::ContentWriter => :publishers } ],
|
33
|
+
publishers: [ Publishers::Publisher => Emailers::Email ],
|
34
|
+
emailers: [ Emailers::Email ]
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
it 'returns an empty array for jobs that do not exist' do
|
39
|
+
subject.new(stages).dependents_for(Writers::AnotherContentWriter).should == []
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns an array containing the recursive dependents' do
|
43
|
+
expected = [Publishers::Publisher, Emailers::Email]
|
44
|
+
|
45
|
+
subject.new(stages).dependents_for(Writers::ContentWriter).should == expected
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#stages_with_resolved_dependencies' do
|
50
|
+
context 'when the stage contains only job classes' do
|
51
|
+
let(:stages) {
|
52
|
+
{
|
53
|
+
writers: [ Writers::ContentWriter ],
|
54
|
+
publishers: [ Publishers::Publisher ]
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
it 'returns a set of nested arrays, keeping the defined order, each representing a stage and its jobs with empty dependents' do
|
59
|
+
expected = {
|
60
|
+
writers: [ { Writers::ContentWriter => [] } ],
|
61
|
+
publishers: [ { Publishers::Publisher => [] } ]
|
62
|
+
}
|
63
|
+
|
64
|
+
subject.new(stages).stages_with_resolved_dependencies.should == expected
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when the stage containing a hash defining a dependent class' do
|
69
|
+
let(:stages) {
|
70
|
+
{ writers: [ { Writers::ContentWriter => Publishers::Publisher } ] }
|
71
|
+
}
|
72
|
+
|
73
|
+
it 'adds the dependent class to the list' do
|
74
|
+
expected = {
|
75
|
+
writers: [ { Writers::ContentWriter => [Publishers::Publisher] } ]
|
76
|
+
}
|
77
|
+
|
78
|
+
subject.new(stages).stages_with_resolved_dependencies.should == expected
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'with the stage containing a hash defining a dependent stage' do
|
83
|
+
let(:stages) {
|
84
|
+
{
|
85
|
+
writers: [ { Writers::ContentWriter => :publishers } ],
|
86
|
+
publishers: [ Publishers::Publisher ]
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
it 'adds all classes within the dependent stage to the list' do
|
91
|
+
expected = {
|
92
|
+
writers: [ { Writers::ContentWriter => [Publishers::Publisher] } ],
|
93
|
+
publishers: [ { Publishers::Publisher => [] } ]
|
94
|
+
}
|
95
|
+
|
96
|
+
subject.new(stages).stages_with_resolved_dependencies.should == expected
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'with the stage containing a hash defining an array of dependent classes' do
|
101
|
+
let(:stages) {
|
102
|
+
{
|
103
|
+
writers: [ { Writers::ContentWriter => [Publishers::Publisher] } ],
|
104
|
+
publishers: [ Publishers::Publisher ]
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
it 'adds all classes within the array to the list' do
|
109
|
+
expected = {
|
110
|
+
writers: [ { Writers::ContentWriter => [Publishers::Publisher] } ],
|
111
|
+
publishers: [ { Publishers::Publisher => [] } ]
|
112
|
+
}
|
113
|
+
|
114
|
+
subject.new(stages).stages_with_resolved_dependencies.should == expected
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'with the stage containing a hash defining an array of dependent stages' do
|
119
|
+
let(:stages) {
|
120
|
+
{
|
121
|
+
writers: [ { Writers::ContentWriter => [:publishers] } ],
|
122
|
+
publishers: [ Publishers::Publisher ]
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
it 'adds all classes within the dependent stages to the list' do
|
127
|
+
expected = {
|
128
|
+
writers: [ { Writers::ContentWriter => [Publishers::Publisher] } ],
|
129
|
+
publishers: [ { Publishers::Publisher => [] } ]
|
130
|
+
}
|
131
|
+
|
132
|
+
subject.new(stages).stages_with_resolved_dependencies.should == expected
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'with a comlex configuration, intermixing dependent types' do
|
137
|
+
let (:stages) {
|
138
|
+
{
|
139
|
+
writers: [ { Writers::ContentWriter => [:publishers, Uploaders::Rsync] },
|
140
|
+
{ Writers::AnotherContentWriter => [Emailers::Email] }
|
141
|
+
],
|
142
|
+
publishers: [ { Publishers::Publisher => :emailers } ],
|
143
|
+
messengers: [ { Messengers::SMS => :uploaders } ],
|
144
|
+
uploaders: [ { Uploaders::Rsync => Notifiers::Twitter } ],
|
145
|
+
emailers: [ Emailers::Email, Emailers::AnotherEmail ],
|
146
|
+
notifiers: [ Notifiers::Twitter ]
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
it 'resolves all dependencies' do
|
151
|
+
expected = {
|
152
|
+
writers: [ { Writers::ContentWriter => [Publishers::Publisher, Emailers::Email, Emailers::AnotherEmail,
|
153
|
+
Uploaders::Rsync, Notifiers::Twitter] },
|
154
|
+
{ Writers::AnotherContentWriter => [Emailers::Email] }
|
155
|
+
],
|
156
|
+
publishers: [ { Publishers::Publisher => [Emailers::Email, Emailers::AnotherEmail] } ],
|
157
|
+
messengers: [ { Messengers::SMS => [Uploaders::Rsync, Notifiers::Twitter] } ],
|
158
|
+
uploaders: [ { Uploaders::Rsync => [Notifiers::Twitter] } ],
|
159
|
+
emailers: [ { Emailers::Email => [] },
|
160
|
+
{ Emailers::AnotherEmail => [] }
|
161
|
+
],
|
162
|
+
notifiers: [ { Notifiers::Twitter => [] } ]
|
163
|
+
}
|
164
|
+
|
165
|
+
subject.new(stages).stages_with_resolved_dependencies.should == expected
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mock_jobs'
|
3
|
+
|
4
|
+
describe Pipes::Store do
|
5
|
+
|
6
|
+
def mock_stages
|
7
|
+
Pipes::Store.stub!(:stages) { stages }
|
8
|
+
stages
|
9
|
+
end
|
10
|
+
|
11
|
+
def mock_pending_jobs(stage)
|
12
|
+
list = send("pending_jobs_#{stage}".to_sym)
|
13
|
+
Pipes::Store.stub!(:pending_jobs).with(stage) { list }
|
14
|
+
list
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:stages) { [] }
|
18
|
+
let(:pending_jobs_content_writers) { [] }
|
19
|
+
let(:pending_jobs_publishers) { [] }
|
20
|
+
|
21
|
+
let(:job_options) { 'en-US' }
|
22
|
+
let(:pipe) { [{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: [job_options]}]},
|
23
|
+
{name: :publishers, jobs: [{class: Publishers::Publisher, args: [job_options]}]}] }
|
24
|
+
|
25
|
+
before do
|
26
|
+
Pipes::Store.clear_all
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '.add_pipe' do
|
30
|
+
before do
|
31
|
+
@writers = mock_pending_jobs(:content_writers)
|
32
|
+
@publishers = mock_pending_jobs(:publishers)
|
33
|
+
Pipes::Store.stub!(:next_stage)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'adds the job to Redis and fires off the next available stage' do
|
37
|
+
Pipes::Store.should_receive(:next_stage)
|
38
|
+
Pipes::Store.add_pipe(pipe)
|
39
|
+
|
40
|
+
@writers.should == [{class: Writers::ContentWriter, args: [job_options]}]
|
41
|
+
@publishers.should == [{class: Publishers::Publisher, args: [job_options]}]
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'does not add duplicate jobs to stages' do
|
45
|
+
another_pipe = [{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: [job_options]},
|
46
|
+
{class: Writers::AnotherContentWriter, args: [job_options]}]},
|
47
|
+
{name: :publishers, jobs: [{class: Publishers::Publisher, args: [job_options]}]}]
|
48
|
+
|
49
|
+
Pipes::Store.add_pipe(pipe)
|
50
|
+
Pipes::Store.add_pipe(another_pipe)
|
51
|
+
|
52
|
+
@writers.should == [{class: Writers::ContentWriter, args: [job_options]}, {class: Writers::AnotherContentWriter, args: [job_options]}]
|
53
|
+
@publishers.should == [{class: Publishers::Publisher, args: [job_options]}]
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with allow_duplicates set' do
|
57
|
+
it 'does not add jobs that have the same class already in the queue' do
|
58
|
+
mock_stages
|
59
|
+
|
60
|
+
Pipes::Store.add_pipe(pipe)
|
61
|
+
|
62
|
+
@writers.should_receive(:<<)
|
63
|
+
@publishers.should_not_receive(:<<)
|
64
|
+
|
65
|
+
another_pipe = [{name: :content_writers, jobs: [{class: Writers::ContentWriter, args: ['some arg']}]},
|
66
|
+
{name: :publishers, jobs: [{class: Publishers::Publisher, args: ['some arg']}]}]
|
67
|
+
|
68
|
+
Pipes::Store.add_pipe(another_pipe, {allow_duplicates: [:content_writers]})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '.next_stage' do
|
75
|
+
context 'with jobs left in the queue' do
|
76
|
+
it 'pulls the next stage with pending jobs off the queue and runs it' do
|
77
|
+
Pipes::Store.stub!(:stages) { [:content_writers, :publishers] }
|
78
|
+
|
79
|
+
writers = mock_pending_jobs(:content_writers) << {class: Writers::ContentWriter, args: []}
|
80
|
+
publishers = mock_pending_jobs(:publishers) << {class: Publishers::Publisher, args: []}
|
81
|
+
|
82
|
+
Pipes::Store.should_receive(:run_stage).with([{class: Writers::ContentWriter, args: []}])
|
83
|
+
Pipes::Store.should_not_receive(:run_stage).with([{class: Publishers::Publisher, args: []}])
|
84
|
+
|
85
|
+
Pipes::Store.next_stage
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'runs stages in the order determined by the stages list' do
|
89
|
+
Pipes::Store.stub!(:stages) { [:publishers, :content_writers] }
|
90
|
+
|
91
|
+
writers = mock_pending_jobs(:content_writers) << {class: Writers::ContentWriter, args: []}
|
92
|
+
publishers = mock_pending_jobs(:publishers) << {class: Publishers::Publisher, args: []}
|
93
|
+
|
94
|
+
Pipes::Store.should_not_receive(:run_stage).with([{class: Writers::ContentWriter, args: []}])
|
95
|
+
Pipes::Store.should_receive(:run_stage).with([{class: Publishers::Publisher, args: []}])
|
96
|
+
|
97
|
+
Pipes::Store.next_stage
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'without jobs left in the queue' do
|
102
|
+
it 'fires off the next pipe' do
|
103
|
+
mock_stages
|
104
|
+
Pipes::Store.should_not_receive(:run_stage)
|
105
|
+
Pipes::Store.next_stage
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '.run_stage' do
|
111
|
+
it 'sets the remaining counter and enqueues the jobs' do
|
112
|
+
stage = [{class: Writers::ContentWriter, args: [job_options]},
|
113
|
+
{class: Writers::AnotherContentWriter, args: [job_options]}]
|
114
|
+
|
115
|
+
remaining = mock('Remaining Jobs')
|
116
|
+
Pipes::Store.stub!(:remaining_jobs) { remaining }
|
117
|
+
|
118
|
+
remaining.should_receive(:clear)
|
119
|
+
remaining.should_receive(:incr).with(2)
|
120
|
+
|
121
|
+
Resque.should_receive(:enqueue).with(Writers::ContentWriter, 'en-US')
|
122
|
+
Resque.should_receive(:enqueue).with(Writers::AnotherContentWriter, 'en-US')
|
123
|
+
|
124
|
+
Pipes::Store.run_stage(stage)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '.done' do
|
129
|
+
context 'as the last job in a stage' do
|
130
|
+
it 'fires off the next stage' do
|
131
|
+
remaining = mock('Remaining Jobs', {decrement: 0}) { 1 }
|
132
|
+
Pipes::Store.stub!(:remaining_jobs) { remaining }
|
133
|
+
|
134
|
+
Pipes::Store.should_receive(:next_stage)
|
135
|
+
Pipes::Store.done
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'with jobs still running' do
|
140
|
+
it 'decrements the remaining jobs but does not run the next stage' do
|
141
|
+
remaining = mock('Remaining Jobs') { 2 }
|
142
|
+
Pipes::Store.stub!(:remaining_jobs) { remaining }
|
143
|
+
|
144
|
+
remaining.should_receive(:decrement) { 1 }
|
145
|
+
Pipes::Store.should_not_receive(:next_stage)
|
146
|
+
Pipes::Store.done
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '.clear' do
|
152
|
+
it 'clears out the jobs for the given stage' do
|
153
|
+
writers = mock_pending_jobs(:content_writers)
|
154
|
+
writers << {class: Writers::ContentWriter, args: [job_options]}
|
155
|
+
|
156
|
+
Pipes::Store.clear(:content_writers)
|
157
|
+
writers.should == []
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe '.clear_all' do
|
162
|
+
it 'deletes Redis keys for all stages, even those not currently being used' do
|
163
|
+
Redis::List.new('pipes:stages:some_stage_used_for_testing') << 'stategy'
|
164
|
+
Redis::List.new('pipes:stages:any_stage_test') << 'stategy'
|
165
|
+
|
166
|
+
Pipes::Store.clear_all
|
167
|
+
|
168
|
+
Redis::List.new('pipes:stages:some_stage_used_for_testing').should == []
|
169
|
+
Redis::List.new('pipes:stages:any_stage_test').should == []
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'resets the remaining jobs counter' do
|
173
|
+
remaining = mock('Remaining Jobs')
|
174
|
+
Pipes::Store.stub!(:remaining_jobs) { remaining }
|
175
|
+
|
176
|
+
remaining.should_receive(:clear)
|
177
|
+
|
178
|
+
Pipes::Store.clear_all
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|