Repository: aurora
Updated Branches:
  refs/heads/master 5ecded788 -> 57468d221


Fix bug when checking to ensure that all db migrations on the classpath have 
been applied.

While testing applying the multiple migrations for storing images, I noticed 
that we were rolling
one back on startup when no migration should be performed.

It turned out I misunderstood the semantics of the Java8 stream API 
filter/findFirst combination.

Reviewed at https://reviews.apache.org/r/45933/


Project: http://git-wip-us.apache.org/repos/asf/aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/57468d22
Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/57468d22
Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/57468d22

Branch: refs/heads/master
Commit: 57468d2212c9d61bcd4f10022ac575ae2d036ffe
Parents: 5ecded7
Author: Joshua Cohen <jco...@apache.org>
Authored: Fri Apr 8 13:48:05 2016 -0500
Committer: Joshua Cohen <jco...@apache.org>
Committed: Fri Apr 8 13:48:05 2016 -0500

----------------------------------------------------------------------
 config/checkstyle/suppressions.xml              |   2 +-
 .../storage/db/MigrationManagerImpl.java        |   2 +-
 .../storage/db/MigrationManagerImplIT.java      | 101 +++++++++++++------
 .../db/testmigration/V002_TestMigration2.java   |  40 ++++++++
 4 files changed, 114 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aurora/blob/57468d22/config/checkstyle/suppressions.xml
----------------------------------------------------------------------
diff --git a/config/checkstyle/suppressions.xml 
b/config/checkstyle/suppressions.xml
index 30a32ce..d9fe92a 100644
--- a/config/checkstyle/suppressions.xml
+++ b/config/checkstyle/suppressions.xml
@@ -21,6 +21,6 @@ limitations under the License.
   <!-- Allow use of System.exit() in main. -->
   <suppress files="org/apache/aurora/scheduler/app/SchedulerMain.java"
             checks="RegexpSinglelineJava"/>
-  <suppress 
files="org/apache/aurora/scheduler/storage/db/testmigration/V001_TestMigration.java"
+  <suppress files="org/apache/aurora/scheduler/storage/db/testmigration/.*"
             checks="TypeName" />
 </suppressions>

http://git-wip-us.apache.org/repos/asf/aurora/blob/57468d22/src/main/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImpl.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImpl.java
 
b/src/main/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImpl.java
index e2b8416..ca11e59 100644
--- 
a/src/main/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImpl.java
+++ 
b/src/main/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImpl.java
@@ -94,7 +94,7 @@ public class MigrationManagerImpl implements MigrationManager 
{
       // which includes class in its equality check rather than checking 
instanceof. Instead we just
       // find the first element in changes whose id matches our applied 
change. If it does not exist
       // then this must be a rollback.
-      if (changes.stream().findFirst().filter(c -> 
c.getId().equals(change.getId())).isPresent()) {
+      if (changes.stream().anyMatch(c -> c.getId().equals(change.getId()))) {
         LOG.info("Change " + change.getId() + " has been applied, no other 
downgrades are "
             + "necessary");
         break;

http://git-wip-us.apache.org/repos/asf/aurora/blob/57468d22/src/test/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImplIT.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImplIT.java
 
b/src/test/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImplIT.java
index 5edc2ad..d594bce 100644
--- 
a/src/test/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImplIT.java
+++ 
b/src/test/java/org/apache/aurora/scheduler/storage/db/MigrationManagerImplIT.java
@@ -19,6 +19,7 @@ import java.sql.SQLException;
 import java.util.List;
 import java.util.Optional;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.io.CharStreams;
 import com.google.inject.Injector;
 
@@ -42,33 +43,91 @@ public class MigrationManagerImplIT {
         new DbModule.MigrationManagerModule(migrationLoader));
   }
 
+  /**
+   * Ensure all changes have been applied and their downgrade scripts stored 
appropriately.
+   *
+   * @param sqlSessionFactory The sql session factory.
+   * @param loader A migration loader.
+   * @throws Exception If the changes were not applied properly.
+   */
+  private void assertMigrationComplete(
+      SqlSessionFactory sqlSessionFactory,
+      MigrationLoader loader) throws Exception {
+
+    try (SqlSession session = sqlSessionFactory.openSession()) {
+      MigrationMapper mapper = session.getMapper(MigrationMapper.class);
+
+      List<MigrationChangelogEntry> appliedChanges = mapper.selectAll();
+
+      for (Change change : loader.getMigrations()) {
+        Optional<MigrationChangelogEntry> appliedChange = appliedChanges
+            .stream()
+            .filter(c -> c.getId().equals(change.getId()))
+            .findFirst();
+
+        assertTrue(appliedChange.isPresent());
+        assertEquals(
+            CharStreams.toString(loader.getScriptReader(change, true /* undo 
*/)),
+            appliedChange.get().getDowngradeScript());
+      }
+
+      // As long as the tables exist, neither of these statements should fail.
+      try (Connection c = session.getConnection()) {
+        try (PreparedStatement select = c.prepareStatement("SELECT * FROM 
V001_test_table")) {
+          select.execute();
+        }
+        try (PreparedStatement select = c.prepareStatement("SELECT * FROM 
V002_test_table2")) {
+          select.execute();
+        }
+      }
+    }
+  }
+
   @Test
   public void testMigrate() throws Exception {
     MigrationLoader loader = new JavaMigrationLoader(
         "org.apache.aurora.scheduler.storage.db.testmigration");
     Injector injector = createMigrationInjector(loader);
 
+    injector.getInstance(MigrationManager.class).migrate();
+    assertMigrationComplete(injector.getInstance(SqlSessionFactory.class), 
loader);
+  }
+
+  @Test
+  public void testNoMigrationNecessary() throws Exception {
+    MigrationLoader loader = new JavaMigrationLoader(
+        "org.apache.aurora.scheduler.storage.db.testmigration");
+    Injector injector = createMigrationInjector(loader);
+
     MigrationManager migrationManager = 
injector.getInstance(MigrationManager.class);
 
     migrationManager.migrate();
 
     SqlSessionFactory sqlSessionFactory = 
injector.getInstance(SqlSessionFactory.class);
+    assertMigrationComplete(sqlSessionFactory, loader);
+
+    // Run the migration a second time, no changes should be made.
+    migrationManager.migrate();
+    assertMigrationComplete(sqlSessionFactory, loader);
+  }
 
+  private void assertRollbackComplete(SqlSessionFactory sqlSessionFactory) 
throws Exception {
     try (SqlSession session = sqlSessionFactory.openSession()) {
       MigrationMapper mapper = session.getMapper(MigrationMapper.class);
-      List<MigrationChangelogEntry> appliedChanges = mapper.selectAll();
 
-      // Ensure all changes have been applied and their downgrade scripts 
stored appropriately.
-      for (Change change : loader.getMigrations()) {
-        Optional<MigrationChangelogEntry> appliedChange = appliedChanges
-            .stream()
-            .findFirst()
-            .filter(c -> c.getId().equals(change.getId()));
-
-        assertTrue(appliedChange.isPresent());
-        assertEquals(
-            CharStreams.toString(loader.getScriptReader(change, true /* undo 
*/)),
-            appliedChange.get().getDowngradeScript());
+      assertTrue(mapper.selectAll().isEmpty());
+      try (Connection c = session.getConnection()) {
+        for (String table : ImmutableList.of("V001_test_table", 
"V002_test_table2")) {
+          try (PreparedStatement select = c.prepareStatement("SELECT * FROM " 
+ table)) {
+            select.execute();
+            fail("Select from " + table + " should have failed, the table 
should have been "
+                + "dropped.");
+          } catch (SQLException e) {
+            // This exception is expected.
+            assertTrue(
+                e.getMessage().startsWith("Table \"" + table.toUpperCase() + 
"\" not found"));
+          }
+        }
       }
     }
   }
@@ -93,22 +152,6 @@ public class MigrationManagerImplIT {
 
     rollbackManager.migrate();
 
-    SqlSessionFactory sqlSessionFactory = 
rollbackInjector.getInstance(SqlSessionFactory.class);
-
-    try (SqlSession session = sqlSessionFactory.openSession()) {
-      MigrationMapper mapper = session.getMapper(MigrationMapper.class);
-
-      assertTrue(mapper.selectAll().isEmpty());
-      try (Connection c = session.getConnection()) {
-        try (PreparedStatement select = c.prepareStatement("SELECT * FROM 
V001_test_table")) {
-          select.execute();
-          fail("Select from V001_test_table should have failed, the table 
should have been "
-              + "dropped.");
-        } catch (SQLException e) {
-          // This exception is expected.
-          assertTrue(e.getMessage().startsWith("Table \"V001_TEST_TABLE\" not 
found"));
-        }
-      }
-    }
+    
assertRollbackComplete(rollbackInjector.getInstance(SqlSessionFactory.class));
   }
 }

http://git-wip-us.apache.org/repos/asf/aurora/blob/57468d22/src/test/java/org/apache/aurora/scheduler/storage/db/testmigration/V002_TestMigration2.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/aurora/scheduler/storage/db/testmigration/V002_TestMigration2.java
 
b/src/test/java/org/apache/aurora/scheduler/storage/db/testmigration/V002_TestMigration2.java
new file mode 100644
index 0000000..621ca4c
--- /dev/null
+++ 
b/src/test/java/org/apache/aurora/scheduler/storage/db/testmigration/V002_TestMigration2.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.storage.db.testmigration;
+
+import java.math.BigDecimal;
+
+import org.apache.ibatis.migration.MigrationScript;
+
+public class V002_TestMigration2 implements MigrationScript {
+  @Override
+  public BigDecimal getId() {
+    return BigDecimal.valueOf(2L);
+  }
+
+  @Override
+  public String getDescription() {
+    return "A second test migration";
+  }
+
+  @Override
+  public String getUpScript() {
+    return "CREATE TABLE V002_test_table2(id int);";
+  }
+
+  @Override
+  public String getDownScript() {
+    return "DROP TABLE V002_test_table2;";
+  }
+}

Reply via email to