diff --git a/.github/workflows/ubuntu-master.yml b/.github/workflows/ubuntu-master.yml
index 2cd8c39c..81518a31 100644
--- a/.github/workflows/ubuntu-master.yml
+++ b/.github/workflows/ubuntu-master.yml
@@ -10,26 +10,41 @@ on:
branches: [ master ]
jobs:
- build:
-
+ tests-ce:
runs-on: ubuntu-latest
-
+ strategy:
+ matrix:
+ tarantool-version: [ "1.10", "2.8" ]
+ fail-fast: false
steps:
- uses: actions/checkout@v2
+
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
+
- name: Cache Maven packages
uses: actions/cache@v2
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
+
+ - name: Cache docker images
+ uses: satackey/action-docker-layer-caching@v0.0.11
+ continue-on-error: true
+ with:
+ key: ${{ runner.os }}-docker-layer-cache-${{ matrix.tarantool-version }}
+ restore-keys: |
+ ${{ runner.os }}-docker-layer-cache-
+
- name: Build with Maven
run: mvn -B verify --file pom.xml
+
- name: Run integration tests
env:
+ TARANTOOL_VERSION: ${{ matrix.tarantool-version }}
TARANTOOL_SERVER_USER: root
TARANTOOL_SERVER_GROUP: root
run: mvn -B test -P integration --file pom.xml
diff --git a/src/main/java/io/tarantool/driver/exceptions/errors/TarantoolErrors.java b/src/main/java/io/tarantool/driver/exceptions/errors/TarantoolErrors.java
index 46c9e298..2d63e4e7 100644
--- a/src/main/java/io/tarantool/driver/exceptions/errors/TarantoolErrors.java
+++ b/src/main/java/io/tarantool/driver/exceptions/errors/TarantoolErrors.java
@@ -26,20 +26,23 @@ public class TarantoolErrors {
private enum ErrorsCodes {
NO_CONNECTION("77"), TIMEOUT("78");
private final String code;
+
ErrorsCodes(String code) {
this.code = code;
}
+
public String getCode() {
return code;
}
}
+
private static final String CLIENT_ERROR = "ClientError";
/**
* Produces {@link TarantoolInternalException} subclasses
* from the serialized representation in the format of require('errors').new_class("NewError")
,
- * @see tarantool/errors
*
+ * @see tarantool/errors
*/
public static class TarantoolErrorsErrorFactory implements TarantoolErrorFactory {
private static final StringValue LINE = ValueFactory.newString("line");
@@ -49,12 +52,10 @@ public static class TarantoolErrorsErrorFactory implements TarantoolErrorFactory
private static final StringValue ERROR_MESSAGE = ValueFactory.newString("str");
private static final StringValue STACKTRACE = ValueFactory.newString("stack");
private static final Pattern NETWORK_ERROR_PATTERN = Pattern.compile(
- ".*" +
- "\"code\":" +
- "[" + ErrorsCodes.NO_CONNECTION.getCode() + "|" + ErrorsCodes.TIMEOUT.getCode() + "]" +
- ".*" +
- "\"type\":\"" + CLIENT_ERROR + "\"" +
- ".*", Pattern.DOTALL);
+ "(?=.*\"type\":\"" + CLIENT_ERROR + "\")"
+ + "(?=.*\"code\":"
+ + "[" + ErrorsCodes.NO_CONNECTION.getCode() + "|" + ErrorsCodes.TIMEOUT.getCode() + "])",
+ Pattern.DOTALL);
public TarantoolErrorsErrorFactory() {
}
@@ -67,7 +68,7 @@ public Optional create(Value error) {
Map map = error.asMapValue().map();
String exceptionMessage = "";
- String errorMessage = map.containsKey(ERROR_MESSAGE) ? map.get(ERROR_MESSAGE).toString() : null;
+ String errorMessage = map.containsKey(ERROR_MESSAGE) ? map.get(ERROR_MESSAGE).toString() : null;
String err = map.containsKey(ERR) ? map.get(ERR).toString() : null;
String line = map.containsKey(LINE) ? map.get(LINE).toString() : null;
String className = map.containsKey(CLASS_NAME) ? map.get(CLASS_NAME).toString() : null;
@@ -133,8 +134,8 @@ private Boolean isErrorsError(String errorMessage) {
/**
* Produces {@link TarantoolInternalException} subclasses from the serialized representation
* in the format of box.error:unpack
,
- * @see box_error
*
+ * @see box_error
*/
public static class TarantoolBoxErrorFactory implements TarantoolErrorFactory {
private static final StringValue CODE = ValueFactory.newString("code");
@@ -236,7 +237,7 @@ private Boolean isNetworkError(String code) {
/**
* Check the error message contains fields of code and message
*
- * @param code code from box.error
+ * @param code code from box.error
* @param message string message from box.error
* @return an {@link Boolean}
*/
@@ -249,7 +250,6 @@ private Boolean isBoxError(String code, String message) {
* The factory is finalizing, i.e. errors passed into
* it will always be introverted as appropriate for the given factory
* The error is generated in a message that is passed to {@link TarantoolInternalException}
- *
*/
public static class TarantoolUnrecognizedErrorFactory implements TarantoolErrorFactory {
public TarantoolUnrecognizedErrorFactory() {
diff --git a/src/test/java/io/tarantool/driver/integration/TarantoolErrorsIT.java b/src/test/java/io/tarantool/driver/integration/TarantoolErrorsIT.java
index 89ebb77e..38a11de8 100644
--- a/src/test/java/io/tarantool/driver/integration/TarantoolErrorsIT.java
+++ b/src/test/java/io/tarantool/driver/integration/TarantoolErrorsIT.java
@@ -46,8 +46,8 @@ private ProxyTarantoolTupleClient setupClient() {
private RetryingTarantoolTupleClient setupRetryingClient(int retries) {
ProxyTarantoolTupleClient client = setupClient();
return new RetryingTarantoolTupleClient(client,
- TarantoolRequestRetryPolicies
- .byNumberOfAttempts(retries).build());
+ TarantoolRequestRetryPolicies
+ .byNumberOfAttempts(retries).build());
}
@Test
@@ -58,14 +58,13 @@ void testNetworkError_boxErrorUnpackNoConnection() {
client.callForSingleResult("box_error_unpack_no_connection", HashMap.class).get();
fail("Exception must be thrown after last retry attempt.");
} catch (Throwable e) {
+ String message = e.getCause().getMessage();
+
assertTrue(e.getCause() instanceof TarantoolInternalNetworkException);
- assertTrue(e.getCause().getMessage().contains(
- "code: 77\n" +
- "message: Connection is not established\n" +
- "base_type: ClientError\n" +
- "type: ClientError\n" +
- "trace:")
- );
+ assertTrue(message.contains("code: 77"));
+ assertTrue(message.contains("message: Connection is not established"));
+ assertTrue(message.contains("type: ClientError"));
+ assertTrue(message.contains("trace:"));
}
}
@@ -80,14 +79,13 @@ void testNetworkError_boxErrorUnpackTimeout() {
String.class).get();
fail("Exception must be thrown after last retry attempt.");
} catch (Throwable e) {
+ String message = e.getCause().getMessage();
+
assertTrue(e.getCause() instanceof TarantoolInternalNetworkException);
- assertTrue(e.getCause().getMessage().contains(
- "code: 78\n" +
- "message: Timeout exceeded\n" +
- "base_type: ClientError\n" +
- "type: ClientError\n" +
- "trace:")
- );
+ assertTrue(message.contains("code: 78"));
+ assertTrue(message.contains("message: Timeout exceeded"));
+ assertTrue(message.contains("type: ClientError"));
+ assertTrue(message.contains("trace:"));
}
}
@@ -102,12 +100,11 @@ void testNetworkError_boxErrorTimeout() {
String.class).get();
fail("Exception must be thrown after last retry attempt.");
} catch (Throwable e) {
+ String message = e.getCause().getMessage();
+
assertTrue(e.getCause() instanceof TarantoolInternalNetworkException);
- assertTrue(e.getCause().getMessage().contains(
- "InnerErrorMessage:\n" +
- "code: 78\n" +
- "message: Timeout exceeded")
- );
+ assertTrue(message.contains("code: 78"));
+ assertTrue(message.contains("message: Timeout exceeded"));
}
}
@@ -119,13 +116,13 @@ void testNetworkError_crudErrorTimeout() {
client.callForSingleResult("crud_error_timeout", HashMap.class).get();
fail("Exception must be thrown after last retry attempt.");
} catch (Throwable e) {
+ String message = e.getCause().getMessage();
+
assertTrue(e.getCause() instanceof TarantoolInternalNetworkException);
- assertTrue(e.getCause().getMessage().contains(
- "Function returned an error: {\"code\":78," +
- "\"base_type\":\"ClientError\"," +
- "\"type\":\"ClientError\"," +
- "\"message\":\"Timeout exceeded\","
- ));
+ assertTrue(message.contains("\"code\":78"));
+ assertTrue(message.contains("\"type\":\"ClientError\""));
+ assertTrue(message.contains("\"message\":\"Timeout exceeded\""));
+ assertTrue(message.contains("\"trace\":"));
}
}
@@ -137,33 +134,32 @@ void testNonNetworkError_boxErrorUnpack() {
client.callForSingleResult("box_error_non_network_error", HashMap.class).get();
fail("Exception must be thrown after last retry attempt.");
} catch (Throwable e) {
+ String message = e.getCause().getMessage();
+
assertTrue(e.getCause() instanceof TarantoolInternalException);
assertFalse(e.getCause() instanceof TarantoolInternalNetworkException);
- assertTrue(e.getCause().getMessage().contains(
- "code: 40\n" +
- "message: Failed to write to disk\n" +
- "base_type: ClientError\n" +
- "type: ClientError\n" +
- "trace:")
- );
+ assertTrue(message.contains("code: 40"));
+ assertTrue(message.contains("message: Failed to write to disk"));
+ assertTrue(message.contains("type: ClientError"));
+ assertTrue(message.contains("trace:"));
}
}
- @Test
- void testNonNetworkError_boxError() {
- try {
- ProxyTarantoolTupleClient client = setupClient();
-
- client.callForSingleResult("raising_error", HashMap.class).get();
- fail("Exception must be thrown after last retry attempt.");
- } catch (Throwable e) {
- assertTrue(e.getCause() instanceof TarantoolInternalException);
- assertFalse(e.getCause() instanceof TarantoolInternalNetworkException);
- assertTrue(e.getCause().getMessage().contains(
- "InnerErrorMessage:\n" +
- "code: 32\n" +
- "message:")
- );
- }
+ @Test
+ void testNonNetworkError_boxError() {
+ try {
+ ProxyTarantoolTupleClient client = setupClient();
+
+ client.callForSingleResult("raising_error", HashMap.class).get();
+ fail("Exception must be thrown after last retry attempt.");
+ } catch (Throwable e) {
+ String message = e.getCause().getMessage();
+
+ assertTrue(e.getCause() instanceof TarantoolInternalException);
+ assertFalse(e.getCause() instanceof TarantoolInternalNetworkException);
+ assertTrue(message.contains("InnerErrorMessage:"));
+ assertTrue(message.contains("code: 32"));
+ assertTrue(message.contains("message:"));
}
+ }
}
diff --git a/src/test/resources/cartridge/app/roles/api_router.lua b/src/test/resources/cartridge/app/roles/api_router.lua
index 0c08cfd3..d09232a5 100644
--- a/src/test/resources/cartridge/app/roles/api_router.lua
+++ b/src/test/resources/cartridge/app/roles/api_router.lua
@@ -1,7 +1,7 @@
local vshard = require('vshard')
-local cartridge_pool = require('cartridge.pool')
local cartridge_rpc = require('cartridge.rpc')
local fiber = require('fiber')
+local crud = require('crud')
local log = require('log')
local function get_schema()
@@ -31,7 +31,7 @@ local function retrying_function()
end
local function get_composite_data(id)
- local data = vshard.router.callro(vshard.router.bucket_id(id), 'get_composite_data', {id})
+ local data = vshard.router.callro(vshard.router.bucket_id(id), 'get_composite_data', { id })
return data
end
@@ -57,7 +57,7 @@ local function raising_error(message)
end
local function reset_request_counters()
- box.space.request_counters:replace({1, 0})
+ box.space.request_counters:replace({ 1, 0 })
end
local function get_router_name()
@@ -77,15 +77,18 @@ local function long_running_function(values)
end
end
- box.space.request_counters:update(1, {{'+', 'count', 1}})
+ -- need using number instead field name as string in update function for compatibility with tarantool 1.10
+ box.space.request_counters:update(1, { { '+', 2, 1 } })
log.info('Executing long-running function ' ..
tostring(box.space.request_counters:get(1)[2]) ..
"(name: " .. disabled_router_name ..
"; sleep: " .. seconds_to_sleep .. ")")
if get_router_name() == disabled_router_name then
- return nil, "Disabled by client; router_name = " .. disabled_router_name
+ return nil, "Disabled by client; router_name = " .. disabled_router_name
+ end
+ if seconds_to_sleep then
+ fiber.sleep(seconds_to_sleep)
end
- if seconds_to_sleep then fiber.sleep(seconds_to_sleep) end
return true
end
@@ -111,16 +114,19 @@ local function box_error_non_network_error()
end
local function crud_error_timeout()
- return crud.get("test_space", ('x'):rep(2^27))
+ return nil, { class_name = 'SelectError',
+ err = 'Failed to get next object: GetTupleError: Failed to get tuples from storages: UpdateTuplesError: Failed to select tuples from storages: Call: Failed for 07d14fec-f32b-4b90-aa72-e6755273ad56: Function returned an error: {\"code\":78,\"base_type\":\"ClientError\",\"type\":\"ClientError\",\"message\":\"Timeout exceeded\",\"trace\":[{\"file\":\"builtin\\/box\\/net_box.lua\",\"line\":419}]}',
+ str = 'SelectError: Failed to get next object: GetTupleError: Failed to get tuples from storages: UpdateTuplesError: Failed to select tuples from storages: Call: Failed for 07d14fec-f32b-4b90-aa72-e6755273ad56: Function returned an error: {\"code\":78,\"base_type\":\"ClientError\",\"type\":\"ClientError\",\"message\":\"Timeout exceeded\",\"trace\":[{\"file\":\"builtin\\/box\\/net_box.lua\",\"line\":419}]}'
+ }
end
local function init(opts)
box.schema.space.create('request_counters', {
- format = {{'id', 'unsigned'}, {'count', 'unsigned'}},
+ format = { { 'id', 'unsigned' }, { 'count', 'unsigned' } },
if_not_exists = true
})
- box.space.request_counters:create_index('primary', {parts = {'id'}, if_not_exists = true})
+ box.space.request_counters:create_index('id', { parts = { 'id' }, if_not_exists = true })
rawset(_G, 'truncate_space', truncate_space)