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
|
# frozen_string_literal: true
# rubocop:todo all
module CSOT
module Examples
# expects the following values to be available:
# `op` -- an instance of an OpMsgBase subclass
def self.included(example_context)
example_context.shared_examples 'mock CSOT environment' do
# Linting freaks out because of the doubles used in these specs.
require_no_linting
let(:message) { op.send(:message, connection) }
let(:body) { message.documents.first }
let(:cursor_type) { nil }
let(:timeout_mode) { nil }
let(:remaining_timeout_sec) { nil }
let(:minimum_round_trip_time) { 0 }
let(:view_options) { {} }
let(:max_await_time_ms) { nil }
let(:view) do
instance_double(Mongo::Collection::View).tap do |view|
allow(view).to receive(:cursor_type).and_return(cursor_type)
allow(view).to receive(:timeout_mode).and_return(timeout_mode)
allow(view).to receive(:options).and_return(view_options)
allow(view).to receive(:max_await_time_ms).and_return(max_await_time_ms)
end
end
let(:context) do
Mongo::Operation::Context.new(view: view).tap do |context|
allow(context).to receive(:remaining_timeout_sec).and_return(remaining_timeout_sec)
allow(context).to receive(:timeout?).and_return(!remaining_timeout_sec.nil?)
end
end
let(:server) do
instance_double(Mongo::Server).tap do |server|
allow(server).to receive(:minimum_round_trip_time).and_return(minimum_round_trip_time)
end
end
let(:address) { Mongo::Address.new('127.0.0.1') }
let(:description) do
Mongo::Server::Description.new(
address, { Mongo::Operation::Result::OK => 1 }
)
end
let(:features) do
Mongo::Server::Description::Features.new(
Mongo::Server::Description::Features::DRIVER_WIRE_VERSIONS,
address
)
end
let(:connection) do
instance_double(Mongo::Server::Connection).tap do |conn|
allow(conn).to receive(:server).and_return(server)
allow(conn).to receive(:description).and_return(description)
allow(conn).to receive(:features).and_return(features)
end
end
before do
# context is normally set when calling `execute` on the operation,
# but since we're not doing that, we have to tell the operation
# what the context is.
op.context = context
end
end
example_context.shared_examples 'a CSOT-compliant OpMsg subclass' do
include_examples 'mock CSOT environment'
context 'when no timeout_ms set' do
it 'does not set maxTimeMS' do
expect(body.key?(:maxTimeMS)).to be false
end
end
context 'when there is enough time to send the message' do
# Ten seconds remaining
let(:remaining_timeout_sec) { 10 }
# One second RTT
let(:minimum_round_trip_time) { 1 }
it 'sets the maxTimeMS' do
# Nine seconds
expect(body[:maxTimeMS]).to eq(9_000)
end
end
context 'when there is not enough time to send the message' do
# Ten seconds remaining
let(:remaining_timeout_sec) { 0.1 }
# One second RTT
let(:minimum_round_trip_time) { 1 }
it 'fails with an exception' do
expect { message }.to raise_error(Mongo::Error::TimeoutError)
end
end
end
end
end
end
|