From 00a56a188b599ca0e243bbb0b141ccfca06e6e52 Mon Sep 17 00:00:00 2001 From: Chris Cranford Date: Wed, 6 Jun 2018 14:54:01 -0400 Subject: [PATCH] HHH-12607 - Added test case. --- .../envers/test/ElementCollectionTest.java | 180 ++++++++++++++++++ .../envers/test/tools/TablePrinter.java | 111 +++++++++++ 2 files changed, 291 insertions(+) create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/ElementCollectionTest.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/tools/TablePrinter.java diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/ElementCollectionTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/ElementCollectionTest.java new file mode 100644 index 0000000000..ee9db31351 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/ElementCollectionTest.java @@ -0,0 +1,180 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.envers.test; + +import java.io.Serializable; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.persistence.ElementCollection; +import javax.persistence.Embeddable; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Tuple; + +import org.hibernate.envers.Audited; +import org.hibernate.envers.strategy.ValidityAuditStrategy; +import org.hibernate.envers.test.tools.TablePrinter; +import org.junit.Test; + +import org.hibernate.testing.TestForIssue; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +/** + * @author Chris Cranford + */ +@TestForIssue(jiraKey = "HHH-12607") +public class ElementCollectionTest extends BaseEnversJPAFunctionalTestCase { + + @Entity(name = "TestEntity") + @Audited + public static class TestEntity { + @Id + private Integer id; + + @ElementCollection + private Map embs1; + + public TestEntity() { + + } + + public TestEntity(Integer id) { + this.id = id; + } + + public Map getEmbs1() { + return embs1; + } + + public void setEmbs1(Map embs1) { + this.embs1 = embs1; + } + } + + @Embeddable + public static class Emb implements Serializable { + private String value; + + public Emb() { + + } + + public Emb(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { TestEntity.class }; + } + + @Test + @Priority(10) + public void initData() { + System.out.println( "************************************************************ " ); + System.out.println( "REV1 - Insert 2 rows into collection" ); + doInJPA( this::entityManagerFactory, entityManager -> { + TestEntity e = new TestEntity( 1 ); + e.setEmbs1( new HashMap<>() ); + e.getEmbs1().put( "a", new Emb( "value1" ) ); + e.getEmbs1().put( "b", new Emb( "value2" ) ); + entityManager.persist( e ); + } ); + + TablePrinter.print( this::entityManagerFactory, "TestEntity_AUD", "TestEntity_embs1_AUD" ); + + System.out.println( "************************************************************ " ); + System.out.println( "REV2 - Replace A with value1 as A with value 3 in collection" ); + doInJPA( this::entityManagerFactory, entityManager -> { + TestEntity e = entityManager.find( TestEntity.class, 1 ); + e.getEmbs1().put( "a", new Emb( "value3" ) ); + } ); + + // ValidityAuditStrategy + // always 4 values when equals/hashCode is implemented + // +-----+---------+---------------+-----------+--------+--------+ + // | REV | REVTYPE | TESTENTITY_ID | EMBS1_KEY | REVEND | VALUE | + // +-----+---------+---------------+-----------+--------+--------+ + // | 1 | 0 | 1 | a | 2 | value1 | + // | 1 | 0 | 1 | b | null | value2 | + // | 2 | 0 | 1 | a | null | value3 | + // | 2 | 2 | 1 | a | null | value1 | + // +-----+---------+---------------+-----------+--------+--------+ + + // DefaultAuditStrategy + // always 4 values when equals/hashCode is implemented + // +-----+---------+---------------+-----------+--------+ + // | REV | REVTYPE | TESTENTITY_ID | EMBS1_KEY | VALUE | + // +-----+---------+---------------+-----------+--------+ + // | 1 | 0 | 1 | a | value1 | + // | 1 | 0 | 1 | b | value2 | + // | 2 | 0 | 1 | a | value3 | + // | 2 | 2 | 1 | a | value1 | + // +-----+---------+---------------+-----------+--------+ + + TablePrinter.print( this::entityManagerFactory, "TestEntity_AUD", "TestEntity_embs1_AUD" ); + + if ( ValidityAuditStrategy.class.getName().equals( getAuditStrategy() ) ) { + System.out.println( "************************************************************ " ); + doInJPA( this::entityManagerFactory, entityManager -> { + List results = entityManager + .createNativeQuery( "SELECT COUNT(1) FROM TestEntity_embs1_AUD WHERE REVEND IS NULL", Tuple.class ) + .getResultList(); + assertEquals( 1, results.size() ); + assertEquals( BigInteger.valueOf( 3 ), results.get( 0 ).get( 0 ) ); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + List results = entityManager + .createNativeQuery( "SELECT COUNT(1) FROM TestEntity_embs1_AUD", Tuple.class ) + .getResultList(); + assertEquals( 1, results.size() ); + assertEquals( BigInteger.valueOf( 4 ), results.get( 0 ).get( 0 ) ); + } ); + } + else { + System.out.println( "************************************************************ " ); + doInJPA( this::entityManagerFactory, entityManager -> { + List results = entityManager + .createNativeQuery( "SELECT COUNT(1) FROM TestEntity_embs1_AUD", Tuple.class ) + .getResultList(); + assertEquals( 1, results.size() ); + + assertEquals( BigInteger.valueOf( 4 ), results.get( 0 ).get( 0 ) ); + } ); + } + } + + @Test + public void testRevisionHistory1() { + TestEntity e = getAuditReader().find( TestEntity.class, 1, 1 ); + assertEquals( 2, e.getEmbs1().size() ); + assertEquals( "value1", e.getEmbs1().get( "a" ).getValue() ); + assertEquals( "value2", e.getEmbs1().get( "b" ).getValue() ); + } + + @Test + public void testRevisionHistory2() { + TestEntity e = getAuditReader().find( TestEntity.class, 1, 2 ); + assertEquals( 2, e.getEmbs1().size() ); + assertEquals( "value3", e.getEmbs1().get( "a" ).getValue() ); + assertEquals( "value2", e.getEmbs1().get( "b" ).getValue() ); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/tools/TablePrinter.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/tools/TablePrinter.java new file mode 100644 index 0000000000..22d526595f --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/tools/TablePrinter.java @@ -0,0 +1,111 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.envers.test.tools; + +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Supplier; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Tuple; +import javax.persistence.TupleElement; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Chris Cranford + */ +public class TablePrinter { + + private static Map buildColumnSizesFromRows(List rows) { + Map columnSizes = new TreeMap<>(); + for ( int i = 0; i < rows.size(); ++i ) { + Tuple row = rows.get( i ); + // on first row, handle columns + if ( i == 0 ) { + for ( int j = 0; j < row.getElements().size(); ++j ) { + TupleElement element = row.getElements().get( j ); + columnSizes.put( j, element.getAlias().length() ); + } + } + // handle values + for ( int j = 0; j < row.getElements().size(); ++j ) { + Object value = row.get( j ); + int length = ( "" + value ).trim().length(); + if ( length > columnSizes.get( j ) ) { + columnSizes.put( j, length ); + } + } + } + return columnSizes; + } + + private static void writeColumn(int columnIndex, int columns, int length, String value) { + System.out.print( "| " + String.format( "%1$-" + length + "s", value ) + " " ); + if ( columnIndex + 1 >= columns ) { + System.out.println( "|" ); + } + } + + private static String buildSplitter(List> columns, Map columnSizes) { + StringBuilder sb = new StringBuilder(); + for ( int i = 0; i < columns.size(); ++i ) { + sb.append( "+-" + String.format( "%1$-" + columnSizes.get( i ) + "s", "" ).replace( ' ', '-' ) + '-' ); + if ( i + 1 >= columns.size() ) { + sb.append( '+' ); + } + } + return sb.toString(); + } + + private static void printTableFromRows(List rows) { + if ( rows.size() > 0 ) { + Map columnSizes = buildColumnSizesFromRows( rows ); + String rowSplitter = null; + for ( int i = 0; i < rows.size(); ++i ) { + Tuple row = rows.get( i ); + List> columns = row.getElements(); + + if ( rowSplitter == null ) { + rowSplitter = buildSplitter( columns, columnSizes ); + } + + // handle columns on first row + if ( i == 0 ) { + System.out.println( rowSplitter ); + for ( int j = 0; j < columns.size(); ++j ) { + writeColumn( j, columns.size(), columnSizes.get( j ), columns.get( j ).getAlias() ); + } + System.out.println( rowSplitter ); + } + + // handle column values + for ( int j = 0; j < columns.size(); ++j ) { + final String value = row.get( j ) + "".trim(); + writeColumn( j, columns.size(), columnSizes.get( j ), value ); + } + } + + System.out.println( rowSplitter ); + } + } + + public static void print(EntityManager entityManager, String... tables) { + for ( String table : tables ) { + List rows = entityManager.createNativeQuery( "SELECT * FROM " + table + " ORDER BY REV", Tuple.class ).getResultList(); + printTableFromRows( rows ); + } + } + + public static void print(Supplier factorySupplier, String... tables) { + doInJPA( factorySupplier, entityManager -> { + print( entityManager, tables ); + } ); + } +}