From fd6024ebf14f776dfdd5f95d5e1a56bc1b4a681f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 13 Jul 2015 11:52:42 -0700 Subject: [PATCH] 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. --- .../redis/RedisMetricRepositoryTests.java | 18 ++- .../RedisMultiMetricRepositoryTests.java | 25 +-- .../metrics/repository/redis/RedisServer.java | 146 ------------------ .../redis/RedisAutoConfigurationTests.java | 1 - .../SessionAutoConfigurationTests.java | 5 + spring-boot/pom.xml | 5 + .../boot/redis/RedisTestServer.java | 110 +++++++++++++ .../boot/redis/package-info.java | 19 +++ 8 files changed, 166 insertions(+), 163 deletions(-) delete mode 100644 spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisServer.java create mode 100644 spring-boot/src/test/java/org/springframework/boot/redis/RedisTestServer.java create mode 100644 spring-boot/src/test/java/org/springframework/boot/redis/package-info.java diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisMetricRepositoryTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisMetricRepositoryTests.java index e9f76f28c64..b46e5ea7c55 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisMetricRepositoryTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisMetricRepositoryTests.java @@ -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 diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisMultiMetricRepositoryTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisMultiMetricRepositoryTests.java index ac60f67405d..ddf90df480f 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisMultiMetricRepositoryTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisMultiMetricRepositoryTests.java @@ -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()); } + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisServer.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisServer.java deleted file mode 100644 index c23f83a02e5..00000000000 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/repository/redis/RedisServer.java +++ /dev/null @@ -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; - } - -} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/redis/RedisAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/redis/RedisAutoConfigurationTests.java index db25ad85dac..de0c1d34241 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/redis/RedisAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/redis/RedisAutoConfigurationTests.java @@ -95,7 +95,6 @@ public class RedisAutoConfigurationTests { @Test public void testRedisConfigurationWithSentinel() throws Exception { List 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)); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java index c167e9e1d17..66cfaa5cd57 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/SessionAutoConfigurationTests.java @@ -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 diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml index 08311a71e9f..c7f6f5d7cdb 100644 --- a/spring-boot/pom.xml +++ b/spring-boot/pom.xml @@ -246,6 +246,11 @@ spring-context-support test + + org.springframework.data + spring-data-redis + test + diff --git a/spring-boot/src/test/java/org/springframework/boot/redis/RedisTestServer.java b/spring-boot/src/test/java/org/springframework/boot/redis/RedisTestServer.java new file mode 100644 index 00000000000..92af3ad0f73 --- /dev/null +++ b/spring-boot/src/test/java/org/springframework/boot/redis/RedisTestServer.java @@ -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); + } + + } + +} diff --git a/spring-boot/src/test/java/org/springframework/boot/redis/package-info.java b/spring-boot/src/test/java/org/springframework/boot/redis/package-info.java new file mode 100644 index 00000000000..3cb5343b4ba --- /dev/null +++ b/spring-boot/src/test/java/org/springframework/boot/redis/package-info.java @@ -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; \ No newline at end of file