Add Smoke Tests asserting the proper behavior of a properly configured Spring ApplicationContext in the case of forced-disconnect / auto-reconnect events in a GemFire/Geode DistributedSystem (cluster).

This commit is contained in:
John Blum
2020-04-27 15:18:45 -07:00
parent 46722ea9c4
commit 08bb53f792
3 changed files with 225 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
apply plugin: 'io.spring.convention.spring-test'
description = "Smoke Tests asserting the proper function of a Spring Boot configured and bootstrapped Apache Geode peer Cache application in a simulated forced-disconnect/auto-reconnect scenairo."
dependencies {
implementation "org.assertj:assertj-core"
implementation project(":apache-geode-extensions")
implementation project(':spring-geode-starter')
// implementation project(':spring-geode-starter-logging')
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation project(":spring-geode-starter-test")
}

View File

@@ -0,0 +1,103 @@
/*
* 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 example.app.geode.cache.peer;
import static org.assertj.core.api.Assertions.assertThat;
import org.apache.geode.ForcedDisconnectException;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.distributed.DistributedSystem;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.gemfire.config.annotation.PeerCacheApplication;
import org.springframework.geode.distributed.event.ApplicationContextMembershipListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A Spring Boot, Apache Geode {@literal peer} {@link Cache} application configured and bootstrapped with the SBDG
* framework, thereby overriding the convention of creating a {@link ClientCache} instance by default.
*
* Additionally, this example class further explores how the Spring Boot configured and bootstrapped Apache Geode
* {@link PeerCacheApplication} might be self-aware that it is a peer member of a {@link DistributedSystem} (cluster),
* handling a possible {@link ForcedDisconnectException} and subsequent auto-reconnect, along with
* cluster configuration.
*
* This code and associated Smoke Tests is purely experimental/exploratory.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.distributed.DistributedSystem
* @see org.springframework.boot.SpringApplication
* @see org.springframework.boot.autoconfigure.SpringBootApplication
* @see org.springframework.boot.builder.SpringApplicationBuilder
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.context.annotation.Bean
* @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication
* @since 1.3.0
*/
@SpringBootApplication
@SuppressWarnings("unused")
public class SpringBootApacheGeodePeerCacheApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(SpringBootApacheGeodePeerCacheApplication.class)
//.contextClass(AnnotationConfigWebApplicationContext.class)
//.web(WebApplicationType.SERVLET)
.build()
.run(args);
}
private final Logger logger = LoggerFactory.getLogger(getClass());
@Bean
public ApplicationRunner peerCacheAssertRunner(Cache peerCache) {
return args -> {
assertThat(peerCache).isNotNull();
assertThat(peerCache.getName()).isEqualTo(SpringBootApacheGeodePeerCacheApplication.class.getSimpleName());
assertThat(peerCache.getDistributedSystem()).isNotNull();
assertThat(peerCache.getDistributedSystem().getProperties()).isNotNull();
assertThat(peerCache.getDistributedSystem().getProperties().getProperty("disable-auto-reconnect"))
.isEqualTo("false");
assertThat(peerCache.getDistributedSystem().getProperties().getProperty("use-cluster-configuration"))
.isEqualTo("true");
this.logger.info("Peer Cache [{}] configured and bootstrapped successfully!", peerCache.getName());
//System.err.printf("Peer Cache [%s] configured and bootstrapped successfully!%n", peerCache.getName());
};
}
@PeerCacheApplication(name = "SpringBootApacheGeodePeerCacheApplication",
enableAutoReconnect = true, useClusterConfiguration = true)
static class GeodeConfiguration {
@Bean
ApplicationContextMembershipListener applicationContextMembershipListener(
ConfigurableApplicationContext applicationContext, Cache peerCache) {
return new ApplicationContextMembershipListener(applicationContext).register(peerCache);
}
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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 example.app.geode.cache.peer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.geode.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.AbstractRefreshableApplicationContext;
import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects;
import org.springframework.geode.distributed.event.ApplicationContextMembershipListener;
import org.springframework.geode.distributed.event.MembershipListenerAdapter;
import org.springframework.geode.distributed.event.support.MemberDepartedEvent;
import org.springframework.geode.distributed.event.support.MemberJoinedEvent;
import org.springframework.geode.test.context.TestRefreshableApplicationContextLoader;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Unit Tests for {@link SpringBootApacheGeodePeerCacheApplication}.
*
* @author John Blum
* @see org.junit.Test
* @see org.apache.geode.cache.Cache
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.context.support.AbstractRefreshableApplicationContext
* @see org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects
* @see org.springframework.geode.test.context.TestRefreshableApplicationContextLoader
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @since 1.3.0
*/
@RunWith(SpringRunner.class)
@EnableGemFireMockObjects
@ContextConfiguration(
classes = SpringBootApacheGeodePeerCacheApplication.class,
loader = TestRefreshableApplicationContextLoader.class
)
@SuppressWarnings({ "unused" })
public class SpringBootApacheGeodePeerCacheApplicationUnitTests {
@Autowired
private ConfigurableApplicationContext applicationContext;
@Autowired
@Qualifier("applicationContextMembershipListener")
private MembershipListenerAdapter<ApplicationContextMembershipListener> membershipListener;
@Before
public void setup() {
//System.err.printf("ApplicationContext Type [%s]%n", ObjectUtils.nullSafeClassName(this.applicationContext));
assertThat(this.applicationContext).isInstanceOf(AbstractRefreshableApplicationContext.class);
}
@Test
public void memberFartedAndDepartedThenJoinedAndWasPurloined() {
MemberDepartedEvent mockMemberDepartedEvent = mock(MemberDepartedEvent.class);
MemberJoinedEvent mockMemberJoinedEvent = mock(MemberJoinedEvent.class);
Cache peerCache = this.applicationContext.getBean(Cache.class);
assertThat(peerCache).isNotNull();
this.membershipListener.handleMemberDeparted(mockMemberDepartedEvent);
assertThat(this.applicationContext.isActive()).isFalse();
assertThat(this.applicationContext.isRunning()).isFalse();
this.membershipListener.handleMemberJoined(mockMemberJoinedEvent);
assertThat(this.applicationContext.isActive()).isTrue();
assertThat(this.applicationContext.isRunning()).isTrue();
Cache reconnectedPeerCache = this.applicationContext.getBean(Cache.class);
assertThat(reconnectedPeerCache).isNotNull();
assertThat(reconnectedPeerCache).isNotSameAs(peerCache);
}
}