1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.migration;
17
18 import static org.junit.jupiter.api.Assertions.assertEquals;
19 import static org.junit.jupiter.api.Assertions.assertFalse;
20 import static org.junit.jupiter.api.Assertions.assertNotEquals;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertTrue;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.PrintWriter;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.nio.file.StandardCopyOption;
31 import java.sql.Connection;
32 import java.sql.ResultSet;
33 import java.sql.Statement;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.List;
37 import java.util.Properties;
38 import java.util.Scanner;
39 import java.util.TreeSet;
40
41 import org.apache.ibatis.migration.io.Resources;
42 import org.apache.ibatis.migration.utils.TestUtil;
43 import org.junit.jupiter.api.BeforeAll;
44 import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
45 import org.junit.jupiter.api.Order;
46 import org.junit.jupiter.api.Test;
47 import org.junit.jupiter.api.TestMethodOrder;
48
49 import uk.org.webcompere.systemstubs.SystemStubs;
50
51 @TestMethodOrder(OrderAnnotation.class)
52 class MigratorTest {
53
54 private static File dir;
55
56 private static Properties env;
57
58 @BeforeAll
59 static void setup() throws IOException {
60 dir = Resources.getResourceAsFile("org/apache/ibatis/migration/example");
61 env = Resources.getResourceAsProperties("org/apache/ibatis/migration/example/environments/development.properties");
62 }
63
64 @Test
65 @Order(1)
66 void testBootstrapCommand() throws Exception {
67 String output = SystemStubs.tapSystemOut(() -> {
68 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "bootstrap", "--env=development"));
69 });
70 assertFalse(output.contains("FAILURE"));
71 assertTrue(output.contains("-- // Bootstrap.sql"));
72 }
73
74 @Test
75 @Order(2)
76 void testStatusContainsNoPendingEntriesUsingStatusShorthand() throws Exception {
77 String output = SystemStubs.tapSystemOut(() -> {
78 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "sta"));
79 });
80 assertFalse(output.contains("FAILURE"));
81 assertTrue(output.contains("...pending..."));
82 }
83
84
85 @Test
86 @Order(3)
87 void testUpCommandWithSpecifiedSteps() throws Exception {
88 String output = SystemStubs.tapSystemOut(() -> {
89 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "up", "3000"));
90 });
91 assertFalse(output.contains("FAILURE"));
92 }
93
94 @Test
95 @Order(4)
96 void assertAuthorEmailContainsPlaceholder() throws Exception {
97 try (Connection conn = TestUtil.getConnection(env); Statement stmt = conn.createStatement();
98 ResultSet rs = stmt.executeQuery("select EMAIL from author where id = 1")) {
99 assertTrue(rs.next());
100 assertEquals("jim@${url}", rs.getString("EMAIL"));
101 }
102 }
103
104 @Test
105 @Order(5)
106 void testDownCommandGiven2Steps() throws Exception {
107 testStatusContainsNoPendingMigrations();
108 String output = SystemStubs.tapSystemOut(() -> {
109 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "down", "2"));
110 });
111 assertFalse(output.contains("FAILURE"));
112 testStatusContainsPendingMigrations();
113 }
114
115 @Test
116 @Order(6)
117 void testRedoCommand() throws Exception {
118 String output = SystemStubs.tapSystemOut(() -> {
119 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "status"));
120 });
121 assertFalse(output.contains("20080827200214 ...pending..."));
122 assertTrue(output.contains("20080827200216 ...pending..."));
123
124 output = SystemStubs.tapSystemOut(() -> {
125 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "redo"));
126 });
127 assertFalse(output.contains("FAILURE"));
128 assertEquals(-1, output.indexOf("DROP TABLE post_tag"), "Should down be just one step");
129 int dropIdx = output.indexOf("DROP TABLE comment");
130 int createIdx = output.indexOf("CREATE TABLE comment (");
131 assertNotEquals(-1, dropIdx);
132 assertNotEquals(-1, createIdx);
133 assertTrue(dropIdx < createIdx);
134
135 output = SystemStubs.tapSystemOut(() -> {
136 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "status"));
137 });
138 assertFalse(output.contains("20080827200214 ...pending..."));
139 assertTrue(output.contains("20080827200216 ...pending..."));
140
141 output = SystemStubs.tapSystemOut(() -> {
142 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "redo", "2"));
143 });
144 assertFalse(output.contains("FAILURE"));
145 assertEquals(-1, output.indexOf("DROP TABLE blog"), "Should down be two steps");
146 List<Integer> lineNums = new ArrayList<>();
147 lineNums.add(output.indexOf("DROP TABLE comment"));
148 lineNums.add(output.indexOf("DROP TABLE post"));
149 lineNums.add(output.indexOf("CREATE TABLE post ("));
150 lineNums.add(output.indexOf("CREATE TABLE comment ("));
151 assertEquals(new TreeSet<>(lineNums).toString(), lineNums.toString());
152
153 output = SystemStubs.tapSystemOut(() -> {
154 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "status"));
155 });
156 assertFalse(output.contains("20080827200214 ...pending..."));
157 assertTrue(output.contains("20080827200216 ...pending..."));
158 }
159
160 @Test
161 @Order(7)
162 void testDoPendingScriptCommand() throws Exception {
163 String output = SystemStubs.tapSystemOut(() -> {
164 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "script", "pending"));
165 });
166 assertTrue(output.contains("INSERT"));
167 assertTrue(output.contains("CHANGELOG"));
168 assertFalse(output.contains("-- @UNDO"));
169
170 output = SystemStubs.tapSystemOut(() -> {
171 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "script", "pending_undo"));
172 });
173 assertTrue(output.contains("DELETE"));
174 assertTrue(output.contains("CHANGELOG"));
175 assertTrue(output.contains("-- @UNDO"));
176 }
177
178 @Test
179 @Order(8)
180 void testVersionCommand() throws Exception {
181 String output = SystemStubs.tapSystemOut(() -> {
182 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "version", "20080827200217"));
183 });
184 assertFalse(output.contains("FAILURE"));
185 }
186
187 @Test
188 @Order(9)
189 void testSkippedScript() throws Exception {
190 testStatusContainsNoPendingMigrations();
191 File skipped = new File(dir + File.separator + "scripts", "20080827200215_skipped_migration.sql");
192 assertTrue(skipped.createNewFile());
193 try {
194 String output = SystemStubs.tapSystemOut(() -> {
195 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "up"));
196 });
197 assertFalse(output.contains("FAILURE"));
198 assertEquals(1, TestUtil.countStr(output, "WARNING"));
199 assertTrue(output.contains(
200 "WARNING: Migration script '20080827200215_skipped_migration.sql' was not applied to the database."));
201 } finally {
202 skipped.delete();
203 }
204 }
205
206 @Test
207 @Order(10)
208 void testMissingScript() throws Exception {
209 Path original = Paths.get(dir + File.separator + "scripts", "20080827200216_create_procs.sql");
210 Path renamed = Paths.get(dir + File.separator + "scripts", "20080827200216_create_procs._sql");
211 assertEquals(renamed, Files.move(original, renamed, StandardCopyOption.REPLACE_EXISTING));
212 try {
213 String output = SystemStubs.tapSystemOut(() -> {
214 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "up"));
215 });
216 assertFalse(output.contains("FAILURE"), "Output contains: \n" + output);
217 assertTrue(output.contains("WARNING: Missing migration script. id='20080827200216', description='create procs'."),
218 "Output contains: \n" + output);
219 } finally {
220 assertEquals(original, Files.move(renamed, original, StandardCopyOption.REPLACE_EXISTING));
221 }
222 }
223
224 @Test
225 @Order(11)
226 void testDownCommand() throws Exception {
227 String output = SystemStubs.tapSystemOut(() -> {
228 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "down"));
229 });
230 assertFalse(output.contains("FAILURE"));
231 testStatusContainsPendingMigrations();
232 }
233
234 @Test
235 @Order(12)
236 void testPendingCommand() throws Exception {
237 String output = SystemStubs.tapSystemOut(() -> {
238 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "pending"));
239 });
240 assertFalse(output.contains("FAILURE"));
241 testStatusContainsNoPendingMigrations();
242 }
243
244 @Test
245 @Order(13)
246 void testHelpCommand() throws Exception {
247 String output = SystemStubs.tapSystemOut(() -> {
248 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "--help"));
249 });
250 assertFalse(output.contains("FAILURE"));
251 assertTrue(output.contains("--help"));
252 }
253
254 @Test
255 @Order(14)
256 void testDoScriptCommand() throws Exception {
257 String output = SystemStubs.tapSystemOut(() -> {
258 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "script", "20080827200212", "20080827200214"));
259 });
260 assertFalse(output.contains("FAILURE"));
261 assertFalse(output.contains("20080827200210"));
262 assertFalse(output.contains("20080827200211"));
263 assertFalse(output.contains("20080827200212"));
264 assertTrue(output.contains("20080827200213"));
265 assertTrue(output.contains("20080827200214"));
266 assertFalse(output.contains("20080827200216"));
267 assertFalse(output.contains("-- @UNDO"));
268
269 output = SystemStubs.tapSystemOut(() -> {
270 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "script", "0", "20080827200211"));
271 });
272 assertFalse(output.contains("FAILURE"));
273 assertTrue(output.contains("20080827200210"));
274 assertTrue(output.contains("20080827200211"));
275 assertFalse(output.contains("20080827200212"));
276 assertFalse(output.contains("20080827200213"));
277 assertFalse(output.contains("20080827200214"));
278 assertFalse(output.contains("20080827200216"));
279 assertFalse(output.contains("-- @UNDO"));
280 }
281
282 @Test
283 @Order(15)
284 void testUndoScriptCommand() throws Exception {
285 String output = SystemStubs.tapSystemOut(() -> {
286 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "script", "20080827200216", "20080827200213"));
287 });
288 assertFalse(output.contains("FAILURE"));
289 assertFalse(output.contains("20080827200210"));
290 assertFalse(output.contains("20080827200211"));
291 assertFalse(output.contains("20080827200212"));
292 assertFalse(output.contains("20080827200213"));
293 assertTrue(output.contains("20080827200214"));
294 assertTrue(output.contains("20080827200216"));
295 assertTrue(output.contains("-- @UNDO"));
296
297 output = SystemStubs.tapSystemOut(() -> {
298 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "script", "20080827200211", "0"));
299 });
300 assertFalse(output.contains("FAILURE"));
301 assertTrue(output.contains("20080827200210"));
302 assertTrue(output.contains("20080827200211"));
303 assertFalse(output.contains("20080827200212"));
304 assertFalse(output.contains("20080827200213"));
305 assertFalse(output.contains("20080827200214"));
306 assertFalse(output.contains("20080827200216"));
307 assertFalse(output.contains("DELETE FROM CHANGELOG WHERE ID = 20080827200210;"));
308 assertTrue(output.contains("-- @UNDO"));
309 }
310
311 @Test
312 void shouldScriptCommandFailIfSameVersion() throws Exception {
313 String output = SystemStubs.tapSystemOut(() -> {
314 int exitCode = SystemStubs.catchSystemExit(() -> {
315 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "script", "20080827200211", "20080827200211"));
316 });
317 assertEquals(1, exitCode);
318 });
319 assertTrue(output.contains("FAILURE"));
320 }
321
322 @Test
323 void shouldInitTempDirectory() throws Exception {
324 File basePath = TestUtil.getTempDir();
325 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "init"));
326 assertNotNull(basePath.list());
327 assertEquals(4, basePath.list().length);
328 File scriptPath = new File(basePath.getCanonicalPath() + File.separator + "scripts");
329 assertEquals(3, scriptPath.list().length);
330 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "new", "test new migration"));
331 assertEquals(4, scriptPath.list().length);
332 assertTrue(TestUtil.deleteDirectory(basePath), "delete temp dir");
333 }
334
335 @Test
336 void shouldRespectIdPattern() throws Exception {
337 String idPattern = "000";
338 File basePath = TestUtil.getTempDir();
339 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--idpattern=" + idPattern, "init"));
340 File changelog = new File(
341 basePath.getCanonicalPath() + File.separator + "scripts" + File.separator + "001_create_changelog.sql");
342 assertTrue(changelog.exists());
343 Migrator.main(
344 TestUtil.args("--path=" + basePath.getAbsolutePath(), "--idpattern=" + idPattern, "new", "new migration"));
345 File newMigration = new File(
346 basePath.getCanonicalPath() + File.separator + "scripts" + File.separator + "003_new_migration.sql");
347 assertTrue(newMigration.exists());
348 assertTrue(TestUtil.deleteDirectory(basePath), "delete temp dir");
349 }
350
351 @Test
352 void useCustomTemplate() throws Exception {
353 String desc = "test new migration";
354 File basePath = TestUtil.getTempDir();
355 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "init"));
356 assertNotNull(basePath.list());
357 assertEquals(4, basePath.list().length);
358 File scriptPath = new File(basePath.getCanonicalPath() + File.separator + "scripts");
359 assertEquals(3, scriptPath.list().length);
360
361 File templatePath = File.createTempFile("customTemplate", "sql");
362 try (PrintWriter writer = new PrintWriter(templatePath)) {
363 writer.println("// ${description}");
364 }
365 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "new", desc,
366 "--template=" + templatePath.getAbsolutePath()));
367 String[] scripts = scriptPath.list();
368 Arrays.sort(scripts);
369 assertEquals(4, scripts.length);
370 try (Scanner scanner = new Scanner(new File(scriptPath, scripts[scripts.length - 2]))) {
371 if (scanner.hasNextLine()) {
372 assertEquals("// " + desc, scanner.nextLine());
373 }
374 }
375 templatePath.delete();
376 assertTrue(TestUtil.deleteDirectory(basePath), "delete temp dir");
377 }
378
379 @Test
380 void useCustomTemplateWithNoValue() throws Exception {
381 File basePath = TestUtil.getTempDir();
382 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "init"));
383 assertNotNull(basePath.list());
384 assertEquals(4, basePath.list().length);
385 File scriptPath = new File(basePath.getCanonicalPath() + File.separator + "scripts");
386 assertEquals(3, scriptPath.list().length);
387
388 File templatePath = File.createTempFile("customTemplate", "sql");
389 templatePath.createNewFile();
390 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "new", "test new migration", "--template="));
391 assertEquals(4, scriptPath.list().length);
392 templatePath.delete();
393 assertTrue(TestUtil.deleteDirectory(basePath), "delete temp dir");
394 }
395
396 @Test
397 void useCustomTemplateWithBadPath() throws Exception {
398 System.setProperty("migrationsHome", TestUtil.getTempDir().getAbsolutePath());
399 File basePath = TestUtil.getTempDir();
400 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "init"));
401 assertNotNull(basePath.list());
402 assertEquals(4, basePath.list().length);
403 File scriptPath = new File(basePath.getCanonicalPath() + File.separator + "scripts");
404 assertEquals(3, scriptPath.list().length);
405
406 String output = SystemStubs.tapSystemOut(() -> {
407 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "new", "test new migration"));
408 });
409 assertEquals(4, scriptPath.list().length);
410 assertTrue(output
411 .contains("Your migrations configuration did not find your custom template. Using the default template."));
412 assertTrue(TestUtil.deleteDirectory(basePath), "delete temp dir");
413 }
414
415 @Test
416 void shouldSuppressOutputIfQuietOptionEnabled() throws Throwable {
417 System.setProperty("migrationsHome", TestUtil.getTempDir().getAbsolutePath());
418 File basePath = TestUtil.getTempDir();
419 String output = SystemStubs.tapSystemOut(() -> {
420 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--quiet", "init"));
421 });
422 assertFalse(output.contains("Initializing:"));
423 assertNotNull(basePath.list());
424 assertTrue(TestUtil.deleteDirectory(basePath), "delete temp dir");
425 }
426
427 @Test
428 void shouldColorizeSuccessOutputIfColorOptionEnabled() throws Throwable {
429 System.setProperty("migrationsHome", TestUtil.getTempDir().getAbsolutePath());
430 File basePath = TestUtil.getTempDir();
431 String output = SystemStubs.tapSystemOut(() -> {
432 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--color", "init"));
433 });
434 assertTrue(output.contains(ConsoleColors.GREEN + "SUCCESS"));
435 assertNotNull(basePath.list());
436 assertTrue(TestUtil.deleteDirectory(basePath), "delete temp dir");
437 }
438
439 @Test
440 void shouldColorizeFailureOutputIfColorOptionEnabled() throws Throwable {
441 System.setProperty("migrationsHome", TestUtil.getTempDir().getAbsolutePath());
442 File basePath = TestUtil.getTempDir();
443 String output = SystemStubs.tapSystemOut(() -> {
444 int exitCode = SystemStubs.catchSystemExit(() -> {
445 Migrator.main(TestUtil.args("--path=" + basePath.getAbsolutePath(), "--color", "new"));
446 });
447 assertEquals(1, exitCode);
448 });
449 assertTrue(output.contains(ConsoleColors.RED + "FAILURE"));
450 assertTrue(TestUtil.deleteDirectory(basePath), "delete temp dir");
451 }
452
453 @Test
454 void shouldShowErrorOnMissingChangelog() throws Throwable {
455
456 try {
457 System.setProperty("migrations_changelog", "changelog1");
458 String output = SystemStubs.tapSystemOut(() -> {
459 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "up", "1"));
460 });
461 assertFalse(output.contains("FAILURE"));
462
463 System.setProperty("migrations_changelog", "changelog2");
464 output = SystemStubs.tapSystemOut(() -> {
465 int exitCode = SystemStubs.catchSystemExit(() -> {
466 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "pending"));
467 });
468 assertEquals(1, exitCode);
469 });
470 assertTrue(output.contains("FAILURE"));
471 assertTrue(output.contains("Change log doesn't exist, no migrations applied. Try running 'up' instead."));
472 } finally {
473 System.clearProperty("migrations_changelog");
474 }
475 }
476
477 @Test
478 void testInfoCommand() throws Exception {
479 String output = SystemStubs.tapSystemOut(() -> {
480 Migrator.main(TestUtil.args("info"));
481 });
482 assertFalse(output.contains("null"), output);
483 }
484
485 @Test
486 void testInfoWithNonExistentBasePath() throws Exception {
487 File baseDir = TestUtil.getTempDir();
488 assertTrue(baseDir.delete());
489 assertFalse(baseDir.exists(), "directory does not exist");
490 String output = SystemStubs.tapSystemOut(() -> {
491 Migrator.main(TestUtil.args("info", "--path=" + baseDir.getAbsolutePath()));
492 });
493 assertFalse(output.contains("Migrations path must be a directory"), "base path not required for info");
494 assertFalse(output.contains("null"), output);
495 }
496
497 @Test
498 void testInitWithNonExistentBasePath() throws Exception {
499 File baseDir = TestUtil.getTempDir();
500 assertTrue(baseDir.delete());
501 assertFalse(baseDir.exists(), "directory does not exist");
502 String output = SystemStubs
503 .tapSystemOut(() -> Migrator.main(TestUtil.args("init", "--path=" + baseDir.getAbsolutePath())));
504 assertFalse(output.contains("Migrations path must be a directory"), output);
505 assertTrue(new File(baseDir, "README").exists(), "README created");
506 assertTrue(new File(baseDir, "environments").isDirectory(), "environments directory created");
507 assertTrue(TestUtil.deleteDirectory(baseDir), "delete temp dir");
508 }
509
510 private void testStatusContainsPendingMigrations() throws Exception {
511 String output = SystemStubs.tapSystemOut(() -> {
512 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "status"));
513 });
514 assertFalse(output.contains("FAILURE"));
515 assertTrue(output.contains("...pending..."));
516 }
517
518 private void testStatusContainsNoPendingMigrations() throws Exception {
519 String output = SystemStubs.tapSystemOut(() -> {
520 Migrator.main(TestUtil.args("--path=" + dir.getAbsolutePath(), "status"));
521 });
522 assertFalse(output.contains("FAILURE"));
523 assertFalse(output.contains("...pending..."));
524 }
525
526 }