cql-rb 1.1.0.pre3 → 1.1.0.pre6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +2 -2
- data/lib/cql/client.rb +9 -5
- data/lib/cql/client/asynchronous_client.rb +105 -192
- data/lib/cql/client/asynchronous_prepared_statement.rb +51 -9
- data/lib/cql/client/connection_helper.rb +155 -0
- data/lib/cql/client/connection_manager.rb +56 -0
- data/lib/cql/client/keyspace_changer.rb +27 -0
- data/lib/cql/client/null_logger.rb +21 -0
- data/lib/cql/client/request_runner.rb +5 -3
- data/lib/cql/client/synchronous_client.rb +5 -5
- data/lib/cql/client/synchronous_prepared_statement.rb +4 -8
- data/lib/cql/future.rb +320 -210
- data/lib/cql/io/connection.rb +5 -5
- data/lib/cql/io/io_reactor.rb +21 -23
- data/lib/cql/protocol/cql_protocol_handler.rb +69 -38
- data/lib/cql/protocol/encoding.rb +5 -1
- data/lib/cql/protocol/requests/register_request.rb +2 -0
- data/lib/cql/protocol/type_converter.rb +1 -0
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/asynchronous_client_spec.rb +368 -175
- data/spec/cql/client/asynchronous_prepared_statement_spec.rb +132 -22
- data/spec/cql/client/connection_helper_spec.rb +335 -0
- data/spec/cql/client/connection_manager_spec.rb +118 -0
- data/spec/cql/client/keyspace_changer_spec.rb +50 -0
- data/spec/cql/client/request_runner_spec.rb +12 -12
- data/spec/cql/client/synchronous_client_spec.rb +15 -15
- data/spec/cql/client/synchronous_prepared_statement_spec.rb +15 -11
- data/spec/cql/future_spec.rb +529 -301
- data/spec/cql/io/connection_spec.rb +12 -12
- data/spec/cql/io/io_reactor_spec.rb +61 -61
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +26 -12
- data/spec/cql/protocol/encoding_spec.rb +5 -0
- data/spec/cql/protocol/type_converter_spec.rb +1 -1
- data/spec/cql/time_uuid_spec.rb +7 -7
- data/spec/integration/client_spec.rb +2 -2
- data/spec/integration/io_spec.rb +20 -20
- data/spec/integration/protocol_spec.rb +17 -17
- data/spec/integration/regression_spec.rb +6 -0
- data/spec/integration/uuid_spec.rb +4 -0
- data/spec/support/fake_io_reactor.rb +38 -8
- data/spec/support/fake_server.rb +3 -3
- metadata +12 -2
@@ -6,16 +6,12 @@ require 'spec_helper'
|
|
6
6
|
module Cql
|
7
7
|
module Client
|
8
8
|
describe AsynchronousPreparedStatement do
|
9
|
-
let :
|
10
|
-
|
9
|
+
let :connection_manager do
|
10
|
+
ConnectionManager.new
|
11
11
|
end
|
12
12
|
|
13
|
-
let :
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
let :statement_id do
|
18
|
-
"\x2a"
|
13
|
+
let :logger do
|
14
|
+
NullLogger.new
|
19
15
|
end
|
20
16
|
|
21
17
|
let :raw_metadata do
|
@@ -33,7 +29,72 @@ module Cql
|
|
33
29
|
]
|
34
30
|
end
|
35
31
|
|
32
|
+
let :cql do
|
33
|
+
'SELECT * FROM my_table'
|
34
|
+
end
|
35
|
+
|
36
|
+
let :connections do
|
37
|
+
[
|
38
|
+
FakeConnection.new('h0.example.com', 1234, 42),
|
39
|
+
FakeConnection.new('h1.example.com', 1234, 42),
|
40
|
+
FakeConnection.new('h2.example.com', 1234, 42),
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
def handle_request(connection, request)
|
45
|
+
case request
|
46
|
+
when Protocol::PrepareRequest
|
47
|
+
statement_id = [rand(2**31)].pack('c*')
|
48
|
+
connection[:last_prepared_statement_id] = statement_id
|
49
|
+
Protocol::PreparedResultResponse.new(statement_id, raw_metadata)
|
50
|
+
when Protocol::ExecuteRequest
|
51
|
+
Protocol::RowsResultResponse.new(rows, raw_metadata)
|
52
|
+
else
|
53
|
+
raise %(Unexpected request: #{request})
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
before do
|
58
|
+
connections.each do |c|
|
59
|
+
c.handle_request { |r| handle_request(c, r) }
|
60
|
+
end
|
61
|
+
connection_manager.add_connections(connections)
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '.prepare' do
|
65
|
+
it 'prepares a statement on all connections' do
|
66
|
+
f = described_class.prepare(cql, :one, connection_manager, logger)
|
67
|
+
f.value
|
68
|
+
connections.each do |c|
|
69
|
+
c.requests.should include(Protocol::PrepareRequest.new(cql))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns a prepared statement object' do
|
74
|
+
f = described_class.prepare(cql, :two, connection_manager, logger)
|
75
|
+
f.value.should be_a(PreparedStatement)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns a failed future when something goes wrong in the preparation' do
|
79
|
+
connections.each(&:close)
|
80
|
+
f = described_class.prepare(cql, :three, connection_manager, logger)
|
81
|
+
expect { f.value }.to raise_error(NotConnectedError)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'returns a failed future if the preparation results in an error' do
|
85
|
+
connections.each do |connection|
|
86
|
+
connection.stub(:send_request).and_return(Future.resolved(Protocol::ErrorResponse.new(99, 'bork')))
|
87
|
+
end
|
88
|
+
f = described_class.prepare(cql, :quorum, connection_manager, logger)
|
89
|
+
expect { f.value }.to raise_error('bork')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
36
93
|
describe '#metadata' do
|
94
|
+
let :statement do
|
95
|
+
described_class.prepare(cql, :all, connection_manager, logger).value
|
96
|
+
end
|
97
|
+
|
37
98
|
it 'returns the interpreted metadata' do
|
38
99
|
statement.metadata.should be_a(ResultMetadata)
|
39
100
|
statement.metadata['my_column'].should be_a(ColumnMetadata)
|
@@ -41,28 +102,77 @@ module Cql
|
|
41
102
|
end
|
42
103
|
|
43
104
|
describe '#execute' do
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
105
|
+
let :statement do
|
106
|
+
described_class.prepare(cql, :local_quorum, connection_manager, logger).value
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'executes itself on one of the connections' do
|
110
|
+
statement.execute(11, 'hello')
|
111
|
+
requests = connections.flat_map(&:requests).select { |r| r.is_a?(Protocol::ExecuteRequest) }
|
112
|
+
requests.should have(1).item
|
113
|
+
requests.first.metadata.should == raw_metadata
|
114
|
+
requests.first.values.should == [11, 'hello']
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'uses the right statement ID for the connection' do
|
118
|
+
statement.execute(11, 'hello')
|
119
|
+
connection, request = connections.map { |c| [c, c.requests.find { |r| r.is_a?(Protocol::ExecuteRequest) }] }.find { |c, r| r }
|
120
|
+
request.id.should == connection[:last_prepared_statement_id]
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'sends the default consistency level' do
|
124
|
+
statement.execute(11, 'hello')
|
125
|
+
request = connections.flat_map(&:requests).find { |r| r.is_a?(Protocol::ExecuteRequest) }
|
126
|
+
request.consistency.should == :local_quorum
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'sends the consistency given as last argument' do
|
130
|
+
statement.execute(11, 'hello', :two)
|
131
|
+
request = connections.flat_map(&:requests).find { |r| r.is_a?(Protocol::ExecuteRequest) }
|
132
|
+
request.consistency.should == :two
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'when it receives a new connection from the connection manager' do
|
136
|
+
let :new_connection do
|
137
|
+
FakeConnection.new('h3.example.com', 1234, 5)
|
138
|
+
end
|
139
|
+
|
140
|
+
before do
|
141
|
+
statement
|
142
|
+
new_connection.handle_request { |r| handle_request(new_connection, r) }
|
143
|
+
connections.each(&:close)
|
144
|
+
connection_manager.add_connections([new_connection])
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'prepares itself on the connection' do
|
148
|
+
statement.execute(11, 'hello')
|
149
|
+
new_connection.requests.should include(Protocol::PrepareRequest.new(cql))
|
150
|
+
execute_request = new_connection.requests.find { |r| r.is_a?(Protocol::ExecuteRequest) }
|
151
|
+
execute_request.metadata.should == raw_metadata
|
152
|
+
execute_request.values.should == [11, 'hello']
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'logs a message' do
|
156
|
+
logger.stub(:debug)
|
157
|
+
statement.execute(11, 'hello')
|
158
|
+
logger.should have_received(:debug).with(/Statement prepared/).once
|
159
|
+
end
|
48
160
|
end
|
49
161
|
|
50
|
-
it 'returns a future that resolves to
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
result.metadata['my_other_column'].should == ColumnMetadata.new('my_keyspace', 'my_table', 'my_other_column', :text)
|
56
|
-
result.first.should == {'my_column' => 11, 'my_other_column' => 'hello'}
|
162
|
+
it 'returns a future that resolves to the result' do
|
163
|
+
f = statement.execute(11, 'hello')
|
164
|
+
query_result = f.value
|
165
|
+
query_result.metadata['my_other_column'].should == ColumnMetadata.new('my_keyspace', 'my_table', 'my_other_column', :text)
|
166
|
+
query_result.first.should == rows.first
|
57
167
|
end
|
58
168
|
|
59
169
|
it 'returns a failed future when the number of arguments is wrong' do
|
60
170
|
f1 = statement.execute(11, :one)
|
61
171
|
f2 = statement.execute(11, 'foo', 22, :one)
|
62
|
-
expect { f1.
|
63
|
-
expect { f2.
|
172
|
+
expect { f1.value }.to raise_error
|
173
|
+
expect { f2.value }.to raise_error
|
64
174
|
end
|
65
175
|
end
|
66
176
|
end
|
67
177
|
end
|
68
|
-
end
|
178
|
+
end
|
@@ -0,0 +1,335 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
|
6
|
+
module Cql
|
7
|
+
module Client
|
8
|
+
describe ConnectionHelper do
|
9
|
+
let :connection_helper do
|
10
|
+
described_class.new(io_reactor, 9876, nil, 7, logger)
|
11
|
+
end
|
12
|
+
|
13
|
+
let :io_reactor do
|
14
|
+
double(:io_reactor)
|
15
|
+
end
|
16
|
+
|
17
|
+
let :logger do
|
18
|
+
NullLogger.new
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#connect' do
|
22
|
+
let :hosts do
|
23
|
+
%w[host0 host1]
|
24
|
+
end
|
25
|
+
|
26
|
+
let :local_metadata do
|
27
|
+
[
|
28
|
+
['system', 'local', 'data_center', :text],
|
29
|
+
['system', 'local', 'host_id', :uuid],
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
before do
|
34
|
+
io_reactor.stub(:start).and_return(Future.resolved)
|
35
|
+
io_reactor.stub(:connect).and_return(Future.resolved)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'starts the IO reactor' do
|
39
|
+
connection_helper.connect(hosts, nil)
|
40
|
+
io_reactor.should have_received(:start)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'fails when the IO reactor fails to start' do
|
44
|
+
io_reactor.stub(:start).and_return(Future.failed(StandardError.new('bork')))
|
45
|
+
f = connection_helper.connect(hosts, nil)
|
46
|
+
expect { f.value }.to raise_error('bork')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'connects to the specified hosts' do
|
50
|
+
connection_helper.connect(hosts, nil)
|
51
|
+
io_reactor.should have_received(:connect).with('host0', 9876, 7)
|
52
|
+
io_reactor.should have_received(:connect).with('host1', 9876, 7)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'logs a message when a node connects' do
|
56
|
+
logger.stub(:info)
|
57
|
+
io_reactor.stub(:connect).and_return(Future.resolved(FakeConnection.new('host', 9876, 7)))
|
58
|
+
connection_helper.connect(hosts, nil)
|
59
|
+
logger.should have_received(:info).with(/Connected to node/).exactly(hosts.size).times
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'logs a message when connecting to a node' do
|
63
|
+
logger.stub(:debug)
|
64
|
+
io_reactor.stub(:connect).and_return(Future.resolved(FakeConnection.new('host', 9876, 7)))
|
65
|
+
connection_helper.connect(hosts, nil)
|
66
|
+
logger.should have_received(:debug).with(/Connecting to node/).exactly(hosts.size).times
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'fails when all hosts fail to connect' do
|
70
|
+
io_reactor.stub(:connect).and_return(Future.failed(StandardError.new('bork')))
|
71
|
+
f = connection_helper.connect(hosts, nil)
|
72
|
+
expect { f.value }.to raise_error('bork')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'logs a message when a node fails to connect' do
|
76
|
+
logger.stub(:warn)
|
77
|
+
io_reactor.stub(:connect).and_return(Future.failed(StandardError.new('bork')))
|
78
|
+
connection_helper.connect(hosts, nil)
|
79
|
+
logger.should have_received(:warn).with(/Failed connecting to node/).exactly(hosts.size).times
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'fails with an AuthenticationError when the connections fail to connect because of authentication issues' do
|
83
|
+
io_reactor.stub(:connect).and_return(Future.failed(QueryError.new(0x100, 'bork')))
|
84
|
+
f = connection_helper.connect(hosts, nil)
|
85
|
+
expect { f.value }.to raise_error(AuthenticationError)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'initializes the connections' do
|
89
|
+
connection0 = FakeConnection.new('host0', 9876, 7)
|
90
|
+
connection1 = FakeConnection.new('host1', 9876, 7)
|
91
|
+
io_reactor.stub(:connect).with('host0', 9876, 7).and_return(Future.resolved(connection0))
|
92
|
+
io_reactor.stub(:connect).with('host1', 9876, 7).and_return(Future.resolved(connection1))
|
93
|
+
connection_helper.connect(hosts, 'some_keyspace')
|
94
|
+
[connection0, connection1].each do |c|
|
95
|
+
c.requests[0].should be_a(Protocol::StartupRequest)
|
96
|
+
c.requests[1].cql.should match(/SELECT .* FROM system.local/)
|
97
|
+
c.requests[2].cql.should == 'USE some_keyspace'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'fails if authentication is required and no credentials were specified' do
|
102
|
+
connection = FakeConnection.new('host0', 9876, 7)
|
103
|
+
connection.handle_request do |request|
|
104
|
+
if request.is_a?(Protocol::StartupRequest)
|
105
|
+
Protocol::AuthenticateResponse.new('xyz')
|
106
|
+
else
|
107
|
+
connection.default_request_handler(request)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
io_reactor.stub(:connect).with('host0', 9876, 7).and_return(Future.resolved(connection))
|
111
|
+
f = connection_helper.connect(hosts, nil)
|
112
|
+
expect { f.value }.to raise_error(AuthenticationError)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'authenticates when authentication is required and credentials were specified' do
|
116
|
+
credentials = {'username' => 'foo', 'password' => 'bar'}
|
117
|
+
connection_helper = described_class.new(io_reactor, 9876, credentials, 7, logger)
|
118
|
+
connection = FakeConnection.new('host0', 9876, 7)
|
119
|
+
authentication_sent = false
|
120
|
+
connection.handle_request do |request|
|
121
|
+
if request.is_a?(Protocol::StartupRequest)
|
122
|
+
Protocol::AuthenticateResponse.new('xyz')
|
123
|
+
elsif request == Protocol::CredentialsRequest.new(credentials)
|
124
|
+
authentication_sent = true
|
125
|
+
Protocol::ReadyResponse.new
|
126
|
+
else
|
127
|
+
connection.default_request_handler(request)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
io_reactor.stub(:connect).with('host0', 9876, 7).and_return(Future.resolved(connection))
|
131
|
+
f = connection_helper.connect(hosts, nil)
|
132
|
+
f.value
|
133
|
+
authentication_sent.should be_true
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'decorates the connections with :host_id and :data_center' do
|
137
|
+
connection = FakeConnection.new('host0', 9876, 7)
|
138
|
+
connection.handle_request do |request|
|
139
|
+
if request.is_a?(Protocol::QueryRequest) && request.cql =~ /SELECT .* FROM system\.local/
|
140
|
+
row = {'data_center' => 'dc1', 'host_id' => Uuid.new('eac69196-1e28-11e3-8e2b-191b6d153d0c')}
|
141
|
+
Protocol::RowsResultResponse.new([row], local_metadata)
|
142
|
+
else
|
143
|
+
connection.default_request_handler(request)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
io_reactor.stub(:connect).with('host0', 9876, 7).and_return(Future.resolved(connection))
|
147
|
+
connection_helper.connect(hosts, nil)
|
148
|
+
connection[:host_id].should == Uuid.new('eac69196-1e28-11e3-8e2b-191b6d153d0c')
|
149
|
+
connection[:data_center].should == 'dc1'
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'registers a close handler that logs when connections close' do
|
153
|
+
logger.stub(:warn)
|
154
|
+
connection = FakeConnection.new('host', 9876, 7)
|
155
|
+
io_reactor.stub(:connect).and_return(Future.resolved(connection))
|
156
|
+
connection_helper.connect(hosts.take(1), nil)
|
157
|
+
connection.close
|
158
|
+
logger.should have_received(:warn).with(/Connection to node .* closed/)
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'initializes a peer discovery when connected to the specified hosts' do
|
162
|
+
connection_helper.stub(:discover_peers)
|
163
|
+
connection_helper.connect(hosts, nil)
|
164
|
+
connection0 = FakeConnection.new('host0', 9876, 7)
|
165
|
+
connection1 = FakeConnection.new('host1', 9876, 7)
|
166
|
+
io_reactor.stub(:connect).with('host0', 9876, 7).and_return(Future.resolved(connection0))
|
167
|
+
io_reactor.stub(:connect).with('host1', 9876, 7).and_return(Future.resolved(connection1))
|
168
|
+
connection_helper.connect(hosts, 'some_keyspace')
|
169
|
+
connection_helper.should have_received(:discover_peers).with([connection0, connection1], 'some_keyspace')
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'initializes a peer discovery with the successfull connections as seeds' do
|
173
|
+
connection_helper.stub(:discover_peers)
|
174
|
+
connection_helper.connect(hosts, nil)
|
175
|
+
connection = FakeConnection.new('host0', 9876, 7)
|
176
|
+
io_reactor.stub(:connect).with('host0', 9876, 7).and_return(Future.resolved(connection))
|
177
|
+
io_reactor.stub(:connect).with('host1', 9876, 7).and_return(Future.failed(StandardError.new('bork')))
|
178
|
+
connection_helper.connect(hosts, 'some_keyspace')
|
179
|
+
connection_helper.should have_received(:discover_peers).with([connection], 'some_keyspace')
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe '#discover_peers' do
|
184
|
+
let :seed_connections do
|
185
|
+
[
|
186
|
+
FakeConnection.new('host0', 9042, 5),
|
187
|
+
FakeConnection.new('host1', 9042, 5),
|
188
|
+
FakeConnection.new('host2', 9042, 5),
|
189
|
+
]
|
190
|
+
end
|
191
|
+
|
192
|
+
let :seed_connection_rows do
|
193
|
+
[
|
194
|
+
{'peer' => IPAddr.new('2.0.0.0'), 'rpc_address' => IPAddr.new('1.0.0.0'), 'data_center' => 'dc1', 'host_id' => Uuid.new('eac69196-1e28-11e3-8e2b-191b6d153d0c')},
|
195
|
+
{'peer' => IPAddr.new('2.0.0.1'), 'rpc_address' => IPAddr.new('1.0.0.1'), 'data_center' => 'dc1', 'host_id' => Uuid.new('fa5f9562-1e28-11e3-bf05-3d3a155d0608')},
|
196
|
+
{'peer' => IPAddr.new('2.0.0.2'), 'rpc_address' => IPAddr.new('1.0.0.2'), 'data_center' => 'dc1', 'host_id' => Uuid.new('018b8f1c-1e29-11e3-b14f-532d016437ce')},
|
197
|
+
]
|
198
|
+
end
|
199
|
+
|
200
|
+
let :extra_connection_rows do
|
201
|
+
[
|
202
|
+
{'peer' => IPAddr.new('2.0.0.3'), 'rpc_address' => IPAddr.new('1.0.0.3'), 'data_center' => 'dc1', 'host_id' => Uuid.new('7a3ccace-1e2a-11e3-a447-43312b1c66e4')},
|
203
|
+
{'peer' => IPAddr.new('2.0.0.4'), 'rpc_address' => IPAddr.new('1.0.0.4'), 'data_center' => 'dc1', 'host_id' => Uuid.new('7bbd4e32-1e2a-11e3-b21d-69d7c02cece8')},
|
204
|
+
{'peer' => IPAddr.new('2.0.0.5'), 'rpc_address' => IPAddr.new('1.0.0.5'), 'data_center' => 'dc1', 'host_id' => Uuid.new('7d7e76f6-1e2a-11e3-bfa0-4fb416ef4064')},
|
205
|
+
]
|
206
|
+
end
|
207
|
+
|
208
|
+
let :peer_metadata do
|
209
|
+
[
|
210
|
+
['system', 'peers', 'peer', :inet],
|
211
|
+
['system', 'peers', 'data_center', :varchar],
|
212
|
+
['system', 'peers', 'host_id', :uuid],
|
213
|
+
['system', 'peers', 'rpc_address', :inet],
|
214
|
+
]
|
215
|
+
end
|
216
|
+
|
217
|
+
before do
|
218
|
+
seed_connections.each_with_index do |c, i|
|
219
|
+
c[:host_id] = seed_connection_rows[i]['host_id']
|
220
|
+
c[:data_center] = seed_connection_rows[i]['data_center']
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def peer_request_response
|
225
|
+
seed_connections.each do |c|
|
226
|
+
c.handle_request do |request|
|
227
|
+
if request.cql =~ /SELECT .* FROM system\.peers/
|
228
|
+
Protocol::RowsResultResponse.new(yield, peer_metadata)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'returns immediately if there are no seed connections' do
|
235
|
+
f = connection_helper.discover_peers([], nil)
|
236
|
+
f.value
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'logs a message when it begins' do
|
240
|
+
logger.stub(:debug)
|
241
|
+
connection_helper.discover_peers([], nil)
|
242
|
+
logger.should have_received(:debug).with(/Looking for additional nodes/)
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'asks a random connection for its peers' do
|
246
|
+
connection_helper.discover_peers(seed_connections, nil)
|
247
|
+
connection = seed_connections.find { |c| c.requests.any? }
|
248
|
+
connection.requests.first.cql.should match(/SELECT .* FROM system\.peers/)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'returns an empty list when it only finds nodes it\'s already connected to' do
|
252
|
+
peer_request_response { seed_connection_rows }
|
253
|
+
f = connection_helper.discover_peers(seed_connections, nil)
|
254
|
+
f.value.should be_empty
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'logs a message when it finds no new nodes' do
|
258
|
+
logger.stub(:debug)
|
259
|
+
peer_request_response { seed_connection_rows }
|
260
|
+
connection_helper.discover_peers(seed_connections, nil)
|
261
|
+
logger.should have_received(:debug).with(/No additional nodes found/)
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'returns an empty list when it only finds nodes data centers other than those of the seed connections' do
|
265
|
+
seed_connections[1][:data_center] = 'dc2'
|
266
|
+
seed_connection_rows[1]['data_center'] = 'dc2'
|
267
|
+
extra_connection_rows[0]['data_center'] = 'dc3'
|
268
|
+
peer_request_response { seed_connection_rows + extra_connection_rows.take(1) }
|
269
|
+
f = connection_helper.discover_peers(seed_connections, nil)
|
270
|
+
f.value.should be_empty
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'connects to the nodes it finds that it is not already connected to' do
|
274
|
+
connection = FakeConnection.new('host3', 9876, 7)
|
275
|
+
io_reactor.stub(:connect).with('1.0.0.3', 9876, 7).and_return(Future.resolved(connection))
|
276
|
+
peer_request_response { seed_connection_rows + extra_connection_rows.take(1) }
|
277
|
+
f = connection_helper.discover_peers(seed_connections, nil)
|
278
|
+
f.value
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'logs the number of new nodes found' do
|
282
|
+
logger.stub(:debug)
|
283
|
+
connection = FakeConnection.new('host3', 9876, 7)
|
284
|
+
io_reactor.stub(:connect).with('1.0.0.3', 9876, 7).and_return(Future.resolved(connection))
|
285
|
+
peer_request_response { seed_connection_rows + extra_connection_rows.take(1) }
|
286
|
+
connection_helper.discover_peers(seed_connections, nil)
|
287
|
+
logger.should have_received(:debug).with(/1 additional nodes found/)
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'returns the new connections' do
|
291
|
+
connection = FakeConnection.new('host3', 9876, 7)
|
292
|
+
io_reactor.stub(:connect).with('1.0.0.3', 9876, 7).and_return(Future.resolved(connection))
|
293
|
+
peer_request_response { seed_connection_rows + extra_connection_rows.take(1) }
|
294
|
+
f = connection_helper.discover_peers(seed_connections, nil)
|
295
|
+
f.value.should == [connection]
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'initializes the new connections' do
|
299
|
+
connection = FakeConnection.new('host3', 9876, 7)
|
300
|
+
io_reactor.stub(:connect).with('1.0.0.3', 9876, 7).and_return(Future.resolved(connection))
|
301
|
+
peer_request_response { seed_connection_rows + extra_connection_rows.take(1) }
|
302
|
+
f = connection_helper.discover_peers(seed_connections, 'some_keyspace')
|
303
|
+
f.value
|
304
|
+
connection.requests[0].should be_a(Protocol::StartupRequest)
|
305
|
+
connection.requests[1].cql.should match(/SELECT .* FROM system.local/)
|
306
|
+
connection.requests[2].cql.should == 'USE some_keyspace'
|
307
|
+
end
|
308
|
+
|
309
|
+
it 'connects only to node in the same data centers as the seed nodes' do
|
310
|
+
seed_connections[1][:data_center] = 'dc2'
|
311
|
+
seed_connection_rows[1]['data_center'] = 'dc2'
|
312
|
+
extra_connection_rows[0]['data_center'] = 'dc3'
|
313
|
+
extra_connection_rows[1]['data_center'] = 'dc2'
|
314
|
+
extra_connection_rows[2]['data_center'] = 'dc1'
|
315
|
+
connection4 = FakeConnection.new('host4', 9876, 7)
|
316
|
+
connection5 = FakeConnection.new('host5', 9876, 7)
|
317
|
+
io_reactor.stub(:connect).with('1.0.0.4', 9876, 7).and_return(Future.resolved(connection4))
|
318
|
+
io_reactor.stub(:connect).with('1.0.0.5', 9876, 7).and_return(Future.resolved(connection5))
|
319
|
+
peer_request_response { seed_connection_rows + extra_connection_rows.take(3) }
|
320
|
+
f = connection_helper.discover_peers(seed_connections, nil)
|
321
|
+
f.value.should == [connection4, connection5]
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'uses the peer address instead of the RPC address when latter is 0.0.0.0' do
|
325
|
+
extra_connection_rows[0]['rpc_address'] = IPAddr.new('0.0.0.0')
|
326
|
+
connection = FakeConnection.new('host3', 9876, 7)
|
327
|
+
io_reactor.stub(:connect).with(extra_connection_rows[0]['peer'].to_s, 9876, 7).and_return(Future.resolved(connection))
|
328
|
+
peer_request_response { seed_connection_rows + extra_connection_rows.take(1) }
|
329
|
+
f = connection_helper.discover_peers(seed_connections, nil)
|
330
|
+
f.value
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|