View Javadoc
1   package fr.ifremer.quadrige2.core.test;
2   
3   /*-
4    * #%L
5    * Quadrige2 Core :: Quadrige2 Test Shared
6    * %%
7    * Copyright (C) 2017 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Affero General Public License as published by
11   * the Free Software Foundation, either version 3 of the License, or
12   * (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU Affero General Public License
20   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21   * #L%
22   */
23  
24  import com.google.common.base.Charsets;
25  import com.google.common.io.Files;
26  import fr.ifremer.quadrige2.core.config.Quadrige2Configuration;
27  import fr.ifremer.quadrige2.core.config.Quadrige2ConfigurationOption;
28  import fr.ifremer.quadrige2.core.dao.technical.Daos;
29  import fr.ifremer.quadrige2.core.dao.technical.DatabaseSchemaDao;
30  import fr.ifremer.quadrige2.core.dao.technical.hibernate.DatabaseSchemaDaoImpl;
31  import fr.ifremer.quadrige2.core.exception.DatabaseSchemaUpdateException;
32  import fr.ifremer.quadrige2.core.exception.Quadrige2TechnicalException;
33  import fr.ifremer.quadrige2.core.service.ServiceLocator;
34  import org.apache.commons.io.FileUtils;
35  import org.apache.commons.io.IOUtils;
36  import org.apache.commons.logging.Log;
37  import org.apache.commons.logging.LogFactory;
38  import org.dbunit.DatabaseUnitException;
39  import org.dbunit.database.DatabaseConnection;
40  import org.dbunit.database.IDatabaseConnection;
41  import org.dbunit.dataset.IDataSet;
42  import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
43  import org.dbunit.ext.hsqldb.HsqldbDataTypeFactory;
44  import org.dbunit.operation.DatabaseOperation;
45  import org.junit.Assume;
46  import org.junit.rules.ExternalResource;
47  import org.nuiton.i18n.I18n;
48  import org.nuiton.i18n.init.DefaultI18nInitializer;
49  import org.nuiton.i18n.init.UserI18nInitializer;
50  
51  import java.io.BufferedReader;
52  import java.io.BufferedWriter;
53  import java.io.File;
54  import java.io.IOException;
55  import java.net.URL;
56  import java.sql.Connection;
57  import java.sql.SQLException;
58  import java.util.Locale;
59  import java.util.Properties;
60  import java.util.StringTokenizer;
61  
62  /**
63   * @author peck7 on 13/10/2017.
64   */
65  public abstract class InitTests extends ExternalResource {
66  
67      private static final String DATASET_COMMON_XML_FILE = "quadrige2.core.test.dataset.common";
68      private static final String DATASET_CLIENT_XML_FILE = "quadrige2.core.test.dataset.client";
69  
70      private static final Log log = LogFactory.getLog(InitTests.class);
71  
72      protected Quadrige2Configuration config;
73  
74      protected abstract String getHsqlDbSourceDatabaseDirectory();
75  
76      protected abstract String getModuleName();
77  
78      protected void initConfig() {
79  
80          config = new Quadrige2Configuration(getModuleName() + "-test-write.properties",
81                  "--option", Quadrige2ConfigurationOption.DB_DIRECTORY.getKey(), getHsqlDbSourceDatabaseDirectory(),
82                  "--option", Quadrige2ConfigurationOption.DB_ENUMERATION_RESOURCE.getKey(), "classpath*:quadrige2-db-enumerations.properties"
83          );
84          Quadrige2Configuration.setInstance(config);
85  
86      }
87  
88      protected void initServiceLocator() {
89  
90          ServiceLocator.initQuadrige2Default();
91      }
92  
93      @Override
94      protected void before() throws Throwable {
95  
96          File dbDirectory = new File(getHsqlDbSourceDatabaseDirectory());
97          File dbConfigFile = new File(dbDirectory, DatabaseResource.HSQLDB_SRC_DATABASE_PROPERTIES_FILE);
98          File dbScriptFile = new File(dbDirectory, DatabaseResource.HSQLDB_SRC_DATABASE_SCRIPT_FILE);
99  
100         initConfig();
101 
102         initServiceLocator();
103 
104         initI18n();
105 
106         boolean isFileDatabase = Daos.isFileDatabase(config.getJdbcURL());
107 
108         if (isFileDatabase) {
109             log.info("Init test data in database... [" + config.getJdbcURL() + "]");
110 
111             // db not exists: create it
112             if (!dbConfigFile.exists() || !dbScriptFile.exists()) {
113                 createDb(dbConfigFile.getParentFile());
114             }
115 
116             // Set database to readonly=false
117             try {
118                 setProperty(dbConfigFile, "readonly", "false");
119             } catch (IOException e) {
120                 Assume.assumeNoException(e);
121             }
122         }
123 
124         // Reload test data into DB
125         Connection conn = Daos.createConnection(config.getConnectionProperties());
126 
127         // Disable integrity constraints
128         Daos.setIntegrityConstraints(conn, false);
129 
130         // Remove some lines that dbUnit can't handle
131         Daos.sqlUpdate(conn, "DELETE FROM SURVEY_QUSER");
132         Daos.sqlUpdate(conn, "DELETE FROM RULE_PRECONDITION");
133         conn.commit();
134 
135         // Import Common dataset
136         {
137             String importFileName = config.getApplicationConfig().getOption(DATASET_COMMON_XML_FILE);
138             Assume.assumeTrue(
139                     String.format("Missing value for configuration option [%s].\nPlease set this properties in the test configuration.",
140                             DATASET_COMMON_XML_FILE),
141                     importFileName != null);
142 
143             log.info("Importing test data... [" + importFileName + "]");
144             URL importFileUrl = getClass().getResource("/" + importFileName);
145             Assume.assumeTrue(
146                     String.format("Unable to find resource for configuration option [%s] resource = %s. \nPlease review your properties in the test configuration.",
147                             DATASET_COMMON_XML_FILE, importFileName),
148                     importFileUrl != null);
149 
150             // Clean & Insert
151             fullDatabaseImport(importFileUrl, conn, true);
152         }
153 
154         // Import client dataset
155         {
156             String importFileNames = config.getApplicationConfig().getOption(DATASET_CLIENT_XML_FILE);
157             Assume.assumeTrue(
158                     String.format("Missing value for configuration option [%s].\nPlease set this properties in the test configuration.",
159                             DATASET_CLIENT_XML_FILE),
160                     importFileNames != null);
161 
162             log.info("Importing test data... [" + importFileNames + "]");
163 
164             // If multiple files, split and loop over
165             StringTokenizer st = new StringTokenizer(importFileNames, ",");
166             while (st.hasMoreTokens()) {
167                 String importFileName = st.nextToken();
168 
169                 URL importFileUrl = getClass().getResource("/" + importFileName);
170                 Assume.assumeTrue(
171                         String.format("Unable to find resource for configuration option [%s] resource = %s. \nPlease review your properties in the test configuration.",
172                                 DATASET_CLIENT_XML_FILE, importFileName),
173                         importFileUrl != null);
174 
175                 // Insert (no Clean)
176                 fullDatabaseImport(importFileUrl, conn, false);
177             }
178         }
179 
180         // Enable integrity constraints
181         Daos.setIntegrityConstraints(conn, true);
182 
183         // DEV ONLY: on server DB, cleaning all previous database change log
184         // if (!isFileDatabase) {
185         // Daos.sqlUpdate(conn, "DELETE FROM DATABASECHANGELOG");
186         // Daos.sqlUpdate(conn, "DELETE FROM DATABASECHANGELOGLOCK");
187         // conn.commit();
188         // }
189 
190         // Update DB schema
191         log.info("Updating database schema...");
192         ServiceLocator.instance().getDatabaseSchemaService().updateSchema();
193 
194         // Shutdown database
195         if (isFileDatabase) {
196             Daos.shutdownDatabase(conn);
197         }
198 
199         // Shutdown spring context
200         IOUtils.closeQuietly(ServiceLocator.instance());
201 
202         if (isFileDatabase) {
203             // Set database to readonly=true
204             try {
205                 setProperty(dbConfigFile, "readonly", "true");
206             } catch (IOException e) {
207                 Assume.assumeNoException(e);
208             }
209         }
210 
211         log.info("Test database has been loaded");
212     }
213 
214     public static void setProperty(File file, String key, String value) throws IOException {
215         // Load old properties values
216         Properties props = new Properties();
217         try (BufferedReader reader = Files.newReader(file, Charsets.UTF_8)) {
218             props.load(reader);
219         }
220 
221         // Store new properties values
222         props.setProperty(key, value);
223         try (BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8)) {
224             props.store(writer, "");
225         }
226     }
227 
228     public static void fullDatabaseImport(URL fileURL, Connection jdbcConnection, boolean cleanBeforeInsert)
229             throws ClassNotFoundException, IOException, SQLException, DatabaseUnitException {
230 
231         IDatabaseConnection connection = new DatabaseConnection(jdbcConnection);
232         connection.getConfig().setProperty("http://www.dbunit.org/properties/datatypeFactory", new HsqldbDataTypeFactory());
233         IDataSet dataSet = new FlatXmlDataSetBuilder().setColumnSensing(true).build(fileURL);
234         if (cleanBeforeInsert) {
235             DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
236         } else {
237             DatabaseOperation.INSERT.execute(connection, dataSet);
238         }
239     }
240 
241 	/* -- internal methods -- */
242 
243     protected void initI18n() throws IOException {
244         Quadrige2Configuration config = Quadrige2Configuration.getInstance();
245 
246         // --------------------------------------------------------------------//
247         // init i18n
248         // --------------------------------------------------------------------//
249         File i18nDirectory = new File(config.getDataDirectory(), "i18n");
250         if (i18nDirectory.exists()) {
251             // clean i18n cache
252             FileUtils.cleanDirectory(i18nDirectory);
253         }
254 
255         FileUtils.forceMkdir(i18nDirectory);
256 
257         if (log.isDebugEnabled()) {
258             log.debug("I18N directory: " + i18nDirectory);
259         }
260 
261         Locale i18nLocale = config.getI18nLocale();
262 
263         if (log.isDebugEnabled()) {
264             log.debug(String.format("Starts i18n with locale [%s] at [%s]",
265                     i18nLocale, i18nDirectory));
266         }
267         I18n.init(new UserI18nInitializer(
268                         i18nDirectory, new DefaultI18nInitializer(getI18nBundleName())),
269                 i18nLocale);
270     }
271 
272     protected String getI18nBundleName() {
273         return getModuleName() + "-i18n";
274     }
275 
276     protected void createDb(File outputDirectory) {
277         Quadrige2Configuration config = Quadrige2Configuration.getInstance();
278         DatabaseSchemaDao databaseSchemaDao = new DatabaseSchemaDaoImpl(config);
279 
280         try {
281             // Create the database
282             databaseSchemaDao.generateNewDb(outputDirectory, false);
283 
284             // Update the DB schema
285             databaseSchemaDao.updateSchema(outputDirectory);
286         } catch (Quadrige2TechnicalException | DatabaseSchemaUpdateException e1) {
287             log.error(e1.getMessage());
288         }
289     }
290 }