1 package fr.ifremer.quadrige3.core.test;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import com.google.common.base.Charsets;
25 import com.google.common.io.Files;
26 import fr.ifremer.quadrige3.core.config.QuadrigeConfiguration;
27 import fr.ifremer.quadrige3.core.config.QuadrigeConfigurationOption;
28 import fr.ifremer.quadrige3.core.dao.technical.Daos;
29 import fr.ifremer.quadrige3.core.dao.technical.DatabaseSchemaDao;
30 import fr.ifremer.quadrige3.core.dao.technical.hibernate.DatabaseSchemaDaoImpl;
31 import fr.ifremer.quadrige3.core.exception.DatabaseSchemaUpdateException;
32 import fr.ifremer.quadrige3.core.exception.QuadrigeTechnicalException;
33 import fr.ifremer.quadrige3.core.service.ServiceLocator;
34 import org.apache.commons.io.FileUtils;
35 import org.apache.commons.io.IOUtils;
36 import org.apache.commons.lang3.ArrayUtils;
37 import org.apache.commons.lang3.StringUtils;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.dbunit.DatabaseUnitException;
41 import org.dbunit.database.DatabaseConfig;
42 import org.dbunit.database.DatabaseConnection;
43 import org.dbunit.database.IDatabaseConnection;
44 import org.dbunit.dataset.IDataSet;
45 import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
46 import org.dbunit.ext.hsqldb.HsqldbDataTypeFactory;
47 import org.dbunit.ext.oracle.WktSupportOracle10DataTypeFactory;
48 import org.dbunit.ext.postgresql.PostgresqlDataTypeFactory;
49 import org.dbunit.operation.DatabaseOperation;
50 import org.junit.Assume;
51 import org.junit.rules.ExternalResource;
52 import org.nuiton.i18n.I18n;
53 import org.nuiton.i18n.init.DefaultI18nInitializer;
54 import org.nuiton.i18n.init.UserI18nInitializer;
55
56 import java.io.BufferedReader;
57 import java.io.BufferedWriter;
58 import java.io.File;
59 import java.io.IOException;
60 import java.net.URL;
61 import java.sql.Connection;
62 import java.sql.SQLException;
63 import java.util.Locale;
64 import java.util.Properties;
65 import java.util.StringTokenizer;
66
67
68
69
70 public class InitTests extends ExternalResource {
71
72 private static final String DATASET_COMMON_XML_FILE = "quadrige3.core.test.dataset.common";
73 private static final String DATASET_ADDITIONAL_XML_FILES = "quadrige3.core.test.dataset.additional";
74
75 private static final Log log = LogFactory.getLog(InitTests.class);
76
77
78
79
80
81
82
83 public static void main(String[] args) throws Throwable{
84
85
86 if (ArrayUtils.isEmpty(args)) {
87 log.error("Missing target directory, as first argument of InitTests.main(). Skipping");
88 System.exit(-1);
89 }
90
91 InitTests initTests = new InitTests();
92
93 try {
94
95
96 String targetDbArg = args[0];
97 initTests.setTargetDbDirectory(targetDbArg);
98
99
100 if (args.length >= 2) {
101 boolean replaceIfExists = Boolean.parseBoolean(args[1]);
102 initTests.setReplaceDbIfExists(replaceIfExists);
103 }
104
105 log.info(String.format("Creating test database into [%s]", initTests.getTargetDbDirectory()));
106
107
108 initTests.compactDatabase = true;
109 initTests.before();
110 } catch (Throwable ex) {
111 log.error(ex.getLocalizedMessage(), ex);
112 throw ex;
113 }
114 }
115
116 protected QuadrigeConfiguration config;
117
118 private String targetDbDirectory = null;
119
120 private boolean replaceDbIfExists = false;
121
122 private boolean compactDatabase = false;
123
124 public void setTargetDbDirectory(String targetDbDirectory) {
125 this.targetDbDirectory = targetDbDirectory;
126 }
127
128 public String getTargetDbDirectory() {
129 return targetDbDirectory;
130 }
131
132 public void setReplaceDbIfExists(boolean replaceDbIfExists) {
133 this.replaceDbIfExists = replaceDbIfExists;
134 }
135
136 public boolean getReplaceDbIfExists() {
137 return replaceDbIfExists;
138 }
139
140 protected String getDbEnumerationResource() {
141 return "classpath*:quadrige3-db-enumerations.properties";
142 }
143
144 protected String getModuleName() {
145 return "quadrige3-test-shared";
146 }
147
148 protected String getEnvironment() {
149 String env = System.getProperty("env");
150 if (StringUtils.isNotBlank(env))
151 return "-" + env;
152 return "";
153 }
154
155 protected String[] getConfigArgs() {
156 return new String[]{
157 "--option", QuadrigeConfigurationOption.DB_DIRECTORY.getKey(), getTargetDbDirectory(),
158 "--option", QuadrigeConfigurationOption.DB_ENUMERATION_RESOURCE.getKey(), getDbEnumerationResource()
159 };
160 }
161
162 protected QuadrigeConfiguration createConfig() {
163
164 QuadrigeConfiguration config = new QuadrigeConfiguration(
165 String.format("%s-test-write%s.properties", getModuleName(), getEnvironment()),
166 getConfigArgs()
167 );
168 QuadrigeConfiguration.setInstance(config);
169 return config;
170
171 }
172
173 protected void initServiceLocator() {
174
175 ServiceLocator.initQuadrigeDefault();
176 }
177
178 @Override
179 protected void before() throws Throwable {
180
181 config = createConfig();
182 Assume.assumeNotNull(config);
183
184 initServiceLocator();
185
186 initI18n();
187
188 log.info("Init test data in database... [" + config.getJdbcURL() + "]");
189 boolean isFileDatabase = Daos.isHsqlFileDatabase(config.getJdbcURL());
190 boolean needSchemaUpdate = true;
191
192 if (isFileDatabase) {
193
194 File dbDirectory = new File(getTargetDbDirectory());
195 File dbConfigFile = new File(dbDirectory, DatabaseResource.HSQLDB_SRC_DATABASE_PROPERTIES_FILE);
196 File dbScriptFile = new File(dbDirectory, DatabaseResource.HSQLDB_SRC_DATABASE_SCRIPT_FILE);
197
198
199 if (!dbConfigFile.exists() || !dbScriptFile.exists() || replaceDbIfExists) {
200
201 generateNewDb(dbDirectory, replaceDbIfExists);
202
203
204 updateSchema(dbDirectory);
205 needSchemaUpdate = false;
206 }
207
208
209 try {
210 setProperty(dbConfigFile, "readonly", "false");
211 } catch (IOException e) {
212 Assume.assumeNoException(e);
213 }
214 }
215
216 Connection conn = null;
217 try {
218
219 if (needSchemaUpdate) {
220 log.info("Updating database schema...");
221 ServiceLocator.instance().getDatabaseSchemaService().updateSchema();
222 }
223
224 conn = Daos.createConnection(config.getConnectionProperties());
225
226
227 try {
228 String commonDataSetFile = config.getApplicationConfig().getOption(DATASET_COMMON_XML_FILE);
229 Assume.assumeTrue(
230 String.format("Missing value for configuration option [%s].\nPlease set this properties in the test configuration.",
231 DATASET_COMMON_XML_FILE),
232 commonDataSetFile != null);
233
234 URL commonDataSetFileUrl = getClass().getResource("/" + commonDataSetFile);
235 Assume.assumeTrue(
236 String.format("Unable to find resource for configuration option [%s] resource = %s. \nPlease review your properties in the test configuration.",
237 DATASET_COMMON_XML_FILE, commonDataSetFile),
238 commonDataSetFileUrl != null);
239
240
241 beforeInsert(conn);
242
243
244 log.info(String.format("Deleting data, from tables found in file {%s}...", commonDataSetFile));
245 deleteAllFromXmlDataSet(commonDataSetFileUrl, conn);
246
247 afterInsert(conn);
248 beforeInsert(conn);
249
250
251 log.info(String.format("Importing data from file {%s}...", commonDataSetFile));
252 insertFromXmlDataSet(commonDataSetFileUrl, conn);
253
254 conn.commit();
255 } finally {
256 afterInsert(conn);
257 }
258
259
260
261
262
263
264
265
266
267 try {
268
269 String importFileNames = config.getApplicationConfig().getOption(DATASET_ADDITIONAL_XML_FILES);
270 Assume.assumeTrue(
271 String.format("Missing value for configuration option [%s].\nPlease set this properties in the test configuration.",
272 DATASET_ADDITIONAL_XML_FILES),
273 importFileNames != null);
274
275
276 beforeInsert(conn);
277
278
279 StringTokenizer st = new StringTokenizer(importFileNames, ",");
280 while (st.hasMoreTokens()) {
281 String importFileName = st.nextToken();
282
283 log.info(String.format("Importing data from file {%s}...", importFileNames));
284 URL importFileUrl = getClass().getResource("/" + importFileName);
285 Assume.assumeTrue(
286 String.format("Unable to find resource for configuration option [%s] resource = %s. \nPlease review your properties in the test configuration.",
287 DATASET_ADDITIONAL_XML_FILES, importFileName),
288 importFileUrl != null);
289
290
291 insertFromXmlDataSet(importFileUrl, conn);
292 }
293
294
295 conn.commit();
296
297 } finally {
298
299 afterInsert(conn);
300 }
301
302 } finally {
303
304 if (conn != null && !conn.isClosed()) {
305 if (isFileDatabase) {
306
307
308 if (compactDatabase) {
309 Daos.compactDatabase(conn);
310 }
311
312
313 Daos.shutdownDatabase(conn);
314 }
315
316 Daos.closeSilently(conn);
317 }
318
319
320 IOUtils.closeQuietly(ServiceLocator.instance());
321 }
322
323
324 if (isFileDatabase) {
325 File dbDirectory = new File(getTargetDbDirectory());
326 File dbConfigFile = new File(dbDirectory, DatabaseResource.HSQLDB_SRC_DATABASE_PROPERTIES_FILE);
327
328 try {
329 setProperty(dbConfigFile, "readonly", "true");
330 } catch (IOException e) {
331 Assume.assumeNoException(e);
332 }
333 }
334
335 log.info("Test database has been loaded");
336 }
337
338 public static void setProperty(File file, String key, String value) throws IOException {
339
340 Properties props = new Properties();
341 try (BufferedReader reader = Files.newReader(file, Charsets.UTF_8)) {
342 props.load(reader);
343 }
344
345
346 props.setProperty(key, value);
347 try (BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8)) {
348 props.store(writer, "");
349 }
350 }
351
352 public void insertFromXmlDataSet(URL fileURL, Connection conn) throws SQLException, DatabaseUnitException {
353
354 IDatabaseConnection connection = createDbUnitConnection(conn);
355 IDataSet dataSet = new FlatXmlDataSetBuilder()
356 .setColumnSensing(true)
357 .build(fileURL);
358 DatabaseOperation.INSERT.execute(connection, dataSet);
359 }
360
361 public void deleteAllFromXmlDataSet(URL fileURL, Connection conn) throws SQLException, DatabaseUnitException {
362
363 IDatabaseConnection connection = createDbUnitConnection(conn);
364 IDataSet dataSet = new FlatXmlDataSetBuilder()
365 .setColumnSensing(true)
366 .build(fileURL);
367 DatabaseOperation.DELETE_ALL.execute(connection, dataSet);
368 }
369
370
371
372 protected void initI18n() throws IOException {
373 QuadrigeConfiguration config = QuadrigeConfiguration.getInstance();
374
375
376
377
378 File i18nDirectory = new File(config.getDataDirectory(), "i18n");
379 if (i18nDirectory.exists()) {
380
381 FileUtils.cleanDirectory(i18nDirectory);
382 }
383
384 FileUtils.forceMkdir(i18nDirectory);
385
386 if (log.isDebugEnabled()) {
387 log.debug("I18N directory: " + i18nDirectory);
388 }
389
390 Locale i18nLocale = config.getI18nLocale();
391
392 if (log.isDebugEnabled()) {
393 log.debug(String.format("Starts i18n with locale [%s] at [%s]",
394 i18nLocale, i18nDirectory));
395 }
396 I18n.init(new UserI18nInitializer(
397 i18nDirectory, new DefaultI18nInitializer(getI18nBundleName())),
398 i18nLocale);
399 }
400
401 protected String getI18nBundleName() {
402 return getModuleName() + "-i18n";
403 }
404
405 protected void generateNewDb(File outputDirectory, boolean replaceDbIfExists) {
406 QuadrigeConfiguration config = QuadrigeConfiguration.getInstance();
407 DatabaseSchemaDao databaseSchemaDao = new DatabaseSchemaDaoImpl(config);
408
409 try {
410
411 databaseSchemaDao.generateNewDb(outputDirectory, replaceDbIfExists);
412 } catch (QuadrigeTechnicalException e) {
413 log.error(e.getMessage());
414 Assume.assumeNoException(e);
415 }
416 }
417
418 protected void updateSchema(File outputDirectory) {
419 QuadrigeConfiguration config = QuadrigeConfiguration.getInstance();
420 DatabaseSchemaDao databaseSchemaDao = new DatabaseSchemaDaoImpl(config);
421
422 try {
423
424 databaseSchemaDao.updateSchema(outputDirectory);
425 } catch (QuadrigeTechnicalException | DatabaseSchemaUpdateException e) {
426 log.error(e.getMessage());
427 Assume.assumeNoException(e);
428 }
429 }
430
431 protected IDatabaseConnection createDbUnitConnection(Connection jdbcConnection) throws DatabaseUnitException {
432
433 IDatabaseConnection dbUnitConnection;
434
435
436 if (Daos.isHsqlDatabase(config.getJdbcURL())) {
437 dbUnitConnection = new DatabaseConnection(jdbcConnection);
438 dbUnitConnection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new HsqldbDataTypeFactory());
439 }
440
441 else if (Daos.isOracleDatabase(config.getJdbcURL())){
442 dbUnitConnection = new DatabaseConnection(jdbcConnection, config.getJdbcSchema());
443 dbUnitConnection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new WktSupportOracle10DataTypeFactory());
444 dbUnitConnection.getConfig().setProperty(DatabaseConfig.FEATURE_SKIP_ORACLE_RECYCLEBIN_TABLES, Boolean.TRUE);
445 }
446
447 else if (Daos.isPostgresqlDatabase(config.getJdbcURL())){
448 dbUnitConnection = new DatabaseConnection(jdbcConnection, config.getJdbcSchema());
449 dbUnitConnection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new PostgresqlDataTypeFactory());
450 dbUnitConnection.getConfig().setProperty(DatabaseConfig.FEATURE_CASE_SENSITIVE_TABLE_NAMES, Boolean.FALSE);
451 }
452 else {
453 throw new QuadrigeTechnicalException("Unable to create DBUnit connection: Unknown DB type for URL [" + config.getJdbcURL() + "]");
454 }
455
456 return dbUnitConnection;
457 }
458
459 protected void beforeInsert(Connection connection) throws SQLException {
460
461 log.debug("Disabling database constraints...");
462 Daos.setIntegrityConstraints(connection, false);
463
464 }
465
466 protected void afterInsert(Connection connection) throws SQLException {
467
468
469 log.debug("Enabling database constraints...");
470 Daos.setIntegrityConstraints(connection, true);
471 }
472
473 }