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,42 @@
|
|
|
1
|
+
require 'test_helper_harvester'
|
|
2
|
+
|
|
3
|
+
class HarvestTest < Test::Unit::TestCase
|
|
4
|
+
ONE_HOUR = 3600
|
|
5
|
+
EARLIEST_FIXTURE = "1998-05-02T04:00:00Z"
|
|
6
|
+
LATEST_FIXTURE = "2005-12-25T05:00:00Z"
|
|
7
|
+
def test_harvest
|
|
8
|
+
until_value = Time.now.utc - ONE_HOUR
|
|
9
|
+
config = OpenStruct.new(sites: { 'test' => { 'url' => 'http://localhost:3333/oai' }})
|
|
10
|
+
OAI::Harvester::Harvest.new(config).start
|
|
11
|
+
last = config.sites.dig('test', 'last')
|
|
12
|
+
assert_kind_of Time, last
|
|
13
|
+
assert last >= (until_value + ONE_HOUR), "#{last} < #{(until_value + ONE_HOUR)}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_harvest_from_last
|
|
17
|
+
from_value = Time.parse(LATEST_FIXTURE).utc
|
|
18
|
+
now = Time.now.utc
|
|
19
|
+
config = OpenStruct.new(sites: { 'test' => { 'url' => 'http://localhost:3333/oai' }})
|
|
20
|
+
OAI::Harvester::Harvest.new(config, nil, from_value).start
|
|
21
|
+
last = config.sites.dig('test', 'last')
|
|
22
|
+
assert last >= now, "#{last} < #{now}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_harvest_after_last
|
|
26
|
+
from_value = Time.parse(LATEST_FIXTURE).utc + 1
|
|
27
|
+
config = OpenStruct.new(sites: { 'test' => { 'url' => 'http://localhost:3333/oai' }})
|
|
28
|
+
OAI::Harvester::Harvest.new(config, nil, from_value).start
|
|
29
|
+
last = config.sites.dig('test', 'last')
|
|
30
|
+
assert_kind_of NilClass, last
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_harvest_with_until
|
|
34
|
+
until_value = Time.parse(EARLIEST_FIXTURE).utc + ONE_HOUR
|
|
35
|
+
config = OpenStruct.new(sites: { 'test' => { 'url' => 'http://localhost:3333/oai' }})
|
|
36
|
+
OAI::Harvester::Harvest.new(config, nil, nil, until_value).start
|
|
37
|
+
last = config.sites.dig('test', 'last')
|
|
38
|
+
assert_kind_of Time, last
|
|
39
|
+
assert_equal last, until_value
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
class Record
|
|
2
|
+
attr_accessor :id, :titles, :creator, :tags, :sets, :updated_at, :deleted
|
|
3
|
+
|
|
4
|
+
def initialize(id,
|
|
5
|
+
titles = 'title',
|
|
6
|
+
creator = 'creator',
|
|
7
|
+
tags = 'tag',
|
|
8
|
+
sets = nil,
|
|
9
|
+
deleted = false,
|
|
10
|
+
updated_at = Time.now.utc.xmlschema)
|
|
11
|
+
|
|
12
|
+
@id = id
|
|
13
|
+
@titles = titles
|
|
14
|
+
@creator = creator
|
|
15
|
+
@tags = tags
|
|
16
|
+
@sets = sets
|
|
17
|
+
@deleted = deleted
|
|
18
|
+
@updated_at = updated_at
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Override Object.id
|
|
22
|
+
def id
|
|
23
|
+
@id
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def in_set(spec)
|
|
27
|
+
if @sets.respond_to?(:each)
|
|
28
|
+
@sets.each { |set| return true if set.spec == spec }
|
|
29
|
+
else
|
|
30
|
+
return true if @sets.spec == spec
|
|
31
|
+
end
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class TestModel < OAI::Provider::Model
|
|
37
|
+
include OAI::Provider
|
|
38
|
+
|
|
39
|
+
def initialize(limit = nil)
|
|
40
|
+
super(limit)
|
|
41
|
+
@records = []
|
|
42
|
+
@sets = []
|
|
43
|
+
@earliest = Time.now.utc.xmlschema
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def earliest
|
|
47
|
+
(@records.min {|a,b| a.updated_at <=> b.updated_at }).updated_at.utc.xmlschema
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def latest
|
|
51
|
+
@records.max {|a,b| a.updated_at <=> b.updated_at }.updated_at.utc.xmlschema
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def sets
|
|
55
|
+
@sets
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def find(selector, opts={})
|
|
59
|
+
return nil unless selector
|
|
60
|
+
|
|
61
|
+
case selector
|
|
62
|
+
when :all
|
|
63
|
+
if opts[:resumption_token]
|
|
64
|
+
raise OAI::ResumptionTokenException.new unless @limit
|
|
65
|
+
begin
|
|
66
|
+
token = ResumptionToken.parse(opts[:resumption_token])
|
|
67
|
+
|
|
68
|
+
if token.last < @groups.size - 1
|
|
69
|
+
PartialResult.new(@groups[token.last], token.next(token.last + 1))
|
|
70
|
+
else
|
|
71
|
+
PartialResult.new(@groups[token.last], token.next(nil))
|
|
72
|
+
end
|
|
73
|
+
rescue
|
|
74
|
+
raise OAI::ResumptionTokenException.new
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
records = @records.select do |rec|
|
|
78
|
+
((opts[:set].nil? || rec.in_set(opts[:set])) &&
|
|
79
|
+
(opts[:from].nil? || rec.updated_at >= opts[:from].to_time) &&
|
|
80
|
+
(opts[:until].nil? || rec.updated_at <= opts[:until].to_time))
|
|
81
|
+
#else
|
|
82
|
+
# ((opts[:set].nil? || rec.in_set(opts[:set])) &&
|
|
83
|
+
# (opts[:from].nil? || rec.updated_at >= opts[:from]) &&
|
|
84
|
+
# (opts[:until].nil? || rec.updated_at <= opts[:until]))
|
|
85
|
+
#end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
if @limit && records.size > @limit
|
|
89
|
+
@groups = generate_chunks(records, @limit)
|
|
90
|
+
return PartialResult.new(@groups[0],
|
|
91
|
+
ResumptionToken.new(opts.merge({:last => 1})))
|
|
92
|
+
end
|
|
93
|
+
return records
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
begin
|
|
97
|
+
@records.each do |record|
|
|
98
|
+
return record if record.id.to_s == selector
|
|
99
|
+
end
|
|
100
|
+
rescue
|
|
101
|
+
end
|
|
102
|
+
nil
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def generate_chunks(records, limit)
|
|
107
|
+
groups = []
|
|
108
|
+
records.each_slice(limit) do |group|
|
|
109
|
+
groups << group
|
|
110
|
+
end
|
|
111
|
+
groups
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def generate_records(number, timestamp = Time.now.utc.xmlschema, sets = [], deleted = false)
|
|
115
|
+
@earliest = timestamp.dup if @earliest.nil? || timestamp.to_s < @earliest.to_s
|
|
116
|
+
@earliest = timestamp.dup if @earliest.nil?
|
|
117
|
+
|
|
118
|
+
# Add any sets we don't already have
|
|
119
|
+
sets = [sets] unless sets.respond_to?(:each)
|
|
120
|
+
sets.each do |set|
|
|
121
|
+
@sets << set unless @sets.include?(set)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Generate some records
|
|
125
|
+
number.times do |id|
|
|
126
|
+
rec = Record.new(@records.size, "title_#{id}", "creator_#{id}", "tag_#{id}")
|
|
127
|
+
rec.updated_at = timestamp.utc
|
|
128
|
+
rec.sets = sets
|
|
129
|
+
rec.deleted = deleted
|
|
130
|
+
@records << rec
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
class SimpleModel < TestModel
|
|
137
|
+
|
|
138
|
+
def initialize
|
|
139
|
+
super
|
|
140
|
+
# Create a couple of sets
|
|
141
|
+
set_one = OAI::Set.new()
|
|
142
|
+
set_one.name = "Test Set One"
|
|
143
|
+
set_one.spec = "A"
|
|
144
|
+
set_one.description = "This is test set one."
|
|
145
|
+
|
|
146
|
+
set_two = OAI::Set.new()
|
|
147
|
+
set_two.name = "Test Set Two"
|
|
148
|
+
set_two.spec = "A:B"
|
|
149
|
+
set_two.description = "This is test set two."
|
|
150
|
+
|
|
151
|
+
generate_records(5, Time.parse("2002-10-5"), set_one)
|
|
152
|
+
generate_records(1, Time.parse("2002-11-5"), [set_two], true)
|
|
153
|
+
generate_records(4, Time.parse("2002-11-5"), [set_two])
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
class BigModel < TestModel
|
|
159
|
+
|
|
160
|
+
def initialize(limit = nil)
|
|
161
|
+
super(limit)
|
|
162
|
+
generate_records(100, Time.parse("October 2 2000"))
|
|
163
|
+
generate_records(100, Time.parse("November 2 2000"))
|
|
164
|
+
generate_records(100, Time.parse("December 2 2000"))
|
|
165
|
+
generate_records(100, Time.parse("January 2 2001"))
|
|
166
|
+
generate_records(100, Time.parse("February 2 2001"))
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
class MappedModel < TestModel
|
|
172
|
+
|
|
173
|
+
def initialize
|
|
174
|
+
super
|
|
175
|
+
set_one = OAI::Set.new()
|
|
176
|
+
set_one.name = "Test Set One"
|
|
177
|
+
set_one.spec = "A"
|
|
178
|
+
set_one.description = "This is test set one."
|
|
179
|
+
|
|
180
|
+
generate_records(5, Time.parse("dec 1 2006"), set_one)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def map_oai_dc
|
|
184
|
+
{:title => :creator, :creator => :titles, :subject => :tags}
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
class ComplexModel < TestModel
|
|
190
|
+
|
|
191
|
+
def initialize(limit = nil)
|
|
192
|
+
super(limit)
|
|
193
|
+
# Create a couple of sets
|
|
194
|
+
set_one = OAI::Set.new
|
|
195
|
+
set_one.name = "Set One"
|
|
196
|
+
set_one.spec = "One"
|
|
197
|
+
set_one.description = "This is test set one."
|
|
198
|
+
|
|
199
|
+
set_two = OAI::Set.new
|
|
200
|
+
set_two.name = "Set Two"
|
|
201
|
+
set_two.spec = "Two"
|
|
202
|
+
set_two.description = "This is test set two."
|
|
203
|
+
|
|
204
|
+
set_three = OAI::Set.new
|
|
205
|
+
set_three.name = "Set Three"
|
|
206
|
+
set_three.spec = "Three"
|
|
207
|
+
set_three.description = "This is test set three."
|
|
208
|
+
|
|
209
|
+
set_four = OAI::Set.new
|
|
210
|
+
set_four.name = "Set Four"
|
|
211
|
+
set_four.spec = "Four"
|
|
212
|
+
set_four.description = "This is test set four."
|
|
213
|
+
|
|
214
|
+
set_one_two = OAI::Set.new
|
|
215
|
+
set_one_two.name = "Set One and Two"
|
|
216
|
+
set_one_two.spec = "One:Two"
|
|
217
|
+
set_one_two.description = "This is combination set of One and Two."
|
|
218
|
+
|
|
219
|
+
set_three_four = OAI::Set.new
|
|
220
|
+
set_three_four.name = "Set Three and Four"
|
|
221
|
+
set_three_four.spec = "Three:Four"
|
|
222
|
+
set_three_four.description = "This is combination set of Three and Four."
|
|
223
|
+
|
|
224
|
+
generate_records(250, Time.parse("May 2 1998"), [set_one, set_one_two])
|
|
225
|
+
generate_records(50, Time.parse("June 2 1998"), [set_one, set_one_two], true)
|
|
226
|
+
generate_records(50, Time.parse("October 10 1998"), [set_three, set_three_four], true)
|
|
227
|
+
generate_records(250, Time.parse("July 2 2002"), [set_two, set_one_two])
|
|
228
|
+
|
|
229
|
+
generate_records(250, Time.parse("September 15 2004"), [set_three, set_three_four])
|
|
230
|
+
generate_records(50, Time.parse("October 10 2004"), [set_three, set_three_four], true)
|
|
231
|
+
generate_records(250, Time.parse("December 25 2005"), [set_four, set_three_four])
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def about record
|
|
235
|
+
xml = <<-eos
|
|
236
|
+
<oai_dc:dc
|
|
237
|
+
xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
|
|
238
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
|
239
|
+
<dc:publisher>Ruby OAI test data</dc:publisher>
|
|
240
|
+
</oai_dc:dc>
|
|
241
|
+
eos
|
|
242
|
+
# Removes new-lines and formatting, which is a problem with Ruby 1.8.x
|
|
243
|
+
xml.gsub(/\s+/, ' ')
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'test_helper_provider'
|
|
2
|
+
|
|
3
|
+
class ProviderExceptions < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def setup
|
|
6
|
+
@provider = ComplexProvider.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_argument_exception
|
|
10
|
+
assert_raise(OAI::ArgumentException) do
|
|
11
|
+
@provider.identify(:identifier => 'invalid_arg')
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_resumption_token_exception
|
|
16
|
+
assert_raise(OAI::ResumptionTokenException) do
|
|
17
|
+
@provider.list_records(:resumption_token => 'aaadddd:1000')
|
|
18
|
+
end
|
|
19
|
+
assert_raise(OAI::ResumptionTokenException) do
|
|
20
|
+
@provider.list_records(:resumption_token => 'oai_dc:1000')
|
|
21
|
+
end
|
|
22
|
+
assert_raise(OAI::ResumptionTokenException) do
|
|
23
|
+
@provider.list_identifiers(:resumption_token => '..::!:.:!:')
|
|
24
|
+
end
|
|
25
|
+
assert_raise(OAI::ResumptionTokenException) do
|
|
26
|
+
@provider.list_identifiers(:resumption_token => '\:\\:\/$%^&*!@#!:1')
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_bad_verb_raises_exception
|
|
31
|
+
assert @provider.process_request(:verb => 'BadVerb') =~ /badVerb/
|
|
32
|
+
assert @provider.process_request(:verb => '\a$#^%!@') =~ /badVerb/
|
|
33
|
+
assert @provider.process_request(:verb => 'identity') =~ /badVerb/
|
|
34
|
+
assert @provider.process_request(:verb => '!!\\$\$\.+') =~ /badVerb/
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_bad_format_raises_exception
|
|
38
|
+
assert_raise(OAI::FormatException) do
|
|
39
|
+
@provider.get_record(:identifier => 'oai:test:1', :metadata_prefix => 'html')
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_missing_format_raises_exception
|
|
44
|
+
assert_raise(OAI::ArgumentException) do
|
|
45
|
+
@provider.list_records()
|
|
46
|
+
end
|
|
47
|
+
assert_raise(OAI::ArgumentException) do
|
|
48
|
+
@provider.get_record(:identifier => 'oai:test:1')
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_bad_id_raises_exception
|
|
53
|
+
badIdentifiers = [
|
|
54
|
+
'oai:test:5000',
|
|
55
|
+
'oai:test:-1',
|
|
56
|
+
'oai:test:one',
|
|
57
|
+
'oai:test/one',
|
|
58
|
+
'oai:test/1',
|
|
59
|
+
'oai:test:\\$1\1!']
|
|
60
|
+
badIdentifiers.each do |id|
|
|
61
|
+
assert_raise(OAI::IdException) do
|
|
62
|
+
@provider.get_record(:identifier => id, :metadata_prefix => 'oai_dc')
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def test_no_records_match_dates_that_are_out_of_range
|
|
68
|
+
assert_raise(OAI::NoMatchException) do
|
|
69
|
+
@provider.list_records(:metadata_prefix => 'oai_dc',
|
|
70
|
+
:from => Time.parse("November 2 2000"),
|
|
71
|
+
:until => Time.parse("November 1 2000"))
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_no_records_match_bad_set
|
|
76
|
+
assert_raise(OAI::NoMatchException) do
|
|
77
|
+
@provider.list_records(:metadata_prefix => 'oai_dc', :set => 'unknown')
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'test_helper_provider'
|
|
2
|
+
|
|
3
|
+
class ResumptionTokenFunctionalTest < Test::Unit::TestCase
|
|
4
|
+
include REXML
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
@provider = ComplexProvider.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_resumption_tokens
|
|
11
|
+
assert_nothing_raised do
|
|
12
|
+
Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
13
|
+
end
|
|
14
|
+
doc = Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
15
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
16
|
+
assert_equal (@provider.model.limit + 1), doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
17
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
18
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
19
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
20
|
+
assert_equal (@provider.model.limit + 1), doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_from_and_until_with_resumption_tokens
|
|
24
|
+
# Should return 550 records broken into 5 groups of 100, and a final group of 50.
|
|
25
|
+
# checked elements under ListRecords are limit + 1, accounting for the resumptionToken element
|
|
26
|
+
assert_nothing_raised do
|
|
27
|
+
Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
28
|
+
end
|
|
29
|
+
doc = Document.new(
|
|
30
|
+
@provider.list_records(
|
|
31
|
+
:metadata_prefix => 'oai_dc',
|
|
32
|
+
:from => Time.parse("September 1 2004"),
|
|
33
|
+
:until => Time.parse("December 25 2005"))
|
|
34
|
+
)
|
|
35
|
+
assert_equal (@provider.model.limit + 1), doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
36
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
37
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
38
|
+
|
|
39
|
+
4.times do
|
|
40
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
41
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
42
|
+
assert_equal (@provider.model.limit + 1), doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
43
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
47
|
+
# assert that ListRecords includes remaining records and an empty resumption token
|
|
48
|
+
assert_equal (551 % @provider.model.limit), doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
49
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
50
|
+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'test_helper_provider'
|
|
2
|
+
|
|
3
|
+
class TestInstanceProvider < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
# Prior to the commit introducing this code, the InstanceProvider#identify
|
|
6
|
+
# method would instantiate a Response::Identify object, passing the
|
|
7
|
+
# InstanceProvider class as the provider for the Response::Identify
|
|
8
|
+
# instance. With the commit introducing this test, the
|
|
9
|
+
# InstanceProvider#identify now passes the instance of InstanceProvider
|
|
10
|
+
# to the instantiation of Response::Identify.
|
|
11
|
+
#
|
|
12
|
+
# Thus we can override, on an instance by instance basis, the behavior of a
|
|
13
|
+
# response object.
|
|
14
|
+
def test_instance_used_in_responses
|
|
15
|
+
@url_path = "/stringy-mc-string-face"
|
|
16
|
+
@instance_provider = InstanceProvider.new({ :provider_context => :instance_based, :url_path => @url_path })
|
|
17
|
+
|
|
18
|
+
xml = @instance_provider.identify
|
|
19
|
+
doc = REXML::Document.new(xml)
|
|
20
|
+
assert_equal "http://localhost#{@url_path}", doc.elements["OAI-PMH/Identify/baseURL"].text
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_class_used_in_responses
|
|
24
|
+
@url_path = "/stringy-mc-string-face"
|
|
25
|
+
@instance_provider = InstanceProvider.new({ :provider_context => :class_based, :url_path => @url_path })
|
|
26
|
+
|
|
27
|
+
xml = @instance_provider.identify
|
|
28
|
+
doc = REXML::Document.new(xml)
|
|
29
|
+
assert_equal "http://localhost", doc.elements["OAI-PMH/Identify/baseURL"].text
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_by_default_class_used_in_responses
|
|
33
|
+
@url_path = "/stringy-mc-string-face"
|
|
34
|
+
@instance_provider = InstanceProvider.new({ :url_path => @url_path })
|
|
35
|
+
|
|
36
|
+
xml = @instance_provider.identify
|
|
37
|
+
doc = REXML::Document.new(xml)
|
|
38
|
+
assert_equal "http://localhost", doc.elements["OAI-PMH/Identify/baseURL"].text
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
require 'test_helper_provider'
|
|
2
|
+
|
|
3
|
+
class OaiTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def setup
|
|
6
|
+
@mapped_provider = MappedProvider.new
|
|
7
|
+
@big_provider = BigProvider.new
|
|
8
|
+
@described_provider = DescribedProvider.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_additional_description
|
|
12
|
+
doc = REXML::Document.new(@described_provider.identify)
|
|
13
|
+
assert_equal "oai:test:13900", doc.elements['OAI-PMH/Identify/description/oai-identifier/sampleIdentifier'].text
|
|
14
|
+
assert_not_nil doc.elements['OAI-PMH/Identify/my_custom_xml']
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_list_identifiers_for_correct_xml
|
|
18
|
+
doc = REXML::Document.new(@mapped_provider.list_identifiers)
|
|
19
|
+
assert_not_nil doc.elements['OAI-PMH/request']
|
|
20
|
+
assert_not_nil doc.elements['OAI-PMH/request/@verb']
|
|
21
|
+
assert_not_nil doc.elements['OAI-PMH/ListIdentifiers']
|
|
22
|
+
assert_not_nil doc.elements['OAI-PMH/ListIdentifiers/header']
|
|
23
|
+
assert_not_nil doc.elements['OAI-PMH/ListIdentifiers/header/identifier']
|
|
24
|
+
assert_not_nil doc.elements['OAI-PMH/ListIdentifiers/header/datestamp']
|
|
25
|
+
assert_not_nil doc.elements['OAI-PMH/ListIdentifiers/header/setSpec']
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_list_records_for_correct_xml
|
|
29
|
+
doc = REXML::Document.new(
|
|
30
|
+
@mapped_provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
31
|
+
assert_not_nil doc.elements['OAI-PMH/request']
|
|
32
|
+
assert_not_nil doc.elements['OAI-PMH/request/@verb']
|
|
33
|
+
assert_not_nil doc.elements['OAI-PMH/request/@metadata_prefix']
|
|
34
|
+
assert_not_nil doc.elements['OAI-PMH/ListRecords/record/header']
|
|
35
|
+
assert_not_nil doc.elements['OAI-PMH/ListRecords/record/metadata']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_mapped_source
|
|
39
|
+
assert_nothing_raised do
|
|
40
|
+
REXML::Document.new(
|
|
41
|
+
@mapped_provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
42
|
+
end
|
|
43
|
+
doc = REXML::Document.new(
|
|
44
|
+
@mapped_provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
45
|
+
assert_equal "title_0", doc.elements['OAI-PMH/ListRecords/record/metadata/oai_dc:dc/dc:creator'].text
|
|
46
|
+
assert_equal "creator_0", doc.elements['OAI-PMH/ListRecords/record/metadata/oai_dc:dc/dc:title'].text
|
|
47
|
+
assert_equal "tag_0", doc.elements['OAI-PMH/ListRecords/record/metadata/oai_dc:dc/dc:subject'].text
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_from
|
|
51
|
+
assert_nothing_raised do
|
|
52
|
+
REXML::Document.new(
|
|
53
|
+
@big_provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
54
|
+
end
|
|
55
|
+
doc = REXML::Document.new(
|
|
56
|
+
@big_provider.list_records(
|
|
57
|
+
:metadata_prefix => 'oai_dc',
|
|
58
|
+
:from => Time.parse("February 1 2001"))
|
|
59
|
+
)
|
|
60
|
+
assert_equal 100, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
61
|
+
|
|
62
|
+
doc = REXML::Document.new(
|
|
63
|
+
@big_provider.list_records(
|
|
64
|
+
:metadata_prefix => 'oai_dc',
|
|
65
|
+
:from => Time.parse("January 1 2001"))
|
|
66
|
+
)
|
|
67
|
+
assert_equal 200, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_until
|
|
71
|
+
assert_nothing_raised do
|
|
72
|
+
REXML::Document.new(
|
|
73
|
+
@big_provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
74
|
+
end
|
|
75
|
+
doc = REXML::Document.new(
|
|
76
|
+
@big_provider.list_records(
|
|
77
|
+
:metadata_prefix => 'oai_dc', :until => Time.parse("November 1 2000"))
|
|
78
|
+
)
|
|
79
|
+
assert_equal 100, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_from_and_until_match
|
|
83
|
+
assert_nothing_raised do
|
|
84
|
+
@big_provider.list_records(
|
|
85
|
+
:metadata_prefix => 'oai_dc',
|
|
86
|
+
:from => "2000-11-01T05:00:00Z",
|
|
87
|
+
:until => "2000-11-30T05:00:00Z"
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
assert_nothing_raised do
|
|
92
|
+
@big_provider.list_records(
|
|
93
|
+
:metadata_prefix => 'oai_dc',
|
|
94
|
+
:from => "2000-11-01",
|
|
95
|
+
:until => "2000-11-30"
|
|
96
|
+
)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
assert_raise(OAI::ArgumentException) do
|
|
100
|
+
@big_provider.list_records(
|
|
101
|
+
:metadata_prefix => 'oai_dc',
|
|
102
|
+
:from => "2000-11-01T05:00:00Z",
|
|
103
|
+
:until => "2000-11-30"
|
|
104
|
+
)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def test_from_and_until
|
|
109
|
+
assert_nothing_raised do
|
|
110
|
+
REXML::Document.new(
|
|
111
|
+
@big_provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
112
|
+
end
|
|
113
|
+
doc = REXML::Document.new(
|
|
114
|
+
@big_provider.list_records(
|
|
115
|
+
:metadata_prefix => 'oai_dc',
|
|
116
|
+
:from => Time.parse("November 1 2000"),
|
|
117
|
+
:until => Time.parse("November 30 2000"))
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
assert_not_nil doc.elements['OAI-PMH/request']
|
|
121
|
+
assert_not_nil doc.elements['OAI-PMH/request/@verb']
|
|
122
|
+
assert_not_nil doc.elements['OAI-PMH/request/@from']
|
|
123
|
+
assert_not_nil doc.elements['OAI-PMH/request/@until']
|
|
124
|
+
|
|
125
|
+
assert_equal 100, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
126
|
+
|
|
127
|
+
doc = REXML::Document.new(
|
|
128
|
+
@big_provider.list_records(
|
|
129
|
+
:metadata_prefix => 'oai_dc',
|
|
130
|
+
:from => Time.parse("December 1 2000"),
|
|
131
|
+
:until => Time.parse("December 31 2000"))
|
|
132
|
+
)
|
|
133
|
+
assert_equal 100, doc.elements['OAI-PMH/ListRecords'].to_a.size
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'test_helper_provider'
|
|
2
|
+
|
|
3
|
+
class ResumptionTokenTest < Test::Unit::TestCase
|
|
4
|
+
include REXML
|
|
5
|
+
include OAI::Provider
|
|
6
|
+
|
|
7
|
+
def setup
|
|
8
|
+
@token = ResumptionToken.new(
|
|
9
|
+
:from => Time.utc(2005,"jan",1,17,0,0),
|
|
10
|
+
:until => Time.utc(2005,"jan",31,17,0,0),
|
|
11
|
+
:set => "A",
|
|
12
|
+
:metadata_prefix => "oai_dc",
|
|
13
|
+
:last => 1
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_resumption_token_options_encoding
|
|
18
|
+
assert_equal "oai_dc.s(A).f(2005-01-01T17:00:00Z).u(2005-01-31T17:00:00Z)",
|
|
19
|
+
@token.to_s
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_resumption_token_next_method
|
|
23
|
+
assert_equal 100, @token.next(100).last
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_resumption_token_to_condition_hash
|
|
27
|
+
hash = @token.to_conditions_hash
|
|
28
|
+
assert_equal @token.from, hash[:from]
|
|
29
|
+
assert_equal @token.until, hash[:until]
|
|
30
|
+
assert_equal @token.set, hash[:set]
|
|
31
|
+
assert_equal @token.prefix, hash[:metadata_prefix]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_resumption_token_parsing
|
|
35
|
+
new_token = ResumptionToken.parse(
|
|
36
|
+
"oai_dc.s(A).f(2005-01-01T17:00:00Z).u(2005-01-31T17:00:00Z):1"
|
|
37
|
+
)
|
|
38
|
+
assert_equal @token, new_token
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_resumption_token_to_xml
|
|
42
|
+
doc = REXML::Document.new(@token.to_xml)
|
|
43
|
+
assert_equal "#{@token.to_s}:#{@token.last}", doc.elements['/resumptionToken'].text
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_resumption_token_id_does_not_need_to_be_numeric
|
|
47
|
+
serialized = "oai_dc.s(A).f(2005-01-01T17:00:00Z).u(2005-01-31T17:00:00Z):FA129C"
|
|
48
|
+
|
|
49
|
+
token = ResumptionToken.parse(serialized)
|
|
50
|
+
assert_equal serialized, token.send(:encode_conditions)
|
|
51
|
+
end
|
|
52
|
+
end
|