1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.dbunit.database;
22
23 import static org.assertj.core.api.Assertions.assertThat;
24 import static org.junit.jupiter.api.Assertions.assertThrows;
25 import static org.junit.jupiter.api.Assertions.fail;
26
27 import java.util.Arrays;
28
29 import org.dbunit.AbstractDatabaseIT;
30 import org.junit.jupiter.api.Assumptions;
31 import org.dbunit.DdlExecutor;
32 import org.dbunit.H2Environment;
33 import org.dbunit.dataset.FilteredDataSet;
34 import org.dbunit.dataset.IDataSet;
35 import org.dbunit.dataset.filter.ITableFilter;
36 import org.dbunit.dataset.filter.IncludeTableFilter;
37 import org.dbunit.ext.h2.H2Connection;
38 import org.dbunit.testutil.TestUtils;
39 import org.junit.jupiter.api.Test;
40
41 import java.sql.Connection;
42
43
44
45
46
47
48 class DatabaseSequenceFilterIT extends AbstractDatabaseIT
49 {
50
51
52
53
54
55
56
57
58 private void refreshConnection() throws Exception
59 {
60 _connection.close();
61 _connection = getDatabaseTester().getConnection();
62 setUpDatabaseConfig(_connection.getConfig());
63 }
64
65 @Test
66 void testGetTableNames_withFkConstrainedTables_returnsDependencyOrderedNames() throws Exception
67 {
68 final String[] testTableNames =
69 {"A", "B", "C", "D", "E", "F", "G", "H"};
70 final String[] expectedNoFilter =
71 {"A", "B", "C", "D", "E", "F", "G", "H",};
72 final String[] expectedFiltered =
73 {"D", "A", "F", "C", "G", "E", "H", "B",};
74
75 DdlExecutor.dropTables(_connection.getConnection(), "B", "C", "E",
76 "H", "F", "G", "A", "D");
77 DdlExecutor.executeDdlFile(TestUtils.getFile("sql/hypersonic_fk.sql"),
78 _connection.getConnection(), false);
79 try
80 {
81 final IDataSet allTables = _connection.createDataSet();
82 final IDataSet databaseDataset =
83 new FilteredDataSet(new IncludeTableFilter(testTableNames),
84 allTables);
85 final String[] actualNoFilter = databaseDataset.getTableNames();
86 assertThat(actualNoFilter).as("no filter")
87 .usingElementComparator(String.CASE_INSENSITIVE_ORDER)
88 .containsExactly(expectedNoFilter);
89
90 final ITableFilter filter =
91 new DatabaseSequenceFilter(_connection);
92 final IDataSet filteredDataSet =
93 new FilteredDataSet(filter, databaseDataset);
94 final String[] actualFiltered = filteredDataSet.getTableNames();
95 assertThat(actualFiltered).as("filtered")
96 .usingElementComparator(String.CASE_INSENSITIVE_ORDER)
97 .containsExactly(expectedFiltered);
98 }
99 finally
100 {
101 DdlExecutor.dropTables(_connection.getConnection(), "B", "C", "E",
102 "H", "F", "G", "A", "D");
103 refreshConnection();
104 }
105 }
106
107 @Test
108 void testGetTableNames_withCyclicFkConstraints_throwsCyclicTablesDependencyException() throws Exception
109 {
110 final String[] testTableNames = {"A", "B", "C", "D", "E"};
111 final String[] expectedNoFilter = {"A", "B", "C", "D", "E",};
112
113 DdlExecutor.dropTables(_connection.getConnection(), "A", "B", "C",
114 "D", "E");
115 DdlExecutor.executeDdlFile(
116 TestUtils.getFile("sql/hypersonic_cyclic.sql"),
117 _connection.getConnection(), false);
118 try
119 {
120 final IDataSet allTables = _connection.createDataSet();
121 final IDataSet databaseDataset =
122 new FilteredDataSet(new IncludeTableFilter(testTableNames),
123 allTables);
124 final String[] actualNoFilter = databaseDataset.getTableNames();
125 assertThat(actualNoFilter).as("no filter")
126 .usingElementComparator(String.CASE_INSENSITIVE_ORDER)
127 .containsExactly(expectedNoFilter);
128
129 assertThrows(CyclicTablesDependencyException.class, () -> {
130 final ITableFilter filter =
131 new DatabaseSequenceFilter(_connection);
132 final IDataSet filteredDataSet =
133 new FilteredDataSet(filter, databaseDataset);
134 filteredDataSet.getTableNames();
135 fail("Should not be here!");
136 }, "Expected CyclicTablesDependencyException was not raised");
137 }
138 finally
139 {
140 DdlExecutor.dropTables(_connection.getConnection(), "A", "B", "C",
141 "D", "E");
142 refreshConnection();
143 }
144 }
145
146 @Test
147 void testGetTableNames_withCyclicFkConstraintsAndSkipCycleCheckFeatureEnabled_doesNotThrow()
148 throws Exception
149 {
150 final String[] testTableNames = {"A", "B", "C", "D", "E"};
151
152 DdlExecutor.dropTables(_connection.getConnection(), "A", "B", "C",
153 "D", "E");
154 DdlExecutor.executeDdlFile(
155 TestUtils.getFile("sql/hypersonic_cyclic.sql"),
156 _connection.getConnection(), false);
157 try
158 {
159 _connection.getConfig().setFeature(DatabaseConfig.FEATURE_SKIP_CYCLE_CHECK, true);
160 final IDataSet allTables = _connection.createDataSet();
161 final IDataSet databaseDataset =
162 new FilteredDataSet(new IncludeTableFilter(testTableNames),
163 allTables);
164
165 final ITableFilter filter = new DatabaseSequenceFilter(_connection);
166 final IDataSet filteredDataSet =
167 new FilteredDataSet(filter, databaseDataset);
168 final String[] actualFiltered = filteredDataSet.getTableNames();
169 final String[] expectedFiltered = {"B", "A", "C", "D", "E"};
170
171 assertThat(actualFiltered)
172 .as("FEATURE_SKIP_CYCLE_CHECK must let the A/C/D/E cycle through without "
173 + "throwing, sorting independent table B before the cycle it is "
174 + "really depended on by (via C's FK), and falling back to input "
175 + "order (A, C, D, E) for the cycle's own members.")
176 .usingElementComparator(String.CASE_INSENSITIVE_ORDER)
177 .containsExactly(expectedFiltered);
178 }
179 finally
180 {
181 DdlExecutor.dropTables(_connection.getConnection(), "A", "B", "C",
182 "D", "E");
183 refreshConnection();
184 }
185 }
186
187 @Test
188 void testGetTableNames_withCaseSensitiveFeatureEnabled_returnsMixedCaseTableNames() throws Exception
189 {
190 final java.sql.DatabaseMetaData dbMeta =
191 _connection.getConnection().getMetaData();
192 Assumptions.assumeTrue(
193 dbMeta.supportsMixedCaseQuotedIdentifiers(),
194 "Skip: database does not treat quoted identifiers as case-sensitive.");
195 Assumptions.assumeTrue(
196 "\"".equals(dbMeta.getIdentifierQuoteString()),
197 "Skip: database does not use ANSI double-quote identifier syntax.");
198 Assumptions.assumeFalse(
199 dbMeta.storesLowerCaseIdentifiers(),
200 "Skip: database stores unquoted identifiers in lowercase.");
201 final String[] testTableNames = {"MixedCaseTable", "UPPER_CASE_TABLE"};
202 final String[] expectedNoFilter =
203 {"MixedCaseTable", "UPPER_CASE_TABLE"};
204 final String[] expectedFiltered =
205 {"MixedCaseTable", "UPPER_CASE_TABLE"};
206
207 DdlExecutor.dropTables(_connection.getConnection(), "UPPER_CASE_TABLE");
208 try
209 {
210 DdlExecutor.executeSql(_connection.getConnection(),
211 "DROP TABLE \"MixedCaseTable\"");
212 }
213 catch (final Exception ignored)
214 {
215 logger.debug("Pre-drop of MixedCaseTable ignored: {}",
216 ignored.getMessage());
217 }
218 DdlExecutor.executeDdlFile(
219 TestUtils.getFile("sql/hypersonic_case_sensitive_test.sql"),
220 _connection.getConnection(), false);
221 try
222 {
223 _connection.getConfig().setProperty(
224 DatabaseConfig.FEATURE_CASE_SENSITIVE_TABLE_NAMES,
225 Boolean.TRUE);
226
227 final IDataSet allTables = _connection.createDataSet();
228 final IDataSet databaseDataset =
229 new FilteredDataSet(new IncludeTableFilter(testTableNames),
230 allTables);
231 final String[] actualNoFilter = databaseDataset.getTableNames();
232 assertThat(Arrays.asList(actualNoFilter)).as("no filter")
233 .isEqualTo(Arrays.asList(expectedNoFilter));
234
235 final ITableFilter filter =
236 new DatabaseSequenceFilter(_connection);
237 final IDataSet filteredDataSet =
238 new FilteredDataSet(filter, databaseDataset);
239 final String[] actualFiltered = filteredDataSet.getTableNames();
240 assertThat(Arrays.asList(actualFiltered)).as("filtered")
241 .isEqualTo(Arrays.asList(expectedFiltered));
242 }
243 finally
244 {
245 _connection.getConfig().setProperty(
246 DatabaseConfig.FEATURE_CASE_SENSITIVE_TABLE_NAMES,
247 Boolean.FALSE);
248 DdlExecutor.dropTables(_connection.getConnection(),
249 "UPPER_CASE_TABLE");
250 try
251 {
252 DdlExecutor.executeSql(_connection.getConnection(),
253 "DROP TABLE \"MixedCaseTable\"");
254 }
255 catch (final Exception ignored)
256 {
257 logger.debug("Post-drop of MixedCaseTable ignored: {}",
258 ignored.getMessage());
259 }
260 refreshConnection();
261 }
262 }
263
264
265
266
267
268
269
270 @Test
271 void testGetTableNames_withMultiSchemaTables_respectsForeignKeyOrder() throws Exception
272 {
273 final Connection jdbcConnection =
274 H2Environment.createJdbcConnection("test");
275 DdlExecutor.executeDdlFile(
276 TestUtils.getFile("sql/h2_multischema_fk_test.sql"),
277 jdbcConnection);
278 final IDatabaseConnection connection = new H2Connection(jdbcConnection, null);
279 connection.getConfig().setProperty(
280 DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, Boolean.TRUE);
281
282 final IDataSet databaseDataset = connection.createDataSet();
283 final ITableFilter filter = new DatabaseSequenceFilter(connection);
284 final IDataSet filteredDataSet =
285 new FilteredDataSet(filter, databaseDataset);
286
287 final String[] actualNoFilter = databaseDataset.getTableNames();
288 assertThat(actualNoFilter).hasSize(2);
289 assertThat(actualNoFilter[0]).isEqualTo("A.FOO");
290 assertThat(actualNoFilter[1]).isEqualTo("B.BAR");
291
292 final String[] actualFiltered = filteredDataSet.getTableNames();
293 assertThat(actualFiltered).hasSize(2);
294 assertThat(actualFiltered[0]).isEqualTo("A.FOO");
295 assertThat(actualFiltered[1]).isEqualTo("B.BAR");
296 }
297 }