/* * (c) Copyright 2010-2012 by Volker Bergmann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted under the terms of the * GNU General Public License (GPL). * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS, * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package org.databene.benerator.engine; import static org.junit.Assert.*; import java.util.Date; import java.util.List; import org.databene.benerator.primitive.datetime.CurrentDateTimeGenerator; import org.databene.benerator.test.BeneratorIntegrationTest; import org.databene.benerator.test.ConsumerMock; import org.databene.commons.CollectionUtil; import org.databene.commons.TimeUtil; import org.databene.jdbacl.DBUtil; import org.databene.jdbacl.dialect.HSQLUtil; import org.databene.model.data.Entity; import org.databene.platform.db.DBSystem; import org.junit.Before; import org.junit.Test; /** * Integration test for Benerator's database support.<br/><br/> * Created: 24.05.2010 17:52:58 * @since 0.6.2 * @author Volker Bergmann */ public class DatabaseIntegrationTest extends BeneratorIntegrationTest { private DBSystem db; private ConsumerMock consumer; @Before public void setUpDatabase() throws Exception { DBUtil.resetMonitors(); consumer = new ConsumerMock(true); context.set("cons", consumer); String dbUrl = HSQLUtil.getInMemoryURL(getClass().getSimpleName()); db = new DBSystem("db", dbUrl, HSQLUtil.DRIVER, HSQLUtil.DEFAULT_USER, HSQLUtil.DEFAULT_PASSWORD, context.getDataModel()); db.setSchema("PUBLIC"); db.execute("drop table referer if exists"); db.execute("drop table referee if exists"); db.execute("create table referee (id int, n int, primary key (id))"); db.execute("insert into referee (id, n) values (2, 2)"); db.execute("insert into referee (id, n) values (3, 3)"); db.execute( "create table referer ( " + " id int," + " referee_id int," + " the_date date," + " primary key (id)," + " constraint referee_fk foreign key (referee_id) references referee (id))"); context.set("db", db); context.getDataModel().addDescriptorProvider(db); } // generation of database references ------------------------------------------------------------------------------- @Test public void testScriptResolution() { context.set("tblName", "referee"); parseAndExecute("<evaluate id='refCount' target='db'>{'select count(*) from ' + tblName}</evaluate>"); assertEquals(2, ((Number) context.get("refCount")).intValue()); closeAndCheckCleanup(); } @Test public void testDbRef_default_nullable() { parseAndExecute("<generate type='referer' count='3' consumer='cons'/>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); for (Entity product : products) { assertNull(product.get("referee_id")); } closeAndCheckCleanup(); } @Test public void testDbRef_default_not_null_defaultOneToOne() { context.setDefaultOneToOne(true); parseAndExecute( "<generate type='referer' consumer='cons'>" + " <reference name='referee_id' nullable='false' source='db' />" + // TODO v0.8 should source='db' be optional? "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); for (Entity product : products) { int ref = (Integer) product.get("referee_id"); assertTrue(ref == 2 || ref == 3); } closeAndCheckCleanup(); } @Test public void testDbRef_default_not_null_defaultManyToOne() { context.setDefaultOneToOne(false); parseAndExecute( "<generate type='referer' count='3' consumer='cons'>" + " <reference name='referee_id' nullable='false' source='db' />" + // TODO v0.8 should source='db' be optional? "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); for (Entity product : products) { int ref = (Integer) product.get("referee_id"); assertTrue(ref == 2 || ref == 3); } closeAndCheckCleanup(); } // Test for bug #3025805 @Test public void testDbRef_distribution() { parseAndExecute( "<generate type='referer' count='3' consumer='cons'>" + " <reference name='referee_id' targetType='referee' source='db' distribution='new org.databene.benerator.distribution.function.ExponentialFunction(-0.5)' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); for (Entity product : products) { int ref = (Integer) product.get("referee_id"); assertTrue(ref == 2 || ref == 3); } closeAndCheckCleanup(); } @Test public void testDbRef_values() { parseAndExecute( "<generate type='referer' count='3' consumer='cons'>" + " <reference name='referee_id' values='1' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); for (Entity product : products) assertEquals(1, product.get("referee_id")); closeAndCheckCleanup(); } @Test public void testDbRef_constant() { parseAndExecute( "<generate type='referer' count='3' consumer='cons'>" + " <reference name='referee_id' constant='1' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); for (Entity product : products) { assertEquals(1, product.get("referee_id")); } closeAndCheckCleanup(); } @Test public void testDbRef_constant_script() { context.set("rid", 2); parseAndExecute( "<generate type='referer' count='3' consumer='cons'>" + " <reference name='referee_id' constant='{rid}' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); for (Entity product : products) { assertEquals(2, product.get("referee_id")); } closeAndCheckCleanup(); } @Test public void testDbRef_attribute_constant_script() { context.set("rid", 2); parseAndExecute( "<generate type='referer' count='3' consumer='cons'>" + " <attribute name='referee_id' constant='{rid}' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); for (Entity product : products) assertEquals(2, product.get("referee_id")); closeAndCheckCleanup(); } @Test public void testDbRef_script() { context.set("rid", 2); parseAndExecute( "<generate type='referer' count='3' consumer='cons'>" + " <reference name='referee_id' script='rid + 1' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); for (Entity product : products) assertEquals(3, product.get("referee_id")); closeAndCheckCleanup(); } @Test public void testDbRef_explicit_selector() { context.set("key", 2); parseAndExecute( "<generate type='referer' consumer='cons'>" + " <reference name='referee_id' source='db' " + " selector=\"{ftl:select id from referee where id=${key}}\" " + " nullable='false'/>" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(1, products.size()); assertEquals(2, products.get(0).get("referee_id")); closeAndCheckCleanup(); } @Test public void testDbRef_explicit_subSelector() { context.set("key", 2); parseAndExecute( "<generate type='referer' consumer='cons' count='3'>" + " <reference name='referee_id' source='db' " + " subSelector='{ftl:select id from referee order by id}' " + " nullable='false'/>" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); assertEquals(2, products.get(0).get("referee_id")); assertEquals(2, products.get(1).get("referee_id")); assertEquals(2, products.get(2).get("referee_id")); closeAndCheckCleanup(); } @Test public void testDbRef_entity_selector() { context.set("key", 2); parseAndExecute( "<generate type='referer' consumer='cons'>" + " <reference name='referee_id' source='db' " + " selector='{ftl:id=${key}}' " + " nullable='false'/>" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(1, products.size()); assertEquals(2, products.get(0).get("referee_id")); closeAndCheckCleanup(); } // iteration through database entries ------------------------------------------------------------------------------ @Test public void testDb_iterate_this() { parseAndExecute( "<iterate type='referee' source='db' consumer='cons'>" + " <attribute name='n' source='db' " + " selector=\"{{'select n+1 from referee where id = ' + this.id}}\" cyclic='true' />" + "</iterate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(3, products.get(0).get("n")); assertEquals(4, products.get(1).get("n")); closeAndCheckCleanup(); } // date generation ------------------------------------------------------------------------------------------------- @Test public void test_datetime_resolution() { parseAndExecute( "<generate type='referer' count='3' consumer='cons'>" + " <attribute name='the_date' generator='" + CurrentDateTimeGenerator.class.getName() + "' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(3, products.size()); for (Entity entity : products) assertTrue(TimeUtil.isNow(((Date) entity.get("the_date")).getTime(), 2000)); closeAndCheckCleanup(); } // transaction control --------------------------------------------------------------------------------------------- @Test public void testTx_default() { context.setDefaultOneToOne(false); db.execute("delete from referee"); parseAndExecute( "<generate type='referee' count='2' consumer='cons'>" + " <generate type='referer' count='2' consumer='cons'>" + " </generate>" + "</generate>"); // check generated products List<Entity> products = getConsumedEntities(); assertEquals(6, products.size()); // check transactions List<String> expectedInvocations = CollectionUtil.toList( ConsumerMock.START_CONSUMING, // referee #1 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #1 ConsumerMock.FLUSH, ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #2 ConsumerMock.FLUSH, ConsumerMock.FINISH_CONSUMING, ConsumerMock.FLUSH, // referee #1 ConsumerMock.START_CONSUMING, // referee #2 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #3 ConsumerMock.FLUSH, ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #4 ConsumerMock.FLUSH, ConsumerMock.FINISH_CONSUMING, ConsumerMock.FLUSH // referee #2 ); assertEquals(expectedInvocations, consumer.invocations); closeAndCheckCleanup(); } @Test public void testTx_subPageSize0() { context.setDefaultOneToOne(false); db.execute("delete from referee"); parseAndExecute( "<generate type='referee' count='2' consumer='cons'>" + " <generate type='referer' count='2' pageSize='0' consumer='cons'>" + " </generate>" + "</generate>"); // check generated products List<Entity> products = getConsumedEntities(); assertEquals(6, products.size()); // check transactions List<String> expectedInvocations = CollectionUtil.toList( ConsumerMock.START_CONSUMING, // referee #1 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #1 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #2 ConsumerMock.FINISH_CONSUMING, ConsumerMock.FLUSH, // referee #1 ConsumerMock.START_CONSUMING, // referee #2 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #3 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #4 ConsumerMock.FINISH_CONSUMING, ConsumerMock.FLUSH // referee #2 ); assertEquals(expectedInvocations, consumer.invocations); closeAndCheckCleanup(); } @Test public void testTx_allPageSizes0() { context.setDefaultOneToOne(false); db.execute("delete from referee"); parseAndExecute( "<generate type='referee' count='2' pageSize='0' consumer='cons'>" + " <generate type='referer' count='2' pageSize='0' consumer='cons'>" + " </generate>" + "</generate>"); // check generated products List<Entity> products = getConsumedEntities(); assertEquals(6, products.size()); // check transactions List<String> expectedInvocations = CollectionUtil.toList( ConsumerMock.START_CONSUMING, // referee #1 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #1 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #2 ConsumerMock.FINISH_CONSUMING, // referee #1 ConsumerMock.START_CONSUMING, // referee #2 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #3 ConsumerMock.START_CONSUMING, ConsumerMock.FINISH_CONSUMING, // referer #4 ConsumerMock.FINISH_CONSUMING // referee #2 ); assertEquals(expectedInvocations, consumer.invocations); closeAndCheckCleanup(); } // selector resolution --------------------------------------------------------------------------------------------- @Test public void testStaticEntitySelector_partial() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <variable name='e' type='referee' source='db' subSelector='id=3' />" + " <reference name='referee_id' script='e.id' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(3, products.get(0).get("referee_id")); assertEquals(3, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testStaticEntitySelector_complete() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <variable name='e' type='referee' source='db' subSelector='select * from referee where id=3' />" + " <reference name='referee_id' script='e.id' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(3, products.get(0).get("referee_id")); assertEquals(3, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testDynamicEntitySelector_partial() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <variable name='n' type='int' min='2' max='3' " + " distribution='new org.databene.benerator.distribution.sequence.StepSequence(-1)'/>" + " <variable name='e' type='referee' source='db' subSelector=\"{{'id=' + n}}\" />" + " <reference name='referee_id' script='e.id' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(3, products.get(0).get("referee_id")); assertEquals(2, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testDynamicEntitySelector_complete() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <variable name='n' type='int' min='2' max='3' " + " distribution='new org.databene.benerator.distribution.sequence.StepSequence(-1)'/>" + " <variable name='e' type='referee' source='db' subSelector=\"{{'select * from referee where id=' + n}}\" />" + " <reference name='referee_id' script='e.id' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(3, products.get(0).get("referee_id")); assertEquals(2, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testStaticArraySelector() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <variable name='a' source='db' subSelector='select id, n from referee where n=3' />" + " <reference name='referee_id' script='a[0]' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(3, products.get(0).get("referee_id")); assertEquals(3, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testDynamicArraySelector() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <variable name='n' type='int' min='2' max='3' distribution='new org.databene.benerator.distribution.sequence.StepSequence(-1)'/>" + " <variable name='a' source='db' subSelector=\"{{'select id, n from referee where id=' + n}}\"/>" + " <reference name='referee_id' script='a[0]' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(3, products.get(0).get("referee_id")); assertEquals(2, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testStaticValueSelector() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <variable name='v' type='int' min='2' distribution='increment' />" + " <reference name='referee_id' source='db' " + " subSelector='select n from referee where id=3' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(3, products.get(0).get("referee_id")); assertEquals(3, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testDynamicValueSelectorUsingContextValue() { context.set("key", 2); parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <id name='id' type='int' min='2' distribution='increment' />" + " <reference name='referee_id' source='db' " + " subSelector=\"{{'select n from referee where id=' + key}}\" />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(2, products.get(0).get("referee_id")); assertEquals(2, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testDynamicValueSelectorUsingVariable() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <variable name='v' type='int' min='2' distribution='increment' />" + " <reference name='referee_id' source='db' " + " subSelector=\"{{'select n from referee where id=' + v}}\" />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(2, products.get(0).get("referee_id")); assertEquals(3, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testDynamicValueSelectorUsingAttribute() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <id name='id' type='int' min='2' distribution='increment' />" + " <reference name='referee_id' source='db' " + " subSelector=\"{{'select n from referee where id=' + referer.id}}\" />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(2, products.get(0).get("referee_id")); assertEquals(3, products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testStaticValueSelectorWithEmptyResultSet() { parseAndExecute( "<generate type='referer' maxCount='2' consumer='cons'>" + " <reference name='referee_id' source='db' " + " subSelector='select id from referee where id=5' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(0, products.size()); closeAndCheckCleanup(); } @Test public void testStaticValueSelectorWithNullResult() { parseAndExecute( "<generate type='referer' count='2' consumer='cons'>" + " <attribute name='referee_id' source='db' " + " subSelector='select null from referee where id=2' />" + "</generate>"); List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertNull(products.get(0).get("referee_id")); assertNull(products.get(1).get("referee_id")); closeAndCheckCleanup(); } @Test public void testUpdater() throws Exception { parseAndExecute( "<iterate type='referee' source='db' consumer='db.updater(), cons'>" + " <attribute name='n' constant='9' />" + "</iterate>"); // check entities sent to consumers List<Entity> products = getConsumedEntities(); assertEquals(2, products.size()); assertEquals(9, products.get(0).get("n")); assertEquals(9, products.get(1).get("n")); // check entities in database List<Object[]> storedData = DBUtil.query("select id, n from referee order by id", db.getConnection()); assertEquals(2, storedData.size()); assertEqualArrays(new Object[] { 2, 9 }, storedData.get(0)); assertEqualArrays(new Object[] { 3, 9 }, storedData.get(1)); closeAndCheckCleanup(); } @Test(expected = RuntimeException.class) public void testUpdateOnNonExistingPK() throws Exception { parseAndExecute( "<iterate type='referee' source='db' selector='id=2' consumer='db.updater(), cons'>" + " <attribute name='id' constant='11' />" + "</iterate>"); } // private helpers ------------------------------------------------------------------------------------------------- @SuppressWarnings({ "unchecked", "rawtypes" }) protected List<Entity> getConsumedEntities() { return (List) consumer.getProducts(); } private void closeAndCheckCleanup() { context.close(); db.close(); DBUtil.assertAllDbResourcesClosed(true); } }