dor-workflow-client 3.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rspec +1 -0
- data/.rubocop.yml +11 -0
- data/.rubocop_todo.yml +21 -0
- data/.travis.yml +10 -0
- data/.yardopts +1 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +22 -0
- data/README.md +35 -0
- data/Rakefile +16 -0
- data/bin/console +14 -0
- data/dor-workflow-client.gemspec +36 -0
- data/lib/dor/models/response/process.rb +55 -0
- data/lib/dor/models/response/update.rb +20 -0
- data/lib/dor/models/response/workflow.rb +54 -0
- data/lib/dor/workflow/client/connection_factory.rb +75 -0
- data/lib/dor/workflow/client/lifecycle_routes.rb +71 -0
- data/lib/dor/workflow/client/queues.rb +208 -0
- data/lib/dor/workflow/client/requestor.rb +48 -0
- data/lib/dor/workflow/client/version.rb +9 -0
- data/lib/dor/workflow/client/version_routes.rb +33 -0
- data/lib/dor/workflow/client/workflow_routes.rb +192 -0
- data/lib/dor/workflow/client.rb +77 -0
- data/lib/dor/workflow_exception.rb +6 -0
- data/spec/models/response/workflow_spec.rb +142 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/workflow/client/connection_factory_spec.rb +25 -0
- data/spec/workflow/client/lifecycle_routes_spec.rb +27 -0
- data/spec/workflow/client/requestor_spec.rb +33 -0
- data/spec/workflow/client/workflow_routes_spec.rb +53 -0
- data/spec/workflow/client_spec.rb +633 -0
- metadata +309 -0
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Dor::Workflow::Response::Workflow do
|
6
|
+
subject(:instance) { described_class.new(xml: xml) }
|
7
|
+
|
8
|
+
describe '#pid' do
|
9
|
+
subject { instance.pid }
|
10
|
+
|
11
|
+
let(:xml) do
|
12
|
+
<<~XML
|
13
|
+
<workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
|
14
|
+
</workflow>
|
15
|
+
XML
|
16
|
+
end
|
17
|
+
it { is_expected.to eq 'druid:mw971zk1113' }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#workflow_name' do
|
21
|
+
subject { instance.workflow_name }
|
22
|
+
|
23
|
+
let(:xml) do
|
24
|
+
<<~XML
|
25
|
+
<workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
|
26
|
+
</workflow>
|
27
|
+
XML
|
28
|
+
end
|
29
|
+
it { is_expected.to eq 'assemblyWF' }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#active?' do
|
33
|
+
subject { instance.active_for?(version: 2) }
|
34
|
+
|
35
|
+
context 'when the workflow has not been instantiated for the given version' do
|
36
|
+
let(:xml) do
|
37
|
+
<<~XML
|
38
|
+
<workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
|
39
|
+
<process version="1" laneId="default" elapsed="0.0" attempts="1" datetime="2013-02-18T14:40:25-0800" status="completed" name="start-assembly"/>
|
40
|
+
<process version="1" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="completed" name="jp2-create"/>
|
41
|
+
</workflow>
|
42
|
+
XML
|
43
|
+
end
|
44
|
+
it { is_expected.to be false }
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when the workflow has been instantiated for the given version' do
|
48
|
+
let(:xml) do
|
49
|
+
<<~XML
|
50
|
+
<workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
|
51
|
+
<process version="1" laneId="default" elapsed="0.0" attempts="1" datetime="2013-02-18T14:40:25-0800" status="completed" name="start-assembly"/>
|
52
|
+
<process version="1" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="completed" name="jp2-create"/>
|
53
|
+
<process version="2" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="waiting" name="jp2-create"/>
|
54
|
+
</workflow>
|
55
|
+
XML
|
56
|
+
end
|
57
|
+
it { is_expected.to be true }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#empty?' do
|
62
|
+
subject { instance.empty? }
|
63
|
+
|
64
|
+
context 'when there is xml' do
|
65
|
+
let(:xml) do
|
66
|
+
'<?xml version="1.0" encoding="UTF-8"?>
|
67
|
+
<workflow repository="dor" objectId="druid:oo201oo0001" id="accessionWF">
|
68
|
+
<process version="2" lifecycle="submitted" elapsed="0.0" archived="true" attempts="1"
|
69
|
+
datetime="2012-11-06T16:18:24-0800" status="completed" name="start-accession"/>
|
70
|
+
<process version="2" elapsed="0.0" archived="true" attempts="1"
|
71
|
+
datetime="2012-11-06T16:18:58-0800" status="completed" name="technical-metadata"/>
|
72
|
+
<process version="2" elapsed="0.0" archived="true" attempts="1"
|
73
|
+
datetime="2012-11-06T16:19:02-0800" status="completed" name="provenance-metadata"/>
|
74
|
+
<process version="2" elapsed="0.0" archived="true" attempts="1"
|
75
|
+
datetime="2012-11-06T16:19:05-0800" status="completed" name="remediate-object"/>
|
76
|
+
<process version="2" elapsed="0.0" archived="true" attempts="1"
|
77
|
+
datetime="2012-11-06T16:19:06-0800" status="completed" name="shelve"/>
|
78
|
+
<process version="2" lifecycle="published" elapsed="0.0" archived="true" attempts="1"
|
79
|
+
datetime="2012-11-06T16:19:07-0800" status="completed" name="publish"/>
|
80
|
+
<process version="2" elapsed="0.0" archived="true" attempts="1"
|
81
|
+
datetime="2012-11-06T16:19:09-0800" status="completed" name="sdr-ingest-transfer"/>
|
82
|
+
<process version="2" lifecycle="accessioned" elapsed="0.0" archived="true" attempts="1"
|
83
|
+
datetime="2012-11-06T16:19:10-0800" status="completed" name="cleanup"/>
|
84
|
+
<process version="2" elapsed="0.0" archived="true" attempts="1"
|
85
|
+
datetime="2012-11-06T16:19:13-0800" status="completed" name="rights-metadata"/>
|
86
|
+
<process version="2" lifecycle="described" elapsed="0.0" archived="true" attempts="1"
|
87
|
+
datetime="2012-11-06T16:19:15-0800" status="completed" name="descriptive-metadata"/>
|
88
|
+
<process version="2" elapsed="0.0" archived="true" attempts="2"
|
89
|
+
datetime="2012-11-06T16:19:16-0800" status="completed" name="content-metadata"/>
|
90
|
+
</workflow>'
|
91
|
+
end
|
92
|
+
|
93
|
+
it { is_expected.to be false }
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'when the xml is empty' do
|
97
|
+
let(:xml) { '' }
|
98
|
+
|
99
|
+
it { is_expected.to be true }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#process_for_recent_version' do
|
104
|
+
subject(:process) { instance.process_for_recent_version(name: 'jp2-create') }
|
105
|
+
|
106
|
+
context 'when the workflow has not been instantiated for the given version' do
|
107
|
+
let(:xml) do
|
108
|
+
<<~XML
|
109
|
+
<workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
|
110
|
+
<process version="1" laneId="default" elapsed="0.0" attempts="1" datetime="2013-02-18T14:40:25-0800" status="completed" name="start-assembly"/>
|
111
|
+
<process version="1" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="completed" name="jp2-create"/>
|
112
|
+
</workflow>
|
113
|
+
XML
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'returns a process' do
|
117
|
+
expect(process).to be_kind_of Dor::Workflow::Response::Process
|
118
|
+
expect(process.status).to eq 'completed'
|
119
|
+
expect(process.name).to eq 'jp2-create'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'when the workflow has been instantiated for the given version' do
|
124
|
+
let(:xml) do
|
125
|
+
<<~XML
|
126
|
+
<workflow repository="dor" objectId="druid:mw971zk1113" id="assemblyWF">
|
127
|
+
<process version="1" laneId="default" elapsed="0.0" attempts="1" datetime="2013-02-18T14:40:25-0800" status="completed" name="start-assembly"/>
|
128
|
+
<process version="1" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="completed" name="jp2-create"/>
|
129
|
+
<process version="2" laneId="default" elapsed="0.509" attempts="1" datetime="2013-02-18T14:42:24-0800" status="error" name="jp2-create" errorMessage="it just broke"/>
|
130
|
+
</workflow>
|
131
|
+
XML
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'returns a process' do
|
135
|
+
expect(process).to be_kind_of Dor::Workflow::Response::Process
|
136
|
+
expect(process.status).to eq 'error'
|
137
|
+
expect(process.error_message).to eq 'it just broke'
|
138
|
+
expect(process.name).to eq 'jp2-create'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'simplecov'
|
7
|
+
SimpleCov.start do
|
8
|
+
add_filter 'spec'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'byebug'
|
12
|
+
require 'dor/workflow/client'
|
13
|
+
require 'equivalent-xml'
|
14
|
+
require 'equivalent-xml/rspec_matchers'
|
15
|
+
require 'webmock/rspec'
|
16
|
+
|
17
|
+
# RSpec.configure do |conf|
|
18
|
+
# end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
# This test can take up to 15s to run because it does retries with exponential backoff
|
6
|
+
RSpec.describe Dor::Workflow::Client::ConnectionFactory do
|
7
|
+
let(:mock_logger) { double('Logger', info: true, debug: true, warn: true) }
|
8
|
+
|
9
|
+
let(:repo) { 'dor' }
|
10
|
+
let(:druid) { 'druid:123' }
|
11
|
+
before do
|
12
|
+
stub_request(:put, "http://example.com/#{repo}/objects/#{druid}/workflows/httpException?create-ds=true")
|
13
|
+
.to_return(status: 500, body: 'Internal error', headers: {})
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:client) { Dor::Workflow::Client.new url: 'http://example.com', logger: mock_logger }
|
17
|
+
|
18
|
+
describe '#create_workflow' do
|
19
|
+
it 'logs an error and retry upon a targeted Faraday exception' do
|
20
|
+
expect(mock_logger).to receive(:warn).with('retrying connection (1 remaining) to http://example.com/dor/objects/druid:123/workflows/httpException?create-ds=true: (Faraday::RetriableResponse) 500')
|
21
|
+
expect(mock_logger).to receive(:warn).with('retrying connection (0 remaining) to http://example.com/dor/objects/druid:123/workflows/httpException?create-ds=true: (Faraday::RetriableResponse) 500')
|
22
|
+
expect { client.create_workflow(repo, druid, 'httpException', '<xml>') }.to raise_error Dor::WorkflowException
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Dor::Workflow::Client::LifecycleRoutes do
|
6
|
+
let(:mock_requestor) { instance_double(Dor::Workflow::Client::Requestor) }
|
7
|
+
|
8
|
+
let(:routes) { described_class.new(requestor: mock_requestor) }
|
9
|
+
|
10
|
+
describe '#milestones' do
|
11
|
+
let(:ng_xml) { Nokogiri::XML(xml) }
|
12
|
+
let(:xml) do
|
13
|
+
'<?xml version="1.0" encoding="UTF-8"?><lifecycle objectId="druid:gv054hp4128"><milestone date="2012-01-26T21:06:54-0800" version="2">published</milestone></lifecycle>'
|
14
|
+
end
|
15
|
+
|
16
|
+
before do
|
17
|
+
allow(routes).to receive(:query_lifecycle).and_return(ng_xml)
|
18
|
+
end
|
19
|
+
|
20
|
+
subject(:milestones) { routes.milestones('dor', 'druid:gv054hp4128') }
|
21
|
+
|
22
|
+
it 'includes the version in with the milestones' do
|
23
|
+
expect(milestones.first[:milestone]).to eq('published')
|
24
|
+
expect(milestones.first[:version]).to eq('2')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Dor::Workflow::Client::Requestor do
|
6
|
+
let(:mock_http_connection) do
|
7
|
+
Faraday.new(url: 'http://example.com/') do |builder|
|
8
|
+
builder.use Faraday::Response::RaiseError
|
9
|
+
builder.options.params_encoder = Faraday::FlatParamsEncoder
|
10
|
+
|
11
|
+
builder.adapter :test, stubs
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:requestor) { described_class.new(connection: mock_http_connection) }
|
16
|
+
|
17
|
+
describe '.send_workflow_resource_request' do
|
18
|
+
let(:stubs) do
|
19
|
+
Faraday::Adapter::Test::Stubs.new do |stub|
|
20
|
+
stub.get('x?complete=a&complete=b') do |_env|
|
21
|
+
[200, {}, 'ab']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'uses the flat params encoder' do
|
27
|
+
response = requestor.send(:send_workflow_resource_request, 'x?complete=a&complete=b')
|
28
|
+
|
29
|
+
expect(response.body).to eq 'ab'
|
30
|
+
expect(response.env.url.query).to eq 'complete=a&complete=b'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Dor::Workflow::Client::WorkflowRoutes do
|
6
|
+
let(:mock_requestor) { instance_double(Dor::Workflow::Client::Requestor) }
|
7
|
+
|
8
|
+
let(:routes) { described_class.new(requestor: mock_requestor) }
|
9
|
+
|
10
|
+
let(:wf_xml) do
|
11
|
+
<<-EOXML
|
12
|
+
<workflow id="etdSubmitWF">
|
13
|
+
<process name="register-object" status="completed" attempts="1" />
|
14
|
+
<process name="submit" status="waiting" />
|
15
|
+
<process name="reader-approval" status="waiting" />
|
16
|
+
<process name="registrar-approval" status="waiting" />
|
17
|
+
<process name="start-accession" status="waiting" />
|
18
|
+
</workflow>
|
19
|
+
EOXML
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#add_lane_id_to_workflow_xml' do
|
23
|
+
it 'adds laneId attributes to all process elements' do
|
24
|
+
expected = <<-XML
|
25
|
+
<workflow id="etdSubmitWF">
|
26
|
+
<process name="register-object" status="completed" attempts="1" laneId="lane1"/>
|
27
|
+
<process name="submit" status="waiting" laneId="lane1"/>
|
28
|
+
<process name="reader-approval" status="waiting" laneId="lane1"/>
|
29
|
+
<process name="registrar-approval" status="waiting" laneId="lane1"/>
|
30
|
+
<process name="start-accession" status="waiting" laneId="lane1"/>
|
31
|
+
</workflow>
|
32
|
+
XML
|
33
|
+
expect(routes.send(:add_lane_id_to_workflow_xml, 'lane1', wf_xml)).to be_equivalent_to(expected)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#workflow' do
|
38
|
+
let(:xml) do
|
39
|
+
<<~XML
|
40
|
+
<workflow repository="dor" objectId="druid:mw971zk1113" id="accessionWF">
|
41
|
+
<process laneId="default" lifecycle="submitted" elapsed="0.0" attempts="1" datetime="2013-02-18T15:08:10-0800" status="completed" name="start-accession"/>
|
42
|
+
</workflow>
|
43
|
+
XML
|
44
|
+
end
|
45
|
+
before do
|
46
|
+
allow(routes).to receive(:workflow_xml) { xml }
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'it returns a workflow' do
|
50
|
+
expect(routes.workflow(pid: 'druid:mw971zk1113', workflow_name: 'accessionWF')).to be_kind_of Dor::Workflow::Response::Workflow
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|