Skip to content

Commit fe1a9f8

Browse files
committed
Tests cleanup
1 parent 441088f commit fe1a9f8

3 files changed

Lines changed: 249 additions & 92 deletions

File tree

cayenne/src/test/java/org/apache/cayenne/unit/AllTestsSchemaManager.java

Lines changed: 180 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,13 @@
2121

2222
import org.apache.cayenne.access.DataDomain;
2323
import org.apache.cayenne.access.DataNode;
24-
import org.apache.cayenne.access.DbGenerator;
25-
import org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy;
26-
import org.apache.cayenne.access.jdbc.reader.DefaultRowReaderFactory;
27-
import org.apache.cayenne.access.translator.batch.DefaultBatchTranslatorFactory;
28-
import org.apache.cayenne.access.translator.select.DefaultSelectTranslatorFactory;
29-
import org.apache.cayenne.ashwood.AshwoodEntitySorter;
30-
import org.apache.cayenne.cache.MapQueryCache;
31-
import org.apache.cayenne.configuration.DataMapLoader;
3224
import org.apache.cayenne.dba.DbAdapter;
33-
import org.apache.cayenne.event.DefaultEventManager;
34-
import org.apache.cayenne.log.JdbcEventLogger;
3525
import org.apache.cayenne.map.DataMap;
3626
import org.apache.cayenne.map.DbAttribute;
3727
import org.apache.cayenne.map.DbEntity;
28+
import org.apache.cayenne.map.DbRelationship;
3829
import org.apache.cayenne.map.Procedure;
39-
import org.apache.cayenne.resource.URLResource;
30+
import org.apache.cayenne.runtime.CayenneRuntime;
4031
import org.apache.cayenne.unit.dba.TestDbAdapter;
4132
import org.slf4j.Logger;
4233
import org.slf4j.LoggerFactory;
@@ -52,90 +43,49 @@
5243
import java.util.Collection;
5344
import java.util.Collections;
5445
import java.util.Comparator;
46+
import java.util.IdentityHashMap;
5547
import java.util.List;
5648
import java.util.ListIterator;
49+
import java.util.Map;
5750
import java.util.Set;
58-
import java.util.stream.Stream;
5951

6052
public class AllTestsSchemaManager {
6153

6254
private static final Logger LOGGER = LoggerFactory.getLogger(AllTestsSchemaManager.class);
6355

64-
private static final String[] MAPS_FOR_SCHEMA_SETUP = {"testmap.map.xml", "compound.map.xml",
65-
"misc-types.map.xml", "things.map.xml", "numeric-types.map.xml", "binary-pk.map.xml", "no-pk.map.xml",
66-
"lob.map.xml", "date-time.map.xml", "enum.map.xml", "json.map.xml", "extended-type.map.xml",
67-
"generated.map.xml", "mixed-persistence-strategy.map.xml", "people.map.xml", "primitive.map.xml",
68-
"inheritance.map.xml", "locking.map.xml", "soft-delete.map.xml", "empty.map.xml", "relationships.map.xml",
69-
"relationships-activity.map.xml", "relationships-delete-rules.map.xml",
70-
"relationships-collection-to-many.map.xml", "relationships-child-master.map.xml",
71-
"relationships-clob.map.xml", "relationships-flattened.map.xml", "relationships-many-to-many-join.map.xml",
72-
"relationships-set-to-many.map.xml", "relationships-to-many-fk.map.xml", "relationships-to-one-fk.map.xml",
73-
"return-types.map.xml", "uuid.map.xml", "multi-tier.map.xml", "reflexive.map.xml", "delete-rules.map.xml",
74-
"lifecycle-callbacks-order.map.xml", "lifecycles.map.xml", "map-to-many.map.xml", "toone.map.xml",
75-
"meaningful-pk.map.xml", "table-primitives.map.xml", "generic.map.xml", "map-db1.map.xml",
76-
"map-db2.map.xml", "embeddable.map.xml", "qualified.map.xml", "quoted-identifiers.map.xml",
77-
"inheritance-single-table1.map.xml", "inheritance-vertical.map.xml", "oneway-rels.map.xml",
78-
"unsupported-distinct-types.map.xml", "array-type.map.xml", "cay-2032.map.xml",
79-
"weighted-sort.map.xml", "hybrid-data-object.map.xml", "legacy-date-time.map.xml", "inheritance-with-enum.map.xml",
80-
"lazy-attributes.map.xml", "cay2666/datamap.map.xml", "cay2641/datamapLazy.map.xml",
81-
"annotation/datamapAnnotation.map.xml"};
82-
8356
// hardcoded dependent entities that should be excluded if LOBs are not supported
8457
private static final Set<String> EXTRA_EXCLUDED_FOR_NO_LOB = Set.of("CLOB_DETAIL");
8558
private static final Set<String> EXTRA_EXCLUDED_FOR_NO_NATIVE_JSON = Set.of("JSON_OTHER");
8659

8760
private final DataSource dataSource;
8861
private final TestDbAdapter testDbAdapter;
89-
private final JdbcEventLogger jdbcEventLogger;
9062
private final DataDomain domain;
63+
private final List<DataMap> dataMapsInSchemaSetupOrder;
9164

92-
public AllTestsSchemaManager(
93-
DataSource dataSource,
94-
DbAdapter dbAdapter,
95-
JdbcEventLogger jdbcEventLogger,
96-
DataMapLoader loader) {
65+
public AllTestsSchemaManager(DataSource dataSource) {
9766

9867
this.dataSource = dataSource;
99-
this.testDbAdapter = TestDbAdapter.of(dbAdapter);
100-
this.jdbcEventLogger = jdbcEventLogger;
101-
102-
// TODO: just create a normal CayenneRuntime with all the defaults
103-
this.domain = initDomain(loader, dbAdapter);
104-
}
105-
106-
private DataDomain initDomain(DataMapLoader loader, DbAdapter dbAdapter) {
107-
DataDomain domain = new DataDomain("temp");
108-
domain.setEventManager(new DefaultEventManager(2));
109-
domain.setEntitySorter(new AshwoodEntitySorter());
110-
domain.setQueryCache(new MapQueryCache(50));
111-
112-
Stream.of(MAPS_FOR_SCHEMA_SETUP).map(m -> getClass().getClassLoader().getResource(m))
113-
.map(u -> loader.load(new URLResource(u)))
114-
.forEach(m -> domain.addNode(initNode(m, dbAdapter)));
115-
116-
return domain;
117-
}
118-
119-
private DataNode initNode(DataMap map, DbAdapter dbAdapter) {
68+
this.domain = CayenneRuntime.builder()
69+
.addConfig("cayenne-ALL.xml")
70+
.dataSource(dataSource)
71+
.build()
72+
.getDataDomain();
73+
74+
this.testDbAdapter = TestDbAdapter.of(domain.getDefaultNode().getAdapter());
75+
76+
for (DataMap map : domain.getDataMaps()) {
77+
// tweak mapping with a delegate
78+
for (Procedure proc : map.getProcedures()) {
79+
testDbAdapter.tweakProcedure(proc);
80+
}
12081

121-
DataNode node = new DataNode(map.getName());
122-
node.setJdbcEventLogger(jdbcEventLogger);
123-
node.setAdapter(dbAdapter);
124-
node.setDataSource(dataSource);
125-
126-
// tweak mapping with a delegate
127-
for (Procedure proc : map.getProcedures()) {
128-
testDbAdapter.tweakProcedure(proc);
82+
filterDataMap(map);
12983
}
130-
filterDataMap(map);
13184

132-
node.addDataMap(map);
85+
// TODO: suspect
86+
domain.getEntitySorter().setEntityResolver(domain.getEntityResolver());
13387

134-
node.setSchemaUpdateStrategy(new SkipSchemaUpdateStrategy());
135-
node.setRowReaderFactory(new DefaultRowReaderFactory());
136-
node.setBatchTranslatorFactory(new DefaultBatchTranslatorFactory());
137-
node.setSelectTranslatorFactory(new DefaultSelectTranslatorFactory());
138-
return node;
88+
this.dataMapsInSchemaSetupOrder = sortDataMapsInSchemaSetupOrder();
13989
}
14090

14191
/**
@@ -185,23 +135,25 @@ private void filterDataMap(DataMap map) {
185135
* Drops all test tables.
186136
*/
187137
private void dropSchema() throws Exception {
188-
for (DataNode node : domain.getDataNodes()) {
189-
dropSchema(node, node.getDataMaps().iterator().next());
138+
ListIterator<DataMap> it = dataMapsInSchemaSetupOrder.listIterator(dataMapsInSchemaSetupOrder.size());
139+
while (it.hasPrevious()) {
140+
DataMap map = it.previous();
141+
dropSchema(domain.lookupDataNode(map), map);
190142
}
191143
}
192144

193145
/**
194146
* Creates all test tables in the database.
195147
*/
196148
private void createSchema() throws Exception {
197-
for (DataNode node : domain.getDataNodes()) {
198-
createSchema(node, node.getDataMaps().iterator().next());
149+
for (DataMap map : dataMapsInSchemaSetupOrder) {
150+
createSchema(domain.lookupDataNode(map), map);
199151
}
200152
}
201153

202154
public void dropPKSupport() throws Exception {
203-
for (DataNode node : domain.getDataNodes()) {
204-
dropPKSupport(node, node.getDataMaps().iterator().next());
155+
for (DataMap map : dataMapsInSchemaSetupOrder) {
156+
dropPKSupport(domain.lookupDataNode(map), map);
205157
}
206158
}
207159

@@ -211,9 +163,91 @@ public void dropPKSupport() throws Exception {
211163
* objects and data for primary key support.
212164
*/
213165
public void createPKSupport() throws Exception {
214-
for (DataNode node : domain.getDataNodes()) {
215-
createPKSupport(node, node.getDataMaps().iterator().next());
166+
for (DataMap map : dataMapsInSchemaSetupOrder) {
167+
createPKSupport(domain.lookupDataNode(map), map);
168+
}
169+
}
170+
171+
private List<DataMap> sortDataMapsInSchemaSetupOrder() {
172+
List<DataMap> maps = new ArrayList<>(domain.getDataMaps());
173+
Map<DataMap, List<DataMap>> dependencies = new IdentityHashMap<>();
174+
175+
for (DataMap map : maps) {
176+
dependencies.put(map, dataMapDependencies(map, maps));
177+
}
178+
179+
List<DataMap> sorted = new ArrayList<>(maps.size());
180+
Set<DataMap> visited = Collections.newSetFromMap(new IdentityHashMap<>());
181+
Set<DataMap> visiting = Collections.newSetFromMap(new IdentityHashMap<>());
182+
183+
for (DataMap map : maps) {
184+
sortDataMap(map, dependencies, visited, visiting, sorted);
185+
}
186+
187+
return Collections.unmodifiableList(sorted);
188+
}
189+
190+
private List<DataMap> dataMapDependencies(DataMap map, List<DataMap> maps) {
191+
List<DataMap> dependencies = new ArrayList<>();
192+
193+
for (DbEntity entity : map.getDbEntities()) {
194+
for (DbRelationship relationship : entity.getRelationships()) {
195+
DataMap targetMap = dataMapDependency(map, relationship);
196+
if (targetMap != null && maps.contains(targetMap) && !dependencies.contains(targetMap)) {
197+
dependencies.add(targetMap);
198+
}
199+
}
200+
}
201+
202+
return dependencies;
203+
}
204+
205+
private DataMap dataMapDependency(DataMap sourceMap, DbRelationship relationship) {
206+
if (relationship.isRuntime() || relationship.isToMany() || !relationship.isToPK() || relationship.isToDependentPK()) {
207+
return null;
208+
}
209+
210+
boolean hasUnresolvedJoin = relationship.getJoins().stream()
211+
.anyMatch(join -> join.getSource() == null || join.getTarget() == null);
212+
if (hasUnresolvedJoin) {
213+
return null;
214+
}
215+
216+
DbEntity targetEntity = relationship.getTargetEntity();
217+
DataMap targetMap = targetEntity != null ? targetEntity.getDataMap() : null;
218+
if (targetMap == null || targetMap == sourceMap) {
219+
return null;
220+
}
221+
222+
if (domain.lookupDataNode(sourceMap) != domain.lookupDataNode(targetMap)) {
223+
return null;
216224
}
225+
226+
return targetMap;
227+
}
228+
229+
private void sortDataMap(
230+
DataMap map,
231+
Map<DataMap, List<DataMap>> dependencies,
232+
Set<DataMap> visited,
233+
Set<DataMap> visiting,
234+
List<DataMap> sorted) {
235+
236+
if (visited.contains(map)) {
237+
return;
238+
}
239+
240+
if (!visiting.add(map)) {
241+
throw new IllegalStateException("Cycle in DataMap dependencies involving " + map.getName());
242+
}
243+
244+
for (DataMap dependency : dependencies.getOrDefault(map, Collections.emptyList())) {
245+
sortDataMap(dependency, dependencies, visited, visiting, sorted);
246+
}
247+
248+
visiting.remove(map);
249+
visited.add(map);
250+
sorted.add(map);
217251
}
218252

219253
public List<DbEntity> dbEntitiesInInsertOrder(String mapName) {
@@ -229,7 +263,7 @@ private List<DbEntity> sortedDbEntities(String mapName, boolean deleteOrder) {
229263
// intentionally taking "mapName", not a "map", as we need to resolve the corresponding map in our private
230264
// namespace defined by "domain"
231265

232-
DataMap localMap = domain.getDataMap(mapName);
266+
DataMap localMap = dataMap(mapName);
233267
List<DbEntity> entities = new ArrayList<>(localMap.getDbEntities());
234268
entities.removeAll(excludeEntities(entities));
235269

@@ -376,8 +410,6 @@ private Collection<String> tableCreateQueries(DataNode node, DataMap map) {
376410
DbAdapter adapter = node.getAdapter();
377411

378412
List<DbEntity> orderedEntities = dbEntitiesInInsertOrder(map.getName());
379-
List<DbEntity> excludedEntities = excludeEntities(map.getDbEntities());
380-
DbGenerator gen = new DbGenerator(adapter, map, excludedEntities, domain, jdbcEventLogger);
381413
List<String> queries = new ArrayList<>();
382414

383415
// table definitions
@@ -391,10 +423,72 @@ private Collection<String> tableCreateQueries(DataNode node, DataMap map) {
391423
continue;
392424
}
393425

394-
List<String> qs = gen.createConstraintsQueries(ent);
395-
queries.addAll(qs);
426+
queries.addAll(createConstraintsQueries(adapter, ent));
396427
}
397428

398429
return queries;
399430
}
431+
432+
private List<String> createConstraintsQueries(DbAdapter adapter, DbEntity table) {
433+
List<String> queries = new ArrayList<>();
434+
435+
for (DbRelationship rel : table.getRelationships()) {
436+
437+
if (rel.isRuntime()) {
438+
continue;
439+
}
440+
441+
if (rel.isToMany()) {
442+
continue;
443+
}
444+
445+
DataMap srcMap = rel.getSourceEntity().getDataMap();
446+
DataMap targetMap = rel.getTargetEntity().getDataMap();
447+
448+
if (srcMap != null && targetMap != null && srcMap != targetMap) {
449+
continue;
450+
}
451+
452+
if (rel.isToPK() && !rel.isToDependentPK()) {
453+
boolean hasUnresolvedJoin = rel.getJoins().stream()
454+
.anyMatch(join -> join.getSource() == null || join.getTarget() == null);
455+
456+
if (hasUnresolvedJoin) {
457+
continue;
458+
}
459+
460+
if (adapter.supportsUniqueConstraints()) {
461+
DbRelationship reverse = rel.getReverseRelationship();
462+
if (reverse != null && !reverse.isToMany() && !reverse.isToPK()) {
463+
String unique = adapter.createUniqueConstraint(rel.getSourceEntity(), rel.getSourceAttributes());
464+
if (unique != null) {
465+
queries.add(unique);
466+
}
467+
}
468+
}
469+
470+
String fk = adapter.createFkConstraint(rel);
471+
if (fk != null) {
472+
queries.add(fk);
473+
}
474+
}
475+
}
476+
477+
return queries;
478+
}
479+
480+
private DataMap dataMap(String name) {
481+
DataMap dataMap = domain.getDataMap(name);
482+
if (dataMap != null) {
483+
return dataMap;
484+
}
485+
486+
for (DataMap candidate : domain.getDataMaps()) {
487+
if (candidate.getName().endsWith('/' + name)) {
488+
return candidate;
489+
}
490+
}
491+
492+
throw new IllegalArgumentException("Unknown DataMap: " + name);
493+
}
400494
}

cayenne/src/test/java/org/apache/cayenne/unit/CayenneTestsEnv.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
2828
import org.apache.cayenne.access.translator.select.SelectTranslatorFactory;
2929
import org.apache.cayenne.configuration.Constants;
30-
import org.apache.cayenne.configuration.DataMapLoader;
3130
import org.apache.cayenne.configuration.DataNodeDescriptor;
3231
import org.apache.cayenne.configuration.DataSourceDescriptor;
3332
import org.apache.cayenne.configuration.runtime.CoreModule;
@@ -78,11 +77,7 @@ public class CayenneTestsEnv implements BeforeEachCallback, AfterEachCallback {
7877
INJECTOR.getInstance(DataSourceDescriptor.class),
7978
INJECTOR.getInstance(AdhocObjectFactory.class));
8079

81-
SCHEMAS = new AllTestsSchemaManager(
82-
DATA_SOURCES.sharedDataSource(),
83-
INJECTOR.getInstance(DbAdapter.class),
84-
INJECTOR.getInstance(JdbcEventLogger.class),
85-
INJECTOR.getInstance(DataMapLoader.class));
80+
SCHEMAS = new AllTestsSchemaManager(DATA_SOURCES.sharedDataSource());
8681

8782
SCHEMAS.rebuildSchema();
8883
}

0 commit comments

Comments
 (0)