1 /*
2  *  Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License, version 2.0,
6  *  as published by the Free Software Foundation.
7  *
8  *  This program is also distributed with certain software (including
9  *  but not limited to OpenSSL) that is licensed under separate terms,
10  *  as designated in a particular file or component or in included license
11  *  documentation.  The authors of MySQL hereby grant you an additional
12  *  permission to link the program and your derivative works with the
13  *  separately licensed software that they have included with MySQL.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License, version 2.0, for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 package testsuite.clusterj;
26 
27 import java.util.Arrays;
28 import java.util.List;
29 import java.util.Properties;
30 
31 import testsuite.clusterj.model.Employee;
32 
33 import com.mysql.clusterj.ClusterJFatalUserException;
34 import com.mysql.clusterj.ClusterJHelper;
35 import com.mysql.clusterj.Constants;
36 import com.mysql.clusterj.Session;
37 import com.mysql.clusterj.SessionFactory;
38 
39 @org.junit.Ignore("test requires specific connection pooling setup")
40 public class ConnectionPoolTest extends AbstractClusterJTest {
41 
42     @Override
getDebug()43     public boolean getDebug() {
44         return false;
45     }
46 
runSpecificNodeIdTests()47     protected boolean runSpecificNodeIdTests() {
48         return false;
49     }
50 
51     @Override
localSetUp()52     public void localSetUp() {
53         loadProperties();
54         // close the existing session factory because it uses one of the cluster connection (api) nodes
55         if (sessionFactory != null) {
56             sessionFactory.close();
57             sessionFactory = null;
58         }
59     }
60 
testNoPooling()61     public void testNoPooling() {
62         Properties modifiedProperties = new Properties();
63         modifiedProperties.putAll(props);
64         SessionFactory sessionFactory1 = null;
65         SessionFactory sessionFactory2 = null;
66 
67         // with connection.pool.size set to 1 each session factory should be the same
68         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_SIZE, 1);
69         sessionFactory1 = ClusterJHelper.getSessionFactory(modifiedProperties);
70         sessionFactory2 = ClusterJHelper.getSessionFactory(modifiedProperties);
71         sessionFactory1.close();
72         sessionFactory2.close();
73         errorIfNotEqual("With connection pooling, SessionFactory1 should be the same object as SessionFactory2",
74                 true, sessionFactory1 == sessionFactory2);
75 
76         // with connection.pool.size set to 0 each session factory should be unique
77         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_SIZE, 0);
78         sessionFactory1 = ClusterJHelper.getSessionFactory(modifiedProperties);
79         sessionFactory2 = ClusterJHelper.getSessionFactory(modifiedProperties);
80         try {
81             SessionFactory sessionFactory3 = ClusterJHelper.getSessionFactory(modifiedProperties);
82             sessionFactory3.close();
83         } catch (ClusterJFatalUserException ex) {
84             // good catch
85         }
86         sessionFactory1.close();
87         sessionFactory2.close();
88         errorIfNotEqual("With no connection pooling, SessionFactory1 should not be the same object as SessionFactory2",
89                 false, sessionFactory1 == sessionFactory2);
90 
91         failOnError();
92     }
93 
testConnectionPoolSize()94     public void testConnectionPoolSize() {
95         Properties modifiedProperties = new Properties();
96         modifiedProperties.putAll(props);
97         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_SIZE, 2);
98         checkConnectionPoolSize2("testConnectionPoolSize", modifiedProperties);
99         failOnError();
100     }
101 
testConnectionPoolSizeAndNodeIds()102     public void testConnectionPoolSizeAndNodeIds() {
103         if (!runSpecificNodeIdTests()) {
104             return;
105         }
106         Properties modifiedProperties = new Properties();
107         modifiedProperties.putAll(props);
108         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_SIZE, 2);
109         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_NODEIDS, "4;5");
110         checkConnectionPoolSize2("testConnectionPoolSizeAndNodeIds", modifiedProperties);
111         failOnError();
112     }
113 
testConnectionNodeIds()114     public void testConnectionNodeIds() {
115         if (!runSpecificNodeIdTests()) {
116             return;
117         }
118         Properties modifiedProperties = new Properties();
119         modifiedProperties.putAll(props);
120         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_NODEIDS, "4,5");
121         checkConnectionPoolSize2("testConnectionNodeIds", modifiedProperties);
122         failOnError();
123     }
124 
testConnectionSingleNodeIdAndConnectionPoolSize()125     public void testConnectionSingleNodeIdAndConnectionPoolSize() {
126         if (!runSpecificNodeIdTests()) {
127             return;
128         }
129         Properties modifiedProperties = new Properties();
130         modifiedProperties.putAll(props);
131         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_SIZE, 2);
132         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_NODEIDS, "4");
133         checkConnectionPoolSize2("testConnectionSingleNodeIdAndConnectionPoolSize", modifiedProperties);
134         failOnError();
135     }
136 
checkConnectionPoolSize2(String where, Properties modifiedProperties)137     private void checkConnectionPoolSize2(String where, Properties modifiedProperties) {
138         SessionFactory sessionFactory1 = null;
139         SessionFactory sessionFactory2 = null;
140         SessionFactory sessionFactory3 = null;
141         sessionFactory1 = ClusterJHelper.getSessionFactory(modifiedProperties);
142         sessionFactory2 = ClusterJHelper.getSessionFactory(modifiedProperties);
143         sessionFactory3 = ClusterJHelper.getSessionFactory(modifiedProperties);
144         errorIfNotEqual(where + " SessionFactory1 should be the same object as SessionFactory2", true,
145                 sessionFactory1 == sessionFactory2);
146         errorIfNotEqual(where + " SessionFactory1 should be the same object as SessionFactory3", true,
147                 sessionFactory1 == sessionFactory3);
148         Session session1 = sessionFactory1.getSession();
149         Employee e1 = session1.find(Employee.class, 0);
150         checkSessions(where + " after get session1", sessionFactory1, new Integer[] {1, 0});
151         Session session2 = sessionFactory1.getSession();
152         Employee e2 = session2.find(Employee.class, 0);
153         checkSessions(where + " after get session2", sessionFactory1, new Integer[] {1, 1});
154         Session session3 = sessionFactory1.getSession();
155         checkSessions(where + " after get session3", sessionFactory1, new Integer[] {2, 1});
156         Session session4 = sessionFactory1.getSession();
157         checkSessions(where + " after get session4", sessionFactory1, new Integer[] {2, 2});
158         Session session5 = sessionFactory1.getSession();
159         checkSessions(where + " after get session5", sessionFactory1, new Integer[] {3, 2});
160         Session session6 = sessionFactory1.getSession();
161         checkSessions(where + " after get session6", sessionFactory1, new Integer[] {3, 3});
162 
163         session1.close();
164         checkSessions(where + " after close session1", sessionFactory1, new Integer[] {2, 3});
165         session4.close();
166         checkSessions(where + " after close session4", sessionFactory1, new Integer[] {2, 2});
167         session5.close();
168         checkSessions(where + " after close session5", sessionFactory1, new Integer[] {1, 2});
169         Session session7 = sessionFactory1.getSession();
170         checkSessions(where + " after get session7", sessionFactory1, new Integer[] {2, 2});
171 
172         session2.close();
173         session3.close();
174         session6.close();
175         session7.close();
176         sessionFactory1.close();
177     }
178 
testNegativeMismatchConnectionPoolSizeAndConnectionPoolNodeids()179     public void testNegativeMismatchConnectionPoolSizeAndConnectionPoolNodeids() {
180         Properties modifiedProperties = new Properties();
181         modifiedProperties.putAll(props);
182         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_SIZE, 3);
183         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_NODEIDS, "4\t5");
184         try {
185             ClusterJHelper.getSessionFactory(modifiedProperties);
186         } catch (ClusterJFatalUserException ex) {
187             if (getDebug()) ex.printStackTrace();
188             // good catch
189             String expected = "4\t5";
190             if (!ex.getMessage().contains(expected)) {
191                 error("Mismatch error message should contain " + expected);
192             }
193         }
194         failOnError();
195     }
196 
testNegativeConnectionPoolNodeidsFormatError()197     public void testNegativeConnectionPoolNodeidsFormatError() {
198         Properties modifiedProperties = new Properties();
199         modifiedProperties.putAll(props);
200         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_SIZE, 2);
201         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_NODEIDS, "7 t");
202         try {
203             ClusterJHelper.getSessionFactory(modifiedProperties);
204         } catch (ClusterJFatalUserException ex) {
205             if (getDebug()) ex.printStackTrace();
206             // good catch
207             String expected = "NumberFormatException";
208             if (!ex.getMessage().contains(expected)) {
209                 error("Mismatch error message '" + ex.getMessage() + "' should contain '" + expected + '"');
210             }
211         }
212         failOnError();
213     }
214 
215     @org.junit.Ignore("testNegativeConnectionPoolIllegalNodeids takes too long")
testNegativeConnectionPoolIllegalNodeids()216     public void testNegativeConnectionPoolIllegalNodeids() {
217         Properties modifiedProperties = new Properties();
218         modifiedProperties.putAll(props);
219         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_NODEIDS, "256");
220         try {
221             ClusterJHelper.getSessionFactory(modifiedProperties);
222         } catch (ClusterJFatalUserException ex) {
223             if (getDebug()) ex.printStackTrace();
224             // good catch
225             String expected = "illegal";
226             if (!ex.getMessage().contains(expected)) {
227                 error("Mismatch error message '" + ex.getMessage() + "' should contain '" + expected + '"');
228             }
229         }
230         failOnError();
231     }
232 
testNegativeConnectionPoolNoNodeId()233     public void testNegativeConnectionPoolNoNodeId() {
234         if (!runSpecificNodeIdTests()) {
235             return;
236         }
237         Properties modifiedProperties = new Properties();
238         modifiedProperties.putAll(props);
239         modifiedProperties.put(Constants.PROPERTY_CONNECTION_POOL_NODEIDS, "48");
240         try {
241             ClusterJHelper.getSessionFactory(modifiedProperties);
242         } catch (ClusterJFatalUserException ex) {
243             if (getDebug()) ex.printStackTrace();
244             // good catch
245             String expected = "No node defined";
246             if (!ex.getMessage().contains(expected)) {
247                 error("Mismatch error message '" + ex.getMessage() + "' should contain '" + expected + '"');
248             }
249         }
250         failOnError();
251     }
252 
checkSessions(String where, SessionFactory sessionFactory, Integer[] expected)253     private void checkSessions(String where, SessionFactory sessionFactory, Integer[] expected) {
254         List<Integer> connectionCounts = sessionFactory.getConnectionPoolSessionCounts();
255         if (getDebug()) System.out.println("connection counts: " + connectionCounts.toString());
256         if (expected.length != connectionCounts.size()) {
257             error(where + " wrong number of connections in pool\n"
258                     + "Expected: " + Arrays.toString(expected)
259                     + " Actual: " + connectionCounts);
260             return;
261         }
262         int i = 0;
263         for (Integer connectionCount: connectionCounts) {
264             if (getDebug()) System.out.println("Connection " + i + " has " + connectionCount + " sessions.");
265             if (i >= expected.length) break;
266             errorIfNotEqual(where + " wrong count on connection " + i, expected[i], connectionCount);
267             i++;
268         }
269         if (getDebug()) System.out.println();
270     }
271 }
272