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,71 @@
|
|
|
1
|
+
require 'test_helper_ar_provider'
|
|
2
|
+
|
|
3
|
+
class SimpleResumptionProviderTest < 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"].to_a.size
|
|
10
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
11
|
+
|
|
12
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
13
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
14
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
15
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
16
|
+
|
|
17
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
18
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
19
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
20
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
21
|
+
|
|
22
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
23
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
24
|
+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
25
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_non_integer_identifiers_resumption
|
|
29
|
+
@provider = SimpleResumptionProviderWithNonIntegerID.new
|
|
30
|
+
|
|
31
|
+
doc = Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
|
|
32
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
33
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
34
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
35
|
+
|
|
36
|
+
next_doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
37
|
+
assert_not_nil next_doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
38
|
+
next_token = next_doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
39
|
+
assert_equal 26, next_doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
40
|
+
|
|
41
|
+
assert_not_equal token, next_token
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_from_and_until
|
|
45
|
+
first_id = DCField.order("id asc").first.id
|
|
46
|
+
DCField.where("dc_fields.id < ?", first_id + 25).update_all(updated_at: Time.parse("September 15 2005"))
|
|
47
|
+
DCField.where(["dc_fields.id <= ? and dc_fields.id > ?", first_id + 50, first_id + 25]).update_all(updated_at: Time.parse("November 1 2005"))
|
|
48
|
+
|
|
49
|
+
total = DCField.where(["dc_fields.updated_at >= ? AND dc_fields.updated_at <= ?", Time.parse("September 1 2005"), Time.parse("November 30 2005")]).count
|
|
50
|
+
|
|
51
|
+
# Should return 50 records broken into 2 groups of 25.
|
|
52
|
+
doc = Document.new(
|
|
53
|
+
@provider.list_records(
|
|
54
|
+
:metadata_prefix => 'oai_dc',
|
|
55
|
+
:from => Time.parse("September 1 2005"),
|
|
56
|
+
:until => Time.parse("November 30 2005"))
|
|
57
|
+
)
|
|
58
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
59
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
60
|
+
token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
61
|
+
doc = Document.new(@provider.list_records(:resumption_token => token))
|
|
62
|
+
assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
|
|
63
|
+
assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
|
|
64
|
+
assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def setup
|
|
68
|
+
@provider = SimpleResumptionProvider.new
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require File.dirname(__FILE__) + '/config/connection'
|
|
5
|
+
require File.dirname(__FILE__) + '/helpers/providers'
|
|
6
|
+
require File.dirname(__FILE__) + '/helpers/set_provider'
|
|
7
|
+
require File.dirname(__FILE__) + '/helpers/transactional_test_case'
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'webrick'
|
|
2
|
+
require File.dirname(__FILE__) + '/../../provider/models'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ProviderServer
|
|
6
|
+
class ComplexClientProvider < OAI::Provider::Base
|
|
7
|
+
repository_name 'Complex Provider'
|
|
8
|
+
repository_url 'http://localhost'
|
|
9
|
+
record_prefix 'oai:test'
|
|
10
|
+
source_model ComplexModel.new(100)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :consumed, :server
|
|
14
|
+
|
|
15
|
+
def initialize(port, mount_point)
|
|
16
|
+
@consumed = []
|
|
17
|
+
@provider = ComplexClientProvider.new
|
|
18
|
+
@server = WEBrick::HTTPServer.new(
|
|
19
|
+
:BindAddress => '127.0.0.1',
|
|
20
|
+
:Logger => WEBrick::Log.new('/dev/null'),
|
|
21
|
+
:AccessLog => [],
|
|
22
|
+
:Port => port)
|
|
23
|
+
@server.mount_proc(mount_point, server_proc)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def port
|
|
27
|
+
@server.config[:Port]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def start
|
|
31
|
+
@thread = Thread.new { @server.start }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def stop
|
|
35
|
+
@thread.exit if @thread
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.wrap(port = 3333, mount_point='/oai')
|
|
39
|
+
server = self.new(port, mount_point)
|
|
40
|
+
begin
|
|
41
|
+
server.start
|
|
42
|
+
yield(server)
|
|
43
|
+
ensure
|
|
44
|
+
server.stop
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
protected
|
|
49
|
+
|
|
50
|
+
def server_proc
|
|
51
|
+
Proc.new do |req, res|
|
|
52
|
+
begin
|
|
53
|
+
res.body = @provider.process_request(req.query)
|
|
54
|
+
res.status = 200
|
|
55
|
+
res['Content-Type'] = 'text/xml'
|
|
56
|
+
rescue => err
|
|
57
|
+
puts err
|
|
58
|
+
puts err.backtrace.join("\n")
|
|
59
|
+
res.body = err.backtrace.join("\n")
|
|
60
|
+
res.status = 500
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
3
|
+
class ExceptionTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def test_not_found
|
|
6
|
+
client = OAI::Client.new 'http://www.google.com'
|
|
7
|
+
assert_raises(OAI::Exception) { client.identify }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_xml_error
|
|
11
|
+
client = OAI::Client.new 'http://www.yahoo.com'
|
|
12
|
+
begin
|
|
13
|
+
client.identify
|
|
14
|
+
rescue OAI::Exception => e
|
|
15
|
+
assert_match /response not well formed XML/, e.to_s, 'xml error'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_oai_error
|
|
20
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
21
|
+
assert_raises(OAI::ResumptionTokenException) do
|
|
22
|
+
client.list_identifiers :resumption_token => 'bogus'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# must pass in options as a hash
|
|
27
|
+
def test_parameter_error
|
|
28
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
29
|
+
assert_raises(OAI::ArgumentException) {client.get_record('foo')}
|
|
30
|
+
assert_raises(OAI::ArgumentException) {client.list_identifiers('foo')}
|
|
31
|
+
assert_raises(OAI::ArgumentException) {client.list_records('foo')}
|
|
32
|
+
assert_raises(OAI::ArgumentException) {client.list_metadata_formats('foo')}
|
|
33
|
+
assert_raises(OAI::ArgumentException) {client.list_sets('foo')}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
3
|
+
class GetRecordTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def test_get_one
|
|
6
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
7
|
+
response = client.get_record :identifier => 'oai:test:3'
|
|
8
|
+
assert_kind_of OAI::GetRecordResponse, response
|
|
9
|
+
assert_kind_of OAI::Record, response.record
|
|
10
|
+
assert_kind_of REXML::Element, response.record._source
|
|
11
|
+
assert_kind_of REXML::Element, response.record.metadata
|
|
12
|
+
assert_kind_of OAI::Header, response.record.header
|
|
13
|
+
assert_kind_of REXML::Element, response.record.about
|
|
14
|
+
|
|
15
|
+
# minimal check that the header is working
|
|
16
|
+
assert_equal 'oai:test:3', response.record.header.identifier
|
|
17
|
+
|
|
18
|
+
# minimal check that the metadata is working
|
|
19
|
+
#assert 'en', response.record.metadata.elements['.//dc:language'].text
|
|
20
|
+
assert_equal 'Ruby OAI test data', response.record.about.elements['.//dc:publisher'].text
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_missing_identifier
|
|
24
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
25
|
+
begin
|
|
26
|
+
client.get_record :metadata_prefix => 'oai_dc'
|
|
27
|
+
flunk 'invalid get_record did not throw OAI::Exception'
|
|
28
|
+
rescue OAI::ArgumentException => e
|
|
29
|
+
assert_match /The request includes illegal arguments/, e.to_s
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_deleted_record
|
|
34
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
35
|
+
record = client.get_record :identifier => 'oai:test:275'
|
|
36
|
+
assert record.deleted?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
require 'webrick'
|
|
3
|
+
|
|
4
|
+
class HttpClientTest < Test::Unit::TestCase
|
|
5
|
+
def test_user_agent_and_from_headers
|
|
6
|
+
faraday_stub = Faraday.new do |builder|
|
|
7
|
+
builder.adapter :test do |stub|
|
|
8
|
+
stub.get('/echo') { |env| [200, {}, Marshal.dump(env)] }
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
client = OAI::Client.new 'http://localhost:3333/oai', :headers => { 'From' => 'oai@example.com', 'User-Agent' => 'ruby-oai' }, :http => faraday_stub
|
|
13
|
+
|
|
14
|
+
response = client.send(:get, '/echo')
|
|
15
|
+
env = Marshal.load(response)
|
|
16
|
+
|
|
17
|
+
assert_equal('oai@example.com', env.request_headers['From'])
|
|
18
|
+
assert_equal('ruby-oai', env.request_headers['User-Agent'])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_pluggable_http_client
|
|
22
|
+
oai_response = <<-eos
|
|
23
|
+
<Identify>
|
|
24
|
+
<repositoryName>Mock OAI Provider</repositoryName>
|
|
25
|
+
<baseURL>http://nowhere.example.com</baseURL>
|
|
26
|
+
</Identify>
|
|
27
|
+
eos
|
|
28
|
+
|
|
29
|
+
faraday_stub = Faraday.new do |builder|
|
|
30
|
+
builder.adapter :test do |stub|
|
|
31
|
+
stub.get('/oai?verb=Identify') { [200, {}, oai_response] }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
client = OAI::Client.new 'http://localhost:3333/oai', :http => faraday_stub
|
|
35
|
+
response = client.identify
|
|
36
|
+
|
|
37
|
+
assert_kind_of OAI::IdentifyResponse, response
|
|
38
|
+
assert_equal 'Mock OAI Provider [http://nowhere.example.com]', response.to_s
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_http_client_handles_trailing_slash_redirects
|
|
43
|
+
# First, test that this works when mocking out Faraday client
|
|
44
|
+
oai_response = <<-eos
|
|
45
|
+
<Identify>
|
|
46
|
+
<repositoryName>Mock OAI Provider</repositoryName>
|
|
47
|
+
<baseURL>http://nowhere.example.com</baseURL>
|
|
48
|
+
</Identify>
|
|
49
|
+
eos
|
|
50
|
+
|
|
51
|
+
stubs = TrailingSlashAwareStubs.new do |stub|
|
|
52
|
+
stub.get('/oai/?verb=Identify') { [200, {}, oai_response] }
|
|
53
|
+
stub.get('/oai?verb=Identify') {
|
|
54
|
+
[301, {
|
|
55
|
+
'Location' => 'http://localhost:3334/oai/?verb=Identify'
|
|
56
|
+
}, '']
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
faraday_stub = Faraday.new do |builder|
|
|
61
|
+
require 'faraday/follow_redirects'
|
|
62
|
+
builder.use Faraday::FollowRedirects::Middleware
|
|
63
|
+
builder.adapter :test, stubs
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
client = OAI::Client.new 'http://localhost:3334/oai', :http => faraday_stub
|
|
67
|
+
response = client.identify
|
|
68
|
+
|
|
69
|
+
assert_kind_of OAI::IdentifyResponse, response
|
|
70
|
+
assert_equal 'Mock OAI Provider [http://nowhere.example.com]', response.to_s
|
|
71
|
+
assert_equal 2, stubs.consumed[:get].length
|
|
72
|
+
assert_equal stubs.consumed[:get].first.path, '/oai'
|
|
73
|
+
assert_equal stubs.consumed[:get].last.path, '/oai/'
|
|
74
|
+
|
|
75
|
+
# Now try it with a real server and default Faraday client
|
|
76
|
+
TrailingSlashProviderServer.wrap(3334) do |server|
|
|
77
|
+
client = OAI::Client.new "http://localhost:#{server.port}/oai"
|
|
78
|
+
response = client.identify
|
|
79
|
+
|
|
80
|
+
assert_kind_of OAI::IdentifyResponse, response
|
|
81
|
+
assert_equal 'Complex Provider [http://localhost]', response.to_s
|
|
82
|
+
assert_equal 2, server.consumed.length
|
|
83
|
+
assert_equal server.consumed.first.path, '/oai'
|
|
84
|
+
assert_equal server.consumed.last.path, '/oai/'
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
class TrailingSlashProviderServer < ProviderServer
|
|
91
|
+
def server_proc
|
|
92
|
+
Proc.new do |req, res|
|
|
93
|
+
@consumed << req
|
|
94
|
+
case req.path
|
|
95
|
+
when "/oai/"
|
|
96
|
+
begin
|
|
97
|
+
res.body = @provider.process_request(req.query)
|
|
98
|
+
res.status = 200
|
|
99
|
+
res['Content-Type'] = 'text/xml'
|
|
100
|
+
rescue => err
|
|
101
|
+
puts err
|
|
102
|
+
puts err.backtrace.join("\n")
|
|
103
|
+
res.body = err.backtrace.join("\n")
|
|
104
|
+
res.status = 500
|
|
105
|
+
end
|
|
106
|
+
else
|
|
107
|
+
res.body = ''
|
|
108
|
+
res.status = 301
|
|
109
|
+
res['Location'] = "http://localhost:#{port}/oai/?#{req.query_string}"
|
|
110
|
+
end
|
|
111
|
+
res
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
class TrailingSlashAwareStubs < Faraday::Adapter::Test::Stubs
|
|
117
|
+
attr_reader :consumed
|
|
118
|
+
|
|
119
|
+
# ensure leading, but not trailing slash
|
|
120
|
+
def normalize_path(path)
|
|
121
|
+
path = '/' + path if path.index('/') != 0
|
|
122
|
+
#path = path.sub('?', '/?')
|
|
123
|
+
#path = path + '/' unless $&
|
|
124
|
+
path.gsub('//', '/')
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
3
|
+
class IdentifyTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def test_ok
|
|
6
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
7
|
+
response = client.identify
|
|
8
|
+
assert_kind_of OAI::IdentifyResponse, response
|
|
9
|
+
assert_equal 'Complex Provider [http://localhost]', response.to_s
|
|
10
|
+
#assert_equal 'PubMed Central (PMC3 - NLM DTD) [http://www.pubmedcentral.gov/oai/oai.cgi]', response.to_s
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
3
|
+
class LibXMLTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def test_oai_exception
|
|
6
|
+
return unless have_libxml
|
|
7
|
+
|
|
8
|
+
uri = 'http://localhost:3333/oai'
|
|
9
|
+
client = OAI::Client.new uri, :parser => 'libxml'
|
|
10
|
+
assert_raises(OAI::IdException) {client.get_record(:identifier => 'nosuchid')}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_list_records
|
|
14
|
+
return unless have_libxml
|
|
15
|
+
|
|
16
|
+
# since there is regex magic going on to remove default oai namespaces
|
|
17
|
+
# it's worth trying a few different oai targets
|
|
18
|
+
oai_targets = %w{
|
|
19
|
+
http://localhost:3333/oai
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#oai_targets = %w{
|
|
23
|
+
# http://etd.caltech.edu:80/ETD-db/OAI/oai
|
|
24
|
+
# http://ir.library.oregonstate.edu/dspace-oai/request
|
|
25
|
+
# http://memory.loc.gov/cgi-bin/oai2_0
|
|
26
|
+
# http://libeprints.open.ac.uk/perl/oai2
|
|
27
|
+
#}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
oai_targets.each do |uri|
|
|
31
|
+
client = OAI::Client.new uri, :parser => 'libxml'
|
|
32
|
+
records = client.list_records
|
|
33
|
+
records.each do |record|
|
|
34
|
+
assert record.header.identifier
|
|
35
|
+
next if record.deleted?
|
|
36
|
+
assert_kind_of LibXML::XML::Node, record.metadata
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_deleted_record
|
|
42
|
+
return unless have_libxml
|
|
43
|
+
|
|
44
|
+
uri = 'http://localhost:3333/oai'
|
|
45
|
+
client = OAI::Client.new(uri, :parser => 'libxml')
|
|
46
|
+
response = client.get_record :identifier => 'oai:test:275'
|
|
47
|
+
assert response.record.deleted?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def have_libxml
|
|
53
|
+
begin
|
|
54
|
+
require 'xml/libxml'
|
|
55
|
+
return true
|
|
56
|
+
rescue LoadError
|
|
57
|
+
return false
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'test_helper_client'
|
|
2
2
|
|
|
3
3
|
class ListIdentifiersTest < Test::Unit::TestCase
|
|
4
4
|
|
|
5
5
|
def test_list_with_resumption_token
|
|
6
|
-
client = OAI::Client.new 'http://
|
|
6
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
7
7
|
|
|
8
8
|
# get a list of identifier headers
|
|
9
|
-
response = client.list_identifiers :metadata_prefix => 'oai_dc'
|
|
9
|
+
response = client.list_identifiers :metadata_prefix => 'oai_dc'
|
|
10
10
|
assert_kind_of OAI::ListIdentifiersResponse, response
|
|
11
11
|
assert_kind_of OAI::Response, response
|
|
12
12
|
assert response.entries.size > 0
|
|
@@ -27,17 +27,36 @@ class ListIdentifiersTest < Test::Unit::TestCase
|
|
|
27
27
|
assert_not_equal response.entries[0].identifier, first_identifier
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def test_list_full
|
|
31
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
32
|
+
|
|
33
|
+
# get a list of identifier headers
|
|
34
|
+
response = client.list_identifiers :metadata_prefix => 'oai_dc'
|
|
35
|
+
assert_kind_of OAI::ListIdentifiersResponse, response
|
|
36
|
+
assert_kind_of OAI::Response, response
|
|
37
|
+
assert response.respond_to?(:full), "Should expose :full"
|
|
38
|
+
|
|
39
|
+
# Check that it runs through the pages
|
|
40
|
+
assert_equal 1150, response.full.count
|
|
41
|
+
response.full.each do |header|
|
|
42
|
+
assert_kind_of OAI::Header, header
|
|
43
|
+
assert header.identifier
|
|
44
|
+
assert header.datestamp
|
|
45
|
+
assert header.set_spec
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
30
49
|
def test_list_with_date_range
|
|
31
|
-
client = OAI::Client.new 'http://
|
|
32
|
-
from_date = Date.new(
|
|
33
|
-
until_date = Date.new(
|
|
50
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
51
|
+
from_date = Date.new(1998,1,1)
|
|
52
|
+
until_date = Date.new(2002,1,1)
|
|
34
53
|
response = client.list_identifiers :from => from_date, :until => until_date
|
|
35
54
|
assert response.entries.size > 0
|
|
36
55
|
end
|
|
37
56
|
|
|
38
57
|
def test_list_with_datetime_range
|
|
39
58
|
# xtcat should support higher granularity
|
|
40
|
-
client = OAI::Client.new 'http://
|
|
59
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
41
60
|
from_date = DateTime.new(2001,1,1)
|
|
42
61
|
until_date = DateTime.now
|
|
43
62
|
response = client.list_identifiers :from => from_date, :until => until_date
|
|
@@ -45,8 +64,8 @@ class ListIdentifiersTest < Test::Unit::TestCase
|
|
|
45
64
|
end
|
|
46
65
|
|
|
47
66
|
def test_invalid_argument
|
|
48
|
-
client = OAI::Client.new 'http://
|
|
49
|
-
assert_raise(OAI::
|
|
67
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
68
|
+
assert_raise(OAI::ArgumentException) {client.list_identifiers :foo => 'bar'}
|
|
50
69
|
end
|
|
51
70
|
|
|
52
71
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
1
3
|
class ListMetadataFormatsTest < Test::Unit::TestCase
|
|
2
4
|
def test_list
|
|
3
|
-
client = OAI::Client.new 'http://
|
|
5
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
4
6
|
response = client.list_metadata_formats
|
|
5
7
|
assert_kind_of OAI::ListMetadataFormatsResponse, response
|
|
6
8
|
assert response.entries.size > 0
|
|
@@ -11,5 +13,6 @@ class ListMetadataFormatsTest < Test::Unit::TestCase
|
|
|
11
13
|
assert_equal 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd', format.schema
|
|
12
14
|
assert_equal 'http://www.openarchives.org/OAI/2.0/oai_dc/', format.namespace
|
|
13
15
|
end
|
|
16
|
+
|
|
14
17
|
end
|
|
15
18
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
3
|
+
class ListRecordsTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def test_list
|
|
6
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
7
|
+
response = client.list_records
|
|
8
|
+
assert_kind_of OAI::ListRecordsResponse, response
|
|
9
|
+
assert response.entries.size > 0
|
|
10
|
+
assert_kind_of OAI::Record, response.entries[0]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_list_full
|
|
14
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
15
|
+
|
|
16
|
+
response = client.list_records
|
|
17
|
+
assert_kind_of OAI::ListRecordsResponse, response
|
|
18
|
+
|
|
19
|
+
# Check that it runs through the pages
|
|
20
|
+
assert_equal 1150, response.full.count
|
|
21
|
+
response.full.each do |record|
|
|
22
|
+
assert_kind_of OAI::Record, record
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
3
|
+
class ListSetsTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def test_list
|
|
6
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
7
|
+
response = client.list_sets
|
|
8
|
+
assert_kind_of OAI::ListSetsResponse, response
|
|
9
|
+
assert response.entries.size > 0
|
|
10
|
+
assert_kind_of OAI::Set, response.entries[0]
|
|
11
|
+
|
|
12
|
+
# test iterator
|
|
13
|
+
for set in response
|
|
14
|
+
assert_kind_of OAI::Set, set
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_list_full
|
|
19
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
20
|
+
|
|
21
|
+
response = client.list_sets
|
|
22
|
+
assert_kind_of OAI::ListSetsResponse, response
|
|
23
|
+
assert_kind_of OAI::Response, response
|
|
24
|
+
assert response.respond_to?(:full), "Should expose :full"
|
|
25
|
+
|
|
26
|
+
# This won't page, but it should work anyway
|
|
27
|
+
assert_equal 6, response.full.count
|
|
28
|
+
response.full.each do |set|
|
|
29
|
+
assert_kind_of OAI::Set, set
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
3
|
+
class LowResolutionDatesTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
def test_low_res_date_parsing
|
|
6
|
+
client = OAI::Client.new 'http://localhost:3333/oai'
|
|
7
|
+
|
|
8
|
+
date = Date.new 2003, 1, 1
|
|
9
|
+
|
|
10
|
+
# get a list of identifier headers
|
|
11
|
+
assert_nothing_raised { client.list_identifiers :from => date }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
3
|
+
class UTF8Test < Test::Unit::TestCase
|
|
4
|
+
def client
|
|
5
|
+
@client ||= OAI::Client.new 'http://localhost:3333/oai'
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def test_escaping_invalid_utf_8_characters
|
|
9
|
+
invalid_utf_8 = [2, 3, 4, 104, 5, 101, 6, 108, 66897, 108, 66535, 111, 1114112, 33, 55234123, 33].pack("U*")
|
|
10
|
+
invalid_utf_8 = invalid_utf_8.force_encoding("binary") if invalid_utf_8.respond_to? :force_encoding
|
|
11
|
+
assert_equal("hello!!", client.send(:strip_invalid_utf_8_chars, invalid_utf_8).gsub(/\?/, ''))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_unescaped_ampersand_content_correction
|
|
15
|
+
src = '<test>Frankie & Johnny <character>♥</character></test>'
|
|
16
|
+
expected = '<test>Frankie & Johnny <character>♥</character></test>'
|
|
17
|
+
assert_equal(expected, client.sanitize_xml(src))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'test_helper_client'
|
|
2
|
+
|
|
3
|
+
class XpathTest < Test::Unit::TestCase
|
|
4
|
+
include OAI::XPath
|
|
5
|
+
|
|
6
|
+
def test_rexml
|
|
7
|
+
require 'rexml/document'
|
|
8
|
+
doc = REXML::Document.new(File.new('test/test.xml'))
|
|
9
|
+
assert_equal xpath(doc, './/responseDate'), '2006-09-11T14:33:15Z'
|
|
10
|
+
assert_equal xpath(doc, './/foobar'), nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_libxml
|
|
14
|
+
begin
|
|
15
|
+
require 'xml/libxml'
|
|
16
|
+
rescue LoadError
|
|
17
|
+
# libxml not available so nothing to test!
|
|
18
|
+
return
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
doc = LibXML::XML::Document.file('test/test.xml')
|
|
22
|
+
assert_equal xpath(doc, './/responseDate'), '2006-09-11T14:33:15Z'
|
|
23
|
+
assert_equal xpath(doc, './/foobar'), nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|