File: query_cache_transactions_spec.rb

package info (click to toggle)
ruby-mongo 2.21.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 14,764 kB
  • sloc: ruby: 108,806; makefile: 5; sh: 2
file content (193 lines) | stat: -rw-r--r-- 6,132 bytes parent folder | download
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