#3310 Update test only, reuse existing entity beans

- Reuse the existing OmBeanListParent and child
- Simplify the test setup code
- Rename test methods to maybe better reflect what I think is failing

Noting that markAsDirty doesn't specifically have anything to do with this bug but it's more on whether the parent bean is dirty or dirty (markAsDirty is just a way to make the parent bean dirty).
This commit is contained in:
Rob Bygrave
2024-02-09 08:30:42 +13:00
parent 006e33cb3e
commit 04ba81d12f
4 changed files with 124 additions and 193 deletions
@@ -2,10 +2,14 @@ package org.tests.model.orphanremoval;
import io.ebean.Model;
import io.ebean.annotation.WhenCreated;
import io.ebean.annotation.WhenModified;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Version;
import java.time.Instant;
import java.util.List;
import static jakarta.persistence.CascadeType.ALL;
@@ -19,6 +23,13 @@ public class OmBeanListParent extends Model {
@Version
private long version;
private String name;
@WhenCreated
private Instant whenCreated;
@WhenModified
private Instant whenModified;
@OneToMany(cascade = ALL, mappedBy = "parent", orphanRemoval = true)
private List<OmBeanListChild> children;
@@ -35,6 +46,42 @@ public class OmBeanListParent extends Model {
this.children.clear();
this.children.addAll(children);
}
public void setChildren2(List<OmBeanListChild> children) {
this.children = children;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public Instant getWhenModified() {
return whenModified;
}
public void setWhenModified(Instant whenModified) {
this.whenModified = whenModified;
}
public Instant getWhenCreated() {
return whenCreated;
}
public void setWhenCreated(Instant whenCreated) {
this.whenCreated = whenCreated;
}
}
@@ -3,147 +3,106 @@ package org.tests.o2m;
import io.ebean.DB;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.tests.o2m.dm.*;
import java.sql.Timestamp;
import org.tests.model.orphanremoval.OmBeanListChild;
import org.tests.model.orphanremoval.OmBeanListParent;
import java.time.Instant;
import java.util.ArrayList;
import static org.assertj.core.api.Assertions.assertThat;
public class OneToManyListMarkAsDirtyTest extends BaseTestCase {
class OneToManyListMarkAsDirtyTest extends BaseTestCase {
@Test
public void workingTestCase() {
var g = new GoodsEntity();
DB.save(g);
void usingNewListWithNonDirtyParent_expect_orphanDeleted_works() {
// setup
var parent = new OmBeanListParent();
var a_b = new OmBeanListChild("b");
parent.getChildren().add(a_b);
DB.save(parent);
var planStart = new StrategicPlan();
planStart.setName("aaa");
planStart.setGoodsCapacities(new ArrayList<>());
DB.save(planStart);
// act
var secondParent = DB.find(OmBeanListParent.class, parent.getId());
secondParent.setChildren2(new ArrayList<>()); // <!-- HERE - setting a new ArrayList rather than using clear()
var a_c = new OmBeanListChild("b");
secondParent.getChildren().add(a_c);
// working here as secondParent itself is not dirty
DB.save(secondParent);
var planFirstCapacity = DB.find(StrategicPlan.class, planStart.getId());
planFirstCapacity.setGoodsCapacities(new ArrayList<>());
var a_b = new GoodsCapacity();
a_b.setGoods(g);
planFirstCapacity.getGoodsCapacities().add(a_b);
DB.save(planFirstCapacity);
var planSecondCapacity = DB.find(StrategicPlan.class, planStart.getId());
planSecondCapacity.setGoodsCapacities(new ArrayList<>());
var a_c = new GoodsCapacity();
a_c.setGoods(g);
planSecondCapacity.getGoodsCapacities().add(a_c);
// without this the goods capacity is saved correctly, version remains same
// (not sure if version should stay the same if OneToMany relationship is changed (through cascade)
// DB.markAsDirty(planSecondCapacity);
DB.save(planSecondCapacity);
var refreshedPlanSecondCapacity = DB.find(StrategicPlan.class, planStart.getId());
assertThat(refreshedPlanSecondCapacity.getGoodsCapacities().size()).isEqualTo(1);
assertThat(refreshedPlanSecondCapacity.getGoodsCapacities().get(0).getId()).isEqualTo(a_c.getId());
// todo is this expected?
assertThat(refreshedPlanSecondCapacity.getVersion()).isEqualTo(planFirstCapacity.getVersion());
assertThat(refreshedPlanSecondCapacity.getWhenModified()).isEqualTo(planFirstCapacity.getWhenModified());
var refreshedPlanSecondCapacity = DB.find(OmBeanListParent.class, parent.getId());
assertThat(refreshedPlanSecondCapacity.getChildren().size()).isEqualTo(1);
assertThat(refreshedPlanSecondCapacity.getChildren().get(0).getId()).isEqualTo(a_c.getId());
// Q: is this expected? A: Rob Bygrave - Yes it is expected
assertThat(refreshedPlanSecondCapacity.getVersion()).isEqualTo(parent.getVersion());
assertThat(refreshedPlanSecondCapacity.getWhenModified()).isEqualTo(parent.getWhenModified());
}
@Test
public void oneToManyShouldBeDeletedWithParentMarkAsDirtyTest() {
var g = new GoodsEntity();
DB.save(g);
void usingNewListWithParentDirty_expect_orphanDeleted_fails2() {
// setup
var parent = new OmBeanListParent();
var a_b = new OmBeanListChild("b");
parent.getChildren().add(a_b);
DB.save(parent);
var planStart = new StrategicPlan();
planStart.setName("aaa");
planStart.setGoodsCapacities(new ArrayList<>());
DB.save(planStart);
var planFirstCapacity = DB.find(StrategicPlan.class, planStart.getId());
planFirstCapacity.setGoodsCapacities(new ArrayList<>());
var a_b = new GoodsCapacity();
a_b.setGoods(g);
planFirstCapacity.getGoodsCapacities().add(a_b);
DB.save(planFirstCapacity);
var planSecondCapacity = DB.find(StrategicPlan.class, planStart.getId());
planSecondCapacity.setGoodsCapacities(new ArrayList<>());
var a_c = new GoodsCapacity();
a_c.setGoods(g);
planSecondCapacity.getGoodsCapacities().add(a_c);
// act
var secondParent = DB.find(OmBeanListParent.class, parent.getId());
secondParent.setChildren2(new ArrayList<>()); // <!-- HERE: using new ArrayList with orphanRemoval
var a_c = new OmBeanListChild("c");
secondParent.getChildren().add(a_c);
// force version increase
// without this the goods capacity is saved correctly, but version isn't
DB.markAsDirty(planSecondCapacity);
DB.save(planSecondCapacity);
DB.markAsDirty(secondParent);
DB.save(secondParent);
var refreshedPlanSecondCapacity = DB.find(StrategicPlan.class, planStart.getId());
assertThat(refreshedPlanSecondCapacity.getGoodsCapacities().size()).isEqualTo(1);
assertThat(refreshedPlanSecondCapacity.getGoodsCapacities().get(0).getId()).isEqualTo(a_c.getId());
assertThat(refreshedPlanSecondCapacity.getVersion()).isGreaterThan(planFirstCapacity.getVersion());
assertThat(refreshedPlanSecondCapacity.getWhenModified()).isAfter(planFirstCapacity.getWhenModified());
var refreshedPlanSecondCapacity = DB.find(OmBeanListParent.class, parent.getId());
assertThat(refreshedPlanSecondCapacity.getChildren().size()).isEqualTo(1);
assertThat(refreshedPlanSecondCapacity.getChildren().get(0).getId()).isEqualTo(a_c.getId());
assertThat(refreshedPlanSecondCapacity.getVersion()).isGreaterThan(parent.getVersion());
assertThat(refreshedPlanSecondCapacity.getWhenModified()).isAfter(parent.getWhenModified());
}
@Test
public void oneToManyShouldBeDeletedWithParentMarkAsDirtyTestWorkAround() {
var g = new GoodsEntity();
DB.save(g);
void usingClearWithParentDirty_expect_orphanDeleted_works() {
// setup
var parent = new OmBeanListParent();
var a_b = new OmBeanListChild("b");
parent.getChildren().add(a_b);
DB.save(parent);
var planStart = new StrategicPlan();
planStart.setName("aaa");
planStart.setGoodsCapacities(new ArrayList<>());
DB.save(planStart);
var planFirstCapacity = DB.find(StrategicPlan.class, planStart.getId());
planFirstCapacity.setGoodsCapacities(new ArrayList<>());
var a_b = new GoodsCapacity();
a_b.setGoods(g);
planFirstCapacity.getGoodsCapacities().add(a_b);
DB.save(planFirstCapacity);
var planSecondCapacity = DB.find(StrategicPlan.class, planStart.getId());
// planSecondCapacity.setGoodsCapacities(new ArrayList<>());
planSecondCapacity.getGoodsCapacities().clear();
var a_c = new GoodsCapacity();
a_c.setGoods(g);
planSecondCapacity.getGoodsCapacities().add(a_c);
// act
var secondParent = DB.find(OmBeanListParent.class, parent.getId());
secondParent.getChildren().clear(); // <!-- HERE: Using clear() with orphanRemoval
var a_c = new OmBeanListChild("c");
secondParent.getChildren().add(a_c);
// force version increase
DB.markAsDirty(planSecondCapacity);
DB.save(planSecondCapacity);
DB.markAsDirty(secondParent);
DB.save(secondParent);
var refreshedPlanSecondCapacity = DB.find(StrategicPlan.class, planStart.getId());
assertThat(refreshedPlanSecondCapacity.getGoodsCapacities().size()).isEqualTo(1);
assertThat(refreshedPlanSecondCapacity.getGoodsCapacities().get(0).getId()).isEqualTo(a_c.getId());
assertThat(refreshedPlanSecondCapacity.getVersion()).isGreaterThan(planFirstCapacity.getVersion());
assertThat(refreshedPlanSecondCapacity.getWhenModified()).isAfter(planFirstCapacity.getWhenModified());
var refreshedParent = DB.find(OmBeanListParent.class, parent.getId());
assertThat(refreshedParent.getChildren().size()).isEqualTo(1);
assertThat(refreshedParent.getChildren().get(0).getId()).isEqualTo(a_c.getId());
assertThat(refreshedParent.getVersion()).isGreaterThan(parent.getVersion());
assertThat(refreshedParent.getWhenModified()).isAfter(parent.getWhenModified());
}
@Test
public void oneToManyShouldBeDeletedWithParentManualModifiedWhenTest() {
var g = new GoodsEntity();
DB.save(g);
void usingNewListWithParentDirty_expect_orphanDeleted_fails() {
// setup
var parent = new OmBeanListParent();
var a_b = new OmBeanListChild("b");
parent.getChildren().add(a_b);
DB.save(parent);
var planStart = new StrategicPlan();
planStart.setName("aaa");
planStart.setGoodsCapacities(new ArrayList<>());
DB.save(planStart);
// act
var secondParent = DB.find(OmBeanListParent.class, parent.getId());
secondParent.setChildren2(new ArrayList<>()); // <!-- HERE: new ArrayList with orphanRemoval
var a_c = new OmBeanListChild("c");
secondParent.getChildren().add(a_c);
secondParent.setWhenCreated(Instant.now());
DB.save(secondParent);
var planFirstCapacity = DB.find(StrategicPlan.class, planStart.getId());
planFirstCapacity.setGoodsCapacities(new ArrayList<>());
var a_b = new GoodsCapacity();
a_b.setGoods(g);
planFirstCapacity.getGoodsCapacities().add(a_b);
DB.save(planFirstCapacity);
var planSecondCapacity = DB.find(StrategicPlan.class, planStart.getId());
planSecondCapacity.setGoodsCapacities(new ArrayList<>());
var a_c = new GoodsCapacity();
a_c.setGoods(g);
planSecondCapacity.getGoodsCapacities().add(a_c);
planSecondCapacity.setWhenCreated(new Timestamp(System.currentTimeMillis()));
DB.save(planSecondCapacity);
var refreshedPlanSecondCapacity = DB.find(StrategicPlan.class, planStart.getId());
assertThat(refreshedPlanSecondCapacity.getGoodsCapacities().size()).isEqualTo(1);
assertThat(refreshedPlanSecondCapacity.getGoodsCapacities().get(0).getId()).isEqualTo(a_c.getId());
assertThat(refreshedPlanSecondCapacity.getVersion()).isGreaterThan(planFirstCapacity.getVersion());
assertThat(refreshedPlanSecondCapacity.getWhenModified()).isAfter(planFirstCapacity.getWhenModified());
var refreshedParent = DB.find(OmBeanListParent.class, parent.getId());
assertThat(refreshedParent.getChildren().size()).isEqualTo(1);
assertThat(refreshedParent.getChildren().get(0).getId()).isEqualTo(a_c.getId());
assertThat(refreshedParent.getVersion()).isGreaterThan(parent.getVersion());
assertThat(refreshedParent.getWhenModified()).isAfter(parent.getWhenModified());
}
}
@@ -1,41 +0,0 @@
package org.tests.o2m.dm;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
@Entity
//@Table(name = "strategic_plan_goods_capacities")
public class GoodsCapacity {
@Id
private Long id;
@ManyToOne
private StrategicPlan strategicPlan;
@ManyToOne
private GoodsEntity goods;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public StrategicPlan getStrategicPlan() {
return strategicPlan;
}
public void setStrategicPlan(StrategicPlan strategicPlan) {
this.strategicPlan = strategicPlan;
}
public GoodsEntity getGoods() {
return goods;
}
public void setGoods(GoodsEntity goods) {
this.goods = goods;
}
}
@@ -1,34 +0,0 @@
package org.tests.o2m.dm;
import io.ebean.annotation.DbJsonB;
import jakarta.persistence.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@Entity
//@Table(name = "strategic_plans")
public class StrategicPlan extends HistoryColumns {
private String name;
@OneToMany(mappedBy = "strategicPlan", cascade = CascadeType.ALL, orphanRemoval = true)
private List<GoodsCapacity> goodsCapacities = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<GoodsCapacity> getGoodsCapacities() {
return goodsCapacities;
}
public void setGoodsCapacities(List<GoodsCapacity> goodsCapacities) {
this.goodsCapacities = goodsCapacities;
}
}