use of com.mysql.cj.xdevapi.Session in project aws-mysql-jdbc by awslabs.
the class SessionTest method basicSessionFailoverRandomSort.
@Test
public void basicSessionFailoverRandomSort() {
UnreliableSocketFactory.flushAllStaticData();
final String testUriPattern = "mysqlx://%s:%s@[%s]/%s?" + PropertyKey.xdevapiConnectTimeout.getKeyName() + "=100&" + PropertyKey.socketFactory.getKeyName() + "=" + UnreliableSocketFactory.class.getName();
String testHosts = IntStream.range(1, 6).mapToObj(i -> "host" + i).peek(h -> UnreliableSocketFactory.mapHost(h, getTestHost())).map(h -> h + ":" + getTestPort()).collect(Collectors.joining(","));
String testUri = String.format(testUriPattern, getTestUser() == null ? "" : getTestUser(), getTestPassword() == null ? "" : getTestPassword(), testHosts, getTestDatabase());
Set<String> downHosts = new HashSet<>();
for (int i = 1; i <= 5; i++) {
Session testSession = this.fact.getSession(testUri);
assertTrue(UnreliableSocketFactory.isConnected());
testSession.close();
String lastHost = UnreliableSocketFactory.getHostFromLastConnection();
for (String h : downHosts) {
assertNotEquals(h, lastHost);
}
downHosts.add(lastHost);
UnreliableSocketFactory.downHost(lastHost.substring(1));
}
// None of the hosts is available by now.
assertThrows(CJCommunicationsException.class, "Unable to connect to any of the target hosts\\.", () -> {
this.fact.getSession(testUri);
return null;
});
UnreliableSocketFactory.dontDownHost("host3");
UnreliableSocketFactory.flushConnectionAttempts();
Session testSession = this.fact.getSession(testUri);
assertTrue(UnreliableSocketFactory.isConnected());
testSession.close();
assertEquals(UnreliableSocketFactory.getHostConnectedStatus("host3"), UnreliableSocketFactory.getHostFromLastConnection());
}
use of com.mysql.cj.xdevapi.Session in project aws-mysql-jdbc by awslabs.
the class SessionTest method testBug97269.
/**
* Test fix for Bug#97269 (30438500), POSSIBLE BUG IN COM.MYSQL.CJ.XDEVAPI.STREAMINGDOCRESULTBUILDER.
*
* @throws Exception
*/
@Test
public void testBug97269() throws Exception {
Session sess = null;
try {
String message1 = "W1";
String message2 = "W2";
// create notice message buffers
Frame.Builder notice1 = Frame.newBuilder().setScope(Frame.Scope.LOCAL).setType(Frame.Type.WARNING_VALUE).setPayload(com.mysql.cj.x.protobuf.MysqlxNotice.Warning.newBuilder().setCode(MysqlErrorNumbers.ER_BAD_DB_ERROR).setMsg(message1).build().toByteString());
Frame.Builder notice2 = Frame.newBuilder().setScope(Frame.Scope.GLOBAL).setType(Frame.Type.WARNING_VALUE).setPayload(com.mysql.cj.x.protobuf.MysqlxNotice.Warning.newBuilder().setCode(MysqlErrorNumbers.ER_BAD_DB_ERROR).setMsg(message2).build().toByteString());
byte[] notice1Bytes = makeNoticeBytes(notice1.build());
byte[] notice2Bytes = makeNoticeBytes(notice2.build());
int size = notice1Bytes.length + notice2Bytes.length;
byte[] noticesBytes = new byte[size];
System.arraycopy(notice1Bytes, 0, noticesBytes, 0, notice1Bytes.length);
System.arraycopy(notice2Bytes, 0, noticesBytes, notice1Bytes.length, notice2Bytes.length);
InjectedSocketFactory.flushAllStaticData();
String url = this.baseUrl + (this.baseUrl.contains("?") ? "" : "?") + makeParam(PropertyKey.socketFactory, InjectedSocketFactory.class.getName(), !this.baseUrl.contains("?") || this.baseUrl.endsWith("?")) + makeParam(PropertyKey.xdevapiSslMode, XdevapiSslMode.DISABLED.toString()) + makeParam(PropertyKey.xdevapiCompression, Compression.DISABLED.toString()) + // to allow injection between result rows
makeParam(PropertyKey.useReadAheadInput, "false");
sess = this.fact.getSession(url);
SocketFactory sf = ((SessionImpl) sess).getSession().getProtocol().getSocketConnection().getSocketFactory();
assertTrue(InjectedSocketFactory.class.isAssignableFrom(sf.getClass()));
Collection collection = sess.getDefaultSchema().createCollection("testBug97269");
collection.add("{\"_id\":\"the_id\",\"g\":1}").execute();
// StreamingDocResultBuilder
InjectedSocketFactory.injectedBuffer = noticesBytes;
DocResult docs = collection.find().fields("$._id as _id, $.g as g, 1 + 1 as q").execute();
DbDoc doc = docs.next();
assertEquals("the_id", ((JsonString) doc.get("_id")).getString());
assertEquals(new Integer(1), ((JsonNumber) doc.get("g")).getInteger());
assertEquals(new Integer(2), ((JsonNumber) doc.get("q")).getInteger());
int cnt = 0;
for (Iterator<Warning> warn = docs.getWarnings(); warn.hasNext(); ) {
Warning w = warn.next();
if (w.getMessage().equals(message1) || w.getMessage().equals(message2)) {
cnt++;
}
}
assertEquals(2, cnt);
InjectedSocketFactory.flushAllStaticData();
InjectedSocketFactory.injectedBuffer = noticesBytes;
SqlResult rs1 = sess.sql("select 1").execute();
assertEquals(1, rs1.fetchOne().getInt(0));
cnt = 0;
for (Iterator<Warning> warn = rs1.getWarnings(); warn.hasNext(); ) {
Warning w = warn.next();
if (w.getMessage().equals(message1) || w.getMessage().equals(message2)) {
cnt++;
}
}
assertEquals(2, cnt);
} finally {
InjectedSocketFactory.flushAllStaticData();
dropCollection("testBug97269");
if (sess != null) {
sess.close();
}
}
}
use of com.mysql.cj.xdevapi.Session in project aws-mysql-jdbc by awslabs.
the class SessionTest method testPooledSessions.
@SuppressWarnings("unchecked")
@Test
public void testPooledSessions() throws Exception {
final ClientFactory cf = new ClientFactory();
final String url = this.baseUrl;
final Properties props = new Properties();
/*
* UT8/1: Verify that setting an incorrect value in the client options defined in the Pooling options in the HLS throw an exception with the expected
* message.
*/
// pooling.enabled
props.clear();
assertThrows(XDevAPIError.class, "Client option 'pooling\\.enabled' does not support value 'sure'\\.", new Callable<Void>() {
public Void call() throws Exception {
props.setProperty(ClientProperty.POOLING_ENABLED.getKeyName(), "sure");
cf.getClient(url, props);
return null;
}
});
assertThrows(XDevAPIError.class, "Client option 'pooling\\.enabled' does not support value 'sure'\\.", new Callable<Void>() {
public Void call() throws Exception {
cf.getClient(url, "{\"pooling\": {\"enabled\": \"sure\"}}");
return null;
}
});
// pooling.maxSize
props.clear();
assertThrows(XDevAPIError.class, "Client option 'pooling\\.maxSize' does not support value '0'\\.", new Callable<Void>() {
public Void call() throws Exception {
props.setProperty(ClientProperty.POOLING_MAX_SIZE.getKeyName(), "0");
cf.getClient(url, props);
return null;
}
});
assertThrows(XDevAPIError.class, "Client option 'pooling\\.maxSize' does not support value '0'\\.", new Callable<Void>() {
public Void call() throws Exception {
cf.getClient(url, "{\"pooling\": {\"maxSize\": 0}}");
return null;
}
});
assertThrows(XDevAPIError.class, "Client option 'pooling\\.maxSize' does not support value 'one'\\.", new Callable<Void>() {
public Void call() throws Exception {
cf.getClient(url, "{\"pooling\": {\"maxSize\": \"one\"}}");
return null;
}
});
// pooling.maxIdleTime
props.clear();
assertThrows(XDevAPIError.class, "Client option 'pooling\\.maxIdleTime' does not support value '-1'\\.", new Callable<Void>() {
public Void call() throws Exception {
props.setProperty(ClientProperty.POOLING_MAX_IDLE_TIME.getKeyName(), "-1");
cf.getClient(url, props);
return null;
}
});
assertThrows(XDevAPIError.class, "Client option 'pooling\\.maxIdleTime' does not support value '-1'\\.", new Callable<Void>() {
public Void call() throws Exception {
cf.getClient(url, "{\"pooling\": {\"maxIdleTime\": -1}}");
return null;
}
});
assertThrows(XDevAPIError.class, "Client option 'pooling\\.maxIdleTime' does not support value 'one'\\.", new Callable<Void>() {
public Void call() throws Exception {
cf.getClient(url, "{\"pooling\": {\"maxIdleTime\": \"one\"}}");
return null;
}
});
// pooling.queueTimeout
props.clear();
assertThrows(XDevAPIError.class, "Client option 'pooling\\.queueTimeout' does not support value '-1'\\.", new Callable<Void>() {
public Void call() throws Exception {
props.setProperty(ClientProperty.POOLING_QUEUE_TIMEOUT.getKeyName(), "-1");
cf.getClient(url, props);
return null;
}
});
assertThrows(XDevAPIError.class, "Client option 'pooling\\.queueTimeout' does not support value '-1'\\.", new Callable<Void>() {
public Void call() throws Exception {
cf.getClient(url, "{\"pooling\": {\"queueTimeout\": -1}}");
return null;
}
});
assertThrows(XDevAPIError.class, "Client option 'pooling\\.queueTimeout' does not support value 'one'\\.", new Callable<Void>() {
public Void call() throws Exception {
cf.getClient(url, "{\"pooling\": {\"queueTimeout\": \"one\"}}");
return null;
}
});
// Unknown pooling option.
props.clear();
assertThrows(XDevAPIError.class, "Client option 'pooling\\.foo' is not recognized as valid\\.", new Callable<Void>() {
public Void call() throws Exception {
props.setProperty("pooling.foo", "bar");
cf.getClient(url, props);
return null;
}
});
assertThrows(XDevAPIError.class, "Client option 'pooling\\.foo' is not recognized as valid\\.", new Callable<Void>() {
public Void call() throws Exception {
cf.getClient(url, "{\"pooling\": {\"foo\": \"bar\"}}");
return null;
}
});
// Unknown clientProps option.
props.clear();
assertThrows(XDevAPIError.class, "Client option 'foo' is not recognized as valid\\.", new Callable<Void>() {
public Void call() throws Exception {
props.setProperty("foo", "bar");
cf.getClient(url, props);
return null;
}
});
assertThrows(XDevAPIError.class, "Client option 'foo' is not recognized as valid\\.", new Callable<Void>() {
public Void call() throws Exception {
cf.getClient(url, "{\"foo\": {\"bar\": \"baz\"}}");
return null;
}
});
/*
* UT9/1: Verify that when no pooling properties passed their values set to defaults: pooling.maxSize=25, pooling.maxIdleTime=0, pooling.queueTimeout=0.
*/
props.clear();
testPooledSessions_checkClientProperties(cf.getClient(this.baseUrl, props), 25, 0, 0);
testPooledSessions_checkClientProperties(cf.getClient(this.baseUrl, (Properties) null), 25, 0, 0);
testPooledSessions_checkClientProperties(cf.getClient(this.baseUrl, "{}"), 25, 0, 0);
testPooledSessions_checkClientProperties(cf.getClient(this.baseUrl, (String) null), 25, 0, 0);
/*
* UT9/2: Verify that when all pooling properties passed via Properties object the Client is configured according to their values.
*/
props.setProperty(ClientProperty.POOLING_ENABLED.getKeyName(), "true");
props.setProperty(ClientProperty.POOLING_MAX_SIZE.getKeyName(), "5");
props.setProperty(ClientProperty.POOLING_MAX_IDLE_TIME.getKeyName(), "6");
props.setProperty(ClientProperty.POOLING_QUEUE_TIMEOUT.getKeyName(), "7");
testPooledSessions_checkClientProperties(cf.getClient(this.baseUrl, props), 5, 6, 7);
/*
* UT9/3: Verify that when all pooling properties passed via json string ({"pooling" : {"enabled" : true, "maxSize" : 8, "maxIdleTime" : 9,
* "queueTimeout" : 10} }) the Client is configured according to their values.
*/
testPooledSessions_checkClientProperties(cf.getClient(this.baseUrl, "{\"pooling\" : {\"enabled\" : true, \"maxSize\" : 8, \"maxIdleTime\" : 9, \"queueTimeout\" : 10} }"), 8, 9, 10);
/*
* UT3/2: Start a client with pooling enabled, call Client.getSession() twice and verify that the objects returned are different and the internal
* connection instances are different too.
*/
Client cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": true}}");
Session s0 = cli0.getSession();
Session s1 = cli0.getSession();
assertNotEquals(s0, s1);
Field fProtocol = CoreSession.class.getDeclaredField("protocol");
fProtocol.setAccessible(true);
assertNotEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s1).getSession()));
cli0.close();
/*
* UT3/3: Start a client with pooling enabled, call Client.getSession() twice, closing the first session before getting the second one, and verify that
* the objects returned are different and that the internal connection instances are the same.
*/
cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": true}}");
s0 = cli0.getSession();
s0.close();
s1 = cli0.getSession();
s1.sql("SELECT 1").execute();
assertNotEquals(s0, s1);
assertEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s1).getSession()));
cli0.close();
/*
* UT3/4: Start a client with pooling disabled, call Client.getSession() twice and verify that the objects returned are different and the internal
* connection instances are different too.
*/
cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": false}}");
s0 = cli0.getSession();
s1 = cli0.getSession();
assertNotEquals(s0, s1);
assertNotEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s1).getSession()));
cli0.close();
/*
* UT3/5: Start a client with pooling disabled, call Client.getSession() twice, closing the first session before getting the second one, and verify that
* the objects returned are different and that the internal connection instances are different too.
*/
cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": false}}");
s0 = cli0.getSession();
s0.close();
s1 = cli0.getSession();
assertNotEquals(s0, s1);
assertNotEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s1).getSession()));
cli0.close();
/*
* UT5/1: Having a full pool and queueTimeout = 0, verify that a new Client.getSession() waits until a Session is released.
* UT6/1: Verify that that a client object can not open/create more sessions that the specified in the maxSize option.
*/
props.setProperty(ClientProperty.POOLING_MAX_SIZE.getKeyName(), "3");
props.setProperty(ClientProperty.POOLING_MAX_IDLE_TIME.getKeyName(), "1000");
props.setProperty(ClientProperty.POOLING_QUEUE_TIMEOUT.getKeyName(), "1000");
Client cli1 = cf.getClient(this.baseUrl, props);
s1 = cli1.getSession();
Session s2 = cli1.getSession();
Session s3 = cli1.getSession();
testPooledSessions_assertFailureTimeout(cli1, 1000, 2000, XDevAPIError.class, "Session can not be obtained within 1000 milliseconds.");
cli1.close();
/*
* UT12/1: Having a pool with a single connection, close the Session, get another Session with Client.getSession(). Verify that the received Session
* object is new and uses the same internal connection (MysqlxSession) instance.
*/
cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": true, \"maxSize\" : 1}}");
s0 = cli0.getSession();
s0.close();
s1 = cli0.getSession();
s1.sql("SELECT 1").execute();
assertNotEquals(s0, s1);
assertEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s1).getSession()));
cli0.close();
/*
* UT12/2: Having a pool with a number of connections greater than 1 and lower than maxPoolSize, close on Session, get another Session with
* Client.getSession(). Verify that the received Session object is new and uses the same internal connection (MysqlxSession) instance.
*/
cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": true, \"maxSize\" : 3}}");
s0 = cli0.getSession();
s0.close();
s1 = cli0.getSession();
s1.sql("SELECT 1").execute();
assertNotEquals(s0, s1);
assertEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s1).getSession()));
cli0.close();
/*
* UT12/3: Having a full pool with all sessions in active state, close one Session, get another Session with Client.getSession(). Verify that the
* received Session object is new and uses the same internal connection (MysqlxSession) instance.
*/
cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": true, \"maxSize\" : 3}}");
s0 = cli0.getSession();
s1 = cli0.getSession();
s2 = cli0.getSession();
s0.close();
s3 = cli0.getSession();
s3.sql("SELECT 1").execute();
assertNotEquals(s0, s3);
assertEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s3).getSession()));
cli0.close();
/*
* UT11/2: Having a pool with a single idle connection and maxIdleTime = n, verify that after n milliseconds a Client.getSession() call will remove all
* expired sessions from pool and return a new Session object that uses a new MysqlxSession instance.
*/
cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": true, \"maxSize\" : 3, \"maxIdleTime\" : 1000}}");
s0 = cli0.getSession();
s0.close();
Thread.sleep(2000);
s1 = cli0.getSession();
assertNotEquals(s0, s1);
assertNotEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s1).getSession()));
Field fIdleSessions = ClientImpl.class.getDeclaredField("idleProtocols");
fIdleSessions.setAccessible(true);
assertTrue(((BlockingQueue<PooledXProtocol>) fIdleSessions.get(cli0)).isEmpty());
/*
* UT4/1: Verify that all idle and active sessions are closed after Client.close() call.
*/
cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": true, \"maxSize\" : 3}}");
s0 = cli0.getSession();
s1 = cli0.getSession();
s0.close();
Field fActiveSessions = ClientImpl.class.getDeclaredField("activeProtocols");
fActiveSessions.setAccessible(true);
assertEquals(1, ((BlockingQueue<PooledXProtocol>) fIdleSessions.get(cli0)).size());
assertEquals(1, ((Set<WeakReference<PooledXProtocol>>) fActiveSessions.get(cli0)).size());
cli0.close();
assertEquals(0, ((BlockingQueue<PooledXProtocol>) fIdleSessions.get(cli0)).size());
assertEquals(0, ((Set<WeakReference<PooledXProtocol>>) fActiveSessions.get(cli0)).size());
final Session ses = s1;
assertThrows(CJCommunicationsException.class, new Callable<Void>() {
public Void call() throws Exception {
ses.getSchemas();
return null;
}
});
/*
* UT4/2: Verify that after Client was closed the Client.getSession() throws an XDevAPIError with the message "Client is closed."
*/
Client cli2 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": true}}");
cli2.close();
assertThrows(XDevAPIError.class, "Client is closed.", new Callable<Void>() {
public Void call() throws Exception {
cli2.getSession();
return null;
}
});
/*
* UT11/1: Having a pool with a single active and maxIdleTime = 0, verify that if closing the session then after any long inactivity time a new Session
* object returned by Client.getSession() uses the same internal MysqlxSession object.
*/
props.setProperty(ClientProperty.POOLING_MAX_SIZE.getKeyName(), "2");
props.setProperty(ClientProperty.POOLING_MAX_IDLE_TIME.getKeyName(), "0");
props.setProperty(ClientProperty.POOLING_QUEUE_TIMEOUT.getKeyName(), "20000");
Client cli3 = cf.getClient(this.baseUrl, props);
s0 = cli3.getSession();
s1 = cli3.getSession();
assertEquals(2, ((Set<WeakReference<PooledXProtocol>>) fActiveSessions.get(cli3)).size());
s0.close();
Thread.sleep(10000);
s2 = cli3.getSession();
s2.sql("SELECT 1").execute();
assertNotEquals(s0, s2);
assertEquals(fProtocol.get(((SessionImpl) s0).getSession()), fProtocol.get(((SessionImpl) s2).getSession()));
cli3.close();
/*
* UT5/1: Having a full pool and queueTimeout = 0, verify that a new Client.getSession() waits until a Session is released.
*/
props.setProperty(ClientProperty.POOLING_MAX_SIZE.getKeyName(), "2");
props.setProperty(ClientProperty.POOLING_MAX_IDLE_TIME.getKeyName(), "1000");
props.setProperty(ClientProperty.POOLING_QUEUE_TIMEOUT.getKeyName(), "0");
cli3 = cf.getClient(this.baseUrl, props);
s1 = cli3.getSession();
Session s6 = cli3.getSession();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10000);
s6.close();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
long begin = System.currentTimeMillis();
t.start();
s1 = cli3.getSession();
long end = System.currentTimeMillis() - begin;
s1.sql("SELECT 1").execute();
assertTrue(end >= 10000, "Expected wait time 10000 ms but was " + end);
assertEquals(fProtocol.get(((SessionImpl) s1).getSession()), fProtocol.get(((SessionImpl) s6).getSession()));
/*
* TS10_2 Verify that RuntimProperty objects are reset to initial values when Session returned to pool.
*/
assertEquals(2, ((Set<WeakReference<PooledXProtocol>>) fActiveSessions.get(cli3)).size());
((SessionImpl) s1).getSession().getPropertySet().getStringProperty(PropertyKey.connectionAttributes).setValue("orig:s1");
s1.close();
assertEquals(1, ((Set<WeakReference<PooledXProtocol>>) fActiveSessions.get(cli3)).size());
s2 = cli3.getSession();
s2.sql("SELECT 1").execute();
assertEquals(fProtocol.get(((SessionImpl) s1).getSession()), fProtocol.get(((SessionImpl) s2).getSession()));
assertNotEquals("orig:s1", ((SessionImpl) s1).getSession().getPropertySet().getStringProperty(PropertyKey.connectionAttributes).getValue());
assertEquals(((SessionImpl) s1).getSession().getPropertySet().getStringProperty(PropertyKey.connectionAttributes).getInitialValue(), ((SessionImpl) s1).getSession().getPropertySet().getStringProperty(PropertyKey.connectionAttributes).getValue());
/*
* UT10/1: Get the max sessions allowed in the pool, create the same variables and temp tables in all the sessions,
* save ((SessionImpl) sN).getSession().getServerSession().getThreadId() values.
* Then close all the sessions and get a new one: the variables and the temp tables must not exist,
* ((SessionImpl) sN).getSession().getServerSession().getThreadId() must return values equal to saved ones.
*/
cli0 = cf.getClient(this.baseUrl, "{\"pooling\": {\"enabled\": true, \"maxSize\" : 2}}");
s0 = cli0.getSession();
s1 = cli0.getSession();
long id0 = ((SessionImpl) s0).getSession().getServerSession().getCapabilities().getThreadId();
long id1 = ((SessionImpl) s1).getSession().getServerSession().getCapabilities().getThreadId();
s0.sql("SET @a='s0'").execute();
s0.sql("CREATE TEMPORARY TABLE testpooledsessionstmps0(x int)").execute();
s1.sql("SET @a='s1'").execute();
s1.sql("CREATE TEMPORARY TABLE testpooledsessionstmps1(x int)").execute();
SqlResult res = s0.sql("SELECT @a as a").execute();
assertTrue(res.hasNext());
assertEquals("s0", res.next().getString(0));
res = s0.sql("SHOW CREATE TABLE testpooledsessionstmps0").execute();
assertTrue(res.hasNext());
assertEquals("testpooledsessionstmps0", res.next().getString(0));
res = s1.sql("SELECT @a as a").execute();
assertTrue(res.hasNext());
assertEquals("s1", res.next().getString(0));
res = s1.sql("SHOW CREATE TABLE testpooledsessionstmps1").execute();
assertTrue(res.hasNext());
assertEquals("testpooledsessionstmps1", res.next().getString(0));
s0.close();
s1.close();
Session s0_new = cli0.getSession();
Session s1_new = cli0.getSession();
assertEquals(id0, ((SessionImpl) s0_new).getSession().getServerSession().getCapabilities().getThreadId());
assertEquals(id1, ((SessionImpl) s1_new).getSession().getServerSession().getCapabilities().getThreadId());
res = s0_new.sql("SELECT @a as a").execute();
assertTrue(res.hasNext());
assertNull(res.next().getString(0));
assertThrows(XProtocolError.class, ".*testpooledsessionstmps0' doesn't exist", new Callable<Void>() {
public Void call() throws Exception {
s0_new.sql("SHOW CREATE TABLE testpooledsessionstmps0").execute();
return null;
}
});
res = s1_new.sql("SELECT @a as a").execute();
assertTrue(res.hasNext());
assertNull(res.next().getString(0));
assertThrows(XProtocolError.class, ".*testpooledsessionstmps1' doesn't exist", new Callable<Void>() {
public Void call() throws Exception {
s1_new.sql("SHOW CREATE TABLE testpooledsessionstmps1").execute();
return null;
}
});
cli0.close();
}
use of com.mysql.cj.xdevapi.Session in project aws-mysql-jdbc by awslabs.
the class SessionTest method testSessionAttributes.
@Test
public void testSessionAttributes() throws Exception {
assumeTrue(mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.16")), "MySQL 8.0.16+ is required to run this test.");
ClientFactory cf = new ClientFactory();
Map<String, String> userAttributes = new HashMap<>();
// TSFR1/TSFR2/TSFR3 Create a Session with xdevapi.connection-attributes in the connection string, verify that
// the session is successfully established. Create a Session using a connection string containing the properties
// as listed below, verify that the session is successfully established and the server contains the defined session attributes.
// xdevapi.connection-attributes=[key1=value1]
// xdevapi.connection-attributes=[key1=value1,key2=value2]
// xdevapi.connection-attributes=key1=value1
// xdevapi.connection-attributes=key1=value1,key2=value2
userAttributes.clear();
userAttributes.put("key1", "value1");
String baseUrlLocal = this.baseUrl + (this.baseUrl.contains("?") ? "&" : "?");
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=value1", true), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=value1]", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=value1", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=value1]", true), userAttributes);
userAttributes.put("key2", "value2");
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=value1,key2=value2", true), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=value1,key2=value2]", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=value1,key2=value2", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=value1,key2=value2]", true), userAttributes);
// TSFR4/TSFR5/TSFR6 Create a Session without xdevapi.connection-attributes in the connection string, verify that all predefined attributes
// exist and contain the correct values. Verify that only connection attributes starting with "_" were set for current session.
userAttributes.clear();
testSessionAttributes_checkSession(this.baseUrl, userAttributes);
testSessionAttributes_checkClient(this.baseUrl, userAttributes);
// TSFR7 Create a Session using a connection string containing the properties as listed below, verify that a WrongArgumentException exception is thrown
// with the message Key names in "xdevapi.connection-attributes" cannot start with "_".
// xdevapi.connection-attributes=[_key1=value1]
// xdevapi.connection-attributes=[key1=value1,_key2=value2]
// xdevapi.connection-attributes=_key1=value1
// xdevapi.connection-attributes=key1=value1,_key2=value2
assertThrows(WrongArgumentException.class, "Key names in \"xdevapi.connection-attributes\" cannot start with \"_\".", () -> {
this.fact.getSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[_key1=value1]", true));
return null;
});
assertThrows(WrongArgumentException.class, "Key names in \"xdevapi.connection-attributes\" cannot start with \"_\".", () -> {
Client cli1 = cf.getClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[_key1=value1]", true), new Properties());
cli1.getSession();
return null;
});
assertThrows(WrongArgumentException.class, "Key names in \"xdevapi.connection-attributes\" cannot start with \"_\".", () -> {
this.fact.getSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=value1,_key2=value2]", true));
return null;
});
assertThrows(WrongArgumentException.class, "Key names in \"xdevapi.connection-attributes\" cannot start with \"_\".", () -> {
Client cli1 = cf.getClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=value1,_key2=value2]", true), new Properties());
cli1.getSession();
return null;
});
assertThrows(WrongArgumentException.class, "Key names in \"xdevapi.connection-attributes\" cannot start with \"_\".", () -> {
this.fact.getSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "_key1=value1", true));
return null;
});
assertThrows(WrongArgumentException.class, "Key names in \"xdevapi.connection-attributes\" cannot start with \"_\".", () -> {
Client cli1 = cf.getClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "_key1=value1", true), new Properties());
cli1.getSession();
return null;
});
assertThrows(WrongArgumentException.class, "Key names in \"xdevapi.connection-attributes\" cannot start with \"_\".", () -> {
this.fact.getSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=value1,_key2=value2", true));
return null;
});
assertThrows(WrongArgumentException.class, "Key names in \"xdevapi.connection-attributes\" cannot start with \"_\".", () -> {
Client cli1 = cf.getClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=value1,_key2=value2", true), new Properties());
cli1.getSession();
return null;
});
// TSFR9 Create a Session using a connection string containing the properties as listed below, verify
// that the user-defined connection attribute key1 has an empty value.
// xdevapi.connection-attributes=[key1]
// xdevapi.connection-attributes=[key1,key2=value2]
// xdevapi.connection-attributes=[key1=]
// xdevapi.connection-attributes=[key1=,key2=value2]
// xdevapi.connection-attributes=key1
// xdevapi.connection-attributes=key1,key2=value2
// xdevapi.connection-attributes=key1=
// xdevapi.connection-attributes=key1=,key2=value2
userAttributes.clear();
userAttributes.put("key1", "");
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1]", true), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=]", true), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1", true), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1]", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=]", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=", true), userAttributes);
userAttributes.put("key2", "value2");
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1,key2=value2]", true), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=,key2=value2]", true), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1,key2=value2", true), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=,key2=value2", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1,key2=value2]", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[key1=,key2=value2]", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1,key2=value2", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=,key2=value2", true), userAttributes);
// TSFR10 Create a Session with xdevapi.connection-attributes=false in the connection string, verify
// that no connection attribute was set for current session.
Session s10 = this.fact.getSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "false", true));
SqlResult res = s10.sql("SELECT * FROM performance_schema.session_connect_attrs WHERE processlist_id = CONNECTION_ID()").execute();
assertFalse(res.hasNext(), "Expected no connection attributes.");
s10.close();
Client c10 = cf.getClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "false", true), new Properties());
s10 = c10.getSession();
res = s10.sql("SELECT * FROM performance_schema.session_connect_attrs WHERE processlist_id = CONNECTION_ID()").execute();
assertFalse(res.hasNext(), "Expected no connection attributes.");
s10.close();
c10.close();
// TSFR11 Create a Session using a connection string containing the properties as listed below, verify
// that only the client-defined connection attributes were set for the current session.
// xdevapi.connection-attributes
// xdevapi.connection-attributes=
// xdevapi.connection-attributes=true
// xdevapi.connection-attributes=[]
userAttributes.clear();
testSessionAttributes_checkSession(baseUrlLocal + PropertyKey.xdevapiConnectionAttributes.getKeyName(), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + PropertyKey.xdevapiConnectionAttributes.getKeyName() + "=", userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "true", true), userAttributes);
testSessionAttributes_checkSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[]", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + PropertyKey.xdevapiConnectionAttributes.getKeyName(), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + PropertyKey.xdevapiConnectionAttributes.getKeyName() + "=", userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "true", true), userAttributes);
testSessionAttributes_checkClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "[]", true), userAttributes);
// TSFR13 Create a Session with xdevapi.connection-attributes=[key1=value1,key1=value2] in the connection string, verify that
// a WrongArgumentException exception is thrown with the message Duplicate key "key1" used in "xdevapi.connection-attributes".
assertThrows(WrongArgumentException.class, "Duplicate key \"key1\" used in \"xdevapi.connection-attributes\".", () -> {
this.fact.getSession(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=value1,key1=value2", true));
return null;
});
assertThrows(WrongArgumentException.class, "Duplicate key \"key1\" used in \"xdevapi.connection-attributes\".", () -> {
Client cli1 = cf.getClient(baseUrlLocal + makeParam(PropertyKey.xdevapiConnectionAttributes, "key1=value1,key1=value2", true), new Properties());
cli1.getSession();
return null;
});
}
use of com.mysql.cj.xdevapi.Session in project aws-mysql-jdbc by awslabs.
the class SessionTest method testPreparedStatementsCleanup.
@Test
public void testPreparedStatementsCleanup() {
assumeTrue(mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.14")), "MySQL 8.0.14+ is required to run this test.");
try {
// Prepare test data.
this.schema.createCollection("testPrepStmtClean", true).add("{\"_id\":\"1\"}").execute();
SessionFactory sf = new SessionFactory();
/*
* Test common usage.
*/
Session testSession = sf.getSession(this.testProperties);
int sessionThreadId = getThreadId(testSession);
assertPreparedStatementsCount(sessionThreadId, 0, 1);
assertPreparedStatementsStatusCounts(testSession, 0, 0, 0);
// Initialize several *Statement objects.
FindStatement testFind1 = testSession.getDefaultSchema().getCollection("testPrepStmtClean").find();
SelectStatement testSelect1 = testSession.getDefaultSchema().getCollectionAsTable("testPrepStmtClean").select("_id");
FindStatement testFind2 = testSession.getDefaultSchema().getCollection("testPrepStmtClean").find();
SelectStatement testSelect2 = testSession.getDefaultSchema().getCollectionAsTable("testPrepStmtClean").select("_id");
// 1st execute -> don't prepare.
testFind1.execute();
assertPreparedStatementsCountsAndId(testSession, 0, testFind1, 0, -1);
testSelect1.execute();
assertPreparedStatementsCountsAndId(testSession, 0, testSelect1, 0, -1);
testFind2.execute();
assertPreparedStatementsCountsAndId(testSession, 0, testFind2, 0, -1);
testSelect2.execute();
assertPreparedStatementsCountsAndId(testSession, 0, testSelect2, 0, -1);
assertPreparedStatementsStatusCounts(testSession, 0, 0, 0);
// 2nd execute -> prepare + execute.
testFind1.execute();
assertPreparedStatementsCountsAndId(testSession, 1, testFind1, 1, 1);
testSelect1.execute();
assertPreparedStatementsCountsAndId(testSession, 2, testSelect1, 2, 1);
testFind2.execute();
assertPreparedStatementsCountsAndId(testSession, 3, testFind2, 3, 1);
testSelect2.execute();
assertPreparedStatementsCountsAndId(testSession, 4, testSelect2, 4, 1);
assertPreparedStatementsStatusCounts(testSession, 4, 4, 0);
assertPreparedStatementsCount(sessionThreadId, 4, 1);
/*
* The following verifications are non-deterministic as System.gc() only hints the JVM to perform a garbage collection. This approach allows some
* time for the JVM to execute the GC. In case of failure the repeats or wait times may have to be adjusted.
* The test can be deleted entirely if no reasonable setup can be found.
*/
// Nullify first statement.
testFind1 = null;
System.gc();
int psCount, countdown = 10;
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
testSession.sql("SELECT 1").execute();
psCount = getPreparedStatementsCount(sessionThreadId);
} while (psCount != 3 && --countdown > 0);
assertPreparedStatementsStatusCounts(testSession, 4, 4, 1);
assertPreparedStatementsCount(sessionThreadId, 3, 1);
// Nullify second and third statements.
testSelect1 = null;
testFind2 = null;
System.gc();
countdown = 10;
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
testSession.sql("SELECT 1").execute();
psCount = getPreparedStatementsCount(sessionThreadId);
} while (psCount != 1 && --countdown > 0);
assertPreparedStatementsStatusCounts(testSession, 4, 4, 3);
assertPreparedStatementsCount(sessionThreadId, 1, 1);
// Nullify last statement.
testSelect2 = null;
System.gc();
countdown = 10;
do {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
testSession.sql("SELECT 1").execute();
psCount = getPreparedStatementsCount(sessionThreadId);
} while (psCount != 0 && --countdown > 0);
assertPreparedStatementsStatusCounts(testSession, 4, 4, 4);
assertPreparedStatementsCount(sessionThreadId, 0, 1);
testSession.close();
assertPreparedStatementsCount(sessionThreadId, 0, 1);
} finally {
this.schema.dropCollection("testPrepStmtClean");
}
}
Aggregations