JpaTestUtils.java
10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
package net.ziemers.swxercise.db.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IMetadataHandler;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.datatype.IDataTypeFactory;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.dbunit.ext.mysql.MySqlDataTypeFactory;
import org.dbunit.ext.mysql.MySqlMetadataHandler;
import org.dbunit.operation.DatabaseOperation;
import org.hibernate.internal.SessionImpl;
import org.jglue.cdiunit.ProducesAlternative;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Stellt nützliche Funktionalität für JUnit-Tests zur Verfügung.
*
* Copyright (c) 2017 Dipl.-Inform. Thomas Ziemer
*
* This file is part of swXercise.
*
* swXercise is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* swXercise is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with swXercise.
* If not, see <http://www.gnu.org/licenses/>.
*/
public class JpaTestUtils {
private static final Logger logger = LoggerFactory.getLogger(JpaTestUtils.class.getName());
private static final String PERSISTENCE_UNIT_TEST = "swXerciseTestPU";
private static final String NET_ZIEMERS_SWXERCISE_PKG = "net/ziemers/swxercise/testdata/";
private static EntityManagerFactory emf = null;
private static EntityManager em = null;
private EntityTransaction tx;
/**
* Produziert eine EntityManagerFactory und einen EntityManager und speichert sie als static (Singleton),
* damit sie nicht immer neu erstellt werden für jeden Test.
*
* @return EntityManager der erzeugt wurde
*/
@Produces
@ProducesAlternative
public EntityManager getEm() {
if (emf == null) {
synchronized (EntityManagerFactory.class) {
if (emf == null) {
emf = createEntityManagerFactory();
}
}
}
if (emf != null && em == null) {
synchronized (EntityManager.class) {
if (emf != null && em == null) {
em = emf.createEntityManager();
}
}
}
return em;
}
@SuppressWarnings("unused")
protected void clearEm() {
em = null;
}
/**
* Private Methode, die eine EntityManagerFactory erzeugen kann. Verwendet eine im Home-Verzeichnis des
* aktuellen Benutzers abgelegte Datei persistence.properties, um die Defaults aus der persistence.xml
* zu überschreiben.
*
* @return neu erstellte {@link EntityManagerFactory}
*/
private static EntityManagerFactory createEntityManagerFactory() {
String homePath = System.getProperty("user.home");
String swxercisePersistenceXmlPath = homePath + File.separator + ".swXercise" + File.separator + "persistence.properties";
File swxercisePersistenceXmlFile = new File(swxercisePersistenceXmlPath);
EntityManagerFactory emf = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(swxercisePersistenceXmlFile);
Properties overrideProperties = new Properties();
overrideProperties.load(fis);
emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_TEST, overrideProperties);
} catch (Exception e) {
// logger.info("Persistence properties will not be overriden because of following error:", e);
logger.info("Persistence properties will not be overriden");
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
if (emf == null) {
emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_TEST);
}
return emf;
}
protected void txBegin() {
tx = getEm().getTransaction();
tx.begin();
}
protected void txCommit() {
tx.commit();
}
@SuppressWarnings("unused")
protected void txRollback() {
tx.rollback();
}
/**
* Hilfsmethode, um ein als XML vorliegendes Dataset zu laden.
*
* @param resourceName Dateiname, welches als Ressource gesucht wird
* @return das geladene Dataset
* @throws Exception wenn beim Behandeln der Dateien eine Exception aufgetreten ist
*/
private static IDataSet readDataset(String resourceName) throws Exception {
IDataSet dataSet = null;
InputStream dtdStream = null;
InputStream resourceAsStream = null;
try {
FlatXmlDataSetBuilder flatXmlDataSetBuilder = new FlatXmlDataSetBuilder();
dtdStream = JpaTestUtils.class.getClassLoader().getResourceAsStream(NET_ZIEMERS_SWXERCISE_PKG + "empty/entity_versioning.dtd");
// flatXmlDataSetBuilder.setMetaDataSetFromDtd(dtdStream);
flatXmlDataSetBuilder.setColumnSensing(true);
resourceAsStream = JpaTestUtils.class.getClassLoader().getResourceAsStream(NET_ZIEMERS_SWXERCISE_PKG + resourceName);
dataSet = flatXmlDataSetBuilder.build(resourceAsStream);
} catch (Exception e) {
logger.warn("Exception while reading test data definitions file named \"{}\". If your tests fail, check existence of file!", resourceName);
// throw e;
} finally {
if (dtdStream != null) {
dtdStream.close();
}
if (resourceAsStream != null) {
resourceAsStream.close();
}
}
return dataSet;
}
/**
* Initialisiert die Datenbank aus einer XML-Beschreibung heraus.
*
* @param resourceName der Name der XML-Datei
* @throws Exception wenn dabei etwas schiefläuft
*/
protected void initDbWith(String resourceName) throws Exception {
final IDataSet dataset = readDataset(resourceName);
if (dataset != null) {
try {
SessionImpl delegate = (SessionImpl) this.getEm().getDelegate();
DatabaseConnection connection = new DatabaseConnection(delegate.connection());
IMetadataHandler mysqlHandler = new MySqlMetadataHandler();
IDataTypeFactory mySqlDataTypeFactory = new MySqlDataTypeFactory();
connection.getConfig().setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, mysqlHandler);
connection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, mySqlDataTypeFactory);
DatabaseOperation.INSERT.execute(connection, dataset);
} catch (DatabaseUnitException qe) {
logger.warn("Database entries already inserted. If your tests fail, check your sql inserts for constraint violations!");
logger.warn(qe.getMessage());
logger.warn(qe.getMessage(), qe);
throw qe;
}
}
}
/**
* Räumt die Datenbank mit DBUnit auf, um für jeden Test eine leere, saubere Datenbank zu haben.
*
* @throws Exception Wirft eventuelle SQL- und I/O-Exceptions
*/
protected void cleanDb() throws Exception {
String schema = getCurrentSchema();
List<String> tables = getTableNamesToBeEmptied();
getEm().getTransaction().begin();
getEm().createNativeQuery("SET foreign_key_checks=0;").executeUpdate();
for (String table : tables) {
getEm().createNativeQuery(getTruncateStatement(schema, table)).executeUpdate();
}
getEm().createNativeQuery("SET foreign_key_checks=1;").executeUpdate();
getEm().getTransaction().commit();
getEm().clear();
}
private String getCurrentSchema() {
String query = "SELECT DATABASE()";
List<Object> result = executeReadQuery(query);
if (result.isEmpty()) {
return null;
}
Object object = result.get(0);
if (object instanceof String) {
return (String) object;
}
return null;
}
private List<String> getTableNamesToBeEmptied() throws Exception {
return showTablesNotEmpty(getCurrentSchema());
}
private List<String> showTablesNotEmpty(String schema) throws Exception {
StringBuilder query = new StringBuilder();
query.append("SELECT table_name ");
query.append("FROM information_schema.tables ");
// query.append("WHERE table_rows > 0 ");
// query.append(String.format("AND table_schema = '%s'", schema));
query.append(String.format("WHERE table_schema = '%s'", schema));
getSkippingTables().stream().forEach(table -> query.append(String.format("AND table_name != '%s'", table)));
List<Object> result = executeReadQuery(query.toString());
return result.stream().filter(o -> o instanceof String).map(o -> (String) o).collect(Collectors.toList());
}
/**
* Verschiedene Tabellen sollen ignoriert werden.
*
* @return eine Liste der zu ignorierenden Tabellen
*/
private List<String> getSkippingTables() {
return Arrays.asList(
"hibernate_sequence",
"schema_version"); // FlywayDB Metatable
}
private List<Object> executeReadQuery(String queryString) {
getEm().getTransaction().begin();
Query query = getEm().createNativeQuery(queryString);
@SuppressWarnings("unchecked")
List<Object> result = query.getResultList();
getEm().getTransaction().rollback();
return result;
}
private String getTruncateStatement(String schema, String table) {
return String.format("DELETE FROM %s.%s;", schema, table);
}
}