1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
# frozen_string_literal: true
# rubocop:todo all
require 'spec_helper'
describe 'QueryCache with transactions' do
# Work around https://jira.mongodb.org/browse/HELP-10518
before(:all) do
client = ClientRegistry.instance.global_client('authorized')
Utils.create_collection(client, 'test')
Utils.mongos_each_direct_client do |client|
client['test'].distinct('foo').to_a
end
end
around do |spec|
Mongo::QueryCache.clear
Mongo::QueryCache.cache { spec.run }
end
# These tests do not currently use the session registry because transactions
# leak sessions independently of the query cache. This will be resolved by
# RUBY-2391.
let(:subscriber) { Mrss::EventSubscriber.new }
let(:client) do
authorized_client.tap do |client|
client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
end
end
before do
collection.delete_many
# Work around https://jira.mongodb.org/browse/HELP-10518
client.start_session do |session|
session.with_transaction do
collection.find({}, session: session).to_a
end
end
subscriber.clear_events!
end
describe 'in transactions' do
require_transaction_support
require_wired_tiger
let(:collection) { client['test'] }
let(:events) do
subscriber.command_started_events('find')
end
context 'with convenient API' do
context 'when same query is performed inside and outside of transaction' do
it 'performs one query' do
collection.find.to_a
session = client.start_session
session.with_transaction do
collection.find({}, session: session).to_a
end
expect(subscriber.command_started_events('find').length).to eq(1)
end
end
context 'when transaction has a different read concern' do
it 'performs two queries' do
collection.find.to_a
session = client.start_session
session.with_transaction(
read_concern: { level: :snapshot }
) do
collection.find({}, session: session).to_a
end
expect(subscriber.command_started_events('find').length).to eq(2)
end
end
context 'when transaction has a different read preference' do
it 'performs two queries' do
collection.find.to_a
session = client.start_session
session.with_transaction(
read: { mode: :primary }
) do
collection.find({}, session: session).to_a
end
expect(subscriber.command_started_events('find').length).to eq(2)
end
end
context 'when transaction is committed' do
it 'clears the cache' do
session = client.start_session
session.with_transaction do
collection.insert_one({ test: 1 }, session: session)
collection.insert_one({ test: 2 }, session: session)
expect(collection.find({}, session: session).to_a.length).to eq(2)
expect(collection.find({}, session: session).to_a.length).to eq(2)
# The driver caches the queries within the transaction
expect(subscriber.command_started_events('find').length).to eq(1)
session.commit_transaction
end
expect(collection.find.to_a.length).to eq(2)
# The driver clears the cache and runs the query again
expect(subscriber.command_started_events('find').length).to eq(2)
end
end
context 'when transaction is aborted' do
it 'clears the cache' do
session = client.start_session
session.with_transaction do
collection.insert_one({ test: 1 }, session: session)
collection.insert_one({ test: 2 }, session: session)
expect(collection.find({}, session: session).to_a.length).to eq(2)
expect(collection.find({}, session: session).to_a.length).to eq(2)
# The driver caches the queries within the transaction
expect(subscriber.command_started_events('find').length).to eq(1)
session.abort_transaction
end
expect(collection.find.to_a.length).to eq(0)
# The driver clears the cache and runs the query again
expect(subscriber.command_started_events('find').length).to eq(2)
end
end
end
context 'with low-level API' do
context 'when transaction is committed' do
it 'clears the cache' do
session = client.start_session
session.start_transaction
collection.insert_one({ test: 1 }, session: session)
collection.insert_one({ test: 2 }, session: session)
expect(collection.find({}, session: session).to_a.length).to eq(2)
expect(collection.find({}, session: session).to_a.length).to eq(2)
# The driver caches the queries within the transaction
expect(subscriber.command_started_events('find').length).to eq(1)
session.commit_transaction
expect(collection.find.to_a.length).to eq(2)
# The driver clears the cache and runs the query again
expect(subscriber.command_started_events('find').length).to eq(2)
end
end
context 'when transaction is aborted' do
it 'clears the cache' do
session = client.start_session
session.start_transaction
collection.insert_one({ test: 1 }, session: session)
collection.insert_one({ test: 2 }, session: session)
expect(collection.find({}, session: session).to_a.length).to eq(2)
expect(collection.find({}, session: session).to_a.length).to eq(2)
# The driver caches the queries within the transaction
expect(subscriber.command_started_events('find').length).to eq(1)
session.abort_transaction
expect(collection.find.to_a.length).to eq(0)
# The driver clears the cache and runs the query again
expect(subscriber.command_started_events('find').length).to eq(2)
end
end
end
end
end
|