spec/mongo/collection_spec.rb in mongo-2.5.0.beta vs spec/mongo/collection_spec.rb in mongo-2.5.0
- old
+ new
@@ -12,10 +12,14 @@
let(:collection_with_validator) do
authorized_client[:validating]
end
+ let(:client) do
+ authorized_client
+ end
+
describe '#==' do
let(:database) do
Mongo::Database.new(authorized_client, :test)
end
@@ -646,11 +650,10 @@
it_behaves_like 'a failed operation using a session'
end
end
end
-
describe '#drop' do
let(:database) do
authorized_client.database
end
@@ -761,12 +764,16 @@
let(:operation) do
client[TEST_COLL].find.first
end
+ let(:operation_with_session) do
+ client[TEST_COLL].find({}, session: session).first
+ end
+
let(:second_operation) do
- client[TEST_COLL].find.first
+ client[TEST_COLL].find({}, session: session).first
end
it_behaves_like 'an operation updating cluster time'
end
@@ -862,14 +869,10 @@
end
end
context 'when provided options' do
- let(:view) do
- authorized_collection.find({}, options)
- end
-
context 'when a session is provided' do
let(:operation) do
authorized_collection.find({}, session: session).to_a
end
@@ -877,21 +880,73 @@
let(:session) do
authorized_client.start_session
end
let(:failed_operation) do
- authorized_collection.find({ '$._id' => 1 }, session: session).to_a
+ client[authorized_collection.name].find({ '$._id' => 1 }, session: session).to_a
end
let(:client) do
authorized_client
end
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+ context 'session id', if: test_sessions? do
+
+ let(:options) do
+ { session: session }
+ end
+
+ let(:client) do
+ authorized_client.with(heartbeat_frequency: 100).tap do |cl|
+ cl.subscribe(Mongo::Monitoring::COMMAND, subscriber)
+ end
+ end
+
+ let(:session) do
+ client.start_session
+ end
+
+ let(:subscriber) do
+ EventSubscriber.new
+ end
+
+ let(:view) do
+ Mongo::Collection::View.new(client[TEST_COLL], selector, view_options)
+ end
+
+ let(:command) do
+ client[TEST_COLL].find({}, session: session).explain
+ subscriber.started_events.find { |c| c.command_name == :explain }.command
+ end
+
+ it 'sends the session id' do
+ expect(command['lsid']).to eq(session.session_id)
+ end
+ end
+
+ context 'when a session supporting causal consistency is used' do
+
+ let(:operation) do
+ collection.find({}, session: session).to_a
+ end
+
+ let(:command) do
+ operation
+ subscriber.started_events.find { |cmd| cmd.command_name == 'find' }.command
+ end
+
+ it_behaves_like 'an operation supporting causally consistent reads'
+ end
+
+ let(:view) do
+ authorized_collection.find({}, options)
+ end
+
context 'when provided :allow_partial_results' do
let(:options) do
{ allow_partial_results: true }
end
@@ -1062,10 +1117,23 @@
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+ context 'when unacknowledged writes is used' do
+
+ let(:collection_with_unacknowledged_write_concern) do
+ authorized_collection.with(write: { w: 0 })
+ end
+
+ let(:operation) do
+ collection_with_unacknowledged_write_concern.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session)
+ end
+
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
+ end
+
context 'when a document contains invalid keys' do
let(:docs) do
[ { 'first.name' => 'test1' }, { name: 'test2' } ]
end
@@ -1216,39 +1284,54 @@
expect(result3.inserted_count).to eq(2)
end
end
end
end
+
+ context 'when unacknowledged writes is used' do
+
+ let(:collection_with_unacknowledged_write_concern) do
+ authorized_collection.with(write: { w: 0 })
+ end
+
+ let(:result) do
+ collection_with_unacknowledged_write_concern.insert_many([{ _id: 1 }, { _id: 1 }])
+ end
+
+ it 'does not raise an exception' do
+ expect(result.inserted_count).to be(0)
+ end
+ end
end
describe '#insert_one' do
describe 'updating cluster time' do
let(:operation) do
client[TEST_COLL].insert_one({ name: 'testing' })
end
+ let(:operation_with_session) do
+ client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
+ end
+
let(:second_operation) do
- client[TEST_COLL].insert_one({ name: 'testing' })
+ client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
end
it_behaves_like 'an operation updating cluster time'
end
let(:result) do
authorized_collection.insert_one({ name: 'testing' })
end
- it 'inserts the document into the collection', if: write_command_enabled? do
+ it 'inserts the document into the collection'do
expect(result.written_count).to eq(1)
end
- it 'inserts the document into the collection', unless: write_command_enabled? do
- expect(result.written_count).to eq(0)
- end
-
it 'contains the id in the result' do
expect(result.inserted_id).to_not be_nil
end
context 'when a session is provided' do
@@ -1272,10 +1355,23 @@
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+ context 'when unacknowledged writes is used' do
+
+ let(:collection_with_unacknowledged_write_concern) do
+ authorized_collection.with(write: { w: 0 })
+ end
+
+ let(:operation) do
+ collection_with_unacknowledged_write_concern.insert_one({ name: 'testing' }, session: session)
+ end
+
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
+ end
+
context 'when the document contains invalid keys' do
let(:doc) do
{ 'testing.test' => 'value' }
end
@@ -1457,17 +1553,35 @@
let(:operation) do
client[TEST_COLL].aggregate([]).first
end
+ let(:operation_with_session) do
+ client[TEST_COLL].aggregate([], session: session).first
+ end
+
let(:second_operation) do
- client[TEST_COLL].aggregate([]).first
+ client[TEST_COLL].aggregate([], session: session).first
end
it_behaves_like 'an operation updating cluster time'
end
+ context 'when a session supporting causal consistency is used' do
+
+ let(:operation) do
+ collection.aggregate([], session: session).first
+ end
+
+ let(:command) do
+ operation
+ subscriber.started_events.find { |cmd| cmd.command_name == 'aggregate' }.command
+ end
+
+ it_behaves_like 'an operation supporting causally consistent reads'
+ end
+
it 'returns an Aggregation object' do
expect(authorized_collection.aggregate([])).to be_a(Mongo::Collection::View::Aggregation)
end
context 'when options are provided' do
@@ -1478,10 +1592,21 @@
it 'sets the options on the Aggregation object' do
expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
end
+ context 'when the :comment option is provided' do
+
+ let(:options) do
+ { :comment => 'testing' }
+ end
+
+ it 'sets the options on the Aggregation object' do
+ expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
+ end
+ end
+
context 'when a session is provided' do
let(:session) do
authorized_client.start_session
end
@@ -1603,10 +1728,24 @@
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+ context 'when a session supporting causal consistency is used' do
+
+ let(:operation) do
+ collection.count({}, session: session)
+ end
+
+ let(:command) do
+ operation
+ subscriber.started_events.find { |cmd| cmd.command_name == :count }.command
+ end
+
+ it_behaves_like 'an operation supporting causally consistent reads'
+ end
+
context 'when a collation is specified' do
let(:selector) do
{ name: 'BANG' }
end
@@ -1703,10 +1842,24 @@
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
end
+ context 'when a session supporting causal consistency is used' do
+
+ let(:operation) do
+ collection.distinct(:field, {}, session: session)
+ end
+
+ let(:command) do
+ operation
+ subscriber.started_events.find { |cmd| cmd.command_name == :distinct }.command
+ end
+
+ it_behaves_like 'an operation supporting causally consistent reads'
+ end
+
context 'when a collation is specified' do
let(:result) do
authorized_collection.distinct(:name, {}, options)
end
@@ -1760,11 +1913,11 @@
authorized_collection.insert_one(name: 'bang')
authorized_collection.insert_one(name: 'BANG')
end
it 'does not apply the collation to the distinct' do
- expect(result).to eq(['bang', 'BANG'])
+ expect(result).to match_array(['bang', 'BANG'])
end
end
end
describe '#delete_one' do
@@ -1840,10 +1993,23 @@
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+ context 'when unacknowledged writes is used' do
+
+ let(:collection_with_unacknowledged_write_concern) do
+ authorized_collection.with(write: { w: 0 })
+ end
+
+ let(:operation) do
+ collection_with_unacknowledged_write_concern.delete_one({}, session: session)
+ end
+
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
+ end
+
context 'when a collation is provided' do
let(:selector) do
{ name: 'BANG' }
end
@@ -1999,10 +2165,23 @@
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+ context 'when unacknowledged writes is used' do
+
+ let(:collection_with_unacknowledged_write_concern) do
+ authorized_collection.with(write: { w: 0 })
+ end
+
+ let(:operation) do
+ collection_with_unacknowledged_write_concern.delete_many({ '$._id' => 1}, session: session)
+ end
+
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
+ end
+
context 'when a collation is specified' do
let(:selector) do
{ name: 'BANG' }
end
@@ -2117,38 +2296,28 @@
let(:cursors) do
authorized_collection.parallel_scan(2)
end
- it 'returns an array of cursors', if: write_command_enabled? do
+ it 'returns an array of cursors' do
cursors.each do |cursor|
expect(cursor.class).to be(Mongo::Cursor)
end
end
- it 'returns the correct number of documents', if: write_command_enabled? do
+ it 'returns the correct number of documents' do
expect(
cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
).to eq(200)
end
- it 'raises an error', unless: write_command_enabled? do
- expect {
- cursors
- }.to raise_error(Mongo::Error::OperationFailure)
- end
-
context 'when a session is provided' do
let(:cursors) do
authorized_collection.parallel_scan(2, session: session)
end
- let(:session) do
- authorized_client.start_session
- end
-
let(:operation) do
cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
end
let(:failed_operation) do
@@ -2161,10 +2330,28 @@
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+ context 'when a session supporting causal consistency is used' do
+
+ let(:cursors) do
+ collection.parallel_scan(2, session: session)
+ end
+
+ let(:operation) do
+ cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
+ end
+
+ let(:command) do
+ operation
+ subscriber.started_events.find { |cmd| cmd.command_name == :parallelCollectionScan }.command
+ end
+
+ it_behaves_like 'an operation supporting causally consistent reads'
+ end
+
context 'when a read concern is provided', if: find_command_enabled? do
let(:result) do
authorized_collection.with(options).parallel_scan(2)
end
@@ -2222,11 +2409,11 @@
result
}.to raise_exception(Mongo::Error::NoServerAvailable)
end
end
- context 'when a max time ms value is provided', if: (!sharded? && write_command_enabled?) do
+ context 'when a max time ms value is provided', if: !sharded? do
let(:result) do
authorized_collection.parallel_scan(2, options)
end
@@ -2274,18 +2461,14 @@
let(:updated) do
authorized_collection.find(field: 'testing').first
end
- it 'updates the first matching document in the collection', if: write_command_enabled? do
+ it 'updates the first matching document in the collection' do
expect(response.modified_count).to eq(1)
end
- it 'does not return modified count', unless: write_command_enabled? do
- expect(response.modified_count).to eq(nil)
- end
-
it 'updates the documents in the collection' do
expect(updated[:field]).to eq('testing')
end
end
@@ -2297,18 +2480,14 @@
let(:updated) do
authorized_collection.find(field: 'test1').to_a
end
- it 'reports that no documents were written', if: write_command_enabled? do
+ it 'reports that no documents were written' do
expect(response.modified_count).to eq(0)
end
- it 'does not return modified count', unless: write_command_enabled? do
- expect(response.modified_count).to eq(nil)
- end
-
it 'does not insert the document' do
expect(updated).to be_empty
end
end
@@ -2339,18 +2518,14 @@
let(:updated) do
authorized_collection.find(field: 'test1').to_a
end
- it 'reports that no documents were written', if: write_command_enabled? do
+ it 'reports that no documents were written' do
expect(response.modified_count).to eq(0)
end
- it 'does not return modified count', unless: write_command_enabled? do
- expect(response.modified_count).to eq(nil)
- end
-
it 'does not insert the document' do
expect(updated).to be_empty
end
end
@@ -2548,10 +2723,23 @@
end
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+
+ context 'when unacknowledged writes is used' do
+
+ let(:collection_with_unacknowledged_write_concern) do
+ authorized_collection.with(write: { w: 0 })
+ end
+
+ let(:operation) do
+ collection_with_unacknowledged_write_concern.replace_one({ a: 1 }, { x: 5 }, session: session)
+ end
+
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
+ end
end
describe '#update_many' do
let(:selector) do
@@ -2570,18 +2758,14 @@
let(:updated) do
authorized_collection.find(field: 'testing').to_a.last
end
- it 'returns the number updated', if: write_command_enabled? do
+ it 'returns the number updated' do
expect(response.modified_count).to eq(2)
end
- it 'does not return modified count', unless: write_command_enabled? do
- expect(response.modified_count).to eq(nil)
- end
-
it 'updates the documents in the collection' do
expect(updated[:field]).to eq('testing')
end
end
@@ -2594,18 +2778,14 @@
let(:updated) do
authorized_collection.find.to_a
end
- it 'reports that no documents were updated', if: write_command_enabled? do
+ it 'reports that no documents were updated' do
expect(response.modified_count).to eq(0)
end
- it 'does not return modified count', unless: write_command_enabled? do
- expect(response.modified_count).to eq(nil)
- end
-
it 'updates no documents in the collection' do
expect(updated).to be_empty
end
end
@@ -2637,18 +2817,14 @@
let(:updated) do
authorized_collection.find.to_a
end
- it 'reports that no documents were updated', if: write_command_enabled? do
+ it 'reports that no documents were updated' do
expect(response.modified_count).to eq(0)
end
- it 'does not return modified count', unless: write_command_enabled? do
- expect(response.modified_count).to eq(nil)
- end
-
it 'updates no documents in the collection' do
expect(updated).to be_empty
end
end
@@ -2951,10 +3127,23 @@
end
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+
+ context 'when unacknowledged writes is used' do
+
+ let(:collection_with_unacknowledged_write_concern) do
+ authorized_collection.with(write: { w: 0 })
+ end
+
+ let(:operation) do
+ collection_with_unacknowledged_write_concern.update_many({a: 1}, { '$set' => {x: 1} }, session: session)
+ end
+
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
+ end
end
describe '#update_one' do
let(:selector) do
@@ -2973,18 +3162,14 @@
let(:updated) do
authorized_collection.find(field: 'testing').first
end
- it 'updates the first matching document in the collection', if: write_command_enabled? do
+ it 'updates the first matching document in the collection' do
expect(response.modified_count).to eq(1)
end
- it 'does not return modified count', unless: write_command_enabled? do
- expect(response.modified_count).to eq(nil)
- end
-
it 'updates the documents in the collection' do
expect(updated[:field]).to eq('testing')
end
end
@@ -2997,18 +3182,14 @@
let(:updated) do
authorized_collection.find.to_a
end
- it 'reports that no documents were updated', if: write_command_enabled? do
+ it 'reports that no documents were updated' do
expect(response.modified_count).to eq(0)
end
- it 'does not return modified count', unless: write_command_enabled? do
- expect(response.modified_count).to eq(nil)
- end
-
it 'updates no documents in the collection' do
expect(updated).to be_empty
end
end
@@ -3040,18 +3221,14 @@
let(:updated) do
authorized_collection.find.to_a
end
- it 'reports that no documents were updated', if: write_command_enabled? do
+ it 'reports that no documents were updated' do
expect(response.modified_count).to eq(0)
end
- it 'does not return modified count', unless: write_command_enabled? do
- expect(response.modified_count).to eq(nil)
- end
-
it 'updates no documents in the collection' do
expect(updated).to be_empty
end
end
@@ -3363,10 +3540,23 @@
end
it_behaves_like 'an operation using a session'
it_behaves_like 'a failed operation using a session'
end
+
+ context 'when unacknowledged writes is used' do
+
+ let(:collection_with_unacknowledged_write_concern) do
+ authorized_collection.with(write: { w: 0 })
+ end
+
+ let(:operation) do
+ collection_with_unacknowledged_write_concern.update_one({a: 1}, { '$set' => {x: 1} }, session: session)
+ end
+
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
+ end
end
describe '#find_one_and_delete' do
before do
@@ -3445,11 +3635,11 @@
it 'returns the document with limited fields' do
expect(document['field']).to eq('test1')
end
end
- context 'when max_time_ms is provided', if: write_command_enabled? do
+ context 'when max_time_ms is provided' do
it 'includes the max_time_ms value in the command' do
expect {
authorized_collection.find_one_and_delete(selector, max_time_ms: 0.1)
}.to raise_error(Mongo::Error::OperationFailure)
@@ -3470,11 +3660,11 @@
it 'returns nil' do
expect(document).to be_nil
end
end
- context 'when the operation fails', if: write_command_enabled? do
+ context 'when the operation fails' do
let(:result) do
authorized_collection.find_one_and_delete(selector, max_time_ms: 0.1)
end
@@ -3683,11 +3873,11 @@
end
end
context 'when max_time_ms is provided' do
- it 'includes the max_time_ms value in the command', if: write_command_enabled? do
+ it 'includes the max_time_ms value in the command' do
expect {
authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
}.to raise_error(Mongo::Error::OperationFailure)
end
end
@@ -3738,11 +3928,11 @@
expect(document['field']).to eq('testing')
end
end
end
- context 'when the operation fails', if: write_command_enabled? do
+ context 'when the operation fails' do
let(:result) do
authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
end
@@ -4114,20 +4304,20 @@
expect(document['field']).to eq('testing')
end
end
end
- context 'when max_time_ms is provided', if: write_command_enabled? do
+ context 'when max_time_ms is provided' do
it 'includes the max_time_ms value in the command' do
expect {
authorized_collection.find_one_and_replace(selector, { field: 'testing' }, max_time_ms: 0.1)
}.to raise_error(Mongo::Error::OperationFailure)
end
end
- context 'when the operation fails', if: write_command_enabled? do
+ context 'when the operation fails' do
let(:result) do
authorized_collection.find_one_and_replace(selector, { field: 'testing' }, max_time_ms: 0.1)
end
@@ -4362,45 +4552,45 @@
end
context 'when batch_size is provided' do
before do
- authorized_collection.insert_one(a: 2)
- authorized_collection.insert_one(a: 3)
+ Thread.new do
+ sleep 1
+ authorized_collection.insert_one(a: 2)
+ authorized_collection.insert_one(a: 3)
+ end
end
let(:change_stream) do
authorized_collection.watch([], batch_size: 2)
end
it 'returns the documents in the batch size specified' do
expect(change_stream.instance_variable_get(:@cursor)).to receive(:get_more).once.and_call_original
enum.next
- enum.next
end
end
context 'when collation is provided' do
- # pending 'server support for collation with the $changeStream operator'
- #
- # before do
- # authorized_collection.update_one({ a: 1 }, { '$set' => { a: 2 } })
- # end
- #
- # let(:change_doc) do
- # change_stream.next
- # change_stream.next
- # end
- #
- # let(:change_stream) do
- # authorized_collection.watch([ { '$match' => { operationType: 'UPDATE'}}],
- # collation: { locale: 'en_US', strength: 2 } ).to_enum
- # end
- #
- # it 'returns the change' do
- # expect(change_doc[:operationType]).to eq('update')
- # expect(change_doc[:fullDocument][:a]).to eq(2)
- # end
+
+ before do
+ authorized_collection.update_one({ a: 1 }, { '$set' => { a: 2 } })
+ end
+
+ let(:change_doc) do
+ enum.next
+ end
+
+ let(:change_stream) do
+ authorized_collection.watch([ { '$match' => { operationType: 'UPDATE'}}],
+ collation: { locale: 'en_US', strength: 2 } ).to_enum
+ end
+
+ it 'returns the change' do
+ expect(change_doc['operationType']).to eq('update')
+ expect(change_doc['updateDescription']['updatedFields']['a']).to eq(2)
+ end
end
end
end
end
end