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
|
# frozen_string_literal: true
# rubocop:todo all
require 'spec_helper'
describe Mongo::Socket do
let(:socket) do
described_class.new(0, {})
end
describe '#human_address' do
it 'raises NotImplementedError' do
expect do
socket.send(:human_address)
end.to raise_error(NotImplementedError)
end
end
describe '#map_exceptions' do
before do
expect(socket).to receive(:human_address).and_return('fake-address')
end
it 'maps timeout exception' do
expect do
socket.send(:map_exceptions) do
raise Errno::ETIMEDOUT
end
end.to raise_error(Mongo::Error::SocketTimeoutError)
end
it 'maps SystemCallError and preserves message' do
expect do
socket.send(:map_exceptions) do
raise SystemCallError.new('Test error', Errno::ENFILE::Errno)
end
end.to raise_error(Mongo::Error::SocketError, 'Errno::ENFILE: Too many open files in system - Test error (for fake-address)')
end
it 'maps IOError and preserves message' do
expect do
socket.send(:map_exceptions) do
raise IOError.new('Test error')
end
end.to raise_error(Mongo::Error::SocketError, 'IOError: Test error (for fake-address)')
end
it 'maps SSLError and preserves message' do
expect do
socket.send(:map_exceptions) do
raise OpenSSL::SSL::SSLError.new('Test error')
end
end.to raise_error(Mongo::Error::SocketError, 'OpenSSL::SSL::SSLError: Test error (for fake-address)')
end
end
describe '#read' do
let(:target_host) do
host = ClusterConfig.instance.primary_address_host
# Take ipv4 address
Socket.getaddrinfo(host, 0).detect { |ai| ai.first == 'AF_INET' }[3]
end
let(:socket) do
Mongo::Socket::TCP.new(target_host, ClusterConfig.instance.primary_address_port, 1, Socket::PF_INET)
end
let(:raw_socket) { socket.instance_variable_get('@socket') }
context 'timeout' do
clean_slate_for_all
shared_examples_for 'times out' do
it 'times out' do
expect(socket).to receive(:timeout).at_least(:once).and_return(0.2)
# When we raise WaitWritable, the socket object is ready for
# writing which makes the read method invoke read_nonblock many times
expect(raw_socket).to receive(:read_nonblock).at_least(:once) do |len, buf|
sleep 0.01
raise exception_class
end
expect do
socket.read(10)
end.to raise_error(Mongo::Error::SocketTimeoutError, /Took more than .* seconds to receive data.*\(for /)
end
end
context 'with WaitReadable' do
let(:exception_class) do
Class.new(Exception) do
include IO::WaitReadable
end
end
it_behaves_like 'times out'
end
context 'with WaitWritable' do
let(:exception_class) do
Class.new(Exception) do
include IO::WaitWritable
end
end
it_behaves_like 'times out'
end
end
end
describe '#write' do
let(:target_host) do
host = ClusterConfig.instance.primary_address_host
# Take ipv4 address
Socket.getaddrinfo(host, 0).detect { |ai| ai.first == 'AF_INET' }[3]
end
let(:socket) do
Mongo::Socket::TCP.new(target_host, ClusterConfig.instance.primary_address_port, 1, Socket::PF_INET)
end
let(:raw_socket) { socket.instance_variable_get('@socket') }
context 'with timeout' do
let(:timeout) { 5_000 }
context 'data is less than WRITE_CHUNK_SIZE' do
let(:data) { "a" * 1024 }
context 'when a partial write occurs' do
before do
expect(raw_socket)
.to receive(:write_nonblock)
.twice
.and_return(data.length / 2)
end
it 'eventually writes everything' do
expect(socket.write(data, timeout: timeout)).
to be === data.length
end
end
end
context 'data is greater than WRITE_CHUNK_SIZE' do
let(:data) { "a" * (2 * Mongo::Socket::WRITE_CHUNK_SIZE + 256) }
context 'when a partial write occurs' do
before do
expect(raw_socket)
.to receive(:write_nonblock)
.exactly(4).times
.and_return(Mongo::Socket::WRITE_CHUNK_SIZE,
128,
Mongo::Socket::WRITE_CHUNK_SIZE - 128,
256)
end
it 'eventually writes everything' do
expect(socket.write(data, timeout: timeout)).
to be === data.length
end
end
end
end
end
end
|