browse-everything 0.15.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.rubocop.yml +61 -9
- data/.rubocop_todo.yml +2 -15
- data/.travis.yml +19 -19
- data/CONTRIBUTING.md +6 -6
- data/Gemfile +12 -8
- data/README.md +30 -0
- data/Rakefile +2 -1
- data/app/assets/javascripts/browse_everything/behavior.js.coffee +5 -0
- data/app/controllers/browse_everything_controller.rb +75 -23
- data/app/helpers/browse_everything_helper.rb +2 -8
- data/app/helpers/font_awesome_version_helper.rb +9 -8
- data/app/services/browse_everything_session.rb +10 -0
- data/app/services/browse_everything_session/provider_session.rb +42 -0
- data/app/services/browser_factory.rb +25 -0
- data/app/views/browse_everything/_files.html.erb +56 -6
- data/browse-everything.gemspec +29 -25
- data/config/routes.rb +7 -2
- data/lib/browse-everything.rb +2 -0
- data/lib/browse_everything.rb +45 -12
- data/lib/browse_everything/auth/google/credentials.rb +28 -0
- data/lib/browse_everything/auth/google/request_parameters.rb +61 -0
- data/lib/browse_everything/browser.rb +11 -4
- data/lib/browse_everything/driver/authentication_factory.rb +22 -0
- data/lib/browse_everything/driver/base.rb +72 -19
- data/lib/browse_everything/driver/box.rb +46 -17
- data/lib/browse_everything/driver/dropbox.rb +36 -10
- data/lib/browse_everything/driver/file_system.rb +14 -26
- data/lib/browse_everything/driver/google_drive.rb +187 -54
- data/lib/browse_everything/driver/s3.rb +81 -75
- data/lib/browse_everything/engine.rb +3 -2
- data/lib/browse_everything/file_entry.rb +3 -1
- data/lib/browse_everything/retriever.rb +103 -31
- data/lib/browse_everything/version.rb +3 -1
- data/lib/generators/browse_everything/assets_generator.rb +3 -2
- data/lib/generators/browse_everything/config_generator.rb +11 -9
- data/lib/generators/browse_everything/install_generator.rb +3 -2
- data/lib/generators/browse_everything/templates/browse_everything_providers.yml.example +12 -11
- data/spec/controllers/browse_everything_controller_spec.rb +80 -0
- data/spec/features/select_files_spec.rb +13 -13
- data/spec/features/test_compiling_stylesheets_spec.rb +2 -0
- data/spec/fixtures/vcr_cassettes/google_drive.yml +331 -0
- data/spec/fixtures/vcr_cassettes/retriever.yml +93 -0
- data/spec/helper/browse_everything_controller_helper_spec.rb +21 -7
- data/spec/javascripts/jasmine_spec.rb +2 -0
- data/spec/javascripts/support/jasmine_helper.rb +1 -0
- data/spec/lib/browse_everything/auth/google/credentials_spec.rb +41 -0
- data/spec/{unit → lib/browse_everything}/browse_everything_helper_spec.rb +2 -0
- data/spec/lib/browse_everything/browser_spec.rb +109 -0
- data/spec/{unit → lib/browse_everything/driver}/base_spec.rb +5 -4
- data/spec/{unit → lib/browse_everything/driver}/box_spec.rb +20 -5
- data/spec/{unit → lib/browse_everything/driver}/dropbox_spec.rb +15 -18
- data/spec/{unit → lib/browse_everything/driver}/file_system_spec.rb +32 -26
- data/spec/lib/browse_everything/driver/google_drive_spec.rb +171 -0
- data/spec/{unit → lib/browse_everything/driver}/s3_spec.rb +38 -21
- data/spec/lib/browse_everything/driver_spec.rb +38 -0
- data/spec/{unit → lib/browse_everything}/file_entry_spec.rb +4 -1
- data/spec/lib/browse_everything/retriever_spec.rb +200 -0
- data/spec/lib/browse_everything_spec.rb +67 -0
- data/spec/services/browse_everything_session/provider_session_spec.rb +50 -0
- data/spec/services/browser_factory_spec.rb +40 -0
- data/spec/spec_helper.rb +39 -18
- data/spec/support/app/controllers/file_handler_controller.rb +4 -4
- data/spec/support/app/views/file_handler/main.html.erb +1 -1
- data/spec/support/capybara.rb +17 -0
- data/spec/support/rake.rb +3 -1
- data/spec/support/wait_for_ajax.rb +14 -0
- data/spec/test_app_templates/Gemfile.extra +1 -0
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +10 -4
- data/spec/views/browse_everything/{_file.html.erb_spec.rb → _files.html.erb_spec.rb} +24 -18
- data/tasks/ci.rake +2 -0
- metadata +159 -107
- data/app/views/browse_everything/_file.html.erb +0 -52
- data/app/views/browse_everything/resolve.html.erb +0 -1
- data/spec/unit/browser_spec.rb +0 -76
- data/spec/unit/retriever_spec.rb +0 -109
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
include BrowserConfigHelper
|
4
|
+
|
5
|
+
describe BrowseEverything::Driver::GoogleDrive, vcr: { cassette_name: 'google_drive', record: :none } do
|
6
|
+
let(:browser) { BrowseEverything::Browser.new(url_options) }
|
7
|
+
let(:provider) { browser.providers['google_drive'] }
|
8
|
+
let(:provider_yml) do
|
9
|
+
{
|
10
|
+
client_id: 'CLIENTID', client_secret: 'CLIENTSECRET',
|
11
|
+
url_options: { port: '3000', protocol: 'http://', host: 'example.com' }
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
before do
|
16
|
+
stub_configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
after do
|
20
|
+
unstub_configuration
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'simple properties' do
|
24
|
+
subject { provider }
|
25
|
+
|
26
|
+
its(:name) { is_expected.to eq('Google Drive') }
|
27
|
+
its(:key) { is_expected.to eq('google_drive') }
|
28
|
+
its(:icon) { is_expected.to eq('google-plus-sign') }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#validate_config' do
|
32
|
+
it 'raises and error with an incomplete configuration' do
|
33
|
+
expect { BrowseEverything::Driver::GoogleDrive.new({}) }.to raise_error(BrowseEverything::InitializationError)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'raises and error with a configuration without a client secret' do
|
37
|
+
expect { BrowseEverything::Driver::GoogleDrive.new(client_id: 'test-client-id') }.to raise_error(BrowseEverything::InitializationError)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'without valid credentials' do
|
42
|
+
let(:driver) { described_class.new(provider_yml) }
|
43
|
+
|
44
|
+
describe '#token=' do
|
45
|
+
let(:value) { 'test' }
|
46
|
+
|
47
|
+
it 'restores the credentials' do
|
48
|
+
allow(driver).to receive(:restore_credentials)
|
49
|
+
driver.token = value
|
50
|
+
expect(driver).to have_received(:restore_credentials).with('test')
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when set to a Hash' do
|
54
|
+
let(:value) { { 'access_token' => 'test' } }
|
55
|
+
|
56
|
+
before do
|
57
|
+
driver.token = value
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'sets the access token value' do
|
61
|
+
expect(driver.token).to be_a String
|
62
|
+
expect(driver.token).to eq 'test'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'with a valid connection' do
|
69
|
+
let(:driver) { described_class.new(provider_yml) }
|
70
|
+
|
71
|
+
before do
|
72
|
+
driver.connect({ code: 'code' }, {})
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#authorized?' do
|
76
|
+
it 'is authorized' do
|
77
|
+
expect(driver.authorized?).to be true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#contents' do
|
82
|
+
subject(:contents) { driver.contents.to_a }
|
83
|
+
|
84
|
+
let(:drive_service_class) { class_double(Google::Apis::DriveV3::DriveService).as_stubbed_const(transfer_nested_constants: true) }
|
85
|
+
let(:drive_service) { instance_double(Google::Apis::DriveV3::DriveService) }
|
86
|
+
let(:file_list) { instance_double(Google::Apis::DriveV3::FileList) }
|
87
|
+
let(:file1) { instance_double(Google::Apis::DriveV3::File) }
|
88
|
+
let(:file2) { instance_double(Google::Apis::DriveV3::File) }
|
89
|
+
let(:files) { [file1, file2] }
|
90
|
+
|
91
|
+
before do
|
92
|
+
allow(file1).to receive(:id).and_return('asset-id2')
|
93
|
+
allow(file2).to receive(:id).and_return('directory-id1')
|
94
|
+
allow(file1).to receive(:name).and_return('asset-name2.pdf')
|
95
|
+
allow(file2).to receive(:name).and_return('directory-name1')
|
96
|
+
allow(file1).to receive(:size).and_return('891764')
|
97
|
+
allow(file2).to receive(:size).and_return('0')
|
98
|
+
allow(file1).to receive(:modified_time).and_return(Time.current)
|
99
|
+
allow(file2).to receive(:modified_time).and_return(Time.current)
|
100
|
+
allow(file1).to receive(:mime_type).and_return('application/pdf')
|
101
|
+
allow(file2).to receive(:mime_type).and_return('application/vnd.google-apps.folder')
|
102
|
+
allow(file_list).to receive(:files).and_return(files)
|
103
|
+
allow(file_list).to receive(:next_page_token).and_return(nil)
|
104
|
+
allow(drive_service).to receive(:list_files).and_yield(file_list, nil)
|
105
|
+
allow(drive_service).to receive(:batch).and_yield(drive_service)
|
106
|
+
allow(drive_service).to receive(:authorization=)
|
107
|
+
allow(drive_service).to receive(:tap).and_yield(drive_service).and_return(drive_service)
|
108
|
+
allow(drive_service_class).to receive(:new).and_return(drive_service)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'retrieves files' do
|
112
|
+
expect(contents).not_to be_empty
|
113
|
+
|
114
|
+
expect(contents.first).to be_a BrowseEverything::FileEntry
|
115
|
+
expect(contents.first.location).to eq 'google_drive:directory-id1'
|
116
|
+
expect(contents.first.mtime).to be_a Time
|
117
|
+
expect(contents.first.name).to eq 'directory-name1'
|
118
|
+
expect(contents.first.size).to eq 0
|
119
|
+
expect(contents.first.type).to eq 'directory'
|
120
|
+
|
121
|
+
expect(contents.last).to be_a BrowseEverything::FileEntry
|
122
|
+
expect(contents.last.location).to eq 'google_drive:asset-id2'
|
123
|
+
expect(contents.last.mtime).to be_a Time
|
124
|
+
expect(contents.last.name).to eq 'asset-name2.pdf'
|
125
|
+
expect(contents.last.size).to eq 891764
|
126
|
+
expect(contents.last.type).to eq 'application/pdf'
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when an error is encountered while authenticating' do
|
130
|
+
before do
|
131
|
+
allow(drive_service).to receive(:list_files).and_yield(file_list, Google::Apis::Error.new('test error'))
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'raises an exception' do
|
135
|
+
expect { driver.contents.to_a }.to raise_error(Google::Apis::Error, 'test error')
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#link_for' do
|
141
|
+
subject(:link) { driver.link_for('asset-id2') }
|
142
|
+
|
143
|
+
it 'generates the link for a Google Drive asset' do
|
144
|
+
expect(link).to be_an Array
|
145
|
+
expect(link.first).to eq 'https://www.googleapis.com/drive/v3/files/asset-id2?alt=media'
|
146
|
+
expect(link.last).to be_a Hash
|
147
|
+
expect(link.last).to include auth_header: { 'Authorization' => 'Bearer access-token' }
|
148
|
+
expect(link.last).to include :expires
|
149
|
+
expect(link.last).to include file_name: 'asset-name2.pdf'
|
150
|
+
expect(link.last).to include file_size: 0
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe '#auth_link' do
|
155
|
+
subject(:uri) { driver.auth_link }
|
156
|
+
|
157
|
+
it 'exposes the authorization endpoint URI' do
|
158
|
+
expect(uri).to be_a Addressable::URI
|
159
|
+
expect(uri.to_s).to eq 'https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&client_id=CLIENTID&include_granted_scopes=true&redirect_uri=http://example.com:3000/browse/connect&response_type=code&scope=https://www.googleapis.com/auth/drive'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe '#drive' do
|
164
|
+
subject(:drive) { driver.drive_service }
|
165
|
+
|
166
|
+
it 'exposes the Google Drive API client' do
|
167
|
+
expect(drive).to be_a Google::Apis::DriveV3::DriveService
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -1,11 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
include BrowserConfigHelper
|
2
4
|
|
3
|
-
describe BrowseEverything::Driver::
|
4
|
-
|
5
|
-
|
5
|
+
describe BrowseEverything::Driver::S3 do
|
6
|
+
subject { provider }
|
7
|
+
|
6
8
|
let(:browser) { BrowseEverything::Browser.new(url_options) }
|
7
9
|
let(:provider) { browser.providers['s3'] }
|
8
|
-
|
10
|
+
|
11
|
+
before do
|
12
|
+
stub_configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
unstub_configuration
|
17
|
+
end
|
9
18
|
|
10
19
|
describe 'defaults' do
|
11
20
|
its(:icon) { is_expected.to eq('amazon') }
|
@@ -14,34 +23,34 @@ describe BrowseEverything::Driver::FileSystem do
|
|
14
23
|
|
15
24
|
describe 'configuration' do
|
16
25
|
it '#validate_config' do
|
17
|
-
expect {
|
26
|
+
expect { described_class.new({}) }.to raise_error(BrowseEverything::InitializationError)
|
18
27
|
end
|
19
28
|
|
20
29
|
it 'rejects app_key if app_secret is missing' do
|
21
|
-
expect {
|
30
|
+
expect { described_class.new(bucket: 'bucket', app_key: 'APP_KEY') }.to raise_error(BrowseEverything::InitializationError)
|
22
31
|
end
|
23
32
|
|
24
33
|
it 'rejects app_secret if app_key is missing' do
|
25
|
-
expect {
|
34
|
+
expect { described_class.new(bucket: 'bucket', app_secret: 'APP_SECRET') }.to raise_error(BrowseEverything::InitializationError)
|
26
35
|
end
|
27
36
|
|
28
37
|
it 'accepts app_key and app_secret together' do
|
29
|
-
expect {
|
38
|
+
expect { described_class.new(bucket: 'bucket', app_key: 'APP_KEY', app_secret: 'APP_SECRET') }.not_to raise_error
|
30
39
|
end
|
31
40
|
|
32
41
|
it 'rejects an invalid response type' do
|
33
|
-
expect {
|
42
|
+
expect { described_class.new(bucket: 'bucket', response_type: :foo) }.to raise_error(BrowseEverything::InitializationError)
|
34
43
|
end
|
35
44
|
|
36
45
|
it 'deprecates :signed_url' do
|
37
|
-
driver =
|
46
|
+
driver = described_class.new(bucket: 'bucket', signed_url: false)
|
38
47
|
expect(driver.config).not_to have_key(:signed_url)
|
39
48
|
expect(driver.config[:response_type]).to eq(:public_url)
|
40
49
|
end
|
41
50
|
end
|
42
51
|
|
43
52
|
describe '#contents' do
|
44
|
-
context 'root directory' do
|
53
|
+
context 'when in a root directory' do
|
45
54
|
before do
|
46
55
|
Aws.config[:s3] = {
|
47
56
|
stub_responses: {
|
@@ -51,19 +60,22 @@ describe BrowseEverything::Driver::FileSystem do
|
|
51
60
|
end
|
52
61
|
|
53
62
|
let(:contents) { provider.contents('') }
|
54
|
-
|
63
|
+
|
64
|
+
context 'with a single asset' do
|
55
65
|
subject { contents[0] }
|
66
|
+
|
56
67
|
its(:name) { is_expected.to eq('bar') }
|
57
68
|
specify { is_expected.to be_container }
|
58
69
|
end
|
59
|
-
context '
|
70
|
+
context 'with two assets' do
|
60
71
|
subject { contents[1] }
|
72
|
+
|
61
73
|
its(:name) { is_expected.to eq('foo') }
|
62
74
|
specify { is_expected.to be_container }
|
63
75
|
end
|
64
76
|
end
|
65
77
|
|
66
|
-
context 'subdirectory' do
|
78
|
+
context 'when in a subdirectory' do
|
67
79
|
before do
|
68
80
|
Aws.config[:s3] = {
|
69
81
|
stub_responses: {
|
@@ -81,21 +93,25 @@ describe BrowseEverything::Driver::FileSystem do
|
|
81
93
|
end
|
82
94
|
|
83
95
|
let(:contents) { provider.contents('foo/') }
|
84
|
-
|
96
|
+
|
97
|
+
context 'with a single directory' do
|
85
98
|
subject { contents[0] }
|
99
|
+
|
86
100
|
its(:name) { is_expected.to eq('..') }
|
87
101
|
specify { is_expected.to be_container }
|
88
102
|
end
|
89
|
-
context '
|
103
|
+
context 'with a JPEG asset' do
|
90
104
|
subject { contents[1] }
|
105
|
+
|
91
106
|
its(:name) { is_expected.to eq('baz.jpg') }
|
92
107
|
its(:location) { is_expected.to eq('s3:foo/baz.jpg') }
|
93
108
|
its(:type) { is_expected.to eq('image/jpeg') }
|
94
109
|
its(:size) { is_expected.to eq(52645) }
|
95
110
|
specify { is_expected.not_to be_container }
|
96
111
|
end
|
97
|
-
context '
|
112
|
+
context 'with a PNG asset' do
|
98
113
|
subject { contents[2] }
|
114
|
+
|
99
115
|
its(:name) { is_expected.to eq('quux.png') }
|
100
116
|
its(:location) { is_expected.to eq('s3:foo/quux.png') }
|
101
117
|
its(:type) { is_expected.to eq('image/png') }
|
@@ -103,8 +119,9 @@ describe BrowseEverything::Driver::FileSystem do
|
|
103
119
|
specify { is_expected.not_to be_container }
|
104
120
|
end
|
105
121
|
|
106
|
-
context '
|
122
|
+
context 'when retrieving the link for an asset' do
|
107
123
|
subject { contents[2] }
|
124
|
+
|
108
125
|
before do
|
109
126
|
object = instance_double(Aws::S3::Object)
|
110
127
|
allow(object).to receive(:presigned_url).and_return('https://s3.amazonaws.com/presigned_url')
|
@@ -116,17 +133,17 @@ describe BrowseEverything::Driver::FileSystem do
|
|
116
133
|
|
117
134
|
it ':signed_url' do
|
118
135
|
provider.config[:response_type] = :signed_url
|
119
|
-
expect(provider.link_for('foo/quux.png')).to eq
|
136
|
+
expect(provider.link_for('foo/quux.png')).to eq ["https://s3.amazonaws.com/presigned_url", {:file_name=>"quux.png", :expires=>14400}]
|
120
137
|
end
|
121
138
|
|
122
139
|
it ':public_url' do
|
123
140
|
provider.config[:response_type] = :public_url
|
124
|
-
expect(provider.link_for('foo/quux.png')).to eq
|
141
|
+
expect(provider.link_for('foo/quux.png')).to eq ["https://s3.amazonaws.com/public_url", {:file_name=>"quux.png"}]
|
125
142
|
end
|
126
143
|
|
127
144
|
it ':s3_uri' do
|
128
145
|
provider.config[:response_type] = :s3_uri
|
129
|
-
expect(provider.link_for('foo/quux.png')).to eq
|
146
|
+
expect(provider.link_for('foo/quux.png')).to eq ['s3://s3.bucket/foo/quux.png', {:file_name=>"quux.png"}]
|
130
147
|
end
|
131
148
|
end
|
132
149
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe BrowseEverything::Driver do
|
4
|
+
|
5
|
+
let(:my_driver) do
|
6
|
+
MyDriver.new
|
7
|
+
end
|
8
|
+
|
9
|
+
before do
|
10
|
+
class MyDriver
|
11
|
+
include BrowseEverything::Driver
|
12
|
+
|
13
|
+
def get_sorter
|
14
|
+
sorter
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#sorter' do
|
20
|
+
it 'defaults to nil' do
|
21
|
+
expect(BrowseEverything::Driver.sorter).to be nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#sorter=' do
|
26
|
+
let(:new_sorter) do
|
27
|
+
lambda { |files| }
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
BrowseEverything::Driver.sorter = new_sorter
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'mutates the sorter from the initializer' do
|
35
|
+
expect(my_driver.get_sorter).to eq new_sorter
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
describe BrowseEverything::FileEntry do
|
2
|
-
let(:mtime) { Time.
|
4
|
+
let(:mtime) { Time.current }
|
3
5
|
|
4
6
|
describe 'regular file' do
|
5
7
|
subject do
|
@@ -42,6 +44,7 @@ describe BrowseEverything::FileEntry do
|
|
42
44
|
'..', '', mtime, true
|
43
45
|
)
|
44
46
|
end
|
47
|
+
|
45
48
|
it { is_expected.to be_container }
|
46
49
|
it { is_expected.to be_relative_parent_path }
|
47
50
|
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe BrowseEverything::Retriever, vcr: { cassette_name: 'retriever', record: :none } do
|
4
|
+
let(:retriever) { described_class.new }
|
5
|
+
let(:datafile) { File.expand_path('../../fixtures/file_system/file_1.pdf', __dir__) }
|
6
|
+
let(:datafile_with_spaces) { File.expand_path('../../fixtures/file_system/file 1.pdf', __dir__) }
|
7
|
+
let(:data) { File.open(datafile, 'rb', &:read) }
|
8
|
+
let(:data_with_spaces) { File.open(datafile_with_spaces, 'rb', &:read) }
|
9
|
+
let(:size) { File.size(datafile) }
|
10
|
+
|
11
|
+
describe '#get_file_size' do
|
12
|
+
subject(:file_size) { retriever.file_size(options) }
|
13
|
+
let(:url) { URI.parse("file://#{datafile}") }
|
14
|
+
let(:headers) { [] }
|
15
|
+
let(:file_size) { 0 }
|
16
|
+
let(:options) do
|
17
|
+
{
|
18
|
+
url: url,
|
19
|
+
headers: headers,
|
20
|
+
file_size: file_size
|
21
|
+
}.with_indifferent_access
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'calculates or retrieves the size of a file' do
|
25
|
+
retriever.retrieve(options) do |chunk, retrieved, total|
|
26
|
+
expect(total).to eq 2256
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when retrieving a resource from a cloud storage provider" do
|
31
|
+
let(:url) { URI.parse("https://drive.google.com/uc?id=id&export=download") }
|
32
|
+
|
33
|
+
it 'calculates or retrieves the size of a file' do
|
34
|
+
retriever.retrieve(options) do |chunk, retrieved, total|
|
35
|
+
expect(total).to eq 1234
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when retrieving a resource with an unsupported protocol" do
|
41
|
+
let(:url) { URI.parse("ftp://invalid") }
|
42
|
+
|
43
|
+
it "raises an error" do
|
44
|
+
expect { retriever.retrieve(options) {|c, r, t|} }.to raise_error(URI::BadURIError, "Unknown URI scheme: ftp")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with a non-URI' do
|
50
|
+
let(:spec) do
|
51
|
+
{
|
52
|
+
'0' => {
|
53
|
+
'url' => '/some/dir/file.pdf',
|
54
|
+
'file_name' => 'file.pdf',
|
55
|
+
'file_size' => size.to_s
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#retrieve' do
|
61
|
+
it 'raises an error' do
|
62
|
+
expect { retriever.retrieve(spec['0']) }.to raise_error(URI::BadURIError)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when retrieving using the HTTP' do
|
68
|
+
let(:expiry_time) { (Time.current + 3600).xmlschema }
|
69
|
+
let(:spec) do
|
70
|
+
{
|
71
|
+
'0' => {
|
72
|
+
'url' => 'https://retrieve.cloud.example.com/some/dir/file.pdf',
|
73
|
+
'auth_header' => { 'Authorization' => 'Bearer ya29.kQCEAHj1bwFXr2AuGQJmSGRWQXpacmmYZs4kzCiXns3d6H1ZpIDWmdM8' },
|
74
|
+
'expires' => expiry_time,
|
75
|
+
'file_name' => 'file.pdf',
|
76
|
+
'file_size' => size.to_s
|
77
|
+
}
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when retrieving data using chunked-encoded streams' do
|
82
|
+
it 'content' do
|
83
|
+
content = +''
|
84
|
+
retriever.retrieve(spec['0']) { |chunk, _retrieved, _total| content << chunk }
|
85
|
+
expect(content).to eq(data)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'callbacks' do
|
89
|
+
expect { |block| retriever.retrieve(spec['0'], &block) }.to yield_with_args(data, data.length, data.length)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when downloading content' do
|
94
|
+
it 'content' do
|
95
|
+
file = retriever.download(spec['0'])
|
96
|
+
expect(File.open(file, 'rb', &:read)).to eq(data)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'callbacks' do
|
100
|
+
expect { |block| retriever.download(spec['0'], &block) }.to yield_with_args(String, data.length, data.length)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when downloading content and a server error occurs' do
|
105
|
+
let(:spec) do
|
106
|
+
{
|
107
|
+
'0' => {
|
108
|
+
'url' => 'https://retrieve.cloud.example.com/some/dir/file_error.pdf',
|
109
|
+
'auth_header' => { 'Authorization' => 'Bearer ya29.kQCEAHj1bwFXr2AuGQJmSGRWQXpacmmYZs4kzCiXns3d6H1ZpIDWmdM8' },
|
110
|
+
'expires' => expiry_time,
|
111
|
+
'file_name' => 'file.pdf',
|
112
|
+
'file_size' => size.to_s
|
113
|
+
}
|
114
|
+
}
|
115
|
+
end
|
116
|
+
let(:download_options) { spec['0'] }
|
117
|
+
|
118
|
+
it 'raises an exception' do
|
119
|
+
expect { retriever.download(download_options) }.to raise_error(BrowseEverything::DownloadError, /BrowseEverything::Retriever: Failed to download/)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when retrieving file content' do
|
125
|
+
let(:spec) do
|
126
|
+
{
|
127
|
+
'0' => {
|
128
|
+
'url' => "file://#{datafile}",
|
129
|
+
'file_name' => 'file.pdf',
|
130
|
+
'file_size' => size.to_s
|
131
|
+
},
|
132
|
+
'1' => {
|
133
|
+
'url' => "file://#{datafile_with_spaces}",
|
134
|
+
'file_name' => 'file.pdf',
|
135
|
+
'file_size' => size.to_s
|
136
|
+
}
|
137
|
+
}
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when retrieving data using chunked-encoded streams' do
|
141
|
+
it 'content' do
|
142
|
+
content = +''
|
143
|
+
retriever.retrieve(spec['0']) { |chunk, _retrieved, _total| content << chunk }
|
144
|
+
expect(content).to eq(data)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'content with spaces' do
|
148
|
+
content = +''
|
149
|
+
retriever.retrieve(spec['1']) { |chunk, _retrieved, _total| content << chunk }
|
150
|
+
expect(content).to eq(data_with_spaces)
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'callbacks' do
|
154
|
+
expect { |block| retriever.retrieve(spec['0'], &block) }.to yield_with_args(data, data.length, data.length)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'when downloading content' do
|
159
|
+
it 'content' do
|
160
|
+
file = retriever.download(spec['0'])
|
161
|
+
expect(File.open(file, 'rb', &:read)).to eq(data)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'callbacks' do
|
165
|
+
expect { |block| retriever.download(spec['0'], &block) }.to yield_with_args(String, data.length, data.length)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context '.can_retrieve?' do
|
171
|
+
let(:expiry_time) { (Time.current + 3600).xmlschema }
|
172
|
+
let(:spec) do
|
173
|
+
{
|
174
|
+
'0' => {
|
175
|
+
'url' => url,
|
176
|
+
'auth_header' => { 'Authorization' => 'Bearer ya29.kQCEAHj1bwFXr2AuGQJmSGRWQXpacmmYZs4kzCiXns3d6H1ZpIDWmdM8' },
|
177
|
+
'expires' => expiry_time,
|
178
|
+
'file_name' => 'file.pdf',
|
179
|
+
'file_size' => '64134'
|
180
|
+
}
|
181
|
+
}
|
182
|
+
end
|
183
|
+
|
184
|
+
context 'can retrieve' do
|
185
|
+
let(:url) { 'https://retrieve.cloud.example.com/some/dir/can_retrieve.pdf' }
|
186
|
+
|
187
|
+
it 'says it can' do
|
188
|
+
expect(described_class.can_retrieve?(url)).to be_truthy
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context 'cannot retrieve' do
|
193
|
+
let(:url) { 'https://retrieve.cloud.example.com/some/dir/cannot_retrieve.pdf' }
|
194
|
+
|
195
|
+
it 'says it cannot' do
|
196
|
+
expect(described_class.can_retrieve?(url)).to be_falsey
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|