resync 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +42 -0
- data/.rubocop.yml +23 -0
- data/.ruby-version +1 -0
- data/.travis.yml +2 -0
- data/Gemfile +3 -0
- data/LICENSE.md +22 -0
- data/README.md +92 -0
- data/Rakefile +56 -0
- data/example.rb +100 -0
- data/lib/resync/capability_list.rb +85 -0
- data/lib/resync/change_dump.rb +15 -0
- data/lib/resync/change_dump_manifest.rb +15 -0
- data/lib/resync/change_list.rb +15 -0
- data/lib/resync/change_list_index.rb +26 -0
- data/lib/resync/link.rb +87 -0
- data/lib/resync/metadata.rb +112 -0
- data/lib/resync/resource.rb +72 -0
- data/lib/resync/resource_dump.rb +15 -0
- data/lib/resync/resource_dump_manifest.rb +15 -0
- data/lib/resync/resource_list.rb +15 -0
- data/lib/resync/resource_list_index.rb +15 -0
- data/lib/resync/shared/augmented.rb +76 -0
- data/lib/resync/shared/base_resource_list.rb +117 -0
- data/lib/resync/shared/descriptor.rb +135 -0
- data/lib/resync/shared/sitemap_index.rb +32 -0
- data/lib/resync/shared/sorted_resource_list.rb +60 -0
- data/lib/resync/source_description.rb +14 -0
- data/lib/resync/types/change.rb +14 -0
- data/lib/resync/types/change_frequency.rb +18 -0
- data/lib/resync/types.rb +6 -0
- data/lib/resync/version.rb +4 -0
- data/lib/resync/xml.rb +216 -0
- data/lib/resync/xml_parser.rb +65 -0
- data/lib/resync.rb +4 -0
- data/resync.gemspec +36 -0
- data/spec/acceptance/xml_parser_spec.rb +1049 -0
- data/spec/data/examples/README.md +1 -0
- data/spec/data/examples/example-1.xml +12 -0
- data/spec/data/examples/example-12.xml +25 -0
- data/spec/data/examples/example-13.xml +25 -0
- data/spec/data/examples/example-14.xml +23 -0
- data/spec/data/examples/example-15.xml +21 -0
- data/spec/data/examples/example-16.xml +24 -0
- data/spec/data/examples/example-17.xml +39 -0
- data/spec/data/examples/example-18.xml +25 -0
- data/spec/data/examples/example-19.xml +28 -0
- data/spec/data/examples/example-2.xml +18 -0
- data/spec/data/examples/example-20.xml +22 -0
- data/spec/data/examples/example-21.xml +31 -0
- data/spec/data/examples/example-22.xml +41 -0
- data/spec/data/examples/example-23.xml +41 -0
- data/spec/data/examples/example-24.xml +28 -0
- data/spec/data/examples/example-25.xml +21 -0
- data/spec/data/examples/example-26.xml +18 -0
- data/spec/data/examples/example-27.xml +36 -0
- data/spec/data/examples/example-28.xml +34 -0
- data/spec/data/examples/example-29.xml +27 -0
- data/spec/data/examples/example-3.xml +17 -0
- data/spec/data/examples/example-30.xml +18 -0
- data/spec/data/examples/example-31.xml +16 -0
- data/spec/data/examples/example-32.xml +22 -0
- data/spec/data/examples/example-33.xml +22 -0
- data/spec/data/examples/example-4.xml +10 -0
- data/spec/data/examples/example-5.xml +18 -0
- data/spec/data/examples/example-6.xml +21 -0
- data/spec/data/examples/example-7.xml +13 -0
- data/spec/data/examples/example-8.xml +12 -0
- data/spec/data/resourcesync.xsd +148 -0
- data/spec/data/siteindex.xsd +75 -0
- data/spec/data/sitemap.xsd +116 -0
- data/spec/rspec_custom_matchers.rb +89 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/todo.rb +11 -0
- data/spec/unit/resync/capability_list_spec.rb +138 -0
- data/spec/unit/resync/change_dump_manifest_spec.rb +75 -0
- data/spec/unit/resync/change_dump_spec.rb +61 -0
- data/spec/unit/resync/change_list_index_spec.rb +49 -0
- data/spec/unit/resync/change_list_spec.rb +75 -0
- data/spec/unit/resync/link_spec.rb +93 -0
- data/spec/unit/resync/metadata_spec.rb +169 -0
- data/spec/unit/resync/resource_dump_manifest_spec.rb +59 -0
- data/spec/unit/resync/resource_dump_spec.rb +62 -0
- data/spec/unit/resync/resource_list_index_spec.rb +53 -0
- data/spec/unit/resync/resource_list_spec.rb +60 -0
- data/spec/unit/resync/resource_spec.rb +176 -0
- data/spec/unit/resync/shared/augmented_examples.rb +58 -0
- data/spec/unit/resync/shared/base_resource_list_examples.rb +103 -0
- data/spec/unit/resync/shared/descriptor_examples.rb +122 -0
- data/spec/unit/resync/shared/descriptor_spec.rb +33 -0
- data/spec/unit/resync/shared/sorted_list_examples.rb +134 -0
- data/spec/unit/resync/shared/uri_field_examples.rb +36 -0
- data/spec/unit/resync/source_description_spec.rb +55 -0
- data/spec/unit/resync/xml/timenode_spec.rb +48 -0
- data/spec/unit/resync/xml/xml_spec.rb +40 -0
- data/spec/unit/resync/xml_parser_spec.rb +82 -0
- metadata +340 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative 'shared/base_resource_list_examples'
|
2
|
+
|
3
|
+
module Resync
|
4
|
+
describe ResourceDumpManifest do
|
5
|
+
it_behaves_like BaseResourceList
|
6
|
+
|
7
|
+
describe 'links' do
|
8
|
+
it_behaves_like Augmented
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'XML conversion' do
|
12
|
+
describe '#from_xml' do
|
13
|
+
it 'parses an XML string' do
|
14
|
+
data = File.read('spec/data/examples/example-18.xml')
|
15
|
+
urlset = ResourceDumpManifest.load_from_xml(XML.element(data))
|
16
|
+
|
17
|
+
links = urlset.links
|
18
|
+
expect(links.size).to eq(1)
|
19
|
+
ln0 = links[0]
|
20
|
+
expect(ln0.rel).to eq('up')
|
21
|
+
expect(ln0.uri).to eq(URI('http://example.com/dataset1/capabilitylist.xml'))
|
22
|
+
|
23
|
+
md = urlset.metadata
|
24
|
+
expect(md.capability).to eq('resourcedump-manifest')
|
25
|
+
expect(md.at_time).to be_time(Time.utc(2013, 1, 3, 9))
|
26
|
+
expect(md.completed_time).to be_time(Time.utc(2013, 1, 3, 9, 2))
|
27
|
+
|
28
|
+
urls = urlset.resources
|
29
|
+
expect(urls.size).to eq(2)
|
30
|
+
|
31
|
+
expected_lastmods = [Time.utc(2013, 1, 2, 13), Time.utc(2013, 1, 2, 14)]
|
32
|
+
expected_hashes = [{ 'md5' => '1584abdf8ebdc9802ac0c6a7402c03b6' }, { 'md5' => '1e0d5cb8ef6ba40c99b14c0237be735e', 'sha-256' => '854f61290e2e197a11bc91063afce22e43f8ccc655237050ace766adc68dc784' }]
|
33
|
+
expected_lengths = [8876, 14_599]
|
34
|
+
expected_types = ['text/html', 'application/pdf']
|
35
|
+
|
36
|
+
(0..1).each do |i|
|
37
|
+
url = urls[i]
|
38
|
+
expect(url.uri).to eq(URI("http://example.com/res#{i + 1}"))
|
39
|
+
expect(url.modified_time).to be_time(expected_lastmods[i])
|
40
|
+
md = url.metadata
|
41
|
+
expect(md.hashes).to eq(expected_hashes[i])
|
42
|
+
expect(md.length).to eq(expected_lengths[i])
|
43
|
+
expect(md.mime_type).to be_mime_type(expected_types[i])
|
44
|
+
expect(md.path).to eq("/resources/res#{i + 1}")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#save_to_xml' do
|
50
|
+
it 'can round-trip to XML' do
|
51
|
+
data = File.read('spec/data/examples/example-18.xml')
|
52
|
+
manifest = ResourceDumpManifest.load_from_xml(XML.element(data))
|
53
|
+
xml = manifest.save_to_xml
|
54
|
+
expect(xml).to be_xml(data)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative 'shared/base_resource_list_examples'
|
2
|
+
|
3
|
+
module Resync
|
4
|
+
describe ResourceDump do
|
5
|
+
it_behaves_like BaseResourceList
|
6
|
+
|
7
|
+
describe 'links' do
|
8
|
+
it_behaves_like Augmented
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'XML conversion' do
|
12
|
+
describe '#from_xml' do
|
13
|
+
it 'parses an XML string' do
|
14
|
+
xml = File.read('spec/data/examples/example-17.xml')
|
15
|
+
urlset = ResourceDump.load_from_xml(XML.element(xml))
|
16
|
+
links = urlset.links
|
17
|
+
expect(links.size).to eq(1)
|
18
|
+
ln0 = links[0]
|
19
|
+
expect(ln0.rel).to eq('up')
|
20
|
+
expect(ln0.uri).to eq(URI('http://example.com/dataset1/capabilitylist.xml'))
|
21
|
+
|
22
|
+
md = urlset.metadata
|
23
|
+
expect(md.capability).to eq('resourcedump')
|
24
|
+
expect(md.at_time).to be_time(Time.utc(2013, 1, 3, 9))
|
25
|
+
expect(md.completed_time).to be_time(Time.utc(2013, 1, 3, 9, 4))
|
26
|
+
|
27
|
+
urls = urlset.resources
|
28
|
+
expect(urls.size).to eq(3)
|
29
|
+
|
30
|
+
expected_lengths = [4765, 9875, 2298]
|
31
|
+
expected_ats = [Time.utc(2013, 1, 3, 9), Time.utc(2013, 1, 3, 9, 1), Time.utc(2013, 1, 3, 9, 3)]
|
32
|
+
expected_completeds = [Time.utc(2013, 1, 3, 9, 2), Time.utc(2013, 1, 3, 9, 3), Time.utc(2013, 1, 3, 9, 4)]
|
33
|
+
|
34
|
+
(0..2).each do |i|
|
35
|
+
url = urls[i]
|
36
|
+
expect(url.uri).to eq(URI("http://example.com/resourcedump-part#{i + 1}.zip"))
|
37
|
+
md = url.metadata
|
38
|
+
expect(md.mime_type).to be_mime_type('application/zip')
|
39
|
+
expect(md.length).to eq(expected_lengths[i])
|
40
|
+
expect(md.at_time).to be_time(expected_ats[i])
|
41
|
+
expect(md.completed_time).to be_time(expected_completeds[i])
|
42
|
+
links = url.links
|
43
|
+
expect(links.size).to eq(1)
|
44
|
+
ln = links[0]
|
45
|
+
expect(ln.rel).to eq('contents')
|
46
|
+
expect(ln.uri).to eq(URI("http://example.com/resourcedump_manifest-part#{i + 1}.xml"))
|
47
|
+
expect(ln.mime_type).to be_mime_type('application/xml')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#save_to_xml' do
|
53
|
+
it 'can round-trip to XML' do
|
54
|
+
data = File.read('spec/data/examples/example-17.xml')
|
55
|
+
dump = ResourceDump.load_from_xml(XML.element(data))
|
56
|
+
xml = dump.save_to_xml
|
57
|
+
expect(xml).to be_xml(data)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'shared/base_resource_list_examples'
|
2
|
+
|
3
|
+
module Resync
|
4
|
+
describe ResourceListIndex do
|
5
|
+
it_behaves_like BaseResourceList
|
6
|
+
|
7
|
+
describe 'links' do
|
8
|
+
it_behaves_like Augmented
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'XML conversion' do
|
12
|
+
describe '#from_xml' do
|
13
|
+
it 'parses an XML string' do
|
14
|
+
data = XML.element(File.read('spec/data/examples/example-15.xml'))
|
15
|
+
sitemapindex = ResourceListIndex.load_from_xml(data)
|
16
|
+
|
17
|
+
links = sitemapindex.links
|
18
|
+
expect(links.size).to eq(1)
|
19
|
+
ln0 = links[0]
|
20
|
+
expect(ln0.rel).to eq('up')
|
21
|
+
expect(ln0.uri).to eq(URI('http://example.com/dataset1/capabilitylist.xml'))
|
22
|
+
|
23
|
+
md = sitemapindex.metadata
|
24
|
+
expect(md.capability).to eq('resourcelist')
|
25
|
+
expect(md.at_time).to be_time(Time.utc(2013, 1, 3, 9))
|
26
|
+
expect(md.completed_time).to be_time(Time.utc(2013, 1, 3, 9, 10))
|
27
|
+
|
28
|
+
sitemaps = sitemapindex.resources
|
29
|
+
expect(sitemaps.size).to eq(3)
|
30
|
+
|
31
|
+
expected_times = [Time.utc(2013, 1, 3, 9), Time.utc(2013, 1, 3, 9, 3), Time.utc(2013, 1, 3, 9, 7)]
|
32
|
+
(0..2).each do |i|
|
33
|
+
sitemap = sitemaps[i]
|
34
|
+
expect(sitemap.uri).to eq(URI("http://example.com/resourcelist#{i + 1}.xml"))
|
35
|
+
md = sitemap.metadata
|
36
|
+
expect(md.at_time).to be_time(expected_times[i])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#save_to_xml' do
|
42
|
+
it 'can round-trip to XML' do
|
43
|
+
data = XML.element(File.read('spec/data/examples/example-15.xml'))
|
44
|
+
list = ResourceListIndex.load_from_xml(XML.element(data), mapping: :sitemapindex)
|
45
|
+
xml = list.save_to_xml
|
46
|
+
expect(xml).to be_xml(data)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative 'shared/base_resource_list_examples'
|
2
|
+
|
3
|
+
module Resync
|
4
|
+
describe ResourceList do
|
5
|
+
it_behaves_like BaseResourceList
|
6
|
+
|
7
|
+
describe 'links' do
|
8
|
+
it_behaves_like Augmented
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'XML conversion' do
|
12
|
+
describe '#from_xml' do
|
13
|
+
it 'parses an XML string' do
|
14
|
+
xml = File.read('spec/data/examples/example-16.xml')
|
15
|
+
list = ResourceList.load_from_xml(XML.element(xml))
|
16
|
+
links = list.links
|
17
|
+
expect(links.size).to eq(2)
|
18
|
+
ln0 = links[0]
|
19
|
+
expect(ln0.rel).to eq('up')
|
20
|
+
expect(ln0.uri).to eq(URI('http://example.com/dataset1/capabilitylist.xml'))
|
21
|
+
ln1 = links[1]
|
22
|
+
expect(ln1.rel).to eq('index')
|
23
|
+
expect(ln1.uri).to eq(URI('http://example.com/dataset1/resourcelist-index.xml'))
|
24
|
+
|
25
|
+
md = list.metadata
|
26
|
+
expect(md.capability).to eq('resourcelist')
|
27
|
+
expect(md.at_time).to be_time(Time.utc(2013, 1, 3, 9))
|
28
|
+
|
29
|
+
urls = list.resources
|
30
|
+
expect(urls.size).to eq(2)
|
31
|
+
|
32
|
+
expected_lastmods = [Time.utc(2013, 1, 2, 13), Time.utc(2013, 1, 2, 14)]
|
33
|
+
expected_hashes = [{ 'md5' => '1584abdf8ebdc9802ac0c6a7402c8753' }, { 'md5' => '4556abdf8ebdc9802ac0c6a7402c9881' }]
|
34
|
+
expected_lengths = [4385, 883]
|
35
|
+
expected_types = ['application/pdf', 'image/png']
|
36
|
+
|
37
|
+
(0..1).each do |i|
|
38
|
+
url = urls[i]
|
39
|
+
expect(url.uri).to eq(URI("http://example.com/res#{i + 3}"))
|
40
|
+
expect(url.modified_time).to be_time(expected_lastmods[i])
|
41
|
+
md = url.metadata
|
42
|
+
expect(md.hashes).to eq(expected_hashes[i])
|
43
|
+
expect(md.length).to eq(expected_lengths[i])
|
44
|
+
expect(md.mime_type).to be_mime_type(expected_types[i])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#save_to_xml' do
|
50
|
+
it 'can round-trip to XML' do
|
51
|
+
data = File.read('spec/data/examples/example-16.xml')
|
52
|
+
list = ResourceList.load_from_xml(XML.element(data))
|
53
|
+
xml = list.save_to_xml
|
54
|
+
expect(xml).to be_xml(data)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative 'shared/uri_field_examples'
|
3
|
+
require_relative 'shared/augmented_examples'
|
4
|
+
|
5
|
+
module Resync
|
6
|
+
describe Resource do
|
7
|
+
describe '#new' do
|
8
|
+
|
9
|
+
describe 'uri' do
|
10
|
+
it_behaves_like 'a URI field'
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'modified_time' do
|
14
|
+
it 'accepts a modified_time timestamp' do
|
15
|
+
lastmod = Time.utc(1997, 7, 16, 19, 20, 30.45)
|
16
|
+
resource = Resource.new(uri: 'http://example.org', modified_time: lastmod)
|
17
|
+
expect(resource.modified_time).to be_time(lastmod)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'defaults to nil if no modified_time timestamp specified' do
|
21
|
+
resource = Resource.new(uri: 'http://example.org')
|
22
|
+
expect(resource.modified_time).to be_nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'links' do
|
27
|
+
def required_arguments
|
28
|
+
{ uri: 'http://example.org' }
|
29
|
+
end
|
30
|
+
it_behaves_like Augmented
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'metadata' do
|
34
|
+
it 'accepts metadata' do
|
35
|
+
md = Metadata.new
|
36
|
+
resource = Resource.new(uri: 'http://example.org', metadata: md)
|
37
|
+
expect(resource.metadata).to eq(md)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'defaults to nil if metadata not specified' do
|
41
|
+
resource = Resource.new(uri: 'http://example.org')
|
42
|
+
expect(resource.metadata).to be_nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'changefreq' do
|
47
|
+
it 'accepts a change frequency' do
|
48
|
+
cf = Types::ChangeFrequency::DAILY
|
49
|
+
resource = Resource.new(uri: 'http://example.org', changefreq: cf)
|
50
|
+
expect(resource.changefreq).to eq(cf)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'defaults to nil if no change frequency specified' do
|
54
|
+
resource = Resource.new(uri: 'http://example.org')
|
55
|
+
expect(resource.changefreq).to be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'priority' do
|
60
|
+
it 'accepts a priority' do
|
61
|
+
priority = 1.234
|
62
|
+
resource = Resource.new(uri: 'http://example.org', priority: priority)
|
63
|
+
expect(resource.priority).to eq(priority)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'defaults to nil if no priority specified' do
|
67
|
+
resource = Resource.new(uri: 'http://example.org')
|
68
|
+
expect(resource.priority).to be_nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'capability' do
|
74
|
+
it 'extracts the capability from the metadata' do
|
75
|
+
md = Metadata.new(capability: 'changelist')
|
76
|
+
resource = Resource.new(uri: 'http://example.org', metadata: md)
|
77
|
+
expect(resource.capability).to eq('changelist')
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'returns nil if no metadata was specified' do
|
81
|
+
resource = Resource.new(uri: 'http://example.org')
|
82
|
+
expect(resource.capability).to be_nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe 'XML conversion' do
|
87
|
+
describe '#from_xml' do
|
88
|
+
it 'parses an XML string' do
|
89
|
+
xml = '<url xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:rs="http://www.openarchives.org/rs/terms/">
|
90
|
+
<loc>http://example.com/res1</loc>
|
91
|
+
<lastmod>2013-01-03T18:00:00Z</lastmod>
|
92
|
+
<rs:md change="updated"
|
93
|
+
hash="md5:1584abdf8ebdc9802ac0c6a7402c03b6"
|
94
|
+
length="8876"
|
95
|
+
type="text/html"/>
|
96
|
+
<rs:ln rel="duplicate"
|
97
|
+
pri="1"
|
98
|
+
href="http://mirror1.example.com/res1"
|
99
|
+
modified="2013-01-03T18:00:00Z"/>
|
100
|
+
<rs:ln rel="duplicate"
|
101
|
+
pri="2"
|
102
|
+
href="http://mirror2.example.com/res1"
|
103
|
+
modified="2013-01-03T18:00:00Z"/>
|
104
|
+
<rs:ln rel="duplicate"
|
105
|
+
pri="3"
|
106
|
+
href="gsiftp://gridftp.example.com/res1"
|
107
|
+
modified="2013-01-03T18:00:00Z"/>
|
108
|
+
</url>'
|
109
|
+
resource = Resource.load_from_xml(XML.element(xml))
|
110
|
+
expect(resource).to be_a(Resource)
|
111
|
+
expect(resource.uri).to eq(URI('http://example.com/res1'))
|
112
|
+
expect(resource.modified_time).to be_time(Time.utc(2013, 1, 3, 18))
|
113
|
+
metadata = resource.metadata
|
114
|
+
expect(metadata.change).to eq(Types::Change::UPDATED)
|
115
|
+
expect(metadata.hash('md5')).to eq('1584abdf8ebdc9802ac0c6a7402c03b6')
|
116
|
+
expect(metadata.length).to eq(8_876)
|
117
|
+
expect(metadata.mime_type).to be_mime_type('text/html')
|
118
|
+
links = resource.links
|
119
|
+
expect(links.size).to eq(3)
|
120
|
+
expected_uris = [URI('http://mirror1.example.com/res1'),
|
121
|
+
URI('http://mirror2.example.com/res1'),
|
122
|
+
URI('gsiftp://gridftp.example.com/res1')]
|
123
|
+
|
124
|
+
(0..2).each do |i|
|
125
|
+
ln = links[i]
|
126
|
+
expect(ln.rel).to eq('duplicate')
|
127
|
+
expect(ln.priority).to eq(i + 1)
|
128
|
+
expect(ln.uri).to eq(expected_uris[i])
|
129
|
+
expect(ln.modified_time).to be_time(Time.utc(2013, 1, 3, 18))
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'can round-trip to XML' do
|
135
|
+
data = '<url xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:rs="http://www.openarchives.org/rs/terms/">
|
136
|
+
<loc>http://example.com/res1</loc>
|
137
|
+
<lastmod>2013-01-03T18:00:00Z</lastmod>
|
138
|
+
<changefreq>daily</changefreq>
|
139
|
+
<rs:ln rel="duplicate"
|
140
|
+
pri="1"
|
141
|
+
href="http://mirror1.example.com/res1"
|
142
|
+
modified="2013-01-03T18:00:00Z"/>
|
143
|
+
<rs:ln rel="duplicate"
|
144
|
+
pri="2"
|
145
|
+
href="http://mirror2.example.com/res1"
|
146
|
+
modified="2013-01-03T18:00:00Z"/>
|
147
|
+
<rs:md change="updated"
|
148
|
+
hash="md5:1584abdf8ebdc9802ac0c6a7402c03b6"
|
149
|
+
length="8876"
|
150
|
+
type="text/html"/>
|
151
|
+
<rs:ln rel="duplicate"
|
152
|
+
pri="3"
|
153
|
+
href="gsiftp://gridftp.example.com/res1"
|
154
|
+
modified="2013-01-03T18:00:00Z"/>
|
155
|
+
</url>'
|
156
|
+
resource = Resource.load_from_xml(XML.element(data))
|
157
|
+
|
158
|
+
# Since resource isn't a root element, these won't be hacked in as in BaseResourceList#pre_save()
|
159
|
+
xml = resource.save_to_xml
|
160
|
+
xml.add_namespace('http://www.sitemaps.org/schemas/sitemap/0.9')
|
161
|
+
xml.add_namespace('rs', 'http://www.openarchives.org/rs/terms/')
|
162
|
+
|
163
|
+
expect(xml).to be_xml(data)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'doesn\'t have side effects that prevent <sitemapindex> parsing' do
|
167
|
+
Resource.xml_mapping_nodes(mapping: :sitemapindex)
|
168
|
+
|
169
|
+
data = File.read('spec/data/examples/example-8.xml')
|
170
|
+
root = REXML::Document.new(data).root
|
171
|
+
sitemapindex = XMLParser.parse(root)
|
172
|
+
expect(sitemapindex).to be_a(ResourceListIndex)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Resync
|
2
|
+
# TODO: Figure out if 'up' is mandatory for all resource lists, or just CapabilityList
|
3
|
+
# TODO: Consider requiring this in base_resource_list_examples again, if 'up' is mandatory
|
4
|
+
RSpec.shared_examples Augmented do
|
5
|
+
|
6
|
+
# TODO: Find a better way to express this
|
7
|
+
def new_instance(**args)
|
8
|
+
required_args = (defined? required_arguments) ? required_arguments : {}
|
9
|
+
args = required_args.merge(args)
|
10
|
+
described_class.new(**args)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'links' do
|
14
|
+
it 'accepts a list of links' do
|
15
|
+
links = [Link.new(rel: 'describedby', uri: 'http://example.org/'), Link.new(rel: 'duplicate', uri: 'http://example.com/')]
|
16
|
+
list = new_instance(links: links)
|
17
|
+
expect(list.links).to eq(links)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'defaults to an empty list if no links are specified' do
|
21
|
+
list = new_instance
|
22
|
+
expect(list.links).to eq([])
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#links_for' do
|
28
|
+
it 'can retrieve a list of links by rel' do
|
29
|
+
links = [
|
30
|
+
Link.new(rel: 'describedby', uri: 'http://example.org/desc1'),
|
31
|
+
Link.new(rel: 'duplicate', uri: 'http://example.com/dup1'),
|
32
|
+
Link.new(rel: 'describedby', uri: 'http://example.org/desc2'),
|
33
|
+
Link.new(rel: 'duplicate', uri: 'http://example.com/dup2')
|
34
|
+
]
|
35
|
+
list = new_instance(links: links)
|
36
|
+
expect(list.links_for(rel: 'describedby')).to eq([links[0], links[2]])
|
37
|
+
expect(list.links_for(rel: 'duplicate')).to eq([links[1], links[3]])
|
38
|
+
expect(list.links_for(rel: 'elvis')).to eq([])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#link_for' do
|
43
|
+
it 'can retrieve the first link for a rel' do
|
44
|
+
links = [
|
45
|
+
Link.new(rel: 'describedby', uri: 'http://example.org/desc1'),
|
46
|
+
Link.new(rel: 'duplicate', uri: 'http://example.com/dup1'),
|
47
|
+
Link.new(rel: 'describedby', uri: 'http://example.org/desc2'),
|
48
|
+
Link.new(rel: 'duplicate', uri: 'http://example.com/dup2')
|
49
|
+
]
|
50
|
+
list = new_instance(links: links)
|
51
|
+
expect(list.link_for(rel: 'describedby')).to eq(links[0])
|
52
|
+
expect(list.link_for(rel: 'duplicate')).to eq(links[1])
|
53
|
+
expect(list.link_for(rel: 'elvis')).to eq(nil)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative 'augmented_examples'
|
3
|
+
|
4
|
+
module Resync
|
5
|
+
RSpec.shared_examples BaseResourceList do
|
6
|
+
|
7
|
+
# ------------------------------------------------------
|
8
|
+
# "Virtual" fixture methods
|
9
|
+
|
10
|
+
# TODO: Find a better way to express this
|
11
|
+
def resource_list
|
12
|
+
(defined? valid_resources) ? valid_resources : [Resource.new(uri: 'http://example.org/'), Resource.new(uri: 'http://example.com/')]
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: Find a better way to express this
|
16
|
+
def new_instance(**args)
|
17
|
+
required_args = (defined? required_arguments) ? required_arguments : {}
|
18
|
+
args = required_args.merge(args)
|
19
|
+
described_class.new(**args)
|
20
|
+
end
|
21
|
+
|
22
|
+
# ------------------------------------------------------
|
23
|
+
# Tests
|
24
|
+
|
25
|
+
describe '#new' do
|
26
|
+
describe 'resources' do
|
27
|
+
it 'accepts a list of resources' do
|
28
|
+
puts defined? valid_resources
|
29
|
+
resources = resource_list
|
30
|
+
list = new_instance(resources: resources)
|
31
|
+
expect(list.resources).to eq(resources)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'defaults to an empty list if no resources are specified' do
|
35
|
+
list = new_instance
|
36
|
+
expect(list.resources).to eq([])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'metadata' do
|
41
|
+
it 'accepts metadata' do
|
42
|
+
metadata = Metadata.new(capability: described_class::CAPABILITY)
|
43
|
+
list = new_instance(metadata: metadata)
|
44
|
+
expect(list.metadata).to eq(metadata)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'defaults (otherwise empty) metadata with capability CAPABILITY if no metadata specified' do
|
48
|
+
list = new_instance
|
49
|
+
metadata = list.metadata
|
50
|
+
expect(metadata.capability).to eq(described_class::CAPABILITY)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'fails if metadata does not have capability CAPABILITY' do
|
54
|
+
expect { new_instance(metadata: Metadata.new) }.to raise_error(ArgumentError)
|
55
|
+
expect { new_instance(metadata: Metadata.new(capability: "not_#{described_class::CAPABILITY}")) }.to raise_error(ArgumentError)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#resources_for' do
|
61
|
+
it 'can retrieve a list of resources by capability' do
|
62
|
+
unless defined? valid_resources
|
63
|
+
resources = [
|
64
|
+
Resource.new(uri: 'http://example.com/dataset1/resourcedump1.xml', metadata: Metadata.new(capability: 'resourcedump')),
|
65
|
+
Resource.new(uri: 'http://example.com/dataset1/changelist1.xml', metadata: Metadata.new(capability: 'changelist')),
|
66
|
+
Resource.new(uri: 'http://example.com/dataset1/resourcedump2.xml', metadata: Metadata.new(capability: 'resourcedump')),
|
67
|
+
Resource.new(uri: 'http://example.com/dataset1/changelist2.xml', metadata: Metadata.new(capability: 'changelist'))
|
68
|
+
]
|
69
|
+
list = new_instance(resources: resources)
|
70
|
+
expect(list.resources_for(capability: 'resourcedump')).to eq([resources[0], resources[2]])
|
71
|
+
expect(list.resources_for(capability: 'changelist')).to eq([resources[1], resources[3]])
|
72
|
+
expect(list.resources_for(capability: 'changedump')).to eq([])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#resource_for' do
|
78
|
+
it 'can retrieve the first resource for a capability' do
|
79
|
+
unless defined? valid_resources
|
80
|
+
resources = [
|
81
|
+
Resource.new(uri: 'http://example.com/dataset1/resourcedump1.xml', metadata: Metadata.new(capability: 'resourcedump')),
|
82
|
+
Resource.new(uri: 'http://example.com/dataset1/changelist1.xml', metadata: Metadata.new(capability: 'changelist')),
|
83
|
+
Resource.new(uri: 'http://example.com/dataset1/resourcedump2.xml', metadata: Metadata.new(capability: 'resourcedump')),
|
84
|
+
Resource.new(uri: 'http://example.com/dataset1/changelist2.xml', metadata: Metadata.new(capability: 'changelist'))
|
85
|
+
]
|
86
|
+
list = new_instance(resources: resources)
|
87
|
+
expect(list.resource_for(capability: 'resourcedump')).to eq(resources[0])
|
88
|
+
expect(list.resource_for(capability: 'changelist')).to eq(resources[1])
|
89
|
+
expect(list.resource_for(capability: 'changedump')).to eq(nil)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'capability' do
|
95
|
+
it 'extracts the capability' do
|
96
|
+
metadata = Metadata.new(capability: described_class::CAPABILITY)
|
97
|
+
list = new_instance(metadata: metadata)
|
98
|
+
expect(list.capability).to eq(described_class::CAPABILITY)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|