From 26961b33cc8f1831720598380aef7e11d119a67f Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sun, 7 Aug 2016 11:49:36 +0200 Subject: [PATCH] [Major] Implemented opt-in versioning - adding versioning tests - fixing broken tests - implemented missing PostgreSQL DAO methods --- .../strolch/agent/impl/CachedElementMap.java | 6 +- .../strolch/persistence/api/StrolchDao.java | 12 + .../persistence/inmemory/InMemoryDao.java | 80 ++--- .../inmemory/InMemoryActivityQueryTest.java | 303 ++++++++++++++++++ .../inmemory/InMemoryOrderQueryTest.java | 20 +- .../inmemory/InMemoryResourceQueryTest.java | 8 +- .../src/main/java/li/strolch/model/Order.java | 2 + .../main/java/li/strolch/model/Resource.java | 3 +- .../main/java/li/strolch/model/Version.java | 3 +- .../li/strolch/model/activity/Activity.java | 4 + .../persistence/postgresql/PostgresqlDao.java | 239 +++++++++++--- .../dao/test/CachedVersioningDaoTest.java | 89 +++++ .../postgresql/dao/test/RealmTest.java | 2 +- .../test/TransactionalVersioningDaoTest.java | 62 ++++ .../config/PrivilegeConfig.xml | 32 ++ .../config/PrivilegeRoles.xml | 16 + .../config/PrivilegeUsers.xml | 18 ++ .../config/StrolchConfiguration.xml | 45 +++ .../config/PrivilegeConfig.xml | 32 ++ .../config/PrivilegeRoles.xml | 16 + .../config/PrivilegeUsers.xml | 18 ++ .../config/StrolchConfiguration.xml | 44 +++ .../testbase/runtime/AbstractModelTest.java | 12 - .../runtime/ActivityModelTestRunner.java | 12 +- .../runtime/OrderModelTestRunner.java | 16 +- .../runtime/ResourceModelTestRunner.java | 15 +- .../runtime/VersioningTestRunner.java | 3 + 27 files changed, 974 insertions(+), 138 deletions(-) create mode 100644 li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryActivityQueryTest.java create mode 100644 li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedVersioningDaoTest.java create mode 100644 li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalVersioningDaoTest.java create mode 100644 li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeConfig.xml create mode 100644 li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeRoles.xml create mode 100644 li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeUsers.xml create mode 100644 li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/StrolchConfiguration.xml create mode 100644 li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeConfig.xml create mode 100644 li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeRoles.xml create mode 100644 li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeUsers.xml create mode 100644 li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/StrolchConfiguration.xml diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedElementMap.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedElementMap.java index 8efdebe53..7ebeb376e 100644 --- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedElementMap.java +++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedElementMap.java @@ -278,7 +278,7 @@ public abstract class CachedElementMap implements if (this.realm.isVersioningEnabled()) { // first perform cached change - getCachedDao().update(element); + getCachedDao().remove(element); // last is to perform DB changes getDbDao(tx).update(element); @@ -303,7 +303,7 @@ public abstract class CachedElementMap implements if (this.realm.isVersioningEnabled()) { // first perform cached change - getCachedDao().updateAll(elements); + getCachedDao().removeAll(elements); // last is to perform DB changes getDbDao(tx).updateAll(elements); @@ -397,7 +397,7 @@ public abstract class CachedElementMap implements getCachedDao().remove(element); getDbDao(tx).remove(element); } else { - T previous = getBy(tx, type, id, elementVersion.getPreviousVersion(), false); + T previous = getBy(tx, type, id, elementVersion.getPreviousVersion(), true); getCachedDao().update(previous); getDbDao(tx).removeVersion(current); } diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchDao.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchDao.java index 2eed44c27..c39e60e9e 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchDao.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchDao.java @@ -130,6 +130,18 @@ public interface StrolchDao { */ public List queryVersionsFor(String type, String id); + /** + * Queries and returns the number of versions for the element with the given type and ID + * + * @param type + * the type of the element to be queried + * @param id + * the id of the element to be queried + * + * @return the number of versions for the element with the given type and ID + */ + public long queryVersionsSizeFor(String type, String id); + /** * Queries and returns all elements regardless of type * diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryDao.java b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryDao.java index 9ad89ce78..b2e1b2619 100644 --- a/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryDao.java +++ b/li.strolch.agent/src/main/java/li/strolch/persistence/inmemory/InMemoryDao.java @@ -23,6 +23,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; import li.strolch.model.StrolchRootElement; import li.strolch.persistence.api.StrolchDao; @@ -53,12 +55,11 @@ public class InMemoryDao implements StrolchDao @Override public synchronized long querySize() { - long size = 0; - for (String type : this.elementMap.keySet()) { - Map> byType = this.elementMap.get(type); - size += byType.size(); - } - return size; + return this.elementMap.entrySet().stream().map(e -> { + return e.getValue().entrySet().stream().filter(f -> { + return !f.getValue().getLast().getVersion().isDeleted(); + }).count(); + }).mapToInt(e -> e.intValue()).sum(); } @Override @@ -66,19 +67,19 @@ public class InMemoryDao implements StrolchDao Map> byType = this.elementMap.get(type); if (byType == null) return 0; - return byType.size(); + return byType.entrySet().stream().filter(e -> !e.getValue().getLast().getVersion().isDeleted()).count(); } @Override public synchronized Set queryKeySet() { - Set keySet = new HashSet<>(); - for (String type : this.elementMap.keySet()) { - Map> byType = this.elementMap.get(type); - for (String id : byType.keySet()) { - keySet.add(id); - } - } - return keySet; + return this.elementMap.entrySet().stream() // + .map(e -> { + return e.getValue().entrySet().stream() // + .filter(f -> !f.getValue().getLast().getVersion().isDeleted()) // + .map(f -> f.getKey()); + }) // + .flatMap(Function.identity()) // + .collect(Collectors.toSet()); } @Override @@ -86,7 +87,11 @@ public class InMemoryDao implements StrolchDao Map> byType = this.elementMap.get(type); if (byType == null) return new HashSet<>(0); - return new HashSet<>(byType.keySet()); + + return byType.entrySet().stream() // + .filter(e -> !e.getValue().getLast().getVersion().isDeleted()) // + .map(e -> e.getKey()) // + .collect(Collectors.toSet()); } @Override @@ -139,19 +144,26 @@ public class InMemoryDao implements StrolchDao } @Override - public synchronized List queryAll() { - List elements = new ArrayList<>(); - for (String type : this.elementMap.keySet()) { - Map> byType = this.elementMap.get(type); - for (String id : byType.keySet()) { - ArrayDeque list = byType.get(id); - T last = list.getLast(); - if (last.getVersion() == null || !last.getVersion().isDeleted()) - elements.add(last); - } - } + public long queryVersionsSizeFor(String type, String id) { + Map> byType = this.elementMap.get(type); + if (byType == null) + return 0L; + ArrayDeque list = byType.get(id); + if (list == null) + return 0L; + return list.size(); + } - return elements; + @Override + public synchronized List queryAll() { + return this.elementMap.entrySet().stream() // + .map(e -> { + return e.getValue().entrySet().stream() // + .filter(f -> !f.getValue().getLast().getVersion().isDeleted()) // + .map(f -> f.getValue().getLast()); + }) // + .flatMap(Function.identity()) // + .collect(Collectors.toList()); } @Override @@ -160,14 +172,10 @@ public class InMemoryDao implements StrolchDao if (byType == null) return new ArrayList<>(0); - List elements = new ArrayList<>(); - for (ArrayDeque list : byType.values()) { - T last = list.getLast(); - if (last.getVersion() == null || !last.getVersion().isDeleted()) - elements.add(last); - } - - return elements; + return byType.entrySet().stream() // + .filter(e -> !e.getValue().getLast().getVersion().isDeleted()) // + .map(e -> e.getValue().getLast()) // + .collect(Collectors.toList()); } @Override diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryActivityQueryTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryActivityQueryTest.java new file mode 100644 index 000000000..f3c0d1664 --- /dev/null +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryActivityQueryTest.java @@ -0,0 +1,303 @@ +package li.strolch.runtime.query.inmemory; + +import static li.strolch.model.query.ParameterSelection.booleanSelection; +import static li.strolch.model.query.ParameterSelection.floatListSelection; +import static li.strolch.model.query.ParameterSelection.floatSelection; +import static li.strolch.model.query.ParameterSelection.integerListSelection; +import static li.strolch.model.query.ParameterSelection.longListSelection; +import static li.strolch.model.query.ParameterSelection.stringListSelection; +import static li.strolch.model.query.ParameterSelection.stringSelection; +import static li.strolch.utils.StringMatchMode.ci; +import static li.strolch.utils.StringMatchMode.es; +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +import li.strolch.model.ModelGenerator; +import li.strolch.model.ParameterBag; +import li.strolch.model.Version; +import li.strolch.model.activity.Activity; +import li.strolch.model.parameter.BooleanParameter; +import li.strolch.model.parameter.FloatListParameter; +import li.strolch.model.parameter.FloatParameter; +import li.strolch.model.parameter.IntegerListParameter; +import li.strolch.model.parameter.LongListParameter; +import li.strolch.model.parameter.StringListParameter; +import li.strolch.model.parameter.StringParameter; +import li.strolch.model.query.ActivityQuery; +import li.strolch.model.query.IdSelection; +import li.strolch.model.query.NameSelection; +import li.strolch.model.query.ParameterSelection; +import li.strolch.persistence.inmemory.InMemoryActivityDao; + +public class InMemoryActivityQueryTest { + + protected InMemoryActivityDao daoInstance() { + return new InMemoryActivityDao(false); + } + + @Test + public void shouldQueryById() { + + List activitys = getActivities(); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery activityQuery = ActivityQuery.query("MyType1"); + activityQuery.with(new IdSelection("@1")); + + List result = dao.doQuery(activityQuery); + assertEquals(1, result.size()); + assertEquals("@1", result.get(0).getId()); + } + + @Test + public void shouldQueryByIdOr() { + + List activitys = getActivities(); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery activityQuery = ActivityQuery.query("MyType2"); + activityQuery.or().with(new IdSelection("@3"), new IdSelection("@4")); + + List result = dao.doQuery(activityQuery); + assertEquals(2, result.size()); + assertEquals("@3", result.get(0).getId()); + assertEquals("@4", result.get(1).getId()); + } + + @Test + public void shouldQueryByIdAnd() { + + List activitys = getActivities(); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery activityQuery = ActivityQuery.query("MyType2"); + activityQuery.and().with(new IdSelection("@3"), new NameSelection("Activity 3", es())); + + List result = dao.doQuery(activityQuery); + assertEquals(1, result.size()); + assertEquals("@3", result.get(0).getId()); + } + + @Test + public void shouldNotQueryByIdAnd() { + + List activitys = getActivities(); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery activityQuery = ActivityQuery.query("MyType1"); + activityQuery.and().with(new IdSelection("@3"), new NameSelection("@4", es())); + + List result = dao.doQuery(activityQuery); + assertEquals(0, result.size()); + } + + @Test + public void shouldQueryByParameter() { + + List activitys = getActivities(); + activitys.add(getBallActivity()); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with( + // + stringSelection("parameters", "color", "red", es()), + booleanSelection("parameters", "forChildren", true), floatSelection("parameters", "diameter", 22.0)); + + List result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + } + + @Test + public void shouldQueryByListParameter() { + + List activitys = getActivities(); + activitys.add(getBallActivity()); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery ballQuery; + List result; + + // string list + { + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(stringListSelection("parameters", "stringListValues", Arrays.asList("a", "z"))); + result = dao.doQuery(ballQuery); + assertEquals(0, result.size()); + + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(stringListSelection("parameters", "stringListValues", Arrays.asList("a"))); + result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(stringListSelection("parameters", "stringListValues", Arrays.asList("c", "b", "a"))); + result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + } + + // integer list + { + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(integerListSelection("parameters", "intListValues", Arrays.asList(1, 5))); + result = dao.doQuery(ballQuery); + assertEquals(0, result.size()); + + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(integerListSelection("parameters", "intListValues", Arrays.asList(1))); + result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(integerListSelection("parameters", "intListValues", Arrays.asList(3, 2, 1))); + result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + } + + // float list + { + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(floatListSelection("parameters", "floatListValues", Arrays.asList(4.0, 8.0))); + result = dao.doQuery(ballQuery); + assertEquals(0, result.size()); + + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(floatListSelection("parameters", "floatListValues", Arrays.asList(4.0))); + result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(floatListSelection("parameters", "floatListValues", Arrays.asList(6.2, 5.1, 4.0))); + result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + } + + // long list + { + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(longListSelection("parameters", "longListValues", Arrays.asList(8L, 11L))); + result = dao.doQuery(ballQuery); + assertEquals(0, result.size()); + + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(longListSelection("parameters", "longListValues", Arrays.asList(8L))); + result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + + ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with(longListSelection("parameters", "longListValues", Arrays.asList(10L, 9L, 8L))); + result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + } + } + + @Test + public void shouldQueryByNullParameter1() { + List activitys = getActivities(); + activitys.add(getBallActivity()); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with( // + ParameterSelection.nullSelection("parameters", "color")); + + List result = dao.doQuery(ballQuery); + assertEquals(0, result.size()); + } + + @Test + public void shouldQueryByNullParameter2() { + List activitys = getActivities(); + activitys.add(getBallActivity()); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with( // + ParameterSelection.nullSelection("parameters", "weight")); + + List result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + } + + @Test + public void shouldQueryByNullParameter3() { + List activitys = getActivities(); + activitys.add(getBallActivity()); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery ballQuery = ActivityQuery.query("Ball"); + ballQuery.and().with( // + ParameterSelection.nullSelection("parameters", "weight")); + + List result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + } + + @Test + public void shouldQueryByName() { + + List activitys = getActivities(); + activitys.add(getBallActivity()); + InMemoryActivityDao dao = daoInstance(); + dao.saveAll(activitys); + + ActivityQuery ballQuery = ActivityQuery.query("Ball"); + ballQuery.with(new NameSelection("ball ", ci())); + + List result = dao.doQuery(ballQuery); + assertEquals(1, result.size()); + } + + private Activity getBallActivity() { + Activity res1 = new Activity("childrensBall", "Ball 1", "Ball"); + Version.setInitialVersionFor(res1, "test"); + ParameterBag bag = new ParameterBag("parameters", "Ball Details", "Parameters"); + bag.addParameter(new StringParameter("color", "Color", "red")); + bag.addParameter(new BooleanParameter("forChildren", "Color", true)); + bag.addParameter(new FloatParameter("diameter", "Color", 22.0)); + bag.addParameter( + new StringListParameter("stringListValues", "List of String Values", Arrays.asList("a", "b", "c"))); + bag.addParameter(new IntegerListParameter("intListValues", "List of Integer Values", Arrays.asList(1, 2, 3))); + bag.addParameter( + new FloatListParameter("floatListValues", "List of Float Values", Arrays.asList(4.0, 5.1, 6.2))); + bag.addParameter(new LongListParameter("longListValues", "List of Long Values", Arrays.asList(8L, 9L, 10L))); + res1.addParameterBag(bag); + return res1; + } + + private List getActivities() { + Activity res1 = ModelGenerator.createActivity("@1", "Activity 1", "MyType1"); + Activity res2 = ModelGenerator.createActivity("@2", "Activity 2", "MyType1"); + Activity res3 = ModelGenerator.createActivity("@3", "Activity 3", "MyType2"); + Activity res4 = ModelGenerator.createActivity("@4", "Activity 4", "MyType2"); + Activity res5 = ModelGenerator.createActivity("@5", "Activity 5", "MyType3"); + Activity res6 = ModelGenerator.createActivity("@6", "Activity 6", "MyType3"); + List activitys = new ArrayList<>(); + activitys.add(res1); + activitys.add(res2); + activitys.add(res3); + activitys.add(res4); + activitys.add(res5); + activitys.add(res6); + + for (Activity activity : activitys) { + Version.setInitialVersionFor(activity, "test"); + } + + return activitys; + } +} diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryOrderQueryTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryOrderQueryTest.java index ba0bda78e..410b2a9be 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryOrderQueryTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryOrderQueryTest.java @@ -100,7 +100,7 @@ public class InMemoryOrderQueryTest { dao.saveAll(orders); OrderQuery orderQuery = OrderQuery.query("MyType2"); - orderQuery.and().with(new IdSelection("@3"), new NameSelection("Res 3", es())); + orderQuery.and().with(new IdSelection("@3"), new NameSelection("Order 3", es())); List result = dao.doQuery(orderQuery); assertEquals(1, result.size()); @@ -285,7 +285,7 @@ public class InMemoryOrderQueryTest { private Order getBallOrder() { Order o1 = new Order("childrensBall", "Ball 1", "Ball"); - o1.setVersion(new Version(o1.getLocator(), 0, "ModelGenerator", false)); + Version.setInitialVersionFor(o1, "test"); ParameterBag bag = new ParameterBag("parameters", "Ball Details", "Parameters"); bag.addParameter(new StringParameter("color", "Color", "red")); bag.addParameter(new BooleanParameter("forChildren", "Color", true)); @@ -301,12 +301,12 @@ public class InMemoryOrderQueryTest { } private List getOrders() { - Order res1 = ModelGenerator.createOrder("@1", "Res 1", "MyType1", new Date(), State.CREATED); - Order res2 = ModelGenerator.createOrder("@2", "Res 2", "MyType1", new Date(), State.CREATED); - Order res3 = ModelGenerator.createOrder("@3", "Res 3", "MyType2", new Date(), State.CREATED); - Order res4 = ModelGenerator.createOrder("@4", "Res 4", "MyType2", new Date(), State.CREATED); - Order res5 = ModelGenerator.createOrder("@5", "Res 5", "MyType3", new Date(), State.CREATED); - Order res6 = ModelGenerator.createOrder("@6", "Res 6", "MyType3", new Date(), State.CREATED); + Order res1 = ModelGenerator.createOrder("@1", "Order 1", "MyType1", new Date(), State.CREATED); + Order res2 = ModelGenerator.createOrder("@2", "Order 2", "MyType1", new Date(), State.CREATED); + Order res3 = ModelGenerator.createOrder("@3", "Order 3", "MyType2", new Date(), State.CREATED); + Order res4 = ModelGenerator.createOrder("@4", "Order 4", "MyType2", new Date(), State.CREATED); + Order res5 = ModelGenerator.createOrder("@5", "Order 5", "MyType3", new Date(), State.CREATED); + Order res6 = ModelGenerator.createOrder("@6", "Order 6", "MyType3", new Date(), State.CREATED); List orders = new ArrayList<>(); orders.add(res1); orders.add(res2); @@ -314,6 +314,10 @@ public class InMemoryOrderQueryTest { orders.add(res4); orders.add(res5); orders.add(res6); + + for (Order order : orders) { + Version.setInitialVersionFor(order, "test"); + } return orders; } } diff --git a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryResourceQueryTest.java b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryResourceQueryTest.java index c38c08b4a..ba151e5fd 100644 --- a/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryResourceQueryTest.java +++ b/li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/InMemoryResourceQueryTest.java @@ -264,7 +264,7 @@ public class InMemoryResourceQueryTest { private Resource getBallResource() { Resource res1 = new Resource("childrensBall", "Ball 1", "Ball"); - res1.setVersion(new Version(res1.getLocator(), 0, "ModelGenerator", false)); + Version.setInitialVersionFor(res1, "test"); ParameterBag bag = new ParameterBag("parameters", "Ball Details", "Parameters"); bag.addParameter(new StringParameter("color", "Color", "red")); bag.addParameter(new BooleanParameter("forChildren", "Color", true)); @@ -293,11 +293,11 @@ public class InMemoryResourceQueryTest { resources.add(res4); resources.add(res5); resources.add(res6); - + for (Resource resource : resources) { - resource.setVersion(new Version(resource.getLocator(), 0, "Test", false)); + Version.setInitialVersionFor(resource, "test"); } - + return resources; } } diff --git a/li.strolch.model/src/main/java/li/strolch/model/Order.java b/li.strolch.model/src/main/java/li/strolch/model/Order.java index 6dec3280b..9018b010c 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/Order.java +++ b/li.strolch.model/src/main/java/li/strolch/model/Order.java @@ -192,6 +192,8 @@ public class Order extends GroupedParameterizedElement implements StrolchRootEle builder.append(this.state); builder.append(", date="); builder.append(ISO8601FormatFactory.getInstance().formatDate(this.date)); + builder.append(", version="); + builder.append(this.version); builder.append("]"); return builder.toString(); diff --git a/li.strolch.model/src/main/java/li/strolch/model/Resource.java b/li.strolch.model/src/main/java/li/strolch/model/Resource.java index 56557c846..a5ef93a36 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/Resource.java +++ b/li.strolch.model/src/main/java/li/strolch/model/Resource.java @@ -203,7 +203,8 @@ public class Resource extends GroupedParameterizedElement implements StrolchRoot builder.append(this.name); builder.append(", type="); builder.append(this.type); - builder.append("]"); + builder.append(", version="); + builder.append(this.version); return builder.toString(); } diff --git a/li.strolch.model/src/main/java/li/strolch/model/Version.java b/li.strolch.model/src/main/java/li/strolch/model/Version.java index e139ce93a..25364bb61 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/Version.java +++ b/li.strolch.model/src/main/java/li/strolch/model/Version.java @@ -4,6 +4,7 @@ import java.text.MessageFormat; import java.util.Date; import li.strolch.utils.dbc.DBC; +import li.strolch.utils.iso8601.ISO8601FormatFactory; /** *

@@ -159,7 +160,7 @@ public class Version { builder.append(", createdBy="); builder.append(this.createdBy); builder.append(", createdAt="); - builder.append(this.createdAt); + builder.append(ISO8601FormatFactory.getInstance().formatDate(this.createdAt)); builder.append(", deleted="); builder.append(this.deleted); builder.append("]"); diff --git a/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java b/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java index 6e3bb29fc..7ce0f9316 100644 --- a/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java +++ b/li.strolch.model/src/main/java/li/strolch/model/activity/Activity.java @@ -296,6 +296,10 @@ public class Activity extends GroupedParameterizedElement builder.append(this.getStart()); builder.append(", end="); builder.append(this.getEnd()); + if (isRootElement()) { + builder.append(", version="); + builder.append(this.version); + } builder.append("]"); return builder.toString(); } diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java index 5fe5a646f..d444aba78 100644 --- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java +++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java @@ -53,10 +53,11 @@ public abstract class PostgresqlDao implements Str @Override public boolean hasElement(String type, String id) { - String sql = "select count(*) from " + getTableName() + " where type = ? and id = ?"; + String sql = "select count(*) from " + getTableName() + " where type = ? and id = ? and latest = true"; try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { statement.setString(1, type); statement.setString(2, id); + try (ResultSet result = statement.executeQuery()) { result.next(); long numberOfElements = result.getLong(1); @@ -68,6 +69,7 @@ public abstract class PostgresqlDao implements Str String msg = MessageFormat.format("Non unique number of elements with type {0} and id {1}", type, id); throw new StrolchPersistenceException(msg); } + } catch (SQLException e) { throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); } @@ -75,12 +77,14 @@ public abstract class PostgresqlDao implements Str @Override public long querySize() { - String sql = "select count(*) from " + getTableName(); + String sql = "select count(*) from " + getTableName() + " where latest = true"; try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { + try (ResultSet result = statement.executeQuery()) { result.next(); return result.getLong(1); } + } catch (SQLException e) { throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); } @@ -88,13 +92,15 @@ public abstract class PostgresqlDao implements Str @Override public long querySize(String type) { - String sql = "select count(*) from " + getTableName() + " where type = ?"; + String sql = "select count(*) from " + getTableName() + " where type = ? and latest = true"; try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { statement.setString(1, type); + try (ResultSet result = statement.executeQuery()) { result.next(); return result.getLong(1); } + } catch (SQLException e) { throw new StrolchPersistenceException("Failed to query size due to: " + e.getMessage(), e); } @@ -105,13 +111,15 @@ public abstract class PostgresqlDao implements Str Set keySet = new HashSet<>(); - String sql = "select id from " + getTableName(); + String sql = "select id from " + getTableName() + " where latest = true"; try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { + try (ResultSet result = statement.executeQuery()) { while (result.next()) { keySet.add(result.getString("id")); } } + } catch (SQLException e) { throw new StrolchPersistenceException("Failed to query key set due to: " + e.getMessage(), e); } @@ -123,14 +131,16 @@ public abstract class PostgresqlDao implements Str public Set queryKeySet(String type) { Set keySet = new HashSet<>(); - String sql = "select id from " + getTableName() + " where type = ?"; + String sql = "select id from " + getTableName() + " where type = ? and latest = true"; try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { statement.setString(1, type); + try (ResultSet result = statement.executeQuery()) { while (result.next()) { keySet.add(result.getString("id")); } } + } catch (SQLException e) { throw new StrolchPersistenceException("Failed to query key set due to: " + e.getMessage(), e); } @@ -142,13 +152,15 @@ public abstract class PostgresqlDao implements Str public Set queryTypes() { Set keySet = new HashSet<>(); - String sql = "select distinct type from " + getTableName(); + String sql = "select distinct type from " + getTableName() + " where latest = true"; try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { + try (ResultSet result = statement.executeQuery()) { while (result.next()) { keySet.add(result.getString("type")); } } + } catch (SQLException e) { throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); } @@ -159,10 +171,12 @@ public abstract class PostgresqlDao implements Str @Override public T queryBy(String type, String id) { - String sql = "select id, name, type, asxml from " + getTableName() + " where id = ? and type = ?"; + String sql = "select id, name, type, asxml from " + getTableName() + + " where type = ? and id = ? and latest = true"; try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { - statement.setString(1, id); - statement.setString(2, type); + statement.setString(1, type); + statement.setString(2, id); + try (ResultSet result = statement.executeQuery()) { if (!result.next()) { return null; @@ -174,6 +188,7 @@ public abstract class PostgresqlDao implements Str throw new StrolchPersistenceException("Non unique result for query: " + sql); return t; } + } catch (SQLException e) { throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); } @@ -181,22 +196,88 @@ public abstract class PostgresqlDao implements Str @Override public T queryBy(String type, String id, int version) { - // TODO Auto-generated method stub - return null; + + String sql = "select id, name, type, asxml from " + getTableName() + + " where type = ? and id = ? and version = ?"; + try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { + statement.setString(1, type); + statement.setString(2, id); + statement.setInt(3, version); + + try (ResultSet result = statement.executeQuery()) { + if (!result.next()) { + return null; + } + + SQLXML sqlxml = result.getSQLXML("asxml"); + T t = parseFromXml(id, type, sqlxml); + if (result.next()) + throw new StrolchPersistenceException("Non unique result for query: " + sql); + return t; + } + + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } } @Override public List queryVersionsFor(String type, String id) { - // TODO Auto-generated method stub - return null; + + String sql = "select id, name, type, asxml from " + getTableName() + + " where type = ? and id = ? order by version"; + + List list = new ArrayList<>(1); + + try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { + statement.setString(1, type); + statement.setString(2, id); + + try (ResultSet result = statement.executeQuery()) { + + while (result.next()) { + SQLXML sqlxml = result.getSQLXML("asxml"); + T t = parseFromXml(id, type, sqlxml); + if (result.next()) + throw new StrolchPersistenceException("Non unique result for query: " + sql); + list.add(t); + } + + return list; + } + + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } + } + + @Override + public long queryVersionsSizeFor(String type, String id) { + + String sql = "select count(*) from " + getTableName() + " where type = ? and id = ?"; + + try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { + statement.setString(1, type); + statement.setString(2, id); + + try (ResultSet result = statement.executeQuery()) { + result.next(); + return result.getLong(1); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); + } } @Override public List queryAll() { List list = new ArrayList<>(); - String sql = "select id, name, type, asxml from " + getTableName(); + + String sql = "select id, name, type, asxml from " + getTableName() + " where latest = true"; try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { + try (ResultSet result = statement.executeQuery()) { while (result.next()) { String id = result.getString("id"); @@ -205,21 +286,24 @@ public abstract class PostgresqlDao implements Str T t = parseFromXml(id, type, sqlxml); list.add(t); } + + return list; } + } catch (SQLException e) { throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); } - - return list; } @Override public List queryAll(String type) { List list = new ArrayList<>(); - String sql = "select id, name, type, asxml from " + getTableName() + " where type = ?"; + + String sql = "select id, name, type, asxml from " + getTableName() + " where type = ? and latest = true"; try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { statement.setString(1, type); + try (ResultSet result = statement.executeQuery()) { while (result.next()) { String id = result.getString("id"); @@ -227,16 +311,17 @@ public abstract class PostgresqlDao implements Str T t = parseFromXml(id, type, sqlxml); list.add(t); } + + return list; } + } catch (SQLException e) { throw new StrolchPersistenceException("Failed to query types due to: " + e.getMessage(), e); } - - return list; } @Override - public void save(final T res) { + public void save(T res) { this.commands.add(txResult -> { internalSave(res); txResult.incCreated(1); @@ -244,7 +329,7 @@ public abstract class PostgresqlDao implements Str } @Override - public void saveAll(final List elements) { + public void saveAll(List elements) { this.commands.add(txResult -> { for (T element : elements) { internalSave(element); @@ -254,7 +339,7 @@ public abstract class PostgresqlDao implements Str } @Override - public void update(final T element) { + public void update(T element) { this.commands.add(txResult -> { internalUpdate(element); txResult.incUpdated(1); @@ -262,7 +347,7 @@ public abstract class PostgresqlDao implements Str } @Override - public void updateAll(final List elements) { + public void updateAll(List elements) { this.commands.add(txResult -> { for (T element : elements) { internalUpdate(element); @@ -272,7 +357,7 @@ public abstract class PostgresqlDao implements Str } @Override - public void remove(final T element) { + public void remove(T element) { this.commands.add(txResult -> { internalRemove(element); txResult.incDeleted(1); @@ -280,7 +365,7 @@ public abstract class PostgresqlDao implements Str } @Override - public void removeAll(final List elements) { + public void removeAll(List elements) { this.commands.add(txResult -> { for (T element : elements) { internalRemove(element); @@ -295,7 +380,7 @@ public abstract class PostgresqlDao implements Str final long toRemove = querySize(); this.commands.add(txResult -> { - internalRemoveAll(toRemove); + internalRemoveAll(); txResult.incDeleted(toRemove); }); @@ -303,12 +388,12 @@ public abstract class PostgresqlDao implements Str } @Override - public long removeAllBy(final String type) { + public long removeAllBy(String type) { - final long toRemove = querySize(type); + long toRemove = querySize(type); this.commands.add(txResult -> { - internalRemoveAllBy(toRemove, type); + internalRemoveAllBy(type); txResult.incDeleted(toRemove); }); @@ -317,8 +402,10 @@ public abstract class PostgresqlDao implements Str @Override public void removeVersion(T element) throws StrolchPersistenceException { - // TODO Auto-generated method stub - + this.commands.add(txResult -> { + internalRemoveVersion(element); + txResult.incDeleted(1); + }); } /** @@ -331,50 +418,102 @@ public abstract class PostgresqlDao implements Str */ protected abstract void internalUpdate(T element); - protected void internalRemove(final T element) { - String sql = "delete from " + getTableName() + " where id = ?"; - try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) { + protected void internalRemove(T element) { + // first find out how many there are + long count = 0; + String sql = "select count(*) from " + getTableName() + " where type = ? and id = ?"; + try (PreparedStatement statement = tx().getConnection().prepareStatement(sql)) { + statement.setString(1, element.getType()); + statement.setString(2, element.getId()); + + try (ResultSet result = statement.executeQuery()) { + result.next(); + count = result.getLong(1); + } + + } catch (SQLException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to remove {0} due to {1}", + element.getLocator(), e.getLocalizedMessage()), e); + } + + if (count == 0) { + throw new StrolchPersistenceException( + MessageFormat.format("Failed to remove {0} as it does not exiset!", element.getLocator())); + } + + sql = "delete from " + getTableName() + " where id = ?"; + try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) { preparedStatement.setString(1, element.getId()); + int modCount = preparedStatement.executeUpdate(); - if (modCount != 1) { - String msg = "Expected to delete 1 element with id {0} but SQL statement modified {1} elements!"; - msg = MessageFormat.format(msg, element.getId(), modCount); + if (modCount != count) { + String msg = "Expected to delete {0} element with id {1} but SQL statement deleted {2} elements!"; + msg = MessageFormat.format(msg, count, element.getId(), modCount); throw new StrolchPersistenceException(msg); } } catch (SQLException e) { - throw new StrolchPersistenceException(MessageFormat.format("Failed to remove {0} due to {2}", + throw new StrolchPersistenceException(MessageFormat.format("Failed to remove {0} due to {1}", element.getLocator(), e.getLocalizedMessage()), e); } } - protected void internalRemoveAll(final long toRemove) { - String sql = "delete from " + getTableName(); + private void internalRemoveVersion(T element) { + String sql = "delete from " + getTableName() + " where type = ? and id = ? and version = ? and latest = true"; try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) { + preparedStatement.setString(1, element.getType()); + preparedStatement.setString(2, element.getId()); + preparedStatement.setInt(3, element.getVersion().getVersion()); + int modCount = preparedStatement.executeUpdate(); - if (modCount != toRemove) { - String msg = "Expected to delete {0} elements but SQL statement removed {1} elements!"; - msg = MessageFormat.format(msg, toRemove, modCount); + if (modCount != 1) { + String msg = "Expected to delete 1 element with id {0} but SQL statement modified {1} elements! Verify that element {2} is the latest version!"; + msg = MessageFormat.format(msg, element.getId(), modCount, element.getVersion()); throw new StrolchPersistenceException(msg); } + // + sql = "update " + getTableName() + " set latest = true where type = ? and id = ? and version = ?"; + try (PreparedStatement updateStmt = tx().getConnection().prepareStatement(sql)) { + int previousVersion = element.getVersion().getPreviousVersion(); + updateStmt.setString(1, element.getType()); + updateStmt.setString(2, element.getId()); + updateStmt.setInt(3, previousVersion); + + modCount = updateStmt.executeUpdate(); + if (modCount != 1) { + String msg = "Expected to update 1 element with id {0} but SQL statement modified {1} elements! Verify that element {2} with version {3} exists!"; + msg = MessageFormat.format(msg, element.getId(), modCount, element.getLocator(), previousVersion); + throw new StrolchPersistenceException(msg); + } + + } + + } catch (SQLException e) { + throw new StrolchPersistenceException(MessageFormat.format("Failed to remove version {0} due to {1}", + element.getLocator(), e.getLocalizedMessage()), e); + } + } + + protected void internalRemoveAll() { + String sql = "delete from " + getTableName(); + try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) { + + preparedStatement.executeUpdate(); + } catch (SQLException e) { throw new StrolchPersistenceException( MessageFormat.format("Failed to remove all elements due to {0}", e.getLocalizedMessage()), e); } } - protected void internalRemoveAllBy(final long toRemove, String type) { + protected void internalRemoveAllBy(String type) { String sql = "delete from " + getTableName() + " where type = ?"; try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) { preparedStatement.setString(1, type); - int modCount = preparedStatement.executeUpdate(); - if (modCount != toRemove) { - String msg = "Expected to delete {0} elements of type {1} but SQL statement removed {2} elements!"; - msg = MessageFormat.format(msg, toRemove, type, modCount); - throw new StrolchPersistenceException(msg); - } + + preparedStatement.executeUpdate(); } catch (SQLException e) { throw new StrolchPersistenceException(MessageFormat diff --git a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedVersioningDaoTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedVersioningDaoTest.java new file mode 100644 index 000000000..d9873fc43 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/CachedVersioningDaoTest.java @@ -0,0 +1,89 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.text.MessageFormat; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.postgresql.Driver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import li.strolch.db.DbSchemaVersionCheck; +import li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler; +import li.strolch.testbase.runtime.AbstractModelTest; +import li.strolch.testbase.runtime.RuntimeMock; +import li.strolch.utils.Version; +import li.strolch.utils.helper.StringHelper; + +public class CachedVersioningDaoTest extends AbstractModelTest { + + public static final String RUNTIME_PATH = "target/cachedStrolchRuntime/"; //$NON-NLS-1$ + public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/cachedruntimeVersioning"; //$NON-NLS-1$ + + public static final String DB_URL = "jdbc:postgresql://localhost/testdb"; //$NON-NLS-1$ + public static final String DB_USERNAME = "testuser"; //$NON-NLS-1$ + public static final String DB_PASSWORD = "test"; //$NON-NLS-1$ + + private static final Logger logger = LoggerFactory.getLogger(CachedVersioningDaoTest.class); + + protected static RuntimeMock runtimeMock; + + @Override + protected RuntimeMock getRuntimeMock() { + return runtimeMock; + } + + @BeforeClass + public static void beforeClass() throws Exception { + + dropSchema(DB_URL, DB_USERNAME, DB_PASSWORD); + + File rootPath = new File(RUNTIME_PATH); + File configSrc = new File(CONFIG_SRC); + runtimeMock = new RuntimeMock(); + runtimeMock.mockRuntime(rootPath, configSrc); + new File(rootPath, DB_STORE_PATH_DIR).mkdir(); + runtimeMock.startContainer(); + } + + public static void dropSchema(String dbUrl, String dbUsername, String dbPassword) throws Exception { + + if (!Driver.isRegistered()) + Driver.register(); + + Version dbVersion = DbSchemaVersionCheck.getExpectedDbVersion(PostgreSqlPersistenceHandler.SCRIPT_PREFIX, + PostgreSqlPersistenceHandler.class); + logger.info(MessageFormat.format("Dropping schema for expected version {0}", dbVersion)); + String sql = DbSchemaVersionCheck.getSql(PostgreSqlPersistenceHandler.SCRIPT_PREFIX, + PostgreSqlPersistenceHandler.class, dbVersion, "drop"); //$NON-NLS-1$ + logger.info(StringHelper.NEW_LINE + sql); + try (Connection connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword)) { + connection.prepareStatement(sql).execute(); + } + } + + @AfterClass + public static void afterClass() { + if (runtimeMock != null) + runtimeMock.destroyRuntime(); + } +} diff --git a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java index da8613545..17cdfc6aa 100644 --- a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java +++ b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java @@ -40,9 +40,9 @@ public class RealmTest extends AbstractModelTest { private static final String TESTUSER2 = "testuser2"; //$NON-NLS-1$ private static final String TESTUSER1 = "testuser1"; //$NON-NLS-1$ - private static final String SECOND = "second"; //$NON-NLS-1$ private static final String TEST = "test"; //$NON-NLS-1$ private static final String FIRST = "first"; //$NON-NLS-1$ + private static final String SECOND = "second"; //$NON-NLS-1$ public static final String RUNTIME_PATH = "target/realmtest/"; //$NON-NLS-1$ public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ diff --git a/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalVersioningDaoTest.java b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalVersioningDaoTest.java new file mode 100644 index 000000000..630ec41a5 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/TransactionalVersioningDaoTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.persistence.postgresql.dao.test; + +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_PASSWORD; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_URL; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.DB_USERNAME; +import static li.strolch.persistence.postgresql.dao.test.CachedDaoTest.dropSchema; + +import java.io.File; + +import li.strolch.testbase.runtime.AbstractModelTest; +import li.strolch.testbase.runtime.RuntimeMock; + +import org.junit.AfterClass; +import org.junit.BeforeClass; + +public class TransactionalVersioningDaoTest extends AbstractModelTest { + + public static final String RUNTIME_PATH = "target/transactionalStrolchRuntime/"; //$NON-NLS-1$ + public static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ + public static final String CONFIG_SRC = "src/test/resources/transactionalruntimeVersioning"; //$NON-NLS-1$ + + protected static RuntimeMock runtimeMock; + + @Override + protected RuntimeMock getRuntimeMock() { + return runtimeMock; + } + + @BeforeClass + public static void beforeClass() throws Exception { + + dropSchema(DB_URL, DB_USERNAME, DB_PASSWORD); + + File rootPath = new File(RUNTIME_PATH); + File configSrc = new File(CONFIG_SRC); + runtimeMock = new RuntimeMock(); + runtimeMock.mockRuntime(rootPath, configSrc); + new File(rootPath, DB_STORE_PATH_DIR).mkdir(); + runtimeMock.startContainer(); + } + + @AfterClass + public static void afterClass() { + if (runtimeMock != null) + runtimeMock.destroyRuntime(); + } +} diff --git a/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeConfig.xml b/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeConfig.xml new file mode 100644 index 000000000..cfab85b24 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeConfig.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeRoles.xml b/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeRoles.xml new file mode 100644 index 000000000..3a9e8ab07 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeRoles.xml @@ -0,0 +1,16 @@ + + + + + li.strolch.agent.impl.StartRealms + + + + + true + + + true + + + diff --git a/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeUsers.xml b/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeUsers.xml new file mode 100644 index 000000000..2973bf8f5 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/PrivilegeUsers.xml @@ -0,0 +1,18 @@ + + + + SYSTEM + + agent + + + + Application + Administrator + ENABLED + en_GB + + AppUser + + + diff --git a/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/StrolchConfiguration.xml b/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/StrolchConfiguration.xml new file mode 100644 index 000000000..e4ad32911 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/resources/cachedruntimeVersioning/config/StrolchConfiguration.xml @@ -0,0 +1,45 @@ + + + + + StrolchPersistenceTest + + true + + + + PrivilegeHandler + li.strolch.runtime.privilege.PrivilegeHandler + li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler + + PrivilegeConfig.xml + + + + RealmHandler + li.strolch.agent.api.RealmHandler + li.strolch.agent.impl.DefaultRealmHandler + PrivilegeHandler + PersistenceHandler + + CACHED + true + true + true + + + + PersistenceHandler + li.strolch.persistence.api.PersistenceHandler + li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler + + true + true + jdbc:postgresql://localhost/testdb + testuser + test + 1 + + + + \ No newline at end of file diff --git a/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeConfig.xml b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeConfig.xml new file mode 100644 index 000000000..cfab85b24 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeConfig.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeRoles.xml b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeRoles.xml new file mode 100644 index 000000000..3a9e8ab07 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeRoles.xml @@ -0,0 +1,16 @@ + + + + + li.strolch.agent.impl.StartRealms + + + + + true + + + true + + + diff --git a/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeUsers.xml b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeUsers.xml new file mode 100644 index 000000000..2973bf8f5 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/PrivilegeUsers.xml @@ -0,0 +1,18 @@ + + + + SYSTEM + + agent + + + + Application + Administrator + ENABLED + en_GB + + AppUser + + + diff --git a/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/StrolchConfiguration.xml b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/StrolchConfiguration.xml new file mode 100644 index 000000000..817dcf542 --- /dev/null +++ b/li.strolch.persistence.postgresql/src/test/resources/transactionalruntimeVersioning/config/StrolchConfiguration.xml @@ -0,0 +1,44 @@ + + + + + StrolchPersistenceTest + + true + + + + PrivilegeHandler + li.strolch.runtime.privilege.PrivilegeHandler + li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler + + PrivilegeConfig.xml + + + + RealmHandler + li.strolch.agent.api.RealmHandler + li.strolch.agent.impl.DefaultRealmHandler + PrivilegeHandler + PersistenceHandler + + TRANSACTIONAL + true + true + + + + PersistenceHandler + li.strolch.persistence.api.PersistenceHandler + li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler + + true + true + jdbc:postgresql://localhost/testdb + testuser + test + 1 + + + + \ No newline at end of file diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AbstractModelTest.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AbstractModelTest.java index d5b391501..5c3a54ee5 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AbstractModelTest.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AbstractModelTest.java @@ -43,84 +43,72 @@ public abstract class AbstractModelTest { @Test public void shouldCreateOrders() { - OrderModelTestRunner testRunner = new OrderModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runCreateOrderTest(); } @Test public void shouldQueryOrderSizes() { - OrderModelTestRunner testRunner = new OrderModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runQuerySizeTest(); } @Test public void shouldOrderCrud() { - OrderModelTestRunner testRunner = new OrderModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runCrudTests(); } @Test public void shouldOrderPerformBulkOperations() { - OrderModelTestRunner testRunner = new OrderModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runBulkOperationTests(); } @Test public void shouldCreateResources() { - ResourceModelTestRunner testRunner = new ResourceModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runCreateResourceTest(); } @Test public void shouldQueryResourceSizes() { - ResourceModelTestRunner testRunner = new ResourceModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runQuerySizeTest(); } @Test public void shouldResourceCrud() { - ResourceModelTestRunner testRunner = new ResourceModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runCrudTests(); } @Test public void shouldResourcePerformBulkOperations() { - ResourceModelTestRunner testRunner = new ResourceModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runBulkOperationTests(); } @Test public void shouldCreateActivities() { - ActivityModelTestRunner testRunner = new ActivityModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runCreateActivityTest(); } @Test public void shouldQueryActivitySizes() { - ActivityModelTestRunner testRunner = new ActivityModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runQuerySizeTest(); } @Test public void shouldActivityCrud() { - ActivityModelTestRunner testRunner = new ActivityModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runCrudTests(); } @Test public void shouldActivityPerformBulkOperations() { - ActivityModelTestRunner testRunner = new ActivityModelTestRunner(getRuntimeMock(), this.realmName); testRunner.runBulkOperationTests(); } diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ActivityModelTestRunner.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ActivityModelTestRunner.java index 7d89694e0..9339b309d 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ActivityModelTestRunner.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ActivityModelTestRunner.java @@ -164,18 +164,16 @@ public class ActivityModelTestRunner { activities.addAll(createActivities(activities.size(), 5, "@", "Further Activity", "MyType3")); // sort them so we know which activity our objects are - Comparator comparator = new Comparator() { - @Override - public int compare(Activity o1, Activity o2) { - return o1.getId().compareTo(o2.getId()); - } - }; + Comparator comparator = (o1, o2) -> o1.getId().compareTo(o2.getId()); Collections.sort(activities, comparator); // first clear the map, so that we have a clean state try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) { ActivityMap activityMap = tx.getActivityMap(); - activityMap.removeAll(tx, activityMap.getAllElements(tx)); + List allElements = activityMap.getAllElements(tx); + long removed = activityMap.removeAll(tx); + assertEquals(allElements.size(), removed); + assertEquals(0, activityMap.querySize(tx)); tx.commitOnClose(); } diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/OrderModelTestRunner.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/OrderModelTestRunner.java index 93bfc11c0..a795a8f51 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/OrderModelTestRunner.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/OrderModelTestRunner.java @@ -75,6 +75,10 @@ public class OrderModelTestRunner { tx.getOrderMap().removeAll(tx, tx.getOrderMap().getAllElements(tx)); tx.commitOnClose(); } + try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) { + long size = tx.getOrderMap().querySize(tx); + assertEquals("Should have 0 objects", 0, size); + } // create three orders Order order1 = createOrder("myTestOrder1", "Test Name", "QTestType1"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ @@ -164,18 +168,16 @@ public class OrderModelTestRunner { orders.addAll(createOrders(orders.size(), 5, "@", "Further Order", "MyType3")); // sort them so we know which order our objects are - Comparator comparator = new Comparator() { - @Override - public int compare(Order o1, Order o2) { - return o1.getId().compareTo(o2.getId()); - } - }; + Comparator comparator = (o1, o2) -> o1.getId().compareTo(o2.getId()); Collections.sort(orders, comparator); // first clear the map, so that we have a clean state try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) { OrderMap orderMap = tx.getOrderMap(); - orderMap.removeAll(tx, orderMap.getAllElements(tx)); + List allElements = orderMap.getAllElements(tx); + long removed = orderMap.removeAll(tx); + assertEquals(allElements.size(), removed); + assertEquals(0, orderMap.querySize(tx)); tx.commitOnClose(); } diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ResourceModelTestRunner.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ResourceModelTestRunner.java index 1c81dd0c7..30152f23e 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ResourceModelTestRunner.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ResourceModelTestRunner.java @@ -164,18 +164,16 @@ public class ResourceModelTestRunner { resources.addAll(createResources(resources.size(), 5, "@", "Further Resource", "MyType3")); // sort them so we know which order our objects are - Comparator comparator = new Comparator() { - @Override - public int compare(Resource o1, Resource o2) { - return o1.getId().compareTo(o2.getId()); - } - }; + Comparator comparator = (o1, o2) -> o1.getId().compareTo(o2.getId()); Collections.sort(resources, comparator); // first clear the map, so that we have a clean state try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) { ResourceMap resourceMap = tx.getResourceMap(); - resourceMap.removeAll(tx, resourceMap.getAllElements(tx)); + List allElements = resourceMap.getAllElements(tx); + long removed = resourceMap.removeAll(tx); + assertEquals(allElements.size(), removed); + assertEquals(0, resourceMap.querySize(tx)); tx.commitOnClose(); } @@ -201,7 +199,8 @@ public class ResourceModelTestRunner { // now use the remove all by type try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) { - tx.getResourceMap().removeAllBy(tx, "MyType3"); + long removed = tx.getResourceMap().removeAllBy(tx, "MyType3"); + assertEquals(5, removed); tx.commitOnClose(); } diff --git a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/VersioningTestRunner.java b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/VersioningTestRunner.java index eccac6a75..c5c64d5fa 100644 --- a/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/VersioningTestRunner.java +++ b/li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/VersioningTestRunner.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import java.util.List; @@ -13,6 +14,7 @@ import li.strolch.model.ModelGenerator; import li.strolch.model.Resource; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.privilege.model.Certificate; +import li.strolch.runtime.StrolchConstants; import li.strolch.runtime.privilege.PrivilegeHandler; public class VersioningTestRunner { @@ -28,6 +30,7 @@ public class VersioningTestRunner { } public void runTestsForVersioning() { + assumeTrue(runtimeMock.getRealm(StrolchConstants.DEFAULT_REALM).isVersioningEnabled()); ComponentContainer container = runtimeMock.getContainer();