// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // 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 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.Matchers; 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() String withAnnotation; @Column(name = "surprise") String withAnnotationAndName; } @Test public void getColumnName() throws SecurityException, NoSuchFieldException { // if no annotation, then the field name Assert.assertEquals("noAnnotation", DbUtil.getColumnName(Testbean.class.getDeclaredField("noAnnotation"))); // there is annotation with name, take the name Assert.assertEquals("surprise", DbUtil.getColumnName(Testbean.class.getDeclaredField("withAnnotationAndName"))); } @Test @Ignore public void getColumnNameWithAnnotationButWithoutNameAttribute() throws SecurityException, NoSuchFieldException { // there is annotation, but no name defined, fallback to field name // this does not work this way, it probably should Assert.assertEquals("withAnnotation", DbUtil.getColumnName(Testbean.class.getDeclaredField("withAnnotation"))); } static class IsPersistableTestBean { static final String staticFinal = "no"; final String justFinal = "no"; transient String transientField; transient static String strange = ""; String instanceField; } @Test public void isPersistable() throws SecurityException, NoSuchFieldException { Assert.assertFalse(DbUtil.isPersistable(IsPersistableTestBean.class.getDeclaredField("staticFinal"))); Assert.assertFalse(DbUtil.isPersistable(IsPersistableTestBean.class.getDeclaredField("justFinal"))); Assert.assertFalse(DbUtil.isPersistable(IsPersistableTestBean.class.getDeclaredField("transientField"))); Assert.assertFalse(DbUtil.isPersistable(IsPersistableTestBean.class.getDeclaredField("strange"))); Assert.assertTrue(DbUtil.isPersistable(IsPersistableTestBean.class.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(Matchers.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(Matchers.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(Matchers.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(Matchers.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(Matchers.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")); } }