active-fedora 11.5.6 → 12.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +4 -0
  3. data/.travis.yml +15 -0
  4. data/Gemfile +1 -3
  5. data/README.md +10 -13
  6. data/active-fedora.gemspec +7 -9
  7. data/lib/active_fedora.rb +3 -5
  8. data/lib/active_fedora/associations/collection_proxy.rb +0 -2
  9. data/lib/active_fedora/attributes/property_builder.rb +3 -1
  10. data/lib/active_fedora/caching_connection.rb +1 -1
  11. data/lib/active_fedora/errors.rb +4 -0
  12. data/lib/active_fedora/fedora.rb +5 -0
  13. data/lib/active_fedora/file.rb +3 -1
  14. data/lib/active_fedora/file/attributes.rb +5 -0
  15. data/lib/active_fedora/file_io.rb +120 -0
  16. data/lib/active_fedora/indexing.rb +6 -1
  17. data/lib/active_fedora/indexing/default_descriptors.rb +128 -0
  18. data/lib/active_fedora/indexing/descendant_fetcher.rb +22 -18
  19. data/lib/active_fedora/indexing/descriptor.rb +44 -0
  20. data/lib/active_fedora/indexing/field_mapper.rb +146 -0
  21. data/lib/active_fedora/indexing/inserter.rb +40 -0
  22. data/lib/active_fedora/indexing/suffix.rb +81 -0
  23. data/lib/active_fedora/indexing_service.rb +2 -2
  24. data/lib/active_fedora/ldp_resource.rb +1 -2
  25. data/lib/active_fedora/railtie.rb +0 -1
  26. data/lib/active_fedora/rdf/field_map_entry.rb +2 -2
  27. data/lib/active_fedora/rdf/indexing_service.rb +6 -6
  28. data/lib/active_fedora/relation.rb +0 -14
  29. data/lib/active_fedora/relation/delegation.rb +1 -2
  30. data/lib/active_fedora/relation/finder_methods.rb +19 -39
  31. data/lib/active_fedora/version.rb +1 -1
  32. data/lib/generators/active_fedora/config/fedora/templates/.fcrepo_wrapper +1 -1
  33. data/lib/generators/active_fedora/config/solr/templates/solr.yml +3 -3
  34. data/lib/generators/active_fedora/config/solr/templates/solr/config/schema.xml +34 -33
  35. data/spec/integration/base_spec.rb +39 -35
  36. data/spec/integration/indexing/descendant_fetcher_spec.rb +64 -0
  37. data/spec/integration/relation_spec.rb +1 -39
  38. data/spec/integration/scoping_spec.rb +17 -11
  39. data/spec/spec_helper.rb +1 -1
  40. data/spec/unit/active_fedora/indexing/inserter_spec.rb +30 -0
  41. data/spec/unit/attributes_spec.rb +3 -7
  42. data/spec/unit/fedora_spec.rb +12 -0
  43. data/spec/unit/file_configurator_spec.rb +0 -9
  44. data/spec/unit/file_io_spec.rb +137 -0
  45. data/spec/unit/file_spec.rb +14 -17
  46. metadata +26 -30
  47. data/.circleci/config.yml +0 -43
@@ -1,21 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveFedora::Base do
4
- describe '#reload' do
5
- before do
6
- class Foo < ActiveFedora::Base
7
- property :person, predicate: ::RDF::Vocab::DC.creator
8
- end
9
- end
10
- after do
11
- Object.send(:remove_const, :Foo)
4
+ before(:all) do
5
+ class Foo < ActiveFedora::Base
6
+ property :person, predicate: ::RDF::Vocab::DC.creator
12
7
  end
8
+ end
9
+ after(:all) { Object.send(:remove_const, :Foo) }
10
+
11
+ describe '#reload' do
13
12
  context "when persisted" do
14
13
  let(:object) { Foo.create(person: ['bob']) }
15
14
  let(:object2) { Foo.find(object.id) }
16
- before do
17
- object2.update(person: ['dave'])
18
- end
15
+ before { object2.update(person: ['dave']) }
19
16
 
20
17
  it 're-queries Fedora' do
21
18
  object.reload
@@ -24,27 +21,22 @@ describe ActiveFedora::Base do
24
21
  end
25
22
 
26
23
  context "when not persisted" do
27
- let(:object) { Foo.new }
28
24
  it 'raises an error' do
29
- expect { object.reload }.to raise_error(ActiveFedora::ObjectNotFoundError)
25
+ expect { Foo.new.reload }.to raise_error(ActiveFedora::ObjectNotFoundError)
30
26
  end
31
27
  end
32
28
  end
33
29
 
34
30
  describe "a saved object" do
35
- before do
31
+ before(:all) do
36
32
  class Book < ActiveFedora::Base
37
33
  type [::RDF::URI("http://www.example.com/Book")]
38
34
  property :title, predicate: ::RDF::Vocab::DC.title
39
35
  end
40
36
  end
41
-
42
- after do
43
- Object.send(:remove_const, :Book)
44
- end
45
- let!(:obj) { Book.create }
46
-
37
+ after(:all) { Object.send(:remove_const, :Book) }
47
38
  after { obj.destroy unless obj.destroyed? }
39
+ let!(:obj) { Book.create }
48
40
 
49
41
  describe "#errors" do
50
42
  subject { obj.errors }
@@ -121,43 +113,55 @@ describe ActiveFedora::Base do
121
113
  end
122
114
  end
123
115
 
124
- describe "#exists?" do
125
- let(:obj) { described_class.create }
116
+ shared_examples 'ActiveFedora::Base#exists?' do
117
+ let(:obj) { test_class.create }
126
118
  it "returns true for objects that exist" do
127
- expect(described_class.exists?(obj)).to be true
119
+ expect(test_class.exists?(obj)).to be true
128
120
  end
129
121
  it "returns true for ids that exist" do
130
- expect(described_class.exists?(obj.id)).to be true
122
+ expect(test_class.exists?(obj.id)).to be true
131
123
  end
132
124
  it "returns false for ids that don't exist" do
133
- expect(described_class.exists?('test_missing_object')).to be false
134
- end
135
- it "returns false for nil" do
136
- expect(described_class.exists?(nil)).to be false
137
- end
138
- it "returns false for false" do
139
- expect(described_class.exists?(false)).to be false
125
+ expect(test_class.exists?('test_missing_object')).to be false
140
126
  end
141
- it "returns false for empty" do
142
- expect(described_class.exists?('')).to be false
127
+ it "returns false for nil, false and empty" do
128
+ expect(test_class.exists?(nil)).to be false
129
+ expect(test_class.exists?(false)).to be false
130
+ expect(test_class.exists?('')).to be false
143
131
  end
144
132
  context "when passed a hash of conditions" do
145
133
  let(:conditions) { { foo: "bar" } }
146
134
  context "and at least one object matches the conditions" do
147
135
  it "returns true" do
148
136
  allow(ActiveFedora::SolrService).to receive(:query) { [instance_double(RSolr::HashWithResponse)] }
149
- expect(described_class.exists?(conditions)).to be true
137
+ expect(test_class.exists?(conditions)).to be true
150
138
  end
151
139
  end
152
140
  context "and no object matches the conditions" do
153
141
  it "returns false" do
154
142
  allow(ActiveFedora::SolrService).to receive(:query) { [] }
155
- expect(described_class.exists?(conditions)).to be false
143
+ expect(test_class.exists?(conditions)).to be false
156
144
  end
157
145
  end
158
146
  end
159
147
  end
160
148
 
149
+ context 'base class' do
150
+ let(:test_class) { described_class }
151
+ it_behaves_like 'ActiveFedora::Base#exists?'
152
+ end
153
+
154
+ context 'subclass' do
155
+ let(:test_class) { Foo }
156
+ it_behaves_like 'ActiveFedora::Base#exists?'
157
+
158
+ it 'does not mistake other fedora objects for subclass' do
159
+ obj = described_class.create
160
+ expect { test_class.exists?(obj.id) }.not_to raise_error
161
+ expect(test_class.exists?(obj.id)).to be false
162
+ end
163
+ end
164
+
161
165
  describe "overriding resource_class_factory" do
162
166
  subject(:test_base) { TestBase.new }
163
167
  before do
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActiveFedora::Indexing::DescendantFetcher do
4
+ before do
5
+ class Thing < ActiveFedora::Base
6
+ property :title, predicate: ::RDF::Vocab::DC.title
7
+ end
8
+ class Source < ActiveFedora::Base
9
+ is_a_container class_name: 'Thing'
10
+ end
11
+ end
12
+ after do
13
+ Object.send(:remove_const, :Source)
14
+ Object.send(:remove_const, :Thing)
15
+ end
16
+
17
+ let(:parent) { Source.create }
18
+ let(:child) { parent.contains.create(title: ['my title']) }
19
+ let(:other_parent) { Source.create }
20
+ let!(:source_uris) { [parent, other_parent].map(&:uri).map(&:to_s) }
21
+ let!(:thing_uris) { [child].map(&:uri).map(&:to_s) }
22
+ let(:uri) { ActiveFedora.fedora.base_uri }
23
+ let(:fetcher) { described_class.new(uri) }
24
+
25
+ describe '.descendant_and_self_uris' do
26
+ context 'with default priority models' do
27
+ it 'returns uris for all objects by walking tree' do
28
+ expect(fetcher.descendant_and_self_uris).to match_array(source_uris + thing_uris)
29
+ end
30
+ end
31
+ context 'when supplying priority models' do
32
+ let(:priority_models) { ['Thing'] }
33
+ let(:fetcher) { described_class.new(uri, priority_models: priority_models) }
34
+ it 'returns priority model uris first' do
35
+ expect(fetcher.descendant_and_self_uris.slice(0..(thing_uris.count - 1))).to match_array(thing_uris)
36
+ end
37
+ end
38
+ end
39
+ describe '.descendant_and_self_uris_partitioned' do
40
+ context 'with default priority models' do
41
+ it 'returns' do
42
+ expect(fetcher.descendant_and_self_uris_partitioned.to_a).to match_array([[:priority, []], [:other, match_array(source_uris + thing_uris)]])
43
+ end
44
+ end
45
+ context 'when supplying priority models' do
46
+ let(:priority_models) { ['Thing'] }
47
+ let(:fetcher) { described_class.new(uri, priority_models: priority_models) }
48
+ it 'returns' do
49
+ expect(fetcher.descendant_and_self_uris_partitioned.to_a).to match_array([[:priority, match_array(thing_uris)], [:other, match_array(source_uris)]])
50
+ end
51
+ end
52
+ end
53
+ describe '.descendant_and_self_uris_partitioned_by_model' do
54
+ it 'returns' do
55
+ expect(fetcher.descendant_and_self_uris_partitioned_by_model.to_a).to match_array([['Source', match_array(source_uris)], ['Thing', match_array(thing_uris)]])
56
+ end
57
+ context 'excluding self' do
58
+ let(:fetcher) { described_class.new(parent.uri, exclude_self: true) }
59
+ it 'returns' do
60
+ expect(fetcher.descendant_and_self_uris_partitioned_by_model.to_a).to match_array([['Thing', [child.uri.to_s]]])
61
+ end
62
+ end
63
+ end
64
+ end
@@ -22,10 +22,6 @@ describe ActiveFedora::Base do
22
22
  end
23
23
 
24
24
  it { is_expected.to respond_to(:each_with_index) }
25
- it { expect(libraries.any?).to eq false }
26
- it { is_expected.to be_blank }
27
- it { is_expected.to be_empty }
28
- it { is_expected.not_to be_present }
29
25
 
30
26
  context "when some records exist" do
31
27
  before do
@@ -43,41 +39,7 @@ describe ActiveFedora::Base do
43
39
 
44
40
  it "does not reload" do
45
41
  expect_any_instance_of(ActiveFedora::Relation).to_not receive :find_each
46
- libraries.each(&:id)
47
- end
48
- end
49
-
50
- it { expect(libraries.any?).to eq true }
51
- it { is_expected.not_to be_blank }
52
- it { is_expected.not_to be_empty }
53
- it { is_expected.to be_present }
54
-
55
- describe '#each' do
56
- before { Book.create }
57
-
58
- it 'returns an enumerator' do
59
- expect(libraries.each).to be_a Enumerator
60
- end
61
-
62
- it 'yields the items' do
63
- expect { |b| libraries.each(&b) }
64
- .to yield_successive_args(*Library.all.to_a)
65
- end
66
-
67
- it 'when called from Base yields all items' do
68
- expect { |b| described_class.all.each(&b) }
69
- .to yield_successive_args(*(Library.all.to_a + Book.all.to_a))
70
- end
71
-
72
- context 'when cached' do
73
- it 'returns an enumerator' do
74
- expect(libraries.each).to be_a Enumerator
75
- end
76
-
77
- it 'yields the items' do
78
- expect { |b| libraries.each(&b) }
79
- .to yield_successive_args(*Library.all.to_a)
80
- end
42
+ libraries[0]
81
43
  end
82
44
  end
83
45
 
@@ -1,17 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveFedora::Scoping::Named do
4
- before do
5
- class TestClass < ActiveFedora::Base
6
- end
4
+ before(:all) do
5
+ class TestClass < ActiveFedora::Base; end
6
+ class OtherClass < ActiveFedora::Base; end
7
7
  end
8
- let!(:test_instance) { TestClass.create! }
9
-
10
- after do
11
- test_instance.delete
8
+ after(:all) do
12
9
  Object.send(:remove_const, :TestClass)
10
+ Object.send(:remove_const, :OtherClass)
13
11
  end
14
12
 
13
+ let!(:test_instance) { TestClass.create! }
14
+ after { test_instance.delete }
15
+
15
16
  describe "#all" do
16
17
  it "returns an array of instances of the calling Class" do
17
18
  result = TestClass.all.to_a
@@ -25,18 +26,23 @@ describe ActiveFedora::Scoping::Named do
25
26
  end
26
27
 
27
28
  describe '#find' do
28
- describe "#find with a valid id without cast" do
29
+ describe "a valid id without cast" do
29
30
  subject { ActiveFedora::Base.find(test_instance.id) }
30
31
  it { is_expected.to be_instance_of TestClass }
31
32
  end
32
- describe "#find with a valid id with cast of false" do
33
+ describe "a valid id with cast of false" do
33
34
  subject { ActiveFedora::Base.find(test_instance.id, cast: false) }
34
35
  it { is_expected.to be_instance_of ActiveFedora::Base }
35
36
  end
36
-
37
- describe "#find with a valid id without cast on a model extending Base" do
37
+ describe "a valid id without cast on a model extending Base" do
38
38
  subject { TestClass.find(test_instance.id) }
39
39
  it { is_expected.to be_instance_of TestClass }
40
40
  end
41
+ it "a valid id on an incompatible class raises ModelMismatch" do
42
+ expect { OtherClass.find(test_instance.id) }.to raise_error(ActiveFedora::ModelMismatch)
43
+ end
44
+ it "invalid id raises ObjectNotFoundError" do
45
+ expect { TestClass.find('some_unused_identifier') }.to raise_error(ActiveFedora::ObjectNotFoundError)
46
+ end
41
47
  end
42
48
  end
@@ -13,7 +13,7 @@ require 'rspec'
13
13
  require 'rspec/its'
14
14
  require 'equivalent-xml/rspec_matchers'
15
15
  require 'logger'
16
- require 'pry' unless ENV['CI']
16
+ require 'pry' unless ENV['TRAVIS']
17
17
 
18
18
  ActiveFedora::Base.logger = Logger.new(STDERR)
19
19
  ActiveFedora::Base.logger.level = Logger::WARN
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActiveFedora::Indexing::Inserter do
4
+ let(:solr_doc) { {} }
5
+
6
+ it "handles many field types" do
7
+ described_class.create_and_insert_terms('my_name', 'value', [:displayable, :searchable, :sortable], solr_doc)
8
+ expect(solr_doc).to eq('my_name_ssm' => ['value'], 'my_name_si' => 'value', 'my_name_teim' => ['value'])
9
+ end
10
+
11
+ it "handles dates that are searchable" do
12
+ described_class.create_and_insert_terms('my_name', Date.parse('2013-01-10'), [:stored_searchable], solr_doc)
13
+ expect(solr_doc).to eq('my_name_dtsim' => ['2013-01-10T00:00:00Z'])
14
+ end
15
+
16
+ it "handles dates that are stored_sortable" do
17
+ described_class.create_and_insert_terms('my_name', Date.parse('2013-01-10'), [:stored_sortable], solr_doc)
18
+ expect(solr_doc).to eq('my_name_dtsi' => '2013-01-10T00:00:00Z')
19
+ end
20
+
21
+ it "handles dates that are displayable" do
22
+ described_class.create_and_insert_terms('my_name', Date.parse('2013-01-10'), [:displayable], solr_doc)
23
+ expect(solr_doc).to eq('my_name_ssm' => ['2013-01-10'])
24
+ end
25
+
26
+ it "handles dates that are sortable" do
27
+ described_class.create_and_insert_terms('my_name', Date.parse('2013-01-10'), [:sortable], solr_doc)
28
+ expect(solr_doc).to eq('my_name_dti' => '2013-01-10T00:00:00Z')
29
+ end
30
+ end
@@ -131,17 +131,13 @@ describe ActiveFedora::Base do
131
131
  expect { history.title = "Quack" }.to raise_error ArgumentError
132
132
  expect { history.title = ["Quack"] }.not_to raise_error
133
133
  expect { history.title = nil }.not_to raise_error
134
- end
135
-
136
- it "allow setting to multiple properties with unintended legacy behavior" do
137
- expect { history.title = '' }.not_to raise_error
138
- expect { history.title = ActiveTriples::Resource.new }.not_to raise_error
134
+ expect { history.title = ActiveTriples::Resource.new }.to raise_error
139
135
  end
140
136
 
141
137
  it "does not allow an enumerable to a unique attribute writer" do
142
138
  expect { history.abstract = "Low" }.not_to raise_error
143
- expect { history.abstract = ["Low"]
144
- }.to raise_error ArgumentError, "You attempted to set the property `abstract' of test:123 to an enumerable value. However, this property is declared as singular."
139
+ expect { history.abstract = ["Low"] }
140
+ .to raise_error ArgumentError, "You attempted to set the property `abstract' of test:123 to an enumerable value. However, this property is declared as singular."
145
141
  expect { history.abstract = nil }.not_to raise_error
146
142
  expect { history.abstract = ActiveTriples::Resource.new }.not_to raise_error
147
143
  end
@@ -15,5 +15,17 @@ describe ActiveFedora::Fedora do
15
15
  fedora.authorized_connection
16
16
  }
17
17
  end
18
+ describe "with request options" do
19
+ let(:config) {
20
+ { url: "https://example.com",
21
+ user: "fedoraAdmin",
22
+ password: "fedoraAdmin",
23
+ request: { timeout: 600, open_timeout: 60 } }
24
+ }
25
+ specify {
26
+ expect(Faraday).to receive(:new).with("https://example.com", request: { timeout: 600, open_timeout: 60 }).and_call_original
27
+ fedora.authorized_connection
28
+ }
29
+ end
18
30
  end
19
31
  end
@@ -141,7 +141,6 @@ describe ActiveFedora::FileConfigurator do
141
141
  configurator.reset!
142
142
  end
143
143
  it "loads the file specified in fedora_config_path" do
144
- allow(configurator).to receive(:load_solrizer_config)
145
144
  expect(configurator).to receive(:config_path).with(:fedora).and_return("/path/to/fedora.yml")
146
145
  expect(configurator).to receive(:load_solr_config)
147
146
  expect(IO).to receive(:read).with("/path/to/fedora.yml").and_return("development:\n url: http://devfedora:8983\ntest:\n url: http://myfedora:8080")
@@ -150,7 +149,6 @@ describe ActiveFedora::FileConfigurator do
150
149
  end
151
150
 
152
151
  it "allows sharding" do
153
- allow(configurator).to receive(:load_solrizer_config)
154
152
  expect(configurator).to receive(:config_path).with(:fedora).and_return("/path/to/fedora.yml")
155
153
  expect(configurator).to receive(:load_solr_config)
156
154
  expect(IO).to receive(:read).with("/path/to/fedora.yml").and_return("development:\n url: http://devfedora:8983\ntest:\n- url: http://myfedora:8080\n- url: http://myfedora:8081")
@@ -159,7 +157,6 @@ describe ActiveFedora::FileConfigurator do
159
157
  end
160
158
 
161
159
  it "parses the file using ERb" do
162
- allow(configurator).to receive(:load_solrizer_config)
163
160
  expect(configurator).to receive(:config_path).with(:fedora).and_return("/path/to/fedora.yml")
164
161
  expect(configurator).to receive(:load_solr_config)
165
162
  expect(IO).to receive(:read).with("/path/to/fedora.yml").and_return("development:\n url: http://devfedora:<%= 8983 %>\ntest:\n url: http://myfedora:<%= 8081 %>")
@@ -173,7 +170,6 @@ describe ActiveFedora::FileConfigurator do
173
170
  configurator.reset!
174
171
  end
175
172
  it "loads the file specified in solr_config_path" do
176
- allow(configurator).to receive(:load_solrizer_config)
177
173
  expect(configurator).to receive(:config_path).with(:solr).and_return("/path/to/solr.yml")
178
174
  expect(configurator).to receive(:load_fedora_config)
179
175
  expect(IO).to receive(:read).with("/path/to/solr.yml").and_return("development:\n default:\n url: http://devsolr:8983\ntest:\n default:\n url: http://mysolr:8080")
@@ -182,7 +178,6 @@ describe ActiveFedora::FileConfigurator do
182
178
  end
183
179
 
184
180
  it "parses the file using ERb" do
185
- allow(configurator).to receive(:load_solrizer_config)
186
181
  expect(configurator).to receive(:config_path).with(:solr).and_return("/path/to/solr.yml")
187
182
  expect(configurator).to receive(:load_fedora_config)
188
183
  expect(IO).to receive(:read).with("/path/to/solr.yml").and_return("development:\n default:\n url: http://devsolr:<%= 8983 %>\ntest:\n default:\n url: http://mysolr:<%= 8081 %>")
@@ -191,7 +186,6 @@ describe ActiveFedora::FileConfigurator do
191
186
  end
192
187
 
193
188
  it "includes update_path and select_path in solr_config" do
194
- allow(configurator).to receive(:load_solrizer_config)
195
189
  expect(configurator).to receive(:config_path).with(:solr).and_return("/path/to/solr.yml")
196
190
  expect(configurator).to receive(:load_fedora_config)
197
191
  expect(IO).to receive(:read).with("/path/to/solr.yml").and_return("test:\n url: http://mysolr:8080\n update_path: update_test\n select_path: select_test\n")
@@ -255,7 +249,6 @@ describe ActiveFedora::FileConfigurator do
255
249
  end
256
250
 
257
251
  it "loads a config from the current working directory as a second choice" do
258
- allow(configurator).to receive(:load_solrizer_config)
259
252
  allow(Dir).to receive(:getwd).and_return(@fake_rails_root)
260
253
  configurator.init
261
254
  expect(configurator.config_path(:fedora)).to eql("#{@fake_rails_root}/config/fedora.yml")
@@ -264,7 +257,6 @@ describe ActiveFedora::FileConfigurator do
264
257
 
265
258
  it "loads the config that ships with this gem as a last choice" do
266
259
  allow(Dir).to receive(:getwd).and_return("/fake/path")
267
- allow(configurator).to receive(:load_solrizer_config)
268
260
  expect(ActiveFedora::Base.logger).to receive(:warn).with("Using the default fedora.yml that comes with active-fedora. If you want to override this, pass the path to fedora.yml to ActiveFedora - ie. ActiveFedora.init(:fedora_config_path => '/path/to/fedora.yml') - or set Rails.root and put fedora.yml into \#{Rails.root}/config.").exactly(3).times
269
261
  configurator.init
270
262
  expected_config = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "config"))
@@ -288,7 +280,6 @@ describe ActiveFedora::FileConfigurator do
288
280
  end
289
281
 
290
282
  it "loads a config from Rails.root as a first choice" do
291
- allow(configurator).to receive(:load_solrizer_config)
292
283
  configurator.init
293
284
  expect(configurator.config_path(:fedora)).to eql("#{Rails.root}/config/fedora.yml")
294
285
  expect(configurator.solr_config_path).to eql("#{Rails.root}/config/solr.yml")