View Javadoc

1   /*
2    * SymmetricDS is an open source database synchronization solution.
3    *   
4    * Copyright (C) Chris Henson <chenson42@users.sourceforge.net>
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Lesser General Public
8    * License as published by the Free Software Foundation; either
9    * version 3 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, see
18   * <http://www.gnu.org/licenses/>.
19   */
20  package org.jumpmind.symmetric.test;
21  
22  import java.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.InputStreamReader;
27  import java.net.URL;
28  import java.sql.Connection;
29  import java.sql.DriverManager;
30  import java.sql.SQLException;
31  import java.util.ArrayList;
32  import java.util.Arrays;
33  import java.util.Collection;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.Properties;
37  import java.util.Set;
38  
39  import javax.servlet.ServletContext;
40  import javax.sql.DataSource;
41  
42  import org.apache.commons.lang.StringUtils;
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  import org.apache.ddlutils.Platform;
46  import org.apache.ddlutils.io.DatabaseIO;
47  import org.apache.ddlutils.model.Database;
48  import org.apache.derby.jdbc.EmbeddedDriver;
49  import org.jumpmind.symmetric.SymmetricEngine;
50  import org.jumpmind.symmetric.SymmetricWebServer;
51  import org.jumpmind.symmetric.common.Constants;
52  import org.jumpmind.symmetric.common.ParameterConstants;
53  import org.jumpmind.symmetric.db.IDbDialect;
54  import org.jumpmind.symmetric.db.SqlScript;
55  import org.jumpmind.symmetric.service.IBootstrapService;
56  import org.jumpmind.symmetric.util.AppUtils;
57  import org.junit.Assert;
58  import org.springframework.mock.web.MockHttpServletRequest;
59  
60  public class TestSetupUtil {
61  
62      static final Log logger = LogFactory.getLog(TestSetupUtil.class);
63  
64      static private SymmetricEngine clientEngine;
65  
66      static private SymmetricWebServer rootServer;
67  
68      public static Collection<String[]> lookupDatabasePairs(String testPrefix) {
69          Properties properties = getTestProperties(testPrefix);
70          String[] clientDatabaseTypes = StringUtils.split(properties.getProperty(testPrefix + ".client"), ",");
71          String[] rootDatabaseTypes = getRootDbTypes(testPrefix);
72  
73          String[][] clientAndRootCombos = new String[rootDatabaseTypes.length * clientDatabaseTypes.length][2];
74  
75          int index = 0;
76          for (String rootDatabaseType : rootDatabaseTypes) {
77              for (String clientDatabaseType : clientDatabaseTypes) {
78                  clientAndRootCombos[index][0] = clientDatabaseType;
79                  clientAndRootCombos[index++][1] = rootDatabaseType;
80              }
81          }
82          return Arrays.asList(clientAndRootCombos);
83      }
84  
85      public static Collection<String[]> lookupDatabases(String testPrefix) {
86          List<String[]> list = new ArrayList<String[]>();
87          String[] dbs = getRootDbTypes(testPrefix);
88          for (String string : dbs) {
89              list.add(new String[] { string });
90          }
91          return list;
92      }
93  
94      public static void cleanup() throws Exception {
95          if (clientEngine != null) {
96              clientEngine.stop();
97              clientEngine = null;
98          }
99          if (rootServer != null) {
100             rootServer.stop();
101             rootServer = null;
102         }
103 
104         closeDerbyAndReloadDriver();
105     }
106     
107     /***
108      * Unit tests were failing after opening and closing several data connection pools against the 
109      * same database in memory.  After shutting down the connection pool, it seems to help by shutting
110      * down the entire database.
111      */
112     protected static void closeDerbyAndReloadDriver() throws SQLException {
113         try {
114             DriverManager.getConnection("jdbc:derby:;shutdown=true");            
115         } catch (SQLException ex) {
116             if (ex.getErrorCode() == 50000) {
117                 DriverManager.registerDriver(new EmbeddedDriver());
118                 logger.info(ex.getMessage());
119             }
120         } catch (Exception ex) {
121             // derby not in use ...
122         }
123     }
124 
125     public static void setup(String testPrefix, String sqlScriptSuffix, String clientDb, String rootDb)
126             throws Exception {
127         if (rootDb != null) {
128             rootServer = new SymmetricWebServer(new SymmetricEngine("file:"
129                     + writeTempPropertiesFileFor(testPrefix, rootDb, DatabaseRole.ROOT).getAbsolutePath()));
130             dropAndCreateDatabaseTables(rootDb, rootServer.getEngine());
131             IBootstrapService bootstrapService = AppUtils.find(Constants.BOOTSTRAP_SERVICE, rootServer.getEngine());
132             bootstrapService.setupDatabase();
133             new SqlScript(getResource("/" + testPrefix + sqlScriptSuffix), (DataSource) rootServer.getEngine()
134                     .getApplicationContext().getBean(Constants.DATA_SOURCE), true).execute();
135             rootServer.setJoin(false);
136             rootServer.start(8888);
137         }
138 
139         if (clientDb != null) {
140             clientEngine = new SymmetricEngine("file:"
141                     + writeTempPropertiesFileFor(testPrefix, clientDb, DatabaseRole.CLIENT).getAbsolutePath(), null);
142             dropAndCreateDatabaseTables(clientDb, clientEngine);
143         }
144     }
145 
146     public static SymmetricEngine getRootEngine() {
147         return rootServer.getEngine();
148     }
149 
150     public static SymmetricEngine getClientEngine() {
151         return clientEngine;
152     }
153 
154     public static boolean isConnectionValid(Properties properties) throws Exception {
155         try {
156             Class.forName(properties.getProperty("db.driver"));
157             Connection c = DriverManager.getConnection(properties.getProperty("db.url"), properties
158                     .getProperty("db.user"), properties.getProperty("db.password"));
159             c.close();
160             return true;
161         } catch (Exception ex) {
162             logger.error("Could not connect to the test database using the url: " + properties.getProperty("db.url")
163                     + " and classpath: " + System.getProperty("java.class.path"), ex);
164             return false;
165         }
166     }
167 
168     protected static void dropAndCreateDatabaseTables(String databaseType, SymmetricEngine engine) {
169         DataSource ds = (DataSource) engine.getApplicationContext().getBean(Constants.DATA_SOURCE);
170         try {
171             IDbDialect dialect = (IDbDialect) engine.getApplicationContext().getBean(Constants.DB_DIALECT);
172             Platform platform = dialect.getPlatform();
173             Database testDb = getTestDatabase();
174             platform.dropTables(testDb, true);
175             dialect.purge();
176 
177             new SqlScript(getResource(TestConstants.TEST_DROP_ALL_SCRIPT), ds, false).execute();
178 
179             String fileName = TestConstants.TEST_DROP_SEQ_SCRIPT + databaseType + ".sql";
180             URL url = getResource(fileName);
181             if (url != null) {
182                 new SqlScript(url, ds, false).execute();
183             }
184 
185             platform.createTables(testDb, false, true);
186 
187         } catch (Exception e) {
188             throw new RuntimeException(e);
189         }
190     }
191 
192     protected static URL getResource(String resource) {
193         return TestSetupUtil.class.getResource(resource);
194     }
195 
196     protected static Database getTestDatabase() throws IOException {
197         return new DatabaseIO().read(new InputStreamReader(getResource("/test-tables-ddl.xml").openStream()));
198     }
199 
200     public static File writeTempPropertiesFileFor(String testPrefix, String databaseType, DatabaseRole databaseRole) {
201         try {
202             Properties properties = getTestProperties(testPrefix);
203             Properties newProperties = new Properties();
204             Set<Object> keys = properties.keySet();
205             for (Object string : keys) {
206                 String key = (String) string;
207                 String dbRoleReplaceToken = databaseType + "." + databaseRole.name().toLowerCase() + ".";
208                 if (key.startsWith(dbRoleReplaceToken)) {
209                     String newKey = key.substring(dbRoleReplaceToken.length());
210                     newProperties.put(newKey, properties.get(key));
211                 } else if (key.startsWith(databaseType)) {
212                     String newKey = key.substring(databaseType.length() + 1);
213                     newProperties.put(newKey, properties.get(key));
214                 } else {
215                     newProperties.put(key, properties.get(key));
216                 }
217             }
218 
219             if (isConnectionValid(newProperties)) {
220                 newProperties.setProperty(ParameterConstants.NODE_GROUP_ID,
221                         databaseRole == DatabaseRole.CLIENT ? TestConstants.TEST_CLIENT_NODE_GROUP
222                                 : TestConstants.TEST_ROOT_NODE_GROUP);
223                 newProperties.setProperty(ParameterConstants.EXTERNAL_ID,
224                         databaseRole == DatabaseRole.ROOT ? TestConstants.TEST_ROOT_EXTERNAL_ID
225                                 : TestConstants.TEST_CLIENT_EXTERNAL_ID);
226                 newProperties.setProperty(ParameterConstants.MY_URL, "http://localhost:8888/sync");
227                 newProperties.setProperty(ParameterConstants.REGISTRATION_URL,
228                         databaseRole == DatabaseRole.CLIENT ? "http://localhost:8888/sync" : "");
229                 newProperties.setProperty(ParameterConstants.ENGINE_NAME, databaseRole.name().toLowerCase());
230 
231                 File propertiesFile = File.createTempFile("symmetric-test.", ".properties");
232                 FileOutputStream os = new FileOutputStream(propertiesFile);
233                 newProperties.store(os, "generated by the symmetricds unit tests");
234                 os.close();
235                 propertiesFile.deleteOnExit();
236                 return propertiesFile;
237 
238             } else {
239                 Assert.fail("Could not find a valid connection for " + databaseType);
240                 return null;
241             }
242         } catch (RuntimeException ex) {
243             throw ex;
244         } catch (Exception ex) {
245             throw new RuntimeException(ex);
246         }
247 
248     }
249 
250     public static Properties getTestProperties(String testPrefix) {
251         try {
252             final String TEST_PROPERTIES_FILE = "/symmetric-" + testPrefix + ".properties";
253             Properties properties = new Properties();
254 
255             properties.load(TestSetupUtil.class.getResourceAsStream(TEST_PROPERTIES_FILE));
256             String homeDir = System.getProperty("user.home");
257             File propertiesFile = new File(homeDir + TEST_PROPERTIES_FILE);
258             if (propertiesFile.exists()) {
259                 FileInputStream f = new FileInputStream(propertiesFile);
260                 properties.load(f);
261                 f.close();
262             } else {
263                 logger.info("Could not find " + propertiesFile.getAbsolutePath()
264                         + ". Using all of the default properties");
265             }
266             return properties;
267         } catch (IOException ex) {
268             throw new RuntimeException(ex);
269         }
270     }
271 
272     protected static String[] getRootDbTypes(String testPrefix) {
273         Properties properties = getTestProperties(testPrefix);
274         return StringUtils.split(properties.getProperty(testPrefix + ".root"), ",");
275     }
276 
277     public static MockHttpServletRequest createMockHttpServletRequest(ServletContext servletContext, String method,
278             String uri, Map<String, String> parameters) {
279         final String[] uriParts = StringUtils.split(uri, "?");
280         final MockHttpServletRequest request = new MockHttpServletRequest(servletContext, method, uriParts[0]);
281         if (uriParts.length > 1) {
282             request.setQueryString(uriParts[1]);
283         }
284         if (parameters != null) {
285             request.setParameters(parameters);
286         }
287         return request;
288     }
289 
290 }