resync-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +42 -0
  3. data/.rubocop.yml +23 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +2 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE.md +22 -0
  8. data/README.md +59 -0
  9. data/Rakefile +56 -0
  10. data/example.rb +49 -0
  11. data/lib/resync/client/bitstream.rb +79 -0
  12. data/lib/resync/client/client.rb +58 -0
  13. data/lib/resync/client/downloadable.rb +35 -0
  14. data/lib/resync/client/dump.rb +25 -0
  15. data/lib/resync/client/http_helper.rb +111 -0
  16. data/lib/resync/client/resync_extensions.rb +85 -0
  17. data/lib/resync/client/version.rb +6 -0
  18. data/lib/resync/client/zip_package.rb +66 -0
  19. data/lib/resync/client.rb +3 -0
  20. data/resync-client.gemspec +35 -0
  21. data/spec/data/examples/capability-list.xml +25 -0
  22. data/spec/data/examples/change-dump-manifest.xml +41 -0
  23. data/spec/data/examples/change-dump.xml +41 -0
  24. data/spec/data/examples/change-list-index.xml +22 -0
  25. data/spec/data/examples/change-list.xml +36 -0
  26. data/spec/data/examples/resource-dump-manifest.xml +25 -0
  27. data/spec/data/examples/resource-dump.xml +39 -0
  28. data/spec/data/examples/resource-list-index.xml +21 -0
  29. data/spec/data/examples/resource-list.xml +24 -0
  30. data/spec/data/examples/source-description.xml +25 -0
  31. data/spec/data/resourcedump/manifest.xml +18 -0
  32. data/spec/data/resourcedump/resourcedump.xml +16 -0
  33. data/spec/data/resourcedump/resourcedump.zip +0 -0
  34. data/spec/data/resourcedump/resources/res1 +7 -0
  35. data/spec/data/resourcedump/resources/res2 +7 -0
  36. data/spec/rspec_custom_matchers.rb +11 -0
  37. data/spec/spec_helper.rb +31 -0
  38. data/spec/todo.rb +65 -0
  39. data/spec/unit/resync/client/bitstream_spec.rb +90 -0
  40. data/spec/unit/resync/client/client_spec.rb +130 -0
  41. data/spec/unit/resync/client/dump_spec.rb +26 -0
  42. data/spec/unit/resync/client/http_helper_spec.rb +235 -0
  43. data/spec/unit/resync/client/resync_extensions_spec.rb +148 -0
  44. data/spec/unit/resync/client/zip_package_spec.rb +44 -0
  45. metadata +238 -0
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+ require 'mime/type'
3
+ require 'zip'
4
+
5
+ module Resync
6
+ describe Bitstream do
7
+
8
+ # ------------------------------------------------------------
9
+ # Fixture
10
+
11
+ before(:each) do
12
+ @zipfile = instance_double(Zip::File)
13
+
14
+ @metadata = instance_double(Metadata)
15
+ @path = 'path/to/resource'
16
+ allow(@metadata).to receive(:path).and_return(@path)
17
+
18
+ @zip_entry = instance_double(Zip::Entry)
19
+ allow(@zipfile).to receive(:find_entry).with(@path).and_return(@zip_entry)
20
+
21
+ @resource = instance_double(Resource)
22
+ allow(@resource).to receive(:metadata).and_return(@metadata)
23
+
24
+ @bitstream = Bitstream.new(zipfile: @zipfile, resource: @resource)
25
+ end
26
+
27
+ # ------------------------------------------------------------
28
+ # Tests
29
+
30
+ describe '#new' do
31
+ it 'requires a zipfile' do
32
+ expect { Bitstream.new(resource: @resource) }.to raise_error
33
+ end
34
+
35
+ it 'requires a resource' do
36
+ expect { Bitstream.new(zipfile: @zipfile) }.to raise_error
37
+ end
38
+ end
39
+
40
+ describe '#size' do
41
+ it 'returns the size of the zip entry' do
42
+ expect(@zip_entry).to receive(:size).and_return(123)
43
+ expect(@bitstream.size).to eq(123)
44
+ end
45
+ end
46
+
47
+ describe '#stream' do
48
+ it 'returns the input stream from the zip entry' do
49
+ stream = instance_double(Zip::InputStream)
50
+ expect(@zip_entry).to receive(:get_input_stream).and_return(stream)
51
+ expect(@bitstream.stream).to be(stream)
52
+ end
53
+
54
+ it 'returns the same stream each time' do
55
+ stream = instance_double(Zip::InputStream)
56
+ expect(@zip_entry).to receive(:get_input_stream).and_return(stream)
57
+ expect(@bitstream.stream).to be(stream)
58
+ expect(@bitstream.stream).to be(stream)
59
+ end
60
+ end
61
+
62
+ describe '#content' do
63
+ it 'gets the content of the stream' do
64
+ stream = instance_double(Zip::InputStream)
65
+ content = 'I am the content of the zip stream'
66
+ allow(stream).to receive(:read).and_return(content)
67
+ expect(@zip_entry).to receive(:get_input_stream).and_return(stream)
68
+ expect(@bitstream.content).to eq(content)
69
+ end
70
+
71
+ it 'gets the content of the stream only once' do
72
+ stream = instance_double(Zip::InputStream)
73
+ content = 'I am the content of the zip stream'
74
+ allow(stream).to receive(:read).and_return(content)
75
+ expect(@zip_entry).to receive(:get_input_stream).and_return(stream)
76
+ expect(@bitstream.content).to eq(content)
77
+ expect(@bitstream.content).to eq(content)
78
+ end
79
+ end
80
+
81
+ describe '#mime_type' do
82
+ it 'returns the MIME type of the metadata' do
83
+ mime_type = instance_double(MIME::Type)
84
+ allow(@metadata).to receive(:mime_type).and_return(mime_type)
85
+ expect(@bitstream.mime_type).to be(mime_type)
86
+ end
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+
3
+ module Resync
4
+ describe Client do
5
+ before(:each) do
6
+ @helper = instance_double(HTTPHelper)
7
+ @client = Client.new(helper: @helper)
8
+ end
9
+
10
+ describe '#get' do
11
+ it 'retrieves a CapabilityList' do
12
+ uri = URI('http://example.org/capability-list.xml')
13
+ data = File.read('spec/data/examples/capability-list.xml')
14
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
15
+ doc = @client.get_and_parse(uri)
16
+ expect(doc).to be_a(Resync::CapabilityList)
17
+ end
18
+
19
+ it 'retrieves a ChangeDump' do
20
+ uri = URI('http://example.org/change-dump.xml')
21
+ data = File.read('spec/data/examples/change-dump.xml')
22
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
23
+ doc = @client.get_and_parse(uri)
24
+ expect(doc).to be_a(Resync::ChangeDump)
25
+ end
26
+
27
+ it 'retrieves a ChangeDumpManifest' do
28
+ uri = URI('http://example.org/change-dump-manifest.xml')
29
+ data = File.read('spec/data/examples/change-dump-manifest.xml')
30
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
31
+ doc = @client.get_and_parse(uri)
32
+ expect(doc).to be_a(Resync::ChangeDumpManifest)
33
+ end
34
+
35
+ it 'retrieves a ChangeList' do
36
+ uri = URI('http://example.org/change-list.xml')
37
+ data = File.read('spec/data/examples/change-list.xml')
38
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
39
+ doc = @client.get_and_parse(uri)
40
+ expect(doc).to be_a(Resync::ChangeList)
41
+ end
42
+
43
+ it 'retrieves a ResourceDump' do
44
+ uri = URI('http://example.org/resource-dump.xml')
45
+ data = File.read('spec/data/examples/resource-dump.xml')
46
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
47
+ doc = @client.get_and_parse(uri)
48
+ expect(doc).to be_a(Resync::ResourceDump)
49
+ end
50
+
51
+ it 'retrieves a ResourceDumpManifest' do
52
+ uri = URI('http://example.org/resource-dump-manifest.xml')
53
+ data = File.read('spec/data/examples/resource-dump-manifest.xml')
54
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
55
+ doc = @client.get_and_parse(uri)
56
+ expect(doc).to be_a(Resync::ResourceDumpManifest)
57
+ end
58
+
59
+ it 'retrieves a ResourceList' do
60
+ uri = URI('http://example.org/resource-list.xml')
61
+ data = File.read('spec/data/examples/resource-list.xml')
62
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
63
+ doc = @client.get_and_parse(uri)
64
+ expect(doc).to be_a(Resync::ResourceList)
65
+ end
66
+
67
+ it 'retrieves a SourceDescription' do
68
+ uri = URI('http://example.org/source-description.xml')
69
+ data = File.read('spec/data/examples/source-description.xml')
70
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
71
+ doc = @client.get_and_parse(uri)
72
+ expect(doc).to be_a(Resync::SourceDescription)
73
+ end
74
+
75
+ it 'retrieves a ChangeListIndex' do
76
+ uri = URI('http://example.org/change-list-index.xml')
77
+ data = File.read('spec/data/examples/change-list-index.xml')
78
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
79
+ doc = @client.get_and_parse(uri)
80
+ expect(doc).to be_a(Resync::ChangeListIndex)
81
+ end
82
+
83
+ it 'retrieves a ResourceListIndex' do
84
+ uri = URI('http://example.org/resource-list-index.xml')
85
+ data = File.read('spec/data/examples/resource-list-index.xml')
86
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
87
+ doc = @client.get_and_parse(uri)
88
+ expect(doc).to be_a(Resync::ResourceListIndex)
89
+ end
90
+
91
+ it 'injects the client into the returned document' do
92
+ uri = URI('http://example.org/resource-list-index.xml')
93
+ data = File.read('spec/data/examples/resource-list-index.xml')
94
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
95
+ doc = @client.get_and_parse(uri)
96
+ expect(doc.client).to be(@client)
97
+ end
98
+ end
99
+
100
+ describe '#new' do
101
+ it 'creates its own connection if none is provided' do
102
+ uri = URI('http://example.org/capability-list.xml')
103
+ data = File.read('spec/data/examples/capability-list.xml')
104
+ expect(HTTPHelper).to receive(:new).and_return(@helper)
105
+ expect(@helper).to receive(:fetch).with(uri: uri).and_return(data)
106
+ client = Client.new
107
+ client.get_and_parse(uri)
108
+ end
109
+ end
110
+
111
+ describe '#download_to_temp_file' do
112
+ it 'delegates to the helper' do
113
+ uri = 'http://example.org/capability-list.xml'
114
+ path = '/tmp/whatever.zip'
115
+ expect(@helper).to receive(:fetch_to_file).with(uri: URI(uri)).and_return(path)
116
+ expect(@client.download_to_temp_file(uri)).to eq(path)
117
+ end
118
+ end
119
+
120
+ describe '#download_to_file' do
121
+ it 'delegates to the helper' do
122
+ uri = 'http://example.org/capability-list.xml'
123
+ path = '/tmp/whatever.zip'
124
+ expect(@helper).to receive(:fetch_to_file).with(uri: URI(uri), path: path).and_return(path)
125
+ expect(@client.download_to_file(uri: uri, path: path)).to eq(path)
126
+ end
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ module Resync
4
+ describe Dump do
5
+ it 'transparently extracts bitstreams' do
6
+ package_uri = URI('http://example.com/resourcedump.zip')
7
+ client = instance_double(Client)
8
+ expect(client).to receive(:download_to_temp_file).once.with(package_uri).and_return('spec/data/resourcedump/resourcedump.zip')
9
+
10
+ resource_dump = XMLParser.parse(File.read('spec/data/resourcedump/resourcedump.xml'))
11
+ resource_dump.client = client
12
+
13
+ zip_packages = resource_dump.zip_packages
14
+ expect(zip_packages.size).to eq(1)
15
+
16
+ zip_package = zip_packages[0]
17
+ expect(zip_package).to be_a(ZipPackage)
18
+
19
+ bitstreams = zip_package.bitstreams
20
+ expect(bitstreams.size).to eq(2)
21
+
22
+ stream1 = bitstreams[0]
23
+ expect(stream1.content).to eq(File.read('spec/data/resourcedump/resources/res1'))
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,235 @@
1
+ require 'spec_helper'
2
+
3
+ module Resync
4
+ describe HTTPHelper do
5
+
6
+ # ------------------------------------------------------------
7
+ # Fixture
8
+
9
+ attr_writer :user_agent
10
+
11
+ def user_agent
12
+ @user_agent ||= 'elvis'
13
+ end
14
+
15
+ attr_writer :helper
16
+
17
+ def helper
18
+ @helper ||= HTTPHelper.new(user_agent: user_agent)
19
+ end
20
+
21
+ # ------------------------------------------------------------
22
+ # Tests
23
+
24
+ describe '#fetch' do
25
+
26
+ # ------------------------------
27
+ # Fixture
28
+
29
+ before(:each) do
30
+ @http = instance_double(Net::HTTP)
31
+ allow(Net::HTTP).to receive(:new).and_return(@http)
32
+ allow(@http).to receive(:start).and_yield(@http)
33
+ @success = Net::HTTPOK.allocate
34
+ @body = 'I am the body of the response'
35
+ allow(@success).to receive(:body).and_return(@body)
36
+ end
37
+
38
+ # ------------------------------
39
+ # Tests
40
+
41
+ it 'requests the specified URI' do
42
+ uri = URI('http://example.org/')
43
+ expect(@http).to receive(:request).with(request_for(uri: uri)).and_yield(@success)
44
+ helper.fetch(uri: uri)
45
+ end
46
+
47
+ it 'gets a response' do
48
+ expect(@http).to receive(:request).and_yield(@success)
49
+ expect(helper.fetch(uri: URI('http://example.org/'))).to be(@body)
50
+ end
51
+
52
+ it 'sets the User-Agent header' do
53
+ agent = 'Not Elvis'
54
+ helper = HTTPHelper.new(user_agent: agent)
55
+ expect(@http).to receive(:request).with(request_for(headers: { 'User-Agent' => agent })).and_yield(@success)
56
+ helper.fetch(uri: URI('http://example.org/'))
57
+ end
58
+
59
+ it 'uses SSL for https requests' do
60
+ uri = URI('https://example.org/')
61
+ expect(Net::HTTP).to receive(:start).with(uri.hostname, uri.port, use_ssl: true).and_call_original
62
+ expect(@http).to receive(:request).and_yield(@success)
63
+ helper.fetch(uri: uri)
64
+ end
65
+
66
+ it 're-requests on receiving a 1xx' do
67
+ uri = URI('http://example.org/')
68
+ @info = Net::HTTPContinue.allocate
69
+
70
+ expected = [@info, @success]
71
+ expect(@http).to receive(:request).twice.with(request_for(uri: uri, headers: { 'User-Agent' => user_agent })) do |&block|
72
+ block.call(expected.shift)
73
+ end
74
+
75
+ expect(helper.fetch(uri: uri)).to be(@body)
76
+ end
77
+
78
+ it 'redirects on receiving a 3xx' do
79
+ uri = URI('http://example.org/')
80
+ uri2 = URI('http://example.org/new')
81
+ @redirect = Net::HTTPMovedPermanently.allocate
82
+ allow(@redirect).to receive(:[]).with('location').and_return(uri2.to_s)
83
+ expect(@http).to receive(:request).with(request_for(uri: uri, headers: { 'User-Agent' => user_agent })).and_yield(@redirect)
84
+ expect(@http).to receive(:request).with(request_for(uri: uri2, headers: { 'User-Agent' => user_agent })).and_yield(@success)
85
+ expect(helper.fetch(uri: uri)).to be(@body)
86
+ end
87
+
88
+ it 'only redirects a limited number of times' do
89
+ uri = URI('http://example.org/')
90
+ @redirect = Net::HTTPMovedPermanently.allocate
91
+ allow(@redirect).to receive(:[]).with('location').and_return(uri.to_s)
92
+ expect(@http).to receive(:request).with(request_for(uri: uri, headers: { 'User-Agent' => user_agent })).exactly(HTTPHelper::DEFAULT_MAX_REDIRECTS).times.and_yield(@redirect)
93
+ expect { helper.fetch(uri: uri) }.to raise_error
94
+ end
95
+
96
+ it 'fails on a 4xx' do
97
+ @error = Net::HTTPForbidden
98
+ allow(@error).to receive(:code).and_return(403)
99
+ allow(@error).to receive(:message).and_return('Forbidden')
100
+ expect(@http).to receive(:request).and_yield(@error)
101
+ uri = URI('http://example.org/')
102
+ expect { helper.fetch(uri: uri) }.to raise_error
103
+ end
104
+
105
+ it 'fails on a 5xx' do
106
+ @error = Net::HTTPServerError
107
+ allow(@error).to receive(:code).and_return(500)
108
+ allow(@error).to receive(:message).and_return('Internal Server Error')
109
+ expect(@http).to receive(:request).and_yield(@error)
110
+ uri = URI('http://example.org/')
111
+ expect { helper.fetch(uri: uri) }.to raise_error
112
+ end
113
+ end
114
+
115
+ describe '#fetch_to_file' do
116
+
117
+ # ------------------------------
118
+ # Fixture
119
+
120
+ before(:each) do
121
+ @path = nil
122
+ @http = instance_double(Net::HTTP)
123
+ allow(Net::HTTP).to receive(:new).and_return(@http)
124
+ allow(@http).to receive(:start).and_yield(@http)
125
+
126
+ @data = (0...100).map { ('a'..'z').to_a[rand(26)] }.join
127
+ @success = Net::HTTPOK.allocate
128
+ allow(@success).to receive(:[]).with('Content-Type').and_return('text/plain')
129
+ stub = allow(@success).to receive(:read_body)
130
+ (0...10).each do |i|
131
+ chunk = @data[10 * i, 10]
132
+ stub = stub.and_yield(chunk)
133
+ end
134
+ end
135
+
136
+ after(:each) do
137
+ File.delete(@path) if @path
138
+ end
139
+
140
+ # ------------------------------
141
+ # Tests
142
+
143
+ it 'requests the specified URI' do
144
+ uri = URI('http://example.org/')
145
+ expect(@http).to receive(:request).with(request_for(uri: uri)).and_yield(@success)
146
+ @path = helper.fetch_to_file(uri: uri)
147
+ end
148
+
149
+ it 'returns the path to a file containing the response' do
150
+ uri = URI('http://example.org/')
151
+ expect(@http).to receive(:request).with(request_for(uri: uri)).and_yield(@success)
152
+ @path = helper.fetch_to_file(uri: uri)
153
+ expect(File.read(@path)).to eq(@data)
154
+ end
155
+
156
+ it 'sets the User-Agent header' do
157
+ agent = 'Not Elvis'
158
+ helper = HTTPHelper.new(user_agent: agent)
159
+ expect(@http).to receive(:request).with(request_for(headers: { 'User-Agent' => agent })).and_yield(@success)
160
+ @path = helper.fetch_to_file(uri: URI('http://example.org/'))
161
+ end
162
+
163
+ it 'uses SSL for https requests' do
164
+ uri = URI('https://example.org/')
165
+ expect(Net::HTTP).to receive(:start).with(uri.hostname, uri.port, use_ssl: true).and_call_original
166
+ expect(@http).to receive(:request).and_yield(@success)
167
+ @path = helper.fetch_to_file(uri: uri)
168
+ end
169
+
170
+ it 're-requests on receiving a 1xx' do
171
+ uri = URI('http://example.org/')
172
+ @info = Net::HTTPContinue.allocate
173
+
174
+ expected = [@info, @success]
175
+ expect(@http).to receive(:request).twice.with(request_for(uri: uri, headers: { 'User-Agent' => user_agent })) do |&block|
176
+ block.call(expected.shift)
177
+ end
178
+
179
+ @path = helper.fetch_to_file(uri: uri)
180
+ expect(File.read(@path)).to eq(@data)
181
+ end
182
+
183
+ it 'redirects on receiving a 3xx' do
184
+ uri = URI('http://example.org/')
185
+ uri2 = URI('http://example.org/new')
186
+ @redirect = Net::HTTPMovedPermanently.allocate
187
+ allow(@redirect).to receive(:[]).with('location').and_return(uri2.to_s)
188
+ expect(@http).to receive(:request).with(request_for(uri: uri, headers: { 'User-Agent' => user_agent })).and_yield(@redirect)
189
+ expect(@http).to receive(:request).with(request_for(uri: uri2, headers: { 'User-Agent' => user_agent })).and_yield(@success)
190
+ @path = helper.fetch_to_file(uri: uri)
191
+ expect(File.read(@path)).to eq(@data)
192
+ end
193
+
194
+ it 'only redirects a limited number of times' do
195
+ uri = URI('http://example.org/')
196
+ @redirect = Net::HTTPMovedPermanently.allocate
197
+ allow(@redirect).to receive(:[]).with('location').and_return(uri.to_s)
198
+ expect(@http).to receive(:request).with(request_for(uri: uri, headers: { 'User-Agent' => user_agent })).exactly(HTTPHelper::DEFAULT_MAX_REDIRECTS).times.and_yield(@redirect)
199
+ expect { @path = helper.fetch_to_file(uri: uri) }.to raise_error
200
+ expect(@path).to be_nil
201
+ end
202
+
203
+ it 'fails on a 4xx' do
204
+ @error = Net::HTTPForbidden
205
+ allow(@error).to receive(:code).and_return(403)
206
+ allow(@error).to receive(:message).and_return('Forbidden')
207
+ expect(@http).to receive(:request).and_yield(@error)
208
+ uri = URI('http://example.org/')
209
+ expect { @path = helper.fetch_to_file(uri: uri) }.to raise_error
210
+ expect(@path).to be_nil
211
+ end
212
+
213
+ it 'fails on a 5xx' do
214
+ @error = Net::HTTPServerError
215
+ allow(@error).to receive(:code).and_return(500)
216
+ allow(@error).to receive(:message).and_return('Internal Server Error')
217
+ expect(@http).to receive(:request).and_yield(@error)
218
+ uri = URI('http://example.org/')
219
+ expect { helper.fetch_to_file(uri: uri) }.to raise_error
220
+ end
221
+
222
+ it 'accepts a file path argument' do
223
+ Dir.mktmpdir do |dir|
224
+ expect(Dir.exist?(dir)).to be(true)
225
+ path = "#{dir}/http_helper_spec.out"
226
+ uri = URI('http://example.org/')
227
+ expect(@http).to receive(:request).with(request_for(uri: uri)).and_yield(@success)
228
+ helper.fetch_to_file(uri: uri, path: path)
229
+ expect(File.read(path)).to eq(@data)
230
+ end
231
+ end
232
+ end
233
+
234
+ end
235
+ end
@@ -0,0 +1,148 @@
1
+ require 'spec_helper'
2
+
3
+ module Resync
4
+ describe 'extensions' do
5
+
6
+ # ------------------------------------------------------------
7
+ # Fixture
8
+
9
+ before(:each) do
10
+ @resources = [
11
+ Resource.new(uri: 'http://example.com/dataset1/resourcelist.xml', metadata: Metadata.new(capability: 'resourcelist')),
12
+ Resource.new(uri: 'http://example.com/dataset1/resourcedump.xml', metadata: Metadata.new(capability: 'resourcedump')),
13
+ Resource.new(uri: 'http://example.com/dataset1/changelist.xml', metadata: Metadata.new(capability: 'changelist')),
14
+ Resource.new(uri: 'http://example.com/dataset1/changedump.xml', metadata: Metadata.new(capability: 'changedump'))
15
+ ]
16
+ @links = [
17
+ Link.new(rel: 'describedby', uri: 'http://example.org/desc1'),
18
+ Link.new(rel: 'duplicate', uri: 'http://example.com/dup1'),
19
+ Link.new(rel: 'describedby', uri: 'http://example.org/desc2'),
20
+ Link.new(rel: 'duplicate', uri: 'http://example.com/dup2')
21
+ ]
22
+ @list = ResourceList.new(resources: @resources, links: @links)
23
+ end
24
+
25
+ # ------------------------------------------------------------
26
+ # Tests
27
+
28
+ describe BaseResourceList do
29
+ it 'proxies all resource client requests to its own client' do
30
+ client = instance_double(Resync::Client)
31
+ @list.client = client
32
+ @resources.each do |r|
33
+ expect(r.client).to be(client)
34
+ end
35
+ client2 = instance_double(Resync::Client)
36
+ @list.client = client2
37
+ @resources.each do |r|
38
+ expect(r.client).to be(client2)
39
+ end
40
+ end
41
+ end
42
+
43
+ describe Augmented do
44
+ it 'proxies all link client requests to its own client' do
45
+ client = instance_double(Resync::Client)
46
+ @list.client = client
47
+ @links.each do |l|
48
+ expect(l.client).to be(client)
49
+ end
50
+ client2 = instance_double(Resync::Client)
51
+ @list.client = client2
52
+ @links.each do |l|
53
+ expect(l.client).to be(client2)
54
+ end
55
+ end
56
+
57
+ it 'defaults to a new client' do
58
+ client = instance_double(Resync::Client)
59
+ expect(Resync::Client).to receive(:new) { client }
60
+ expect(@list.client).to be(client)
61
+ end
62
+ end
63
+
64
+ describe Resource do
65
+ describe '#get_and_parse' do
66
+ it 'gets the resource using the injected client' do
67
+ client = instance_double(Resync::Client)
68
+ resource = instance_double(Resync::ResourceList)
69
+ @list.client = client
70
+ expect(client).to receive(:get_and_parse).with(@resources[0].uri) { resource }
71
+ expect(@resources[0].get_and_parse).to be(resource)
72
+ end
73
+ end
74
+
75
+ describe '#get' do
76
+ it 'gets the resource contents using the injected client' do
77
+ data = 'I am the contents of a resource'
78
+ client = instance_double(Resync::Client)
79
+ @list.client = client
80
+ expect(client).to receive(:get).with(@resources[0].uri) { data }
81
+ expect(@resources[0].get).to be(data)
82
+ end
83
+ end
84
+
85
+ describe '#download_to_temp_file' do
86
+ it 'downloads the resource contents to a file using the injected client' do
87
+ path = '/tmp/whatever.zip'
88
+ client = instance_double(Resync::Client)
89
+ @list.client = client
90
+ expect(client).to receive(:download_to_temp_file).with(@resources[0].uri) { path }
91
+ expect(@resources[0].download_to_temp_file).to be(path)
92
+ end
93
+ end
94
+
95
+ describe '#download_to_file' do
96
+ it 'delegates to the injected client' do
97
+ path = '/tmp/whatever.zip'
98
+ client = instance_double(Resync::Client)
99
+ @list.client = client
100
+ expect(client).to receive(:download_to_file).with(uri: @resources[0].uri, path: path) { path }
101
+ expect(@resources[0].download_to_file(path)).to be(path)
102
+ end
103
+ end
104
+ end
105
+
106
+ describe Link do
107
+ describe '#get_and_parse' do
108
+ it 'gets the link using the injected client' do
109
+ client = instance_double(Resync::Client)
110
+ resource = instance_double(Resync::ResourceList)
111
+ @list.client = client
112
+ expect(client).to receive(:get_and_parse).with(@links[0].uri) { resource }
113
+ expect(@links[0].get_and_parse).to be(resource)
114
+ end
115
+ end
116
+
117
+ describe '#get' do
118
+ it 'gets the link contents using the injected client' do
119
+ data = 'I am the contents of a link'
120
+ client = instance_double(Resync::Client)
121
+ @list.client = client
122
+ expect(client).to receive(:get).with(@links[0].uri) { data }
123
+ expect(@links[0].get).to be(data)
124
+ end
125
+ end
126
+
127
+ describe '#download_to_temp_file' do
128
+ it 'downloads the link contents to a file using the injected client' do
129
+ path = '/tmp/whatever.zip'
130
+ client = instance_double(Resync::Client)
131
+ @list.client = client
132
+ expect(client).to receive(:download_to_temp_file).with(@links[0].uri) { path }
133
+ expect(@links[0].download_to_temp_file).to be(path)
134
+ end
135
+ end
136
+
137
+ describe '#download_to_file' do
138
+ it 'delegates to the injected client' do
139
+ path = '/tmp/whatever.zip'
140
+ client = instance_double(Resync::Client)
141
+ @list.client = client
142
+ expect(client).to receive(:download_to_file).with(uri: @links[0].uri, path: path) { path }
143
+ expect(@links[0].download_to_file(path)).to be(path)
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'resync/client/zip_package'
3
+
4
+ module Resync
5
+ describe ZipPackage do
6
+ describe '#new' do
7
+ it 'accepts a path to a ZIP file' do
8
+ path = 'spec/data/resourcedump/resourcedump.zip'
9
+ pkg = ZipPackage.new(path)
10
+ zipfile = pkg.zipfile
11
+ expect(zipfile).to be_a(Zip::File)
12
+ expect(zipfile.name).to eq(path)
13
+ end
14
+
15
+ it 'accepts a Zip::File object' do
16
+ zipfile = Zip::File.open('spec/data/resourcedump/resourcedump.zip')
17
+ pkg = ZipPackage.new(zipfile)
18
+ expect(pkg.zipfile).to eq(zipfile)
19
+ end
20
+
21
+ it 'extracts a manifest' do
22
+ pkg = ZipPackage.new('spec/data/resourcedump/resourcedump.zip')
23
+ manifest = pkg.manifest
24
+ expect(manifest).to be_a(Resync::ResourceDumpManifest)
25
+ end
26
+
27
+ it 'extracts entries' do
28
+ pkg = ZipPackage.new('spec/data/resourcedump/resourcedump.zip')
29
+ bitstreams = pkg.bitstreams
30
+ expect(bitstreams.size).to eq(2)
31
+
32
+ bs0 = bitstreams[0]
33
+ expect(bs0.path).to eq('resources/res1')
34
+ expect(bs0.size).to eq(446)
35
+ expect(bs0.content).to eq(File.read('spec/data/resourcedump/resources/res1'))
36
+
37
+ bs1 = bitstreams[1]
38
+ expect(bs1.path).to eq('resources/res2')
39
+ expect(bs1.size).to eq(447)
40
+ expect(bs1.content).to eq(File.read('spec/data/resourcedump/resources/res2'))
41
+ end
42
+ end
43
+ end
44
+ end