Move and refactor Redis test server @Rule

Move the Redis JUnit @Rule so that it can be used with
SessionAutoConfigurationTests. Also refactored the internals a little.
This commit is contained in:
Phillip Webb 2015-07-13 11:52:42 -07:00
parent 9ebe15232e
commit fd6024ebf1
8 changed files with 166 additions and 163 deletions

View File

@ -23,6 +23,7 @@ import org.junit.Test;
import org.springframework.boot.actuate.metrics.Iterables;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.writer.Delta;
import org.springframework.boot.redis.RedisTestServer;
import org.springframework.data.redis.core.StringRedisTemplate;
import static org.junit.Assert.assertEquals;
@ -30,29 +31,34 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* Tests for {@link RedisMetricRepository}.
*
* @author Dave Syer
*/
public class RedisMetricRepositoryTests {
@Rule
public RedisServer redis = RedisServer.running();
public RedisTestServer redis = new RedisTestServer();
private RedisMetricRepository repository;
private String prefix;
@Before
public void init() {
this.prefix = "spring.test." + System.currentTimeMillis();
this.repository = new RedisMetricRepository(this.redis.getResource(), this.prefix);
this.repository = new RedisMetricRepository(this.redis.getConnectionFactory(),
this.prefix);
}
@After
public void clear() {
assertNotNull(new StringRedisTemplate(this.redis.getResource()).opsForValue()
.get(this.prefix + ".foo"));
assertNotNull(new StringRedisTemplate(this.redis.getConnectionFactory())
.opsForValue().get(this.prefix + ".foo"));
this.repository.reset("foo");
this.repository.reset("bar");
assertNull(new StringRedisTemplate(this.redis.getResource()).opsForValue().get(
this.prefix + ".foo"));
assertNull(new StringRedisTemplate(this.redis.getConnectionFactory())
.opsForValue().get(this.prefix + ".foo"));
}
@Test

View File

@ -33,6 +33,7 @@ import org.junit.runners.Parameterized.Parameters;
import org.springframework.boot.actuate.metrics.Iterables;
import org.springframework.boot.actuate.metrics.Metric;
import org.springframework.boot.actuate.metrics.writer.Delta;
import org.springframework.boot.redis.RedisTestServer;
import org.springframework.data.redis.core.StringRedisTemplate;
import static org.junit.Assert.assertEquals;
@ -48,8 +49,10 @@ import static org.junit.Assert.assertTrue;
public class RedisMultiMetricRepositoryTests {
@Rule
public RedisServer redis = RedisServer.running();
public RedisTestServer redis = new RedisTestServer();
private RedisMultiMetricRepository repository;
@Parameter(0)
public String prefix;
@ -62,24 +65,25 @@ public class RedisMultiMetricRepositoryTests {
public void init() {
if (this.prefix == null) {
this.prefix = "spring.groups";
this.repository = new RedisMultiMetricRepository(this.redis.getResource());
this.repository = new RedisMultiMetricRepository(
this.redis.getConnectionFactory());
}
else {
this.repository = new RedisMultiMetricRepository(this.redis.getResource(),
this.prefix);
this.repository = new RedisMultiMetricRepository(
this.redis.getConnectionFactory(), this.prefix);
}
}
@After
public void clear() {
assertTrue(new StringRedisTemplate(this.redis.getResource()).opsForZSet().size(
"keys." + this.prefix) > 0);
assertTrue(new StringRedisTemplate(this.redis.getConnectionFactory())
.opsForZSet().size("keys." + this.prefix) > 0);
this.repository.reset("foo");
this.repository.reset("bar");
assertNull(new StringRedisTemplate(this.redis.getResource()).opsForValue().get(
this.prefix + ".foo"));
assertNull(new StringRedisTemplate(this.redis.getResource()).opsForValue().get(
this.prefix + ".bar"));
assertNull(new StringRedisTemplate(this.redis.getConnectionFactory())
.opsForValue().get(this.prefix + ".foo"));
assertNull(new StringRedisTemplate(this.redis.getConnectionFactory())
.opsForValue().get(this.prefix + ".bar"));
}
@Test
@ -136,4 +140,5 @@ public class RedisMultiMetricRepositoryTests {
assertTrue("Wrong names: " + names, names.contains("foo.bar"));
assertEquals(3d, bar.getValue());
}
}

View File

@ -1,146 +0,0 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* 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.springframework.boot.actuate.metrics.repository.redis;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Assume;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import static org.junit.Assert.fail;
/**
* @author Eric Bottard
* @author Gary Russell
* @author Dave Syer
*/
public class RedisServer implements TestRule {
private static final String EXTERNAL_SERVERS_REQUIRED = "EXTERNAL_SERVERS_REQUIRED";
protected JedisConnectionFactory resource;
private final String resourceDescription = "Redis ConnectionFactory";
private static final Log logger = LogFactory.getLog(RedisServer.class);
public static RedisServer running() {
return new RedisServer();
}
private RedisServer() {
}
@Override
public Statement apply(final Statement base, Description description) {
try {
this.resource = obtainResource();
}
catch (Exception ex) {
maybeCleanup();
return failOrSkip(ex);
}
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
}
finally {
try {
cleanupResource();
}
catch (Exception ignored) {
RedisServer.logger.warn(
"Exception while trying to cleanup proper resource",
ignored);
}
}
}
};
}
private Statement failOrSkip(Exception exception) {
String serversRequired = System.getenv(EXTERNAL_SERVERS_REQUIRED);
if ("true".equalsIgnoreCase(serversRequired)) {
logger.error(this.resourceDescription + " IS REQUIRED BUT NOT AVAILABLE",
exception);
fail(this.resourceDescription + " IS NOT AVAILABLE");
// Never reached, here to satisfy method signature
return null;
}
else {
logger.error(this.resourceDescription + " IS NOT AVAILABLE, SKIPPING TESTS",
exception);
return new Statement() {
@Override
public void evaluate() throws Throwable {
Assume.assumeTrue("Skipping test due to "
+ RedisServer.this.resourceDescription
+ " not being available", false);
}
};
}
}
private void maybeCleanup() {
if (this.resource != null) {
try {
cleanupResource();
}
catch (Exception ignored) {
logger.warn("Exception while trying to cleanup failed resource", ignored);
}
}
}
public RedisConnectionFactory getResource() {
return this.resource;
}
/**
* Perform cleanup of the {@link #resource} field, which is guaranteed to be non null.
*
* @throws Exception any exception thrown by this method will be logged and swallowed
*/
protected void cleanupResource() throws Exception {
this.resource.destroy();
}
/**
* Try to obtain and validate a resource. Implementors should either set the
* {@link #resource} field with a valid resource and return normally, or throw an
* exception.
* @return the jedis connection factory
* @throws Exception if the factory cannot be obtained
*/
protected JedisConnectionFactory obtainResource() throws Exception {
JedisConnectionFactory resource = new JedisConnectionFactory();
resource.afterPropertiesSet();
resource.getConnection().close();
return resource;
}
}

View File

@ -95,7 +95,6 @@ public class RedisAutoConfigurationTests {
@Test
public void testRedisConfigurationWithSentinel() throws Exception {
List<String> sentinels = Arrays.asList("127.0.0.1:26379", "127.0.0.1:26380");
if (isAtLeastOneSentinelAvailable(sentinels)) {
load("spring.redis.sentinel.master:mymaster", "spring.redis.sentinel.nodes:"
+ StringUtils.collectionToCommaDelimitedString(sentinels));

View File

@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.session;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration;
@ -25,6 +26,7 @@ import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfigurat
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.MockEmbeddedServletContainerFactory;
import org.springframework.boot.redis.RedisTestServer;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -39,6 +41,9 @@ import static org.junit.Assert.assertNotNull;
*/
public class SessionAutoConfigurationTests {
@Rule
public RedisTestServer redis = new RedisTestServer();
private AnnotationConfigEmbeddedWebApplicationContext context;
@After

View File

@ -246,6 +246,11 @@
<artifactId>spring-context-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -0,0 +1,110 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* 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.springframework.boot.redis;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Assume;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
/**
* {@link TestRule} for working with an optional Redis server.
*
* @author Eric Bottard
* @author Gary Russell
* @author Dave Syer
* @author Phillip Webb
*/
public class RedisTestServer implements TestRule {
private static final Log logger = LogFactory.getLog(RedisTestServer.class);
private JedisConnectionFactory connectionFactory;
@Override
public Statement apply(final Statement base, Description description) {
try {
this.connectionFactory = createConnectionFactory();
return new RedisStatement(base, this.connectionFactory);
}
catch (Exception ex) {
logger.error("No Redis server availble", ex);
return new SkipStatement();
}
}
private JedisConnectionFactory createConnectionFactory() {
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
connectionFactory.afterPropertiesSet();
testConnection(connectionFactory);
return connectionFactory;
}
private void testConnection(JedisConnectionFactory connectionFactory) {
connectionFactory.getConnection().close();
}
/**
* @return the connection factory if any
*/
public RedisConnectionFactory getConnectionFactory() {
return this.connectionFactory;
}
private static class RedisStatement extends Statement {
private final Statement base;
private final JedisConnectionFactory connectionFactory;
public RedisStatement(Statement base, JedisConnectionFactory connectionFactory) {
this.base = base;
this.connectionFactory = connectionFactory;
}
@Override
public void evaluate() throws Throwable {
try {
this.base.evaluate();
}
finally {
try {
this.connectionFactory.destroy();
}
catch (Exception ex) {
logger.warn("Exception while trying to cleanup redis resource", ex);
}
}
}
}
private static class SkipStatement extends Statement {
@Override
public void evaluate() throws Throwable {
Assume.assumeTrue("Skipping test due to " + "Redis ConnectionFactory"
+ " not being available", false);
}
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright 2012-2015 the original author or authors.
*
* 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.
*/
/**
* @author pwebb
*/
package org.springframework.boot.redis;