taskinator 0.5.0 → 0.5.2
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.
- checksums.yaml +4 -4
- data/.github/workflows/{taskinator.yml → build.yml} +2 -15
- data/.github/workflows/release.yml +18 -0
- data/CHANGELOG.md +126 -108
- data/Gemfile +1 -1
- data/Gemfile.lock +64 -69
- data/README.md +50 -42
- data/lib/taskinator/builder.rb +129 -0
- data/lib/taskinator/definition.rb +2 -2
- data/lib/taskinator/instrumentation.rb +1 -0
- data/lib/taskinator/persistence.rb +57 -10
- data/lib/taskinator/process.rb +14 -9
- data/lib/taskinator/task.rb +9 -11
- data/lib/taskinator/version.rb +1 -1
- data/lib/taskinator.rb +0 -13
- data/spec/support/test_job.rb +30 -0
- data/spec/support/test_job_task.rb +2 -0
- data/spec/support/test_step_task.rb +2 -0
- data/spec/support/test_subprocess_task.rb +2 -0
- data/spec/taskinator/{definition/builder_spec.rb → builder_spec.rb} +2 -2
- data/spec/taskinator/definition_spec.rb +31 -0
- data/spec/taskinator/instrumentation_spec.rb +3 -2
- data/spec/taskinator/persistence_spec.rb +131 -5
- data/spec/taskinator/process_spec.rb +11 -3
- data/spec/taskinator/task_spec.rb +43 -25
- data/spec/taskinator/taskinator_spec.rb +16 -0
- data/taskinator.gemspec +2 -3
- metadata +20 -29
- data/lib/taskinator/definition/builder.rb +0 -129
- data/lib/taskinator/log_stats.rb +0 -49
- data/lib/taskinator/xml_visitor.rb +0 -109
- data/spec/taskinator/xml_visitor_spec.rb +0 -5
data/lib/taskinator/process.rb
CHANGED
@@ -48,6 +48,7 @@ module Taskinator
|
|
48
48
|
@parent = value
|
49
49
|
# update the uuid to be "scoped" within the parent task
|
50
50
|
@uuid = "#{@parent.uuid}:subprocess"
|
51
|
+
@key = nil # NB: invalidate memoized key
|
51
52
|
end
|
52
53
|
|
53
54
|
def tasks
|
@@ -123,7 +124,7 @@ module Taskinator
|
|
123
124
|
instrument('taskinator.process.completed', completed_payload) do
|
124
125
|
complete if respond_to?(:complete)
|
125
126
|
# notify the parent task (if there is one) that this process has completed
|
126
|
-
# note: parent may be a proxy, so
|
127
|
+
# note: parent may be a proxy, so explicitly check for nil?
|
127
128
|
unless parent.nil?
|
128
129
|
parent.complete!
|
129
130
|
else
|
@@ -133,6 +134,9 @@ module Taskinator
|
|
133
134
|
end
|
134
135
|
end
|
135
136
|
|
137
|
+
# TODO: add retry method - to pick up from a failed task
|
138
|
+
# e.g. like retrying a failed job in Resque Web
|
139
|
+
|
136
140
|
def tasks_completed?
|
137
141
|
# TODO: optimize this
|
138
142
|
tasks.all?(&:completed?)
|
@@ -151,7 +155,7 @@ module Taskinator
|
|
151
155
|
instrument('taskinator.process.failed', failed_payload(error)) do
|
152
156
|
fail(error) if respond_to?(:fail)
|
153
157
|
# notify the parent task (if there is one) that this process has failed
|
154
|
-
# note: parent may be a proxy, so
|
158
|
+
# note: parent may be a proxy, so explicitly check for nil?
|
155
159
|
parent.fail!(error) unless parent.nil?
|
156
160
|
end
|
157
161
|
end
|
@@ -166,6 +170,7 @@ module Taskinator
|
|
166
170
|
# subclasses must implement the following methods
|
167
171
|
#--------------------------------------------------
|
168
172
|
|
173
|
+
# :nocov:
|
169
174
|
def enqueue
|
170
175
|
raise NotImplementedError
|
171
176
|
end
|
@@ -177,6 +182,7 @@ module Taskinator
|
|
177
182
|
def task_completed(task)
|
178
183
|
raise NotImplementedError
|
179
184
|
end
|
185
|
+
# :nocov:
|
180
186
|
|
181
187
|
#--------------------------------------------------
|
182
188
|
|
@@ -199,10 +205,9 @@ module Taskinator
|
|
199
205
|
end
|
200
206
|
|
201
207
|
def task_completed(task)
|
202
|
-
#
|
208
|
+
# decrement the count of pending sequential tasks
|
203
209
|
pending = deincr_pending_tasks
|
204
210
|
|
205
|
-
Taskinator.statsd_client.count("taskinator.#{definition.name.underscore.parameterize}.pending", pending)
|
206
211
|
Taskinator.logger.info("Completed task for process '#{uuid}'. Pending is #{pending}.")
|
207
212
|
|
208
213
|
next_task = task.next
|
@@ -237,7 +242,6 @@ module Taskinator
|
|
237
242
|
if tasks.empty?
|
238
243
|
complete! # weren't any tasks to start with
|
239
244
|
else
|
240
|
-
Taskinator.statsd_client.count("taskinator.#{definition.name.underscore.parameterize}.pending", tasks.count)
|
241
245
|
Taskinator.logger.info("Enqueuing #{tasks.count} tasks for process '#{uuid}'.")
|
242
246
|
tasks.each(&:enqueue!)
|
243
247
|
end
|
@@ -249,6 +253,7 @@ module Taskinator
|
|
249
253
|
complete! # weren't any tasks to start with
|
250
254
|
else
|
251
255
|
if concurrency_method == :fork
|
256
|
+
# :nocov:
|
252
257
|
warn("[DEPRECATED]: concurrency_method will be removed in a future version.")
|
253
258
|
tasks.each do |task|
|
254
259
|
fork do
|
@@ -256,6 +261,7 @@ module Taskinator
|
|
256
261
|
end
|
257
262
|
end
|
258
263
|
Process.waitall
|
264
|
+
# :nocov:
|
259
265
|
else
|
260
266
|
threads = tasks.map do |task|
|
261
267
|
Thread.new do
|
@@ -268,14 +274,13 @@ module Taskinator
|
|
268
274
|
end
|
269
275
|
|
270
276
|
def task_completed(task)
|
271
|
-
#
|
277
|
+
# decrement the count of pending concurrent tasks
|
272
278
|
pending = deincr_pending_tasks
|
273
279
|
|
274
|
-
Taskinator.statsd_client.count("taskinator.#{definition.name.underscore.parameterize}.pending", pending)
|
275
280
|
Taskinator.logger.info("Completed task for process '#{uuid}'. Pending is #{pending}.")
|
276
281
|
|
277
282
|
# when complete on first, then don't bother with subsequent tasks completing
|
278
|
-
if
|
283
|
+
if complete_on == CompleteOn::First
|
279
284
|
complete! unless completed?
|
280
285
|
else
|
281
286
|
complete! if pending < 1
|
@@ -283,7 +288,7 @@ module Taskinator
|
|
283
288
|
end
|
284
289
|
|
285
290
|
def tasks_completed?
|
286
|
-
if
|
291
|
+
if complete_on == CompleteOn::First
|
287
292
|
tasks.any?(&:completed?)
|
288
293
|
else
|
289
294
|
super # all
|
data/lib/taskinator/task.rb
CHANGED
@@ -21,6 +21,7 @@ module Taskinator
|
|
21
21
|
end
|
22
22
|
|
23
23
|
attr_reader :process
|
24
|
+
attr_reader :definition
|
24
25
|
attr_reader :uuid
|
25
26
|
attr_reader :options
|
26
27
|
attr_reader :queue
|
@@ -35,6 +36,7 @@ module Taskinator
|
|
35
36
|
|
36
37
|
@uuid = "#{process.uuid}:task:#{Taskinator.generate_uuid}"
|
37
38
|
@process = process
|
39
|
+
@definition = process.definition
|
38
40
|
@options = options
|
39
41
|
@queue = options.delete(:queue)
|
40
42
|
@created_at = Time.now.utc
|
@@ -45,6 +47,7 @@ module Taskinator
|
|
45
47
|
def accept(visitor)
|
46
48
|
visitor.visit_attribute(:uuid)
|
47
49
|
visitor.visit_process_reference(:process)
|
50
|
+
visitor.visit_type(:definition)
|
48
51
|
visitor.visit_task_reference(:next)
|
49
52
|
visitor.visit_args(:options)
|
50
53
|
visitor.visit_attribute(:queue)
|
@@ -134,6 +137,7 @@ module Taskinator
|
|
134
137
|
# subclasses must implement the following methods
|
135
138
|
#--------------------------------------------------
|
136
139
|
|
140
|
+
# :nocov:
|
137
141
|
def enqueue
|
138
142
|
raise NotImplementedError
|
139
143
|
end
|
@@ -141,6 +145,7 @@ module Taskinator
|
|
141
145
|
def start
|
142
146
|
raise NotImplementedError
|
143
147
|
end
|
148
|
+
# :nocov:
|
144
149
|
|
145
150
|
#--------------------------------------------------
|
146
151
|
# and optionally, provide methods:
|
@@ -155,13 +160,11 @@ module Taskinator
|
|
155
160
|
# a task which invokes the specified method on the definition
|
156
161
|
# the args must be intrinsic types, since they are serialized to YAML
|
157
162
|
class Step < Task
|
158
|
-
attr_reader :definition
|
159
163
|
attr_reader :method
|
160
164
|
attr_reader :args
|
161
165
|
|
162
166
|
def initialize(process, method, args, options={})
|
163
167
|
super(process, options)
|
164
|
-
@definition = process.definition # for convenience
|
165
168
|
|
166
169
|
raise ArgumentError, 'method' if method.nil?
|
167
170
|
raise NoMethodError, method unless executor.respond_to?(method)
|
@@ -188,17 +191,16 @@ module Taskinator
|
|
188
191
|
|
189
192
|
def accept(visitor)
|
190
193
|
super
|
191
|
-
visitor.visit_type(:definition)
|
192
194
|
visitor.visit_attribute(:method)
|
193
195
|
visitor.visit_args(:args)
|
194
196
|
end
|
195
197
|
|
196
198
|
def executor
|
197
|
-
@executor ||= Taskinator::Executor.new(
|
199
|
+
@executor ||= Taskinator::Executor.new(definition, self)
|
198
200
|
end
|
199
201
|
|
200
202
|
def inspect
|
201
|
-
%(#<#{self.class.name}:0x#{self.__id__.to_s(16)} uuid="#{uuid}", method=:#{method}, args=#{args}, current_state=:#{current_state}>)
|
203
|
+
%(#<#{self.class.name}:0x#{self.__id__.to_s(16)} uuid="#{uuid}", definition=:#{definition}, method=:#{method}, args=#{args}, current_state=:#{current_state}>)
|
202
204
|
end
|
203
205
|
end
|
204
206
|
|
@@ -207,13 +209,11 @@ module Taskinator
|
|
207
209
|
# a task which invokes the specified background job
|
208
210
|
# the args must be intrinsic types, since they are serialized to YAML
|
209
211
|
class Job < Task
|
210
|
-
attr_reader :definition
|
211
212
|
attr_reader :job
|
212
213
|
attr_reader :args
|
213
214
|
|
214
215
|
def initialize(process, job, args, options={})
|
215
216
|
super(process, options)
|
216
|
-
@definition = process.definition # for convenience
|
217
217
|
|
218
218
|
raise ArgumentError, 'job' if job.nil?
|
219
219
|
raise ArgumentError, 'job' unless job.methods.include?(:perform) || job.instance_methods.include?(:perform)
|
@@ -228,7 +228,6 @@ module Taskinator
|
|
228
228
|
|
229
229
|
def start
|
230
230
|
# NNB: if other job types are required, may need to implement how they get invoked here!
|
231
|
-
# FIXME: possible implement using ActiveJob instead, so it doesn't matter how the worker is implemented
|
232
231
|
|
233
232
|
if job.respond_to?(:perform)
|
234
233
|
# resque
|
@@ -250,13 +249,12 @@ module Taskinator
|
|
250
249
|
|
251
250
|
def accept(visitor)
|
252
251
|
super
|
253
|
-
visitor.visit_type(:definition)
|
254
252
|
visitor.visit_type(:job)
|
255
253
|
visitor.visit_args(:args)
|
256
254
|
end
|
257
255
|
|
258
256
|
def inspect
|
259
|
-
%(#<#{self.class.name}:0x#{self.__id__.to_s(16)} uuid="#{uuid}", job=#{job}, args=#{args}, current_state=:#{current_state}>)
|
257
|
+
%(#<#{self.class.name}:0x#{self.__id__.to_s(16)} uuid="#{uuid}", definition=:#{definition}, job=#{job}, args=#{args}, current_state=:#{current_state}>)
|
260
258
|
end
|
261
259
|
end
|
262
260
|
|
@@ -302,7 +300,7 @@ module Taskinator
|
|
302
300
|
end
|
303
301
|
|
304
302
|
def inspect
|
305
|
-
%(#<#{self.class.name}:0x#{self.__id__.to_s(16)} uuid="#{uuid}", sub_process=#{sub_process.inspect}, current_state=:#{current_state}>)
|
303
|
+
%(#<#{self.class.name}:0x#{self.__id__.to_s(16)} uuid="#{uuid}", definition=:#{definition}, sub_process=#{sub_process.inspect}, current_state=:#{current_state}>)
|
306
304
|
end
|
307
305
|
end
|
308
306
|
end
|
data/lib/taskinator/version.rb
CHANGED
data/lib/taskinator.rb
CHANGED
@@ -6,8 +6,6 @@ require 'delegate'
|
|
6
6
|
|
7
7
|
require 'taskinator/version'
|
8
8
|
|
9
|
-
require 'taskinator/log_stats'
|
10
|
-
|
11
9
|
require 'taskinator/complete_on'
|
12
10
|
require 'taskinator/redis_connection'
|
13
11
|
require 'taskinator/logger'
|
@@ -19,7 +17,6 @@ require 'taskinator/workflow'
|
|
19
17
|
require 'taskinator/visitor'
|
20
18
|
require 'taskinator/persistence'
|
21
19
|
require 'taskinator/instrumentation'
|
22
|
-
require 'taskinator/xml_visitor'
|
23
20
|
|
24
21
|
require 'taskinator/task'
|
25
22
|
require 'taskinator/tasks'
|
@@ -87,14 +84,6 @@ module Taskinator
|
|
87
84
|
Taskinator::Logging.logger = log
|
88
85
|
end
|
89
86
|
|
90
|
-
def statsd_client
|
91
|
-
Taskinator::LogStats.client
|
92
|
-
end
|
93
|
-
|
94
|
-
def statsd_client=(client)
|
95
|
-
Taskinator::LogStats.client = client
|
96
|
-
end
|
97
|
-
|
98
87
|
# the queue adapter to use
|
99
88
|
# supported adapters include
|
100
89
|
# :active_job, :delayed_job, :redis and :sidekiq
|
@@ -135,14 +124,12 @@ module Taskinator
|
|
135
124
|
end
|
136
125
|
|
137
126
|
class NoOpInstrumenter
|
138
|
-
# :nocov:
|
139
127
|
def instrument(event, payload={})
|
140
128
|
yield(payload) if block_given?
|
141
129
|
end
|
142
130
|
end
|
143
131
|
|
144
132
|
class ConsoleInstrumenter
|
145
|
-
# :nocov:
|
146
133
|
def instrument(event, payload={})
|
147
134
|
puts [event.inspect, payload.to_yaml]
|
148
135
|
yield(payload) if block_given?
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module TestJob
|
2
|
+
def self.perform(*args)
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
class TestJobClass
|
7
|
+
def perform(*args)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module TestJobModule
|
12
|
+
def self.perform(*args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TestJobClassNoArgs
|
17
|
+
def perform
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module TestJobModuleNoArgs
|
22
|
+
def self.perform
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module TestJobError
|
27
|
+
def self.perform
|
28
|
+
raise ArgumentError
|
29
|
+
end
|
30
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Taskinator::
|
3
|
+
describe Taskinator::Builder do
|
4
4
|
|
5
5
|
let(:definition) do
|
6
6
|
Module.new do
|
@@ -26,7 +26,7 @@ describe Taskinator::Definition::Builder do
|
|
26
26
|
Proc.new {|*args| the_block.call }
|
27
27
|
}
|
28
28
|
|
29
|
-
subject { Taskinator::
|
29
|
+
subject { Taskinator::Builder.new(process, definition, *[*args, builder_options]) }
|
30
30
|
|
31
31
|
it "assign attributes" do
|
32
32
|
expect(subject.process).to eq(process)
|
@@ -106,6 +106,37 @@ describe Taskinator::Definition do
|
|
106
106
|
expect(subject.create_process).to be_a(Taskinator::Process)
|
107
107
|
end
|
108
108
|
|
109
|
+
it "handles error" do
|
110
|
+
subject.define_process do
|
111
|
+
raise ArgumentError
|
112
|
+
end
|
113
|
+
|
114
|
+
expect {
|
115
|
+
subject.create_process
|
116
|
+
}.to raise_error(ArgumentError)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "checks defined arguments provided" do
|
120
|
+
subject.define_process :arg1, :arg2 do
|
121
|
+
end
|
122
|
+
|
123
|
+
expect {
|
124
|
+
subject.create_process
|
125
|
+
}.to raise_error(ArgumentError)
|
126
|
+
|
127
|
+
expect {
|
128
|
+
subject.create_process :foo
|
129
|
+
}.to raise_error(ArgumentError)
|
130
|
+
|
131
|
+
expect {
|
132
|
+
subject.create_process :foo, :bar
|
133
|
+
}.not_to raise_error
|
134
|
+
|
135
|
+
expect {
|
136
|
+
subject.create_process :foo, :bar, :baz
|
137
|
+
}.not_to raise_error
|
138
|
+
end
|
139
|
+
|
109
140
|
it "defaults the scope to :shared" do
|
110
141
|
block = SpecSupport::Block.new
|
111
142
|
allow(block).to receive(:to_proc) {
|
@@ -2,8 +2,6 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Taskinator::Instrumentation, :redis => true do
|
4
4
|
|
5
|
-
let(:definition) { TestDefinition }
|
6
|
-
|
7
5
|
subject do
|
8
6
|
klass = Class.new do
|
9
7
|
include Taskinator::Persistence
|
@@ -15,10 +13,12 @@ describe Taskinator::Instrumentation, :redis => true do
|
|
15
13
|
|
16
14
|
attr_reader :uuid
|
17
15
|
attr_reader :options
|
16
|
+
attr_reader :definition
|
18
17
|
|
19
18
|
def initialize
|
20
19
|
@uuid = Taskinator.generate_uuid
|
21
20
|
@options = { :bar => :baz }
|
21
|
+
@definition = TestDefinition
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -75,6 +75,7 @@ describe Taskinator::Instrumentation, :redis => true do
|
|
75
75
|
expect(subject.completed_payload(:baz => :qux)).to eq(
|
76
76
|
OpenStruct.new({
|
77
77
|
:type => subject.class.name,
|
78
|
+
:definition => subject.definition.name,
|
78
79
|
:process_uuid => subject.uuid,
|
79
80
|
:process_options => {:foo => :bar},
|
80
81
|
:uuid => subject.uuid,
|
@@ -46,6 +46,15 @@ describe Taskinator::Persistence, :redis => true do
|
|
46
46
|
expect(subject.fetch('uuid', cache)).to eq(item)
|
47
47
|
end
|
48
48
|
|
49
|
+
it "yields UnknownType" do
|
50
|
+
Taskinator.redis do |conn|
|
51
|
+
conn.hmset(*[subject.key_for("foo"), [:type, 'UnknownFoo']])
|
52
|
+
end
|
53
|
+
instance = subject.fetch("foo")
|
54
|
+
expect(instance).to be_a(Taskinator::Persistence::UnknownType)
|
55
|
+
expect(instance.type).to eq("UnknownFoo")
|
56
|
+
end
|
57
|
+
|
49
58
|
describe "for processes" do
|
50
59
|
let(:process) { TestProcess.new(definition) }
|
51
60
|
|
@@ -53,6 +62,19 @@ describe Taskinator::Persistence, :redis => true do
|
|
53
62
|
process.save
|
54
63
|
expect(TestProcess.fetch(process.uuid)).to eq(process)
|
55
64
|
}
|
65
|
+
|
66
|
+
describe "unknown definition" do
|
67
|
+
it "yields UnknownType" do
|
68
|
+
Taskinator.redis do |conn|
|
69
|
+
conn.hmset(*[process.key, [:type, TestProcess.name], [:uuid, process.uuid], [:definition, 'UnknownFoo']])
|
70
|
+
end
|
71
|
+
|
72
|
+
instance = TestProcess.fetch(process.uuid)
|
73
|
+
expect(instance.uuid).to eq(process.uuid)
|
74
|
+
expect(instance.definition).to be_a(Taskinator::Persistence::UnknownType)
|
75
|
+
expect(instance.definition.type).to eq("UnknownFoo")
|
76
|
+
end
|
77
|
+
end
|
56
78
|
end
|
57
79
|
|
58
80
|
describe "for tasks" do
|
@@ -62,9 +84,45 @@ describe Taskinator::Persistence, :redis => true do
|
|
62
84
|
it {
|
63
85
|
process.tasks << task
|
64
86
|
process.save
|
65
|
-
|
66
|
-
|
87
|
+
|
88
|
+
instance = TestTask.fetch(task.uuid)
|
89
|
+
expect(instance).to eq(task)
|
90
|
+
expect(instance.process).to eq(process)
|
67
91
|
}
|
92
|
+
|
93
|
+
describe "unknown job" do
|
94
|
+
let(:task) { TestJobTask.new(process, TestJob, []) }
|
95
|
+
|
96
|
+
it "yields UnknownType" do
|
97
|
+
Taskinator.redis do |conn|
|
98
|
+
conn.hmset(*[task.key, [:type, task.class.name], [:uuid, task.uuid], [:job, 'UnknownBar']])
|
99
|
+
end
|
100
|
+
|
101
|
+
instance = TestJobTask.fetch(task.uuid)
|
102
|
+
expect(instance.uuid).to eq(task.uuid)
|
103
|
+
expect(instance.job).to be_a(Taskinator::Persistence::UnknownType)
|
104
|
+
expect(instance.job.type).to eq("UnknownBar")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "unknown subprocess" do
|
109
|
+
let(:sub_process) { TestProcess.new(definition) }
|
110
|
+
let(:task) { TestSubProcessTask.new(process, sub_process) }
|
111
|
+
|
112
|
+
it "yields UnknownType" do
|
113
|
+
Taskinator.redis do |conn|
|
114
|
+
conn.multi do |transaction|
|
115
|
+
transaction.hmset(*[task.key, [:type, task.class.name], [:uuid, task.uuid], [:sub_process, sub_process.uuid]])
|
116
|
+
transaction.hmset(*[sub_process.key, [:type, sub_process.class.name], [:uuid, sub_process.uuid], [:definition, 'UnknownBaz']])
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
instance = TestSubProcessTask.fetch(task.uuid)
|
121
|
+
expect(instance.uuid).to eq(task.uuid)
|
122
|
+
expect(instance.sub_process.definition).to be_a(Taskinator::Persistence::UnknownType)
|
123
|
+
expect(instance.sub_process.definition.type).to eq("UnknownBaz")
|
124
|
+
end
|
125
|
+
end
|
68
126
|
end
|
69
127
|
end
|
70
128
|
end
|
@@ -188,6 +246,72 @@ describe Taskinator::Persistence, :redis => true do
|
|
188
246
|
end
|
189
247
|
end
|
190
248
|
|
249
|
+
describe "unknown type helpers" do
|
250
|
+
subject { Taskinator::Persistence::UnknownType }
|
251
|
+
|
252
|
+
describe "#new" do
|
253
|
+
it "instantiates new module instance" do
|
254
|
+
instance = subject.new("foo")
|
255
|
+
expect(instance).to_not be_nil
|
256
|
+
expect(instance).to be_a(::Module)
|
257
|
+
end
|
258
|
+
|
259
|
+
it "yields same instance for same type" do
|
260
|
+
instance1 = subject.new("foo")
|
261
|
+
instance2 = subject.new("foo")
|
262
|
+
expect(instance1).to eq(instance2)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe ".type" do
|
267
|
+
it {
|
268
|
+
instance = subject.new("foo")
|
269
|
+
expect(instance.type).to eq("foo")
|
270
|
+
}
|
271
|
+
end
|
272
|
+
|
273
|
+
describe ".to_s" do
|
274
|
+
it {
|
275
|
+
instance = subject.new("foo")
|
276
|
+
expect(instance.to_s).to eq("Unknown type 'foo'.")
|
277
|
+
}
|
278
|
+
end
|
279
|
+
|
280
|
+
describe ".allocate" do
|
281
|
+
it "emulates Object#allocate" do
|
282
|
+
instance = subject.new("foo")
|
283
|
+
expect(instance.allocate).to eq(instance)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
describe ".accept" do
|
288
|
+
it {
|
289
|
+
instance = subject.new("foo")
|
290
|
+
expect(instance).to respond_to(:accept)
|
291
|
+
}
|
292
|
+
end
|
293
|
+
|
294
|
+
describe ".perform" do
|
295
|
+
it "raises UnknownTypeError" do
|
296
|
+
instance = subject.new("foo")
|
297
|
+
expect {
|
298
|
+
instance.perform(:foo, 1, false)
|
299
|
+
}.to raise_error(Taskinator::Persistence::UnknownTypeError)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
describe "via executor" do
|
304
|
+
it "raises UnknownTypeError" do
|
305
|
+
instance = subject.new("foo")
|
306
|
+
executor = Taskinator::Executor.new(instance)
|
307
|
+
|
308
|
+
expect {
|
309
|
+
executor.foo
|
310
|
+
}.to raise_error(Taskinator::Persistence::UnknownTypeError)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
191
315
|
describe "instance methods" do
|
192
316
|
subject {
|
193
317
|
klass = Class.new do
|
@@ -207,11 +331,14 @@ describe Taskinator::Persistence, :redis => true do
|
|
207
331
|
}
|
208
332
|
|
209
333
|
describe "#save" do
|
210
|
-
pending
|
334
|
+
pending
|
211
335
|
end
|
212
336
|
|
213
337
|
describe "#to_xml" do
|
214
|
-
|
338
|
+
it {
|
339
|
+
process = TestFlows::Task.create_process(1)
|
340
|
+
expect(process.to_xml).to match(/xml/)
|
341
|
+
}
|
215
342
|
end
|
216
343
|
|
217
344
|
describe "#key" do
|
@@ -426,6 +553,5 @@ describe Taskinator::Persistence, :redis => true do
|
|
426
553
|
end
|
427
554
|
|
428
555
|
end
|
429
|
-
|
430
556
|
end
|
431
557
|
end
|
@@ -35,6 +35,14 @@ describe Taskinator::Process do
|
|
35
35
|
it { expect(subject.tasks).to be_a(Taskinator::Tasks) }
|
36
36
|
end
|
37
37
|
|
38
|
+
describe "#no_tasks_defined?" do
|
39
|
+
it { expect(subject.no_tasks_defined?).to be }
|
40
|
+
it {
|
41
|
+
subject.tasks << :mock
|
42
|
+
expect(subject.no_tasks_defined?).to_not be
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
38
46
|
describe "#to_s" do
|
39
47
|
it { expect(subject.to_s).to match(/#{subject.uuid}/) }
|
40
48
|
end
|
@@ -288,7 +296,7 @@ describe Taskinator::Process do
|
|
288
296
|
subject.task_completed(task1)
|
289
297
|
end
|
290
298
|
|
291
|
-
it "
|
299
|
+
it "decrements the pending task count" do
|
292
300
|
tasks.each {|t| subject.tasks << t }
|
293
301
|
task1 = tasks[0]
|
294
302
|
task2 = tasks[1]
|
@@ -367,7 +375,7 @@ describe Taskinator::Process do
|
|
367
375
|
subject.task_failed(tasks.first, error)
|
368
376
|
end
|
369
377
|
|
370
|
-
it "doesn't
|
378
|
+
it "doesn't decrement pending task count" do
|
371
379
|
tasks.each {|t| subject.tasks << t }
|
372
380
|
|
373
381
|
expect(subject).to_not receive(:deincr_pending_tasks)
|
@@ -515,7 +523,7 @@ describe Taskinator::Process do
|
|
515
523
|
end
|
516
524
|
end
|
517
525
|
|
518
|
-
it "
|
526
|
+
it "decrements the pending task count" do
|
519
527
|
tasks.each {|t| subject.tasks << t }
|
520
528
|
task1 = tasks[0]
|
521
529
|
task2 = tasks[1]
|