duracloud-client 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/README.md +52 -3
- data/lib/duracloud/abstract_entity.rb +92 -0
- data/lib/duracloud/chunked_content.rb +35 -0
- data/lib/duracloud/client.rb +4 -4
- data/lib/duracloud/content.rb +78 -98
- data/lib/duracloud/content_manifest.rb +88 -0
- data/lib/duracloud/manifest.rb +34 -15
- data/lib/duracloud/properties.rb +1 -1
- data/lib/duracloud/request.rb +6 -5
- data/lib/duracloud/rest_methods.rb +8 -8
- data/lib/duracloud/space.rb +8 -10
- data/lib/duracloud/tsv.rb +27 -4
- data/lib/duracloud/version.rb +1 -1
- data/lib/duracloud.rb +3 -0
- data/spec/fixtures/content_manifest.xml +32 -0
- data/spec/support/shared_examples_for_tsv.rb +23 -0
- data/spec/unit/audit_log_spec.rb +5 -15
- data/spec/unit/bit_integrity_report_spec.rb +5 -15
- data/spec/unit/content_manifest_spec.rb +17 -0
- data/spec/unit/content_spec.rb +117 -28
- data/spec/unit/manifest_spec.rb +5 -14
- metadata +11 -4
- data/lib/duracloud/has_properties.rb +0 -52
- data/lib/duracloud/persistence.rb +0 -59
@@ -1,9 +1,13 @@
|
|
1
|
+
require 'support/shared_examples_for_tsv'
|
2
|
+
|
1
3
|
module Duracloud
|
2
4
|
RSpec.describe BitIntegrityReport do
|
3
5
|
|
6
|
+
subject { described_class.new("myspace") }
|
7
|
+
|
4
8
|
let(:path) { File.expand_path('../../fixtures/bit_integrity_report.tsv', __FILE__) }
|
5
9
|
|
6
|
-
|
10
|
+
it_behaves_like "a TSV"
|
7
11
|
|
8
12
|
describe "#csv" do
|
9
13
|
before do
|
@@ -17,19 +21,5 @@ module Duracloud
|
|
17
21
|
}
|
18
22
|
end
|
19
23
|
|
20
|
-
describe "#load_tsv" do
|
21
|
-
it "loads a string" do
|
22
|
-
tsv = File.read(path)
|
23
|
-
subject.load_tsv(tsv)
|
24
|
-
expect(subject.tsv).to eq(tsv)
|
25
|
-
end
|
26
|
-
it "loads an IO" do
|
27
|
-
tsv = File.read(path)
|
28
|
-
tsv_io = File.new(path, "rb")
|
29
|
-
subject.load_tsv(tsv)
|
30
|
-
expect(subject.tsv.to_s).to eq(tsv)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
24
|
end
|
35
25
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Duracloud
|
2
|
+
RSpec.describe ContentManifest do
|
3
|
+
|
4
|
+
describe "source" do
|
5
|
+
let(:manifest) { described_class.new(space_id: 'foo', manifest_id: 'bar') }
|
6
|
+
subject { manifest.source }
|
7
|
+
before do
|
8
|
+
allow(manifest).to receive(:xml) { File.read(File.expand_path("../../fixtures/content_manifest.xml", __FILE__)) }
|
9
|
+
end
|
10
|
+
its(:md5) { is_expected.to eq "164e9aee34c0c42915716e11d5d539b5" }
|
11
|
+
its(:size) { is_expected.to eq 4227858432 }
|
12
|
+
its(:content_type) { is_expected.to eq "application/octet-stream" }
|
13
|
+
its(:content_id) { is_expected.to eq "datastreamStore/8/b/d4/info%3Afedora%2Fduke%3A447146%2Fcontent%2Fcontent.0" }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
data/spec/unit/content_spec.rb
CHANGED
@@ -2,16 +2,32 @@ module Duracloud
|
|
2
2
|
RSpec.describe Content do
|
3
3
|
|
4
4
|
let(:url) { "https://example.com/durastore/foo/bar" }
|
5
|
+
let(:manifest_url) { "#{url}.dura-manifest" }
|
5
6
|
|
6
7
|
describe ".find" do
|
7
8
|
describe "when it exists" do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
subject { described_class.find(space_id: "foo", content_id: "bar") }
|
10
|
+
describe "and it is not chunked" do
|
11
|
+
before { stub_request(:head, url) }
|
12
|
+
it { is_expected.to be_a described_class }
|
13
|
+
end
|
14
|
+
describe "and it is chunked" do
|
15
|
+
let(:manifest_xml) { File.read(File.expand_path("../../fixtures/content_manifest.xml", __FILE__)) }
|
16
|
+
before do
|
17
|
+
stub_request(:head, url).to_return(status: 404)
|
18
|
+
stub_request(:head, manifest_url)
|
19
|
+
stub_request(:get, manifest_url).to_return(body: manifest_xml)
|
20
|
+
end
|
21
|
+
it { is_expected.to be_a described_class }
|
22
|
+
its(:md5) { is_expected.to eq "164e9aee34c0c42915716e11d5d539b5" }
|
23
|
+
its(:content_type) { is_expected.to eq "application/octet-stream" }
|
24
|
+
end
|
12
25
|
end
|
13
26
|
describe "when it does not exist" do
|
14
|
-
before
|
27
|
+
before do
|
28
|
+
stub_request(:head, url).to_return(status: 404)
|
29
|
+
stub_request(:head, manifest_url).to_return(status: 404)
|
30
|
+
end
|
15
31
|
specify {
|
16
32
|
expect { Content.find(space_id: "foo", content_id: "bar") }.to raise_error(NotFoundError)
|
17
33
|
}
|
@@ -35,13 +51,28 @@ module Duracloud
|
|
35
51
|
|
36
52
|
describe ".exist?" do
|
37
53
|
describe "when it exists" do
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
54
|
+
describe "and it is not chunked" do
|
55
|
+
before { stub_request(:head, url) }
|
56
|
+
specify {
|
57
|
+
expect(Content.exist?(space_id: "foo", content_id: "bar")).to be true
|
58
|
+
}
|
59
|
+
end
|
60
|
+
describe "and it is chunked" do
|
61
|
+
before do
|
62
|
+
stub_request(:head, url).to_return(status: 404)
|
63
|
+
stub_request(:head, manifest_url)
|
64
|
+
stub_request(:get, manifest_url)
|
65
|
+
end
|
66
|
+
specify {
|
67
|
+
expect(Content.exist?(space_id: "foo", content_id: "bar")).to be true
|
68
|
+
}
|
69
|
+
end
|
42
70
|
end
|
43
71
|
describe "when it does not exist" do
|
44
|
-
before
|
72
|
+
before do
|
73
|
+
stub_request(:head, url).to_return(status: 404)
|
74
|
+
stub_request(:head, manifest_url).to_return(status: 404)
|
75
|
+
end
|
45
76
|
specify {
|
46
77
|
expect(Content.exist?(space_id: "foo", content_id: "bar")).to be false
|
47
78
|
}
|
@@ -83,12 +114,12 @@ module Duracloud
|
|
83
114
|
end
|
84
115
|
end
|
85
116
|
describe "and the space exists" do
|
86
|
-
before
|
117
|
+
before do
|
87
118
|
stub_request(:put, url)
|
88
119
|
.with(body: "Some file content",
|
89
120
|
headers: {"Content-MD5"=>"92bbcf620ceb5f5bf38f08e9a1f31e7b"})
|
90
121
|
.to_return(status: 201)
|
91
|
-
|
122
|
+
end
|
92
123
|
it "stores the content" do
|
93
124
|
subject.save
|
94
125
|
expect(subject).to be_persisted
|
@@ -115,7 +146,6 @@ module Duracloud
|
|
115
146
|
end
|
116
147
|
describe "and the body has not changed" do
|
117
148
|
before {
|
118
|
-
allow(subject).to receive(:body_changed?) { false }
|
119
149
|
stub_request(:post, url)
|
120
150
|
.with(headers: {'x-dura-meta-creator'=>'testuser'})
|
121
151
|
}
|
@@ -173,33 +203,92 @@ module Duracloud
|
|
173
203
|
end
|
174
204
|
|
175
205
|
describe "#copy" do
|
176
|
-
let(:target) { "https://example.com/durastore/spam/eggs" }
|
177
206
|
subject { Content.new(space_id: "foo", content_id: "bar") }
|
207
|
+
let(:target) { "https://example.com/durastore/spam/eggs" }
|
208
|
+
before do
|
209
|
+
stub_request(:put, target)
|
210
|
+
.with(headers: {'x-dura-meta-copy-source'=>'foo/bar'})
|
211
|
+
stub_request(:head, target).to_return(status: 404)
|
212
|
+
stub_request(:head, "#{target}.dura-manifest").to_return(status: 404)
|
213
|
+
end
|
178
214
|
specify {
|
215
|
+
copied = subject.copy(space_id: "spam", content_id: "eggs")
|
216
|
+
expect(copied).to be_a(Content)
|
217
|
+
}
|
218
|
+
it "defaults target space to current space" do
|
219
|
+
target = "https://example.com/durastore/foo/eggs"
|
179
220
|
stub1 = stub_request(:put, target)
|
180
221
|
.with(headers: {'x-dura-meta-copy-source'=>'foo/bar'})
|
181
|
-
stub2 = stub_request(:head, target)
|
182
|
-
|
222
|
+
stub2 = stub_request(:head, target).to_return(status: 404)
|
223
|
+
stub3 = stub_request(:head, "#{target}.dura-manifest").to_return(status: 404)
|
224
|
+
copied = subject.copy(content_id: "eggs")
|
183
225
|
expect(copied).to be_a(Content)
|
184
226
|
expect(stub1).to have_been_requested
|
185
227
|
expect(stub2).to have_been_requested
|
186
|
-
|
228
|
+
expect(stub3).to have_been_requested
|
229
|
+
end
|
230
|
+
describe "when the target exists" do
|
231
|
+
before do
|
232
|
+
stub_request(:head, target).to_return(status: 200)
|
233
|
+
end
|
234
|
+
describe "and force argument is true" do
|
235
|
+
it "overwrites the target" do
|
236
|
+
expect { subject.copy(space_id: "spam", content_id: "eggs", force: true) }.not_to raise_error
|
237
|
+
end
|
238
|
+
end
|
239
|
+
describe "and force argument is false" do
|
240
|
+
it "raises an exception" do
|
241
|
+
expect { subject.copy(space_id: "spam", content_id: "eggs", force: false) }.to raise_error(Content::CopyError)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
187
245
|
end
|
188
246
|
|
189
247
|
describe "#move" do
|
190
248
|
let(:target) { "https://example.com/durastore/spam/eggs" }
|
191
249
|
subject { Content.new(space_id: "foo", content_id: "bar") }
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
250
|
+
describe "when copy succeeds" do
|
251
|
+
it "deletes the source" do
|
252
|
+
stub1 = stub_request(:put, target)
|
253
|
+
.with(headers: {'x-dura-meta-copy-source'=>'foo/bar'})
|
254
|
+
stub2 = stub_request(:head, target).to_return(status: 404)
|
255
|
+
stub2a = stub_request(:head, "#{target}.dura-manifest").to_return(status: 404)
|
256
|
+
stub3 = stub_request(:delete, "https://example.com/durastore/foo/bar")
|
257
|
+
moved = subject.move(space_id: "spam", content_id: "eggs")
|
258
|
+
expect(moved).to be_a(Content)
|
259
|
+
expect(stub1).to have_been_requested
|
260
|
+
expect(stub2).to have_been_requested
|
261
|
+
expect(stub2a).to have_been_requested
|
262
|
+
expect(stub3).to have_been_requested
|
263
|
+
end
|
264
|
+
end
|
265
|
+
describe "when copy fails" do
|
266
|
+
it "does not delete the source" do
|
267
|
+
allow(subject).to receive(:copy).with(space_id: "spam", content_id: "eggs").and_raise(Content::CopyError)
|
268
|
+
expect(subject).not_to receive(:delete)
|
269
|
+
expect { subject.move(space_id: "spam", content_id: "eggs") }.to raise_error(Content::CopyError)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
describe "when target exists" do
|
273
|
+
before do
|
274
|
+
stub_request(:put, target)
|
275
|
+
.with(headers: {'x-dura-meta-copy-source'=>'foo/bar'})
|
276
|
+
stub_request(:delete, "https://example.com/durastore/foo/bar")
|
277
|
+
stub_request(:head, target).to_return(status: 200)
|
278
|
+
allow(Content).to receive(:exist?).with(space_id: "spam", content_id: "eggs") { true }
|
279
|
+
end
|
280
|
+
describe "and force argument is true" do
|
281
|
+
it "overwrites the target" do
|
282
|
+
expect(subject).to receive(:copy).and_call_original
|
283
|
+
subject.move(space_id: "spam", content_id: "eggs", force: true)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
describe "and force argument is false" do
|
287
|
+
it "raises an exception" do
|
288
|
+
expect { subject.move(space_id: "spam", content_id: "eggs", force: false) }.to raise_error(Content::CopyError)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
203
292
|
end
|
204
293
|
|
205
294
|
end
|
data/spec/unit/manifest_spec.rb
CHANGED
@@ -1,9 +1,14 @@
|
|
1
|
+
require 'support/shared_examples_for_tsv'
|
2
|
+
|
1
3
|
module Duracloud
|
2
4
|
RSpec.describe Manifest do
|
3
5
|
|
4
6
|
subject { described_class.new("myspace") }
|
7
|
+
|
5
8
|
let(:path) { File.expand_path('../../fixtures/manifest.tsv', __FILE__) }
|
6
9
|
|
10
|
+
it_behaves_like "a TSV"
|
11
|
+
|
7
12
|
describe "#csv" do
|
8
13
|
before do
|
9
14
|
allow(subject).to receive(:tsv) { File.read(path) }
|
@@ -16,19 +21,5 @@ module Duracloud
|
|
16
21
|
}
|
17
22
|
end
|
18
23
|
|
19
|
-
describe "#load_tsv" do
|
20
|
-
it "loads a string" do
|
21
|
-
tsv = File.read(path)
|
22
|
-
subject.load_tsv(tsv)
|
23
|
-
expect(subject.tsv).to eq(tsv)
|
24
|
-
end
|
25
|
-
it "loads an IO" do
|
26
|
-
tsv = File.read(path)
|
27
|
-
tsv_io = File.new(path, "rb")
|
28
|
-
subject.load_tsv(tsv)
|
29
|
-
expect(subject.tsv.to_s).to eq(tsv)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
24
|
end
|
34
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duracloud-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Chandek-Stark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashie
|
@@ -161,19 +161,20 @@ files:
|
|
161
161
|
- gemfiles/Gemfile.activemodel-5.0
|
162
162
|
- lib/duracloud-client.rb
|
163
163
|
- lib/duracloud.rb
|
164
|
+
- lib/duracloud/abstract_entity.rb
|
164
165
|
- lib/duracloud/audit_log.rb
|
165
166
|
- lib/duracloud/bit_integrity_report.rb
|
167
|
+
- lib/duracloud/chunked_content.rb
|
166
168
|
- lib/duracloud/client.rb
|
167
169
|
- lib/duracloud/configuration.rb
|
168
170
|
- lib/duracloud/connection.rb
|
169
171
|
- lib/duracloud/content.rb
|
172
|
+
- lib/duracloud/content_manifest.rb
|
170
173
|
- lib/duracloud/content_properties.rb
|
171
174
|
- lib/duracloud/durastore_request.rb
|
172
175
|
- lib/duracloud/error.rb
|
173
176
|
- lib/duracloud/error_handler.rb
|
174
|
-
- lib/duracloud/has_properties.rb
|
175
177
|
- lib/duracloud/manifest.rb
|
176
|
-
- lib/duracloud/persistence.rb
|
177
178
|
- lib/duracloud/properties.rb
|
178
179
|
- lib/duracloud/request.rb
|
179
180
|
- lib/duracloud/response.rb
|
@@ -186,12 +187,15 @@ files:
|
|
186
187
|
- lib/duracloud/version.rb
|
187
188
|
- spec/fixtures/audit_log.tsv
|
188
189
|
- spec/fixtures/bit_integrity_report.tsv
|
190
|
+
- spec/fixtures/content_manifest.xml
|
189
191
|
- spec/fixtures/lorem_ipsum.txt
|
190
192
|
- spec/fixtures/manifest.tsv
|
191
193
|
- spec/spec_helper.rb
|
194
|
+
- spec/support/shared_examples_for_tsv.rb
|
192
195
|
- spec/unit/audit_log_spec.rb
|
193
196
|
- spec/unit/bit_integrity_report_spec.rb
|
194
197
|
- spec/unit/client_spec.rb
|
198
|
+
- spec/unit/content_manifest_spec.rb
|
195
199
|
- spec/unit/content_spec.rb
|
196
200
|
- spec/unit/manifest_spec.rb
|
197
201
|
- spec/unit/properties_spec.rb
|
@@ -225,12 +229,15 @@ summary: Ruby client for communicating with DuraCloud
|
|
225
229
|
test_files:
|
226
230
|
- spec/fixtures/audit_log.tsv
|
227
231
|
- spec/fixtures/bit_integrity_report.tsv
|
232
|
+
- spec/fixtures/content_manifest.xml
|
228
233
|
- spec/fixtures/lorem_ipsum.txt
|
229
234
|
- spec/fixtures/manifest.tsv
|
230
235
|
- spec/spec_helper.rb
|
236
|
+
- spec/support/shared_examples_for_tsv.rb
|
231
237
|
- spec/unit/audit_log_spec.rb
|
232
238
|
- spec/unit/bit_integrity_report_spec.rb
|
233
239
|
- spec/unit/client_spec.rb
|
240
|
+
- spec/unit/content_manifest_spec.rb
|
234
241
|
- spec/unit/content_spec.rb
|
235
242
|
- spec/unit/manifest_spec.rb
|
236
243
|
- spec/unit/properties_spec.rb
|
@@ -1,52 +0,0 @@
|
|
1
|
-
module Duracloud
|
2
|
-
module HasProperties
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.class_eval do
|
6
|
-
include Persistence
|
7
|
-
|
8
|
-
before_delete :reset_properties
|
9
|
-
after_save :reset_properties
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
# Return the properties associated with this resource,
|
14
|
-
# loading from Duracloud if necessary.
|
15
|
-
# @return [Duracloud::Properties] the properties
|
16
|
-
# @raise [Duracloud::NotFoundError] if the resource is marked persisted
|
17
|
-
# but does not exist in Duracloud
|
18
|
-
def properties
|
19
|
-
load_properties if persisted? && @properties.nil?
|
20
|
-
@properties ||= properties_class.new
|
21
|
-
end
|
22
|
-
|
23
|
-
# @api private
|
24
|
-
# @raise [Duracloud::NotFoundError] the resource does not exist in DuraCloud.
|
25
|
-
def load_properties
|
26
|
-
response = get_properties_response
|
27
|
-
self.properties = response.headers
|
28
|
-
yield response if block_given?
|
29
|
-
persisted!
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def properties=(props)
|
35
|
-
filtered = props ? properties_class.filter(props) : props
|
36
|
-
@properties = properties_class.new(filtered)
|
37
|
-
end
|
38
|
-
|
39
|
-
def reset_properties
|
40
|
-
@properties = nil
|
41
|
-
end
|
42
|
-
|
43
|
-
def properties_class
|
44
|
-
Properties
|
45
|
-
end
|
46
|
-
|
47
|
-
def get_properties_response
|
48
|
-
raise NotImplementedError, "Class must implement `get_properties_response`."
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
require "active_model"
|
2
|
-
|
3
|
-
module Duracloud
|
4
|
-
module Persistence
|
5
|
-
|
6
|
-
def self.included(base)
|
7
|
-
base.class_eval do
|
8
|
-
extend ActiveModel::Callbacks
|
9
|
-
|
10
|
-
define_model_callbacks :save, :delete
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def save
|
15
|
-
raise Error, "Cannot save deleted #{self.class}." if deleted?
|
16
|
-
run_callbacks :save do
|
17
|
-
do_save
|
18
|
-
persisted!
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def delete
|
23
|
-
raise Error, "Cannot delete, already deleted." if deleted?
|
24
|
-
run_callbacks :delete do
|
25
|
-
do_delete
|
26
|
-
deleted!
|
27
|
-
freeze
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def persisted?
|
32
|
-
!!@persisted
|
33
|
-
end
|
34
|
-
|
35
|
-
def deleted?
|
36
|
-
!!@deleted
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def persisted!
|
42
|
-
@persisted = true
|
43
|
-
end
|
44
|
-
|
45
|
-
def deleted!
|
46
|
-
@deleted = true
|
47
|
-
@persisted = false
|
48
|
-
end
|
49
|
-
|
50
|
-
def do_delete
|
51
|
-
raise NotImplementedError, "Classes must implement `do_delete`."
|
52
|
-
end
|
53
|
-
|
54
|
-
def do_save
|
55
|
-
raise NotImplementedError, "Classes must implement `do_save`."
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|