oai 0.0.1 → 1.3.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 +7 -0
- data/README.md +128 -0
- data/Rakefile +64 -0
- data/bin/oai +66 -0
- data/examples/models/file_model.rb +63 -0
- data/examples/providers/dublin_core.rb +474 -0
- data/lib/oai/{get_record.rb → client/get_record.rb} +5 -1
- data/lib/oai/client/header.rb +18 -0
- data/lib/oai/{identify.rb → client/identify.rb} +2 -0
- data/lib/oai/{list_identifiers.rb → client/list_identifiers.rb} +1 -0
- data/lib/oai/{list_records.rb → client/list_records.rb} +6 -5
- data/lib/oai/{list_sets.rb → client/list_sets.rb} +7 -6
- data/lib/oai/client/record.rb +27 -0
- data/lib/oai/client/response.rb +53 -0
- data/lib/oai/client/resumable.rb +42 -0
- data/lib/oai/client.rb +313 -108
- data/lib/oai/constants.rb +34 -0
- data/lib/oai/exception.rb +80 -1
- data/lib/oai/harvester/config.rb +41 -0
- data/lib/oai/harvester/harvest.rb +162 -0
- data/lib/oai/harvester/logging.rb +68 -0
- data/lib/oai/harvester/mailer.rb +17 -0
- data/lib/oai/harvester/shell.rb +337 -0
- data/lib/oai/harvester.rb +43 -0
- data/lib/oai/provider/metadata_format/oai_dc.rb +28 -0
- data/lib/oai/provider/metadata_format.rb +119 -0
- data/lib/oai/provider/model/activerecord_caching_wrapper.rb +129 -0
- data/lib/oai/provider/model/activerecord_wrapper.rb +217 -0
- data/lib/oai/provider/model.rb +80 -0
- data/lib/oai/provider/partial_result.rb +18 -0
- data/lib/oai/provider/response/error.rb +16 -0
- data/lib/oai/provider/response/get_record.rb +27 -0
- data/lib/oai/provider/response/identify.rb +37 -0
- data/lib/oai/provider/response/list_identifiers.rb +30 -0
- data/lib/oai/provider/response/list_metadata_formats.rb +39 -0
- data/lib/oai/provider/response/list_records.rb +47 -0
- data/lib/oai/provider/response/list_sets.rb +23 -0
- data/lib/oai/provider/response/record_response.rb +103 -0
- data/lib/oai/provider/response.rb +133 -0
- data/lib/oai/provider/resumption_token.rb +155 -0
- data/lib/oai/provider.rb +487 -0
- data/lib/oai/set.rb +14 -5
- data/lib/oai/xpath.rb +59 -5
- data/lib/oai.rb +7 -13
- data/lib/test.rb +25 -0
- data/test/activerecord_provider/config/connection.rb +30 -0
- data/test/activerecord_provider/database/0001_oaipmh_tables.rb +70 -0
- data/test/activerecord_provider/fixtures/dc.yml +1501 -0
- data/test/activerecord_provider/helpers/providers.rb +68 -0
- data/test/activerecord_provider/helpers/set_provider.rb +24 -0
- data/test/activerecord_provider/helpers/transactional_test_case.rb +35 -0
- data/test/activerecord_provider/models/dc_field.rb +15 -0
- data/test/activerecord_provider/models/dc_lang.rb +3 -0
- data/test/activerecord_provider/models/dc_set.rb +7 -0
- data/test/activerecord_provider/models/exclusive_set_dc_field.rb +17 -0
- data/test/activerecord_provider/models/oai_token.rb +3 -0
- data/test/activerecord_provider/tc_activerecord_wrapper.rb +63 -0
- data/test/activerecord_provider/tc_ar_provider.rb +199 -0
- data/test/activerecord_provider/tc_ar_sets_provider.rb +159 -0
- data/test/activerecord_provider/tc_caching_paging_provider.rb +50 -0
- data/test/activerecord_provider/tc_simple_paging_provider.rb +71 -0
- data/test/activerecord_provider/test_helper_ar_provider.rb +7 -0
- data/test/client/helpers/provider.rb +65 -0
- data/test/client/helpers/test_wrapper.rb +6 -0
- data/test/client/tc_exception.rb +36 -0
- data/test/client/tc_get_record.rb +39 -0
- data/test/client/tc_http_client.rb +129 -0
- data/test/client/tc_identify.rb +13 -0
- data/test/client/tc_libxml.rb +61 -0
- data/test/{tc_list_identifiers.rb → client/tc_list_identifiers.rb} +28 -9
- data/test/{tc_list_metadata_formats.rb → client/tc_list_metadata_formats.rb} +4 -1
- data/test/client/tc_list_records.rb +26 -0
- data/test/client/tc_list_sets.rb +34 -0
- data/test/client/tc_low_resolution_dates.rb +14 -0
- data/test/client/tc_utf8_escaping.rb +19 -0
- data/test/client/tc_xpath.rb +26 -0
- data/test/client/test_helper_client.rb +5 -0
- data/test/harvester/tc_harvest.rb +42 -0
- data/test/harvester/test_helper_harvester.rb +6 -0
- data/test/provider/models.rb +246 -0
- data/test/provider/tc_exceptions.rb +81 -0
- data/test/provider/tc_functional_tokens.rb +53 -0
- data/test/provider/tc_instance_provider.rb +41 -0
- data/test/provider/tc_provider.rb +136 -0
- data/test/provider/tc_resumption_tokens.rb +52 -0
- data/test/provider/tc_simple_provider.rb +138 -0
- data/test/provider/test_helper_provider.rb +62 -0
- data/test/test.xml +22 -0
- metadata +238 -56
- data/lib/oai/header.rb +0 -12
- data/lib/oai/record.rb +0 -11
- data/lib/oai/response.rb +0 -20
- data/test/tc_get_record.rb +0 -27
- data/test/tc_identify.rb +0 -8
- data/test/tc_list_records.rb +0 -9
- data/test/tc_list_sets.rb +0 -17
- data/test.rb +0 -12
- /data/lib/oai/{list_metadata_formats.rb → client/list_metadata_formats.rb} +0 -0
- /data/lib/oai/{metadata_format.rb → client/metadata_format.rb} +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
require 'oai'
|
|
3
|
+
|
|
4
|
+
Dir.glob(File.dirname(__FILE__) + "/../models/*.rb").each do |lib|
|
|
5
|
+
require lib
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class ARProvider < OAI::Provider::Base
|
|
9
|
+
repository_name 'ActiveRecord Based Provider'
|
|
10
|
+
repository_url 'http://localhost'
|
|
11
|
+
record_prefix 'oai:test'
|
|
12
|
+
source_model ActiveRecordWrapper.new(DCField)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class ARProviderCustomIdentifierField < OAI::Provider::Base
|
|
16
|
+
repository_name 'ActiveRecord Based Provider'
|
|
17
|
+
repository_url 'http://localhost'
|
|
18
|
+
record_prefix 'oai:test'
|
|
19
|
+
source_model ActiveRecordWrapper.new(DCField, identifier_field: "source")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class ARProviderWithScope < OAI::Provider::Base
|
|
23
|
+
DATE_LESS_THAN_RESTRICTION = Time.parse("2007-03-12 19:30:22 UTC")
|
|
24
|
+
|
|
25
|
+
repository_name 'ActiveRecord Based Provider'
|
|
26
|
+
repository_url 'http://localhost'
|
|
27
|
+
record_prefix 'oai:test'
|
|
28
|
+
source_model ActiveRecordWrapper.new(DCField.where("date < ?", DATE_LESS_THAN_RESTRICTION).includes(:sets))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class SimpleResumptionProvider < OAI::Provider::Base
|
|
32
|
+
repository_name 'ActiveRecord Resumption Provider'
|
|
33
|
+
repository_url 'http://localhost'
|
|
34
|
+
record_prefix 'oai:test'
|
|
35
|
+
source_model ActiveRecordWrapper.new(DCField, :limit => 25)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class SimpleResumptionProviderWithNonIntegerID < OAI::Provider::Base
|
|
39
|
+
repository_name 'ActiveRecord Resumption Provider With Non-Integer ID'
|
|
40
|
+
repository_url 'http://localhost'
|
|
41
|
+
record_prefix 'oai:test'
|
|
42
|
+
source_model ActiveRecordWrapper.new(DCField, :limit => 25, identifier_field: "source")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class CachingResumptionProvider < OAI::Provider::Base
|
|
46
|
+
repository_name 'ActiveRecord Caching Resumption Provider'
|
|
47
|
+
repository_url 'http://localhost'
|
|
48
|
+
record_prefix 'oai:test'
|
|
49
|
+
source_model ActiveRecordCachingWrapper.new(DCField, :limit => 25)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ARLoader
|
|
54
|
+
def self.load
|
|
55
|
+
fixtures = YAML.load_file(
|
|
56
|
+
File.join(File.dirname(__FILE__), '..', 'fixtures', 'dc.yml')
|
|
57
|
+
)
|
|
58
|
+
fixtures.keys.sort.each do |key|
|
|
59
|
+
lang = DCLang.create(name: fixtures[key].delete('language'))
|
|
60
|
+
DCField.create(fixtures[key].merge(dc_lang: lang))
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.unload
|
|
65
|
+
DCField.delete_all
|
|
66
|
+
DCLang.delete_all
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Extend ActiveRecordModel to support sets
|
|
2
|
+
class SetModel < OAI::Provider::ActiveRecordWrapper
|
|
3
|
+
|
|
4
|
+
# Return all available sets
|
|
5
|
+
def sets
|
|
6
|
+
DCSet.all
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class ARSetProvider < OAI::Provider::Base
|
|
12
|
+
repository_name 'ActiveRecord Set Based Provider'
|
|
13
|
+
repository_url 'http://localhost'
|
|
14
|
+
record_prefix = 'oai:test'
|
|
15
|
+
source_model SetModel.new(DCField, :timestamp_field => 'date')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class ARExclusiveSetProvider < OAI::Provider::Base
|
|
19
|
+
repository_name 'ActiveRecord Set Based Provider'
|
|
20
|
+
repository_url 'http://localhost'
|
|
21
|
+
record_prefix = 'oai:test'
|
|
22
|
+
source_model OAI::Provider::ActiveRecordWrapper.new(
|
|
23
|
+
ExclusiveSetDCField, :timestamp_field => 'date')
|
|
24
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
class TransactionalTestCase < Test::Unit::TestCase
|
|
2
|
+
|
|
3
|
+
def run(result, &block)
|
|
4
|
+
# Handle the default "you have no tests" test if it turns up
|
|
5
|
+
return if @method_name.to_s == "default_test"
|
|
6
|
+
ActiveRecord::Base.transaction do
|
|
7
|
+
load_fixtures
|
|
8
|
+
result = super(result, &block)
|
|
9
|
+
raise ActiveRecord::Rollback
|
|
10
|
+
end
|
|
11
|
+
result
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def load_fixtures
|
|
17
|
+
fixtures = YAML.load_file(
|
|
18
|
+
File.join(File.dirname(__FILE__), '..', 'fixtures', 'dc.yml')
|
|
19
|
+
)
|
|
20
|
+
disable_logging do
|
|
21
|
+
fixtures.keys.sort.each do |key|
|
|
22
|
+
lang = DCLang.create(name: fixtures[key].delete('language'))
|
|
23
|
+
DCField.create(fixtures[key].merge(dc_lang: lang))
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def disable_logging
|
|
29
|
+
logger = ActiveRecord::Base.logger
|
|
30
|
+
ActiveRecord::Base.logger = nil
|
|
31
|
+
yield
|
|
32
|
+
ActiveRecord::Base.logger = logger
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class DCField < ActiveRecord::Base
|
|
2
|
+
self.inheritance_column = 'DONOTINHERIT'
|
|
3
|
+
has_and_belongs_to_many :sets,
|
|
4
|
+
:join_table => "dc_fields_dc_sets",
|
|
5
|
+
:foreign_key => "dc_field_id",
|
|
6
|
+
:class_name => "DCSet"
|
|
7
|
+
|
|
8
|
+
belongs_to :dc_lang, class_name: "DCLang", optional: true
|
|
9
|
+
|
|
10
|
+
default_scope -> { left_outer_joins(:dc_lang) }
|
|
11
|
+
|
|
12
|
+
def language
|
|
13
|
+
dc_lang&.name
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class ExclusiveSetDCField < ActiveRecord::Base
|
|
2
|
+
self.inheritance_column = 'DONOTINHERIT'
|
|
3
|
+
|
|
4
|
+
def self.sets
|
|
5
|
+
klass = Struct.new(:name, :spec)
|
|
6
|
+
self.distinct.pluck(:set).compact.map do |spec|
|
|
7
|
+
klass.new("Set #{spec}", spec)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
belongs_to :dc_lang, class_name: "DCLang", optional: true
|
|
12
|
+
|
|
13
|
+
def language
|
|
14
|
+
dc_lang&.name
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'test_helper_ar_provider'
|
|
2
|
+
|
|
3
|
+
class ActiveRecordWrapperTest < TransactionalTestCase
|
|
4
|
+
def test_sql_conditions_from_date
|
|
5
|
+
input = "2005-12-25"
|
|
6
|
+
expected = input.dup
|
|
7
|
+
sql_template, sql_opts = sql_conditions(from: input)
|
|
8
|
+
assert_equal "dc_fields.updated_at >= :from", sql_template
|
|
9
|
+
assert_equal expected, sql_opts[:from]
|
|
10
|
+
sql_template, sql_opts = sql_conditions(from: Date.strptime(input, "%Y-%m-%d"))
|
|
11
|
+
assert_equal "dc_fields.updated_at >= :from", sql_template
|
|
12
|
+
assert_equal expected, sql_opts[:from]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_sql_conditions_from_time
|
|
16
|
+
input = "2005-12-25T00:00:00Z"
|
|
17
|
+
expected = "2005-12-25 00:00:00"
|
|
18
|
+
sql_template, sql_opts = sql_conditions(from: input)
|
|
19
|
+
assert_equal "dc_fields.updated_at >= :from", sql_template
|
|
20
|
+
assert_equal expected, sql_opts[:from]
|
|
21
|
+
sql_template, sql_opts = sql_conditions(from: Time.strptime(input, "%Y-%m-%dT%H:%M:%S%Z"))
|
|
22
|
+
assert_equal "dc_fields.updated_at >= :from", sql_template
|
|
23
|
+
assert_equal expected, sql_opts[:from]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_sql_conditions_until_date
|
|
27
|
+
input = "2005-12-25"
|
|
28
|
+
expected = "2005-12-26"
|
|
29
|
+
sql_template, sql_opts = sql_conditions(until: input)
|
|
30
|
+
assert_equal "dc_fields.updated_at < :until", sql_template
|
|
31
|
+
assert_equal expected, sql_opts[:until]
|
|
32
|
+
sql_template, sql_opts = sql_conditions(until: Date.strptime(input, "%Y-%m-%d"))
|
|
33
|
+
assert_equal "dc_fields.updated_at < :until", sql_template
|
|
34
|
+
assert_equal expected, sql_opts[:until]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_sql_conditions_until_time
|
|
38
|
+
input = "2005-12-25T00:00:00Z"
|
|
39
|
+
expected = "2005-12-25 00:00:01"
|
|
40
|
+
sql_template, sql_opts = sql_conditions(until: input)
|
|
41
|
+
assert_equal "dc_fields.updated_at < :until", sql_template
|
|
42
|
+
assert_equal expected, sql_opts[:until]
|
|
43
|
+
sql_template, sql_opts = sql_conditions(until: Time.strptime(input, "%Y-%m-%dT%H:%M:%S%Z"))
|
|
44
|
+
assert_equal "dc_fields.updated_at < :until", sql_template
|
|
45
|
+
assert_equal expected, sql_opts[:until]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_sql_conditions_both
|
|
49
|
+
input = "2005-12-25"
|
|
50
|
+
sql_template, sql_opts = sql_conditions(from: input, until: input)
|
|
51
|
+
assert_equal "dc_fields.updated_at >= :from AND dc_fields.updated_at < :until", sql_template
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def setup
|
|
55
|
+
@wrapper = OAI::Provider::ActiveRecordWrapper.new(DCField)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def sql_conditions(opts)
|
|
59
|
+
@wrapper.send :sql_conditions, opts
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
require 'test_helper_ar_provider'
|
|
2
|
+
|
|
3
|
+
class ActiveRecordProviderTest < TransactionalTestCase
|
|
4
|
+
|
|
5
|
+
def test_identify
|
|
6
|
+
assert @provider.identify =~ /ActiveRecord Based Provider/
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_metadata_formats
|
|
10
|
+
assert_nothing_raised { REXML::Document.new(@provider.list_metadata_formats) }
|
|
11
|
+
doc = REXML::Document.new(@provider.list_metadata_formats)
|
|
12
|
+
assert doc.elements['/OAI-PMH/ListMetadataFormats/metadataFormat/metadataPrefix'].text == 'oai_dc'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_metadata_formats_for_record
|
|
16
|
+
record_id = DCField.first.id
|
|
17
|
+
assert_nothing_raised { REXML::Document.new(@provider.list_metadata_formats(:identifier => "oai:test:#{record_id}")) }
|
|
18
|
+
doc = REXML::Document.new(@provider.list_metadata_formats)
|
|
19
|
+
assert doc.elements['/OAI-PMH/ListMetadataFormats/metadataFormat/metadataPrefix'].text == 'oai_dc'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_list_records
|
|
23
|
+
assert_nothing_raised do
|
|
24
|
+
REXML::Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
25
|
+
end
|
|
26
|
+
doc = REXML::Document.new(@provider.list_records(
|
|
27
|
+
:metadata_prefix => 'oai_dc'))
|
|
28
|
+
assert_equal 100, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_list_records_scope
|
|
32
|
+
@provider = ARProviderWithScope.new
|
|
33
|
+
|
|
34
|
+
doc = nil
|
|
35
|
+
assert_nothing_raised do
|
|
36
|
+
doc = REXML::Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
expected_count = DCField.where("date < ?", ARProviderWithScope::DATE_LESS_THAN_RESTRICTION).count
|
|
40
|
+
assert_equal expected_count, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_invalid_set_raises_no_match
|
|
44
|
+
assert_raises(OAI::NoMatchException) do
|
|
45
|
+
@provider.list_records(:metadata_prefix => 'oai_dc', :set => "invalid_does_not_exist")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_get_record_alternate_identifier_column
|
|
50
|
+
@provider = ARProviderCustomIdentifierField.new
|
|
51
|
+
|
|
52
|
+
record_id = DCField.first.send(@provider.class.model.identifier_field)
|
|
53
|
+
|
|
54
|
+
doc = REXML::Document.new(@provider.get_record(
|
|
55
|
+
:identifier => "oai:test:#{record_id}", :metadata_prefix => 'oai_dc'))
|
|
56
|
+
|
|
57
|
+
assert_equal "oai:test:#{record_id}", doc.elements['OAI-PMH/GetRecord/record/header/identifier'].text
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_list_identifiers
|
|
61
|
+
assert_nothing_raised { REXML::Document.new(@provider.list_identifiers) }
|
|
62
|
+
doc = REXML::Document.new(@provider.list_identifiers)
|
|
63
|
+
assert_equal 100, doc.elements['OAI-PMH/ListIdentifiers'].to_a.size
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_get_record
|
|
67
|
+
record_id = DCField.first.id
|
|
68
|
+
assert_nothing_raised do
|
|
69
|
+
REXML::Document.new(@provider.get_record(
|
|
70
|
+
:identifier => "oai:test:#{record_id}", :metadata_prefix => 'oai_dc'))
|
|
71
|
+
end
|
|
72
|
+
doc = REXML::Document.new(@provider.get_record(
|
|
73
|
+
:identifier => "#{record_id}", :metadata_prefix => 'oai_dc'))
|
|
74
|
+
assert_equal "oai:test:#{record_id}", doc.elements['OAI-PMH/GetRecord/record/header/identifier'].text
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_deleted
|
|
78
|
+
record = DCField.first
|
|
79
|
+
record.deleted = true;
|
|
80
|
+
record.save
|
|
81
|
+
doc = REXML::Document.new(@provider.get_record(
|
|
82
|
+
:identifier => "oai:test:#{record.id}", :metadata_prefix => 'oai_dc'))
|
|
83
|
+
assert_equal "oai:test:#{record.id}", doc.elements['OAI-PMH/GetRecord/record/header/identifier'].text
|
|
84
|
+
assert_equal 'deleted', doc.elements['OAI-PMH/GetRecord/record/header'].attributes["status"]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_from
|
|
88
|
+
first_id = DCField.order("id asc").first.id
|
|
89
|
+
DCField.where("dc_fields.id < #{first_id + 90}").update_all(updated_at: Time.parse("January 1 2005"))
|
|
90
|
+
|
|
91
|
+
DCField.where("dc_fields.id < #{first_id + 10}").update_all(updated_at: Time.parse("June 1 2005"))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
from_param = Time.parse("January 1 2006").getutc.iso8601
|
|
95
|
+
|
|
96
|
+
doc = REXML::Document.new(
|
|
97
|
+
@provider.list_records(
|
|
98
|
+
:metadata_prefix => 'oai_dc', :from => from_param)
|
|
99
|
+
)
|
|
100
|
+
assert_equal DCField.where(["dc_fields.updated_at >= ?", from_param]).size,
|
|
101
|
+
doc.elements['OAI-PMH/ListRecords'].size
|
|
102
|
+
|
|
103
|
+
doc = REXML::Document.new(
|
|
104
|
+
@provider.list_records(
|
|
105
|
+
:metadata_prefix => 'oai_dc', :from => Time.parse("May 30 2005").getutc.iso8601)
|
|
106
|
+
)
|
|
107
|
+
assert_equal 20, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_until
|
|
111
|
+
first_id = DCField.order(id: :asc).first.id
|
|
112
|
+
DCField.where("dc_fields.id < ?", first_id + 10).update_all(updated_at: Time.parse("June 1 2005"))
|
|
113
|
+
|
|
114
|
+
doc = REXML::Document.new(
|
|
115
|
+
@provider.list_records(
|
|
116
|
+
:metadata_prefix => 'oai_dc', :until => Time.parse("June 1 2005"))
|
|
117
|
+
)
|
|
118
|
+
assert_equal 10, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def test_from_and_until
|
|
122
|
+
first_id = DCField.order(id: :asc).first.id
|
|
123
|
+
DCField.update_all(updated_at: Time.parse("June 1 2005"))
|
|
124
|
+
DCField.where("dc_fields.id < ?", first_id + 50).update_all(updated_at: Time.parse("June 15 2005"))
|
|
125
|
+
DCField.where("dc_fields.id < ?", first_id + 10).update_all(updated_at: Time.parse("June 30 2005"))
|
|
126
|
+
|
|
127
|
+
doc = REXML::Document.new(
|
|
128
|
+
@provider.list_records(
|
|
129
|
+
:metadata_prefix => 'oai_dc',
|
|
130
|
+
:from => Time.parse("June 3 2005").getutc.iso8601,
|
|
131
|
+
:until => Time.parse("June 16 2005").getutc.iso8601)
|
|
132
|
+
)
|
|
133
|
+
assert_equal 40, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def test_bad_until_raises_exception
|
|
137
|
+
DCField.order(id: :asc).limit(10).update_all(updated_at: 1.year.ago)
|
|
138
|
+
DCField.order(id: :desc).limit(10).update_all(updated_at: 1.year.from_now)
|
|
139
|
+
badTimes = [
|
|
140
|
+
'junk',
|
|
141
|
+
'February 92nd, 2015']
|
|
142
|
+
badTimes.each do |time|
|
|
143
|
+
assert_raise(OAI::ArgumentException) do
|
|
144
|
+
@provider.list_records(:metadata_prefix => 'oai_dc', :until => time)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def test_bad_from_raises_exception
|
|
150
|
+
DCField.order(id: :asc).limit(10).update_all(updated_at: 1.year.ago)
|
|
151
|
+
DCField.order(id: :desc).limit(10).update_all(updated_at: 1.year.from_now)
|
|
152
|
+
|
|
153
|
+
badTimes = [
|
|
154
|
+
'junk',
|
|
155
|
+
'February 92nd, 2015']
|
|
156
|
+
badTimes.each do |time|
|
|
157
|
+
assert_raise(OAI::ArgumentException) do
|
|
158
|
+
@provider.list_records(:metadata_prefix => 'oai_dc', :from => time)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def test_handles_empty_collections
|
|
164
|
+
DCField.delete_all
|
|
165
|
+
assert DCField.count == 0
|
|
166
|
+
# Identify and ListMetadataFormats should return normally
|
|
167
|
+
test_identify
|
|
168
|
+
test_metadata_formats
|
|
169
|
+
# ListIdentifiers and ListRecords should return "noRecordsMatch" error code
|
|
170
|
+
assert_raises(OAI::NoMatchException) do
|
|
171
|
+
REXML::Document.new(@provider.list_identifiers)
|
|
172
|
+
end
|
|
173
|
+
assert_raises(OAI::NoMatchException) do
|
|
174
|
+
REXML::Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def test_bad_id_raises_exception
|
|
179
|
+
badIdentifiers = [
|
|
180
|
+
'invalid"id',
|
|
181
|
+
'oai:test/5000',
|
|
182
|
+
'oai:test/-1',
|
|
183
|
+
'oai:test/one',
|
|
184
|
+
'oai:test/\\$1\1!']
|
|
185
|
+
badIdentifiers.each do |id|
|
|
186
|
+
assert_raise(OAI::IdException) do
|
|
187
|
+
@provider.get_record(:identifier => id, :metadata_prefix => 'oai_dc')
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def setup
|
|
194
|
+
@provider = ARProvider.new
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
require 'test_helper_ar_provider'
|
|
2
|
+
|
|
3
|
+
class ActiveRecordSetProviderTest < TransactionalTestCase
|
|
4
|
+
|
|
5
|
+
def test_list_sets
|
|
6
|
+
doc = REXML::Document.new(@provider.list_sets)
|
|
7
|
+
sets = doc.elements["/OAI-PMH/ListSets"]
|
|
8
|
+
assert sets.size == 4
|
|
9
|
+
assert sets[0].elements["//setName"].text == "Set A"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def test_set_a
|
|
13
|
+
doc = REXML::Document.new(@provider.list_records(
|
|
14
|
+
:metadata_prefix => 'oai_dc', :set => "A"))
|
|
15
|
+
assert_equal 20, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_set_b
|
|
19
|
+
doc = REXML::Document.new(@provider.list_records(
|
|
20
|
+
:metadata_prefix => 'oai_dc', :set => "B"))
|
|
21
|
+
assert_equal 10, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_set_ab
|
|
25
|
+
doc = REXML::Document.new(@provider.list_records(
|
|
26
|
+
:metadata_prefix => 'oai_dc', :set => "A:B"))
|
|
27
|
+
assert_equal 10, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_record_with_multiple_sets
|
|
31
|
+
record = DCSet.where("spec = 'C'").first.dc_fields.first
|
|
32
|
+
assert_equal 2, record.sets.size
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_missing_set
|
|
36
|
+
assert_raise(OAI::NoMatchException) do
|
|
37
|
+
doc = REXML::Document.new(@provider.list_records(
|
|
38
|
+
:metadata_prefix => 'oai_dc', :set => "D"))
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def setup
|
|
43
|
+
@provider = ARSetProvider.new
|
|
44
|
+
define_sets
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def define_sets
|
|
48
|
+
set_a = DCSet.create(:name => "Set A", :spec => "A")
|
|
49
|
+
set_b = DCSet.create(:name => "Set B", :spec => "B")
|
|
50
|
+
set_c = DCSet.create(:name => "Set C", :spec => "C")
|
|
51
|
+
set_ab = DCSet.create(:name => "Set A:B", :spec => "A:B")
|
|
52
|
+
|
|
53
|
+
next_id = 0
|
|
54
|
+
DCField.limit(10).order(id: :asc).each do |record|
|
|
55
|
+
set_a.dc_fields << record
|
|
56
|
+
next_id = record.id
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
DCField.where("dc_fields.id > ?", next_id).limit(10).order(id: :asc).each do |record|
|
|
60
|
+
set_b.dc_fields << record
|
|
61
|
+
next_id = record.id
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
DCField.where("dc_fields.id > ?", next_id).limit(10).order(id: :asc).each do |record|
|
|
65
|
+
set_ab.dc_fields << record
|
|
66
|
+
next_id = record.id
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
DCField.where("dc_fields.id > ?", next_id).limit(10).order(id: :asc).each do |record|
|
|
70
|
+
set_a.dc_fields << record
|
|
71
|
+
set_c.dc_fields << record
|
|
72
|
+
next_id = record.id
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ActiveRecordExclusiveSetsProviderTest < TransactionalTestCase
|
|
79
|
+
|
|
80
|
+
def test_list_sets
|
|
81
|
+
doc = REXML::Document.new(@provider.list_sets)
|
|
82
|
+
sets = doc.elements["/OAI-PMH/ListSets"]
|
|
83
|
+
assert_equal 3, sets.size
|
|
84
|
+
assert_equal "Set A", sets[0].elements["//setName"].text
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_set_a
|
|
88
|
+
doc = REXML::Document.new(@provider.list_records(
|
|
89
|
+
:metadata_prefix => 'oai_dc', :set => "A"))
|
|
90
|
+
assert_equal 20, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def test_set_b
|
|
94
|
+
doc = REXML::Document.new(@provider.list_records(
|
|
95
|
+
:metadata_prefix => 'oai_dc', :set => "B"))
|
|
96
|
+
assert_equal 10, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_set_ab
|
|
100
|
+
doc = REXML::Document.new(@provider.list_records(
|
|
101
|
+
:metadata_prefix => 'oai_dc', :set => "A:B"))
|
|
102
|
+
assert_equal 10, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_missing_set
|
|
106
|
+
assert_raise(OAI::NoMatchException) do
|
|
107
|
+
doc = REXML::Document.new(@provider.list_records(
|
|
108
|
+
:metadata_prefix => 'oai_dc', :set => "D"))
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def setup
|
|
113
|
+
@provider = ARExclusiveSetProvider.new
|
|
114
|
+
define_sets
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def define_sets
|
|
118
|
+
next_id = 0
|
|
119
|
+
|
|
120
|
+
ExclusiveSetDCField.limit(10).order(id: :asc).each do |record|
|
|
121
|
+
record.set = "A"
|
|
122
|
+
record.save!
|
|
123
|
+
next_id = record.id
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
ExclusiveSetDCField.where("id > ?", next_id).limit(10).order(id: :asc).each do |record|
|
|
127
|
+
record.set = "B"
|
|
128
|
+
record.save!
|
|
129
|
+
next_id = record.id
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
ExclusiveSetDCField.where("id > ?", next_id).limit(10).order(id: :asc).each do |record|
|
|
133
|
+
record.set = "A:B"
|
|
134
|
+
record.save!
|
|
135
|
+
next_id = record.id
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
ExclusiveSetDCField.where("id > ?", next_id).limit(10).order(id: :asc).each do |record|
|
|
139
|
+
record.set = "A"
|
|
140
|
+
record.save!
|
|
141
|
+
next_id = record.id
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
protected
|
|
146
|
+
|
|
147
|
+
def load_fixtures
|
|
148
|
+
fixtures = YAML.load_file(
|
|
149
|
+
File.join(File.dirname(__FILE__), 'fixtures', 'dc.yml')
|
|
150
|
+
)
|
|
151
|
+
disable_logging do
|
|
152
|
+
fixtures.keys.sort.each do |key|
|
|
153
|
+
lang = DCLang.create(name: fixtures[key].delete('language'))
|
|
154
|
+
ExclusiveSetDCField.create(fixtures[key].merge(dc_lang: lang))
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'test_helper_ar_provider'
|
|
2
|
+
|
|
3
|
+
class CachingPagingProviderTest < TransactionalTestCase
|
|
4
|
+
include REXML
|
|
5
|
+
|
|
6
|
+
def test_full_harvest
|
|
7
|
+
doc = Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
8
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
9
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
|
|
10
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
11
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
12
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
13
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
14
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
|
|
15
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
16
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
17
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
18
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
|
|
19
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
20
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
21
|
+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
22
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_from_and_until
|
|
26
|
+
first_id = DCField.order(id: :asc).first.id
|
|
27
|
+
DCField.where("dc_fields.id <= ?", first_id + 25).update_all(updated_at: Time.parse("September 15 2005"))
|
|
28
|
+
DCField.where(["dc_fields.id < ? and dc_fields.id > ?", first_id + 50, first_id + 25]).update_all(updated_at: Time.parse("November 1 2005"))
|
|
29
|
+
|
|
30
|
+
# Should return 50 records broken into 2 groups of 25.
|
|
31
|
+
doc = Document.new(
|
|
32
|
+
@provider.list_records(
|
|
33
|
+
:metadata_prefix => 'oai_dc',
|
|
34
|
+
:from => Time.parse("September 1 2005"),
|
|
35
|
+
:until => Time.parse("November 30 2005"))
|
|
36
|
+
)
|
|
37
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
|
|
38
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
39
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
40
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
41
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
42
|
+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
43
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def setup
|
|
47
|
+
@provider = CachingResumptionProvider.new
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|