dwf 0.1.7 → 0.1.11

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.
@@ -20,7 +20,8 @@ describe Dwf::Item, item: true do
20
20
  klass: 'Dwf::Item',
21
21
  started_at: started_at,
22
22
  finished_at: finished_at,
23
- callback_type: Dwf::Workflow::BUILD_IN
23
+ callback_type: Dwf::Workflow::BUILD_IN,
24
+ payloads: nil
24
25
  }
25
26
  end
26
27
  let!(:item) { described_class.new(options) }
@@ -89,7 +90,7 @@ describe Dwf::Item, item: true do
89
90
  before do
90
91
  allow(Dwf::Client).to receive(:new).and_return client_double
91
92
  allow(client_double)
92
- .to receive(:find_job).and_return a_item
93
+ .to receive(:find_node).and_return a_item
93
94
  end
94
95
 
95
96
  context 'parent jobs already finished' do
@@ -98,8 +99,8 @@ describe Dwf::Item, item: true do
98
99
  it do
99
100
  expect(item.parents_succeeded?).to be_truthy
100
101
  expect(client_double)
101
- .to have_received(:find_job)
102
- .with(workflow_id, incoming.first)
102
+ .to have_received(:find_node)
103
+ .with(incoming.first, workflow_id)
103
104
  end
104
105
  end
105
106
 
@@ -109,8 +110,8 @@ describe Dwf::Item, item: true do
109
110
  it do
110
111
  expect(item.parents_succeeded?).to be_falsy
111
112
  expect(client_double)
112
- .to have_received(:find_job)
113
- .with(workflow_id, incoming.first)
113
+ .to have_received(:find_node)
114
+ .with(incoming.first, workflow_id)
114
115
  end
115
116
  end
116
117
  end
@@ -181,4 +182,78 @@ describe Dwf::Item, item: true do
181
182
  it { expect(a_item).not_to have_received(:persist_and_perform_async!) }
182
183
  end
183
184
  end
185
+
186
+ describe '#output' do
187
+ before { item.output(1) }
188
+
189
+ it { expect(item.output_payload).to eq 1 }
190
+ end
191
+
192
+ describe '#payloads' do
193
+ let(:incoming) { ["Dwf::Item|#{SecureRandom.uuid}", "Dwf::Workflow|#{workflow_id}"] }
194
+ let(:client_double) { double(find_job: nil, build_workflow_id: workflow_id) }
195
+ let(:workflow) { Dwf::Workflow.new }
196
+ let!(:a_item) do
197
+ described_class.new(
198
+ workflow_id: SecureRandom.uuid,
199
+ id: SecureRandom.uuid,
200
+ finished_at: finished_at,
201
+ output_payload: 1
202
+ )
203
+ end
204
+
205
+ before do
206
+ allow(Dwf::Client).to receive(:new).and_return client_double
207
+ allow(client_double)
208
+ .to receive(:find_node)
209
+ .with(incoming.first, workflow_id).and_return a_item
210
+ allow(client_double)
211
+ .to receive(:find_node)
212
+ .with(incoming.last, workflow_id).and_return workflow
213
+ end
214
+
215
+ it do
216
+ expected_payload = [
217
+ {
218
+ class: a_item.class.name,
219
+ id: a_item.name,
220
+ output: 1
221
+ },
222
+ {
223
+ class: workflow.class.name,
224
+ id: workflow.name,
225
+ output: []
226
+ }
227
+ ]
228
+ expect(item.payloads).to match_array expected_payload
229
+ end
230
+ end
231
+
232
+ describe '#start_batch!' do
233
+ let(:callback_double) { double(start: nil) }
234
+ let(:client_double) { double(persist_job: nil) }
235
+
236
+ before do
237
+ allow(Dwf::Client).to receive(:new).and_return client_double
238
+ allow(Dwf::Callback).to receive(:new).and_return callback_double
239
+ item.start_batch!
240
+ end
241
+
242
+ it do
243
+ expect(callback_double).to have_received(:start).with(item)
244
+ expect(item.enqueued_at).not_to be_nil
245
+ end
246
+ end
247
+
248
+ describe '#leaf?' do
249
+ context 'when item has outgoing item' do
250
+ let(:outgoing) { ["Dwf::Item|#{SecureRandom.uuid}"] }
251
+ it { expect(item.leaf?).to be_falsy }
252
+ end
253
+
254
+ context 'when item does not have outgoing item' do
255
+ let(:outgoing) { [] }
256
+ it { expect(item.leaf?).to be_truthy }
257
+ end
258
+ end
184
259
  end
@@ -20,4 +20,13 @@ describe Dwf::Utils, utils: true do
20
20
 
21
21
  it { expect(described_class.symbolize_keys(hash)).to eq expected }
22
22
  end
23
+
24
+ describe "#workflow_name?" do
25
+ FirstWorkflow = Class.new(Dwf::Workflow)
26
+ FirstJob = Class.new(Dwf::Item)
27
+
28
+ it { expect(described_class.workflow_name?(Dwf::Workflow.name)).to be_truthy }
29
+ it { expect(described_class.workflow_name?(FirstWorkflow.name)).to be_truthy }
30
+ it { expect(described_class.workflow_name?(FirstJob.name)).to be_falsy }
31
+ end
23
32
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'mock_redis'
5
+ require 'sidekiq/testing'
6
+
7
+ describe Dwf::Worker, client: true do
8
+ let(:workflow_id) { SecureRandom.uuid }
9
+ let(:id) { SecureRandom.uuid }
10
+ let(:redis) { Redis.new }
11
+ let(:worker) { described_class.perform_async(workflow_id, job.name) }
12
+ before do
13
+ redis_instance = MockRedis.new
14
+ allow(Redis).to receive(:new).and_return redis_instance
15
+ end
16
+
17
+ describe '#find_job' do
18
+ let!(:job) do
19
+ j = Dwf::Item.new(workflow_id: workflow_id, id: id)
20
+ j.persist!
21
+ j
22
+ end
23
+
24
+ before do
25
+ worker
26
+ Sidekiq::Worker.drain_all
27
+ job.reload
28
+ end
29
+
30
+ it { expect(job.finished?).to be_truthy }
31
+ end
32
+ end
@@ -0,0 +1,349 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'mock_redis'
5
+ AItem = Class.new(Dwf::Item)
6
+ BItem = Class.new(Dwf::Item)
7
+ CItem = Class.new(Dwf::Item)
8
+ SWorkflow = Class.new(Dwf::Workflow)
9
+
10
+ describe Dwf::Workflow, workflow: true do
11
+ let(:workflow_id) { SecureRandom.uuid }
12
+ let(:item_id) { SecureRandom.uuid }
13
+ let(:item) { nil }
14
+ let(:client) do
15
+ double(
16
+ persist_workflow: nil,
17
+ persist_job: nil,
18
+ build_workflow_id: workflow_id,
19
+ build_job_id: item_id,
20
+ find_workflow: nil,
21
+ find_node: item
22
+ )
23
+ end
24
+ before do
25
+ allow(Dwf::Client).to receive(:new).and_return client
26
+ end
27
+
28
+ describe '#create' do
29
+ it do
30
+ workflow = described_class.create
31
+ expect(client).to have_received(:persist_workflow)
32
+ .with(an_instance_of(described_class))
33
+ expect(workflow.id).to eq workflow_id
34
+ expect(workflow.persisted).to be_truthy
35
+ end
36
+ end
37
+
38
+ describe '#find' do
39
+ before { Dwf::Workflow.find(workflow_id) }
40
+
41
+ it { expect(client).to have_received(:find_workflow).with(workflow_id) }
42
+ end
43
+
44
+ describe '#persist!' do
45
+ let(:workflow) { described_class.new }
46
+ let(:job) do
47
+ Dwf::Item.new(
48
+ worflow_id: workflow_id,
49
+ id: item_id
50
+ )
51
+ end
52
+ before do
53
+ workflow.jobs << job
54
+ workflow.persist!
55
+ end
56
+
57
+ it do
58
+ expect(client).to have_received(:persist_workflow)
59
+ .with(an_instance_of(described_class))
60
+ expect(client).to have_received(:persist_job).with(job)
61
+ expect(workflow.id).to eq workflow_id
62
+ expect(workflow.persisted).to be_truthy
63
+ end
64
+ end
65
+
66
+ describe '#start' do
67
+ let(:workflow) { described_class.new }
68
+ let(:job) do
69
+ Dwf::Item.new(
70
+ worflow_id: workflow_id,
71
+ id: item_id
72
+ )
73
+ end
74
+ before do
75
+ workflow.jobs << job
76
+ workflow.persist!
77
+ end
78
+
79
+ it do
80
+ expect(client).to have_received(:persist_workflow)
81
+ .with(an_instance_of(described_class))
82
+ expect(client).to have_received(:persist_job).with(job)
83
+ expect(workflow.id).to eq workflow_id
84
+ expect(workflow.persisted).to be_truthy
85
+ expect(workflow.stopped).to be_falsy
86
+ end
87
+ end
88
+
89
+ describe '#run' do
90
+ let!(:workflow) { described_class.new }
91
+
92
+ before do
93
+ workflow.run AItem, after: BItem, before: CItem
94
+ workflow.run SWorkflow, after: AItem
95
+ end
96
+
97
+ it do
98
+ expect(workflow.jobs).not_to be_empty
99
+ expected = [
100
+ {
101
+ from: BItem.to_s,
102
+ to: "AItem|#{item_id}"
103
+ },
104
+ {
105
+ from: "AItem|#{item_id}",
106
+ to: CItem.to_s
107
+ },
108
+ {
109
+ from: AItem.to_s,
110
+ to: "SWorkflow|#{workflow_id}"
111
+ }
112
+ ]
113
+ expect(workflow.dependencies).to match_array expected
114
+ end
115
+ end
116
+
117
+ describe '#find_job' do
118
+ let!(:workflow) { described_class.new }
119
+ before do
120
+ workflow.jobs = [
121
+ AItem.new,
122
+ BItem.new(id: item_id),
123
+ CItem.new
124
+ ]
125
+ end
126
+
127
+ it 'searches by klass' do
128
+ job = workflow.find_job('AItem')
129
+ expect(job).to be_kind_of AItem
130
+ end
131
+
132
+ it 'searches by name' do
133
+ job = workflow.find_job("BItem|#{item_id}")
134
+ expect(job).to be_kind_of BItem
135
+ end
136
+ end
137
+
138
+ describe '#setup' do
139
+ let!(:workflow) { described_class.new }
140
+ before do
141
+ workflow.run AItem
142
+ workflow.run BItem, after: AItem
143
+ workflow.run SWorkflow, after: BItem
144
+ workflow.run CItem, after: SWorkflow
145
+
146
+ workflow.send(:setup)
147
+ end
148
+
149
+ it do
150
+ job_a = workflow.find_job("AItem")
151
+
152
+ expect(job_a.incoming).to be_empty
153
+ expect(job_a.outgoing).to eq ["BItem|#{item_id}"]
154
+
155
+ job_b = workflow.find_job('BItem')
156
+
157
+ expect(job_b.incoming).to eq ["AItem|#{item_id}"]
158
+ expect(job_b.outgoing).to eq ["SWorkflow|#{workflow_id}"]
159
+
160
+ job_c = workflow.find_job('CItem')
161
+
162
+ expect(job_c.incoming).to eq ["SWorkflow|#{workflow_id}"]
163
+ expect(job_c.outgoing).to be_empty
164
+ end
165
+ end
166
+
167
+ describe '#callback_type' do
168
+ let!(:workflow) { described_class.new }
169
+
170
+ it do
171
+ expect(workflow.callback_type).to eq described_class::BUILD_IN
172
+ workflow.callback_type = described_class::SK_BATCH
173
+ expect(workflow.callback_type).to eq described_class::SK_BATCH
174
+ end
175
+ end
176
+
177
+ describe '#reload' do
178
+ let!(:workflow) do
179
+ flow = described_class.new
180
+ flow.id = workflow_id
181
+ flow
182
+ end
183
+
184
+ before do
185
+ allow(client).to receive(:find_workflow).and_return workflow
186
+ workflow.reload
187
+ end
188
+
189
+ it { expect(client).to have_received(:find_workflow).with(workflow_id) }
190
+ end
191
+
192
+ describe '#parents_succeeded?' do
193
+ let(:incoming) { ["A|#{SecureRandom.uuid}"] }
194
+ let!(:workflow) do
195
+ flow = described_class.new
196
+ flow.parent_id = SecureRandom.uuid
197
+ flow.incoming = incoming
198
+ flow
199
+ end
200
+ let(:item) do
201
+ Dwf::Item.new(
202
+ workflow_id: SecureRandom.uuid,
203
+ id: SecureRandom.uuid,
204
+ finished_at: finished_at
205
+ )
206
+ end
207
+
208
+ context 'parent jobs already finished' do
209
+ let(:finished_at) { Time.now.to_i }
210
+
211
+ it do
212
+ expect(workflow.parents_succeeded?).to be_truthy
213
+ expect(client).to have_received(:find_node)
214
+ .with(incoming.first, workflow.parent_id)
215
+ end
216
+ end
217
+
218
+ context 'parent jobs havent finished yet' do
219
+ let(:finished_at) { nil }
220
+
221
+ it do
222
+ expect(workflow.parents_succeeded?).to be_falsy
223
+ expect(client)
224
+ .to have_received(:find_node)
225
+ .with(incoming.first, workflow.parent_id)
226
+ end
227
+ end
228
+ end
229
+
230
+ describe '#sub_workflow?' do
231
+ let!(:workflow) { described_class.new }
232
+ let!(:sub_workflow) do
233
+ flow = described_class.new
234
+ flow.parent_id = workflow.id
235
+ flow
236
+ end
237
+
238
+ specify do
239
+ expect(workflow.sub_workflow?).to be_falsy
240
+ expect(sub_workflow.sub_workflow?).to be_truthy
241
+ end
242
+ end
243
+
244
+ describe '#payloads' do
245
+ let!(:item) do
246
+ Dwf::Item.new(
247
+ workflow_id: SecureRandom.uuid,
248
+ id: SecureRandom.uuid,
249
+ output_payload: 1
250
+ )
251
+ end
252
+ let(:workflow) { described_class.new }
253
+
254
+ context 'when workflow is main flow' do
255
+ it { expect(workflow.payloads).to be_nil }
256
+ end
257
+
258
+ context 'when workflow is sub flow' do
259
+ before do
260
+ workflow.incoming = incoming
261
+ workflow.parent_id = SecureRandom.uuid
262
+ end
263
+
264
+ context 'when incoming blank' do
265
+ let(:incoming) { [] }
266
+ it { expect(workflow.payloads).to be_nil }
267
+ end
268
+
269
+ context 'when incoming present' do
270
+ let(:incoming) { ["Dwf::Item|#{SecureRandom.uuid}", "Dwf::Workflow|#{workflow_id}"] }
271
+ it do
272
+ expected_payload = [
273
+ {
274
+ class: item.class.name,
275
+ id: item.name,
276
+ output: 1
277
+ }
278
+ ]
279
+ expect(workflow.payloads).to eq expected_payload
280
+ expect(client).to have_received(:find_node).with(incoming.first, workflow.parent_id)
281
+ end
282
+ end
283
+ end
284
+ end
285
+
286
+ describe '#left?' do
287
+ let(:workflow) { described_class.new }
288
+ before { workflow.outgoing = outgoing }
289
+
290
+ context 'when item has outgoing item' do
291
+ let(:outgoing) { ["Dwf::Item|#{SecureRandom.uuid}"] }
292
+ it { expect(workflow.leaf?).to be_falsy }
293
+ end
294
+
295
+ context 'when item does not have outgoing item' do
296
+ let(:outgoing) { [] }
297
+ it { expect(workflow.leaf?).to be_truthy }
298
+ end
299
+ end
300
+
301
+ describe '#leaf_nodes' do
302
+ let!(:workflow) { described_class.new }
303
+ before do
304
+ workflow.run AItem
305
+ workflow.run BItem, after: AItem
306
+ workflow.run SWorkflow, after: BItem
307
+ workflow.run CItem, after: SWorkflow
308
+
309
+ workflow.send(:setup)
310
+ end
311
+
312
+ specify do
313
+ expect(workflow.leaf_nodes.count).to eq 1
314
+ expect(workflow.leaf_nodes.first).to be_kind_of CItem
315
+ end
316
+ end
317
+
318
+ describe '#output_payloads' do
319
+ let!(:workflow) { described_class.new }
320
+ before do
321
+ allow_any_instance_of(CItem).to receive(:output_payload).and_return 1
322
+ workflow.run AItem
323
+ workflow.run BItem, after: AItem
324
+ workflow.run SWorkflow, after: BItem
325
+ workflow.run CItem, after: SWorkflow
326
+
327
+ workflow.send(:setup)
328
+ end
329
+
330
+ it { expect(workflow.output_payload).to eq [1] }
331
+ end
332
+
333
+ describe '#callback_type=' do
334
+ let!(:workflow) { described_class.new }
335
+ before do
336
+ workflow.run AItem
337
+ workflow.run BItem, after: AItem
338
+
339
+ workflow.send(:setup)
340
+ workflow.callback_type = described_class::SK_BATCH
341
+ end
342
+
343
+ specify do
344
+ expect(workflow.callback_type).to eq described_class::SK_BATCH
345
+ job_callback_types = workflow.jobs.map(&:callback_type).uniq
346
+ expect(job_callback_types).to eq [described_class::SK_BATCH]
347
+ end
348
+ end
349
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  require 'dwf'
2
+ require 'simplecov'
3
+
4
+ SimpleCov.start
2
5
  # This file was generated by the `rspec --init` command. Conventionally, all
3
6
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
4
7
  # The generated `.rspec` file contains `--require spec_helper` which will cause
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dwf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - dthtien
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-08 00:00:00.000000000 Z
11
+ date: 2021-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 11.1.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: mock_redis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.27.2
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.27.2
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: redis
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -53,33 +67,33 @@ dependencies:
53
67
  - !ruby/object:Gem::Version
54
68
  version: '3.2'
55
69
  - !ruby/object:Gem::Dependency
56
- name: mock_redis
70
+ name: sidekiq
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: 0.27.2
62
- type: :development
75
+ version: 6.2.0
76
+ type: :runtime
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: 0.27.2
82
+ version: 6.2.0
69
83
  - !ruby/object:Gem::Dependency
70
- name: sidekiq
84
+ name: simplecov
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - "~>"
87
+ - - ">="
74
88
  - !ruby/object:Gem::Version
75
- version: 6.2.0
76
- type: :runtime
89
+ version: '0'
90
+ type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - "~>"
94
+ - - ">="
81
95
  - !ruby/object:Gem::Version
82
- version: 6.2.0
96
+ version: '0'
83
97
  description: Workflow
84
98
  email:
85
99
  - tiendt2311@gmail.com
@@ -100,7 +114,9 @@ files:
100
114
  - lib/dwf.rb
101
115
  - lib/dwf/callback.rb
102
116
  - lib/dwf/client.rb
117
+ - lib/dwf/concerns/checkable.rb
103
118
  - lib/dwf/configuration.rb
119
+ - lib/dwf/errors.rb
104
120
  - lib/dwf/item.rb
105
121
  - lib/dwf/utils.rb
106
122
  - lib/dwf/version.rb
@@ -110,6 +126,8 @@ files:
110
126
  - spec/dwf/configuration_spec.rb
111
127
  - spec/dwf/item_spec.rb
112
128
  - spec/dwf/utils_spec.rb
129
+ - spec/dwf/worker_spec.rb
130
+ - spec/dwf/workflow_spec.rb
113
131
  - spec/spec_helper.rb
114
132
  homepage: https://github.com/dthtien/wf
115
133
  licenses:
@@ -140,4 +158,6 @@ test_files:
140
158
  - spec/dwf/configuration_spec.rb
141
159
  - spec/dwf/item_spec.rb
142
160
  - spec/dwf/utils_spec.rb
161
+ - spec/dwf/worker_spec.rb
162
+ - spec/dwf/workflow_spec.rb
143
163
  - spec/spec_helper.rb