Updated Branches: refs/heads/master 438cf4ea6 -> 065e5afa0
Tests for DBUtil This patch adds test for the lock management: - getGlobalLock - releaseGlobalLock Signed-off-by: Laszlo Hornyak <laszlo.horn...@gmail.com> Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/065e5afa Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/065e5afa Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/065e5afa Branch: refs/heads/master Commit: 065e5afa08a34d414cdb8ced092c0dc8756c8463 Parents: 438cf4e Author: Laszlo Hornyak <laszlo.horn...@gmail.com> Authored: Sat Nov 16 14:25:29 2013 +0100 Committer: Laszlo Hornyak <laszlo.horn...@gmail.com> Committed: Sat Nov 16 15:44:31 2013 +0100 ---------------------------------------------------------------------- framework/db/pom.xml | 4 + framework/db/src/com/cloud/utils/db/DbUtil.java | 31 ++- .../db/test/com/cloud/utils/DbUtilTest.java | 190 +++++++++++++++++++ 3 files changed, 206 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/065e5afa/framework/db/pom.xml ---------------------------------------------------------------------- diff --git a/framework/db/pom.xml b/framework/db/pom.xml index e28628e..b24b742 100644 --- a/framework/db/pom.xml +++ b/framework/db/pom.xml @@ -36,6 +36,10 @@ <artifactId>commons-dbcp</artifactId> </dependency> <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + </dependency> + <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/065e5afa/framework/db/src/com/cloud/utils/db/DbUtil.java ---------------------------------------------------------------------- diff --git a/framework/db/src/com/cloud/utils/db/DbUtil.java b/framework/db/src/com/cloud/utils/db/DbUtil.java index 2570093..2a613d2 100755 --- a/framework/db/src/com/cloud/utils/db/DbUtil.java +++ b/framework/db/src/com/cloud/utils/db/DbUtil.java @@ -208,13 +208,14 @@ public class DbUtil { } PreparedStatement pstmt = null; + ResultSet rs = null; try { pstmt = conn.prepareStatement("SELECT COALESCE(GET_LOCK(?, ?),0)"); pstmt.setString(1, name); pstmt.setInt(2, timeoutSeconds); - ResultSet rs = pstmt.executeQuery(); + rs = pstmt.executeQuery(); if (rs != null && rs.first()) { if(rs.getInt(1) > 0) { return true; @@ -228,13 +229,8 @@ public class DbUtil { } catch (Throwable e) { s_logger.error("GET_LOCK() throws exception ", e); } finally { - if (pstmt != null) { - try { - pstmt.close(); - } catch (Throwable e) { - s_logger.error("What the heck? ", e); - } - } + closeStatement(pstmt); + closeResultSet(rs); } removeConnectionForGlobalLocks(name); @@ -259,10 +255,11 @@ public class DbUtil { } PreparedStatement pstmt = null; + ResultSet rs = null; try { pstmt = conn.prepareStatement("SELECT COALESCE(RELEASE_LOCK(?), 0)"); pstmt.setString(1, name); - ResultSet rs = pstmt.executeQuery(); + rs = pstmt.executeQuery(); if(rs != null && rs.first()) return rs.getInt(1) > 0; s_logger.error("RELEASE_LOCK() returns unexpected result : " + rs.getInt(1)); @@ -271,13 +268,9 @@ public class DbUtil { } catch (Throwable e) { s_logger.error("RELEASE_LOCK() throws exception ", e); } finally { - try { - if (pstmt != null) { - pstmt.close(); - } - conn.close(); - } catch(SQLException e) { - } + closeResultSet(rs); + closeStatement(pstmt); + closeConnection(conn); } return false; } @@ -305,7 +298,7 @@ public class DbUtil { resultSet.close(); } - } catch (Exception e) { + } catch (SQLException e) { s_logger.warn("Ignored exception while closing result set.",e); } @@ -319,7 +312,7 @@ public class DbUtil { statement.close(); } - } catch (Exception e) { + } catch (SQLException e) { s_logger.warn("Ignored exception while closing statement.",e); } @@ -333,7 +326,7 @@ public class DbUtil { connection.close(); } - } catch (Exception e) { + } catch (SQLException e) { s_logger.warn("Ignored exception while close connection.",e); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/065e5afa/framework/db/test/com/cloud/utils/DbUtilTest.java ---------------------------------------------------------------------- diff --git a/framework/db/test/com/cloud/utils/DbUtilTest.java b/framework/db/test/com/cloud/utils/DbUtilTest.java index e9a7287..4839c23 100644 --- a/framework/db/test/com/cloud/utils/DbUtilTest.java +++ b/framework/db/test/com/cloud/utils/DbUtilTest.java @@ -16,16 +16,58 @@ // under the License. package com.cloud.utils; +import java.io.IOException; +import java.lang.reflect.Field; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; + import javax.persistence.Column; +import javax.persistence.Table; +import javax.sql.DataSource; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; import com.cloud.utils.db.DbUtil; +import com.cloud.utils.db.TransactionLegacy; +@RunWith(MockitoJUnitRunner.class) public class DbUtilTest { + @Mock + Connection connection; + + @Mock + PreparedStatement preparedStatement; + + @Mock + Statement statement; + + @Mock + ResultSet resultSet; + + @Mock + DataSource dataSource; + + DataSource backup; + + Map<String, Connection> connectionMapBackup = null; + + Map<String, Connection> connectionMap = null; + + @Table(name = "test_table") static class Testbean { String noAnnotation; @Column() @@ -78,4 +120,152 @@ public class DbUtilTest { .getDeclaredField("instanceField"))); } + class Bar { + + } + + @Test + public void getTableName() { + Assert.assertEquals("test_table", DbUtil.getTableName(Testbean.class)); + Assert.assertEquals("Bar", DbUtil.getTableName(Bar.class)); + } + + @SuppressWarnings("unchecked") + @Before + public void setup() throws SecurityException, NoSuchFieldException, + IllegalArgumentException, IllegalAccessException { + Field globalLocks = DbUtil.class + .getDeclaredField("s_connectionForGlobalLocks"); + globalLocks.setAccessible(true); + connectionMapBackup = (Map<String, Connection>) globalLocks.get(null); + connectionMap = new HashMap<String, Connection>(); + globalLocks.set(null, connectionMap); + + Field dsField = TransactionLegacy.class.getDeclaredField("s_ds"); + dsField.setAccessible(true); + backup = (DataSource) dsField.get(null); + dsField.set(null, dataSource); + } + + @After + public void cleanup() throws SecurityException, NoSuchFieldException, + IllegalArgumentException, IllegalAccessException { + Field globalLocks = DbUtil.class + .getDeclaredField("s_connectionForGlobalLocks"); + globalLocks.setAccessible(true); + globalLocks.set(null, connectionMapBackup); + + Field dsField = TransactionLegacy.class.getDeclaredField("s_ds"); + dsField.setAccessible(true); + dsField.set(null, backup); + } + + @Test + public void getGlobalLock() throws SQLException { + Mockito.when(dataSource.getConnection()).thenReturn(connection); + Mockito.when(connection.prepareStatement(Mockito.anyString())) + .thenReturn(preparedStatement); + Mockito.when(preparedStatement.executeQuery()).thenReturn(resultSet); + Mockito.when(resultSet.first()).thenReturn(true); + Mockito.when(resultSet.getInt(1)).thenReturn(1); + Assert.assertTrue(DbUtil.getGlobalLock("TEST", 600)); + + Mockito.verify(connection).prepareStatement(Mockito.anyString()); + Mockito.verify(preparedStatement).close(); + Mockito.verify(resultSet).close(); + } + + @Test + public void getGlobalLockTimeout() throws SQLException { + Mockito.when(dataSource.getConnection()).thenReturn(connection); + Mockito.when(connection.prepareStatement(Mockito.anyString())) + .thenReturn(preparedStatement); + Mockito.when(preparedStatement.executeQuery()).thenReturn(resultSet); + Mockito.when(resultSet.first()).thenReturn(true); + Mockito.when(resultSet.getInt(1)).thenReturn(0); + Assert.assertFalse(DbUtil.getGlobalLock("TEST", 600)); + + Mockito.verify(connection).prepareStatement(Mockito.anyString()); + Mockito.verify(preparedStatement).close(); + Mockito.verify(resultSet).close(); + Mockito.verify(connection).close(); + + // if any error happens, the connection map must be cleared + Assert.assertTrue(connectionMap.isEmpty()); + } + + @Test + public void closeNull() { + DbUtil.closeStatement((Statement) null); + DbUtil.closeConnection((Connection) null); + DbUtil.closeResultSet((ResultSet) null); + // no exception should be thrown + } + + @Test + public void closeConnection() throws IOException, SQLException { + DbUtil.closeConnection(connection); + Mockito.verify(connection).close(); + } + + @Test + public void closeConnectionFail() throws IOException, SQLException { + Mockito.doThrow(new SQLException("it is all right")).when(connection) + .close(); + DbUtil.closeConnection(connection); + Mockito.verify(connection).close(); + } + + @Test + public void closeStatement() throws IOException, SQLException { + DbUtil.closeStatement(statement); + Mockito.verify(statement).close(); + } + + @Test + public void closeStatementFail() throws IOException, SQLException { + Mockito.doThrow(new SQLException("it is all right")).when(statement) + .close(); + DbUtil.closeStatement(statement); + Mockito.verify(statement).close(); + } + + @Test + public void closeResultSet() throws IOException, SQLException { + DbUtil.closeResultSet(resultSet); + Mockito.verify(resultSet).close(); + } + + @Test + public void closeResultSetFail() throws IOException, SQLException { + Mockito.doThrow(new SQLException("it is all right")).when(resultSet) + .close(); + DbUtil.closeResultSet(resultSet); + Mockito.verify(resultSet).close(); + } + + @Test + @Ignore + //can not be performed since assertion embedded in this branch of execution + public void releaseGlobalLockNotexisting() throws SQLException { + Assert.assertFalse(DbUtil.releaseGlobalLock("notexisting")); + Mockito.verify(dataSource, Mockito.never()).getConnection(); + } + + @Test + public void releaseGlobalLock() throws SQLException { + Mockito.when(connection.prepareStatement(Mockito.anyString())) + .thenReturn(preparedStatement); + Mockito.when(preparedStatement.executeQuery()).thenReturn(resultSet); + Mockito.when(resultSet.first()).thenReturn(true); + Mockito.when(resultSet.getInt(1)).thenReturn(1); + connectionMap.put("testLock", connection); + Assert.assertTrue(DbUtil.releaseGlobalLock("testLock")); + + Mockito.verify(resultSet).close(); + Mockito.verify(preparedStatement).close(); + Mockito.verify(connection).close(); + Assert.assertFalse(connectionMap.containsKey("testLock")); + } + }