mongo 2.1.0.beta → 2.2.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.md +10 -3
- data/Rakefile +1 -7
- data/lib/mongo/address/ipv4.rb +6 -1
- data/lib/mongo/address/unix.rb +2 -2
- data/lib/mongo/address.rb +32 -10
- data/lib/mongo/auth/cr/conversation.rb +1 -1
- data/lib/mongo/auth/ldap/conversation.rb +7 -3
- data/lib/mongo/auth/scram/conversation.rb +9 -3
- data/lib/mongo/auth/user/view.rb +23 -2
- data/lib/mongo/auth/x509/conversation.rb +1 -1
- data/lib/mongo/bulk_write/combineable.rb +51 -0
- data/lib/mongo/bulk_write/ordered_combiner.rb +55 -0
- data/lib/mongo/bulk_write/result.rb +61 -8
- data/lib/mongo/bulk_write/result_combiner.rb +117 -0
- data/lib/mongo/bulk_write/transformable.rb +132 -0
- data/lib/mongo/bulk_write/unordered_combiner.rb +52 -0
- data/lib/mongo/bulk_write/validatable.rb +62 -0
- data/lib/mongo/bulk_write.rb +164 -23
- data/lib/mongo/client.rb +75 -18
- data/lib/mongo/cluster/topology/replica_set.rb +8 -6
- data/lib/mongo/cluster/topology/unknown.rb +5 -2
- data/lib/mongo/cluster.rb +85 -5
- data/lib/mongo/collection/view/aggregation.rb +19 -45
- data/lib/mongo/collection/view/builder/aggregation.rb +98 -0
- data/lib/mongo/collection/view/builder/find_command.rb +111 -0
- data/lib/mongo/collection/view/builder/flags.rb +62 -0
- data/lib/mongo/collection/view/builder/map_reduce.rb +134 -0
- data/lib/mongo/collection/view/builder/modifiers.rb +80 -0
- data/lib/mongo/collection/view/builder/op_query.rb +83 -0
- data/lib/mongo/collection/view/builder.rb +20 -0
- data/lib/mongo/collection/view/explainable.rb +15 -0
- data/lib/mongo/collection/view/immutable.rb +4 -11
- data/lib/mongo/collection/view/iterable.rb +40 -5
- data/lib/mongo/collection/view/map_reduce.rb +67 -37
- data/lib/mongo/collection/view/readable.rb +114 -100
- data/lib/mongo/collection/view/writable.rb +46 -22
- data/lib/mongo/collection/view.rb +25 -22
- data/lib/mongo/collection.rb +130 -12
- data/lib/mongo/cursor/builder/get_more_command.rb +71 -0
- data/lib/mongo/cursor/builder/kill_cursors_command.rb +62 -0
- data/lib/mongo/cursor/builder/op_get_more.rb +61 -0
- data/lib/mongo/cursor/builder/op_kill_cursors.rb +56 -0
- data/lib/mongo/cursor/builder.rb +18 -0
- data/lib/mongo/cursor.rb +76 -21
- data/lib/mongo/database/view.rb +11 -6
- data/lib/mongo/database.rb +16 -6
- data/lib/mongo/dbref.rb +9 -9
- data/lib/mongo/{bulk_write/unordered_bulk_write.rb → error/closed_stream.rb} +12 -21
- data/lib/mongo/{bulk_write/ordered_bulk_write.rb → error/extra_file_chunk.rb} +13 -27
- data/lib/mongo/error/file_not_found.rb +37 -0
- data/lib/mongo/error/invalid_file.rb +2 -2
- data/lib/mongo/error/invalid_file_revision.rb +37 -0
- data/lib/mongo/error/invalid_uri.rb +5 -4
- data/lib/mongo/error/invalid_write_concern.rb +35 -0
- data/lib/mongo/error/missing_file_chunk.rb +38 -0
- data/lib/mongo/error/operation_failure.rb +33 -2
- data/lib/mongo/error/unchangeable_collection_option.rb +38 -0
- data/lib/mongo/error/unexpected_chunk_length.rb +39 -0
- data/lib/mongo/error.rb +8 -0
- data/lib/mongo/grid/file/chunk.rb +9 -9
- data/lib/mongo/grid/file/{metadata.rb → info.rb} +41 -39
- data/lib/mongo/grid/file.rb +12 -9
- data/lib/mongo/grid/fs_bucket.rb +448 -0
- data/lib/mongo/grid/stream/read.rb +208 -0
- data/lib/mongo/grid/stream/write.rb +187 -0
- data/lib/mongo/grid/stream.rb +64 -0
- data/lib/mongo/grid.rb +2 -1
- data/lib/mongo/index/view.rb +7 -4
- data/lib/mongo/index.rb +5 -0
- data/lib/mongo/loggable.rb +34 -57
- data/lib/mongo/logger.rb +16 -78
- data/lib/mongo/monitoring/command_log_subscriber.rb +38 -14
- data/lib/mongo/monitoring/event/command_started.rb +2 -1
- data/lib/mongo/monitoring/event/command_succeeded.rb +24 -2
- data/lib/mongo/monitoring/event/secure.rb +58 -0
- data/lib/mongo/monitoring/event.rb +1 -0
- data/lib/mongo/monitoring/publishable.rb +22 -12
- data/lib/mongo/monitoring.rb +1 -5
- data/lib/mongo/operation/commands/aggregate/result.rb +89 -0
- data/lib/mongo/operation/commands/aggregate.rb +64 -0
- data/lib/mongo/operation/commands/collections_info/result.rb +41 -0
- data/lib/mongo/operation/{read → commands}/collections_info.rb +5 -3
- data/lib/mongo/operation/commands/command.rb +47 -0
- data/lib/mongo/operation/commands/find/result.rb +62 -0
- data/lib/mongo/operation/commands/find.rb +27 -0
- data/lib/mongo/operation/commands/get_more/result.rb +62 -0
- data/lib/mongo/operation/commands/get_more.rb +27 -0
- data/lib/mongo/operation/{read → commands}/indexes.rb +9 -6
- data/lib/mongo/operation/{list_collections → commands/list_collections}/result.rb +1 -21
- data/lib/mongo/operation/{read → commands}/list_collections.rb +4 -32
- data/lib/mongo/operation/{list_indexes → commands/list_indexes}/result.rb +1 -21
- data/lib/mongo/operation/{read → commands}/list_indexes.rb +3 -33
- data/lib/mongo/operation/commands/map_reduce/result.rb +119 -0
- data/lib/mongo/operation/commands/map_reduce.rb +49 -0
- data/lib/mongo/operation/commands/parallel_scan/result.rb +64 -0
- data/lib/mongo/operation/commands/parallel_scan.rb +52 -0
- data/lib/mongo/operation/commands/user_query.rb +71 -0
- data/lib/mongo/operation/commands/users_info/result.rb +38 -0
- data/lib/mongo/operation/commands/users_info.rb +48 -0
- data/lib/mongo/operation/commands.rb +26 -0
- data/lib/mongo/operation/executable.rb +4 -68
- data/lib/mongo/operation/kill_cursors.rb +3 -3
- data/lib/mongo/operation/object_id_generator.rb +36 -0
- data/lib/mongo/operation/read/get_more.rb +2 -22
- data/lib/mongo/operation/read/query/result.rb +40 -0
- data/lib/mongo/operation/read/query.rb +4 -21
- data/lib/mongo/operation/read.rb +0 -4
- data/lib/mongo/operation/{read_preferrable.rb → read_preference.rb} +3 -2
- data/lib/mongo/operation/result.rb +43 -1
- data/lib/mongo/operation/specifiable.rb +59 -1
- data/lib/mongo/operation/write/bulk/bulkable.rb +83 -0
- data/lib/mongo/operation/write/bulk/delete/result.rb +67 -0
- data/lib/mongo/operation/write/bulk/delete.rb +71 -0
- data/lib/mongo/operation/write/bulk/insert/result.rb +129 -0
- data/lib/mongo/operation/write/bulk/insert.rb +96 -0
- data/lib/mongo/operation/write/bulk/legacy_mergable.rb +87 -0
- data/lib/mongo/operation/write/bulk/mergable.rb +71 -0
- data/lib/mongo/operation/write/bulk/update/result.rb +174 -0
- data/lib/mongo/operation/write/bulk/update.rb +81 -0
- data/lib/mongo/operation/write/bulk.rb +6 -3
- data/lib/mongo/operation/write/command/create_index.rb +0 -1
- data/lib/mongo/operation/write/command/create_user.rb +0 -1
- data/lib/mongo/operation/write/command/delete.rb +3 -3
- data/lib/mongo/operation/write/command/drop_index.rb +0 -1
- data/lib/mongo/operation/write/command/insert.rb +4 -3
- data/lib/mongo/operation/write/command/remove_user.rb +0 -1
- data/lib/mongo/operation/write/command/update.rb +6 -4
- data/lib/mongo/operation/write/command/update_user.rb +0 -1
- data/lib/mongo/operation/write/command/writable.rb +13 -18
- data/lib/mongo/operation/write/create_index.rb +4 -27
- data/lib/mongo/operation/write/create_user.rb +4 -30
- data/lib/mongo/operation/write/delete.rb +6 -29
- data/lib/mongo/operation/write/drop_index.rb +3 -3
- data/lib/mongo/operation/write/gle.rb +49 -0
- data/lib/mongo/operation/write/idable.rb +24 -2
- data/lib/mongo/operation/write/insert.rb +2 -24
- data/lib/mongo/operation/write/remove_user.rb +4 -27
- data/lib/mongo/operation/write/update.rb +13 -36
- data/lib/mongo/operation/write/update_user.rb +4 -30
- data/lib/mongo/operation/write/write_command_enabled.rb +53 -0
- data/lib/mongo/operation/write.rb +2 -0
- data/lib/mongo/operation.rb +33 -5
- data/lib/mongo/options/mapper.rb +26 -2
- data/lib/mongo/options/redacted.rb +156 -0
- data/lib/mongo/options.rb +1 -0
- data/lib/mongo/protocol/bit_vector.rb +11 -9
- data/lib/mongo/protocol/delete.rb +78 -3
- data/lib/mongo/protocol/get_more.rb +59 -2
- data/lib/mongo/protocol/insert.rb +73 -1
- data/lib/mongo/protocol/kill_cursors.rb +66 -4
- data/lib/mongo/protocol/message.rb +44 -20
- data/lib/mongo/protocol/query.rb +153 -65
- data/lib/mongo/protocol/reply.rb +92 -1
- data/lib/mongo/protocol/serializers.rb +49 -40
- data/lib/mongo/protocol/update.rb +93 -1
- data/lib/mongo/retryable.rb +101 -0
- data/lib/mongo/server/connectable.rb +28 -8
- data/lib/mongo/server/connection.rb +52 -10
- data/lib/mongo/server/connection_pool/queue.rb +15 -0
- data/lib/mongo/server/connection_pool.rb +12 -15
- data/lib/mongo/server/description/features.rb +4 -2
- data/lib/mongo/server/description.rb +39 -3
- data/lib/mongo/server/monitor/connection.rb +49 -28
- data/lib/mongo/server/monitor.rb +3 -14
- data/lib/mongo/server.rb +31 -4
- data/lib/mongo/server_selector/selectable.rb +58 -32
- data/lib/mongo/server_selector.rb +19 -10
- data/lib/mongo/socket/ssl.rb +4 -1
- data/lib/mongo/socket/tcp.rb +2 -2
- data/lib/mongo/socket/unix.rb +5 -8
- data/lib/mongo/socket.rb +11 -4
- data/lib/mongo/uri.rb +245 -139
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo/write_concern.rb +21 -6
- data/lib/mongo.rb +4 -4
- data/mongo.gemspec +1 -2
- data/spec/mongo/address/unix_spec.rb +1 -1
- data/spec/mongo/address_spec.rb +25 -0
- data/spec/mongo/auth/ldap/conversation_spec.rb +43 -0
- data/spec/mongo/auth/user/view_spec.rb +26 -1
- data/spec/mongo/bulk_write/ordered_combiner_spec.rb +284 -0
- data/spec/mongo/bulk_write/unordered_combiner_spec.rb +239 -0
- data/spec/mongo/bulk_write_spec.rb +385 -161
- data/spec/mongo/client_spec.rb +193 -23
- data/spec/mongo/cluster/topology/replica_set_spec.rb +2 -0
- data/spec/mongo/collection/view/aggregation_spec.rb +65 -0
- data/spec/mongo/collection/view/builder/find_command_spec.rb +167 -0
- data/spec/mongo/collection/view/builder/flags_spec.rb +106 -0
- data/spec/mongo/collection/view/builder/modifiers_spec.rb +210 -0
- data/spec/mongo/collection/view/builder/op_query_spec.rb +154 -0
- data/spec/mongo/collection/view/explainable_spec.rb +1 -2
- data/spec/mongo/collection/view/immutable_spec.rb +54 -0
- data/spec/mongo/collection/view/map_reduce_spec.rb +104 -9
- data/spec/mongo/collection/view/readable_spec.rb +109 -112
- data/spec/mongo/collection/view_spec.rb +119 -487
- data/spec/mongo/collection_spec.rb +1002 -33
- data/spec/mongo/command_monitoring_spec.rb +64 -0
- data/spec/mongo/connection_string_spec.rb +115 -0
- data/spec/mongo/cursor/builder/get_more_command_spec.rb +160 -0
- data/spec/mongo/cursor/builder/op_get_more_spec.rb +52 -0
- data/spec/mongo/cursor_spec.rb +10 -60
- data/spec/mongo/database_spec.rb +81 -12
- data/spec/mongo/dbref_spec.rb +4 -4
- data/spec/mongo/grid/file/chunk_spec.rb +6 -6
- data/spec/mongo/grid/file/{metadata_spec.rb → info_spec.rb} +29 -17
- data/spec/mongo/grid/file_spec.rb +8 -8
- data/spec/mongo/grid/fs_bucket_spec.rb +1020 -0
- data/spec/mongo/grid/stream/read_spec.rb +275 -0
- data/spec/mongo/grid/stream/write_spec.rb +440 -0
- data/spec/mongo/grid/stream_spec.rb +48 -0
- data/spec/mongo/gridfs_spec.rb +50 -0
- data/spec/mongo/index/view_spec.rb +41 -0
- data/spec/mongo/logger_spec.rb +0 -40
- data/spec/mongo/monitoring/command_log_subscriber_spec.rb +76 -0
- data/spec/mongo/monitoring/event/command_started_spec.rb +26 -0
- data/spec/mongo/monitoring/event/command_succeeded_spec.rb +26 -0
- data/spec/mongo/monitoring/event/secure_spec.rb +57 -0
- data/spec/mongo/operation/{aggregate → commands/aggregate}/result_spec.rb +1 -1
- data/spec/mongo/operation/commands/aggregate_spec.rb +69 -0
- data/spec/mongo/operation/{read → commands}/collections_info_spec.rb +1 -1
- data/spec/mongo/operation/{command_spec.rb → commands/command_spec.rb} +1 -19
- data/spec/mongo/operation/{read → commands}/indexes_spec.rb +1 -1
- data/spec/mongo/operation/{map_reduce_spec.rb → commands/map_reduce_spec.rb} +1 -19
- data/spec/mongo/operation/kill_cursors_spec.rb +1 -17
- data/spec/mongo/operation/read/get_more_spec.rb +0 -16
- data/spec/mongo/operation/read/query_spec.rb +19 -16
- data/spec/mongo/operation/{read_preferrable_spec.rb → read_preference_spec.rb} +11 -11
- data/spec/mongo/operation/result_spec.rb +19 -0
- data/spec/mongo/operation/write/bulk/{bulk_delete_spec.rb → delete_spec.rb} +17 -28
- data/spec/mongo/operation/write/bulk/{bulk_insert_spec.rb → insert_spec.rb} +1 -12
- data/spec/mongo/operation/write/bulk/{bulk_update_spec.rb → update_spec.rb} +7 -18
- data/spec/mongo/operation/write/command/delete_spec.rb +18 -9
- data/spec/mongo/operation/write/command/insert_spec.rb +18 -9
- data/spec/mongo/operation/write/command/update_spec.rb +18 -9
- data/spec/mongo/operation/write/delete_spec.rb +3 -3
- data/spec/mongo/operation/write/insert_spec.rb +0 -11
- data/spec/mongo/operation/write/update_spec.rb +6 -6
- data/spec/mongo/options/redacted_spec.rb +350 -0
- data/spec/mongo/protocol/delete_spec.rb +4 -4
- data/spec/mongo/protocol/get_more_spec.rb +4 -4
- data/spec/mongo/protocol/insert_spec.rb +3 -3
- data/spec/mongo/protocol/kill_cursors_spec.rb +8 -6
- data/spec/mongo/protocol/query_spec.rb +21 -7
- data/spec/mongo/protocol/update_spec.rb +5 -5
- data/spec/mongo/retryable_spec.rb +221 -0
- data/spec/mongo/server/connection_pool/queue_spec.rb +16 -0
- data/spec/mongo/server/connection_pool_spec.rb +42 -6
- data/spec/mongo/server/connection_spec.rb +86 -1
- data/spec/mongo/server/description/features_spec.rb +25 -0
- data/spec/mongo/server/description_spec.rb +42 -0
- data/spec/mongo/server/monitor_spec.rb +44 -0
- data/spec/mongo/server_discovery_and_monitoring_spec.rb +25 -59
- data/spec/mongo/server_selection_rtt_spec.rb +37 -57
- data/spec/mongo/server_selection_spec.rb +5 -3
- data/spec/mongo/server_selector/nearest_spec.rb +35 -27
- data/spec/mongo/server_selector/primary_preferred_spec.rb +32 -30
- data/spec/mongo/server_selector/primary_spec.rb +21 -14
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +28 -26
- data/spec/mongo/server_selector/secondary_spec.rb +24 -22
- data/spec/mongo/server_selector_spec.rb +87 -24
- data/spec/mongo/server_spec.rb +78 -15
- data/spec/mongo/socket/ssl_spec.rb +101 -57
- data/spec/mongo/socket/unix_spec.rb +52 -0
- data/spec/mongo/uri_spec.rb +271 -59
- data/spec/mongo/write_concern_spec.rb +126 -0
- data/spec/spec_helper.rb +29 -23
- data/spec/support/authorization.rb +4 -5
- data/spec/support/command_monitoring/bulkWrite.yml +73 -0
- data/spec/support/command_monitoring/command.yml +42 -0
- data/spec/support/command_monitoring/deleteMany.yml +55 -0
- data/spec/support/command_monitoring/deleteOne.yml +55 -0
- data/spec/support/command_monitoring/find.yml +268 -0
- data/spec/support/command_monitoring/insertMany.yml +81 -0
- data/spec/support/command_monitoring/insertOne.yml +51 -0
- data/spec/support/command_monitoring/updateMany.yml +67 -0
- data/spec/support/command_monitoring/updateOne.yml +95 -0
- data/spec/support/command_monitoring.rb +373 -0
- data/spec/support/connection_string.rb +228 -0
- data/spec/support/connection_string_tests/invalid-uris.yml +193 -0
- data/spec/support/connection_string_tests/valid-auth.yml +256 -0
- data/spec/support/connection_string_tests/valid-host_identifiers.yml +121 -0
- data/spec/support/connection_string_tests/valid-options.yml +30 -0
- data/spec/support/connection_string_tests/valid-unix_socket-absolute.yml +197 -0
- data/spec/support/connection_string_tests/valid-unix_socket-relative.yml +213 -0
- data/spec/support/connection_string_tests/valid-warnings.yml +55 -0
- data/spec/support/crud/read.rb +14 -10
- data/spec/support/crud/write.rb +36 -9
- data/spec/support/crud.rb +10 -2
- data/spec/support/gridfs.rb +637 -0
- data/spec/support/gridfs_tests/delete.yml +157 -0
- data/spec/support/gridfs_tests/download.yml +210 -0
- data/spec/support/gridfs_tests/download_by_name.yml +113 -0
- data/spec/support/gridfs_tests/upload.yml +158 -0
- data/spec/support/matchers.rb +2 -2
- data/spec/support/sdam/rs/equal_electionids.yml +1 -2
- data/spec/support/sdam/rs/new_primary_new_electionid.yml +0 -3
- data/spec/support/sdam/rs/primary_mismatched_me.yml +37 -0
- data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +75 -0
- data/spec/support/sdam/rs/rsother_discovered.yml +24 -3
- data/spec/support/sdam/rs/secondary_mismatched_me.yml +37 -0
- data/spec/support/sdam/rs/stepdown_change_set_name.yml +59 -0
- data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
- data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
- data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
- data/spec/support/sdam/single/not_ok_response.yml +0 -1
- data/spec/support/server_discovery_and_monitoring.rb +3 -1
- data/spec/support/server_selection.rb +3 -1
- data/spec/support/shared/bulk_write.rb +192 -0
- data/spec/support/shared/protocol.rb +5 -5
- data/spec/support/shared/server_selector.rb +78 -13
- data/spec/support/travis.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +211 -72
- metadata.gz.sig +0 -0
- data/lib/mongo/bulk_write/bulk_writable.rb +0 -252
- data/lib/mongo/bulk_write/deletable.rb +0 -57
- data/lib/mongo/bulk_write/insertable.rb +0 -49
- data/lib/mongo/bulk_write/replacable.rb +0 -58
- data/lib/mongo/bulk_write/updatable.rb +0 -69
- data/lib/mongo/grid/fs.rb +0 -146
- data/lib/mongo/operation/aggregate/result.rb +0 -103
- data/lib/mongo/operation/aggregate.rb +0 -108
- data/lib/mongo/operation/command.rb +0 -61
- data/lib/mongo/operation/map_reduce/result.rb +0 -122
- data/lib/mongo/operation/map_reduce.rb +0 -95
- data/lib/mongo/operation/parallel_scan/result.rb +0 -72
- data/lib/mongo/operation/parallel_scan.rb +0 -76
- data/lib/mongo/operation/write/bulk/bulk_delete/result.rb +0 -75
- data/lib/mongo/operation/write/bulk/bulk_delete.rb +0 -145
- data/lib/mongo/operation/write/bulk/bulk_insert/result.rb +0 -130
- data/lib/mongo/operation/write/bulk/bulk_insert.rb +0 -132
- data/lib/mongo/operation/write/bulk/bulk_mergable.rb +0 -67
- data/lib/mongo/operation/write/bulk/bulk_update/result.rb +0 -174
- data/lib/mongo/operation/write/bulk/bulk_update.rb +0 -154
- data/lib/mongo/operation/write/bulk/legacy_bulk_mergable.rb +0 -83
- data/spec/mongo/grid/fs_spec.rb +0 -160
- data/spec/mongo/loggable_spec.rb +0 -63
- data/spec/mongo/operation/aggregate_spec.rb +0 -127
@@ -0,0 +1,1020 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongo::Grid::FSBucket do
|
4
|
+
|
5
|
+
let(:fs) do
|
6
|
+
described_class.new(authorized_client.database, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:options) do
|
10
|
+
{ }
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:filename) do
|
14
|
+
'specs.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:file) do
|
18
|
+
File.open(__FILE__)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#initialize' do
|
22
|
+
|
23
|
+
it 'sets the files collection' do
|
24
|
+
expect(fs.files_collection.name).to eq('fs.files')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'sets the chunks collection' do
|
28
|
+
expect(fs.chunks_collection.name).to eq('fs.chunks')
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when options are provided' do
|
32
|
+
|
33
|
+
let(:fs) do
|
34
|
+
described_class.new(authorized_client.database, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when a write concern is set' do
|
38
|
+
|
39
|
+
context 'when the option :write is provided' do
|
40
|
+
|
41
|
+
let(:options) do
|
42
|
+
{ write: { w: 2 } }
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'sets the write concern' do
|
46
|
+
expect(fs.send(:write_concern).options).to eq(Mongo::WriteConcern.get(w: 2).options)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when a read preference is set' do
|
52
|
+
|
53
|
+
let(:options) do
|
54
|
+
{ read: { mode: :secondary, server_selection_timeout: 0.1 } }
|
55
|
+
end
|
56
|
+
|
57
|
+
let(:read_pref) do
|
58
|
+
Mongo::ServerSelector.get(Mongo::Options::Redacted.new(options[:read].merge(authorized_client.options)))
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'sets the read preference' do
|
62
|
+
expect(fs.send(:read_preference)).to eq(read_pref)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when a write stream is opened' do
|
67
|
+
|
68
|
+
let(:stream) do
|
69
|
+
fs.open_upload_stream('test.txt')
|
70
|
+
end
|
71
|
+
|
72
|
+
let(:fs) do
|
73
|
+
described_class.new(authorized_client.database, options)
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when a write option is specified' do
|
77
|
+
|
78
|
+
let(:options) do
|
79
|
+
{ write: { w: 2 } }
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'passes the write concern to the write stream' do
|
83
|
+
expect(stream.write_concern.options).to eq(Mongo::WriteConcern.get(options[:write]).options)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#find' do
|
91
|
+
|
92
|
+
let(:fs) do
|
93
|
+
described_class.new(authorized_client.database)
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'when there is no selector provided' do
|
97
|
+
|
98
|
+
let(:files) do
|
99
|
+
[
|
100
|
+
Mongo::Grid::File.new('hello world!', :filename => 'test.txt'),
|
101
|
+
Mongo::Grid::File.new('goodbye world!', :filename => 'test1.txt')
|
102
|
+
]
|
103
|
+
end
|
104
|
+
|
105
|
+
before do
|
106
|
+
files.each do |file|
|
107
|
+
fs.insert_one(file)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
after do
|
112
|
+
fs.files_collection.delete_many
|
113
|
+
fs.chunks_collection.delete_many
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'returns a collection view' do
|
117
|
+
expect(fs.find).to be_a(Mongo::Collection::View)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'iterates over the documents in the result' do
|
121
|
+
fs.find.each do |document|
|
122
|
+
expect(document).to_not be_nil
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'when provided a filter' do
|
128
|
+
|
129
|
+
let(:view) do
|
130
|
+
fs.find(filename: 'test.txt')
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'returns a collection view for the filter' do
|
134
|
+
expect(view.filter).to eq('filename' => 'test.txt')
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'when options are provided' do
|
139
|
+
|
140
|
+
let(:view) do
|
141
|
+
fs.find({filename: 'test.txt'}, options)
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'when provided batch_size' do
|
145
|
+
|
146
|
+
let(:options) do
|
147
|
+
{ batch_size: 5 }
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'sets the batch_size on the view' do
|
151
|
+
expect(view.batch_size).to eq(options[:batch_size])
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when provided limit' do
|
156
|
+
|
157
|
+
let(:options) do
|
158
|
+
{ limit: 5 }
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'sets the limit on the view' do
|
162
|
+
expect(view.limit).to eq(options[:limit])
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'when provided no_cursor_timeout' do
|
167
|
+
|
168
|
+
let(:options) do
|
169
|
+
{ no_cursor_timeout: true }
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'sets the no_cursor_timeout on the view' do
|
173
|
+
expect(view.options[:no_cursor_timeout]).to eq(options[:no_cursor_timeout])
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'when provided skip' do
|
178
|
+
|
179
|
+
let(:options) do
|
180
|
+
{ skip: 5 }
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'sets the skip on the view' do
|
184
|
+
expect(view.skip).to eq(options[:skip])
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'when provided sort' do
|
189
|
+
|
190
|
+
let(:options) do
|
191
|
+
{ sort: { 'x' => Mongo::Index::ASCENDING } }
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'sets the sort on the view' do
|
195
|
+
expect(view.sort).to eq(options[:sort])
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe '#find_one' do
|
202
|
+
|
203
|
+
let(:fs) do
|
204
|
+
described_class.new(authorized_client.database)
|
205
|
+
end
|
206
|
+
|
207
|
+
let(:file) do
|
208
|
+
Mongo::Grid::File.new('hello world!', :filename => 'test.txt')
|
209
|
+
end
|
210
|
+
|
211
|
+
before do
|
212
|
+
fs.insert_one(file)
|
213
|
+
end
|
214
|
+
|
215
|
+
after do
|
216
|
+
fs.files_collection.delete_many
|
217
|
+
fs.chunks_collection.delete_many
|
218
|
+
end
|
219
|
+
|
220
|
+
let(:from_db) do
|
221
|
+
fs.find_one(:filename => 'test.txt')
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'returns the assembled file from the db' do
|
225
|
+
expect(from_db.filename).to eq(file.info.filename)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe '#insert_one' do
|
230
|
+
|
231
|
+
let(:fs) do
|
232
|
+
described_class.new(authorized_client.database)
|
233
|
+
end
|
234
|
+
|
235
|
+
let(:file) do
|
236
|
+
Mongo::Grid::File.new('Hello!', :filename => 'test.txt')
|
237
|
+
end
|
238
|
+
|
239
|
+
context 'when inserting the file once' do
|
240
|
+
|
241
|
+
let!(:result) do
|
242
|
+
fs.insert_one(file)
|
243
|
+
end
|
244
|
+
|
245
|
+
after do
|
246
|
+
fs.files_collection.delete_many
|
247
|
+
fs.chunks_collection.delete_many
|
248
|
+
end
|
249
|
+
|
250
|
+
let(:from_db) do
|
251
|
+
fs.find_one(:filename => 'test.txt')
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'inserts the file into the database' do
|
255
|
+
expect(from_db.filename).to eq(file.info.filename)
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'includes the chunks and data with the file' do
|
259
|
+
expect(from_db.data).to eq('Hello!')
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'returns the file id' do
|
263
|
+
expect(result).to eq(file.id)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
context 'when the files collection is empty' do
|
268
|
+
|
269
|
+
before do
|
270
|
+
fs.files_collection.delete_many
|
271
|
+
fs.chunks_collection.delete_many
|
272
|
+
expect(fs.files_collection).to receive(:indexes).and_call_original
|
273
|
+
expect(fs.chunks_collection).to receive(:indexes).and_call_original
|
274
|
+
fs.insert_one(file)
|
275
|
+
end
|
276
|
+
|
277
|
+
after do
|
278
|
+
fs.files_collection.delete_many
|
279
|
+
fs.chunks_collection.delete_many
|
280
|
+
end
|
281
|
+
|
282
|
+
let(:chunks_index) do
|
283
|
+
fs.database[fs.chunks_collection.name].indexes.get(:files_id => 1, :n => 1)
|
284
|
+
end
|
285
|
+
|
286
|
+
let(:files_index) do
|
287
|
+
fs.database[fs.files_collection.name].indexes.get(:filename => 1, :uploadDate => 1)
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'creates an index on the files collection' do
|
291
|
+
expect(files_index[:name]).to eq('filename_1_uploadDate_1')
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'creates an index on the chunks collection' do
|
295
|
+
expect(chunks_index[:name]).to eq('files_id_1_n_1')
|
296
|
+
end
|
297
|
+
|
298
|
+
context 'when a write operation is called more than once' do
|
299
|
+
|
300
|
+
before do
|
301
|
+
expect(fs).not_to receive(:ensure_indexes!)
|
302
|
+
end
|
303
|
+
|
304
|
+
let(:file2) do
|
305
|
+
Mongo::Grid::File.new('Goodbye!', :filename => 'test2.txt')
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'only creates the indexes the first time' do
|
309
|
+
expect(fs.insert_one(file2)).to be_a(BSON::ObjectId)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
context 'when the index creation encounters an error', if: write_command_enabled? do
|
315
|
+
|
316
|
+
before do
|
317
|
+
fs.chunks_collection.drop
|
318
|
+
fs.chunks_collection.indexes.create_one(Mongo::Grid::FSBucket::CHUNKS_INDEX, :unique => false)
|
319
|
+
expect(fs.chunks_collection).to receive(:indexes).and_call_original
|
320
|
+
expect(fs.files_collection).not_to receive(:indexes)
|
321
|
+
end
|
322
|
+
|
323
|
+
after do
|
324
|
+
fs.database[fs.chunks_collection.name].indexes.drop_one('files_id_1_n_1')
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'raises the error to the user' do
|
328
|
+
expect {
|
329
|
+
fs.insert_one(file)
|
330
|
+
}.to raise_error(Mongo::Error::OperationFailure)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
context 'when the files collection is not empty' do
|
335
|
+
|
336
|
+
before do
|
337
|
+
fs.files_collection.insert_one(a: 1)
|
338
|
+
expect(fs.files_collection).not_to receive(:indexes)
|
339
|
+
expect(fs.chunks_collection).not_to receive(:indexes)
|
340
|
+
fs.insert_one(file)
|
341
|
+
end
|
342
|
+
|
343
|
+
after do
|
344
|
+
fs.files_collection.delete_many
|
345
|
+
fs.chunks_collection.delete_many
|
346
|
+
end
|
347
|
+
|
348
|
+
let(:files_index) do
|
349
|
+
fs.database[fs.files_collection.name].indexes.get(:filename => 1, :uploadDate => 1)
|
350
|
+
end
|
351
|
+
|
352
|
+
it 'assumes indexes already exist' do
|
353
|
+
expect(files_index[:name]).to eq('filename_1_uploadDate_1')
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
context 'when inserting the file more than once' do
|
358
|
+
|
359
|
+
after do
|
360
|
+
fs.files_collection.delete_many
|
361
|
+
fs.chunks_collection.delete_many
|
362
|
+
end
|
363
|
+
|
364
|
+
it 'raises an error' do
|
365
|
+
expect {
|
366
|
+
fs.insert_one(file)
|
367
|
+
fs.insert_one(file)
|
368
|
+
}.to raise_error(Mongo::Error::BulkWriteError)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
context 'when the file exceeds the max bson size' do
|
373
|
+
|
374
|
+
let(:fs) do
|
375
|
+
described_class.new(authorized_client.database)
|
376
|
+
end
|
377
|
+
|
378
|
+
let(:file) do
|
379
|
+
str = 'y' * 16777216
|
380
|
+
Mongo::Grid::File.new(str, :filename => 'large-file.txt')
|
381
|
+
end
|
382
|
+
|
383
|
+
before do
|
384
|
+
fs.insert_one(file)
|
385
|
+
end
|
386
|
+
|
387
|
+
after do
|
388
|
+
fs.files_collection.delete_many
|
389
|
+
fs.chunks_collection.delete_many
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'successfully inserts the file' do
|
393
|
+
expect(
|
394
|
+
fs.find_one(:filename => 'large-file.txt').chunks
|
395
|
+
).to eq(file.chunks)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
describe '#delete_one' do
|
401
|
+
|
402
|
+
let(:file) do
|
403
|
+
Mongo::Grid::File.new('Hello!', :filename => 'test.txt')
|
404
|
+
end
|
405
|
+
|
406
|
+
before do
|
407
|
+
fs.insert_one(file)
|
408
|
+
fs.delete_one(file)
|
409
|
+
end
|
410
|
+
|
411
|
+
let(:from_db) do
|
412
|
+
fs.find_one(:filename => 'test.txt')
|
413
|
+
end
|
414
|
+
|
415
|
+
it 'removes the file from the db' do
|
416
|
+
expect(from_db).to be_nil
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
describe '#delete' do
|
421
|
+
|
422
|
+
let(:file_id) do
|
423
|
+
fs.upload_from_stream(filename, file)
|
424
|
+
end
|
425
|
+
|
426
|
+
before do
|
427
|
+
fs.delete(file_id)
|
428
|
+
end
|
429
|
+
|
430
|
+
let(:from_db) do
|
431
|
+
fs.find_one(:filename => filename)
|
432
|
+
end
|
433
|
+
|
434
|
+
it 'removes the file from the db' do
|
435
|
+
expect(from_db).to be_nil
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
context 'when a read stream is opened' do
|
440
|
+
|
441
|
+
let(:fs) do
|
442
|
+
described_class.new(authorized_client.database)
|
443
|
+
end
|
444
|
+
|
445
|
+
let(:io) do
|
446
|
+
StringIO.new
|
447
|
+
end
|
448
|
+
|
449
|
+
after do
|
450
|
+
fs.files_collection.delete_many
|
451
|
+
fs.chunks_collection.delete_many
|
452
|
+
end
|
453
|
+
|
454
|
+
describe '#open_download_stream' do
|
455
|
+
|
456
|
+
let!(:file_id) do
|
457
|
+
fs.open_upload_stream(filename) do |stream|
|
458
|
+
stream.write(file)
|
459
|
+
end.file_id
|
460
|
+
end
|
461
|
+
|
462
|
+
context 'when a block is provided' do
|
463
|
+
|
464
|
+
let!(:stream) do
|
465
|
+
fs.open_download_stream(file_id) do |stream|
|
466
|
+
io.write(stream.read)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
it 'returns a Stream::Read object' do
|
471
|
+
expect(stream).to be_a(Mongo::Grid::FSBucket::Stream::Read)
|
472
|
+
end
|
473
|
+
|
474
|
+
it 'closes the stream after the block completes' do
|
475
|
+
expect(stream.closed?).to be(true)
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'yields the stream to the block' do
|
479
|
+
expect(io.size).to eq(file.size)
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
context 'when a block is not provided' do
|
484
|
+
|
485
|
+
let!(:stream) do
|
486
|
+
fs.open_download_stream(file_id)
|
487
|
+
end
|
488
|
+
|
489
|
+
it 'returns a Stream::Read object' do
|
490
|
+
expect(stream).to be_a(Mongo::Grid::FSBucket::Stream::Read)
|
491
|
+
end
|
492
|
+
|
493
|
+
it 'does not close the stream' do
|
494
|
+
expect(stream.closed?).to be(false)
|
495
|
+
end
|
496
|
+
|
497
|
+
it 'does not yield the stream to the block' do
|
498
|
+
expect(io.size).to eq(0)
|
499
|
+
end
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
describe '#download_to_stream' do
|
504
|
+
|
505
|
+
context 'when the file is found' do
|
506
|
+
|
507
|
+
let!(:file_id) do
|
508
|
+
fs.open_upload_stream(filename) do |stream|
|
509
|
+
stream.write(file)
|
510
|
+
end.file_id
|
511
|
+
end
|
512
|
+
|
513
|
+
before do
|
514
|
+
fs.download_to_stream(file_id, io)
|
515
|
+
end
|
516
|
+
|
517
|
+
it 'writes to the provided stream' do
|
518
|
+
expect(io.size).to eq(file.size)
|
519
|
+
end
|
520
|
+
|
521
|
+
it 'does not close the stream' do
|
522
|
+
expect(io.closed?).to be(false)
|
523
|
+
end
|
524
|
+
|
525
|
+
context 'when the file has length 0' do
|
526
|
+
|
527
|
+
let(:file) do
|
528
|
+
StringIO.new('')
|
529
|
+
end
|
530
|
+
|
531
|
+
let(:from_db) do
|
532
|
+
fs.open_upload_stream(filename) { |s| s.write(file) }
|
533
|
+
fs.find_one(:filename => filename)
|
534
|
+
end
|
535
|
+
|
536
|
+
it 'can read the file back' do
|
537
|
+
expect(from_db.data.size).to eq(file.size)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
542
|
+
context 'when there is no files collection document found' do
|
543
|
+
|
544
|
+
it 'raises an exception' do
|
545
|
+
expect{
|
546
|
+
fs.download_to_stream(BSON::ObjectId.new, io)
|
547
|
+
}.to raise_exception(Mongo::Error::FileNotFound)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
context 'when a file has an id that is not an ObjectId' do
|
552
|
+
|
553
|
+
before do
|
554
|
+
fs.insert_one(file)
|
555
|
+
fs.download_to_stream(file_id, io)
|
556
|
+
end
|
557
|
+
|
558
|
+
let(:file_id) do
|
559
|
+
'non-object-id'
|
560
|
+
end
|
561
|
+
|
562
|
+
let(:file) do
|
563
|
+
Mongo::Grid::File.new(File.open(__FILE__).read,
|
564
|
+
:filename => filename,
|
565
|
+
:_id => file_id)
|
566
|
+
end
|
567
|
+
|
568
|
+
it 'reads the file successfully' do
|
569
|
+
expect(io.size).to eq(file.data.size)
|
570
|
+
end
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
context 'when a read preference is specified' do
|
575
|
+
|
576
|
+
let(:fs) do
|
577
|
+
described_class.new(authorized_client.database, options)
|
578
|
+
end
|
579
|
+
|
580
|
+
let(:options) do
|
581
|
+
{ read: { mode: :secondary } }
|
582
|
+
end
|
583
|
+
|
584
|
+
let(:stream) do
|
585
|
+
fs.open_download_stream(BSON::ObjectId)
|
586
|
+
end
|
587
|
+
|
588
|
+
it 'sets the read preference on the Stream::Read object' do
|
589
|
+
expect(stream.read_preference).to eq(Mongo::ServerSelector.get(options[:read]))
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
describe '#download_to_stream_by_name' do
|
594
|
+
|
595
|
+
let(:files) do
|
596
|
+
[
|
597
|
+
StringIO.new('hello 1'),
|
598
|
+
StringIO.new('hello 2'),
|
599
|
+
StringIO.new('hello 3'),
|
600
|
+
StringIO.new('hello 4')
|
601
|
+
]
|
602
|
+
end
|
603
|
+
|
604
|
+
before do
|
605
|
+
files.each do |file|
|
606
|
+
fs.upload_from_stream('test.txt', file)
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
let(:io) do
|
611
|
+
StringIO.new
|
612
|
+
end
|
613
|
+
|
614
|
+
context 'when revision is not specified' do
|
615
|
+
|
616
|
+
let!(:result) do
|
617
|
+
fs.download_to_stream_by_name('test.txt', io)
|
618
|
+
end
|
619
|
+
|
620
|
+
it 'returns the most recent version' do
|
621
|
+
expect(io.string).to eq('hello 4')
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
context 'when revision is 0' do
|
626
|
+
|
627
|
+
let!(:result) do
|
628
|
+
fs.download_to_stream_by_name('test.txt', io, revision: 0)
|
629
|
+
end
|
630
|
+
|
631
|
+
it 'returns the original stored file' do
|
632
|
+
expect(io.string).to eq('hello 1')
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
context 'when revision is negative' do
|
637
|
+
|
638
|
+
let!(:result) do
|
639
|
+
fs.download_to_stream_by_name('test.txt', io, revision: -2)
|
640
|
+
end
|
641
|
+
|
642
|
+
it 'returns that number of versions from the most recent' do
|
643
|
+
expect(io.string).to eq('hello 3')
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
context 'when revision is positive' do
|
648
|
+
|
649
|
+
let!(:result) do
|
650
|
+
fs.download_to_stream_by_name('test.txt', io, revision: 1)
|
651
|
+
end
|
652
|
+
|
653
|
+
it 'returns that number revision' do
|
654
|
+
expect(io.string).to eq('hello 2')
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
context 'when the file revision is not found' do
|
659
|
+
|
660
|
+
it 'raises a FileNotFound error' do
|
661
|
+
expect {
|
662
|
+
fs.download_to_stream_by_name('test.txt', io, revision: 100)
|
663
|
+
}.to raise_exception(Mongo::Error::InvalidFileRevision)
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
667
|
+
context 'when the file is not found' do
|
668
|
+
|
669
|
+
it 'raises a FileNotFound error' do
|
670
|
+
expect {
|
671
|
+
fs.download_to_stream_by_name('non-existent.txt', io)
|
672
|
+
}.to raise_exception(Mongo::Error::FileNotFound)
|
673
|
+
end
|
674
|
+
end
|
675
|
+
end
|
676
|
+
|
677
|
+
describe '#open_download_stream_by_name' do
|
678
|
+
|
679
|
+
let(:files) do
|
680
|
+
[
|
681
|
+
StringIO.new('hello 1'),
|
682
|
+
StringIO.new('hello 2'),
|
683
|
+
StringIO.new('hello 3'),
|
684
|
+
StringIO.new('hello 4')
|
685
|
+
]
|
686
|
+
end
|
687
|
+
|
688
|
+
before do
|
689
|
+
files.each do |file|
|
690
|
+
fs.upload_from_stream('test.txt', file)
|
691
|
+
end
|
692
|
+
end
|
693
|
+
|
694
|
+
let(:io) do
|
695
|
+
StringIO.new
|
696
|
+
end
|
697
|
+
|
698
|
+
context 'when a block is provided' do
|
699
|
+
|
700
|
+
let(:stream) do
|
701
|
+
fs.open_download_stream_by_name('test.txt') do |stream|
|
702
|
+
io.write(stream.read)
|
703
|
+
end
|
704
|
+
end
|
705
|
+
|
706
|
+
it 'returns a Stream::Read object' do
|
707
|
+
expect(stream).to be_a(Mongo::Grid::FSBucket::Stream::Read)
|
708
|
+
end
|
709
|
+
|
710
|
+
it 'closes the stream after the block completes' do
|
711
|
+
expect(stream.closed?).to be(true)
|
712
|
+
end
|
713
|
+
|
714
|
+
it 'yields the stream to the block' do
|
715
|
+
stream
|
716
|
+
expect(io.size).to eq(files[0].size)
|
717
|
+
end
|
718
|
+
|
719
|
+
context 'when revision is not specified' do
|
720
|
+
|
721
|
+
let!(:result) do
|
722
|
+
fs.open_download_stream_by_name('test.txt') do |stream|
|
723
|
+
io.write(stream.read)
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
it 'returns the most recent version' do
|
728
|
+
expect(io.string).to eq('hello 4')
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
732
|
+
context 'when revision is 0' do
|
733
|
+
|
734
|
+
let!(:result) do
|
735
|
+
fs.open_download_stream_by_name('test.txt', revision: 0) do |stream|
|
736
|
+
io.write(stream.read)
|
737
|
+
end
|
738
|
+
end
|
739
|
+
|
740
|
+
it 'returns the original stored file' do
|
741
|
+
expect(io.string).to eq('hello 1')
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
745
|
+
context 'when revision is negative' do
|
746
|
+
|
747
|
+
let!(:result) do
|
748
|
+
fs.open_download_stream_by_name('test.txt', revision: -2) do |stream|
|
749
|
+
io.write(stream.read)
|
750
|
+
end
|
751
|
+
end
|
752
|
+
|
753
|
+
it 'returns that number of versions from the most recent' do
|
754
|
+
expect(io.string).to eq('hello 3')
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
758
|
+
context 'when revision is positive' do
|
759
|
+
|
760
|
+
let!(:result) do
|
761
|
+
fs.open_download_stream_by_name('test.txt', revision: 1) do |stream|
|
762
|
+
io.write(stream.read)
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
766
|
+
it 'returns that number revision' do
|
767
|
+
expect(io.string).to eq('hello 2')
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
context 'when the file revision is not found' do
|
772
|
+
|
773
|
+
it 'raises a FileNotFound error' do
|
774
|
+
expect {
|
775
|
+
fs.open_download_stream_by_name('test.txt', revision: 100)
|
776
|
+
}.to raise_exception(Mongo::Error::InvalidFileRevision)
|
777
|
+
end
|
778
|
+
end
|
779
|
+
|
780
|
+
context 'when the file is not found' do
|
781
|
+
|
782
|
+
it 'raises a FileNotFound error' do
|
783
|
+
expect {
|
784
|
+
fs.open_download_stream_by_name('non-existent.txt')
|
785
|
+
}.to raise_exception(Mongo::Error::FileNotFound)
|
786
|
+
end
|
787
|
+
end
|
788
|
+
end
|
789
|
+
|
790
|
+
context 'when a block is not provided' do
|
791
|
+
|
792
|
+
let!(:stream) do
|
793
|
+
fs.open_download_stream_by_name('test.txt')
|
794
|
+
end
|
795
|
+
|
796
|
+
it 'returns a Stream::Read object' do
|
797
|
+
expect(stream).to be_a(Mongo::Grid::FSBucket::Stream::Read)
|
798
|
+
end
|
799
|
+
|
800
|
+
it 'does not close the stream' do
|
801
|
+
expect(stream.closed?).to be(false)
|
802
|
+
end
|
803
|
+
|
804
|
+
it 'does not yield the stream to the block' do
|
805
|
+
expect(io.size).to eq(0)
|
806
|
+
end
|
807
|
+
end
|
808
|
+
end
|
809
|
+
end
|
810
|
+
|
811
|
+
context 'when a write stream is opened' do
|
812
|
+
|
813
|
+
let(:stream) do
|
814
|
+
fs.open_upload_stream(filename)
|
815
|
+
end
|
816
|
+
|
817
|
+
after do
|
818
|
+
fs.files_collection.delete_many
|
819
|
+
fs.chunks_collection.delete_many
|
820
|
+
end
|
821
|
+
|
822
|
+
describe '#open_upload_stream' do
|
823
|
+
|
824
|
+
context 'when a block is not provided' do
|
825
|
+
|
826
|
+
it 'returns a Stream::Write object' do
|
827
|
+
expect(stream).to be_a(Mongo::Grid::FSBucket::Stream::Write)
|
828
|
+
end
|
829
|
+
|
830
|
+
it 'creates an ObjectId for the file' do
|
831
|
+
expect(stream.file_id).to be_a(BSON::ObjectId)
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
835
|
+
context 'when a block is provided' do
|
836
|
+
|
837
|
+
let!(:stream) do
|
838
|
+
fs.open_upload_stream(filename) do |stream|
|
839
|
+
stream.write(file)
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
let(:result) do
|
844
|
+
fs.find_one(filename: filename)
|
845
|
+
end
|
846
|
+
|
847
|
+
it 'returns the stream' do
|
848
|
+
expect(stream).to be_a(Mongo::Grid::FSBucket::Stream::Write)
|
849
|
+
end
|
850
|
+
|
851
|
+
it 'creates an ObjectId for the file' do
|
852
|
+
expect(stream.file_id).to be_a(BSON::ObjectId)
|
853
|
+
end
|
854
|
+
|
855
|
+
it 'yields the stream to the block' do
|
856
|
+
expect(result.data.size).to eq(file.size)
|
857
|
+
end
|
858
|
+
|
859
|
+
it 'closes the stream when the block completes' do
|
860
|
+
expect(stream.closed?).to be(true)
|
861
|
+
end
|
862
|
+
end
|
863
|
+
end
|
864
|
+
|
865
|
+
describe '#upload_from_stream' do
|
866
|
+
|
867
|
+
let!(:result) do
|
868
|
+
fs.upload_from_stream(filename, file)
|
869
|
+
end
|
870
|
+
|
871
|
+
let(:file_from_db) do
|
872
|
+
fs.find_one(:filename => filename)
|
873
|
+
end
|
874
|
+
|
875
|
+
it 'writes to the provided stream' do
|
876
|
+
expect(file_from_db.data.length).to eq(file.size)
|
877
|
+
end
|
878
|
+
|
879
|
+
it 'does not close the stream' do
|
880
|
+
expect(file.closed?).to be(false)
|
881
|
+
end
|
882
|
+
|
883
|
+
it 'returns the id of the file' do
|
884
|
+
expect(result).to be_a(BSON::ObjectId)
|
885
|
+
end
|
886
|
+
|
887
|
+
context 'when the io stream raises an error' do
|
888
|
+
|
889
|
+
let(:stream) do
|
890
|
+
fs.open_upload_stream(filename)
|
891
|
+
end
|
892
|
+
|
893
|
+
before do
|
894
|
+
allow(fs).to receive(:open_upload_stream).and_yield(stream)
|
895
|
+
end
|
896
|
+
|
897
|
+
context 'when stream#abort does not raise an OperationFailure' do
|
898
|
+
|
899
|
+
before do
|
900
|
+
expect(stream).to receive(:abort).and_call_original
|
901
|
+
file.close
|
902
|
+
end
|
903
|
+
|
904
|
+
it 'raises the original IOError' do
|
905
|
+
expect {
|
906
|
+
fs.upload_from_stream(filename, file)
|
907
|
+
}.to raise_exception(IOError)
|
908
|
+
end
|
909
|
+
end
|
910
|
+
|
911
|
+
context 'when stream#abort raises an OperationFailure' do
|
912
|
+
|
913
|
+
before do
|
914
|
+
allow(stream).to receive(:abort).and_raise(Mongo::Error::OperationFailure)
|
915
|
+
file.close
|
916
|
+
end
|
917
|
+
|
918
|
+
it 'raises the original IOError' do
|
919
|
+
expect {
|
920
|
+
fs.upload_from_stream(filename, file)
|
921
|
+
}.to raise_exception(IOError)
|
922
|
+
end
|
923
|
+
end
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
context 'when options are provided when opening the write stream' do
|
928
|
+
|
929
|
+
let(:stream) do
|
930
|
+
fs.open_upload_stream(filename, stream_options)
|
931
|
+
end
|
932
|
+
|
933
|
+
context 'when a write option is specified' do
|
934
|
+
|
935
|
+
let(:stream_options) do
|
936
|
+
{ write: { w: 2 } }
|
937
|
+
end
|
938
|
+
|
939
|
+
it 'sets the write concern on the write stream' do
|
940
|
+
expect(stream.write_concern.options).to eq(Mongo::WriteConcern.get(stream_options[:write]).options)
|
941
|
+
end
|
942
|
+
end
|
943
|
+
|
944
|
+
context 'when there is a chunk size set on the FSBucket' do
|
945
|
+
|
946
|
+
let(:stream_options) do
|
947
|
+
{ }
|
948
|
+
end
|
949
|
+
|
950
|
+
let(:options) do
|
951
|
+
{ chunk_size: 100 }
|
952
|
+
end
|
953
|
+
|
954
|
+
it 'sets the chunk size as the default on the write stream' do
|
955
|
+
expect(stream.options[:chunk_size]).to eq(options[:chunk_size])
|
956
|
+
end
|
957
|
+
end
|
958
|
+
|
959
|
+
context 'when a chunk size option is specified' do
|
960
|
+
|
961
|
+
let(:stream_options) do
|
962
|
+
{ chunk_size: 50 }
|
963
|
+
end
|
964
|
+
|
965
|
+
it 'sets the chunk size on the write stream' do
|
966
|
+
expect(stream.options[:chunk_size]).to eq(stream_options[:chunk_size])
|
967
|
+
end
|
968
|
+
|
969
|
+
context 'when there is a chunk size set on the FSBucket' do
|
970
|
+
|
971
|
+
let(:options) do
|
972
|
+
{ chunk_size: 100 }
|
973
|
+
end
|
974
|
+
|
975
|
+
let(:fs) do
|
976
|
+
described_class.new(authorized_client.database, options)
|
977
|
+
end
|
978
|
+
|
979
|
+
it 'uses the chunk size set on the write stream' do
|
980
|
+
expect(stream.options[:chunk_size]).to eq(stream_options[:chunk_size])
|
981
|
+
end
|
982
|
+
|
983
|
+
end
|
984
|
+
end
|
985
|
+
|
986
|
+
context 'when a file metadata option is specified' do
|
987
|
+
|
988
|
+
let(:stream_options) do
|
989
|
+
{ metadata: { some_field: 1 } }
|
990
|
+
end
|
991
|
+
|
992
|
+
it 'sets the file metadata option on the write stream' do
|
993
|
+
expect(stream.options[:metadata]).to eq(stream_options[:metadata])
|
994
|
+
end
|
995
|
+
end
|
996
|
+
|
997
|
+
context 'when a content type option is specified' do
|
998
|
+
|
999
|
+
let(:stream_options) do
|
1000
|
+
{ content_type: 'text/plain' }
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
it 'sets the content type on the write stream' do
|
1004
|
+
expect(stream.options[:content_type]).to eq(stream_options[:content_type])
|
1005
|
+
end
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
context 'when a aliases option is specified' do
|
1009
|
+
|
1010
|
+
let(:stream_options) do
|
1011
|
+
{ aliases: [ 'another-name.txt' ] }
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
it 'sets the alias option on the write stream' do
|
1015
|
+
expect(stream.options[:aliases]).to eq(stream_options[:aliases])
|
1016
|
+
end
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
end
|