browse-everything 0.15.1 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|