补充测试,重构代码

This commit is contained in:
DigitalSonic
2018-04-12 23:16:18 +08:00
parent cdefafd232
commit 64be5cc703
8 changed files with 142 additions and 33 deletions
@@ -13,6 +13,11 @@ import java.sql.Driver;
import java.sql.SQLException;
import java.util.Properties;
/**
* FilterChain to create new connection with placeholder in URL
*
* @author DigitalSonic
*/
public class ConnectionConnectFilterChainImpl extends FilterChainImpl {
private final static Log LOG = LogFactory.getLog(ConnectionConnectFilterChainImpl.class);
@@ -14,6 +14,11 @@ import java.util.Map;
import java.util.Properties;
import java.util.Random;
/**
* A singleton object to hold Host & Port information.
*
* @author DigitalSonic
*/
public class HostAndPortHolder {
private static final Log LOG = LogFactory.getLog(ConnectionConnectFilterChainImpl.class);
@@ -30,18 +35,22 @@ public class HostAndPortHolder {
return instance;
}
public static void loadFromProperties(String file) {
public static void loadProperties(String file) {
Properties properties = new Properties();
if (file == null) {
return;
}
InputStream is;
InputStream is = null;
try {
LOG.debug("Trying to load " + file + " from FileSystem.");
is = new FileInputStream(file);
} catch(FileNotFoundException e) {
LOG.debug("Trying to load " + file + " from Classpath.");
is = HostAndPortHolder.class.getResourceAsStream(file);
try {
is = HostAndPortHolder.class.getResourceAsStream(file);
} catch (Exception ex) {
LOG.warn("Can not load resource " + file, ex);
}
}
if (is != null) {
try {
@@ -10,6 +10,12 @@ import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
/**
* A thread to run the validation on each host:port.
* If some host:port is failed in the validation, we can set test flags in DruidDataSource.
*
* @author DigitalSonic
*/
public class HostAndPortValidatorThread implements Runnable {
private final static Log LOG = LogFactory.getLog(HostAndPortValidatorThread.class);
private DruidDataSource dataSource;
@@ -38,8 +44,6 @@ public class HostAndPortValidatorThread implements Runnable {
}
protected void check() {
Driver driver = dataSource.getRawDriver();
Properties info = dataSource.getConnectProperties();
String url = dataSource.getRawJdbcUrl();
if (url == null || (url != null &&
(url.indexOf("${") == -1 || url.indexOf("}") == -1))) {
@@ -49,31 +53,40 @@ public class HostAndPortValidatorThread implements Runnable {
String placeHolder = url.substring(url.indexOf("${") + 2, url.indexOf("}"));
List<String> values = HostAndPortHolder.getInstance().getAll(placeHolder);
for (String v : values) {
Connection conn = null;
try {
String realUrl = url.replace("${" + placeHolder + "}", v);
conn = driver.connect(realUrl, info);
dataSource.validateConnection(conn);
HostAndPortHolder.getInstance().removeBlacklist(v);
} catch (SQLException e) {
LOG.warn("Validation FAILED for " + v, e);
HostAndPortHolder.getInstance().addBlacklist(v);
modifyFlagsIfNeeded();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
LOG.error("Can not close connection for HostAndPort Validation.", e);
}
}
}
validateConnection(dataSource, placeHolder, v);
}
if (HostAndPortHolder.getInstance().getBlacklistSize() == 0) {
resetFlagsIfNeeded();
}
}
private void validateConnection(DruidDataSource dataSource, String placeHolder, String target) {
Driver driver = dataSource.getRawDriver();
Properties info = dataSource.getConnectProperties();
String url = dataSource.getRawJdbcUrl();
Connection conn = null;
try {
LOG.debug("Validating " + target + " every " + sleepSeconds + " seconds.");
String realUrl = url.replace("${" + placeHolder + "}", target);
conn = driver.connect(realUrl, info);
dataSource.validateConnection(conn);
HostAndPortHolder.getInstance().removeBlacklist(target);
} catch (SQLException e) {
LOG.warn("Validation FAILED for " + target, e);
HostAndPortHolder.getInstance().addBlacklist(target);
modifyFlagsIfNeeded();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
LOG.error("Can not close connection for HostAndPort Validation.", e);
}
}
}
}
private void resetFlagsIfNeeded() {
if (modifyTestFlags) {
dataSource.setTestOnBorrow(oldTestOnBorrow);
@@ -85,7 +98,7 @@ public class HostAndPortValidatorThread implements Runnable {
if (!modifyTestFlags) {
return;
}
if (oldTestOnReturn || oldTestOnBorrow) {
if (!oldTestOnReturn || !oldTestOnBorrow) {
dataSource.setTestOnBorrow(true);
dataSource.setTestOnReturn(true);
}
@@ -11,22 +11,35 @@ import com.alibaba.druid.support.logging.LogFactory;
import java.sql.SQLException;
import java.util.Properties;
/**
* The filter to replace the placeholder in JDBC URL.
*
* @author DigitalSonic
*/
public class JdbcUrlHostAndPortReplaceFilter extends FilterAdapter {
private final static Log LOG = LogFactory.getLog(HostAndPortValidatorThread.class);
public static final String DEFAULT_FILE = "/druid-datasource.properties";
public static final String DEFAULT_FILE = "datasource.properties";
private String file = DEFAULT_FILE;
private int healthCheckIntervalSeconds = 0;
private HostAndPortValidatorThread validatorThread;
private Thread runningValidatorThread;
private boolean isValidatorThreadStarted = false;
private boolean modifyTestFlags = false;
public void init() {
if (file == null || file.trim().length() == 0) {
file = DEFAULT_FILE;
}
HostAndPortHolder.loadFromProperties(file);
HostAndPortHolder.loadProperties(file);
}
public void close() {
if (runningValidatorThread != null) {
runningValidatorThread.interrupt();
}
}
@Override
@@ -44,9 +57,11 @@ public class JdbcUrlHostAndPortReplaceFilter extends FilterAdapter {
if (validatorThread == null) {
validatorThread = new HostAndPortValidatorThread();
validatorThread.setSleepSeconds(healthCheckIntervalSeconds);
validatorThread.setModifyTestFlags(modifyTestFlags);
}
validatorThread.setDataSource((DruidDataSource) dataSource);
new Thread(validatorThread).start();
runningValidatorThread = new Thread(validatorThread);
runningValidatorThread.start();
isValidatorThreadStarted = true;
} else {
LOG.warn("The DataSource is not a DruidDataSource, ignore HostAndPortValidator.");
@@ -64,4 +79,8 @@ public class JdbcUrlHostAndPortReplaceFilter extends FilterAdapter {
public void setValidatorThread(HostAndPortValidatorThread validatorThread) {
this.validatorThread = validatorThread;
}
public void setModifyTestFlags(boolean modifyTestFlags) {
this.modifyTestFlags = modifyTestFlags;
}
}
@@ -7,12 +7,20 @@ import org.junit.Test;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
/**
* Test class for HostAndPortHolder
*
* @author DigitalSonic
*/
public class HostAndPortHolderTest {
@Before
public void setUp() {
HostAndPortHolder.loadFromProperties("/com/alibaba/druid/filter/url/datasource.properties");
HostAndPortHolder.loadProperties("/com/alibaba/druid/filter/url/datasource.properties");
}
@After
@@ -20,6 +28,13 @@ public class HostAndPortHolderTest {
HostAndPortHolder.getInstance().clearBlacklist();
}
@Test
public void testLoadFromFileNotExisted() {
int size = HostAndPortHolder.getInstance().getHolder().size();
HostAndPortHolder.loadProperties("FILE_NOT_FOUND");
assertEquals(size, HostAndPortHolder.getInstance().getHolder().size());
}
@Test
public void testLoadFromProperties() {
Map<String, List<String>> holder = HostAndPortHolder.getInstance().getHolder();
@@ -0,0 +1,40 @@
package com.alibaba.druid.filter.url;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Test class for HostAndPortValidatorThread
*
* @author DigitalSonic
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/alibaba/druid/filter/url/dataSource.xml")
public class HostAndPortValidatorThreadTest {
@Autowired
private DruidDataSource dataSource;
@Test
public void testValidateFail() throws Exception {
assertEquals(0, HostAndPortHolder.getInstance().getBlacklistSize());
dataSource.setValidationQuery("select xxx from foo");
Thread.sleep(20 * 1000);
assertTrue(HostAndPortHolder.getInstance().getBlacklistSize() > 0);
assertTrue(dataSource.isTestOnBorrow());
assertTrue(dataSource.isTestOnReturn());
dataSource.setValidationQuery(null);
Thread.sleep(20 * 1000);
assertEquals(0, HostAndPortHolder.getInstance().getBlacklistSize());
assertFalse(dataSource.isTestOnBorrow());
assertFalse(dataSource.isTestOnReturn());
}
}
@@ -14,8 +14,14 @@ import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Test class for JdbcUrlHostAndPortReplaceFilter
*
* @author DigitalSonic
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/alibaba/druid/filter/url/dataSource.xml")
public class JdbcUrlHostAndPortReplaceFilterTest {
@@ -46,5 +52,4 @@ public class JdbcUrlHostAndPortReplaceFilterTest {
c.close();
}
}
}
@@ -9,8 +9,11 @@
default-lazy-init="false">
<tx:annotation-driven />
<bean id="url-filter" class="com.alibaba.druid.filter.url.JdbcUrlHostAndPortReplaceFilter" init-method="init">
<bean id="url-filter" class="com.alibaba.druid.filter.url.JdbcUrlHostAndPortReplaceFilter"
init-method="init" destroy-method="close">
<property name="file" value="/com/alibaba/druid/filter/url/datasource.properties" />
<property name="healthCheckIntervalSeconds" value="10" />
<property name="modifyTestFlags" value="true" />
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"