Add 'strictMatch' annotation attribute to the @EnableClusterAware annotation.

Using 'strictMatch' enables fail-fast behavior so that users can configure their Spring Boot, Apache Geode ClientCache applications to fail on startup if no cluster is available across any environment.

Additionally, enhanced the log output to give users better information about the runtime environment and whether an Apache Geode-based cluster was found and available.

Resolves gh-99.
This commit is contained in:
John Blum
2021-01-15 19:32:44 -08:00
parent 62848e9277
commit 4090cf4ebd
9 changed files with 560 additions and 47 deletions

View File

@@ -37,7 +37,7 @@ import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockO
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration Tests for {@link EnableClusterAware} and {@link ClusterAvailableConfiguration.ClusterAvailableCondition}
* Integration Tests for {@link EnableClusterAware} and {@link ClusterAvailableConfiguration.StandaloneClusterAvailableCondition}
* specifically when the Spring Boot application is run in CloudFoundry.
*
* @author John Blum

View File

@@ -118,6 +118,7 @@ public class ClusterAwareConfigurationUnitTests extends IntegrationTestsSupport
doReturn(false).when(this.condition).isMatch(eq(mockConditionContext));
doReturn(true).when(this.condition).doCachedMatch(eq(mockConditionContext));
doReturn(false).when(this.condition).isStrictMatch(any(), eq(mockConditionContext));
assertThat(this.condition.matches(mockConditionContext, null)).isTrue();
@@ -125,6 +126,7 @@ public class ClusterAwareConfigurationUnitTests extends IntegrationTestsSupport
order.verify(this.condition, times(1)).isMatch(eq(mockConditionContext));
order.verify(this.condition, times(1)).doCachedMatch(eq(mockConditionContext));
order.verify(this.condition, times(1)).isStrictMatch(any(), eq(mockConditionContext));
verifyNoInteractions(mockConditionContext);
}
@@ -135,6 +137,7 @@ public class ClusterAwareConfigurationUnitTests extends IntegrationTestsSupport
ConditionContext mockConditionContext = mock(ConditionContext.class);
doReturn(true).when(this.condition).isMatch(eq(mockConditionContext));
doReturn(false).when(this.condition).isStrictMatch(any(), eq(mockConditionContext));
assertThat(this.condition.matches(mockConditionContext, null)).isTrue();
@@ -142,6 +145,7 @@ public class ClusterAwareConfigurationUnitTests extends IntegrationTestsSupport
order.verify(this.condition, times(1)).isMatch(eq(mockConditionContext));
order.verify(this.condition, never()).doCachedMatch(any());
order.verify(this.condition, times(1)).isStrictMatch(any(), eq(mockConditionContext));
verifyNoInteractions(mockConditionContext);
}
@@ -237,7 +241,7 @@ public class ClusterAwareConfigurationUnitTests extends IntegrationTestsSupport
verify(this.condition, atLeastOnce()).getLogger();
verifyNoMoreInteractions(this.condition, mockConditionContext);
verifyNoMoreInteractions(mockConditionContext);
verifyNoInteractions(mockConnectionEndpointList, mockEnvironment);
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2020 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
*
* https://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.geode.config.annotation;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Properties;
import org.junit.AfterClass;
import org.junit.Test;
import org.apache.geode.cache.client.ClientCache;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.tests.integration.SpringBootApplicationIntegrationTestsSupport;
import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects;
/**
* Integration Tests for {@link EnableClusterAware} and {@link ClusterAwareConfiguration}
* as well as {@link ClusterAvailableConfiguration} when {@code strictMode} is {@literal true}
* configured in Spring Boot {@literal application.properties}
* using the {@literal spring.boot.data.gemfire.cluster.condition.match.strict} property
* when no Apache Geode Cluster was provisioned and made available to service Apache Geode
* {@link ClientCache clients}.
*
* @author John Blum
* @see java.util.Properties
* @see org.junit.Test
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.boot.builder.SpringApplicationBuilder
* @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication
* @see org.springframework.data.gemfire.tests.integration.SpringBootApplicationIntegrationTestsSupport
* @see org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects
* @see org.springframework.geode.config.annotation.EnableClusterAware
* @since 1.4.1
*/
public class PropertyConfiguredStrictMatchingClusterNotAvailableConfigurationIntegrationTests
extends SpringBootApplicationIntegrationTestsSupport {
@AfterClass
public static void tearDown() {
ClusterAwareConfiguration.ClusterAwareCondition.reset();
}
@Override
protected SpringApplicationBuilder processBeforeBuild(SpringApplicationBuilder springApplicationBuilder) {
Properties testProperties = new Properties();
testProperties
.setProperty(ClusterAwareConfiguration.SPRING_BOOT_DATA_GEMFIRE_CLUSTER_CONDITION_MATCH_STRICT_PROPERTY,
Boolean.TRUE.toString());
return springApplicationBuilder.properties(testProperties);
}
@Test(expected = ClusterNotAvailableException.class)
public void clusterNotAvailableExceptionThrownWhenClusterIsNotAvailableAndStrictMatchIsTrue() throws Throwable {
try {
newApplicationContext(TestGeodeClientConfiguration.class);
}
catch (Throwable expected) {
expected = NestedExceptionUtils.getMostSpecificCause(expected);
assertThat(expected).isInstanceOf(ClusterNotAvailableException.class);
assertThat(expected).hasMessage("Failed to find available cluster in [%s] when strictMatch was [true]",
ClusterAwareConfiguration.ClusterAwareCondition.RUNTIME_ENVIRONMENT_NAME);
assertThat(expected).hasNoCause();
throw expected;
}
}
@ClientCacheApplication
@EnableClusterAware(strictMatch = false)
@EnableGemFireMockObjects
@SuppressWarnings("all")
static class TestGeodeClientConfiguration { }
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2020 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
*
* https://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.geode.config.annotation;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.AfterClass;
import org.junit.Test;
import org.apache.geode.cache.client.ClientCache;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.tests.integration.SpringBootApplicationIntegrationTestsSupport;
import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects;
/**
* Integration Tests for {@link EnableClusterAware} and {@link ClusterAwareConfiguration}
* as well as {@link ClusterAvailableConfiguration} when {@code strictMode} is {@literal true}
* using the {@link EnableClusterAware#strictMatch()} annotation attribute when no Apache Geode Cluster
* was provisioned and made available to service Apache Geode {@link ClientCache clients}.
*
* @author John Blum
* @see org.junit.Test
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication
* @see org.springframework.data.gemfire.tests.integration.SpringBootApplicationIntegrationTestsSupport
* @see org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects
* @see org.springframework.geode.config.annotation.EnableClusterAware
* @since 1.4.1
*/
public class StrictMatchingClusterNotAvailableConfigurationIntegrationTests
extends SpringBootApplicationIntegrationTestsSupport {
@AfterClass
public static void tearDown() {
ClusterAwareConfiguration.ClusterAwareCondition.reset();
}
@Test(expected = ClusterNotAvailableException.class)
public void clusterNotAvailableExceptionThrownWhenClusterIsNotAvailableAndStrictMatchIsTrue() throws Throwable {
try {
newApplicationContext(TestGeodeClientConfiguration.class);
}
catch (Throwable expected) {
expected = NestedExceptionUtils.getMostSpecificCause(expected);
assertThat(expected).isInstanceOf(ClusterNotAvailableException.class);
assertThat(expected).hasMessage("Failed to find available cluster in [%s] when strictMatch was [true]",
ClusterAwareConfiguration.ClusterAwareCondition.RUNTIME_ENVIRONMENT_NAME);
assertThat(expected).hasNoCause();
throw expected;
}
}
@ClientCacheApplication
@EnableGemFireMockObjects
@EnableClusterAware(strictMatch = true)
static class TestGeodeClientConfiguration { }
}