mongo 2.1.0.beta → 2.1.0.rc0
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.tar.gz.sig +0 -0
- data/Rakefile +2 -2
- data/lib/mongo.rb +2 -3
- data/lib/mongo/address.rb +7 -5
- data/lib/mongo/address/unix.rb +2 -2
- data/lib/mongo/auth/ldap/conversation.rb +6 -2
- data/lib/mongo/auth/scram/conversation.rb +8 -2
- data/lib/mongo/auth/user/view.rb +21 -0
- data/lib/mongo/bulk_write.rb +155 -23
- 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 +117 -0
- data/lib/mongo/bulk_write/unordered_combiner.rb +52 -0
- data/lib/mongo/bulk_write/validatable.rb +62 -0
- data/lib/mongo/client.rb +7 -3
- data/lib/mongo/cluster.rb +3 -3
- data/lib/mongo/cluster/topology/replica_set.rb +8 -6
- data/lib/mongo/cluster/topology/unknown.rb +5 -2
- data/lib/mongo/collection.rb +75 -4
- data/lib/mongo/collection/view.rb +1 -2
- data/lib/mongo/collection/view/aggregation.rb +13 -8
- data/lib/mongo/collection/view/immutable.rb +6 -6
- data/lib/mongo/collection/view/iterable.rb +13 -4
- data/lib/mongo/collection/view/map_reduce.rb +22 -17
- data/lib/mongo/collection/view/readable.rb +121 -70
- data/lib/mongo/cursor.rb +5 -1
- data/lib/mongo/database.rb +3 -3
- data/lib/mongo/database/view.rb +1 -1
- data/lib/mongo/error.rb +7 -0
- 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/missing_file_chunk.rb +38 -0
- data/lib/mongo/error/operation_failure.rb +1 -1
- data/lib/mongo/error/unchangeable_collection_option.rb +38 -0
- data/lib/mongo/error/unexpected_chunk_length.rb +39 -0
- data/lib/mongo/grid.rb +2 -1
- data/lib/mongo/grid/file.rb +12 -9
- data/lib/mongo/grid/file/chunk.rb +6 -6
- data/lib/mongo/grid/file/{metadata.rb → info.rb} +41 -39
- data/lib/mongo/grid/fs_bucket.rb +441 -0
- data/lib/mongo/grid/stream.rb +64 -0
- data/lib/mongo/grid/stream/read.rb +208 -0
- data/lib/mongo/grid/stream/write.rb +187 -0
- data/lib/mongo/index/view.rb +1 -1
- data/lib/mongo/loggable.rb +34 -57
- data/lib/mongo/logger.rb +16 -78
- data/lib/mongo/monitoring.rb +1 -5
- data/lib/mongo/monitoring/command_log_subscriber.rb +35 -17
- data/lib/mongo/monitoring/event/command_succeeded.rb +20 -1
- data/lib/mongo/monitoring/publishable.rb +22 -12
- data/lib/mongo/operation.rb +3 -6
- data/lib/mongo/operation/commands.rb +24 -0
- data/lib/mongo/operation/{aggregate.rb → commands/aggregate.rb} +3 -41
- data/lib/mongo/operation/{aggregate → commands/aggregate}/result.rb +0 -0
- data/lib/mongo/operation/commands/collections_info.rb +66 -0
- data/lib/mongo/operation/{command.rb → commands/command.rb} +2 -18
- data/lib/mongo/operation/commands/indexes.rb +70 -0
- data/lib/mongo/operation/commands/list_collections.rb +54 -0
- data/lib/mongo/operation/commands/list_collections/result.rb +112 -0
- data/lib/mongo/operation/commands/list_indexes.rb +56 -0
- data/lib/mongo/operation/commands/list_indexes/result.rb +115 -0
- data/lib/mongo/operation/{map_reduce.rb → commands/map_reduce.rb} +3 -41
- data/lib/mongo/operation/{map_reduce → commands/map_reduce}/result.rb +0 -0
- data/lib/mongo/operation/{parallel_scan.rb → commands/parallel_scan.rb} +3 -23
- data/lib/mongo/operation/{parallel_scan → commands/parallel_scan}/result.rb +0 -0
- data/lib/mongo/operation/commands/user_query.rb +69 -0
- data/lib/mongo/operation/commands/users_info.rb +53 -0
- data/lib/mongo/operation/commands/users_info/result.rb +36 -0
- data/lib/mongo/operation/executable.rb +4 -68
- data/lib/mongo/operation/kill_cursors.rb +3 -3
- data/lib/mongo/operation/read.rb +0 -4
- data/lib/mongo/operation/read/get_more.rb +2 -22
- data/lib/mongo/operation/read/query.rb +2 -21
- data/lib/mongo/operation/{read_preferrable.rb → read_preference.rb} +3 -2
- data/lib/mongo/operation/specifiable.rb +24 -0
- data/lib/mongo/operation/write.rb +2 -0
- data/lib/mongo/operation/write/bulk.rb +6 -3
- data/lib/mongo/operation/write/bulk/bulkable.rb +82 -0
- data/lib/mongo/operation/write/bulk/delete.rb +71 -0
- data/lib/mongo/operation/write/bulk/delete/result.rb +74 -0
- data/lib/mongo/operation/write/bulk/insert.rb +96 -0
- data/lib/mongo/operation/write/bulk/insert/result.rb +129 -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.rb +81 -0
- data/lib/mongo/operation/write/bulk/update/result.rb +174 -0
- 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 +0 -1
- data/lib/mongo/operation/write/command/drop_index.rb +0 -1
- data/lib/mongo/operation/write/command/insert.rb +0 -1
- data/lib/mongo/operation/write/command/remove_user.rb +0 -1
- data/lib/mongo/operation/write/command/update.rb +0 -1
- 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 +5 -28
- data/lib/mongo/operation/write/drop_index.rb +3 -3
- data/lib/mongo/operation/write/gle.rb +48 -0
- data/lib/mongo/operation/write/idable.rb +5 -0
- 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 +4 -32
- data/lib/mongo/operation/write/update_user.rb +4 -30
- data/lib/mongo/operation/write/write_command_enabled.rb +53 -0
- data/lib/mongo/options/mapper.rb +4 -2
- data/lib/mongo/protocol/delete.rb +68 -3
- data/lib/mongo/protocol/get_more.rb +54 -2
- data/lib/mongo/protocol/insert.rb +59 -1
- data/lib/mongo/protocol/kill_cursors.rb +53 -4
- data/lib/mongo/protocol/message.rb +12 -12
- data/lib/mongo/protocol/query.rb +139 -65
- data/lib/mongo/protocol/reply.rb +69 -1
- data/lib/mongo/protocol/update.rb +70 -1
- data/lib/mongo/server/connection.rb +11 -3
- data/lib/mongo/server/description.rb +29 -0
- data/lib/mongo/server/description/features.rb +2 -1
- data/lib/mongo/server/monitor.rb +2 -2
- data/lib/mongo/server_selector.rb +14 -10
- data/lib/mongo/server_selector/selectable.rb +24 -22
- data/lib/mongo/socket.rb +6 -3
- data/lib/mongo/socket/tcp.rb +2 -2
- data/lib/mongo/socket/unix.rb +5 -8
- data/lib/mongo/uri.rb +243 -139
- data/lib/mongo/version.rb +1 -1
- 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 +271 -0
- data/spec/mongo/bulk_write/unordered_combiner_spec.rb +239 -0
- data/spec/mongo/bulk_write_spec.rb +332 -166
- data/spec/mongo/client_spec.rb +25 -0
- 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/immutable_spec.rb +103 -0
- data/spec/mongo/collection/view/map_reduce_spec.rb +98 -3
- data/spec/mongo/collection/view/readable_spec.rb +17 -30
- data/spec/mongo/collection/view_spec.rb +233 -7
- data/spec/mongo/collection_spec.rb +360 -18
- data/spec/mongo/command_monitoring_spec.rb +51 -0
- data/spec/mongo/connection_string_spec.rb +137 -0
- data/spec/mongo/database_spec.rb +27 -11
- data/spec/mongo/grid/file/chunk_spec.rb +5 -5
- 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/logger_spec.rb +0 -40
- data/spec/mongo/monitoring/command_log_subscriber_spec.rb +76 -0
- data/spec/mongo/operation/{aggregate_spec.rb → commands/aggregate_spec.rb} +0 -42
- data/spec/mongo/operation/{read → commands}/collections_info_spec.rb +1 -1
- data/spec/mongo/operation/{command_spec.rb → commands/command_spec.rb} +0 -0
- data/spec/mongo/operation/{read → commands}/indexes_spec.rb +1 -1
- data/spec/mongo/operation/{map_reduce_spec.rb → commands/map_reduce_spec.rb} +0 -18
- data/spec/mongo/operation/kill_cursors_spec.rb +1 -1
- data/spec/mongo/operation/{read_preferrable_spec.rb → read_preference_spec.rb} +11 -11
- data/spec/mongo/operation/write/bulk/{bulk_delete_spec.rb → delete_spec.rb} +1 -12
- 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} +1 -12
- data/spec/mongo/operation/write/insert_spec.rb +0 -11
- data/spec/mongo/protocol/kill_cursors_spec.rb +5 -3
- data/spec/mongo/server/description_spec.rb +42 -0
- data/spec/mongo/server/monitor_spec.rb +21 -0
- data/spec/mongo/server_discovery_and_monitoring_spec.rb +1 -0
- data/spec/mongo/server_selection_spec.rb +3 -3
- data/spec/mongo/server_selector/nearest_spec.rb +34 -27
- data/spec/mongo/server_selector/primary_preferred_spec.rb +31 -30
- data/spec/mongo/server_selector/primary_spec.rb +14 -13
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +27 -26
- data/spec/mongo/server_selector/secondary_spec.rb +23 -22
- data/spec/mongo/server_selector_spec.rb +87 -24
- data/spec/mongo/socket/unix_spec.rb +52 -0
- data/spec/mongo/uri_spec.rb +251 -39
- data/spec/spec_helper.rb +11 -4
- data/spec/support/authorization.rb +4 -5
- data/spec/support/command_monitoring.rb +365 -0
- 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 +219 -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/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.rb +3 -1
- data/spec/support/crud/read.rb +14 -10
- data/spec/support/crud/write.rb +36 -9
- 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/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/secondary_mismatched_me.yml +37 -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/server_selector.rb +21 -12
- metadata +147 -57
- 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/list_collections/result.rb +0 -114
- data/lib/mongo/operation/list_indexes/result.rb +0 -118
- data/lib/mongo/operation/read/collections_info.rb +0 -68
- data/lib/mongo/operation/read/indexes.rb +0 -69
- data/lib/mongo/operation/read/list_collections.rb +0 -76
- data/lib/mongo/operation/read/list_indexes.rb +0 -78
- data/lib/mongo/operation/write/bulk/bulk_delete.rb +0 -145
- data/lib/mongo/operation/write/bulk/bulk_delete/result.rb +0 -75
- data/lib/mongo/operation/write/bulk/bulk_insert.rb +0 -132
- data/lib/mongo/operation/write/bulk/bulk_insert/result.rb +0 -130
- data/lib/mongo/operation/write/bulk/bulk_mergable.rb +0 -67
- data/lib/mongo/operation/write/bulk/bulk_update.rb +0 -154
- data/lib/mongo/operation/write/bulk/bulk_update/result.rb +0 -174
- 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
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongo::Grid::FSBucket::Stream::Read do
|
4
|
+
|
5
|
+
let(:fs_options) do
|
6
|
+
{ }
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:fs) do
|
10
|
+
authorized_client.database.fs(fs_options)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:options) do
|
14
|
+
{ file_id: file_id }
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:filename) do
|
18
|
+
'specs.rb'
|
19
|
+
end
|
20
|
+
|
21
|
+
let!(:file_id) do
|
22
|
+
fs.upload_from_stream(filename, File.open(__FILE__))
|
23
|
+
end
|
24
|
+
|
25
|
+
after do
|
26
|
+
fs.files_collection.delete_many
|
27
|
+
fs.chunks_collection.delete_many
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:stream) do
|
31
|
+
described_class.new(fs, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#initialize' do
|
35
|
+
|
36
|
+
it 'sets the file id' do
|
37
|
+
expect(stream.file_id).to eq(file_id)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'sets the fs object' do
|
41
|
+
expect(stream.fs).to eq(fs)
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when there is a read preference set on the FSBucket' do
|
45
|
+
|
46
|
+
let(:fs_options) do
|
47
|
+
{ read: { mode: :secondary } }
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'uses the read preference of the fs as a default' do
|
51
|
+
expect(stream.read_preference).to eq(fs.read_preference)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'opens a stream' do
|
56
|
+
expect(stream.close).to eq(file_id)
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when provided options' do
|
60
|
+
|
61
|
+
context 'when provided read preference' do
|
62
|
+
|
63
|
+
let(:options) do
|
64
|
+
{
|
65
|
+
file_id: file_id,
|
66
|
+
read: { mode: :primary_preferred }
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'sets the read preference' do
|
71
|
+
expect(stream.read_preference).to eq(Mongo::ServerSelector.get(options[:read]))
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'sets the read preference on the view' do
|
75
|
+
expect(stream.send(:view).read).to eq(Mongo::ServerSelector.get(options[:read]))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when provided a file_id' do
|
80
|
+
|
81
|
+
it 'sets the file id' do
|
82
|
+
expect(stream.file_id).to eq(options[:file_id])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#each' do
|
89
|
+
|
90
|
+
let(:filename) do
|
91
|
+
'specs.rb'
|
92
|
+
end
|
93
|
+
|
94
|
+
let!(:file_id) do
|
95
|
+
fs.upload_from_stream(filename, File.open(__FILE__))
|
96
|
+
end
|
97
|
+
|
98
|
+
after do
|
99
|
+
fs.files_collection.delete_many
|
100
|
+
fs.chunks_collection.delete_many
|
101
|
+
end
|
102
|
+
|
103
|
+
let(:fs_options) do
|
104
|
+
{ chunk_size: 5 }
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'iterates over all the chunks of the file' do
|
108
|
+
stream.each do |chunk|
|
109
|
+
expect(chunk).not_to be(nil)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when the stream is closed' do
|
114
|
+
|
115
|
+
before do
|
116
|
+
stream.close
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'does not allow further iteration' do
|
120
|
+
expect {
|
121
|
+
stream.to_a
|
122
|
+
}.to raise_error(Mongo::Error::ClosedStream)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when a chunk is found out of order' do
|
127
|
+
|
128
|
+
before do
|
129
|
+
view = stream.fs.chunks_collection.find({ :files_id => file_id }, options).sort(:n => -1)
|
130
|
+
stream.instance_variable_set(:@view, view)
|
131
|
+
expect(stream).to receive(:close)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'raises an exception' do
|
135
|
+
expect {
|
136
|
+
stream.to_a
|
137
|
+
}.to raise_error(Mongo::Error::MissingFileChunk)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'closes the query' do
|
141
|
+
begin
|
142
|
+
stream.to_a
|
143
|
+
rescue Mongo::Error::MissingFileChunk
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'when a chunk does not have the expected length' do
|
149
|
+
|
150
|
+
before do
|
151
|
+
stream.send(:file_info)
|
152
|
+
stream.instance_variable_get(:@file_info).document['chunkSize'] = 4
|
153
|
+
expect(stream).to receive(:close)
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'raises an exception' do
|
157
|
+
expect {
|
158
|
+
stream.to_a
|
159
|
+
}.to raise_error(Mongo::Error::UnexpectedChunkLength)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'closes the query' do
|
163
|
+
begin
|
164
|
+
stream.to_a
|
165
|
+
rescue Mongo::Error::UnexpectedChunkLength
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'when there is no files document found' do
|
171
|
+
|
172
|
+
before do
|
173
|
+
fs.files_collection.delete_many
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'raises an Exception' do
|
177
|
+
expect{
|
178
|
+
stream.to_a
|
179
|
+
}.to raise_exception(Mongo::Error::FileNotFound)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe '#read' do
|
185
|
+
|
186
|
+
let(:filename) do
|
187
|
+
'specs.rb'
|
188
|
+
end
|
189
|
+
|
190
|
+
let(:file) do
|
191
|
+
File.open(__FILE__)
|
192
|
+
end
|
193
|
+
|
194
|
+
let(:file_id) do
|
195
|
+
fs.upload_from_stream(filename, file)
|
196
|
+
end
|
197
|
+
|
198
|
+
after do
|
199
|
+
fs.files_collection.delete_many
|
200
|
+
fs.chunks_collection.delete_many
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'returns a string of all data' do
|
204
|
+
expect(stream.read.size).to eq(file.size)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe '#file_info' do
|
209
|
+
|
210
|
+
it 'returns a files information document' do
|
211
|
+
expect(stream.file_info).to be_a(Mongo::Grid::File::Info)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe '#close' do
|
216
|
+
|
217
|
+
let(:view) do
|
218
|
+
stream.instance_variable_get(:@view)
|
219
|
+
end
|
220
|
+
|
221
|
+
before do
|
222
|
+
stream.to_a
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'returns the file id' do
|
226
|
+
expect(stream.close).to eq(file_id)
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'when the stream is closed' do
|
230
|
+
|
231
|
+
before do
|
232
|
+
stream.to_a
|
233
|
+
expect(view).to receive(:close_query).and_call_original
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'calls close_query on the view' do
|
237
|
+
expect(stream.close).to be_a(BSON::ObjectId)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context 'when the stream is already closed' do
|
242
|
+
|
243
|
+
before do
|
244
|
+
stream.close
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'raises an exception' do
|
248
|
+
expect {
|
249
|
+
stream.close
|
250
|
+
}.to raise_error(Mongo::Error::ClosedStream)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
describe '#closed?' do
|
256
|
+
|
257
|
+
context 'when the stream is closed' do
|
258
|
+
|
259
|
+
before do
|
260
|
+
stream.close
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'returns true' do
|
264
|
+
expect(stream.closed?).to be(true)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
context 'when the stream is still open' do
|
269
|
+
|
270
|
+
it 'returns false' do
|
271
|
+
expect(stream.closed?).to be(false)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,440 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongo::Grid::FSBucket::Stream::Write do
|
4
|
+
|
5
|
+
let(:file) do
|
6
|
+
File.open(__FILE__)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:file2) do
|
10
|
+
File.open(__FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:fs_options) do
|
14
|
+
{ }
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:fs) do
|
18
|
+
authorized_client.database.fs(fs_options)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:filename) do
|
22
|
+
'specs.rb'
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:extra_options) do
|
26
|
+
{ }
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:options) do
|
30
|
+
{ filename: filename }.merge(extra_options)
|
31
|
+
end
|
32
|
+
|
33
|
+
after do
|
34
|
+
fs.files_collection.delete_many
|
35
|
+
fs.chunks_collection.delete_many
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:stream) do
|
39
|
+
described_class.new(fs, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#initialize' do
|
43
|
+
|
44
|
+
it 'sets the file id' do
|
45
|
+
expect(stream.file_id).to be_a(BSON::ObjectId)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'sets the fs object' do
|
49
|
+
expect(stream.fs).to eq(fs)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'opens a stream' do
|
53
|
+
expect(stream.close).to be_a(BSON::ObjectId)
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when the fs has a write concern', if: standalone? do
|
57
|
+
|
58
|
+
let(:fs_options) do
|
59
|
+
{ write: { w: (WRITE_CONCERN[:w] + 1) } }
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'uses the write concern of the fs as a default' do
|
63
|
+
expect{
|
64
|
+
stream.close
|
65
|
+
}.to raise_exception(Mongo::Error::OperationFailure)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when provided options' do
|
70
|
+
|
71
|
+
context 'when provided a write option' do
|
72
|
+
|
73
|
+
let(:extra_options) do
|
74
|
+
{
|
75
|
+
write: { w: (WRITE_CONCERN[:w] + 1) }
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
let(:expected) do
|
80
|
+
Mongo::WriteConcern.get(options[:write]).options
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'sets the write concern' do
|
84
|
+
expect(stream.write_concern.options).to eq(expected)
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'when chunks are inserted' do
|
88
|
+
|
89
|
+
it 'uses that write concern' do
|
90
|
+
expect(stream.send(:chunks_collection).write_concern.options).to eq(expected)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when a files document is inserted' do
|
95
|
+
|
96
|
+
it 'uses that write concern' do
|
97
|
+
expect(stream.send(:files_collection).write_concern.options).to eq(expected)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when provided a metadata document' do
|
103
|
+
|
104
|
+
let(:options) do
|
105
|
+
{
|
106
|
+
metadata: { 'some_field' => 'test-file' }
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'sets the metadata document' do
|
111
|
+
expect(stream.send(:file_info).metadata).to eq(options[:metadata])
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when provided a chunk size option' do
|
116
|
+
|
117
|
+
let(:options) do
|
118
|
+
{
|
119
|
+
chunk_size: 50
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'sets the chunk size' do
|
124
|
+
expect(stream.send(:file_info).chunk_size).to eq(options[:chunk_size])
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'when chunk size is also set on the FSBucket object' do
|
128
|
+
|
129
|
+
let(:fs_options) do
|
130
|
+
{
|
131
|
+
chunk_size: 100
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'uses the write stream options' do
|
136
|
+
expect(stream.send(:file_info).chunk_size).to eq(options[:chunk_size])
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'when provided a content type option' do
|
142
|
+
|
143
|
+
let(:options) do
|
144
|
+
{
|
145
|
+
content_type: 'text/plain'
|
146
|
+
}
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'sets the content type' do
|
150
|
+
expect(stream.send(:file_info).content_type).to eq(options[:content_type])
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when provided an aliases option' do
|
155
|
+
|
156
|
+
let(:options) do
|
157
|
+
{
|
158
|
+
aliases: [ 'testing-file' ]
|
159
|
+
}
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'sets the aliases' do
|
163
|
+
expect(stream.send(:file_info).document[:aliases]).to eq(options[:aliases])
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe '#write' do
|
170
|
+
|
171
|
+
after do
|
172
|
+
fs.files_collection.delete_many
|
173
|
+
fs.chunks_collection.delete_many
|
174
|
+
end
|
175
|
+
|
176
|
+
let(:file_from_db) do
|
177
|
+
fs.find_one(filename: filename)
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when the stream is written to' do
|
181
|
+
|
182
|
+
before do
|
183
|
+
stream.write(file)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'does not close the stream' do
|
187
|
+
expect(stream).not_to receive(:close)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'when indexes need to be ensured' do
|
192
|
+
|
193
|
+
context 'when the files collection is empty' do
|
194
|
+
|
195
|
+
before do
|
196
|
+
fs.files_collection.delete_many
|
197
|
+
fs.chunks_collection.delete_many
|
198
|
+
expect(fs.files_collection).to receive(:indexes).and_call_original
|
199
|
+
expect(fs.chunks_collection).to receive(:indexes).and_call_original
|
200
|
+
stream.write(file)
|
201
|
+
end
|
202
|
+
|
203
|
+
let(:chunks_index) do
|
204
|
+
fs.database[fs.chunks_collection.name].indexes.get(:files_id => 1, :n => 1)
|
205
|
+
end
|
206
|
+
|
207
|
+
let(:files_index) do
|
208
|
+
fs.database[fs.files_collection.name].indexes.get(:filename => 1, :uploadDate => 1)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'creates an index on the files collection' do
|
212
|
+
expect(files_index[:name]).to eq('filename_1_uploadDate_1')
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'creates an index on the chunks collection' do
|
216
|
+
expect(chunks_index[:name]).to eq('files_id_1_n_1')
|
217
|
+
end
|
218
|
+
|
219
|
+
context 'when write is called more than once' do
|
220
|
+
|
221
|
+
before do
|
222
|
+
expect(fs).not_to receive(:ensure_indexes!)
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'only creates the indexes the first time' do
|
226
|
+
stream.write(file2)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'when the files collection is not empty' do
|
232
|
+
|
233
|
+
before do
|
234
|
+
fs.files_collection.insert_one(a: 1)
|
235
|
+
expect(fs.files_collection).not_to receive(:indexes)
|
236
|
+
expect(fs.chunks_collection).not_to receive(:indexes)
|
237
|
+
stream.write(file)
|
238
|
+
end
|
239
|
+
|
240
|
+
after do
|
241
|
+
fs.files_collection.delete_many
|
242
|
+
fs.chunks_collection.delete_many
|
243
|
+
end
|
244
|
+
|
245
|
+
let(:files_index) do
|
246
|
+
fs.database[fs.files_collection.name].indexes.get(:filename => 1, :uploadDate => 1)
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'assumes indexes already exist' do
|
250
|
+
expect(files_index[:name]).to eq('filename_1_uploadDate_1')
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'when the index creation encounters an error', if: write_command_enabled? do
|
255
|
+
|
256
|
+
before do
|
257
|
+
fs.chunks_collection.drop
|
258
|
+
fs.chunks_collection.indexes.create_one(Mongo::Grid::FSBucket::CHUNKS_INDEX, :unique => false)
|
259
|
+
expect(fs.chunks_collection).to receive(:indexes).and_call_original
|
260
|
+
expect(fs.files_collection).not_to receive(:indexes)
|
261
|
+
end
|
262
|
+
|
263
|
+
after do
|
264
|
+
fs.database[fs.chunks_collection.name].indexes.drop_one('files_id_1_n_1')
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'raises the error to the user' do
|
268
|
+
expect {
|
269
|
+
stream.write(file)
|
270
|
+
}.to raise_error(Mongo::Error::OperationFailure)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
context 'when provided an io stream' do
|
276
|
+
|
277
|
+
before do
|
278
|
+
stream.write(file)
|
279
|
+
stream.close
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'writes the contents of the stream' do
|
283
|
+
expect(file_from_db.data.size).to eq(file.size)
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'updates the length written' do
|
287
|
+
expect(stream.send(:file_info).document['length']).to eq(file.size)
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'updates the position (n)' do
|
291
|
+
expect(stream.instance_variable_get(:@n)).to eq(1)
|
292
|
+
end
|
293
|
+
|
294
|
+
context 'when the user file contains no data' do
|
295
|
+
|
296
|
+
let(:file) do
|
297
|
+
StringIO.new('')
|
298
|
+
end
|
299
|
+
|
300
|
+
let(:files_coll_doc) do
|
301
|
+
stream.fs.files_collection.find(filename: filename).to_a.first
|
302
|
+
end
|
303
|
+
|
304
|
+
let(:chunks_documents) do
|
305
|
+
stream.fs.chunks_collection.find(files_id: stream.file_id).to_a
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'creates a files document' do
|
309
|
+
expect(files_coll_doc).not_to be(nil)
|
310
|
+
end
|
311
|
+
|
312
|
+
it 'sets length to 0 in the files document' do
|
313
|
+
expect(files_coll_doc['length']).to eq(0)
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'does not insert any chunks' do
|
317
|
+
expect(file_from_db.data.size).to eq(file.size)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
context 'when the stream is written to multiple times' do
|
323
|
+
|
324
|
+
before do
|
325
|
+
stream.write(file)
|
326
|
+
stream.write(file2)
|
327
|
+
stream.close
|
328
|
+
end
|
329
|
+
|
330
|
+
it 'writes the contents of the stream' do
|
331
|
+
expect(file_from_db.data.size).to eq(file.size * 2)
|
332
|
+
end
|
333
|
+
|
334
|
+
it 'updates the length written' do
|
335
|
+
expect(stream.send(:file_info).document['length']).to eq(file.size * 2)
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'updates the position (n)' do
|
339
|
+
expect(stream.instance_variable_get(:@n)).to eq(2)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
context 'when the stream is closed' do
|
344
|
+
|
345
|
+
before do
|
346
|
+
stream.close
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'does not allow further writes' do
|
350
|
+
expect {
|
351
|
+
stream.write(file)
|
352
|
+
}.to raise_error(Mongo::Error::ClosedStream)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
describe '#close' do
|
358
|
+
|
359
|
+
let(:file_content) do
|
360
|
+
File.open(__FILE__).read
|
361
|
+
end
|
362
|
+
|
363
|
+
context 'when close is called on the stream' do
|
364
|
+
|
365
|
+
before do
|
366
|
+
stream.write(file)
|
367
|
+
end
|
368
|
+
|
369
|
+
let(:file_id) do
|
370
|
+
stream.file_id
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'returns the file id' do
|
374
|
+
expect(stream.close).to eq(file_id)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
context 'when the stream is closed' do
|
379
|
+
|
380
|
+
before do
|
381
|
+
stream.write(file)
|
382
|
+
stream.close
|
383
|
+
end
|
384
|
+
|
385
|
+
let(:md5) do
|
386
|
+
Digest::MD5.new.update(file_content).hexdigest
|
387
|
+
end
|
388
|
+
|
389
|
+
let(:files_coll_doc) do
|
390
|
+
stream.fs.files_collection.find(filename: filename).to_a.first
|
391
|
+
end
|
392
|
+
|
393
|
+
it 'inserts a file documents in the files collection' do
|
394
|
+
expect(files_coll_doc['_id']).to eq(stream.file_id)
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'updates the length in the files collection file document' do
|
398
|
+
expect(stream.send(:file_info).document[:length]).to eq(file.size)
|
399
|
+
end
|
400
|
+
|
401
|
+
it 'updates the md5 in the files collection file document' do
|
402
|
+
expect(stream.send(:file_info).document[:md5]).to eq(md5)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
context 'when the stream is already closed' do
|
407
|
+
|
408
|
+
before do
|
409
|
+
stream.close
|
410
|
+
end
|
411
|
+
|
412
|
+
it 'raises an exception' do
|
413
|
+
expect {
|
414
|
+
stream.close
|
415
|
+
}.to raise_error(Mongo::Error::ClosedStream)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
describe '#closed?' do
|
421
|
+
|
422
|
+
context 'when the stream is closed' do
|
423
|
+
|
424
|
+
before do
|
425
|
+
stream.close
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'returns true' do
|
429
|
+
expect(stream.closed?).to be(true)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
context 'when the stream is still open' do
|
434
|
+
|
435
|
+
it 'returns false' do
|
436
|
+
expect(stream.closed?).to be(false)
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|