1
1
#include < clickhouse/client.h>
2
2
3
+ #include " clickhouse/base/socket.h"
3
4
#include " readonly_client_test.h"
4
5
#include " connection_failed_client_test.h"
6
+ #include " ut/utils_comparison.h"
5
7
#include " utils.h"
8
+ #include " ut/roundtrip_column.h"
9
+ #include " ut/value_generators.h"
6
10
7
11
#include < gtest/gtest.h>
8
12
13
+ #include < memory>
9
14
#include < optional>
15
+ #include < ostream>
16
+ #include < string_view>
10
17
#include < thread>
11
18
#include < chrono>
12
19
13
20
using namespace clickhouse ;
14
21
22
+ namespace clickhouse {
23
+ std::ostream & operator << (std::ostream & ostr, const Endpoint & endpoint) {
24
+ return ostr << endpoint.host << " :" << endpoint.port ;
25
+ }
26
+ }
27
+
28
+ template <typename T>
29
+ std::shared_ptr<T> createTableWithOneColumn (Client & client, const std::string & table_name, const std::string & column_name)
30
+ {
31
+ auto col = std::make_shared<T>();
32
+ const auto type_name = col->GetType ().GetName ();
33
+
34
+ client.Execute (" DROP TEMPORARY TABLE IF EXISTS " + table_name + " ;" );
35
+ client.Execute (" CREATE TEMPORARY TABLE IF NOT EXISTS " + table_name + " ( " + column_name + " " + type_name + " )" );
36
+
37
+ return col;
38
+ }
39
+
15
40
// Use value-parameterized tests to run same tests with different client
16
41
// options.
17
42
class ClientCase : public testing ::TestWithParam<ClientOptions> {
@@ -27,13 +52,9 @@ class ClientCase : public testing::TestWithParam<ClientOptions> {
27
52
template <typename T>
28
53
std::shared_ptr<T> createTableWithOneColumn (Block & block)
29
54
{
30
- auto col = std::make_shared<T>();
31
- const auto type_name = col->GetType ().GetName ();
32
-
33
- client_->Execute (" DROP TEMPORARY TABLE IF EXISTS " + table_name + " ;" );
34
- client_->Execute (" CREATE TEMPORARY TABLE IF NOT EXISTS " + table_name + " ( " + column_name + " " + type_name + " )" );
55
+ auto col = ::createTableWithOneColumn<T>(*client_, table_name, column_name);
35
56
36
- block.AppendColumn (" test_column " , col);
57
+ block.AppendColumn (column_name , col);
37
58
38
59
return col;
39
60
}
@@ -1352,3 +1373,91 @@ INSTANTIATE_TEST_SUITE_P(ResetConnectionClientTest, ResetConnectionTestCase,
1352
1373
.SetRetryTimeout (std::chrono::seconds (1 ))
1353
1374
}
1354
1375
));
1376
+
1377
+ struct CountingSocketFactoryAdapter : public SocketFactory {
1378
+
1379
+ using ConnectRequests = std::vector<std::pair<ClientOptions, Endpoint>>;
1380
+
1381
+ SocketFactory & socket_factory;
1382
+ ConnectRequests & connect_requests;
1383
+
1384
+ CountingSocketFactoryAdapter (SocketFactory & socket_factory, ConnectRequests& connect_requests)
1385
+ : socket_factory(socket_factory)
1386
+ , connect_requests(connect_requests)
1387
+ {}
1388
+
1389
+ std::unique_ptr<SocketBase> connect (const ClientOptions& opts, const Endpoint& endpoint) {
1390
+ connect_requests.emplace_back (opts, endpoint);
1391
+
1392
+ return socket_factory.connect (opts, endpoint);
1393
+ }
1394
+
1395
+ void sleepFor (const std::chrono::milliseconds& duration) {
1396
+ return socket_factory.sleepFor (duration);
1397
+ }
1398
+
1399
+ size_t GetConnectRequestsCount () const {
1400
+ return connect_requests.size ();
1401
+ }
1402
+
1403
+ };
1404
+
1405
+ TEST (SimpleClientTest, issue_335) {
1406
+ // Make sure Client connects to server even with ClientOptions.SetSendRetries(0)
1407
+ auto vals = MakeStrings ();
1408
+ auto col = std::make_shared<ColumnString>(vals);
1409
+
1410
+ CountingSocketFactoryAdapter::ConnectRequests connect_requests;
1411
+ std::unique_ptr<SocketFactory> wrapped_socket_factory = std::make_unique<NonSecureSocketFactory>();
1412
+ std::unique_ptr<SocketFactory> socket_factory = std::make_unique<CountingSocketFactoryAdapter>(*wrapped_socket_factory, connect_requests);
1413
+
1414
+ Client client (ClientOptions (LocalHostEndpoint)
1415
+ .SetSendRetries (0 ), // <<=== crucial for reproducing https://github.com/ClickHouse/clickhouse-cpp/issues/335
1416
+ std::move (socket_factory));
1417
+
1418
+ EXPECT_EQ (1u , connect_requests.size ());
1419
+ EXPECT_TRUE (CompareRecursive (vals, *RoundtripColumnValuesTyped (client, col)));
1420
+
1421
+ connect_requests.clear ();
1422
+
1423
+ client.ResetConnection ();
1424
+ EXPECT_EQ (1u , connect_requests.size ());
1425
+ EXPECT_TRUE (CompareRecursive (vals, *RoundtripColumnValuesTyped (client, col)));
1426
+
1427
+ connect_requests.clear ();
1428
+
1429
+ client.ResetConnectionEndpoint ();
1430
+ EXPECT_EQ (1u , connect_requests.size ());
1431
+ EXPECT_TRUE (CompareRecursive (vals, *RoundtripColumnValuesTyped (client, col)));
1432
+ }
1433
+
1434
+ TEST (SimpleClientTest, issue_335_reconnects_count) {
1435
+ // Make sure that client attempts to connect to each endpoint at least once.
1436
+ CountingSocketFactoryAdapter::ConnectRequests connect_requests;
1437
+ std::unique_ptr<SocketFactory> wrapped_socket_factory = std::make_unique<NonSecureSocketFactory>();
1438
+ std::unique_ptr<SocketFactory> socket_factory = std::make_unique<CountingSocketFactoryAdapter>(*wrapped_socket_factory, connect_requests);
1439
+
1440
+ const std::vector<Endpoint> endpoints = {
1441
+ Endpoint{" foo-invalid-hostname" , 1234 },
1442
+ Endpoint{" bar-invalid-hostname" , 4567 },
1443
+ };
1444
+
1445
+ EXPECT_ANY_THROW (
1446
+ Client (ClientOptions ()
1447
+ .SetEndpoints (endpoints)
1448
+ .SetSendRetries (0 ), // <<=== crucial for reproducing https://github.com/ClickHouse/clickhouse-cpp/issues/335
1449
+ std::move (socket_factory));
1450
+ );
1451
+
1452
+ EXPECT_EQ (endpoints.size (), connect_requests.size ());
1453
+ // make sure there was an attempt to connect to each endpoint at least once.
1454
+ for (const auto & endpoint : endpoints)
1455
+ {
1456
+ auto p = std::find_if (connect_requests.begin (), connect_requests.end (), [&endpoint](const auto & connect_request) {
1457
+ return connect_request.second == endpoint;
1458
+ });
1459
+
1460
+ EXPECT_TRUE (connect_requests.end () != p)
1461
+ << " \t There was no attempt to connect to endpoint " << endpoint;
1462
+ }
1463
+ }
0 commit comments