ezid-client 1.3.0 → 1.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 +25 -48
- data/VERSION +1 -1
- data/ezid-client.gemspec +1 -0
- data/lib/ezid/batch_download.rb +0 -1
- data/lib/ezid/client.rb +0 -1
- data/lib/ezid/error.rb +8 -0
- data/lib/ezid/identifier.rb +149 -50
- data/lib/ezid/metadata.rb +43 -17
- data/lib/ezid/proxy_identifier.rb +2 -0
- data/lib/ezid/responses/response.rb +12 -1
- data/spec/integration/identifier_spec.rb +28 -32
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/batch_download_spec.rb +5 -0
- data/spec/unit/identifier_spec.rb +278 -212
- metadata +18 -3
- data/lib/ezid/reserved_metadata.rb +0 -26
data/lib/ezid/metadata.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require "hashie"
|
2
|
-
require_relative "reserved_metadata"
|
3
2
|
|
4
3
|
module Ezid
|
5
4
|
#
|
@@ -8,7 +7,6 @@ module Ezid
|
|
8
7
|
# @api private
|
9
8
|
#
|
10
9
|
class Metadata < Hashie::Mash
|
11
|
-
include ReservedMetadata
|
12
10
|
|
13
11
|
# EZID metadata field/value separator
|
14
12
|
ANVL_SEPARATOR = ": "
|
@@ -30,13 +28,35 @@ module Ezid
|
|
30
28
|
# A line ending
|
31
29
|
LINE_ENDING_RE = /\r?\n/
|
32
30
|
# @api private
|
33
|
-
RESERVED_ALIASES = %w(
|
34
|
-
coowners datacenter export owner ownergroup
|
35
|
-
profile shadowedby shadows status target
|
36
|
-
).freeze
|
37
31
|
|
38
|
-
|
39
|
-
|
32
|
+
#
|
33
|
+
# EZID reserved metadata elements
|
34
|
+
#
|
35
|
+
# @see http://ezid.cdlib.org/doc/apidoc.html#internal-metadata
|
36
|
+
#
|
37
|
+
COOWNERS = "_coowners".freeze
|
38
|
+
CREATED = "_created".freeze
|
39
|
+
DATACENTER = "_datacenter".freeze
|
40
|
+
EXPORT = "_export".freeze
|
41
|
+
OWNER = "_owner".freeze
|
42
|
+
OWNERGROUP = "_ownergroup".freeze
|
43
|
+
PROFILE = "_profile".freeze
|
44
|
+
SHADOWEDBY = "_shadowedby".freeze
|
45
|
+
SHADOWS = "_shadows".freeze
|
46
|
+
STATUS = "_status".freeze
|
47
|
+
TARGET = "_target".freeze
|
48
|
+
UPDATED = "_updated".freeze
|
49
|
+
RESERVED = [
|
50
|
+
COOWNERS, CREATED, DATACENTER, EXPORT, OWNER, OWNERGROUP,
|
51
|
+
PROFILE, SHADOWEDBY, SHADOWS, STATUS, TARGET, UPDATED
|
52
|
+
].freeze
|
53
|
+
READONLY = [
|
54
|
+
CREATED, DATACENTER, OWNER, OWNERGROUP, SHADOWEDBY, SHADOWS, UPDATED
|
55
|
+
].freeze
|
56
|
+
|
57
|
+
def initialize(data=nil)
|
58
|
+
super()
|
59
|
+
update(data) if data
|
40
60
|
end
|
41
61
|
|
42
62
|
def elements
|
@@ -53,6 +73,14 @@ module Ezid
|
|
53
73
|
to_time(_updated)
|
54
74
|
end
|
55
75
|
|
76
|
+
def update(data)
|
77
|
+
super coerce(data)
|
78
|
+
end
|
79
|
+
|
80
|
+
def replace(data)
|
81
|
+
super coerce(data)
|
82
|
+
end
|
83
|
+
|
56
84
|
# Output metadata in EZID ANVL format
|
57
85
|
# @see http://ezid.cdlib.org/doc/apidoc.html#request-response-bodies
|
58
86
|
# @return [String] the ANVL output
|
@@ -74,13 +102,13 @@ module Ezid
|
|
74
102
|
|
75
103
|
# Overrides Hashie::Mash
|
76
104
|
def convert_key(key)
|
77
|
-
|
78
|
-
if
|
79
|
-
"_#{
|
80
|
-
elsif
|
81
|
-
|
105
|
+
converted = super
|
106
|
+
if RESERVED.include?("_#{converted}")
|
107
|
+
"_#{converted}"
|
108
|
+
elsif converted =~ /\A(dc|datacite|erc)_/
|
109
|
+
converted.sub(/_/, ".")
|
82
110
|
else
|
83
|
-
|
111
|
+
converted
|
84
112
|
end
|
85
113
|
end
|
86
114
|
|
@@ -93,9 +121,7 @@ module Ezid
|
|
93
121
|
|
94
122
|
# Coerce data into a Hash of elements
|
95
123
|
def coerce(data)
|
96
|
-
data.to_h
|
97
|
-
rescue NoMethodError
|
98
|
-
coerce_string(data)
|
124
|
+
data.respond_to?(:to_h) ? data.to_h : coerce_string(data)
|
99
125
|
end
|
100
126
|
|
101
127
|
# Escape string for sending to EZID host
|
@@ -59,7 +59,7 @@ module Ezid
|
|
59
59
|
# Returns an exception instance if there was an error
|
60
60
|
# @return [Ezid::Error] the exception
|
61
61
|
def exception
|
62
|
-
|
62
|
+
error_class.new(message) if error?
|
63
63
|
end
|
64
64
|
|
65
65
|
# The URI path of the request
|
@@ -68,5 +68,16 @@ module Ezid
|
|
68
68
|
__getobj__.uri.path
|
69
69
|
end
|
70
70
|
|
71
|
+
def error_class
|
72
|
+
case message
|
73
|
+
when /no such identifier/
|
74
|
+
IdentifierNotFoundError
|
75
|
+
when /identifier status does not support deletion/
|
76
|
+
DeletionError
|
77
|
+
else
|
78
|
+
Error
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
71
82
|
end
|
72
83
|
end
|
@@ -1,51 +1,47 @@
|
|
1
1
|
module Ezid
|
2
2
|
RSpec.describe Identifier do
|
3
3
|
|
4
|
+
before {
|
5
|
+
@identifier = described_class.mint(TEST_ARK_SHOULDER, target: "http://example.com")
|
6
|
+
}
|
7
|
+
|
4
8
|
describe "CRUD operations" do
|
9
|
+
describe "mint" do
|
10
|
+
subject { @identifier }
|
11
|
+
it { is_expected.to be_a(described_class) }
|
12
|
+
end
|
5
13
|
describe "create" do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
expect(subject.id).to match(/#{TEST_ARK_SHOULDER}/)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
describe "with an id" do
|
14
|
-
let(:minted) { described_class.create(shoulder: TEST_ARK_SHOULDER) }
|
15
|
-
subject { described_class.create(id: "#{minted}/123") }
|
16
|
-
it "should create the identifier" do
|
17
|
-
expect(subject).to be_a(described_class)
|
18
|
-
expect(subject.id).to eq("#{minted}/123")
|
19
|
-
end
|
14
|
+
subject { described_class.create("#{@identifier}/123") }
|
15
|
+
it "should create the identifier" do
|
16
|
+
expect(subject).to be_a(described_class)
|
17
|
+
expect(subject.id).to eq("#{@identifier}/123")
|
20
18
|
end
|
21
19
|
end
|
22
|
-
|
23
20
|
describe "retrieve" do
|
24
|
-
|
25
|
-
|
26
|
-
it "should instantiate the identifier" do
|
21
|
+
subject { described_class.find(@identifier.id) }
|
22
|
+
it "instantiates the identifier" do
|
27
23
|
expect(subject).to be_a(described_class)
|
28
|
-
expect(subject.id).to eq(
|
24
|
+
expect(subject.id).to eq(@identifier.id)
|
29
25
|
expect(subject.target).to eq("http://example.com")
|
30
26
|
end
|
31
27
|
end
|
32
|
-
|
33
28
|
describe "update" do
|
34
|
-
|
35
|
-
|
36
|
-
subject.target = "http://example.com"
|
29
|
+
specify {
|
30
|
+
subject.target = "http://google.com"
|
37
31
|
subject.save
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
32
|
+
expect(subject.target).to eq("http://google.com")
|
33
|
+
}
|
34
|
+
specify {
|
35
|
+
subject.update(target: "http://www.microsoft.com")
|
36
|
+
expect(subject.target).to eq("http://www.microsoft.com")
|
37
|
+
}
|
42
38
|
end
|
43
|
-
|
44
39
|
describe "delete" do
|
45
|
-
subject { described_class.
|
46
|
-
|
47
|
-
|
48
|
-
expect
|
40
|
+
subject { described_class.mint(TEST_ARK_SHOULDER, status: "reserved") }
|
41
|
+
it "deletes the identifier" do
|
42
|
+
subject.delete
|
43
|
+
expect(subject).to be_deleted
|
44
|
+
expect { described_class.find(subject.id) }.to raise_error(IdentifierNotFoundError)
|
49
45
|
end
|
50
46
|
end
|
51
47
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,283 +1,349 @@
|
|
1
1
|
module Ezid
|
2
2
|
RSpec.describe Identifier do
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
describe "class methods" do
|
4
|
+
describe ".create" do
|
5
|
+
let(:args) { ["id", {profile: "dc", target: "http://example.com"}] }
|
6
|
+
it "instantiates a new Identifier and saves it" do
|
7
|
+
expect_any_instance_of(described_class).to receive(:save) { double(id: "id") }
|
8
|
+
described_class.create(*args)
|
9
|
+
end
|
10
10
|
end
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
describe ".mint" do
|
12
|
+
let(:attrs) { {profile: "dc", target: "http://example.com"} }
|
13
|
+
let(:args) { [TEST_ARK_SHOULDER, attrs] }
|
14
|
+
it "instantiates a new Identifier and saves it" do
|
15
|
+
expect_any_instance_of(described_class).to receive(:save) { double(id: "id") }
|
16
|
+
described_class.mint(*args)
|
17
|
+
end
|
18
18
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
describe ".modify" do
|
20
|
+
let(:args) { ["id", {profile: "dc", target: "http://example.com"}] }
|
21
|
+
it "instantiates a new Indentifier and modifies it" do
|
22
|
+
expect_any_instance_of(described_class).not_to receive(:save)
|
23
|
+
expect_any_instance_of(described_class).to receive(:modify!)
|
24
|
+
described_class.modify(*args)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
describe ".find" do
|
28
|
+
it "instantiates a new identifier and loads the metadata" do
|
29
|
+
expect_any_instance_of(described_class).to receive(:id=).with("id").and_call_original
|
30
|
+
expect_any_instance_of(described_class).to receive(:load_metadata) {
|
31
|
+
double(id: "id", metadata: nil)
|
32
|
+
}
|
33
|
+
described_class.find("id")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
describe ".defaults" do
|
37
|
+
before { @original_defaults = described_class.defaults }
|
38
|
+
after { described_class.defaults = @original_defaults }
|
39
|
+
it "can be set via client config" do
|
40
|
+
Client.config.identifier.defaults = {status: "reserved"}
|
41
|
+
expect(described_class.defaults).to eq({status: "reserved"})
|
42
|
+
end
|
27
43
|
end
|
28
44
|
end
|
29
45
|
|
30
|
-
describe "
|
31
|
-
describe "
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
46
|
+
describe "instance methods" do
|
47
|
+
describe "#initialize" do
|
48
|
+
before {
|
49
|
+
allow(described_class).to receive(:defaults) { defaults }
|
50
|
+
}
|
51
|
+
let(:defaults) { {} }
|
52
|
+
describe "with no arguments" do
|
53
|
+
its(:id) { is_expected.to be_nil }
|
54
|
+
describe "and no default metadata" do
|
55
|
+
its(:metadata) { is_expected.to be_empty }
|
37
56
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
it "sets the metadata" do
|
42
|
-
expect(subject.profile).to eq("dc")
|
43
|
-
expect(subject.target).to eq("http://example.com")
|
57
|
+
describe "and with default metadata" do
|
58
|
+
let(:defaults) { {export: "no"} }
|
59
|
+
its(:metadata) { is_expected.to eq({"_export"=>"no"}) }
|
44
60
|
end
|
45
61
|
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
62
|
+
describe "with an id and no metadata" do
|
63
|
+
subject { described_class.new("id") }
|
64
|
+
its(:id) { is_expected.to eq("id") }
|
65
|
+
describe "and no default metadata" do
|
66
|
+
its(:metadata) { is_expected.to be_empty }
|
67
|
+
end
|
68
|
+
describe "and with default metadata" do
|
69
|
+
let(:defaults) { {export: "no"} }
|
70
|
+
its(:metadata) { is_expected.to eq({"_export"=>"no"}) }
|
71
|
+
end
|
50
72
|
end
|
51
|
-
|
52
|
-
|
53
|
-
|
73
|
+
describe "with an id and metadata" do
|
74
|
+
subject { described_class.new("id", metadata: "_profile: dc\n_target: http://example.com", status: "reserved") }
|
75
|
+
its(:id) { is_expected.to eq("id") }
|
76
|
+
describe "and no default metadata" do
|
77
|
+
its(:metadata) { is_expected.to eq("_profile"=>"dc", "_target"=>"http://example.com", "_status"=>"reserved") }
|
78
|
+
end
|
79
|
+
describe "and with default metadata" do
|
80
|
+
let(:defaults) { {export: "no", status: "public"} }
|
81
|
+
its(:metadata) { is_expected.to eq("_profile"=>"dc", "_target"=>"http://example.com", "_status"=>"reserved", "_export"=>"no") }
|
82
|
+
end
|
54
83
|
end
|
55
|
-
|
56
|
-
subject { described_class.new(
|
57
|
-
|
58
|
-
|
59
|
-
|
84
|
+
describe "with only metadata" do
|
85
|
+
subject { described_class.new(metadata: "_profile: dc\n_target: http://example.com", status: "reserved") }
|
86
|
+
its(:id) { is_expected.to be_nil }
|
87
|
+
describe "and no default metadata" do
|
88
|
+
its(:metadata) { is_expected.to eq("_profile"=>"dc", "_target"=>"http://example.com", "_status"=>"reserved") }
|
89
|
+
end
|
90
|
+
describe "and with default metadata" do
|
91
|
+
let(:defaults) { {export: "no", status: "public"} }
|
92
|
+
its(:metadata) { is_expected.to eq("_profile"=>"dc", "_target"=>"http://example.com", "_status"=>"reserved", "_export"=>"no") }
|
60
93
|
end
|
61
94
|
end
|
62
95
|
end
|
63
|
-
end
|
64
96
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
97
|
+
describe "#update" do
|
98
|
+
let(:metadata) { {"status" => "unavailable"} }
|
99
|
+
subject { described_class.new(id: "id") }
|
100
|
+
it "updates the metadata and saves" do
|
101
|
+
expect(subject).to receive(:update_metadata).with(metadata)
|
102
|
+
expect(subject).to receive(:save) { double }
|
103
|
+
subject.update(metadata)
|
104
|
+
end
|
72
105
|
end
|
73
|
-
end
|
74
106
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
107
|
+
describe "#modify!" do
|
108
|
+
describe "when the Identifier has no id" do
|
109
|
+
specify {
|
110
|
+
expect { subject.modify! }.to raise_error(Error)
|
111
|
+
}
|
112
|
+
end
|
113
|
+
describe "when the Identifier has an id" do
|
114
|
+
specify {
|
115
|
+
subject.id = "id"
|
116
|
+
expect(subject).not_to receive(:save)
|
117
|
+
expect(subject).to receive(:modify)
|
118
|
+
subject.modify!
|
119
|
+
}
|
120
|
+
describe "when the identifier does not exist" do
|
121
|
+
specify {
|
122
|
+
subject.id = "id"
|
123
|
+
allow(subject.client).to receive(:modify_identifier).and_raise(IdentifierNotFoundError)
|
124
|
+
expect { subject.modify! }.to raise_error(IdentifierNotFoundError)
|
125
|
+
}
|
126
|
+
end
|
127
|
+
end
|
79
128
|
end
|
80
|
-
end
|
81
129
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
expect(Metadata).to receive(:new).with(metadata)
|
88
|
-
subject.load_metadata
|
130
|
+
describe "#update_metadata" do
|
131
|
+
it "updates the metadata" do
|
132
|
+
subject.update_metadata(:status => "public", _target: "localhost", "dc.creator" => "Me")
|
133
|
+
expect(subject.metadata.to_h).to eq({"_status"=>"public", "_target"=>"localhost", "dc.creator"=>"Me"})
|
134
|
+
end
|
89
135
|
end
|
90
|
-
end
|
91
136
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
137
|
+
describe "#load_metadata" do
|
138
|
+
let(:metadata) { "_profile: erc" }
|
139
|
+
before { allow(subject).to receive(:id) { "id" } }
|
140
|
+
it "replaces the remote metadata with metadata from EZID" do
|
141
|
+
expect(subject.client).to receive(:get_identifier_metadata).with("id") { double(id: "id", metadata: metadata) }
|
142
|
+
expect(subject.remote_metadata).to receive(:replace).with(metadata)
|
143
|
+
subject.load_metadata
|
144
|
+
end
|
96
145
|
end
|
97
|
-
end
|
98
146
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
147
|
+
describe "#reset_metadata" do
|
148
|
+
before {
|
149
|
+
subject.status = "public"
|
150
|
+
subject.remote_metadata.profile = "dc"
|
151
|
+
}
|
152
|
+
it "clears the local metadata" do
|
153
|
+
expect { subject.reset_metadata }
|
154
|
+
.to change { subject.metadata.empty? }
|
155
|
+
.from(false).to(true)
|
156
|
+
end
|
157
|
+
it "clears the remote metadata" do
|
158
|
+
expect { subject.reset_metadata }
|
159
|
+
.to change { subject.remote_metadata.empty? }
|
160
|
+
.from(false).to(true)
|
107
161
|
end
|
108
162
|
end
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
163
|
+
|
164
|
+
describe "#persisted?" do
|
165
|
+
describe "after initialization" do
|
166
|
+
it { is_expected.not_to be_persisted }
|
113
167
|
end
|
114
|
-
|
115
|
-
|
168
|
+
describe "when saving an unpersisted object" do
|
169
|
+
before {
|
170
|
+
allow(subject.client).to receive(:mint_identifier) { double(id: "id") }
|
171
|
+
subject.save
|
172
|
+
}
|
173
|
+
it { is_expected.to be_persisted }
|
174
|
+
end
|
175
|
+
describe "when saving a persisted object" do
|
176
|
+
before do
|
177
|
+
allow(subject).to receive(:persisted?) { true }
|
178
|
+
allow(subject).to receive(:modify) { nil }
|
179
|
+
end
|
180
|
+
it "does not change the persisted status" do
|
181
|
+
expect { subject.save }.not_to change(subject, :persisted?)
|
182
|
+
end
|
116
183
|
end
|
117
184
|
end
|
118
|
-
end
|
119
185
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
186
|
+
describe "#delete" do
|
187
|
+
context "when the identifier is reserved" do
|
188
|
+
subject { described_class.new("id", status: Status::RESERVED) }
|
189
|
+
context "and is persisted" do
|
190
|
+
before { allow(subject).to receive(:persisted?) { true } }
|
191
|
+
it "deletes the identifier" do
|
192
|
+
expect(subject.client).to receive(:delete_identifier).with("id") { double(id: "id") }
|
193
|
+
subject.delete
|
194
|
+
expect(subject).to be_deleted
|
195
|
+
end
|
196
|
+
end
|
197
|
+
context "and is not persisted" do
|
198
|
+
before { allow(subject).to receive(:persisted?) { false } }
|
199
|
+
it "raises an exception" do
|
200
|
+
expect { subject.delete }.to raise_error(Error)
|
201
|
+
end
|
129
202
|
end
|
130
203
|
end
|
131
|
-
context "
|
132
|
-
|
204
|
+
context "when identifier is not reserved" do
|
205
|
+
subject { described_class.new(id: "id", status: Status::PUBLIC) }
|
133
206
|
it "raises an exception" do
|
134
207
|
expect { subject.delete }.to raise_error(Error)
|
135
208
|
end
|
136
209
|
end
|
137
210
|
end
|
138
|
-
context "when identifier is not reserved" do
|
139
|
-
subject { described_class.new(id: "id", status: Status::PUBLIC) }
|
140
|
-
it "raises an exception" do
|
141
|
-
expect { subject.delete }.to raise_error(Error)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
211
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
subject.save
|
157
|
-
end
|
158
|
-
end
|
159
|
-
context "when the identifier is not persisted" do
|
160
|
-
before do
|
161
|
-
allow(subject).to receive(:persisted?) { false }
|
162
|
-
end
|
163
|
-
context "and `id' is present" do
|
164
|
-
before { allow(subject).to receive(:id) { "id" } }
|
165
|
-
it "creates the identifier" do
|
166
|
-
expect(subject.client).to receive(:create_identifier).with("id", subject.metadata) { double(id: "id") }
|
212
|
+
describe "#save" do
|
213
|
+
context "when the identifier is persisted" do
|
214
|
+
let(:metadata) { Metadata.new }
|
215
|
+
before do
|
216
|
+
allow(subject).to receive(:id) { "id" }
|
217
|
+
allow(subject).to receive(:persisted?) { true }
|
218
|
+
allow(subject).to receive(:metadata) { metadata }
|
219
|
+
end
|
220
|
+
it "modifies the identifier" do
|
221
|
+
expect(subject.client).to receive(:modify_identifier).with("id", metadata) { double(id: "id") }
|
167
222
|
subject.save
|
168
223
|
end
|
169
224
|
end
|
170
|
-
context "
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
225
|
+
context "when the identifier is not persisted" do
|
226
|
+
before do
|
227
|
+
allow(subject).to receive(:persisted?) { false }
|
228
|
+
end
|
229
|
+
context "and `id' is present" do
|
230
|
+
before { allow(subject).to receive(:id) { "id" } }
|
231
|
+
it "creates the identifier" do
|
232
|
+
expect(subject.client).to receive(:create_identifier).with("id", subject.metadata) { double(id: "id") }
|
175
233
|
subject.save
|
176
234
|
end
|
177
235
|
end
|
178
|
-
context "and `
|
179
|
-
|
180
|
-
|
181
|
-
|
236
|
+
context "and `id' is not present" do
|
237
|
+
context "and `shoulder' is present" do
|
238
|
+
before { allow(subject).to receive(:shoulder) { TEST_ARK_SHOULDER } }
|
239
|
+
it "mints the identifier" do
|
240
|
+
expect(subject.client).to receive(:mint_identifier).with(TEST_ARK_SHOULDER, subject.metadata) { double(id: "id") }
|
241
|
+
subject.save
|
242
|
+
end
|
243
|
+
end
|
244
|
+
context "and `shoulder' is not present" do
|
245
|
+
before { allow(Client.config).to receive(:default_shoulder) { nil } }
|
246
|
+
it "raises an exception" do
|
247
|
+
expect { subject.save }.to raise_error(Error)
|
248
|
+
end
|
182
249
|
end
|
183
250
|
end
|
184
251
|
end
|
185
252
|
end
|
186
|
-
end
|
187
253
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
it { is_expected.not_to be_reserved }
|
193
|
-
it { is_expected.not_to be_unavailable }
|
194
|
-
end
|
195
|
-
context "when the identifier is reserved" do
|
196
|
-
before { subject.status = Status::RESERVED }
|
197
|
-
it { is_expected.not_to be_public }
|
198
|
-
it { is_expected.to be_reserved }
|
199
|
-
it { is_expected.not_to be_unavailable }
|
200
|
-
end
|
201
|
-
context "when the identifier is unavailable" do
|
202
|
-
context "and it has no reason" do
|
203
|
-
before { subject.unavailable! }
|
204
|
-
it { is_expected.not_to be_public }
|
254
|
+
describe "boolean status methods" do
|
255
|
+
context "when the identifier is public" do
|
256
|
+
before { subject.public! }
|
257
|
+
it { is_expected.to be_public }
|
205
258
|
it { is_expected.not_to be_reserved }
|
206
|
-
it { is_expected.
|
259
|
+
it { is_expected.not_to be_unavailable }
|
207
260
|
end
|
208
|
-
context "
|
209
|
-
before { subject.
|
261
|
+
context "when the identifier is reserved" do
|
262
|
+
before { subject.status = Status::RESERVED }
|
210
263
|
it { is_expected.not_to be_public }
|
211
|
-
it { is_expected.
|
212
|
-
it { is_expected.
|
264
|
+
it { is_expected.to be_reserved }
|
265
|
+
it { is_expected.not_to be_unavailable }
|
266
|
+
end
|
267
|
+
context "when the identifier is unavailable" do
|
268
|
+
context "and it has no reason" do
|
269
|
+
before { subject.unavailable! }
|
270
|
+
it { is_expected.not_to be_public }
|
271
|
+
it { is_expected.not_to be_reserved }
|
272
|
+
it { is_expected.to be_unavailable }
|
273
|
+
end
|
274
|
+
context "and it has a reason" do
|
275
|
+
before { subject.unavailable!("withdrawn") }
|
276
|
+
it { is_expected.not_to be_public }
|
277
|
+
it { is_expected.not_to be_reserved }
|
278
|
+
it { is_expected.to be_unavailable }
|
279
|
+
end
|
213
280
|
end
|
214
281
|
end
|
215
|
-
end
|
216
282
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
283
|
+
describe "status-changing methods" do
|
284
|
+
subject { described_class.new(id: "id", status: status) }
|
285
|
+
describe "#unavailable!" do
|
286
|
+
context "when the status is \"unavailable\"" do
|
287
|
+
let(:status) { "#{Status::UNAVAILABLE} | whatever" }
|
288
|
+
context "and no reason is given" do
|
289
|
+
it "logs a warning" do
|
290
|
+
pending "https://github.com/duke-libraries/ezid-client/issues/46"
|
291
|
+
allow_message_expectations_on_nil
|
292
|
+
expect(subject.logger).to receive(:warn)
|
293
|
+
subject.unavailable!
|
294
|
+
end
|
295
|
+
it "does not change the status" do
|
296
|
+
expect { subject.unavailable! }.not_to change(subject, :status)
|
297
|
+
end
|
228
298
|
end
|
229
|
-
|
230
|
-
|
299
|
+
context "and a reason is given" do
|
300
|
+
it "logs a warning" do
|
301
|
+
pending "https://github.com/duke-libraries/ezid-client/issues/46"
|
302
|
+
allow_message_expectations_on_nil
|
303
|
+
expect(subject.logger).to receive(:warn)
|
304
|
+
subject.unavailable!("because")
|
305
|
+
end
|
306
|
+
it "should change the status" do
|
307
|
+
expect { subject.unavailable!("because") }.to change(subject, :status).from(status).to("#{Status::UNAVAILABLE} | because")
|
308
|
+
end
|
231
309
|
end
|
232
310
|
end
|
233
|
-
context "
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
311
|
+
context "when the status is \"reserved\"" do
|
312
|
+
let(:status) { Status::RESERVED }
|
313
|
+
context "and persisted" do
|
314
|
+
before { allow(subject).to receive(:persisted?) { true } }
|
315
|
+
it "raises an exception" do
|
316
|
+
expect { subject.unavailable! }.to raise_error(Error)
|
317
|
+
end
|
239
318
|
end
|
240
|
-
|
241
|
-
|
319
|
+
context "and not persisted" do
|
320
|
+
before { allow(subject).to receive(:persisted?) { false } }
|
321
|
+
it "changes the status" do
|
322
|
+
expect { subject.unavailable! }.to change(subject, :status).from(Status::RESERVED).to(Status::UNAVAILABLE)
|
323
|
+
end
|
242
324
|
end
|
243
325
|
end
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
expect { subject.unavailable! }.to raise_error(Error)
|
326
|
+
context "when the status is \"public\"" do
|
327
|
+
let(:status) { Status::PUBLIC }
|
328
|
+
context "and no reason is given" do
|
329
|
+
it "changes the status" do
|
330
|
+
expect { subject.unavailable! }.to change(subject, :status).from(Status::PUBLIC).to(Status::UNAVAILABLE)
|
331
|
+
end
|
251
332
|
end
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
expect { subject.unavailable! }.to change(subject, :status).from(Status::RESERVED).to(Status::UNAVAILABLE)
|
333
|
+
context "and a reason is given" do
|
334
|
+
it "changes the status and appends the reason" do
|
335
|
+
expect { subject.unavailable!("withdrawn") }.to change(subject, :status).from(Status::PUBLIC).to("#{Status::UNAVAILABLE} | withdrawn")
|
336
|
+
end
|
257
337
|
end
|
258
338
|
end
|
259
339
|
end
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
expect { subject.unavailable! }.to change(subject, :status).from(Status::PUBLIC).to(Status::UNAVAILABLE)
|
265
|
-
end
|
340
|
+
describe "#public!" do
|
341
|
+
subject { described_class.new(id: "id", status: Status::UNAVAILABLE) }
|
342
|
+
it "changes the status" do
|
343
|
+
expect { subject.public! }.to change(subject, :status).from(Status::UNAVAILABLE).to(Status::PUBLIC)
|
266
344
|
end
|
267
|
-
context "and a reason is given" do
|
268
|
-
it "changes the status and appends the reason" do
|
269
|
-
expect { subject.unavailable!("withdrawn") }.to change(subject, :status).from(Status::PUBLIC).to("#{Status::UNAVAILABLE} | withdrawn")
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
273
|
-
end
|
274
|
-
describe "#public!" do
|
275
|
-
subject { described_class.new(id: "id", status: Status::UNAVAILABLE) }
|
276
|
-
it "changes the status" do
|
277
|
-
expect { subject.public! }.to change(subject, :status).from(Status::UNAVAILABLE).to(Status::PUBLIC)
|
278
345
|
end
|
279
346
|
end
|
280
347
|
end
|
281
|
-
|
282
348
|
end
|
283
349
|
end
|