Skip to content

Commit

Permalink
Update test
Browse files Browse the repository at this point in the history
Update getRetryingTarantoolClient in ReconnectIT and add test_should_retryDelete_ifRecordsNotFound test to use it in retrying client documentation

Needed for #309
  • Loading branch information
iDneprov committed Feb 7, 2023
1 parent 3717bb0 commit 5819ca9
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 21 deletions.
97 changes: 76 additions & 21 deletions src/test/java/io/tarantool/driver/integration/ReconnectIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import io.tarantool.driver.api.TarantoolClusterAddressProvider;
import io.tarantool.driver.api.TarantoolResult;
import io.tarantool.driver.api.TarantoolServerAddress;
import io.tarantool.driver.api.conditions.Conditions;
import io.tarantool.driver.api.space.TarantoolSpaceOperations;
import io.tarantool.driver.api.tuple.DefaultTarantoolTupleFactory;
import io.tarantool.driver.api.tuple.TarantoolTuple;
import io.tarantool.driver.api.tuple.TarantoolTupleFactory;
Expand Down Expand Up @@ -46,13 +48,22 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* @author Oleg Kuznetsov
* @author Ivan Dneprov
* <p>
* WARNING: If you updated the code in this file, don't forget to update the MultiInstanceConnecting.md and
* docs/RetryingTarantoolClient.md permalinks!
*/
@Testcontainers
public class ReconnectIT extends SharedCartridgeContainer {

private static final Logger logger = LoggerFactory.getLogger(ReconnectIT.class);

private static String USER_NAME;
private static String PASSWORD;
private static final String SPACE_NAME = "test__profile";
private static final String PK_FIELD_NAME = "profile_id";

private static final DefaultMessagePackMapperFactory mapperFactory = DefaultMessagePackMapperFactory.getInstance();
private static final TarantoolTupleFactory tupleFactory =
Expand All @@ -66,21 +77,54 @@ public static void setUp() throws TimeoutException {
PASSWORD = container.getPassword();
}

@Test
public void test_should_retryDelete_ifRecordsNotFound() {
// Creating multiple clients
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> crudClient = getCrudClient();
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> retryingClient =
getRetryingTarantoolClient(crudClient);

TarantoolSpaceOperations<TarantoolTuple, TarantoolResult<TarantoolTuple>> space =
crudClient.space(SPACE_NAME);
space.truncate().join();

// Use TarantoolTupleFactory for instantiating new tuples
TarantoolTupleFactory tupleFactory = new DefaultTarantoolTupleFactory(
crudClient.getConfig().getMessagePackMapper());

// Start another thread that will insert value after 100 ms
new Thread(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
space.insert(tupleFactory.create(1, null, "FIO", 50, 100)).join();
}).start();

// Call delete_with_error_if_not_found before record was inserted
Conditions conditions = Conditions.equals(PK_FIELD_NAME, 1);
assertDoesNotThrow(() -> retryingClient.space(SPACE_NAME).delete(conditions).join());
TarantoolResult<TarantoolTuple> selectResult = space.select(conditions).join();
assertEquals(0, selectResult.size());
}

/**
* Checking if this test is valid is here
* {@link TarantoolErrorsIT#test_should_throwTarantoolNoSuchProcedureException_ifProcedureIsNil}
*/
@Test
public void test_should_reconnect_ifCrudProcedureIsNotDefined() {
//when
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> clusterClient = getClusterClient();
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> retryingClient = getRetryingTarantoolClient();
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> crudClient = getCrudClient();
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> retryingClient =
getRetryingTarantoolClient(crudClient);

try {
//save procedure to tmp variable set it to nil and call
clusterClient.eval("rawset(_G, 'tmp_test_no_such_procedure', test_no_such_procedure)")
.thenAccept(c -> clusterClient.eval("rawset(_G, 'test_no_such_procedure', nil)"))
.thenApply(c -> clusterClient.call("test_no_such_procedure"))
crudClient.eval("rawset(_G, 'tmp_test_no_such_procedure', test_no_such_procedure)")
.thenAccept(c -> crudClient.eval("rawset(_G, 'test_no_such_procedure', nil)"))
.thenApply(c -> crudClient.call("test_no_such_procedure"))
.join();
} catch (CompletionException exception) {
assertTrue(exception.getCause() instanceof TarantoolNoSuchProcedureException);
Expand All @@ -93,30 +137,36 @@ public void test_should_reconnect_ifCrudProcedureIsNotDefined() {
} catch (InterruptedException e) {
e.printStackTrace();
}
clusterClient.eval("rawset(_G, 'test_no_such_procedure', tmp_test_no_such_procedure)").join();
crudClient.eval("rawset(_G, 'test_no_such_procedure', tmp_test_no_such_procedure)").join();
}).start();

assertDoesNotThrow(() -> retryingClient.call("test_no_such_procedure").join());
assertEquals("test_no_such_procedure", retryingClient.call("test_no_such_procedure").join().get(0));
}

private TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> getClusterClient() {
return TarantoolClientFactory
.createClient()
private TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> getCrudClient() {
return TarantoolClientFactory.createClient()
// You can connect to multiple routers
.withAddresses(
new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3301)),
new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3302)),
new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3303))
)
// For connecting to a Cartridge application,
// use the value of cluster_cookie parameter in the init.lua file
.withCredentials(USER_NAME, PASSWORD)
// Number of connections per Tarantool instance
.withConnections(10)
// Specify using the default CRUD proxy operations mapping configuration
.withProxyMethodMapping()
.build();
}

@Test
public void test_should_reconnect_ifReconnectIsInvoked() throws Exception {
//when
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> client = getRetryingTarantoolClient();
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> client =
getRetryingTarantoolClient(getCrudClient());

// getting all routers uuids
final Set<String> routerUuids = getInstancesUuids(client);
Expand All @@ -141,18 +191,23 @@ public void test_should_reconnect_ifReconnectIsInvoked() throws Exception {
assertEquals(routerUuids.size(), uuidsAfterReconnect.size());
}

private TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> getRetryingTarantoolClient() {
return TarantoolClientFactory.createClient()
.withAddresses(
new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3301)),
new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3302)),
new TarantoolServerAddress(container.getRouterHost(), container.getMappedPort(3303))
)
.withCredentials(USER_NAME, PASSWORD)
.withConnections(10)
.withProxyMethodMapping()
private TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> getRetryingTarantoolClient(
TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> client) {

return TarantoolClientFactory.configureClient(client)
// Configure a custom delete function
.withProxyMethodMapping(builder -> builder.withDeleteFunctionName("delete_with_error_if_not_found"))
// Set retrying policy
// First parameter is number of attempts
.withRetryingByNumberOfAttempts(5,
retryNetworkErrors().or(retryTarantoolNoSuchProcedureErrors()),
// You can use default predicates from TarantoolRequestRetryPolicies for checking errors
retryNetworkErrors()
// Also you can use your own predicates and combine them with each other
.or(e -> e.getMessage().contains("Unsuccessful attempt"))
.or(e -> e.getMessage().contains("Records not found"))
// Or with defaults
.or(retryTarantoolNoSuchProcedureErrors()),
// Also you can set delay in millisecond between attempts
factory -> factory.withDelay(300)
)
.build();
Expand Down
13 changes: 13 additions & 0 deletions src/test/resources/cartridge/app/roles/api_router.lua
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,19 @@ local function box_error_non_network_error()
return nil, box.error.new(box.error.WAL_IO):unpack()
end

function delete_with_error_if_not_found(space_name, key, opts)
local result, err = crud.delete(space_name, key, opts)
if err then
return nil, err
end

if #result.rows == 0 then
return nil, "Records not found"
end

return result
end

local function test_no_such_procedure()
return 'test_no_such_procedure'
end
Expand Down

0 comments on commit 5819ca9

Please sign in to comment.