/**
* Copyright (c) 2009 - 2012 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package org.candlepin.model;
import static org.junit.Assert.*;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.candlepin.config.DatabaseConfigFactory;
import org.candlepin.test.DatabaseTestFixture;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* AbstractHibernateCuratorTest
*/
@RunWith(JUnitParamsRunner.class)
public class AbstractHibernateCuratorTest extends DatabaseTestFixture {
/**
* Test implementation that provides access to some protected methods
*/
private static class TestHibernateCurator<E extends Persisted> extends AbstractHibernateCurator<E> {
public TestHibernateCurator(Class entityClass) {
super(entityClass);
}
@Override
public int bulkSQLUpdate(String table, String column, Map<Object, Object> values,
Map<String, Object> criteria) {
return super.bulkSQLUpdate(table, column, values, criteria);
}
@Override
public E lockAndLoadById(Class<E> entityClass, Serializable id) {
return super.lockAndLoadById(entityClass, id);
}
@Override
protected Collection<E> lockAndLoadByIds(Class<E> entityClass, Iterable<? extends Serializable> ids) {
return super.lockAndLoadByIds(entityClass, ids);
}
}
AbstractHibernateCurator<Content> testContentCurator;
@Before
public void setup() {
this.testContentCurator = new TestHibernateCurator<Content>(Content.class);
this.injectMembers(this.testContentCurator);
}
@Test
public void testBulkSQLUpdate() throws Exception {
Owner owner = this.createOwner();
Content c1 = this.createContent("c1", "content 1", owner);
Content c2 = this.createContent("c2", "content 2", owner);
Content c3 = this.createContent("c3", "content 3", owner);
Map<Object, Object> values = new HashMap<Object, Object>();
values.put("content 1", "update 1");
values.put("content 2", "update 2");
values.put("content ?", "should not exist");
int result = this.testContentCurator.bulkSQLUpdate(Content.DB_TABLE, "name", values, null);
// Note:
// This looks like it should be 2, and technically that's what's happening here, but with
// the way the bulk updater works, even the non-matching columns are getting updated to
// themselves.
assertEquals(3, result);
testContentCurator.refresh(c1, c2, c3);
assertEquals("update 1", c1.getName());
assertEquals("update 2", c2.getName());
assertEquals("content 3", c3.getName());
}
@Test
public void testBulkSQLUpdateSingleUpdate() throws Exception {
Owner owner = this.createOwner();
Content c1 = this.createContent("c1", "content 1", owner);
Content c2 = this.createContent("c2", "content 2", owner);
Content c3 = this.createContent("c3", "content 3", owner);
Map<Object, Object> values = new HashMap<Object, Object>();
values.put("content 1", "update 1");
int result = this.testContentCurator.bulkSQLUpdate(Content.DB_TABLE, "name", values, null);
assertEquals(1, result);
testContentCurator.refresh(c1, c2, c3);
assertEquals("update 1", c1.getName());
assertEquals("content 2", c2.getName());
assertEquals("content 3", c3.getName());
}
@Test
public void testBulkSQLUpdateSingleUpdateNoChange() throws Exception {
Owner owner = this.createOwner();
Content c1 = this.createContent("c1", "content 1", owner);
Content c2 = this.createContent("c2", "content 2", owner);
Content c3 = this.createContent("c3", "content 3", owner);
Map<Object, Object> values = new HashMap<Object, Object>();
values.put("content B", "update 1");
int result = this.testContentCurator.bulkSQLUpdate(Content.DB_TABLE, "name", values, null);
assertEquals(0, result);
testContentCurator.refresh(c1, c2, c3);
assertEquals("content 1", c1.getName());
assertEquals("content 2", c2.getName());
assertEquals("content 3", c3.getName());
}
@Test
public void testBulkSQLUpdateWithEmptyValues() throws Exception {
Owner owner = this.createOwner();
Content c1 = this.createContent("c1", "content 1", owner);
Content c2 = this.createContent("c2", "content 2", owner);
Content c3 = this.createContent("c3", "content 3", owner);
Map<Object, Object> values = new HashMap<Object, Object>();
int result = this.testContentCurator.bulkSQLUpdate(Content.DB_TABLE, "name", values, null);
assertEquals(0, result);
testContentCurator.refresh(c1, c2, c3);
assertEquals("content 1", c1.getName());
assertEquals("content 2", c2.getName());
assertEquals("content 3", c3.getName());
}
@Test
public void testBulkSQLUpdateWithSingleCriteria() {
Owner owner = this.createOwner();
Content c1 = this.createContent("c1", "content 1", owner);
Content c2 = this.createContent("c2", "content 2", owner);
Content c3 = this.createContent("c3", "content 3", owner);
Map<Object, Object> values = new HashMap<Object, Object>();
values.put("content 1", "update 1");
values.put("content 2", "update 2");
values.put("content ?", "should not exist");
Map<String, Object> criteria = new HashMap<String, Object>();
criteria.put("name", values.keySet());
int result = this.testContentCurator.bulkSQLUpdate(Content.DB_TABLE, "name", values, criteria);
// Unlike the base test where the result count is 3, this filters by only the values we
// intend to update, so it should be 2.
assertEquals(2, result);
testContentCurator.refresh(c1, c2, c3);
assertEquals("update 1", c1.getName());
assertEquals("update 2", c2.getName());
assertEquals("content 3", c3.getName());
}
@Test
public void testBulkSQLUpdateWithMultipleCriteria() {
Owner owner = this.createOwner();
Content c1 = this.createContent("c1", "content 1", owner);
Content c2 = this.createContent("c2", "content 2", owner);
Content c3 = this.createContent("c3", "content 3", owner);
Map<Object, Object> values = new HashMap<Object, Object>();
values.put("content 1", "update 1");
values.put("content 2", "update 2");
values.put("content ?", "should not exist");
Map<String, Object> criteria = new HashMap<String, Object>();
criteria.put("name", values.keySet());
criteria.put("content_id", "c2");
int result = this.testContentCurator.bulkSQLUpdate(Content.DB_TABLE, "name", values, criteria);
// Unlike the base test where the result count is 3, this filters by only the values we
// intend to update, so it should be 1.
assertEquals(1, result);
testContentCurator.refresh(c1, c2, c3);
assertEquals("content 1", c1.getName());
assertEquals("update 2", c2.getName());
assertEquals("content 3", c3.getName());
}
protected Object[][] largeValueSetSizes() {
int caseBlockSize = getConfigForParameters().getInt(DatabaseConfigFactory.CASE_OPERATOR_BLOCK_SIZE);
return new Object[][] {
new Object[] { (int) (caseBlockSize), 0 },
new Object[] { (int) (caseBlockSize + 1), 0 },
new Object[] { (int) (caseBlockSize * 1.5), 0 },
new Object[] { (int) (caseBlockSize * 1.5 + 1), 0 },
new Object[] { (int) (caseBlockSize * 2), 0 },
new Object[] { (int) (caseBlockSize * 2 + 1), 0 },
new Object[] { (int) (caseBlockSize * 2.5), 0 },
new Object[] { (int) (caseBlockSize * 2.5 + 1), 0 },
new Object[] { (int) (caseBlockSize * 3), 0 },
new Object[] { (int) (caseBlockSize * 3 + 1), 0 },
new Object[] { (int) (caseBlockSize * 3.5), 0 },
new Object[] { (int) (caseBlockSize * 3.5 + 1), 0 },
new Object[] { (int) (caseBlockSize), 1 },
new Object[] { (int) (caseBlockSize + 1), 1 },
new Object[] { (int) (caseBlockSize * 1.5), 1 },
new Object[] { (int) (caseBlockSize * 1.5 + 1), 1 },
new Object[] { (int) (caseBlockSize * 2), 1 },
new Object[] { (int) (caseBlockSize * 2 + 1), 1 },
new Object[] { (int) (caseBlockSize * 2.5), 1 },
new Object[] { (int) (caseBlockSize * 2.5 + 1), 1 },
new Object[] { (int) (caseBlockSize * 3), 1 },
new Object[] { (int) (caseBlockSize * 3 + 1), 1 },
new Object[] { (int) (caseBlockSize * 3.5), 1 },
new Object[] { (int) (caseBlockSize * 3.5 + 1), 1 },
};
}
@Test
@Parameters(method = "largeValueSetSizes")
public void testBulkSQLUpdateWithLargeValueSets(int count, int skip) {
Owner owner = this.createOwner();
for (int i = 1; i <= count; ++i) {
this.createContent("c" + i, "content-" + i, owner);
}
Map<Object, Object> values = new LinkedHashMap<Object, Object>();
for (int i = 1; i <= count; ++i) {
// We want every odd value to be unaffected, but we still want a fake update entry
// for the query
values.put("content-" + (i % 2 == skip ? i : "X" + i), "update-" + i);
}
int result = this.testContentCurator.bulkSQLUpdate(Content.DB_TABLE, "name", values, null);
assertEquals(count, result);
testContentCurator.clear();
for (int i = 1; i <= count; ++i) {
Content content = this.ownerContentCurator.getContentById(owner, "c" + i);
if (i % 2 == skip) {
assertEquals("update-" + i, content.getName());
}
else {
assertEquals("content-" + i, content.getName());
}
}
}
protected Object[] largeValueSetAndCriteriaSizes() {
List<Object[]> entries = new LinkedList<Object[]>();
// Declaring these as variables because the constant names are loooooooong
int caseBlockSize = getConfigForParameters().getInt(DatabaseConfigFactory.CASE_OPERATOR_BLOCK_SIZE);
int inBlockSize = getConfigForParameters().getInt(DatabaseConfigFactory.IN_OPERATOR_BLOCK_SIZE);
for (float multi = 1; multi < 4.0f; multi += 0.5) {
entries.add(new Object[] { (int) (caseBlockSize * multi), (int) (inBlockSize * multi) });
entries.add(new Object[] { (int) (caseBlockSize * multi + 1), (int) (inBlockSize * multi + 1) });
}
return entries.toArray();
}
@Test
@Parameters(method = "largeValueSetAndCriteriaSizes")
public void testBulkSQLUpdateWithLargeValueSetAndCriteriaList(int valueCount, int criteriaListSize) {
Owner owner = this.createOwner();
Map<Object, Object> values = new HashMap<Object, Object>();
for (int i = 1; i <= valueCount; ++i) {
this.createContent("c" + i, "content-" + i, owner);
// We want every odd value to be unaffected, but we still want a fake update entry
// for the query
values.put("content-" + (i % 2 == 0 ? i : "X" + i), "update-" + i);
}
Map<String, Object> criteria = new HashMap<String, Object>();
List<String> valueList = new LinkedList<String>();
criteria.put("name", valueList);
for (int i = 1; i <= criteriaListSize; ++i) {
valueList.add("content-" + (i % 2 == 0 ? i : "X" + i));
}
int result = this.testContentCurator.bulkSQLUpdate(Content.DB_TABLE, "name", values, criteria);
assertEquals(valueCount / 2, result);
testContentCurator.clear();
for (int i = 1; i <= valueCount; ++i) {
Content content = this.ownerContentCurator.getContentById(owner, "c" + i);
if (i % 2 == 0) {
assertEquals("update-" + i, content.getName());
}
else {
assertEquals("content-" + i, content.getName());
}
}
}
@Test
public void testLockAndLoadSingleEntityRefresh() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that we're getting an equal entity back out
Content output = this.testContentCurator.lockAndLoad(content);
assertEquals(content, output);
}
@Test
public void testLockAndLoadSingleEntityRevertsPropertyChange() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that lockAndLoad's refresh reverts our name change
content.setName("changed_name");
this.testContentCurator.lockAndLoad(content);
assertEquals("content-1", content.getName());
}
@Test
public void testLockAndLoadSingleEntityRevertsUnflushedMerge() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that even a pending merge will be reverted
content.setName("changed_name");
testContentCurator.merge(content);
this.testContentCurator.lockAndLoad(content);
assertEquals("content-1", content.getName());
}
@Test
public void testLockAndLoadSingleEntityRefreshIgnoresEvicted() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify evicted/detached elements aren't affected
content.setName("detached");
testContentCurator.evict(content);
Content output = this.testContentCurator.lockAndLoad(content);
assertNotEquals(content, output);
assertEquals("content-1", output.getName());
assertEquals("detached", content.getName());
}
@Test
public void testLockAndLoadSingleEntityRefreshRetainsFlushedChanged() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that a flush will make the change persistent
content.setName("changed_name");
testContentCurator.merge(content);
testContentCurator.flush();
this.testContentCurator.lockAndLoad(content);
assertEquals("changed_name", content.getName());
}
@Test
public void testLockAndLoadSingleEntityByIdRefresh() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that we're getting an equal entity back out
Content output = this.testContentCurator.lockAndLoadById(content.getUuid());
assertEquals(content, output);
}
@Test
public void testLockAndLoadSingleEntityByIdRevertsPropertyChange() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that lockAndLoad's refresh reverts our name change
content.setName("changed_name");
this.testContentCurator.lockAndLoadById(content.getUuid());
assertEquals("content-1", content.getName());
}
@Test
public void testLockAndLoadSingleEntityByIdRevertsUnflushedMerge() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that even a pending merge will be reverted
content.setName("changed_name");
testContentCurator.merge(content);
this.testContentCurator.lockAndLoadById(content.getUuid());
assertEquals("content-1", content.getName());
}
@Test
public void testLockAndLoadSingleEntityByIdRefreshIgnoresEvicted() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify evicted/detached elements aren't affected
content.setName("detached");
testContentCurator.evict(content);
Content output = this.testContentCurator.lockAndLoadById(content.getUuid());
assertNotNull(output);
assertNotEquals(content, output);
assertEquals("content-1", output.getName());
assertEquals("detached", content.getName());
}
@Test
public void testLockAndLoadSingleEntityByIdRefreshRetainsFlushedChanged() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that a flush will make the change persistent
content.setName("changed_name");
testContentCurator.merge(content);
testContentCurator.flush();
this.testContentCurator.lockAndLoadById(content.getUuid());
assertEquals("changed_name", content.getName());
}
@Test
public void testLockAndLoadSingleEntityByClassAndIdRefresh() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that we're getting an equal entity back out
Content output = this.testContentCurator.lockAndLoadById(Content.class, content.getUuid());
assertEquals(content, output);
}
@Test
public void testLockAndLoadSingleEntityByClassAndIdRevertsPropertyChange() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that lockAndLoad's refresh reverts our name change
content.setName("changed_name");
this.testContentCurator.lockAndLoadById(Content.class, content.getUuid());
assertEquals("content-1", content.getName());
}
@Test
public void testLockAndLoadSingleEntityByClassAndIdRevertsUnflushedMerge() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that even a pending merge will be reverted
content.setName("changed_name");
testContentCurator.merge(content);
this.testContentCurator.lockAndLoadById(Content.class, content.getUuid());
assertEquals("content-1", content.getName());
}
@Test
public void testLockAndLoadSingleEntityByClassAndIdRefreshIgnoresEvicted() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify evicted/detached elements aren't affected
content.setName("detached");
testContentCurator.evict(content);
Content output = this.testContentCurator.lockAndLoadById(Content.class, content.getUuid());
assertNotNull(output);
assertNotEquals(content, output);
assertEquals("content-1", output.getName());
assertEquals("detached", content.getName());
}
@Test
public void testLockAndLoadSingleEntityByClassAndIdRefreshRetainsFlushedChanged() {
Owner owner = this.createOwner();
Content content = this.createContent("c1", "content-1", owner);
// Verify that a flush will make the change persistent
content.setName("changed_name");
testContentCurator.merge(content);
testContentCurator.flush();
this.testContentCurator.lockAndLoadById(Content.class, content.getUuid());
assertEquals("changed_name", content.getName());
}
@Test
public void testLockAndLoadMultiEntity() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify we're getting the correct number of entities out
Collection<Content> input = Arrays.asList(content1, content2, content3);
Collection<Content> output = this.testContentCurator.lockAndLoad(input);
assertEquals(3, output.size());
// Note: the instances may be different here, but as long as they're equal (including UUID),
// we're okay.
for (Content expected : input) {
boolean found = false;
for (Content content : output) {
if (expected.equals(content)) {
assertFalse(found);
assertEquals(expected.getUuid(), content.getUuid());
found = true;
// We don't break here because we're verifying we didn't receive any duplicates.
}
}
assertTrue("expected entity was not found in output: " + expected.getId(), found);
}
}
@Test
public void testLockAndLoadMultiEntityRefreshRevertsPropertyChange() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify that lockAndLoad's refresh reverts our name changes only where applicable
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
Collection<Content> output = this.testContentCurator.lockAndLoad(Arrays.asList(content1, content3));
assertEquals(2, output.size());
assertTrue(output.contains(content1));
assertFalse(output.contains(content2));
assertTrue(output.contains(content3));
assertEquals("content-1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("content-3", content3.getName());
}
@Test
public void testLockAndLoadMultiEntityRefreshRevertsUnflushedMerge() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify that even a pending merge will be reverted
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
this.testContentCurator.merge(content1);
this.testContentCurator.merge(content2);
this.testContentCurator.merge(content3);
Collection<Content> output = this.testContentCurator.lockAndLoad(Arrays.asList(content1, content3));
assertEquals(2, output.size());
assertTrue(output.contains(content1));
assertFalse(output.contains(content2));
assertTrue(output.contains(content3));
assertEquals("content-1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("content-3", content3.getName());
}
@Test
public void testLockAndLoadMultiEntityRefreshRetainsFlushedChanged() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify that a flush will make the change persistent
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
this.testContentCurator.merge(content1);
this.testContentCurator.merge(content2);
this.testContentCurator.merge(content3);
this.testContentCurator.flush();
Collection<Content> output = this.testContentCurator.lockAndLoad(Arrays.asList(content1, content3));
assertEquals(2, output.size());
assertTrue(output.contains(content1));
assertFalse(output.contains(content2));
assertTrue(output.contains(content3));
assertEquals("name change 1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("name change 3", content3.getName());
}
@Test
public void testLockAndLoadMultiEntityRefreshIgnoresEvicted() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify evicted/detached elements aren't affected
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
this.testContentCurator.evict(content1);
this.testContentCurator.evict(content2);
this.testContentCurator.evict(content3);
Collection<Content> output = this.testContentCurator.lockAndLoad(Arrays.asList(content1, content3));
assertEquals(2, output.size());
assertFalse(output.contains(content1));
assertFalse(output.contains(content2));
assertFalse(output.contains(content3));
assertEquals("name change 1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("name change 3", content3.getName());
for (Content entity : output) {
assertTrue(entity.getName().matches("content-\\d"));
}
}
@Test
public void testLockAndLoadMultiEntityByIds() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify we're getting the correct number of entities out
Collection<String> input = Arrays.asList(content1.getUuid(), content2.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(input);
assertEquals(3, output.size());
// Note: the instances may be different here, but as long as they're equal (including UUID),
// we're okay.
for (Content expected : Arrays.asList(content1, content2, content3)) {
boolean found = false;
for (Content content : output) {
if (expected.equals(content)) {
assertFalse(found);
assertEquals(expected.getUuid(), content.getUuid());
found = true;
// We don't break here because we're verifying we didn't receive any duplicates.
}
}
assertTrue("expected entity was not found in output: " + expected.getId(), found);
}
}
@Test
public void testLockAndLoadMultiEntityByIdsRefreshRevertsPropertyChange() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify that lockAndLoad's refresh reverts our name changes only where applicable
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
Collection<String> input = Arrays.asList(content1.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(input);
assertEquals(2, output.size());
assertTrue(output.contains(content1));
assertFalse(output.contains(content2));
assertTrue(output.contains(content3));
assertEquals("content-1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("content-3", content3.getName());
}
@Test
public void testLockAndLoadMultiEntityByIdsRefreshRevertsUnflushedMerge() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify that even a pending merge will be reverted
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
this.testContentCurator.merge(content1);
this.testContentCurator.merge(content2);
this.testContentCurator.merge(content3);
Collection<String> input = Arrays.asList(content1.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(input);
assertEquals(2, output.size());
assertTrue(output.contains(content1));
assertFalse(output.contains(content2));
assertTrue(output.contains(content3));
assertEquals("content-1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("content-3", content3.getName());
}
@Test
public void testLockAndLoadMultiEntityByIdsRefreshRetainsFlushedChanged() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify that a flush will make the change persistent
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
this.testContentCurator.merge(content1);
this.testContentCurator.merge(content2);
this.testContentCurator.merge(content3);
this.testContentCurator.flush();
Collection<String> input = Arrays.asList(content1.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(input);
assertEquals(2, output.size());
assertTrue(output.contains(content1));
assertFalse(output.contains(content2));
assertTrue(output.contains(content3));
assertEquals("name change 1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("name change 3", content3.getName());
}
@Test
public void testLockAndLoadMultiEntityByIdsRefreshIgnoresEvicted() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify evicted/detached elements aren't affected
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
this.testContentCurator.evict(content1);
this.testContentCurator.evict(content2);
this.testContentCurator.evict(content3);
Collection<String> input = Arrays.asList(content1.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(input);
assertEquals(2, output.size());
assertFalse(output.contains(content1));
assertFalse(output.contains(content2));
assertFalse(output.contains(content3));
assertEquals("name change 1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("name change 3", content3.getName());
for (Content entity : output) {
assertTrue(entity.getName().matches("content-\\d"));
}
}
@Test
public void testLockAndLoadMultiEntityByClassAndIds() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify we're getting the correct number of entities out
Collection<String> input = Arrays.asList(content1.getUuid(), content2.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(Content.class, input);
assertEquals(3, output.size());
// Note: the instances may be different here, but as long as they're equal (including UUID),
// we're okay.
for (Content expected : Arrays.asList(content1, content2, content3)) {
boolean found = false;
for (Content content : output) {
if (expected.equals(content)) {
assertFalse(found);
assertEquals(expected.getUuid(), content.getUuid());
found = true;
// We don't break here because we're verifying we didn't receive any duplicates.
}
}
assertTrue("expected entity was not found in output: " + expected.getId(), found);
}
}
@Test
public void testLockAndLoadMultiEntityByClassAndIdsRefreshRevertsPropertyChange() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify that lockAndLoad's refresh reverts our name changes only where applicable
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
Collection<String> input = Arrays.asList(content1.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(Content.class, input);
assertEquals(2, output.size());
assertTrue(output.contains(content1));
assertFalse(output.contains(content2));
assertTrue(output.contains(content3));
assertEquals("content-1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("content-3", content3.getName());
}
@Test
public void testLockAndLoadMultiEntityByClassAndIdsRefreshRevertsUnflushedMerge() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify that even a pending merge will be reverted
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
this.testContentCurator.merge(content1);
this.testContentCurator.merge(content2);
this.testContentCurator.merge(content3);
Collection<String> input = Arrays.asList(content1.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(Content.class, input);
assertEquals(2, output.size());
assertTrue(output.contains(content1));
assertFalse(output.contains(content2));
assertTrue(output.contains(content3));
assertEquals("content-1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("content-3", content3.getName());
}
@Test
public void testLockAndLoadMultiEntityByClassAndIdsRefreshRetainsFlushedChanged() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify that a flush will make the change persistent
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
this.testContentCurator.merge(content1);
this.testContentCurator.merge(content2);
this.testContentCurator.merge(content3);
this.testContentCurator.flush();
Collection<String> input = Arrays.asList(content1.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(Content.class, input);
assertEquals(2, output.size());
assertTrue(output.contains(content1));
assertFalse(output.contains(content2));
assertTrue(output.contains(content3));
assertEquals("name change 1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("name change 3", content3.getName());
}
@Test
public void testLockAndLoadMultiEntityByClassAndIdsRefreshIgnoresEvicted() {
Owner owner = this.createOwner();
Content content1 = this.createContent("c1", "content-1", owner);
Content content2 = this.createContent("c2", "content-2", owner);
Content content3 = this.createContent("c3", "content-3", owner);
// Verify evicted/detached elements aren't affected
content1.setName("name change 1");
content2.setName("name change 2");
content3.setName("name change 3");
this.testContentCurator.evict(content1);
this.testContentCurator.evict(content2);
this.testContentCurator.evict(content3);
Collection<String> input = Arrays.asList(content1.getUuid(), content3.getUuid());
Collection<Content> output = this.testContentCurator.lockAndLoadByIds(Content.class, input);
assertEquals(2, output.size());
assertFalse(output.contains(content1));
assertFalse(output.contains(content2));
assertFalse(output.contains(content3));
assertEquals("name change 1", content1.getName());
assertEquals("name change 2", content2.getName());
assertEquals("name change 3", content3.getName());
for (Content entity : output) {
assertTrue(entity.getName().matches("content-\\d"));
}
}
}