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.
@@ -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
- subject { described_class.new("myspace") }
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
@@ -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
- before { stub_request(:head, url) }
9
- specify {
10
- expect(Content.find(space_id: "foo", content_id: "bar")).to be_a(Content)
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 { stub_request(:head, url).to_return(status: 404) }
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
- before { stub_request(:head, url) }
39
- specify {
40
- expect(Content.exist?(space_id: "foo", content_id: "bar")).to be true
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 { stub_request(:head, url).to_return(status: 404) }
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
- copied = subject.copy(target_space_id: "spam", target_content_id: "eggs")
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
- specify {
193
- stub1 = stub_request(:put, target)
194
- .with(headers: {'x-dura-meta-copy-source'=>'foo/bar'})
195
- stub2 = stub_request(:head, target)
196
- stub3 = stub_request(:delete, "https://example.com/durastore/foo/bar")
197
- moved = subject.move(target_space_id: "spam", target_content_id: "eggs")
198
- expect(moved).to be_a(Content)
199
- expect(stub1).to have_been_requested
200
- expect(stub2).to have_been_requested
201
- expect(stub3).to have_been_requested
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
@@ -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.3.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-01-27 00:00:00.000000000 Z
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