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.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +128 -0
  3. data/Rakefile +64 -0
  4. data/bin/oai +66 -0
  5. data/examples/models/file_model.rb +63 -0
  6. data/examples/providers/dublin_core.rb +474 -0
  7. data/lib/oai/{get_record.rb → client/get_record.rb} +5 -1
  8. data/lib/oai/client/header.rb +18 -0
  9. data/lib/oai/{identify.rb → client/identify.rb} +2 -0
  10. data/lib/oai/{list_identifiers.rb → client/list_identifiers.rb} +1 -0
  11. data/lib/oai/{list_records.rb → client/list_records.rb} +6 -5
  12. data/lib/oai/{list_sets.rb → client/list_sets.rb} +7 -6
  13. data/lib/oai/client/record.rb +27 -0
  14. data/lib/oai/client/response.rb +53 -0
  15. data/lib/oai/client/resumable.rb +42 -0
  16. data/lib/oai/client.rb +313 -108
  17. data/lib/oai/constants.rb +34 -0
  18. data/lib/oai/exception.rb +80 -1
  19. data/lib/oai/harvester/config.rb +41 -0
  20. data/lib/oai/harvester/harvest.rb +162 -0
  21. data/lib/oai/harvester/logging.rb +68 -0
  22. data/lib/oai/harvester/mailer.rb +17 -0
  23. data/lib/oai/harvester/shell.rb +337 -0
  24. data/lib/oai/harvester.rb +43 -0
  25. data/lib/oai/provider/metadata_format/oai_dc.rb +28 -0
  26. data/lib/oai/provider/metadata_format.rb +119 -0
  27. data/lib/oai/provider/model/activerecord_caching_wrapper.rb +129 -0
  28. data/lib/oai/provider/model/activerecord_wrapper.rb +217 -0
  29. data/lib/oai/provider/model.rb +80 -0
  30. data/lib/oai/provider/partial_result.rb +18 -0
  31. data/lib/oai/provider/response/error.rb +16 -0
  32. data/lib/oai/provider/response/get_record.rb +27 -0
  33. data/lib/oai/provider/response/identify.rb +37 -0
  34. data/lib/oai/provider/response/list_identifiers.rb +30 -0
  35. data/lib/oai/provider/response/list_metadata_formats.rb +39 -0
  36. data/lib/oai/provider/response/list_records.rb +47 -0
  37. data/lib/oai/provider/response/list_sets.rb +23 -0
  38. data/lib/oai/provider/response/record_response.rb +103 -0
  39. data/lib/oai/provider/response.rb +133 -0
  40. data/lib/oai/provider/resumption_token.rb +155 -0
  41. data/lib/oai/provider.rb +487 -0
  42. data/lib/oai/set.rb +14 -5
  43. data/lib/oai/xpath.rb +59 -5
  44. data/lib/oai.rb +7 -13
  45. data/lib/test.rb +25 -0
  46. data/test/activerecord_provider/config/connection.rb +30 -0
  47. data/test/activerecord_provider/database/0001_oaipmh_tables.rb +70 -0
  48. data/test/activerecord_provider/fixtures/dc.yml +1501 -0
  49. data/test/activerecord_provider/helpers/providers.rb +68 -0
  50. data/test/activerecord_provider/helpers/set_provider.rb +24 -0
  51. data/test/activerecord_provider/helpers/transactional_test_case.rb +35 -0
  52. data/test/activerecord_provider/models/dc_field.rb +15 -0
  53. data/test/activerecord_provider/models/dc_lang.rb +3 -0
  54. data/test/activerecord_provider/models/dc_set.rb +7 -0
  55. data/test/activerecord_provider/models/exclusive_set_dc_field.rb +17 -0
  56. data/test/activerecord_provider/models/oai_token.rb +3 -0
  57. data/test/activerecord_provider/tc_activerecord_wrapper.rb +63 -0
  58. data/test/activerecord_provider/tc_ar_provider.rb +199 -0
  59. data/test/activerecord_provider/tc_ar_sets_provider.rb +159 -0
  60. data/test/activerecord_provider/tc_caching_paging_provider.rb +50 -0
  61. data/test/activerecord_provider/tc_simple_paging_provider.rb +71 -0
  62. data/test/activerecord_provider/test_helper_ar_provider.rb +7 -0
  63. data/test/client/helpers/provider.rb +65 -0
  64. data/test/client/helpers/test_wrapper.rb +6 -0
  65. data/test/client/tc_exception.rb +36 -0
  66. data/test/client/tc_get_record.rb +39 -0
  67. data/test/client/tc_http_client.rb +129 -0
  68. data/test/client/tc_identify.rb +13 -0
  69. data/test/client/tc_libxml.rb +61 -0
  70. data/test/{tc_list_identifiers.rb → client/tc_list_identifiers.rb} +28 -9
  71. data/test/{tc_list_metadata_formats.rb → client/tc_list_metadata_formats.rb} +4 -1
  72. data/test/client/tc_list_records.rb +26 -0
  73. data/test/client/tc_list_sets.rb +34 -0
  74. data/test/client/tc_low_resolution_dates.rb +14 -0
  75. data/test/client/tc_utf8_escaping.rb +19 -0
  76. data/test/client/tc_xpath.rb +26 -0
  77. data/test/client/test_helper_client.rb +5 -0
  78. data/test/harvester/tc_harvest.rb +42 -0
  79. data/test/harvester/test_helper_harvester.rb +6 -0
  80. data/test/provider/models.rb +246 -0
  81. data/test/provider/tc_exceptions.rb +81 -0
  82. data/test/provider/tc_functional_tokens.rb +53 -0
  83. data/test/provider/tc_instance_provider.rb +41 -0
  84. data/test/provider/tc_provider.rb +136 -0
  85. data/test/provider/tc_resumption_tokens.rb +52 -0
  86. data/test/provider/tc_simple_provider.rb +138 -0
  87. data/test/provider/test_helper_provider.rb +62 -0
  88. data/test/test.xml +22 -0
  89. metadata +238 -56
  90. data/lib/oai/header.rb +0 -12
  91. data/lib/oai/record.rb +0 -11
  92. data/lib/oai/response.rb +0 -20
  93. data/test/tc_get_record.rb +0 -27
  94. data/test/tc_identify.rb +0 -8
  95. data/test/tc_list_records.rb +0 -9
  96. data/test/tc_list_sets.rb +0 -17
  97. data/test.rb +0 -12
  98. /data/lib/oai/{list_metadata_formats.rb → client/list_metadata_formats.rb} +0 -0
  99. /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,3 @@
1
+ class DCLang < ActiveRecord::Base
2
+ has_many :dc_fields
3
+ end
@@ -0,0 +1,7 @@
1
+ class DCSet < ActiveRecord::Base
2
+ has_and_belongs_to_many :dc_fields,
3
+ :join_table => "dc_fields_dc_sets",
4
+ :foreign_key => "dc_set_id",
5
+ :class_name => "DCField"
6
+
7
+ 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,3 @@
1
+ class OaiToken < ActiveRecord::Base
2
+ serialize :params
3
+ 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