Skip to content

Commit fe03060

Browse files
committed
add tests for basic connector functionality
Added tests for connector API. Closes #51
1 parent a96c8d9 commit fe03060

13 files changed

+1280
-10
lines changed

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ before_script:
1212
- src/test/travis.pre.sh
1313

1414
script:
15-
- mvn test
16-
- sudo cat /var/log/tarantool/jdk-testing.log
15+
- mvn verify
16+
- cat testroot/data/jdk-testing.log

pom.xml

+19
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,19 @@
5050
<artifactId>maven-surefire-plugin</artifactId>
5151
<version>2.22.0</version>
5252
</plugin>
53+
<plugin>
54+
<groupId>org.apache.maven.plugins</groupId>
55+
<artifactId>maven-failsafe-plugin</artifactId>
56+
<version>2.22.0</version>
57+
<executions>
58+
<execution>
59+
<goals>
60+
<goal>integration-test</goal>
61+
<goal>verify</goal>
62+
</goals>
63+
</execution>
64+
</executions>
65+
</plugin>
5366
</plugins>
5467
</build>
5568

@@ -66,6 +79,12 @@
6679
<version>1.9.5</version>
6780
<scope>test</scope>
6881
</dependency>
82+
<dependency>
83+
<groupId>org.yaml</groupId>
84+
<artifactId>snakeyaml</artifactId>
85+
<version>1.23</version>
86+
<scope>test</scope>
87+
</dependency>
6988
</dependencies>
7089

7190
<parent>

src/main/java/org/tarantool/TarantoolClientImpl.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ public List exec(Code code, Object... args) {
503503

504504
@Override
505505
public void close() {
506-
throw new IllegalStateException("You should close TarantoolClient to make this");
506+
throw new IllegalStateException("You should close TarantoolClient instead.");
507507
}
508508
}
509509

@@ -525,7 +525,7 @@ public Long exec(Code code, Object... args) {
525525

526526
@Override
527527
public void close() {
528-
throw new IllegalStateException("You should close TarantoolClient to make this");
528+
throw new IllegalStateException("You should close TarantoolClient instead.");
529529
}
530530
}
531531

src/test/instance.lua

+6-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ box.once('init', function()
1616
box.schema.user.create('test_ordin', { password = '2HWRXHfa' })
1717
box.schema.user.create('test_admin', { password = '4pWBZmLEgkmKK5WP' })
1818

19-
box.schema.user.grant('test_ordin', 'read,write', 'user')
20-
box.schema.user.grant('test_admin', 'execute', 'super')
19+
box.schema.user.grant('test_ordin', 'read,write', 'space', 'user')
20+
box.schema.user.grant('test_admin', 'super')
2121
end)
2222

23+
-- Java has no internal support for unix domain sockets,
24+
-- so we will use tcp for console communication.
25+
console = require('console')
26+
console.listen(3313)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
package org.tarantool;
2+
3+
import org.junit.jupiter.api.AfterAll;
4+
import org.junit.jupiter.api.BeforeAll;
5+
6+
import java.io.File;
7+
import java.io.IOException;
8+
import java.net.InetSocketAddress;
9+
import java.net.Socket;
10+
import java.nio.channels.SocketChannel;
11+
import java.util.List;
12+
import java.util.concurrent.CountDownLatch;
13+
import java.util.concurrent.TimeUnit;
14+
15+
import static org.junit.jupiter.api.Assertions.assertEquals;
16+
import static org.junit.jupiter.api.Assertions.assertNotNull;
17+
import static org.junit.jupiter.api.Assertions.assertTrue;
18+
19+
/**
20+
* Abstract test. Provides environment control and frequently used functions.
21+
*/
22+
public abstract class AbstractTarantoolConnectorIT {
23+
protected static final String host = System.getProperty("tntHost", "localhost");
24+
protected static final int port = Integer.parseInt(System.getProperty("tntPort", "3301"));
25+
protected static final int consolePort = Integer.parseInt(System.getProperty("tntConsolePort", "3313"));
26+
protected static final String username = System.getProperty("tntUser", "test_admin");
27+
protected static final String password = System.getProperty("tntPass", "4pWBZmLEgkmKK5WP");
28+
protected static final String tntCtlWorkDir = System.getProperty("tntCtlWorkDir", new File("").getAbsolutePath());
29+
30+
protected static final SocketChannelProvider socketChannelProvider = new TestSocketChannelProvider(host, port);
31+
32+
protected static final int TIMEOUT = 500;
33+
protected static final int RESTART_TIMEOUT = 2000;
34+
35+
protected static TarantoolConsole console;
36+
37+
protected static final String SPACE_NAME = "basic_test";
38+
protected static final String MULTIPART_SPACE_NAME = "multipart_test";
39+
40+
protected static int SPACE_ID;
41+
protected static int MULTI_PART_SPACE_ID;
42+
43+
protected static int PK_INDEX_ID;
44+
protected static int MPK_INDEX_ID;
45+
protected static int VIDX_INDEX_ID;
46+
47+
private static final String[] setupScript = new String[] {
48+
"box.schema.space.create('basic_test', { format = " +
49+
"{{name = 'id', type = 'integer'}," +
50+
" {name = 'val', type = 'string'} } })",
51+
52+
"box.space.basic_test:create_index('pk', { type = 'TREE', parts = {'id'} } )",
53+
"box.space.basic_test:create_index('vidx', { type = 'TREE', unique = false, parts = {'val'} } )",
54+
55+
"box.space.basic_test:replace{1, 'one'}",
56+
"box.space.basic_test:replace{2, 'two'}",
57+
"box.space.basic_test:replace{3, 'three'}",
58+
59+
"box.schema.space.create('multipart_test', { format = " +
60+
"{{name = 'id1', type = 'integer'}," +
61+
" {name = 'id2', type = 'string'}," +
62+
" {name = 'val1', type = 'string'} } })",
63+
64+
"box.space.multipart_test:create_index('pk', { type = 'TREE', parts = {'id1', 'id2'} })",
65+
"box.space.multipart_test:create_index('vidx', { type = 'TREE', unique = false, parts = {'val1'} })",
66+
67+
"box.space.multipart_test:replace{1, 'one', 'o n e'}",
68+
"box.space.multipart_test:replace{2, 'two', 't w o'}",
69+
"box.space.multipart_test:replace{3, 'three', 't h r e e'}",
70+
71+
"function echo(...) return ... end"
72+
};
73+
74+
private static final String[] cleanScript = new String[] {
75+
"box.space.basic_test and box.space.basic_test:drop()",
76+
"box.space.multipart_test and box.space.multipart_test:drop()"
77+
};
78+
79+
@BeforeAll
80+
public static void setupEnv() {
81+
console = openConsole();
82+
83+
executeLua(cleanScript);
84+
executeLua(setupScript);
85+
86+
SPACE_ID = console.eval("box.space.basic_test.id");
87+
PK_INDEX_ID = console.eval("box.space.basic_test.index.pk.id");
88+
VIDX_INDEX_ID = console.eval("box.space.basic_test.index.vidx.id");
89+
90+
MULTI_PART_SPACE_ID = console.eval("box.space.multipart_test.id");
91+
MPK_INDEX_ID = console.eval("box.space.multipart_test.index.pk.id");
92+
}
93+
94+
@AfterAll
95+
public static void cleanupEnv() {
96+
executeLua(cleanScript);
97+
98+
console.close();
99+
}
100+
101+
private static void executeLua(String[] exprs) {
102+
for (String expr : exprs) {
103+
console.exec(expr);
104+
}
105+
}
106+
107+
protected void checkTupleResult(Object res, List tuple) {
108+
assertNotNull(res);
109+
assertTrue(List.class.isAssignableFrom(res.getClass()));
110+
List list = (List)res;
111+
assertEquals(1, list.size());
112+
assertNotNull(list.get(0));
113+
assertTrue(List.class.isAssignableFrom(list.get(0).getClass()));
114+
assertEquals(tuple, list.get(0));
115+
}
116+
117+
protected TarantoolClient makeClient() {
118+
TarantoolClientConfig config = new TarantoolClientConfig();
119+
config.username = username;
120+
config.password = password;
121+
config.initTimeoutMillis = 1000;
122+
config.sharedBufferSize = 128;
123+
124+
return new TarantoolClientImpl(socketChannelProvider, config);
125+
}
126+
127+
protected static TarantoolConsole openConsole() {
128+
return TarantoolConsole.open(host, consolePort);
129+
}
130+
131+
protected static TarantoolConsole openConsole(String instance) {
132+
return TarantoolConsole.open(tntCtlWorkDir, instance);
133+
}
134+
135+
protected TarantoolConnection openConnection() {
136+
Socket socket = new Socket();
137+
try {
138+
socket.connect(new InetSocketAddress(host, port));
139+
} catch (IOException e) {
140+
throw new RuntimeException("Test failed due to invalid environment.", e);
141+
}
142+
try {
143+
return new TarantoolConnection(username, password, socket);
144+
} catch (Exception e) {
145+
try {
146+
socket.close();
147+
} catch (IOException ignored) {
148+
// No-op.
149+
}
150+
throw new RuntimeException(e);
151+
}
152+
}
153+
154+
protected List<?> consoleSelect(String spaceName, Object key) {
155+
StringBuilder sb = new StringBuilder("box.space.");
156+
sb.append(spaceName);
157+
sb.append(":select{");
158+
if (List.class.isAssignableFrom(key.getClass())) {
159+
List parts = (List)key;
160+
for (int i = 0; i < parts.size(); i++) {
161+
if (i != 0)
162+
sb.append(", ");
163+
Object k = parts.get(i);
164+
if (k.getClass().isAssignableFrom(String.class)) {
165+
sb.append('\'');
166+
sb.append(k);
167+
sb.append('\'');
168+
} else {
169+
sb.append(k);
170+
}
171+
}
172+
} else {
173+
sb.append(key);
174+
}
175+
sb.append("}");
176+
return console.eval(sb.toString());
177+
}
178+
179+
protected void stopTarantool(String instance) {
180+
tarantoolControl("stop", instance);
181+
}
182+
183+
protected void startTarantool(String instance) {
184+
tarantoolControl("start", instance);
185+
}
186+
187+
/**
188+
* Control the given tarantool instance via tarantoolctl utility.
189+
*
190+
* @param command A tarantoolctl utility command.
191+
* @param instanceName Name of tarantool instance to control.
192+
*/
193+
private void tarantoolControl(String command, String instanceName) {
194+
ProcessBuilder builder = new ProcessBuilder("env", "tarantoolctl", command, instanceName);
195+
builder.directory(new File(tntCtlWorkDir));
196+
197+
final Process process;
198+
try {
199+
process = builder.start();
200+
} catch (IOException e) {
201+
throw new RuntimeException("environment failure", e);
202+
}
203+
204+
final CountDownLatch latch = new CountDownLatch(1);
205+
// The thread below is necessary to organize timed wait on the process.
206+
// We cannot use Process.waitFor(long, TimeUnit) because we on java 6.
207+
Thread thread = new Thread(new Runnable() {
208+
@Override
209+
public void run() {
210+
try {
211+
process.waitFor();
212+
} catch (InterruptedException e) {
213+
// No-op.
214+
}
215+
latch.countDown();
216+
}
217+
});
218+
219+
thread.start();
220+
221+
boolean res;
222+
try {
223+
res = latch.await(RESTART_TIMEOUT, TimeUnit.MILLISECONDS);
224+
} catch (InterruptedException e) {
225+
throw new RuntimeException("wait interrupted", e);
226+
}
227+
228+
if (!res) {
229+
thread.interrupt();
230+
process.destroy();
231+
232+
throw new RuntimeException("timeout");
233+
}
234+
235+
int code = process.exitValue();
236+
237+
if (code != 0) {
238+
throw new RuntimeException("returned exitcode " + code);
239+
}
240+
}
241+
242+
/**
243+
* Socket channel provider to be used throughout the tests.
244+
*/
245+
public static class TestSocketChannelProvider implements SocketChannelProvider {
246+
String host;
247+
int port;
248+
249+
public TestSocketChannelProvider(String host, int port) {
250+
this.host = host;
251+
this.port = port;
252+
}
253+
254+
@Override
255+
public SocketChannel get(int retryNumber, Throwable lastError) {
256+
long budget = System.currentTimeMillis() + RESTART_TIMEOUT;
257+
while (!Thread.currentThread().isInterrupted()) {
258+
try {
259+
return SocketChannel.open(new InetSocketAddress(host, port));
260+
} catch (Exception e) {
261+
if (budget < System.currentTimeMillis())
262+
throw new RuntimeException(e);
263+
try {
264+
Thread.sleep(100);
265+
} catch (InterruptedException ex) {
266+
// No-op.
267+
Thread.currentThread().interrupt();
268+
}
269+
}
270+
}
271+
throw new RuntimeException("Test failure due to invalid environment. " +
272+
"Timeout connecting to " + host + ":" + port);
273+
}
274+
}
275+
}

0 commit comments

Comments
 (0)