oai 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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]) &&