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 package org.nuiton.topia.replication;
26
27 import org.apache.commons.logging.Log;
28 import org.junit.Assert;
29 import org.nuiton.i18n.I18n;
30 import org.nuiton.topia.TopiaContext;
31 import org.nuiton.topia.TopiaException;
32 import org.nuiton.topia.framework.TopiaContextImplementor;
33 import org.nuiton.topia.persistence.TopiaDAO;
34 import org.nuiton.topia.persistence.TopiaEntity;
35 import org.nuiton.topia.persistence.TopiaEntityEnum;
36 import org.nuiton.topia.persistence.util.EntityOperator;
37 import org.nuiton.topia.persistence.util.EntityOperatorStore;
38 import org.nuiton.topia.persistence.util.TopiaEntityHelper;
39 import org.nuiton.topia.replication.model.ReplicationModel;
40 import org.nuiton.topia.replication.model.ReplicationNode;
41 import org.nuiton.topia.replication.model.ReplicationOperationDef;
42
43 import java.io.File;
44 import java.util.Arrays;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.Date;
48 import java.util.HashSet;
49 import java.util.Iterator;
50 import java.util.List;
51 import java.util.Locale;
52 import java.util.Set;
53
54
55
56
57
58
59
60
61
62
63 public abstract class AbstractTopiaReplicationServiceTest extends Assert {
64
65 static protected TopiaContext context;
66
67 static protected TopiaContext ctxt;
68
69 protected TopiaContextImplementor dstCtxt;
70
71 protected TopiaReplicationService service;
72
73 protected ReplicationModel model;
74
75 static protected boolean init;
76
77 static private Long testsTimeStamp;
78
79 static private File testsBasedir;
80
81 static private final String TEST_BASEDIR = "target%1$ssurefire-tests%1$s%2$td_%2$tm_%2$tY%1$s%2$tH_%2$tM_%2$tS";
82
83 public static void after() throws Exception {
84 if (context != null && !context.isClosed()) {
85 try {
86 context.closeContext();
87 } catch (TopiaException e) {
88
89
90 }
91 }
92 init = false;
93 }
94
95 public void setUp() throws Exception {
96
97 if (!init) {
98
99 I18n.setDefaultLocale(Locale.FRANCE);
100
101 try {
102 context = createDb("source");
103 } catch (Exception e) {
104 getLog().error("could not create db source.", e);
105 throw e;
106 }
107 init = true;
108 }
109
110 ctxt = context.beginTransaction();
111
112 service = context.getService(TopiaReplicationService.class);
113 }
114
115 public void tearDown() throws Exception {
116 if (ctxt != null) {
117 ctxt.rollbackTransaction();
118 ctxt.closeContext();
119 ctxt = null;
120 }
121 service = null;
122 }
123
124
125 protected TopiaReplicationModelBuilder getModelBuilder() {
126 return service.getModelBuilder();
127 }
128
129 protected abstract TopiaContext createDb2(String name) throws Exception;
130
131 protected abstract TopiaContext createDb(String name) throws Exception;
132
133 protected TopiaContext createReplicateDb(Object contract) throws Exception {
134 TopiaContext rootCtxt = createDb2(contract.toString() + dbCounter++);
135 return rootCtxt;
136 }
137
138 protected abstract TopiaEntityEnum[] getContracts();
139
140 protected abstract Log getLog();
141
142 protected <E extends TopiaEntity> E update(E e) throws TopiaException {
143 return (E) ctxt.findByTopiaId(e.getTopiaId());
144 }
145
146
147
148
149
150
151 public void testDetectTypes() throws Exception {
152 }
153
154
155
156
157
158
159 public void testGetOperation() throws Exception {
160 }
161
162
163
164
165
166
167 public void testDetectAssociations() throws Exception {
168 }
169
170
171
172
173
174
175 public void testDetectDirectDependencies() throws Exception {
176 }
177
178
179
180
181
182
183 public void testDetectShell() throws Exception {
184 }
185
186
187
188
189
190
191 public void testDetectDependencies() throws Exception {
192 }
193
194
195
196
197
198
199 public void testDetectObjectsToDettach() throws Exception {
200 }
201
202
203
204
205
206
207 public void testDetectOperations() throws Exception {
208 }
209
210
211
212
213
214
215 public void testDoReplicate() throws Exception {
216 }
217
218 protected void detectTypes(TopiaEntity entity, Object... expectedCouple) throws TopiaException {
219
220 Set<?> detectTypes;
221
222 detectTypes = service.getModelBuilder().detectTypes(context, getContracts(), entity.getTopiaId());
223 assertEquals("expected types : " +
224 Arrays.toString(expectedCouple) +
225 " but was " + detectTypes,
226 expectedCouple.length, detectTypes.size());
227 for (Object o : expectedCouple) {
228 assertTrue(detectTypes.contains(o));
229 }
230 }
231
232 protected void getOperation(Class<? extends TopiaReplicationOperation> operationClass, boolean shouldExist) throws TopiaException {
233 TopiaReplicationOperation operation = getModelBuilder().getOperationProvider().getOperation(operationClass);
234 assertEquals(shouldExist, operation != null);
235 }
236
237 protected void detectAssociations(TopiaEntity entity,
238 Object... expectedCouple)
239 throws TopiaException {
240
241 createModel(entity);
242 model.detectAssociations();
243
244 assertEquals(0, expectedCouple.length % 2);
245
246 for (int i = 0, j = expectedCouple.length / 2; i < j; i++) {
247 TopiaEntityEnum src = (TopiaEntityEnum) expectedCouple[2 * i];
248 String name = (String) expectedCouple[2 * i + 1];
249 ReplicationNode nodeSrc = model.getNode(src);
250 assertNotNull("association " + name + " not found", nodeSrc);
251 assertTrue(nodeSrc.hasAssociation());
252 assertTrue(nodeSrc.getAssociations().containsKey(name));
253 }
254 }
255
256 protected void detectDirectDependencies(TopiaEntity entity,
257 Object... expectedCouple)
258 throws TopiaException {
259
260 createModel(entity);
261 model.detectDirectDependencies();
262
263 assertEquals(0, expectedCouple.length % 2);
264
265 for (int i = 0, j = expectedCouple.length / 2; i < j; i++) {
266 TopiaEntityEnum src = (TopiaEntityEnum) expectedCouple[2 * i];
267 String name = (String) expectedCouple[2 * i + 1];
268 ReplicationNode nodeSrc = model.getNode(src);
269 assertTrue(nodeSrc + " should have dependency but was not!", nodeSrc.hasDependency());
270 assertTrue(nodeSrc + " should contain dependency " + name + "but was not! (" + nodeSrc.getDependencies() + ")", nodeSrc.getDependencies().containsKey(name));
271 }
272 }
273
274 protected void detectShell(TopiaEntity entity,
275 TopiaEntityEnum... expected) throws
276 TopiaException {
277 Set<ReplicationNode> shell;
278
279 createModel(entity);
280 model.detectAssociations();
281 model.detectDirectDependencies();
282 model.detectShell();
283
284 TopiaEntityEnum c = TopiaEntityHelper.getEntityEnum(
285 entity.getClass(), getContracts());
286 assertNotNull(c);
287 shell = model.getNode(c).getShell();
288 assertEquals(
289 "expected shell : " + Arrays.toString(expected) + ", but was " +
290 shell, expected.length, shell.size());
291
292 for (int i = 0, j = expected.length; i < j; i++) {
293 TopiaEntityEnum type = expected[i];
294 ReplicationNode node = model.getNode(type);
295 assertTrue(shell.contains(node));
296 assertEquals(type, node.getContract());
297 }
298 }
299
300 protected void detectDependencies(
301 TopiaEntity entity,
302 TopiaEntityEnum[]... expected) throws TopiaException {
303
304 createModel(entity);
305 model.detectAssociations();
306 model.detectDirectDependencies();
307 model.detectShell();
308 model.detectDependencies();
309 List<ReplicationNode> dependencies = model.getOrder();
310
311 int i = 0;
312 for (ReplicationNode level : dependencies) {
313 getLog().info("level " + level + " = " + level);
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334 }
335
336 protected void detectObjectsToDettach(TopiaEntity entity, Object... expected) throws TopiaException {
337
338 assertEquals(0, expected.length % 2);
339
340 createModel(entity);
341 model.detectAssociations();
342 model.detectDirectDependencies();
343 model.detectShell();
344 model.detectDependencies();
345 model.detectObjectsToDettach();
346 Set<ReplicationNode> nodes = new HashSet<ReplicationNode>();
347
348 for (int i = 0, j = expected.length / 2; i < j; i++) {
349 TopiaEntityEnum e = (TopiaEntityEnum) expected[2 * i];
350 ReplicationNode node = model.getNode(e);
351 String[] ids = (String[]) expected[2 * i + 1];
352 assertEquals(ids.length > 0, node.hasAssociationsToDettach());
353 for (String id : ids) {
354 assertTrue(node.getAssociationsToDettach().contains(id));
355 }
356 nodes.add(node);
357 }
358
359 for (ReplicationNode node : model.getNodes()) {
360 if (!nodes.contains(node)) {
361
362 assertFalse(node.hasAssociationsToDettach());
363 }
364 }
365
366 }
367
368 protected void detectOperations(TopiaEntity entity, Object... expected) throws TopiaException {
369
370 assertEquals(0, expected.length % 2);
371
372 if (entity == null) {
373 prepareModel();
374 } else {
375 prepareModel(entity.getTopiaId());
376 }
377
378
379
380
381
382
383
384
385 if (getLog().isInfoEnabled()) {
386 getLog().info("==========================================================================");
387 if (entity == null) {
388
389 getLog().info("resume of operations for all ");
390 } else {
391 getLog().info("resume of operations for entity " + entity.getTopiaId());
392 }
393
394 for (ReplicationNode node : model.getOrder()) {
395 ReplicationOperationDef[] operations = node.getOperations();
396 for (ReplicationOperationDef op : operations) {
397 getLog().info("[" + node + "] : operation " + op);
398 }
399 }
400 getLog().info("==========================================================================");
401 }
402 }
403
404 private static int dbCounter;
405
406 protected void doReplicate(TopiaEntityEnum contract,
407 TopiaEntity... entity) throws Exception {
408
409 TopiaContext rootCtxt = createReplicateDb("doReplicate_" + contract);
410
411 List<String> ids = TopiaEntityHelper.getTopiaIdList(Arrays.asList(entity));
412 getLog().info("entity " + ids);
413
414 prepareModel(ids.toArray(new String[ids.size()]));
415
416 dstCtxt = (TopiaContextImplementor) rootCtxt;
417
418 service.doReplicate(model, dstCtxt);
419
420
421
422 if (entity.length == 0) {
423
424 return;
425 }
426 dstCtxt = (TopiaContextImplementor) rootCtxt.beginTransaction();
427
428 for (TopiaEntity e : entity) {
429 TopiaEntity actual = dstCtxt.findByTopiaId(e.getTopiaId());
430 assertNotNull(actual);
431 assertEquals(e, actual);
432 }
433
434 dstCtxt.closeContext();
435
436 dstCtxt = (TopiaContextImplementor) rootCtxt;
437 }
438
439 protected void doReplicateAll() throws Exception {
440
441 TopiaContext rootCtxt = createReplicateDb("doReplicateAll");
442
443 prepareModelAll();
444
445 dstCtxt = (TopiaContextImplementor) rootCtxt;
446
447 service.doReplicate(model, dstCtxt);
448
449 TopiaContextImplementor ctxt2 = (TopiaContextImplementor) ctxt;
450 dstCtxt = (TopiaContextImplementor) rootCtxt.beginTransaction();
451
452 assertDbEquals(model.getContracts(), (TopiaContextImplementor) ctxt, ctxt2);
453
454 dstCtxt.closeContext();
455
456 dstCtxt = (TopiaContextImplementor) rootCtxt;
457 }
458
459 protected void doReplicateWithComputedOrder(TopiaEntity... entity) throws Exception {
460
461 TopiaContext rootCtxt = createReplicateDb("doReplicateWithComputedOrder");
462
463 List<String> ids = TopiaEntityHelper.getTopiaIdList(Arrays.asList(entity));
464
465 prepareModelWithComputedOrder(ids.toArray(new String[ids.size()]));
466
467 dstCtxt = (TopiaContextImplementor) rootCtxt;
468
469 service.doReplicate(model, dstCtxt);
470
471 getLog().info("replication is done for " + Arrays.toString(entity) + ", will verify data...");
472
473 TopiaContextImplementor ctxt2 = (TopiaContextImplementor) ctxt;
474 dstCtxt = (TopiaContextImplementor) rootCtxt.beginTransaction();
475
476 assertDbEquals(model.getContracts(), (TopiaContextImplementor) ctxt, ctxt2);
477
478 dstCtxt.closeContext();
479
480 dstCtxt = (TopiaContextImplementor) rootCtxt;
481 }
482
483 protected void assertDbEquals(TopiaEntityEnum[] contracts,
484 TopiaContextImplementor ctxt,
485 TopiaContextImplementor ctxt2) throws TopiaException {
486 Set<String> ids = new HashSet<String>();
487
488 if (getLog().isInfoEnabled()) {
489 getLog().info("will verify db for contracts " + Arrays.toString(contracts));
490 }
491 for (TopiaEntityEnum c : contracts) {
492 if (getLog().isDebugEnabled()) {
493 getLog().debug("verify for contract " + c);
494 }
495 TopiaDAO<? extends TopiaEntity> daoSrc = ctxt.getDAO(c.getContract());
496 TopiaDAO<? extends TopiaEntity> daoDst = ctxt2.getDAO(c.getContract());
497 long nbSrc = daoSrc.count();
498 long nbDst = daoDst.count();
499 assertEquals("le nombres d'entites de type " + c + " devrait etre " + nbSrc + " mais est " + nbDst, nbSrc, nbDst);
500 List<String> idsSrc = daoSrc.findAllIds();
501 List<String> idsDst = daoDst.findAllIds();
502 Collections.sort(idsSrc);
503 Collections.sort(idsDst);
504 assertEquals(idsSrc, idsDst);
505 for (String id : idsSrc) {
506 if (getLog().isDebugEnabled()) {
507 getLog().debug("verify for entity " + id);
508 }
509 TopiaEntity eSrc = daoSrc.findByTopiaId(id);
510 TopiaEntity eDst = daoDst.findByTopiaId(id);
511 assertEquals(eSrc, eDst);
512 assertEntityEquals(eSrc, eDst, ids);
513 }
514 }
515 }
516
517 protected void assertEntityEquals(TopiaEntity expected,
518 TopiaEntity actual,
519 Set<String> treated) {
520 if (treated == null) {
521 treated = new HashSet<String>();
522 }
523 if (treated.contains(actual.getTopiaId())) {
524 return;
525 }
526 if (getLog().isDebugEnabled()) {
527 getLog().debug(expected);
528 }
529 assertEquals(actual.getTopiaId(), expected.getTopiaId());
530 treated.add(actual.getTopiaId());
531 if (getLog().isDebugEnabled()) {
532 getLog().debug("expected : " + expected + " / actual " + actual);
533 }
534 TopiaEntityEnum contract = TopiaEntityHelper.getEntityEnum(expected.getClass(), getContracts());
535 if (contract == null) {
536
537 getLog().debug("untested property type " + expected.getClass());
538 return;
539 }
540 Assert.assertNotNull(
541 "contract not found for " + expected.getClass() + " in " +
542 Arrays.toString(getContracts()), contract);
543 EntityOperator<TopiaEntity> operator = EntityOperatorStore.getOperator(contract);
544 List<String> associationProperties = operator.getAssociationProperties();
545 for (String name : associationProperties) {
546 if (getLog().isDebugEnabled()) {
547 getLog().debug("association " + name);
548 }
549 if (operator.isChildEmpty(name, expected)) {
550 assertTrue("l'association " + name + " devrait etre vide mais possede " + operator.sizeChild(name, actual) + " entrees", operator.isChildEmpty(name, actual));
551 } else {
552 assertFalse("l'association " + name + " devrait posseder " + operator.isChildEmpty(name, expected) + " mais est vide", operator.isChildEmpty(name, actual));
553
554 }
555 assertEquals(operator.isChildEmpty(name, actual), operator.isChildEmpty(name, expected));
556
557 Class<?> type = operator.getAssociationPropertyType(name);
558 Collection<?> src = (Collection<?>) operator.get(name, expected);
559 Collection<?> dst = (Collection<?>) operator.get(name, actual);
560
561 Iterator<?> itrSrc = src.iterator();
562 Iterator<?> itrDst = dst.iterator();
563 while (itrSrc.hasNext()) {
564 if (TopiaEntity.class.isAssignableFrom(type)) {
565 assertEntityEquals((TopiaEntity) itrSrc.next(), (TopiaEntity) itrDst.next(), treated);
566 } else {
567 assertEquals(itrSrc.next(), itrDst.next());
568 }
569 }
570 }
571
572 for (String name : operator.getProperties()) {
573 if (getLog().isDebugEnabled()) {
574 getLog().debug("dependency " + name);
575 }
576 if (associationProperties.contains(name)) {
577
578 continue;
579 }
580 Class<?> type = operator.getPropertyType(name);
581 Object src = operator.get(name, expected);
582 Object dst = operator.get(name, actual);
583 assertFalse(src == null && dst != null);
584 assertFalse(src != null && dst == null);
585 if (src == null) {
586 continue;
587 }
588 if (TopiaEntity.class.isAssignableFrom(type)) {
589 assertEntityEquals((TopiaEntity) src, (TopiaEntity) dst, treated);
590 } else {
591 assertEquals(src, dst);
592 }
593 }
594 }
595
596 @Deprecated
597 protected void createUnsupportedBeforeOperation(TopiaEntityEnum contract,
598 TopiaEntity entity,
599 Class<? extends TopiaReplicationOperation> operationClass,
600 Object... parameters) throws Exception {
601
602 getLog().info("entity " + entity.getTopiaId());
603 prepareModel(entity.getTopiaId());
604
605 getModelBuilder().addBeforeOperation(model, contract, operationClass, parameters);
606
607 fail();
608 }
609
610 @Deprecated
611 protected void createUnsupportedAfterOperation(
612 TopiaEntityEnum contract,
613 TopiaEntity entity,
614 Class<? extends TopiaReplicationOperation> operationClass,
615 Object... parameters) throws Exception {
616
617 getLog().info("entity " + entity.getTopiaId());
618 prepareModel(entity.getTopiaId());
619
620
621 getModelBuilder().addAfterOperation(model, contract, operationClass, parameters);
622
623 fail();
624 }
625
626 protected void createSupportedBeforeOperation(TopiaEntityEnum contract,
627 TopiaEntity entity,
628 Class<? extends TopiaReplicationOperation> operationClass,
629 Object... parameters) throws Exception {
630
631 getLog().info("entity " + entity.getTopiaId());
632 prepareModel(entity.getTopiaId());
633
634 getModelBuilder().addBeforeOperation(model, contract, operationClass, parameters);
635
636 Assert.assertTrue(true);
637 }
638
639 protected void createSupportedAfterOperation(
640 TopiaEntityEnum contract,
641 TopiaEntity entity,
642 Class<? extends TopiaReplicationOperation> operationClass,
643 Object... parameters) throws Exception {
644
645 getLog().info("entity " + entity.getTopiaId());
646 prepareModel(entity.getTopiaId());
647
648
649 getModelBuilder().addAfterOperation(model, contract, operationClass, parameters);
650
651 Assert.assertTrue(true);
652 }
653
654 protected Long getTestsTimeStamp() {
655 if (testsTimeStamp == null) {
656 testsTimeStamp = System.currentTimeMillis();
657 getLog().info("tests timestamp : " + testsTimeStamp);
658 }
659 return testsTimeStamp;
660 }
661
662 protected File getTestDir(Class<?> testClass) {
663 if (testsBasedir == null) {
664 String tmp = System.getProperty("basedir");
665 if (tmp == null) {
666 tmp = new File("").getAbsolutePath();
667 }
668 String name = String.format(TEST_BASEDIR, File.separator, new Date(getTestsTimeStamp()));
669 testsBasedir = new File(new File(tmp), name);
670 getLog().info("tests basedir : " + testsBasedir);
671 }
672 return new File(testsBasedir, testClass.getSimpleName());
673 }
674
675 protected void createModel(TopiaEntity entity) throws TopiaException {
676 model = getModelBuilder().createModel(context,
677 getContracts(),
678 true,
679 entity.getTopiaId()
680 );
681 }
682
683 protected void prepareModel(String... ids) throws TopiaException {
684 model = service.prepare(getContracts(), true, ids);
685 }
686
687 protected void prepareModelAll() throws TopiaException {
688 model = service.prepareForAll(getContracts());
689 }
690
691 protected void prepareModelWithComputedOrder(String... ids) throws TopiaException {
692 model = service.prepare(getContracts(), false, ids);
693 }
694 }