1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.dbunit;
22
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.assertj.core.api.Assertions.assertThatCode;
25 import static org.assertj.core.api.Assertions.catchThrowable;
26
27 import java.sql.Statement;
28
29 import org.dbunit.database.DatabaseConfig;
30 import org.dbunit.database.IDatabaseConnection;
31 import org.dbunit.database.rowcount.ClearRowCountCheckSystemProperties;
32 import org.dbunit.database.rowcount.RowCountDifference;
33 import org.dbunit.database.rowcount.UnexpectedRowCountException;
34 import org.dbunit.dataset.Column;
35 import org.dbunit.dataset.DefaultDataSet;
36 import org.dbunit.dataset.DefaultTable;
37 import org.dbunit.dataset.datatype.DataType;
38 import org.dbunit.operation.DatabaseOperation;
39 import org.dbunit.util.fileloader.DataFileLoader;
40 import org.dbunit.util.fileloader.FlatXmlDataFileLoader;
41 import org.junit.jupiter.api.AfterEach;
42 import org.junit.jupiter.api.BeforeEach;
43 import org.junit.jupiter.api.Test;
44
45
46
47
48
49
50
51
52 @ClearRowCountCheckSystemProperties
53 class DefaultPrepAndExpectedTestCaseRowCountCheckIT
54 {
55 private static final String EMPTY_TABLE = "EMPTY_TABLE";
56 private static final String SECOND_TABLE = "SECOND_TABLE";
57
58 private final DataFileLoader dataFileLoader = new FlatXmlDataFileLoader();
59
60 private IDatabaseConnection connection;
61 private DefaultPrepAndExpectedTestCase tc;
62
63 @BeforeEach
64 void setUp() throws Exception
65 {
66 final DatabaseEnvironment dbEnv = DatabaseEnvironment.getInstance();
67 connection = dbEnv.getConnection();
68 connection.getConfig().setFeature(DatabaseConfig.FEATURE_ROW_COUNT_CHECK, true);
69
70 final IDatabaseTester databaseTester = new DefaultDatabaseTester(connection);
71 databaseTester.setTearDownOperation(DatabaseOperation.DELETE_ALL);
72 tc = new DefaultPrepAndExpectedTestCase(dataFileLoader, databaseTester);
73 }
74
75 @AfterEach
76 void cleanUp() throws Exception
77 {
78 final DatabaseEnvironment dbEnv = DatabaseEnvironment.getInstance();
79 final IDatabaseConnection cleanupConnection = dbEnv.getConnection();
80 try
81 {
82 deleteAllRowsQuietly(cleanupConnection, EMPTY_TABLE);
83 deleteAllRowsQuietly(cleanupConnection, SECOND_TABLE);
84 } finally
85 {
86 closeQuietly(cleanupConnection);
87 }
88 }
89
90 @Test
91 void testPostTest_rowLeakedIntoUnlistedTable_throwsUnexpectedRowCountExceptionNamingIt()
92 throws Exception
93 {
94 tc.preTest();
95
96
97 insertRow(EMPTY_TABLE);
98
99 final Throwable thrown = catchThrowable(() -> tc.postTest());
100
101 assertThat(thrown)
102 .as("A row left behind in a table absent from prep/expected must fail the"
103 + " test with UnexpectedRowCountException.")
104 .isInstanceOf(UnexpectedRowCountException.class);
105 assertThat(differenceFor((UnexpectedRowCountException) thrown, EMPTY_TABLE).getDelta())
106 .as("A row was left behind, so the delta must be positive; not asserting the"
107 + " exact value, since EMPTY_TABLE is shared with other IT classes"
108 + " and may not start genuinely empty.")
109 .isPositive();
110 }
111
112 @Test
113 void testPostTest_referenceTableWronglyListedForCleanup_throwsUnexpectedRowCountExceptionWithNegativeDelta()
114 throws Exception
115 {
116
117 insertRow(SECOND_TABLE);
118
119
120
121 final Column[] columns = {new Column("COLUMN0", DataType.VARCHAR)};
122 tc.setPrepDs(new DefaultDataSet(new DefaultTable(SECOND_TABLE, columns)));
123
124 tc.preTest();
125
126 final Throwable thrown = catchThrowable(() -> tc.postTest());
127
128 assertThat(thrown)
129 .as("A reference table wrongly listed for cleanup must fail the test with"
130 + " UnexpectedRowCountException.")
131 .isInstanceOf(UnexpectedRowCountException.class);
132 assertThat(differenceFor((UnexpectedRowCountException) thrown, SECOND_TABLE).getDelta())
133 .as("Pre-existing rows were wiped, so the delta must be negative; not"
134 + " asserting the exact value, since SECOND_TABLE is shared with"
135 + " other IT classes and may carry more than this test's own row.")
136 .isNegative();
137 }
138
139 @Test
140 void testPostTest_leakedRowInExcludedTable_doesNotThrow() throws Exception
141 {
142 connection.getConfig().setProperty(
143 DatabaseConfig.PROPERTY_ROW_COUNT_CHECK_EXCLUDE_TABLES,
144 new String[] {EMPTY_TABLE});
145
146 tc.preTest();
147 insertRow(EMPTY_TABLE);
148
149 assertThatCode(() -> tc.postTest())
150 .as("A table matching an exclude pattern must never be reported, even"
151 + " though its count actually changed.")
152 .doesNotThrowAnyException();
153 }
154
155 private RowCountDifference differenceFor(final UnexpectedRowCountException exception,
156 final String tableName)
157 {
158 return exception.getDifferences().stream()
159 .filter(difference -> difference.getTableName().equalsIgnoreCase(tableName))
160 .findFirst()
161 .orElseThrow(() -> new AssertionError(
162 "No difference reported for table '" + tableName + "': "
163 + exception.getDifferences()));
164 }
165
166 private void insertRow(final String tableName) throws Exception
167 {
168 try (Statement statement = connection.getConnection().createStatement())
169 {
170 statement.execute(
171 "INSERT INTO " + tableName + " (COLUMN0) VALUES ('rowCountCheckIT')");
172 }
173 }
174
175 private static void deleteAllRowsQuietly(final IDatabaseConnection connection,
176 final String tableName)
177 {
178 try (Statement statement = connection.getConnection().createStatement())
179 {
180 statement.execute("DELETE FROM " + tableName);
181 } catch (final Exception e)
182 {
183
184 }
185 }
186
187 private static void closeQuietly(final IDatabaseConnection connection)
188 {
189 try
190 {
191 connection.close();
192 } catch (final Exception e)
193 {
194
195 }
196 }
197 }