dwf 0.1.7 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -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