From 3053bac169662498ee7168e38283fe1d1ca78a81 Mon Sep 17 00:00:00 2001 From: John Blum Date: Mon, 21 Oct 2019 15:29:35 -0700 Subject: [PATCH] Add Smoke Tests for a client/server Function execution use case, configured with SBDG auto-configuration on the client-side and SDG Function annotation config on the server-side. --- .../lombok.config | 2 + ...-tests-function-execution-on-region.gradle | 21 ++ .../PetServiceFunctionExecutions.java | 36 ++++ .../java/example/app/petclinic/model/Pet.java | 67 +++++++ .../app/petclinic/repo/PetRepository.java | 32 +++ .../PetClinicApplicationSmokeTests.java | 185 ++++++++++++++++++ .../src/test/resources/logback.xml | 22 +++ 7 files changed, 365 insertions(+) create mode 100644 spring-geode-tests/smoke-tests/function-execution-on-region/lombok.config create mode 100644 spring-geode-tests/smoke-tests/function-execution-on-region/spring-geode-smoke-tests-function-execution-on-region.gradle create mode 100644 spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/function/PetServiceFunctionExecutions.java create mode 100644 spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/model/Pet.java create mode 100644 spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/repo/PetRepository.java create mode 100644 spring-geode-tests/smoke-tests/function-execution-on-region/src/test/java/example/app/petclinic/PetClinicApplicationSmokeTests.java create mode 100644 spring-geode-tests/smoke-tests/function-execution-on-region/src/test/resources/logback.xml diff --git a/spring-geode-tests/smoke-tests/function-execution-on-region/lombok.config b/spring-geode-tests/smoke-tests/function-execution-on-region/lombok.config new file mode 100644 index 00000000..6aa51d71 --- /dev/null +++ b/spring-geode-tests/smoke-tests/function-execution-on-region/lombok.config @@ -0,0 +1,2 @@ +# This file is generated by the 'io.freefair.lombok' Gradle plugin +config.stopBubbling = true diff --git a/spring-geode-tests/smoke-tests/function-execution-on-region/spring-geode-smoke-tests-function-execution-on-region.gradle b/spring-geode-tests/smoke-tests/function-execution-on-region/spring-geode-smoke-tests-function-execution-on-region.gradle new file mode 100644 index 00000000..e04f7aff --- /dev/null +++ b/spring-geode-tests/smoke-tests/function-execution-on-region/spring-geode-smoke-tests-function-execution-on-region.gradle @@ -0,0 +1,21 @@ +plugins { + id "io.freefair.lombok" version "4.1.2" +} + +apply plugin: 'io.spring.convention.spring-test' + +description = "Smoke Tests asserting the proper execution of an Apache Geode Function using Spring Data for Apache Geode Function annotation support in a Spring Boot context." + +dependencies { + + implementation project(':spring-geode-starter') + + implementation "org.assertj:assertj-core" + implementation "org.projectlombok:lombok" + + testImplementation project(':spring-geode-starter-test') + + testImplementation('org.springframework.boot:spring-boot-starter-test') { + exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' + } +} diff --git a/spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/function/PetServiceFunctionExecutions.java b/spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/function/PetServiceFunctionExecutions.java new file mode 100644 index 00000000..c75b1723 --- /dev/null +++ b/spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/function/PetServiceFunctionExecutions.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019 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.petclinic.function; + +import org.springframework.data.gemfire.function.annotation.FunctionId; +import org.springframework.data.gemfire.function.annotation.OnRegion; + +import example.app.petclinic.model.Pet; + +/** + * Function interface declaring all {@link Pet} services administered by the Pet Clinic. + * + * @author John Blum + * @see example.app.petclinic.model.Pet + * @since 1.2.1 + */ +@OnRegion(region = "Pets") +public interface PetServiceFunctionExecutions { + + @FunctionId(("AdministerPetVaccinations")) + void administerPetVaccinations(); + +} diff --git a/spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/model/Pet.java b/spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/model/Pet.java new file mode 100644 index 00000000..e8c82063 --- /dev/null +++ b/spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/model/Pet.java @@ -0,0 +1,67 @@ +/* + * Copyright 2019 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.petclinic.model; + +import java.time.LocalDateTime; + +import org.springframework.data.annotation.Id; +import org.springframework.data.gemfire.mapping.annotation.Region; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +/** + * Abstract Data Type (ADT) modeling a pet. + * + * @author John Blum + * @see org.springframework.data.annotation.Id + * @see org.springframework.data.gemfire.mapping.annotation.Region + * @since 1.2.1 + */ +@Region("Pets") +@ToString(of = "name") +@EqualsAndHashCode(of = "name") +@RequiredArgsConstructor(staticName = "newPet") +@SuppressWarnings("unused") +public class Pet { + + @Getter + private LocalDateTime vaccinationDateTime; + + @Id @NonNull @Getter + private String name; + + @Getter + private Type petType; + + public Pet as(Type petType) { + this.petType = petType; + return this; + } + + public void vaccinate() { + this.vaccinationDateTime = LocalDateTime.now(); + } + + public enum Type { + CAT, + DOG, + RABBIT, + } +} diff --git a/spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/repo/PetRepository.java b/spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/repo/PetRepository.java new file mode 100644 index 00000000..b442513c --- /dev/null +++ b/spring-geode-tests/smoke-tests/function-execution-on-region/src/main/java/example/app/petclinic/repo/PetRepository.java @@ -0,0 +1,32 @@ +/* + * Copyright 2019 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.petclinic.repo; + +import org.springframework.data.repository.CrudRepository; + +import example.app.petclinic.model.Pet; + +/** + * Data Access Object (DAO) containing basic CRUD and simple Query data access operations on {@link Pet} objects. + * + * @author John Blum + * @see org.springframework.data.repository.CrudRepository + * @see example.app.petclinic.model.Pet + * @since 1.2.1 + */ +public interface PetRepository extends CrudRepository { + +} diff --git a/spring-geode-tests/smoke-tests/function-execution-on-region/src/test/java/example/app/petclinic/PetClinicApplicationSmokeTests.java b/spring-geode-tests/smoke-tests/function-execution-on-region/src/test/java/example/app/petclinic/PetClinicApplicationSmokeTests.java new file mode 100644 index 00000000..60f6c43d --- /dev/null +++ b/spring-geode-tests/smoke-tests/function-execution-on-region/src/test/java/example/app/petclinic/PetClinicApplicationSmokeTests.java @@ -0,0 +1,185 @@ +/* + * Copyright 2019 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.petclinic; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.Set; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.apache.geode.cache.Region; +import org.apache.geode.cache.execute.Function; +import org.apache.geode.cache.execute.FunctionContext; +import org.apache.geode.cache.execute.RegionFunctionContext; + +import org.apache.shiro.util.CollectionUtils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; +import org.springframework.data.gemfire.config.annotation.CacheServerApplication; +import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions; +import org.springframework.data.gemfire.config.annotation.EnablePdx; +import org.springframework.data.gemfire.config.annotation.PeerCacheApplication; +import org.springframework.data.gemfire.function.annotation.GemfireFunction; +import org.springframework.data.gemfire.function.config.EnableGemfireFunctions; +import org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import example.app.petclinic.function.PetServiceFunctionExecutions; +import example.app.petclinic.model.Pet; +import example.app.petclinic.repo.PetRepository; + +/** + * Smoke Tests asserting the proper injection and execution of an Apache Geode {@link Function} using Spring Data + * for Apache Geode {@link Function} annotation support in a Spring (Boot) context. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.execute.Function + * @see org.springframework.boot.autoconfigure.SpringBootApplication + * @see org.springframework.boot.test.context.SpringBootTest + * @see org.springframework.context.annotation.AnnotationConfigApplicationContext + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.annotation.Profile + * @see org.springframework.data.gemfire.config.annotation.CacheServerApplication + * @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication + * @see org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport + * @see org.springframework.test.context.ActiveProfiles + * @see org.springframework.test.context.junit4.SpringRunner + * @see PetServiceFunctionExecutions + * @see example.app.petclinic.model.Pet + * @see example.app.petclinic.repo.PetRepository + * @since 1.2.1 + */ +@ActiveProfiles("petclinic-client-function-execution") +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) +@SuppressWarnings("unused") +public class PetClinicApplicationSmokeTests extends ForkingClientServerIntegrationTestsSupport { + + @BeforeClass + public static void startGeodeServer() throws Exception { + startGemFireServer(GeodeServerTestConfiguration.class, + "-Dspring.profiles.active=petclinic-server-function-execution"); + } + + private Pet castle = Pet.newPet("Castle").as(Pet.Type.CAT); + private Pet cocoa = Pet.newPet("Cocoa").as(Pet.Type.CAT); + private Pet maha = Pet.newPet("Maha").as(Pet.Type.DOG); + private Pet mittens = Pet.newPet("Mittens").as(Pet.Type.CAT); + + private Set pets = CollectionUtils.asSet(castle, cocoa, maha, mittens); + + @Autowired + private PetRepository petRepository; + + @Autowired + private PetServiceFunctionExecutions petServiceFunctions; + + @Before + public void setup() { + + assertThat(this.petRepository.count()).isEqualTo(0); + + this.pets.forEach(pet -> assertThat(pet.getVaccinationDateTime()).isNull()); + this.petRepository.saveAll(this.pets); + + assertThat(this.petRepository.count()).isEqualTo(this.pets.size()); + } + + @Test + public void administerPetVaccinationsIsSuccessful() { + + LocalDateTime beforeVaccinations = LocalDateTime.now(); + + this.petServiceFunctions.administerPetVaccinations(); + + LocalDateTime afterVaccinations = LocalDateTime.now(); + + this.petRepository.findAll().forEach(pet -> { + + assertThat(pet.getVaccinationDateTime()) + .describedAs("Vaccinations [%s] for [%s] was not correct", pet.getVaccinationDateTime(), pet) + .isAfterOrEqualTo(beforeVaccinations); + + assertThat(pet.getVaccinationDateTime()).isBeforeOrEqualTo(afterVaccinations); + }); + } + + @Profile("petclinic-client-function-execution") + @EnableEntityDefinedRegions(basePackageClasses = Pet.class) + @SpringBootApplication(scanBasePackageClasses = PetClinicApplicationSmokeTests.class) + static class GeodeClientTestConfiguration { } + + @Profile("petclinic-peer-function-execution") + @PeerCacheApplication(name = "PetClinicApplicationSmokeTests") + @EnableEntityDefinedRegions(basePackageClasses = Pet.class) + @SpringBootApplication(scanBasePackageClasses = PetClinicApplicationSmokeTests.class) + static class GeodePeerTestConfiguration { } + + @Profile("petclinic-server-function-execution") + @CacheServerApplication(name = "PetClinicApplicationSmokeTestsServer") + @EnableEntityDefinedRegions(basePackageClasses = Pet.class) + @EnableGemfireFunctions + @EnablePdx + static class GeodeServerTestConfiguration { + + public static void main(String[] args) { + + AnnotationConfigApplicationContext applicationContext = + new AnnotationConfigApplicationContext(GeodeServerTestConfiguration.class); + + applicationContext.registerShutdownHook(); + } + + @Bean + PetServiceFunctions petServiceFunctions() { + return new PetServiceFunctions(); + } + } + + public static class PetServiceFunctions { + + @GemfireFunction(id = "AdministerPetVaccinations", optimizeForWrite = true) + public void administerPetVaccinations(FunctionContext functionContext) { + + Optional.ofNullable(functionContext) + .filter(RegionFunctionContext.class::isInstance) + .map(RegionFunctionContext.class::cast) + .map(RegionFunctionContext::getDataSet) + .map(Region::values) + .ifPresent(pets -> pets.forEach(pet -> { + + Pet resolvePet = (Pet) pet; + + resolvePet.vaccinate(); + + ((RegionFunctionContext) functionContext).getDataSet().put(resolvePet.getName(), resolvePet); + })); + } + } +} diff --git a/spring-geode-tests/smoke-tests/function-execution-on-region/src/test/resources/logback.xml b/spring-geode-tests/smoke-tests/function-execution-on-region/src/test/resources/logback.xml new file mode 100644 index 00000000..de99c52b --- /dev/null +++ b/spring-geode-tests/smoke-tests/function-execution-on-region/src/test/resources/logback.xml @@ -0,0 +1,22 @@ + + + + + + + + %d %5p %40.40c:%4L - %m%n + + + + + + + + + + + + + +