ddr-models 2.0.1 → 2.1.0.rc1
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 +23 -17
- data/app/models/collection.rb +1 -35
- data/ddr-models.gemspec +2 -1
- data/lib/ddr/actions.rb +1 -0
- data/lib/ddr/actions/virus_check.rb +28 -0
- data/lib/ddr/auth.rb +4 -0
- data/lib/ddr/auth/ability_definitions/datastream_ability_definitions.rb +7 -5
- data/lib/ddr/auth/grouper_gateway.rb +9 -1
- data/lib/ddr/auth/permissions.rb +2 -1
- data/lib/ddr/auth/role_based_access_controls_enforcement.rb +5 -5
- data/lib/ddr/auth/roles/role_types.rb +2 -1
- data/lib/ddr/datastreams.rb +2 -2
- data/lib/ddr/datastreams/administrative_metadata_datastream.rb +27 -14
- data/lib/ddr/datastreams/datastream_behavior.rb +13 -0
- data/lib/ddr/datastreams/fits_datastream.rb +88 -0
- data/lib/ddr/derivatives/png_generator.rb +2 -0
- data/lib/ddr/derivatives/ptif_generator.rb +2 -0
- data/lib/ddr/events/fixity_check_event.rb +2 -2
- data/lib/ddr/events/virus_check_event.rb +2 -14
- data/lib/ddr/index.rb +29 -0
- data/lib/ddr/index/abstract_query_result.rb +23 -0
- data/lib/ddr/index/connection.rb +17 -0
- data/lib/ddr/index/csv_query_result.rb +61 -0
- data/lib/ddr/index/document_builder.rb +9 -0
- data/lib/ddr/index/field.rb +23 -0
- data/lib/ddr/index/fields.rb +83 -0
- data/lib/ddr/index/filter.rb +48 -0
- data/lib/ddr/index/filters.rb +19 -0
- data/lib/ddr/index/legacy_license_fields.rb +14 -0
- data/lib/ddr/index/query.rb +35 -0
- data/lib/ddr/index/query_builder.rb +74 -0
- data/lib/ddr/index/query_clause.rb +52 -0
- data/lib/ddr/index/query_result.rb +70 -0
- data/lib/ddr/index/query_value.rb +16 -0
- data/lib/ddr/index/response.rb +13 -0
- data/lib/ddr/index/unique_key_field.rb +12 -0
- data/lib/ddr/index_fields.rb +7 -53
- data/lib/ddr/jobs.rb +1 -1
- data/lib/ddr/jobs/fits_file_characterization.rb +51 -0
- data/lib/ddr/managers.rb +1 -0
- data/lib/ddr/managers/technical_metadata_manager.rb +104 -0
- data/lib/ddr/models.rb +39 -23
- data/lib/ddr/models/base.rb +0 -2
- data/lib/ddr/models/describable.rb +1 -1
- data/lib/ddr/models/effective_license.rb +9 -0
- data/lib/ddr/models/engine.rb +13 -0
- data/lib/ddr/models/file_management.rb +157 -160
- data/lib/ddr/models/governable.rb +0 -4
- data/lib/ddr/models/has_admin_metadata.rb +80 -72
- data/lib/ddr/models/has_children.rb +1 -1
- data/lib/ddr/models/has_content.rb +18 -0
- data/lib/ddr/models/has_struct_metadata.rb +5 -1
- data/lib/ddr/models/indexing.rb +32 -20
- data/lib/ddr/models/inherited_license.rb +13 -0
- data/lib/ddr/models/license.rb +38 -0
- data/lib/ddr/models/solr_document.rb +195 -211
- data/lib/ddr/models/version.rb +1 -1
- data/lib/ddr/models/year_facet.rb +154 -0
- data/lib/ddr/utils.rb +13 -1
- data/lib/ddr/vocab/roles.rb +0 -10
- data/spec/controllers/including_role_based_access_controls_enforcement_spec.rb +4 -4
- data/spec/datastreams/fits_datastream_spec.rb +84 -0
- data/spec/fixtures/fits/document.xml +65 -0
- data/spec/fixtures/fits/image.xml +59 -0
- data/spec/index/filter_spec.rb +47 -0
- data/spec/index/filters_spec.rb +17 -0
- data/spec/index/query_spec.rb +19 -0
- data/spec/jobs/fits_file_characterization_spec.rb +52 -0
- data/spec/managers/technical_metadata_manager_spec.rb +140 -0
- data/spec/models/active_fedora_datastream_spec.rb +44 -0
- data/spec/models/collection_spec.rb +7 -12
- data/spec/models/component_spec.rb +3 -6
- data/spec/models/effective_license_spec.rb +49 -0
- data/spec/models/has_admin_metadata_spec.rb +143 -194
- data/spec/models/has_struct_metadata_spec.rb +2 -2
- data/spec/models/indexing_spec.rb +40 -0
- data/spec/models/solr_document_spec.rb +96 -37
- data/spec/models/year_facet_spec.rb +65 -0
- data/spec/spec_helper.rb +1 -7
- data/spec/support/shared_examples_for_ddr_models.rb +0 -2
- data/spec/support/shared_examples_for_has_content.rb +37 -3
- metadata +79 -32
- data/lib/ddr/datastreams/properties_datastream.rb +0 -25
- data/lib/ddr/jobs/migrate_legacy_authorization.rb +0 -23
- data/lib/ddr/models/has_properties.rb +0 -15
- data/lib/ddr/models/licensable.rb +0 -28
- data/spec/auth/legacy_authorization_spec.rb +0 -94
- data/spec/auth/legacy_roles_spec.rb +0 -32
- data/spec/jobs/migrate_legacy_authorization_spec.rb +0 -43
- data/spec/support/shared_examples_for_has_properties.rb +0 -5
- data/spec/support/shared_examples_for_licensable.rb +0 -15
@@ -0,0 +1,17 @@
|
|
1
|
+
module Ddr::Index
|
2
|
+
RSpec.describe Filters do
|
3
|
+
|
4
|
+
describe "HAS_CONTENT" do
|
5
|
+
subject { Filters::HAS_CONTENT }
|
6
|
+
its(:clauses) { is_expected.to eq(["active_fedora_model_ssi:(Component OR Attachment OR Target)"]) }
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "class methods" do
|
10
|
+
describe "is_governed_by(pid)" do
|
11
|
+
subject { Filters.is_governed_by("test:1") }
|
12
|
+
its(:clauses) { is_expected.to eq(["{!term f=is_governed_by_ssim}info:fedora/test:1"]) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Ddr::Index
|
2
|
+
RSpec.describe Query do
|
3
|
+
|
4
|
+
subject do
|
5
|
+
QueryBuilder.build do |query|
|
6
|
+
query
|
7
|
+
.q("foo:bar")
|
8
|
+
.where("spam"=>"eggs")
|
9
|
+
.fields("id", "foo", "spam")
|
10
|
+
.limit(50)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
its(:to_s) { is_expected.to eq("q=foo%3Abar&fq=%7B%21term+f%3Dspam%7Deggs&fl=id%2Cfoo%2Cspam&rows=50") }
|
15
|
+
|
16
|
+
its(:params) { is_expected.to eq({q: "foo:bar", fl: "id,foo,spam", fq: ["{!term f=spam}eggs"], rows: 50}) }
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Ddr::Jobs
|
4
|
+
RSpec.describe FitsFileCharacterization, jobs: true, file_characterization: true do
|
5
|
+
|
6
|
+
shared_examples "has a fits update event" do
|
7
|
+
let(:event) { object.update_events.last }
|
8
|
+
it "should have the correct event attributes" do
|
9
|
+
expect(event.outcome).to eq(expected_outcome)
|
10
|
+
expect(event.detail).to eq(expected_detail)
|
11
|
+
expect(event.software).to eq("fits #{fits_version}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "content-bearing object" do
|
16
|
+
let(:object) { TestContent.create }
|
17
|
+
let(:stdout_msg) { '<fits />' }
|
18
|
+
let(:stderr_msg) { 'stderr msg' }
|
19
|
+
let(:fits_version) { '0.9.9 '}
|
20
|
+
before { allow(Ddr::Jobs::FitsFileCharacterization).to receive(:fits_version) { fits_version } }
|
21
|
+
context "fits command is successful" do
|
22
|
+
let(:expected_outcome) { Ddr::Events::Event::SUCCESS }
|
23
|
+
let(:expected_detail) { nil }
|
24
|
+
before do
|
25
|
+
allow(Open3).to receive(:capture3) { [ stdout_msg, stderr_msg, $? ] }
|
26
|
+
allow_any_instance_of(Process::Status).to receive(:success?) { true }
|
27
|
+
Ddr::Jobs::FitsFileCharacterization.perform(object.pid)
|
28
|
+
object.reload
|
29
|
+
end
|
30
|
+
it "should populate the fits datastream" do
|
31
|
+
expect(object.fits.content).to be_present
|
32
|
+
end
|
33
|
+
it_behaves_like "has a fits update event"
|
34
|
+
end
|
35
|
+
context "fits command is not successful" do
|
36
|
+
let(:expected_outcome) { Ddr::Events::Event::FAILURE }
|
37
|
+
let(:expected_detail) { stderr_msg }
|
38
|
+
before do
|
39
|
+
allow(Open3).to receive(:capture3) { [ stdout_msg, stderr_msg, $? ] }
|
40
|
+
allow_any_instance_of(Process::Status).to receive(:success?) { false }
|
41
|
+
Ddr::Jobs::FitsFileCharacterization.perform(object.pid)
|
42
|
+
object.reload
|
43
|
+
end
|
44
|
+
it "should not populate the fits datastream" do
|
45
|
+
expect(object.fits.content).to_not be_present
|
46
|
+
end
|
47
|
+
it_behaves_like "has a fits update event"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Ddr::Managers
|
4
|
+
RSpec.describe TechnicalMetadataManager do
|
5
|
+
|
6
|
+
subject { described_class.new(obj) }
|
7
|
+
|
8
|
+
let(:obj) { Component.new }
|
9
|
+
|
10
|
+
describe "when fits datastream not present" do
|
11
|
+
its(:valid) { is_expected.to be_empty }
|
12
|
+
its(:well_formed) { is_expected.to be_empty }
|
13
|
+
its(:format_label) { is_expected.to be_empty }
|
14
|
+
its(:media_type) { is_expected.to be_empty }
|
15
|
+
its(:format_version) { is_expected.to be_empty }
|
16
|
+
its(:last_modified) { is_expected.to be_empty }
|
17
|
+
its(:modification_time) { is_expected.to be_empty }
|
18
|
+
its(:created) { is_expected.to be_empty }
|
19
|
+
its(:creation_time) { is_expected.to be_empty }
|
20
|
+
its(:pronom_identifier) { is_expected.to be_empty }
|
21
|
+
its(:creating_application) { is_expected.to be_empty }
|
22
|
+
its(:file_size) { is_expected.to be_empty }
|
23
|
+
its(:fits_version) { is_expected.to be_nil }
|
24
|
+
its(:fits_datetime) { is_expected.to be_nil }
|
25
|
+
its(:fits?) { is_expected.to be false }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "when content is not present" do
|
29
|
+
its(:checksum_digest) { is_expected.to be_nil }
|
30
|
+
its(:checksum_value) { is_expected.to be_nil }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "common metadata" do
|
34
|
+
before do
|
35
|
+
obj.fits.content = fixture_file_upload(File.join("fits", "document.xml"))
|
36
|
+
end
|
37
|
+
its(:fits?) { is_expected.to be true }
|
38
|
+
its(:valid) { is_expected.to eq(["false"]) }
|
39
|
+
its(:well_formed) { is_expected.to eq(["true"]) }
|
40
|
+
its(:format_label) { is_expected.to eq(["Portable Document Format"]) }
|
41
|
+
its(:media_type) { is_expected.to eq(["application/pdf"]) }
|
42
|
+
its(:format_version) { is_expected.to eq(["1.6"]) }
|
43
|
+
its(:last_modified) { is_expected.to eq(["2015-06-08T21:22:35Z"]) }
|
44
|
+
its(:created) { is_expected.to eq(["2015:06:05 15:16:23-04:00"]) }
|
45
|
+
its(:pronom_identifier) { is_expected.to eq(["fmt/20"]) }
|
46
|
+
its(:creating_application) { is_expected.to contain_exactly("Adobe Acrobat Pro 11.0.3 Paper Capture Plug-in/PREMIS Editorial Committee", "Adobe Acrobat Pro 11.0.3 Paper Capture Plug-in/Acrobat PDFMaker 11 for Word") }
|
47
|
+
its(:fits_version) { is_expected.to eq("0.8.5") }
|
48
|
+
its(:extent) { is_expected.to eq(["3786205"]) }
|
49
|
+
its(:file_size) { is_expected.to eq([3786205]) }
|
50
|
+
its(:media_type) { is_expected.to eq(["application/pdf"]) }
|
51
|
+
|
52
|
+
describe "datetime fields" do
|
53
|
+
its(:creation_time) { is_expected.to contain_exactly(DateTime.parse("2015-06-05 15:16:23-04:00").to_time.utc) }
|
54
|
+
its(:modification_time) { is_expected.to contain_exactly(DateTime.parse("2015-06-08T21:22:35Z").to_time.utc) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "checksum fields" do
|
59
|
+
before do
|
60
|
+
allow(obj.content).to receive(:checksumType) { "SHA-256" }
|
61
|
+
allow(obj.content).to receive(:checksum) { "b744b4b308a11a7b6282b383ec428a91d77b21701d4bd09021bf0543dc8946fa" }
|
62
|
+
end
|
63
|
+
|
64
|
+
its(:checksum_digest) { is_expected.to eq("SHA-256") }
|
65
|
+
its(:checksum_value) { is_expected.to eq("b744b4b308a11a7b6282b383ec428a91d77b21701d4bd09021bf0543dc8946fa") }
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "image metadata" do
|
69
|
+
before do
|
70
|
+
obj.fits.content = fixture_file_upload(File.join("fits", "image.xml"))
|
71
|
+
end
|
72
|
+
its(:image_width) { is_expected.to eq(["500"]) }
|
73
|
+
its(:image_height) { is_expected.to eq(["569"]) }
|
74
|
+
its(:color_space) { is_expected.to eq(["YCbCr"]) }
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "valid? / invalid?" do
|
78
|
+
describe "when #valid has a 'false' value" do
|
79
|
+
before do
|
80
|
+
allow(subject).to receive(:valid) { ["false"] }
|
81
|
+
end
|
82
|
+
it { is_expected.to be_invalid }
|
83
|
+
it { is_expected.not_to be_valid }
|
84
|
+
end
|
85
|
+
describe "when #valid has 'false' and 'true' values" do
|
86
|
+
before do
|
87
|
+
allow(subject).to receive(:valid) { ["false", "true"] }
|
88
|
+
end
|
89
|
+
it { is_expected.to be_invalid }
|
90
|
+
it { is_expected.not_to be_valid }
|
91
|
+
end
|
92
|
+
describe "when #valid has a 'true' value" do
|
93
|
+
before do
|
94
|
+
allow(subject).to receive(:valid) { ["true"] }
|
95
|
+
end
|
96
|
+
it { is_expected.not_to be_invalid }
|
97
|
+
it { is_expected.to be_valid }
|
98
|
+
end
|
99
|
+
describe "when #valid is empty" do
|
100
|
+
before do
|
101
|
+
allow(subject).to receive(:valid) { [] }
|
102
|
+
end
|
103
|
+
it { is_expected.not_to be_invalid }
|
104
|
+
it { is_expected.to be_valid }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "ill_formed? / well_formed?" do
|
109
|
+
describe "when #well_formed has a 'false' value" do
|
110
|
+
before do
|
111
|
+
allow(subject).to receive(:well_formed) { ["false"] }
|
112
|
+
end
|
113
|
+
it { is_expected.to be_ill_formed }
|
114
|
+
it { is_expected.not_to be_well_formed }
|
115
|
+
end
|
116
|
+
describe "when #well_formed has 'false' and 'true' values" do
|
117
|
+
before do
|
118
|
+
allow(subject).to receive(:well_formed) { ["false", "true"] }
|
119
|
+
end
|
120
|
+
it { is_expected.to be_ill_formed }
|
121
|
+
it { is_expected.not_to be_well_formed }
|
122
|
+
end
|
123
|
+
describe "when #well_formed has a 'true' value" do
|
124
|
+
before do
|
125
|
+
allow(subject).to receive(:well_formed) { ["true"] }
|
126
|
+
end
|
127
|
+
it { is_expected.not_to be_ill_formed }
|
128
|
+
it { is_expected.to be_well_formed }
|
129
|
+
end
|
130
|
+
describe "when #well_formed is empty" do
|
131
|
+
before do
|
132
|
+
allow(subject).to receive(:well_formed) { [] }
|
133
|
+
end
|
134
|
+
it { is_expected.not_to be_ill_formed }
|
135
|
+
it { is_expected.to be_well_formed }
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
@@ -3,6 +3,50 @@ require 'spec_helper'
|
|
3
3
|
module ActiveFedora
|
4
4
|
RSpec.describe Datastream do
|
5
5
|
|
6
|
+
describe "#tempfile" do
|
7
|
+
subject { described_class.new(nil, "DS1", controlGroup: "M") }
|
8
|
+
describe "when the datastream has no content" do
|
9
|
+
it "should raise an exception" do
|
10
|
+
expect { subject.tempfile { |f| puts f.path } }.to raise_error(Ddr::Models::Error)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
describe "when the datastream has content" do
|
14
|
+
let(:file) { fixture_file_upload("sample.pdf", "application/pdf") }
|
15
|
+
before do
|
16
|
+
subject.content = file.read
|
17
|
+
subject.mimeType = file.content_type
|
18
|
+
allow(subject).to receive(:pid) { "test:1" }
|
19
|
+
end
|
20
|
+
describe "the yielded file" do
|
21
|
+
it "should by default have an extension for the datastream media type" do
|
22
|
+
subject.tempfile do |f|
|
23
|
+
expect(f.path.end_with?(".pdf")).to be true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
it "should use the prefix provided" do
|
27
|
+
subject.tempfile(prefix: "foo") do |f|
|
28
|
+
expect(File.basename(f.path).start_with?("foo")).to be true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
it "should use the sufffix provided" do
|
32
|
+
subject.tempfile(suffix: "bar") do |f|
|
33
|
+
expect(f.path.end_with?("bar")).to be true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
it "should by default have a prefix based on the PID" do
|
37
|
+
subject.tempfile do |f|
|
38
|
+
expect(File.basename(f.path).start_with?("test_1_DS1--")).to be true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
it "should have the same size as the datastream content" do
|
42
|
+
subject.tempfile do |f|
|
43
|
+
expect(f.size).to eq(subject.content.length)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
6
50
|
describe "#validate_checksum!" do
|
7
51
|
subject { described_class.new(nil, nil, controlGroup: "M") }
|
8
52
|
let!(:checksum) { "dea56f15b309e47b74fa24797f85245dda0ca3d274644a96804438bbd659555a" }
|
@@ -6,21 +6,16 @@ RSpec.describe Collection, type: :model do
|
|
6
6
|
it_behaves_like "it has an association", :has_many, :children, :is_member_of_collection, "Item"
|
7
7
|
it_behaves_like "it has an association", :has_many, :targets, :is_external_target_for, "Target"
|
8
8
|
|
9
|
-
describe "
|
9
|
+
describe "legacy license information" do
|
10
10
|
before do
|
11
|
-
subject.
|
12
|
-
subject.
|
13
|
-
subject.
|
14
|
-
end
|
15
|
-
it "should set the terms correctly" do
|
16
|
-
expect(subject.defaultRights.license.title.first).to eq("License Title")
|
17
|
-
expect(subject.defaultRights.license.description.first).to eq("License Description")
|
18
|
-
expect(subject.defaultRights.license.url.first).to eq("http://library.duke.edu")
|
11
|
+
subject.defaultRights.license.title = ["License Title"]
|
12
|
+
subject.defaultRights.license.description = ["License Description"]
|
13
|
+
subject.defaultRights.license.url = ["http://library.duke.edu"]
|
19
14
|
end
|
20
15
|
it "should index the terms" do
|
21
|
-
expect(subject.to_solr[Ddr::
|
22
|
-
expect(subject.to_solr[Ddr::
|
23
|
-
expect(subject.to_solr[Ddr::
|
16
|
+
expect(subject.to_solr[Ddr::Index::Fields::DEFAULT_LICENSE_TITLE]).to eq("License Title")
|
17
|
+
expect(subject.to_solr[Ddr::Index::Fields::DEFAULT_LICENSE_DESCRIPTION]).to eq("License Description")
|
18
|
+
expect(subject.to_solr[Ddr::Index::Fields::DEFAULT_LICENSE_URL]).to eq("http://library.duke.edu")
|
24
19
|
end
|
25
20
|
end
|
26
21
|
|
@@ -9,14 +9,11 @@ RSpec.describe Component, type: :model, components: true do
|
|
9
9
|
it_behaves_like "a non-collection model"
|
10
10
|
|
11
11
|
describe "indexing" do
|
12
|
-
|
12
|
+
subject { FactoryGirl.build(:component) }
|
13
13
|
before do
|
14
|
-
|
15
|
-
end
|
16
|
-
it "should include the COLLECTION_URI field in its indexing" do
|
17
|
-
expect(component.index_fields).to have_key(Ddr::IndexFields::COLLECTION_URI)
|
18
|
-
expect(component.index_fields[Ddr::IndexFields::COLLECTION_URI]).to eq('info:fedora/test:1')
|
14
|
+
allow(subject).to receive(:collection) { Collection.new(pid: "test:1") }
|
19
15
|
end
|
16
|
+
its(:index_fields) { is_expected.to include(Ddr::Index::Fields::COLLECTION_URI => "info:fedora/test:1") }
|
20
17
|
end
|
21
18
|
|
22
19
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Ddr::Models
|
2
|
+
RSpec.describe EffectiveLicense do
|
3
|
+
|
4
|
+
subject { described_class.call(obj) }
|
5
|
+
|
6
|
+
let(:mock) { Struct.new(:license, :parent, :admin_policy, :pid) }
|
7
|
+
let(:obj) { mock.new }
|
8
|
+
|
9
|
+
let(:url) { "https://creativecommons.org/licenses/by-nc-nd/4.0/" }
|
10
|
+
let(:license) { License.new(url: url) }
|
11
|
+
before { allow(License).to receive(:get).with(url) { license } }
|
12
|
+
|
13
|
+
describe "when the object has a licence" do
|
14
|
+
before { obj.license = url }
|
15
|
+
it { is_expected.to eq(license) }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "when the object does not have a license" do
|
19
|
+
describe "when the object has a parent" do
|
20
|
+
let(:parent) { mock.new }
|
21
|
+
before do
|
22
|
+
parent.license = url
|
23
|
+
obj.parent = parent
|
24
|
+
end
|
25
|
+
it { is_expected.to eq(license) }
|
26
|
+
end
|
27
|
+
describe "when the object does not have a parent" do
|
28
|
+
describe "when the object has an admin policy" do
|
29
|
+
describe "and the admin policy is a different object" do
|
30
|
+
let(:admin_policy) { mock.new }
|
31
|
+
before do
|
32
|
+
admin_policy.license = url
|
33
|
+
obj.admin_policy = admin_policy
|
34
|
+
end
|
35
|
+
it { is_expected.to eq(license) }
|
36
|
+
end
|
37
|
+
describe "and the admin policy is the object itself" do
|
38
|
+
before { obj.admin_policy = obj }
|
39
|
+
it { is_expected.to be_nil }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
describe "otherwise" do
|
43
|
+
it { is_expected.to be_nil }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -1,246 +1,195 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'support/ezid_mock_identifier'
|
3
3
|
|
4
|
-
module Ddr
|
5
|
-
|
6
|
-
RSpec.describe HasAdminMetadata, type: :model, contacts: true do
|
7
|
-
|
8
|
-
describe "local id" do
|
9
|
-
subject { FactoryGirl.build(:item) }
|
10
|
-
describe "indexing" do
|
11
|
-
before { subject.local_id = "foo" }
|
12
|
-
it "should index the local id value" do
|
13
|
-
expect(subject.to_solr).to include(Ddr::IndexFields::LOCAL_ID => "foo")
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
4
|
+
module Ddr::Models
|
5
|
+
RSpec.describe HasAdminMetadata, type: :model, contacts: true do
|
17
6
|
|
18
|
-
|
19
|
-
|
7
|
+
describe "permanent id and permanent url" do
|
8
|
+
subject { FactoryGirl.build(:item) }
|
20
9
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
34
|
-
context "and auto-assignment is disabled" do
|
35
|
-
before { allow(Ddr::Models).to receive(:auto_assign_permanent_ids) { false } }
|
36
|
-
it "should not assign a permanent id" do
|
37
|
-
expect(subject).not_to receive(:assign_permanent_id!)
|
38
|
-
subject.save!
|
39
|
-
end
|
10
|
+
describe "#assign_permanent_id!" do
|
11
|
+
it "should assign the permanent id later" do
|
12
|
+
expect(subject.permanent_id_manager).to receive(:assign_later) { nil }
|
13
|
+
subject.assign_permanent_id!
|
14
|
+
end
|
15
|
+
context "when the object is created (first saved)" do
|
16
|
+
context "and auto-assignment is enabled" do
|
17
|
+
before { allow(Ddr::Models).to receive(:auto_assign_permanent_ids) { true } }
|
18
|
+
it "should assign a permanent id" do
|
19
|
+
expect(subject).to receive(:assign_permanent_id!) { nil }
|
20
|
+
subject.save!
|
40
21
|
end
|
41
22
|
end
|
42
|
-
context "
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
subject.save!
|
48
|
-
subject.title = ["New Title"]
|
49
|
-
subject.save!
|
50
|
-
end
|
51
|
-
end
|
52
|
-
context "and auto-assignment is disabled" do
|
53
|
-
before { allow(Ddr::Models).to receive(:auto_assign_permanent_ids) { false } }
|
54
|
-
it "should not assign a permanent id" do
|
55
|
-
expect(subject).not_to receive(:assign_permanent_id!)
|
56
|
-
subject.save!
|
57
|
-
end
|
23
|
+
context "and auto-assignment is disabled" do
|
24
|
+
before { allow(Ddr::Models).to receive(:auto_assign_permanent_ids) { false } }
|
25
|
+
it "should not assign a permanent id" do
|
26
|
+
expect(subject).not_to receive(:assign_permanent_id!)
|
27
|
+
subject.save!
|
58
28
|
end
|
59
29
|
end
|
60
30
|
end
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
it "should update the status of the identifier when the object is destroyed" do
|
71
|
-
expect { subject.destroy }.to change(identifier, :status).from("public").to("unavailable | deleted")
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
describe "events" do
|
76
|
-
before { allow(Ddr::Models).to receive(:auto_assign_permanent_ids) { true } }
|
77
|
-
context "when the operation succeeds" do
|
78
|
-
let!(:mock_identifier) { Ezid::MockIdentifier.new(id: "ark:/99999/fk4zzz",
|
79
|
-
metadata: "_target: http://example.com") }
|
80
|
-
before do
|
81
|
-
allow(Ezid::Identifier).to receive(:create) { mock_identifier }
|
82
|
-
allow(Ezid::Identifier).to receive(:find) { mock_identifier }
|
83
|
-
allow(subject.permanent_id_manager).to receive(:record) { mock_identifier }
|
84
|
-
end
|
85
|
-
it "should create a success event" do
|
86
|
-
expect { subject.save }.to change { subject.update_events.count }.by(1)
|
31
|
+
context "when saved" do
|
32
|
+
context "and auto-assignment is enabled" do
|
33
|
+
before { allow(Ddr::Models).to receive(:auto_assign_permanent_ids) { true } }
|
34
|
+
it "should assign a permanent id once" do
|
35
|
+
expect(subject).to receive(:assign_permanent_id!).once { nil }
|
36
|
+
subject.save!
|
37
|
+
subject.title = ["New Title"]
|
38
|
+
subject.save!
|
87
39
|
end
|
88
40
|
end
|
89
|
-
context "
|
90
|
-
before { allow(
|
91
|
-
it "should
|
92
|
-
|
93
|
-
|
94
|
-
rescue Ezid::Error
|
95
|
-
end
|
96
|
-
expect(subject.update_events.last).to be_failure
|
41
|
+
context "and auto-assignment is disabled" do
|
42
|
+
before { allow(Ddr::Models).to receive(:auto_assign_permanent_ids) { false } }
|
43
|
+
it "should not assign a permanent id" do
|
44
|
+
expect(subject).not_to receive(:assign_permanent_id!)
|
45
|
+
subject.save!
|
97
46
|
end
|
98
47
|
end
|
99
48
|
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "lifecycle" do
|
52
|
+
let!(:identifier) { Ezid::MockIdentifier.new(id: "ark:/99999/fk4zzz", status: "public") }
|
53
|
+
before do
|
54
|
+
allow(Ddr::Models).to receive(:auto_assign_permanent_ids) { false }
|
55
|
+
allow(Ezid::Identifier).to receive(:find).with("ark:/99999/fk4zzz") { identifier }
|
56
|
+
subject.permanent_id = "ark:/99999/fk4zzz"
|
57
|
+
subject.save!
|
58
|
+
end
|
59
|
+
it "should update the status of the identifier when the object is destroyed" do
|
60
|
+
expect { subject.destroy }.to change(identifier, :status).from("public").to("unavailable | deleted")
|
61
|
+
end
|
62
|
+
end
|
100
63
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
let(:
|
64
|
+
describe "events" do
|
65
|
+
before { allow(Ddr::Models).to receive(:auto_assign_permanent_ids) { true } }
|
66
|
+
context "when the operation succeeds" do
|
67
|
+
let!(:mock_identifier) { Ezid::MockIdentifier.new(id: "ark:/99999/fk4zzz",
|
68
|
+
metadata: "_target: http://example.com") }
|
105
69
|
before do
|
106
|
-
|
107
|
-
|
108
|
-
subject.
|
70
|
+
allow(Ezid::Identifier).to receive(:create) { mock_identifier }
|
71
|
+
allow(Ezid::Identifier).to receive(:find) { mock_identifier }
|
72
|
+
allow(subject.permanent_id_manager).to receive(:record) { mock_identifier }
|
109
73
|
end
|
110
|
-
it "should
|
111
|
-
expect
|
74
|
+
it "should create a success event" do
|
75
|
+
expect { subject.save }.to change { subject.update_events.count }.by(1)
|
112
76
|
end
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
it "should
|
117
|
-
|
77
|
+
end
|
78
|
+
context "when there's an exception" do
|
79
|
+
before { allow(Ezid::Identifier).to receive(:create).and_raise(Ezid::Error) }
|
80
|
+
it "should create a failure event" do
|
81
|
+
begin
|
82
|
+
subject.save
|
83
|
+
rescue Ezid::Error
|
84
|
+
end
|
85
|
+
expect(subject.update_events.last).to be_failure
|
118
86
|
end
|
119
87
|
end
|
120
|
-
|
121
88
|
end
|
89
|
+
end
|
122
90
|
|
123
|
-
|
91
|
+
describe "workflow" do
|
124
92
|
|
125
|
-
|
93
|
+
subject { FactoryGirl.build(:item) }
|
126
94
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
end
|
95
|
+
describe "#published?" do
|
96
|
+
context "object is published" do
|
97
|
+
before { allow(subject).to receive(:workflow_state) { Ddr::Managers::WorkflowManager::PUBLISHED } }
|
98
|
+
it "should return true" do
|
99
|
+
expect(subject).to be_published
|
133
100
|
end
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
101
|
+
end
|
102
|
+
context "object is not published" do
|
103
|
+
before { allow(subject).to receive(:workflow_state) { nil } }
|
104
|
+
it "should return false" do
|
105
|
+
expect(subject).not_to be_published
|
139
106
|
end
|
140
107
|
end
|
108
|
+
end
|
141
109
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
110
|
+
describe "#publish" do
|
111
|
+
it "should publish the object" do
|
112
|
+
subject.publish
|
113
|
+
expect(subject).to be_published
|
147
114
|
end
|
115
|
+
end
|
148
116
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
117
|
+
describe "#publish!" do
|
118
|
+
it "should publish and persist the object" do
|
119
|
+
subject.publish!
|
120
|
+
expect(subject.reload).to be_published
|
154
121
|
end
|
122
|
+
end
|
155
123
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
end
|
124
|
+
describe "#unpublish" do
|
125
|
+
before { subject.publish }
|
126
|
+
it "should unpublish the object" do
|
127
|
+
subject.unpublish
|
128
|
+
expect(subject).not_to be_published
|
162
129
|
end
|
130
|
+
end
|
163
131
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
end
|
132
|
+
describe "#unpublish!" do
|
133
|
+
before { subject.publish! }
|
134
|
+
it "should unpublish and persist the object" do
|
135
|
+
subject.unpublish!
|
136
|
+
expect(subject.reload).not_to be_published
|
170
137
|
end
|
171
138
|
end
|
139
|
+
end
|
172
140
|
|
173
|
-
|
141
|
+
describe "roles" do
|
174
142
|
|
175
|
-
|
143
|
+
subject { FactoryGirl.build(:item) }
|
176
144
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
end
|
183
|
-
let(:policy_roles) do
|
184
|
-
[ FactoryGirl.build(:role, :curator, :person, :policy) ]
|
185
|
-
end
|
186
|
-
before do
|
187
|
-
other.roles.grant *resource_roles
|
188
|
-
other.roles.grant *policy_roles
|
189
|
-
subject.copy_resource_roles_from(other)
|
190
|
-
end
|
191
|
-
its(:roles) { should include(*resource_roles) }
|
192
|
-
its(:roles) { should_not include(*policy_roles) }
|
145
|
+
describe "#copy_resource_roles_from" do
|
146
|
+
let(:other) { FactoryGirl.build(:collection) }
|
147
|
+
let(:resource_roles) do
|
148
|
+
[ FactoryGirl.build(:role, :viewer, :public, :resource),
|
149
|
+
FactoryGirl.build(:role, :editor, :group, :resource) ]
|
193
150
|
end
|
194
|
-
|
195
|
-
|
196
|
-
let(:user) { FactoryGirl.build(:user) }
|
197
|
-
before { subject.grant_roles_to_creator(user) }
|
198
|
-
its(:roles) { should include(Ddr::Auth::Roles::Role.build(type: "Editor", agent: user.agent, scope: "resource")) }
|
151
|
+
let(:policy_roles) do
|
152
|
+
[ FactoryGirl.build(:role, :curator, :person, :policy) ]
|
199
153
|
end
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
subject.roles.grant role
|
205
|
-
subject.save!
|
206
|
-
subject.reload
|
207
|
-
expect(subject.roles).to contain_exactly(role)
|
208
|
-
end
|
154
|
+
before do
|
155
|
+
other.roles.grant *resource_roles
|
156
|
+
other.roles.grant *policy_roles
|
157
|
+
subject.copy_resource_roles_from(other)
|
209
158
|
end
|
159
|
+
its(:roles) { should include(*resource_roles) }
|
160
|
+
its(:roles) { should_not include(*policy_roles) }
|
161
|
+
end
|
210
162
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
it "should index the agents having roles in resource scope" do
|
225
|
-
expect(indexed[Ddr::IndexFields::RESOURCE_ROLE]).to contain_exactly(role1.agent.first)
|
226
|
-
end
|
163
|
+
describe "#grant_roles_to_creator" do
|
164
|
+
let(:user) { FactoryGirl.build(:user) }
|
165
|
+
before { subject.grant_roles_to_creator(user) }
|
166
|
+
its(:roles) { should include(Ddr::Auth::Roles::Role.build(type: "Editor", agent: user.agent, scope: "resource")) }
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "persistence" do
|
170
|
+
let(:role) { FactoryGirl.build(:role, :downloader, :public) }
|
171
|
+
it "should persist the role information" do
|
172
|
+
subject.roles.grant role
|
173
|
+
subject.save!
|
174
|
+
subject.reload
|
175
|
+
expect(subject.roles).to contain_exactly(role)
|
227
176
|
end
|
177
|
+
end
|
228
178
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
end
|
179
|
+
describe "contacts" do
|
180
|
+
before do
|
181
|
+
allow(YAML).to receive(:load_file) { { 'a' => { 'name' => 'Contact A', 'short_name' => 'A' },
|
182
|
+
'b' => { 'name' => 'Contact B', 'short_name' => 'B' } } }
|
183
|
+
Ddr::Contacts.load_contacts
|
184
|
+
end
|
185
|
+
describe "#research_help" do
|
186
|
+
before { subject.research_help_contact = 'b' }
|
187
|
+
it "should return the appropriate contact" do
|
188
|
+
expect(subject.research_help.slug).to eq('b')
|
240
189
|
end
|
241
190
|
end
|
242
|
-
|
243
191
|
end
|
192
|
+
|
244
193
|
end
|
245
194
|
end
|
246
195
|
end
|