oai 1.1.0 → 1.2.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -4
  3. data/Rakefile +7 -0
  4. data/bin/oai +0 -2
  5. data/examples/models/file_model.rb +2 -2
  6. data/lib/oai/client/response.rb +8 -8
  7. data/lib/oai/client.rb +34 -10
  8. data/lib/oai/exception.rb +46 -38
  9. data/lib/oai/harvester/config.rb +1 -1
  10. data/lib/oai/harvester/harvest.rb +37 -25
  11. data/lib/oai/harvester/logging.rb +3 -5
  12. data/lib/oai/harvester.rb +4 -1
  13. data/lib/oai/provider/model/activerecord_caching_wrapper.rb +5 -8
  14. data/lib/oai/provider/model/activerecord_wrapper.rb +38 -22
  15. data/lib/oai/provider/model.rb +1 -1
  16. data/lib/oai/provider/response/list_records.rb +12 -0
  17. data/lib/oai/provider/response.rb +7 -4
  18. data/lib/oai/provider/resumption_token.rb +18 -5
  19. data/test/activerecord_provider/database/0001_oaipmh_tables.rb +7 -1
  20. data/test/activerecord_provider/helpers/providers.rb +3 -1
  21. data/test/activerecord_provider/helpers/transactional_test_case.rb +2 -1
  22. data/test/activerecord_provider/models/dc_field.rb +8 -0
  23. data/test/activerecord_provider/models/dc_lang.rb +3 -0
  24. data/test/activerecord_provider/models/exclusive_set_dc_field.rb +6 -0
  25. data/test/activerecord_provider/tc_activerecord_wrapper.rb +63 -0
  26. data/test/activerecord_provider/tc_ar_provider.rb +54 -26
  27. data/test/activerecord_provider/tc_ar_sets_provider.rb +10 -9
  28. data/test/activerecord_provider/tc_caching_paging_provider.rb +9 -7
  29. data/test/activerecord_provider/tc_simple_paging_provider.rb +9 -7
  30. data/test/client/tc_exception.rb +1 -1
  31. data/test/client/tc_get_record.rb +1 -1
  32. data/test/client/tc_http_client.rb +2 -2
  33. data/test/client/tc_libxml.rb +1 -1
  34. data/test/client/tc_utf8_escaping.rb +8 -1
  35. data/test/harvester/tc_harvest.rb +42 -0
  36. data/test/harvester/test_helper_harvester.rb +6 -0
  37. data/test/provider/models.rb +3 -3
  38. data/test/provider/tc_functional_tokens.rb +17 -11
  39. data/test/provider/tc_provider.rb +26 -0
  40. metadata +27 -16
@@ -29,7 +29,7 @@ module OAI::Provider
29
29
  # see the ResumptionToken class for more details.
30
30
  #
31
31
  class Model
32
- attr_reader :timestamp_field, :identifier_field
32
+ attr_reader :timestamp_field, :identifier_field, :limit
33
33
 
34
34
  def initialize(limit = nil, timestamp_field = 'updated_at', identifier_field = 'id')
35
35
  @limit = limit
@@ -2,6 +2,18 @@ module OAI::Provider::Response
2
2
 
3
3
  class ListRecords < RecordResponse
4
4
  required_parameters :metadata_prefix
5
+
6
+ def valid?
7
+ super && matching_granularity?
8
+ end
9
+
10
+ def matching_granularity?
11
+ if options[:from].nil? == false && options[:until].nil? == false && options[:from].class.name != options[:until].class.name
12
+ raise OAI::ArgumentException.new, "The 'from' and 'until' options specified must have the same granularity"
13
+ else
14
+ true
15
+ end
16
+ end
5
17
 
6
18
  def to_xml
7
19
  result = provider.model.find(:all, options)
@@ -90,10 +90,13 @@ module OAI
90
90
 
91
91
  def parse_date(value)
92
92
  return value if value.respond_to?(:strftime)
93
-
94
- Date.parse(value) # This will raise an exception for badly formatted dates
95
- Time.parse(value).utc # -- UTC Bug fix hack 8/08 not in core
96
- rescue
93
+
94
+ if value[-1] == "Z"
95
+ Time.strptime(value, "%Y-%m-%dT%H:%M:%S%Z").utc
96
+ else
97
+ Date.strptime(value, "%Y-%m-%d")
98
+ end
99
+ rescue ArgumentError => e
97
100
  raise OAI::ArgumentException.new, "unparsable date: '#{value}'"
98
101
  end
99
102
 
@@ -1,5 +1,4 @@
1
1
  require 'time'
2
- require 'enumerator'
3
2
  require File.dirname(__FILE__) + "/partial_result"
4
3
 
5
4
  module OAI::Provider
@@ -37,7 +36,7 @@ module OAI::Provider
37
36
  attr_reader :prefix, :set, :from, :until, :last, :last_str, :expiration, :total
38
37
 
39
38
  # parses a token string and returns a ResumptionToken
40
- def self.parse(token_string)
39
+ def self.parse(token_string, expiration = nil, total = nil)
41
40
  begin
42
41
  options = {}
43
42
  matches = /(.+):([^ :]+)$/.match(token_string)
@@ -55,7 +54,7 @@ module OAI::Provider
55
54
  options[:until] = Time.parse(part.sub(/^u\(/, '').sub(/\)$/, '')).localtime
56
55
  end
57
56
  end
58
- self.new(options)
57
+ self.new(options, expiration, total)
59
58
  rescue => err
60
59
  raise OAI::ResumptionTokenException.new
61
60
  end
@@ -123,10 +122,24 @@ module OAI::Provider
123
122
  end
124
123
 
125
124
  def encode_conditions
125
+ return "" if last_str.nil? || last_str.to_s.strip.eql?("")
126
+
126
127
  encoded_token = @prefix.to_s.dup
127
128
  encoded_token << ".s(#{set})" if set
128
- encoded_token << ".f(#{self.from.utc.xmlschema})" if self.from
129
- encoded_token << ".u(#{self.until.utc.xmlschema})" if self.until
129
+ if self.from
130
+ if self.from.respond_to?(:utc)
131
+ encoded_token << ".f(#{self.from.utc.xmlschema})"
132
+ else
133
+ encoded_token << ".f(#{self.from.xmlschema})"
134
+ end
135
+ end
136
+ if self.until
137
+ if self.until.respond_to?(:utc)
138
+ encoded_token << ".u(#{self.until.utc.xmlschema})"
139
+ else
140
+ encoded_token << ".u(#{self.until.xmlschema})"
141
+ end
142
+ end
130
143
  encoded_token << ":#{last_str}"
131
144
  end
132
145
 
@@ -10,6 +10,12 @@ class OaipmhTables < ActiveRecord::Migration[5.2]
10
10
  t.column :oai_token_id, :integer, :null => false
11
11
  end
12
12
 
13
+ create_table :dc_langs do |t|
14
+ t.column :name, :string
15
+ t.column :updated_at, :datetime
16
+ t.column :created_at, :datetime
17
+ end
18
+
13
19
  dc_fields = proc do |t|
14
20
  t.column :title, :string
15
21
  t.column :creator, :string
@@ -21,7 +27,7 @@ class OaipmhTables < ActiveRecord::Migration[5.2]
21
27
  t.column :type, :string
22
28
  t.column :format, :string
23
29
  t.column :source, :string
24
- t.column :language, :string
30
+ t.column :dc_lang_id, :integer
25
31
  t.column :relation, :string
26
32
  t.column :coverage, :string
27
33
  t.column :rights, :string
@@ -56,11 +56,13 @@ class ARLoader
56
56
  File.join(File.dirname(__FILE__), '..', 'fixtures', 'dc.yml')
57
57
  )
58
58
  fixtures.keys.sort.each do |key|
59
- DCField.create(fixtures[key])
59
+ lang = DCLang.create(name: fixtures[key].delete('language'))
60
+ DCField.create(fixtures[key].merge(dc_lang: lang))
60
61
  end
61
62
  end
62
63
 
63
64
  def self.unload
64
65
  DCField.delete_all
66
+ DCLang.delete_all
65
67
  end
66
68
  end
@@ -19,7 +19,8 @@ class TransactionalTestCase < Test::Unit::TestCase
19
19
  )
20
20
  disable_logging do
21
21
  fixtures.keys.sort.each do |key|
22
- DCField.create(fixtures[key])
22
+ lang = DCLang.create(name: fixtures[key].delete('language'))
23
+ DCField.create(fixtures[key].merge(dc_lang: lang))
23
24
  end
24
25
  end
25
26
  end
@@ -4,4 +4,12 @@ class DCField < ActiveRecord::Base
4
4
  :join_table => "dc_fields_dc_sets",
5
5
  :foreign_key => "dc_field_id",
6
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
7
15
  end
@@ -0,0 +1,3 @@
1
+ class DCLang < ActiveRecord::Base
2
+ has_many :dc_fields
3
+ end
@@ -8,4 +8,10 @@ class ExclusiveSetDCField < ActiveRecord::Base
8
8
  end
9
9
  end
10
10
 
11
+ belongs_to :dc_lang, class_name: "DCLang", optional: true
12
+
13
+ def language
14
+ dc_lang&.name
15
+ end
16
+
11
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
+
@@ -81,30 +81,30 @@ class ActiveRecordProviderTest < TransactionalTestCase
81
81
 
82
82
  def test_from
83
83
  first_id = DCField.order("id asc").first.id
84
- DCField.where("id < #{first_id + 90}").update_all(updated_at: Time.parse("January 1 2005"))
84
+ DCField.where("dc_fields.id < #{first_id + 90}").update_all(updated_at: Time.parse("January 1 2005"))
85
85
 
86
- DCField.where("id < #{first_id + 10}").update_all(updated_at: Time.parse("June 1 2005"))
86
+ DCField.where("dc_fields.id < #{first_id + 10}").update_all(updated_at: Time.parse("June 1 2005"))
87
87
 
88
88
 
89
- from_param = Time.parse("January 1 2006")
89
+ from_param = Time.parse("January 1 2006").getutc.iso8601
90
90
 
91
91
  doc = REXML::Document.new(
92
92
  @provider.list_records(
93
93
  :metadata_prefix => 'oai_dc', :from => from_param)
94
94
  )
95
- assert_equal DCField.where(["updated_at >= ?", from_param]).size,
95
+ assert_equal DCField.where(["dc_fields.updated_at >= ?", from_param]).size,
96
96
  doc.elements['OAI-PMH/ListRecords'].size
97
97
 
98
98
  doc = REXML::Document.new(
99
99
  @provider.list_records(
100
- :metadata_prefix => 'oai_dc', :from => Time.parse("May 30 2005"))
100
+ :metadata_prefix => 'oai_dc', :from => Time.parse("May 30 2005").getutc.iso8601)
101
101
  )
102
102
  assert_equal 20, doc.elements['OAI-PMH/ListRecords'].to_a.size
103
103
  end
104
104
 
105
105
  def test_until
106
- first_id = DCField.order("id asc").first.id
107
- DCField.where("id < #{first_id + 10}").update_all(updated_at: Time.parse("June 1 2005"))
106
+ first_id = DCField.order(id: :asc).first.id
107
+ DCField.where("dc_fields.id < ?", first_id + 10).update_all(updated_at: Time.parse("June 1 2005"))
108
108
 
109
109
  doc = REXML::Document.new(
110
110
  @provider.list_records(
@@ -114,19 +114,46 @@ class ActiveRecordProviderTest < TransactionalTestCase
114
114
  end
115
115
 
116
116
  def test_from_and_until
117
- first_id = DCField.order("id asc").first.id
117
+ first_id = DCField.order(id: :asc).first.id
118
118
  DCField.update_all(updated_at: Time.parse("June 1 2005"))
119
- DCField.where("id < #{first_id + 50}").update_all(updated_at: Time.parse("June 15 2005"))
120
- DCField.where("id < #{first_id + 10}").update_all(updated_at: Time.parse("June 30 2005"))
119
+ DCField.where("dc_fields.id < ?", first_id + 50).update_all(updated_at: Time.parse("June 15 2005"))
120
+ DCField.where("dc_fields.id < ?", first_id + 10).update_all(updated_at: Time.parse("June 30 2005"))
121
121
 
122
122
  doc = REXML::Document.new(
123
123
  @provider.list_records(
124
124
  :metadata_prefix => 'oai_dc',
125
- :from => Time.parse("June 3 2005"),
126
- :until => Time.parse("June 16 2005"))
125
+ :from => Time.parse("June 3 2005").getutc.iso8601,
126
+ :until => Time.parse("June 16 2005").getutc.iso8601)
127
127
  )
128
128
  assert_equal 40, doc.elements['OAI-PMH/ListRecords'].to_a.size
129
129
  end
130
+
131
+ def test_bad_until_raises_exception
132
+ DCField.order(id: :asc).limit(10).update_all(updated_at: 1.year.ago)
133
+ DCField.order(id: :desc).limit(10).update_all(updated_at: 1.year.from_now)
134
+ badTimes = [
135
+ 'junk',
136
+ 'February 92nd, 2015']
137
+ badTimes.each do |time|
138
+ assert_raise(OAI::ArgumentException) do
139
+ @provider.list_records(:metadata_prefix => 'oai_dc', :until => time)
140
+ end
141
+ end
142
+ end
143
+
144
+ def test_bad_from_raises_exception
145
+ DCField.order(id: :asc).limit(10).update_all(updated_at: 1.year.ago)
146
+ DCField.order(id: :desc).limit(10).update_all(updated_at: 1.year.from_now)
147
+
148
+ badTimes = [
149
+ 'junk',
150
+ 'February 92nd, 2015']
151
+ badTimes.each do |time|
152
+ assert_raise(OAI::ArgumentException) do
153
+ @provider.list_records(:metadata_prefix => 'oai_dc', :from => time)
154
+ end
155
+ end
156
+ end
130
157
 
131
158
  def test_handles_empty_collections
132
159
  DCField.delete_all
@@ -142,6 +169,21 @@ class ActiveRecordProviderTest < TransactionalTestCase
142
169
  REXML::Document.new(@provider.list_records(:metadata_prefix => 'oai_dc'))
143
170
  end
144
171
  end
172
+
173
+ def test_bad_id_raises_exception
174
+ badIdentifiers = [
175
+ 'invalid"id',
176
+ 'oai:test/5000',
177
+ 'oai:test/-1',
178
+ 'oai:test/one',
179
+ 'oai:test/\\$1\1!']
180
+ badIdentifiers.each do |id|
181
+ assert_raise(OAI::IdException) do
182
+ @provider.get_record(:identifier => id, :metadata_prefix => 'oai_dc')
183
+ end
184
+ end
185
+ end
186
+
145
187
 
146
188
  def setup
147
189
  @provider = ARProvider.new
@@ -149,18 +191,4 @@ class ActiveRecordProviderTest < TransactionalTestCase
149
191
 
150
192
  end
151
193
 
152
- class ActiveRecordProviderTimezoneTest < ActiveRecordProviderTest
153
-
154
- def setup
155
- require 'active_record'
156
- ActiveRecord::Base.default_timezone = :utc
157
- super
158
- end
159
194
 
160
- def teardown
161
- require 'active_record'
162
- ActiveRecord::Base.default_timezone = :local
163
- super
164
- end
165
-
166
- end
@@ -51,22 +51,22 @@ class ActiveRecordSetProviderTest < TransactionalTestCase
51
51
  set_ab = DCSet.create(:name => "Set A:B", :spec => "A:B")
52
52
 
53
53
  next_id = 0
54
- DCField.limit(10).order("id asc").each do |record|
54
+ DCField.limit(10).order(id: :asc).each do |record|
55
55
  set_a.dc_fields << record
56
56
  next_id = record.id
57
57
  end
58
58
 
59
- DCField.where("id > #{next_id}").limit(10).order("id asc").each do |record|
59
+ DCField.where("dc_fields.id > ?", next_id).limit(10).order(id: :asc).each do |record|
60
60
  set_b.dc_fields << record
61
61
  next_id = record.id
62
62
  end
63
63
 
64
- DCField.where("id > #{next_id}").limit(10).order("id asc").each do |record|
64
+ DCField.where("dc_fields.id > ?", next_id).limit(10).order(id: :asc).each do |record|
65
65
  set_ab.dc_fields << record
66
66
  next_id = record.id
67
67
  end
68
68
 
69
- DCField.where("id > #{next_id}").limit(10).order("id asc").each do |record|
69
+ DCField.where("dc_fields.id > ?", next_id).limit(10).order(id: :asc).each do |record|
70
70
  set_a.dc_fields << record
71
71
  set_c.dc_fields << record
72
72
  next_id = record.id
@@ -117,25 +117,25 @@ class ActiveRecordExclusiveSetsProviderTest < TransactionalTestCase
117
117
  def define_sets
118
118
  next_id = 0
119
119
 
120
- ExclusiveSetDCField.limit(10).order("id asc").each do |record|
120
+ ExclusiveSetDCField.limit(10).order(id: :asc).each do |record|
121
121
  record.set = "A"
122
122
  record.save!
123
123
  next_id = record.id
124
124
  end
125
125
 
126
- ExclusiveSetDCField.where("id > #{next_id}").limit(10).order("id asc").each do |record|
126
+ ExclusiveSetDCField.where("id > ?", next_id).limit(10).order(id: :asc).each do |record|
127
127
  record.set = "B"
128
128
  record.save!
129
129
  next_id = record.id
130
130
  end
131
131
 
132
- ExclusiveSetDCField.where("id > #{next_id}").limit(10).order("id asc").each do |record|
132
+ ExclusiveSetDCField.where("id > ?", next_id).limit(10).order(id: :asc).each do |record|
133
133
  record.set = "A:B"
134
134
  record.save!
135
135
  next_id = record.id
136
136
  end
137
137
 
138
- ExclusiveSetDCField.where("id > #{next_id}").limit(10).order("id asc").each do |record|
138
+ ExclusiveSetDCField.where("id > ?", next_id).limit(10).order(id: :asc).each do |record|
139
139
  record.set = "A"
140
140
  record.save!
141
141
  next_id = record.id
@@ -150,7 +150,8 @@ class ActiveRecordExclusiveSetsProviderTest < TransactionalTestCase
150
150
  )
151
151
  disable_logging do
152
152
  fixtures.keys.sort.each do |key|
153
- ExclusiveSetDCField.create(fixtures[key])
153
+ lang = DCLang.create(name: fixtures[key].delete('language'))
154
+ ExclusiveSetDCField.create(fixtures[key].merge(dc_lang: lang))
154
155
  end
155
156
  end
156
157
  end
@@ -17,14 +17,15 @@ class CachingPagingProviderTest < TransactionalTestCase
17
17
  token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
18
18
  assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].size
19
19
  doc = Document.new(@provider.list_records(:resumption_token => token))
20
- assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
21
- assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].size
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
22
23
  end
23
24
 
24
25
  def test_from_and_until
25
- first_id = DCField.order("id asc").first.id
26
- DCField.where("id <= #{first_id + 25}").update_all(updated_at: Time.parse("September 15 2005"))
27
- DCField.where("id < #{first_id + 50} and id > #{first_id + 25}").update_all(updated_at: Time.parse("November 1 2005"))
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"))
28
29
 
29
30
  # Should return 50 records broken into 2 groups of 25.
30
31
  doc = Document.new(
@@ -37,8 +38,9 @@ class CachingPagingProviderTest < TransactionalTestCase
37
38
  token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
38
39
  assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
39
40
  doc = Document.new(@provider.list_records(:resumption_token => token))
40
- assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].size
41
- assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
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
42
44
  end
43
45
 
44
46
  def setup
@@ -20,8 +20,9 @@ class SimpleResumptionProviderTest < TransactionalTestCase
20
20
  assert_equal 26, doc.elements["/OAI-PMH/ListRecords"].to_a.size
21
21
 
22
22
  doc = Document.new(@provider.list_records(:resumption_token => token))
23
- assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
24
- assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].to_a.size
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
25
26
  end
26
27
 
27
28
  def test_non_integer_identifiers_resumption
@@ -42,10 +43,10 @@ class SimpleResumptionProviderTest < TransactionalTestCase
42
43
 
43
44
  def test_from_and_until
44
45
  first_id = DCField.order("id asc").first.id
45
- DCField.where("id < #{first_id + 25}").update_all(updated_at: Time.parse("September 15 2005"))
46
- DCField.where("id <= #{first_id + 50} and id > #{first_id + 25}").update_all(updated_at: Time.parse("November 1 2005"))
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"))
47
48
 
48
- total = DCField.where(["updated_at >= ? AND updated_at <= ?", Time.parse("September 1 2005"), Time.parse("November 30 2005")]).count
49
+ total = DCField.where(["dc_fields.updated_at >= ? AND dc_fields.updated_at <= ?", Time.parse("September 1 2005"), Time.parse("November 30 2005")]).count
49
50
 
50
51
  # Should return 50 records broken into 2 groups of 25.
51
52
  doc = Document.new(
@@ -58,8 +59,9 @@ class SimpleResumptionProviderTest < TransactionalTestCase
58
59
  assert_not_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
59
60
  token = doc.elements["/OAI-PMH/ListRecords/resumptionToken"].text
60
61
  doc = Document.new(@provider.list_records(:resumption_token => token))
61
- assert_equal 25, doc.elements["/OAI-PMH/ListRecords"].to_a.size
62
- assert_nil doc.elements["/OAI-PMH/ListRecords/resumptionToken"]
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
63
65
  end
64
66
 
65
67
  def setup
@@ -18,7 +18,7 @@ class ExceptionTest < Test::Unit::TestCase
18
18
 
19
19
  def test_oai_error
20
20
  client = OAI::Client.new 'http://localhost:3333/oai'
21
- assert_raises(OAI::Exception) do
21
+ assert_raises(OAI::ResumptionTokenException) do
22
22
  client.list_identifiers :resumption_token => 'bogus'
23
23
  end
24
24
  end
@@ -25,7 +25,7 @@ class GetRecordTest < Test::Unit::TestCase
25
25
  begin
26
26
  client.get_record :metadata_prefix => 'oai_dc'
27
27
  flunk 'invalid get_record did not throw OAI::Exception'
28
- rescue OAI::Exception => e
28
+ rescue OAI::ArgumentException => e
29
29
  assert_match /The request includes illegal arguments/, e.to_s
30
30
  end
31
31
  end
@@ -58,8 +58,8 @@ eos
58
58
  end
59
59
 
60
60
  faraday_stub = Faraday.new do |builder|
61
- require 'faraday_middleware'
62
- builder.use FaradayMiddleware::FollowRedirects
61
+ require 'faraday/follow_redirects'
62
+ builder.use Faraday::FollowRedirects::Middleware
63
63
  builder.adapter :test, stubs
64
64
  end
65
65
 
@@ -7,7 +7,7 @@ class LibXMLTest < Test::Unit::TestCase
7
7
 
8
8
  uri = 'http://localhost:3333/oai'
9
9
  client = OAI::Client.new uri, :parser => 'libxml'
10
- assert_raises(OAI::Exception) {client.get_record(:identifier => 'nosuchid')}
10
+ assert_raises(OAI::IdException) {client.get_record(:identifier => 'nosuchid')}
11
11
  end
12
12
 
13
13
  def test_list_records
@@ -1,12 +1,19 @@
1
1
  require 'test_helper_client'
2
2
 
3
3
  class UTF8Test < Test::Unit::TestCase
4
+ def client
5
+ @client ||= OAI::Client.new 'http://localhost:3333/oai'
6
+ end
4
7
 
5
8
  def test_escaping_invalid_utf_8_characters
6
- client = OAI::Client.new 'http://localhost:3333/oai' #, :parser => 'libxml'
7
9
  invalid_utf_8 = [2, 3, 4, 104, 5, 101, 6, 108, 66897, 108, 66535, 111, 1114112, 33, 55234123, 33].pack("U*")
8
10
  invalid_utf_8 = invalid_utf_8.force_encoding("binary") if invalid_utf_8.respond_to? :force_encoding
9
11
  assert_equal("hello!!", client.send(:strip_invalid_utf_8_chars, invalid_utf_8).gsub(/\?/, ''))
10
12
  end
11
13
 
14
+ def test_unescaped_ampersand_content_correction
15
+ src = '<test>Frankie & Johnny <character>&#9829;</character></test>'
16
+ expected = '<test>Frankie &amp; Johnny <character>&#9829;</character></test>'
17
+ assert_equal(expected, client.sanitize_xml(src))
18
+ end
12
19
  end
@@ -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,6 @@
1
+ require 'oai'
2
+ require 'oai/harvester'
3
+ require 'test/unit'
4
+
5
+ require File.dirname(__FILE__) + '/../client/helpers/provider'
6
+ require File.dirname(__FILE__) + '/../client/helpers/test_wrapper'
@@ -68,7 +68,7 @@ class TestModel < OAI::Provider::Model
68
68
  if token.last < @groups.size - 1
69
69
  PartialResult.new(@groups[token.last], token.next(token.last + 1))
70
70
  else
71
- @groups[token.last]
71
+ PartialResult.new(@groups[token.last], token.next(nil))
72
72
  end
73
73
  rescue
74
74
  raise OAI::ResumptionTokenException.new
@@ -76,8 +76,8 @@ class TestModel < OAI::Provider::Model
76
76
  else
77
77
  records = @records.select do |rec|
78
78
  ((opts[:set].nil? || rec.in_set(opts[:set])) &&
79
- (opts[:from].nil? || rec.updated_at >= opts[:from]) &&
80
- (opts[:until].nil? || rec.updated_at <= opts[:until]))
79
+ (opts[:from].nil? || rec.updated_at >= opts[:from].to_time) &&
80
+ (opts[:until].nil? || rec.updated_at <= opts[:until].to_time))
81
81
  #else
82
82
  # ((opts[:set].nil? || rec.in_set(opts[:set])) &&
83
83
  # (opts[:from].nil? || rec.updated_at >= opts[:from]) &&