pipes 0.1.0
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/.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
|