11package io .tarantool .driver .integration ;
22
3- import io .tarantool .driver .api .TarantoolClientConfig ;
4- import io .tarantool .driver .api .TarantoolClusterAddressProvider ;
5- import io .tarantool .driver .api .TarantoolServerAddress ;
6- import io .tarantool .driver .api .connection .TarantoolConnection ;
7- import io .tarantool .driver .api .retry .TarantoolRequestRetryPolicies ;
8- import io .tarantool .driver .auth .SimpleTarantoolCredentials ;
9- import io .tarantool .driver .core .ClusterTarantoolTupleClient ;
10- import io .tarantool .driver .core .ProxyTarantoolTupleClient ;
11- import io .tarantool .driver .core .RetryingTarantoolTupleClient ;
12- import org .junit .jupiter .api .BeforeAll ;
13- import org .junit .jupiter .api .Test ;
14- import org .rnorth .ducttape .unreliables .Unreliables ;
15- import org .testcontainers .containers .Container ;
16- import org .testcontainers .junit .jupiter .Testcontainers ;
17-
183import java .io .IOException ;
194import java .util .ArrayList ;
205import java .util .Arrays ;
216import java .util .Collections ;
227import java .util .List ;
238import java .util .concurrent .CompletableFuture ;
9+ import java .util .concurrent .ExecutionException ;
2410import java .util .concurrent .TimeUnit ;
2511import java .util .concurrent .TimeoutException ;
2612import java .util .concurrent .atomic .AtomicReference ;
13+ import java .util .stream .Collectors ;
2714
15+ import org .jetbrains .annotations .NotNull ;
16+ import org .junit .jupiter .api .BeforeAll ;
17+ import org .junit .jupiter .api .Test ;
18+ import org .rnorth .ducttape .unreliables .Unreliables ;
19+ import org .testcontainers .containers .Container ;
20+ import org .testcontainers .junit .jupiter .Testcontainers ;
2821import static org .junit .jupiter .api .Assertions .assertDoesNotThrow ;
2922import static org .junit .jupiter .api .Assertions .assertEquals ;
3023import static org .junit .jupiter .api .Assertions .assertTrue ;
3124
25+ import io .tarantool .driver .api .TarantoolClient ;
26+ import io .tarantool .driver .api .TarantoolClientConfig ;
27+ import io .tarantool .driver .api .TarantoolClientFactory ;
28+ import io .tarantool .driver .api .TarantoolClusterAddressProvider ;
29+ import io .tarantool .driver .api .TarantoolResult ;
30+ import io .tarantool .driver .api .TarantoolServerAddress ;
31+ import io .tarantool .driver .api .connection .TarantoolConnection ;
32+ import io .tarantool .driver .api .retry .TarantoolRequestRetryPolicies ;
33+ import io .tarantool .driver .api .tuple .TarantoolTuple ;
34+ import io .tarantool .driver .auth .SimpleTarantoolCredentials ;
35+ import io .tarantool .driver .auth .TarantoolCredentials ;
36+ import io .tarantool .driver .cluster .BinaryClusterDiscoveryEndpoint ;
37+ import io .tarantool .driver .cluster .BinaryDiscoveryClusterAddressProvider ;
38+ import io .tarantool .driver .cluster .TarantoolClusterDiscoveryConfig ;
39+ import io .tarantool .driver .cluster .TestWrappedClusterAddressProvider ;
40+ import io .tarantool .driver .core .ClusterTarantoolTupleClient ;
41+ import io .tarantool .driver .core .ProxyTarantoolTupleClient ;
42+ import io .tarantool .driver .core .RetryingTarantoolTupleClient ;
43+
3244/**
3345 * @author Alexey Kuzin
3446 * @author Artyom Dubinin
@@ -49,17 +61,18 @@ public static void setUp() throws TimeoutException {
4961
5062 private TarantoolClientConfig .Builder prepareConfig () {
5163 return TarantoolClientConfig .builder ()
52- .withCredentials (new SimpleTarantoolCredentials (USER_NAME , PASSWORD ))
53- .withConnectTimeout (1000 )
54- .withReadTimeout (1000 );
64+ .withCredentials (new SimpleTarantoolCredentials (USER_NAME , PASSWORD ))
65+ .withConnectTimeout (1000 )
66+ .withReadTimeout (1000 );
5567 }
5668
5769 private RetryingTarantoolTupleClient setupRouterClient (int port , int retries , long delay ) {
5870 ClusterTarantoolTupleClient clusterClient = new ClusterTarantoolTupleClient (
5971 prepareConfig ().build (), container .getRouterHost (), container .getMappedPort (port ));
6072
6173 return new RetryingTarantoolTupleClient (new ProxyTarantoolTupleClient (clusterClient ),
62- TarantoolRequestRetryPolicies .byNumberOfAttempts (retries ).withDelay (delay ).build ());
74+ TarantoolRequestRetryPolicies .byNumberOfAttempts (retries )
75+ .withDelay (delay ).build ());
6376 }
6477
6578 private RetryingTarantoolTupleClient setupClusterClient (
@@ -70,7 +83,143 @@ private RetryingTarantoolTupleClient setupClusterClient(
7083
7184 ProxyTarantoolTupleClient client = new ProxyTarantoolTupleClient (clusterClient );
7285 return new RetryingTarantoolTupleClient (client ,
73- TarantoolRequestRetryPolicies .byNumberOfAttempts (retries , e -> true ).withDelay (delay ).build ());
86+ TarantoolRequestRetryPolicies .byNumberOfAttempts (retries , e -> true )
87+ .withDelay (delay ).build ());
88+ }
89+
90+ @ Test
91+ void test_roundRobin_shouldWorkCorrectly_withDiscoveryAndConnections ()
92+ throws ExecutionException , InterruptedException , IOException {
93+
94+ TarantoolClient <TarantoolTuple , TarantoolResult <TarantoolTuple >> clusterClient =
95+ getTarantoolClusterClientWithDiscovery (2 , 5_000 );
96+
97+ TarantoolClient <TarantoolTuple , TarantoolResult <TarantoolTuple >> routerClient1 = getSimpleClient (3301 );
98+ TarantoolClient <TarantoolTuple , TarantoolResult <TarantoolTuple >> routerClient2 = getSimpleClient (3302 );
99+ TarantoolClient <TarantoolTuple , TarantoolResult <TarantoolTuple >> routerClient3 = getSimpleClient (3303 );
100+ // 3306 isn't in cluster topology yet
101+ TarantoolClient <TarantoolTuple , TarantoolResult <TarantoolTuple >> routerClient4 = getSimpleClient (3306 );
102+
103+ int callCounter = 15 ;
104+ for (int i = 0 ; i < callCounter ; i ++) {
105+ clusterClient .callForSingleResult (
106+ "simple_long_running_function" , Arrays .asList (0 , true ), Boolean .class ).get ();
107+ }
108+
109+ String getAllConnectionCalls =
110+ "return box.space.request_counters.index.count:select(0, {iterator = box.index.GT})" ;
111+ // 15 calls on 3 routers on 2 connection == 15 / 3 == 5 / 2 == 2 or 3 calls per connect
112+ for (TarantoolClient router : Arrays .asList (routerClient1 , routerClient2 , routerClient3 )) {
113+ assertEquals (Arrays .asList (2 , 3 ), getCallCountersPerConnection (getAllConnectionCalls , router ));
114+ }
115+
116+ // add new router
117+ // put 3306 in topology as router
118+ routerClient1 .eval ("cartridge = require('cartridge') " +
119+ "replicasets = { " +
120+ " { " +
121+ " alias = 'app-router-fourth', " +
122+ " roles = { 'vshard-router', 'app.roles.custom', 'app.roles.api_router' }, " +
123+ " join_servers = { { uri = 'localhost:3306' } } " +
124+ " }} " +
125+ "cartridge.admin_edit_topology({ replicasets = replicasets }) " ).join ();
126+
127+ // wait until discovery get topology
128+ Thread .sleep (5_000 );
129+
130+ callCounter = 16 ;
131+ // 16 / 4 / 2 = 2 requests per connect
132+ for (int i = 0 ; i < callCounter ; i ++) {
133+ clusterClient .callForSingleResult (
134+ "simple_long_running_function" , Arrays .asList (0 , true ), Boolean .class ).get ();
135+ }
136+
137+ for (TarantoolClient router :
138+ Arrays .asList (routerClient1 , routerClient2 , routerClient3 )) {
139+ assertEquals (Arrays .asList (4 , 5 ), getCallCountersPerConnection (getAllConnectionCalls , router ));
140+ }
141+
142+ Object routerCallCounterPerConnection = getCallCountersPerConnection (getAllConnectionCalls , routerClient4 );
143+ assertEquals (Arrays .asList (2 , 2 ), routerCallCounterPerConnection );
144+
145+ String pid = container .execInContainer ("pgrep" , "-f" , "testapp@second-router" )
146+ .getStdout ().replace ("\n " , "" );
147+ container .execInContainer ("kill" , "-9" , pid );
148+ // wait until discovery get topology
149+ Thread .sleep (5_000 );
150+
151+ callCounter = 12 ;
152+ // 12 / 3 / 2 = 2 requests per connect
153+ for (int i = 0 ; i < callCounter ; i ++) {
154+ clusterClient .callForSingleResult (
155+ "simple_long_running_function" , Arrays .asList (0 , true ), Boolean .class ).get ();
156+ }
157+ Thread .sleep (5_000 );
158+ for (TarantoolClient router :
159+ Arrays .asList (routerClient1 , routerClient3 )) {
160+ assertEquals (Arrays .asList (6 , 7 ), getCallCountersPerConnection (getAllConnectionCalls , router ));
161+ }
162+ routerCallCounterPerConnection = getCallCountersPerConnection (getAllConnectionCalls , routerClient4 );
163+ assertEquals (Arrays .asList (4 , 4 ), routerCallCounterPerConnection );
164+ }
165+
166+ private static TarantoolClient <TarantoolTuple , TarantoolResult <TarantoolTuple >> getSimpleClient (Integer port ) {
167+ return TarantoolClientFactory .createClient ()
168+ .withAddress (container .getRouterHost (), container .getMappedPort (port ))
169+ .withCredentials (USER_NAME , PASSWORD )
170+ .build ();
171+ }
172+
173+ private static TarantoolClient <TarantoolTuple , TarantoolResult <TarantoolTuple >>
174+ getTarantoolClusterClientWithDiscovery (
175+ int connections , int delay ) {
176+ String host = container .getRouterHost ();
177+ int port = container .getRouterPort ();
178+
179+ TarantoolCredentials credentials = new SimpleTarantoolCredentials (
180+ USER_NAME ,
181+ PASSWORD
182+ );
183+ TarantoolClientConfig config = TarantoolClientConfig .builder ()
184+ .withCredentials (credentials )
185+ .build ();
186+
187+ BinaryClusterDiscoveryEndpoint endpoint = new BinaryClusterDiscoveryEndpoint .Builder ()
188+ .withClientConfig (config )
189+ .withEntryFunction ("get_routers" )
190+ .withEndpointProvider (() -> Collections .singletonList (
191+ new TarantoolServerAddress (
192+ host , port
193+ )))
194+ .build ();
195+
196+ TarantoolClusterDiscoveryConfig clusterDiscoveryConfig = new TarantoolClusterDiscoveryConfig .Builder ()
197+ .withDelay (delay )
198+ .withEndpoint (endpoint )
199+ .build ();
200+
201+ BinaryDiscoveryClusterAddressProvider discoveryProvider = new BinaryDiscoveryClusterAddressProvider (
202+ clusterDiscoveryConfig );
203+
204+ TarantoolClusterAddressProvider wrapperDiscoveryProvider
205+ = new TestWrappedClusterAddressProvider (discoveryProvider , container ); // because we use docker ports
206+
207+ return TarantoolClientFactory .createClient ()
208+ .withAddressProvider (wrapperDiscoveryProvider )
209+ .withCredentials (USER_NAME , PASSWORD )
210+ .withConnections (connections )
211+ .build ();
212+ }
213+
214+ @ NotNull
215+ private static Object getCallCountersPerConnection (String getAllConnectionCalls , TarantoolClient router ) {
216+ List <?> luaResponse = router .eval (getAllConnectionCalls ).join ();
217+ ArrayList tuples = (ArrayList ) luaResponse .get (0 ); // because lua has multivalue response
218+
219+ Object routerCallCounterPerConnection = tuples .stream ()
220+ .map (item -> ((ArrayList ) item ).get (1 ))
221+ .collect (Collectors .toList ());
222+ return routerCallCounterPerConnection ;
74223 }
75224
76225 @ Test
0 commit comments