1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.configuration2;
18
19 import java.io.File;
20 import java.nio.file.Files;
21 import java.sql.Connection;
22
23 import javax.sql.DataSource;
24
25 import org.apache.commons.configuration2.builder.BasicConfigurationBuilder;
26 import org.apache.commons.configuration2.builder.fluent.DatabaseBuilderParameters;
27 import org.apache.commons.configuration2.builder.fluent.Parameters;
28 import org.apache.commons.configuration2.ex.ConfigurationException;
29 import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
30 import org.apache.commons.configuration2.test.HsqlDB;
31 import org.apache.commons.dbcp2.BasicDataSource;
32 import org.dbunit.database.DatabaseConnection;
33 import org.dbunit.database.IDatabaseConnection;
34 import org.dbunit.dataset.IDataSet;
35 import org.dbunit.dataset.xml.XmlDataSet;
36 import org.dbunit.operation.DatabaseOperation;
37
38 /**
39 * A helper class for performing tests for {@link DatabaseConfiguration}. This class maintains an in-process database
40 * that stores configuration data and can be accessed from a {@link DatabaseConfiguration} instance. Constants for table
41 * and column names and database connection settings are provided, too.
42 */
43 public class DatabaseConfigurationTestHelper {
44
45 /** Constant for the configuration table. */
46 public static final String TABLE = "configuration";
47
48 /** Constant for the multi configuration table. */
49 public static final String TABLE_MULTI = "configurations";
50
51 /** Constant for the column with the keys. */
52 public static final String COL_KEY = "key";
53
54 /** Constant for the column with the values. */
55 public static final String COL_VALUE = "value";
56
57 /** Constant for the column with the configuration name. */
58 public static final String COL_NAME = "name";
59
60 /** Constant for the name of the test configuration. */
61 public static final String CONFIG_NAME = "test";
62
63 /** Constant for the JDBC driver class. */
64 public static final String DATABASE_DRIVER = "org.hsqldb.jdbcDriver";
65
66 /** Constant for the connection URL. */
67 public static final String DATABASE_URL = "jdbc:hsqldb:mem:testdb";
68
69 /** Constant for the DB user name. */
70 public static final String DATABASE_USERNAME = "sa";
71
72 /** Constant for the DB password. */
73 public static final String DATABASE_PASSWORD = "";
74
75 /** Stores the in-process database. */
76 private HsqlDB hsqlDB;
77
78 /** The data source. */
79 private DataSource dataSource;
80
81 /**
82 * The auto-commit mode for the configuration instances created by this helper.
83 */
84 private boolean autoCommit;
85
86 /**
87 * Creates a configuration instance of the specified class with the given parameters.
88 *
89 * @param <T> the type of the result configuration
90 * @param configCls the configuration class
91 * @param params the parameters object
92 * @return the newly created configuration instance
93 * @throws ConfigurationException if an error occurs
94 */
95 public <T extends DatabaseConfiguration> T createConfiguration(final Class<T> configCls, final DatabaseBuilderParameters params)
96 throws ConfigurationException {
97 return new BasicConfigurationBuilder<>(configCls).configure(params).getConfiguration();
98 }
99
100 /**
101 * Returns the {@code DataSource} managed by this class. The data source is created on first access.
102 *
103 * @return the {@code DataSource}
104 */
105 public DataSource getDataSource() {
106 if (dataSource == null) {
107 try {
108 dataSource = setUpDataSource();
109 } catch (final Exception ex) {
110 throw new ConfigurationRuntimeException("Could not create data source", ex);
111 }
112 }
113 return dataSource;
114 }
115
116 /**
117 * Returns the auto-commit mode of the configuration instances created by this helper.
118 *
119 * @return the auto-commit mode
120 */
121 public boolean isAutoCommit() {
122 return autoCommit;
123 }
124
125 /**
126 * Sets the auto-commit mode of the configuration instances created by this helper.
127 *
128 * @param autoCommit the auto-commit mode
129 */
130 public void setAutoCommit(final boolean autoCommit) {
131 this.autoCommit = autoCommit;
132 }
133
134 /**
135 * Initializes this helper object. This method can be called from a {@code setUp()} method of a unit test class. It
136 * creates the database instance if necessary.
137 *
138 * @throws Exception if an error occurs
139 */
140 public void setUp() throws Exception {
141 final File script = ConfigurationAssert.getTestFile("testdb.script");
142 hsqlDB = new HsqlDB(DATABASE_URL, DATABASE_DRIVER, script.getAbsolutePath());
143 }
144
145 /**
146 * Creates a database configuration with default settings.
147 *
148 * @return the configuration
149 * @throws ConfigurationException if an error occurs
150 */
151 public DatabaseConfiguration setUpConfig() throws ConfigurationException {
152 return setUpConfig(DatabaseConfiguration.class);
153 }
154
155 /**
156 * Creates a database configuration with default settings of the specified class.
157 *
158 * @param <T> the type of the result configuration
159 * @param configCls the configuration class
160 * @return the newly created configuration instance
161 * @throws ConfigurationException if an error occurs
162 */
163 public <T extends DatabaseConfiguration> T setUpConfig(final Class<T> configCls) throws ConfigurationException {
164 return createConfiguration(configCls, setUpDefaultParameters());
165 }
166
167 /**
168 * Creates the internal data source. This method also initializes the database.
169 *
170 * @return the data source
171 * @throws Exception if an error occurs
172 */
173 private DataSource setUpDataSource() throws Exception {
174 final BasicDataSource ds = new BasicDataSource();
175 ds.setDriverClassName(DATABASE_DRIVER);
176 ds.setUrl(DATABASE_URL);
177 ds.setUsername(DATABASE_USERNAME);
178 ds.setPassword(DATABASE_PASSWORD);
179 ds.setDefaultAutoCommit(!isAutoCommit());
180
181 // prepare the database
182 final Connection conn = ds.getConnection();
183 final IDatabaseConnection connection = new DatabaseConnection(conn);
184 final IDataSet dataSet = new XmlDataSet(Files.newInputStream(ConfigurationAssert.getTestPath("dataset.xml")));
185
186 try {
187 DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
188 } finally {
189 if (!isAutoCommit()) {
190 conn.commit();
191 }
192 connection.close();
193 }
194
195 return ds;
196 }
197
198 /**
199 * Returns a parameters object with default settings.
200 *
201 * @return the parameters object
202 */
203 public DatabaseBuilderParameters setUpDefaultParameters() {
204 return new Parameters().database().setDataSource(getDataSource()).setTable(TABLE).setKeyColumn(COL_KEY).setValueColumn(COL_VALUE)
205 .setAutoCommit(isAutoCommit());
206 }
207
208 /**
209 * Creates a database configuration that supports multiple configurations in a table with default values.
210 *
211 * @return the configuration
212 * @throws ConfigurationException if an error occurs
213 */
214 public DatabaseConfiguration setUpMultiConfig() throws ConfigurationException {
215 return setUpMultiConfig(DatabaseConfiguration.class, null);
216 }
217
218 /**
219 * Creates a configuration with support for multiple configuration instances in a single table of the specified class.
220 *
221 * @param <T> the type of the result configuration
222 * @param configCls the configuration class
223 * @param configName the name of the configuration instance or <strong>null</strong> for the default name
224 * @return the newly created configuration instance
225 * @throws ConfigurationException if an error occurs
226 */
227 public <T extends DatabaseConfiguration> T setUpMultiConfig(final Class<T> configCls, final String configName) throws ConfigurationException {
228 return createConfiguration(configCls, setUpMultiParameters(configName));
229 }
230
231 /**
232 * Returns a parameters object with settings for a configuration table containing the data of multiple configurations.
233 *
234 * @param configName the name of the configuration instance or <strong>null</strong> for the default name
235 * @return the parameters object
236 */
237 public DatabaseBuilderParameters setUpMultiParameters(final String configName) {
238 return setUpDefaultParameters().setTable(TABLE_MULTI).setConfigurationNameColumn(COL_NAME)
239 .setConfigurationName(configName != null ? configName : CONFIG_NAME);
240 }
241
242 /**
243 * Frees the resources used by this helper class. This method can be called by a {@code tearDown()} method of a unit
244 * test class.
245 *
246 * @throws Exception if an error occurs
247 */
248 public void tearDown() throws Exception {
249 if (dataSource != null) {
250 dataSource.getConnection().close();
251 }
252 hsqlDB.close();
253 }
254 }