├── deploy ├── pubring.gpg.enc ├── secring.gpg.enc ├── publish.sh └── settings.xml ├── samples ├── spring-automocker-property-source-sample │ ├── src │ │ ├── main │ │ │ ├── config │ │ │ │ └── appli.properties │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── fridujo │ │ │ │ └── sample │ │ │ │ └── propertySource │ │ │ │ ├── TextService.java │ │ │ │ └── PropertySourceApplication.java │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── fridujo │ │ │ └── sample │ │ │ └── propertySource │ │ │ └── PropertySourceApplicationTest.java │ └── pom.xml ├── spring-automocker-amqp-sample │ ├── src │ │ ├── main │ │ │ ├── conf │ │ │ │ └── application.yml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── fridujo │ │ │ │ └── sample │ │ │ │ └── amqp │ │ │ │ ├── Receiver.java │ │ │ │ ├── Sender.java │ │ │ │ └── AmqpApplication.java │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── fridujo │ │ │ └── sample │ │ │ └── amqp │ │ │ └── AmqpApplicationTest.java │ └── pom.xml ├── spring-automocker-jms-sample │ ├── src │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── github │ │ │ │ │ └── fridujo │ │ │ │ │ └── sample │ │ │ │ │ └── jms │ │ │ │ │ ├── BusinessHeaders.java │ │ │ │ │ ├── JmsListenerContainerFactories.java │ │ │ │ │ ├── Broker.java │ │ │ │ │ ├── utils │ │ │ │ │ └── ActiveMQConnectionFactoryFactory.java │ │ │ │ │ ├── buyer │ │ │ │ │ ├── Buyer.java │ │ │ │ │ └── BuyerConfiguration.java │ │ │ │ │ ├── JmsApplication.java │ │ │ │ │ └── seller │ │ │ │ │ ├── SellerConfiguration.java │ │ │ │ │ └── Seller.java │ │ │ └── conf │ │ │ │ └── application.yml │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── fridujo │ │ │ └── sample │ │ │ └── jms │ │ │ └── JmsApplicationTest.java │ └── pom.xml ├── spring-automocker-jdbc-sample │ ├── src │ │ ├── main │ │ │ ├── conf │ │ │ │ └── application.yml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── fridujo │ │ │ │ └── sample │ │ │ │ └── jdbc │ │ │ │ ├── customer │ │ │ │ ├── CustomerRepository.java │ │ │ │ ├── Customer.java │ │ │ │ └── CustomerConfig.java │ │ │ │ ├── order │ │ │ │ ├── OrderRepository.java │ │ │ │ ├── LineItem.java │ │ │ │ ├── Order.java │ │ │ │ └── OrderConfig.java │ │ │ │ ├── JdbcApplication.java │ │ │ │ └── DataInitializer.java │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── fridujo │ │ │ └── sample │ │ │ └── jdbc │ │ │ └── JdbcApplicationTest.java │ └── pom.xml ├── spring-automocker-graphite-sample │ ├── src │ │ ├── main │ │ │ ├── conf │ │ │ │ └── application.yml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── fridujo │ │ │ │ └── sample │ │ │ │ └── graphite │ │ │ │ └── GraphiteApplication.java │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── fridujo │ │ │ └── sample │ │ │ └── graphite │ │ │ └── GraphiteApplicationTest.java │ └── pom.xml └── spring-automocker-mvc-sample │ ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── fridujo │ │ │ └── sample │ │ │ └── mvc │ │ │ ├── Customer.java │ │ │ └── MvcApplication.java │ └── test │ │ └── java │ │ └── com │ │ └── github │ │ └── fridujo │ │ └── sample │ │ └── mvc │ │ └── MvcApplicationTest.java │ └── pom.xml ├── .editorconfig ├── spring-automocker ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── fridujo │ │ │ │ └── automocker │ │ │ │ ├── api │ │ │ │ ├── Resettable.java │ │ │ │ ├── AfterBeanRegistrationExecutable.java │ │ │ │ ├── metrics │ │ │ │ │ ├── Point.java │ │ │ │ │ ├── DerivativeMetricAsserter.java │ │ │ │ │ ├── MetricAsserter.java │ │ │ │ │ ├── AbstractMetricAsserter.java │ │ │ │ │ ├── GraphiteMock.java │ │ │ │ │ └── GraphiteSenderMock.java │ │ │ │ ├── BeforeBeanRegistrationExecutable.java │ │ │ │ ├── ResetMocks.java │ │ │ │ ├── jms │ │ │ │ │ ├── JmsMockLocator.java │ │ │ │ │ ├── ErrorHandlerMock.java │ │ │ │ │ ├── DestinationManagerResetter.java │ │ │ │ │ ├── JmsDestinationAssert.java │ │ │ │ │ ├── JmsListenerContainerFactoryConfigurer.java │ │ │ │ │ ├── JmsMessageAssert.java │ │ │ │ │ ├── JmsMock.java │ │ │ │ │ └── JmsMessageBuilder.java │ │ │ │ ├── AfterBeanRegistration.java │ │ │ │ ├── BeforeBeanRegistration.java │ │ │ │ ├── jdbc │ │ │ │ │ ├── DataSourceResetter.java │ │ │ │ │ ├── DataSources.java │ │ │ │ │ └── Connections.java │ │ │ │ ├── tools │ │ │ │ │ └── BeanLocator.java │ │ │ │ └── ExtendedBeanDefinitionRegistry.java │ │ │ │ ├── utils │ │ │ │ ├── PropertiesBuilder.java │ │ │ │ ├── LamdaLuggageException.java │ │ │ │ ├── ThrowingConsumer.java │ │ │ │ ├── ThrowingBiConsumer.java │ │ │ │ ├── Maps.java │ │ │ │ ├── ThrowingFunction.java │ │ │ │ ├── Version.java │ │ │ │ ├── Classes.java │ │ │ │ ├── Annotations.java │ │ │ │ └── BeanDefinitions.java │ │ │ │ ├── context │ │ │ │ ├── AutomockerContextCustomizerFactory.java │ │ │ │ ├── ResettableTestExecutionListener.java │ │ │ │ ├── AutomockerContextCustomizer.java │ │ │ │ ├── AutomockerPostProcessor.java │ │ │ │ └── ExtendedBeanDefinitionRegistryImpl.java │ │ │ │ └── base │ │ │ │ ├── Automocker.java │ │ │ │ ├── RegisterTools.java │ │ │ │ ├── MockPropertySources.java │ │ │ │ ├── MockJdbc.java │ │ │ │ ├── MockAmqp.java │ │ │ │ ├── MockWebMvc.java │ │ │ │ ├── MockJms.java │ │ │ │ └── MockMicrometerGraphite.java │ │ └── resources │ │ │ ├── META-INF │ │ │ └── spring.factories │ │ │ └── logback.xml │ └── test │ │ └── java │ │ └── com │ │ └── github │ │ └── fridujo │ │ └── automocker │ │ ├── utils │ │ ├── PropertiesBuilderTest.java │ │ ├── MapsTest.java │ │ ├── VersionTest.java │ │ ├── AnnotationsTest.java │ │ ├── ClassesTest.java │ │ ├── ThrowingTest.java │ │ └── BeanDefinitionsTest.java │ │ ├── api │ │ ├── jms │ │ │ └── JmsMockLocatorTest.java │ │ ├── ExtendedBeanDefinitionRegistryTest.java │ │ └── tools │ │ │ └── BeanLocatorTest.java │ │ └── context │ │ ├── ResettableTestExecutionListenerTest.java │ │ └── ExtendedBeanDefinitionRegistryImplTest.java └── pom.xml ├── starters ├── README.md ├── spring-automocker-starter-jdbc │ └── pom.xml ├── spring-automocker-starter-web │ └── pom.xml ├── spring-automocker-starter-jms │ └── pom.xml ├── spring-automocker-starter-amqp │ └── pom.xml └── spring-automocker-starter │ └── pom.xml ├── .gitignore ├── .travis.yml └── README.md /deploy/pubring.gpg.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fridujo/spring-automocker/HEAD/deploy/pubring.gpg.enc -------------------------------------------------------------------------------- /deploy/secring.gpg.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fridujo/spring-automocker/HEAD/deploy/secring.gpg.enc -------------------------------------------------------------------------------- /samples/spring-automocker-property-source-sample/src/main/config/appli.properties: -------------------------------------------------------------------------------- 1 | text.literal=literal text content 2 | -------------------------------------------------------------------------------- /samples/spring-automocker-amqp-sample/src/main/conf/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | rabbitmq: 3 | host: 127.0.0.1 4 | username: guest 5 | password: guest 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | charset = utf-8 8 | 9 | indent_style = space 10 | indent_size = 4 11 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/Resettable.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api; 2 | 3 | public interface Resettable { 4 | 5 | void reset(); 6 | } 7 | -------------------------------------------------------------------------------- /starters/README.md: -------------------------------------------------------------------------------- 1 | # Starters 2 | 3 | Spring-Automocker Starters are a convenient way to get all needed dependencies in one shot with the right version. 4 | 5 | See [samples](samples/) for usage. 6 | -------------------------------------------------------------------------------- /deploy/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $TRAVIS_PULL_REQUEST == "false" && $TRAVIS_BRANCH == 'master' ]]; then 4 | mvn deploy --settings $GPG_DIR/settings.xml -DperformRelease=true -DskipTests=true 5 | exit $? 6 | fi 7 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/java/com/github/fridujo/sample/jms/BusinessHeaders.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms; 2 | 3 | public interface BusinessHeaders { 4 | String BUYER_ID = "BUYER_ID"; 5 | String SELLER_ID = "SELLER_ID"; 6 | } 7 | -------------------------------------------------------------------------------- /deploy/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ossrh 5 | ${env.SONATYPE_USERNAME} 6 | ${env.SONATYPE_PASSWORD} 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/conf/application.yml: -------------------------------------------------------------------------------- 1 | order: 2 | datasource: 3 | driverClassName: org.hsqldb.jdbcDriver 4 | url: jdbc:hsqldb:mem:order 5 | 6 | customer: 7 | datasource: 8 | driverClassName: org.hsqldb.jdbcDriver 9 | url: jdbc:hsqldb:mem:customer 10 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/conf/application.yml: -------------------------------------------------------------------------------- 1 | buyer: 2 | activemq: 3 | broker-url: vm://localhost?broker.persistent=false 4 | user: guest 5 | password: guest 6 | seller: 7 | activemq: 8 | broker-url: vm://localhost?broker.persistent=false 9 | user: guest 10 | password: guest 11 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/java/com/github/fridujo/sample/jms/JmsListenerContainerFactories.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms; 2 | 3 | public interface JmsListenerContainerFactories { 4 | String SELLER = "sellerJmsListenerContainerFactory"; 5 | String BUYER = "buyerJmsListenerContainerFactory"; 6 | } 7 | -------------------------------------------------------------------------------- /spring-automocker/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.test.context.ContextCustomizerFactory=\ 2 | com.github.fridujo.automocker.context.AutomockerContextCustomizerFactory 3 | 4 | org.springframework.test.context.TestExecutionListener=\ 5 | com.github.fridujo.automocker.context.ResettableTestExecutionListener 6 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/AfterBeanRegistrationExecutable.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api; 2 | 3 | import java.lang.annotation.Annotation; 4 | 5 | public interface AfterBeanRegistrationExecutable { 6 | 7 | void execute(A annotation, ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry); 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | pom.xml.next 7 | release.properties 8 | dependency-reduced-pom.xml 9 | buildNumber.properties 10 | .mvn/timing.properties 11 | 12 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 13 | !/.mvn/wrapper/maven-wrapper.jar 14 | 15 | # IntelliJ 16 | .idea/ 17 | *.iml 18 | -------------------------------------------------------------------------------- /samples/spring-automocker-graphite-sample/src/main/conf/application.yml: -------------------------------------------------------------------------------- 1 | management.metrics.export.graphite: 2 | # The location of your Graphite server 3 | host: mygraphitehost 4 | 5 | # You will probably want to conditionally disable Graphite publishing in local development. 6 | enabled: true 7 | 8 | # The interval at which metrics are sent to Graphite. The default is 1 minute. 9 | step: 1m 10 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/java/com/github/fridujo/sample/jdbc/customer/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc.customer; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | import java.util.Optional; 6 | 7 | public interface CustomerRepository extends CrudRepository { 8 | 9 | Optional findByLastname(String lastname); 10 | } 11 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/metrics/Point.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.metrics; 2 | 3 | public class Point { 4 | static final Point NEUTRAl_ELEMENT = new Point(0, 0); 5 | final long timestamp; 6 | final double value; 7 | 8 | Point(long timestamp, double value) { 9 | this.timestamp = timestamp; 10 | this.value = value; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/BeforeBeanRegistrationExecutable.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api; 2 | 3 | import org.springframework.context.ConfigurableApplicationContext; 4 | 5 | import java.lang.annotation.Annotation; 6 | 7 | public interface BeforeBeanRegistrationExecutable { 8 | 9 | void execute(A annotation, ConfigurableApplicationContext context); 10 | } 11 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/java/com/github/fridujo/sample/jdbc/order/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc.order; 2 | 3 | import com.github.fridujo.sample.jdbc.customer.Customer; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface OrderRepository extends CrudRepository { 9 | 10 | List findByCustomer(Customer.CustomerId id); 11 | } 12 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/PropertiesBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import java.util.Properties; 4 | 5 | public final class PropertiesBuilder { 6 | private PropertiesBuilder() { 7 | } 8 | 9 | public static Properties of(String key, String value) { 10 | Properties properties = new Properties(); 11 | properties.setProperty(key, value); 12 | return properties; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/LamdaLuggageException.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | @SuppressWarnings("serial") 4 | public class LamdaLuggageException extends RuntimeException { 5 | 6 | LamdaLuggageException(Exception cause) { 7 | super(cause); 8 | } 9 | 10 | public static RuntimeException wrap(Exception e) { 11 | if (e instanceof RuntimeException) { 12 | return (RuntimeException) e; 13 | } else { 14 | return new LamdaLuggageException(e); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/ThrowingConsumer.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import java.util.function.Consumer; 4 | 5 | @FunctionalInterface 6 | public interface ThrowingConsumer { 7 | 8 | static Consumer silent(ThrowingConsumer throwing) { 9 | return t -> { 10 | try { 11 | throwing.accept(t); 12 | } catch (Exception e) { 13 | throw LamdaLuggageException.wrap(e); 14 | } 15 | }; 16 | } 17 | 18 | void accept(T t) throws Exception; 19 | } 20 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/utils/PropertiesBuilderTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Properties; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | import static org.assertj.core.data.MapEntry.entry; 9 | 10 | class PropertiesBuilderTest { 11 | 12 | @Test 13 | void trivial_singleton_properties() { 14 | Properties properties = PropertiesBuilder.of("testKey", "testValue"); 15 | 16 | assertThat(properties).containsOnly(entry("testKey", "testValue")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /samples/spring-automocker-amqp-sample/src/main/java/com/github/fridujo/sample/amqp/Receiver.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.amqp; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | @Component 9 | public class Receiver { 10 | 11 | private final List messages = new ArrayList<>(); 12 | 13 | public void receiveMessage(String message) { 14 | System.out.println("Received <" + message + ">"); 15 | this.messages.add(message); 16 | } 17 | 18 | public List getMessages() { 19 | return messages; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/ThrowingBiConsumer.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import java.util.function.BiConsumer; 4 | 5 | @FunctionalInterface 6 | public interface ThrowingBiConsumer { 7 | 8 | static BiConsumer silent(ThrowingBiConsumer throwing) { 9 | return (t, u) -> { 10 | try { 11 | throwing.accept(t, u); 12 | } catch (Exception e) { 13 | throw LamdaLuggageException.wrap(e); 14 | } 15 | }; 16 | } 17 | 18 | void accept(T t, U u) throws Exception; 19 | } 20 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/ResetMocks.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Activate a {@link org.springframework.test.context.TestExecutionListener} to 11 | * reset any bean implementing {@link Resettable}. 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Documented 16 | public @interface ResetMocks { 17 | boolean disable() default false; 18 | } 19 | -------------------------------------------------------------------------------- /samples/spring-automocker-amqp-sample/src/main/java/com/github/fridujo/sample/amqp/Sender.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.amqp; 2 | 3 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | public class Sender { 8 | 9 | private final RabbitTemplate rabbitTemplate; 10 | 11 | public Sender(RabbitTemplate rabbitTemplate) { 12 | this.rabbitTemplate = rabbitTemplate; 13 | } 14 | 15 | public void send() { 16 | System.out.println("Sending message..."); 17 | rabbitTemplate.convertAndSend("", AmqpApplication.QUEUE_NAME, "Hello from RabbitMQ!"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/java/com/github/fridujo/sample/jms/Broker.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms; 2 | 3 | import org.springframework.beans.factory.annotation.Qualifier; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | @Target({ElementType.FIELD, 11 | ElementType.METHOD, 12 | ElementType.TYPE, 13 | ElementType.PARAMETER}) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Qualifier 16 | public @interface Broker { 17 | Type value(); 18 | 19 | enum Type { 20 | SELLER, 21 | BUYER 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/context/AutomockerContextCustomizerFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.context; 2 | 3 | import org.springframework.test.context.ContextConfigurationAttributes; 4 | import org.springframework.test.context.ContextCustomizer; 5 | import org.springframework.test.context.ContextCustomizerFactory; 6 | 7 | import java.util.List; 8 | 9 | class AutomockerContextCustomizerFactory implements ContextCustomizerFactory { 10 | @Override 11 | public ContextCustomizer createContextCustomizer(Class testClass, List configAttributes) { 12 | return new AutomockerContextCustomizer(testClass); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/base/Automocker.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.base; 2 | 3 | import com.github.fridujo.automocker.api.ResetMocks; 4 | 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | /** 12 | * Collection of mocking strategies supplied by default. 13 | */ 14 | @Target(ElementType.TYPE) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Documented 17 | 18 | @RegisterTools 19 | @ResetMocks 20 | @MockPropertySources 21 | @MockWebMvc 22 | @MockJdbc 23 | @MockJms 24 | @MockMicrometerGraphite 25 | @MockAmqp 26 | public @interface Automocker { 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/spring-automocker-mvc-sample/src/main/java/com/github/fridujo/sample/mvc/Customer.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.mvc; 2 | 3 | public class Customer { 4 | 5 | private final int id; 6 | private final String firstName; 7 | private final String lastName; 8 | 9 | public Customer(int id, String firstName, String lastName) { 10 | this.id = id; 11 | this.firstName = firstName; 12 | this.lastName = lastName; 13 | } 14 | 15 | public String getFirstName() { 16 | return firstName; 17 | } 18 | 19 | public String getLastName() { 20 | return lastName; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | return String.format("Customer[firstName='%s', lastName='%s']", firstName, lastName); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/metrics/DerivativeMetricAsserter.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.metrics; 2 | 3 | import java.util.List; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | 7 | public class DerivativeMetricAsserter extends AbstractMetricAsserter { 8 | 9 | public DerivativeMetricAsserter(String metricName, List points) { 10 | super(metricName, points); 11 | } 12 | 13 | public void hasLastValue(int expectedValue) { 14 | Point lastPoint = getLastPoint(); 15 | final Point penultimatePoint = getPenultimatePoint(); 16 | 17 | assertThat(lastPoint.value - penultimatePoint.value) 18 | .as("Last recorded derivative of metric [" + metricName + "]") 19 | .isEqualTo(expectedValue); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/JmsMockLocator.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jms; 2 | 3 | import javax.jms.ConnectionFactory; 4 | import java.util.Optional; 5 | import java.util.Set; 6 | 7 | /** 8 | * Used to find {@link JmsMock} by {@link ConnectionFactory}. 9 | * 10 | * @see JmsListenerContainerFactoryConfigurer 11 | */ 12 | public class JmsMockLocator { 13 | 14 | private final Set jmsMocks; 15 | 16 | JmsMockLocator(Set jmsMocks) { 17 | this.jmsMocks = jmsMocks; 18 | } 19 | 20 | Optional getJmsMockByConnectionFactory(ConnectionFactory connectionFactory) { 21 | return jmsMocks 22 | .stream() 23 | .filter(jmsMock -> jmsMock.connectionFactory == connectionFactory) 24 | .findFirst(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/metrics/MetricAsserter.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.metrics; 2 | 3 | import java.util.List; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | 7 | public class MetricAsserter extends AbstractMetricAsserter { 8 | 9 | public MetricAsserter(String metricName, List points) { 10 | super(metricName, points); 11 | } 12 | 13 | public void hasLastValue(double expectedValue) { 14 | Point lastPoint = getLastPoint(); 15 | 16 | assertThat(lastPoint.value) 17 | .as("Last recorded value of metric [" + metricName + "]") 18 | .isEqualTo(expectedValue); 19 | } 20 | 21 | public DerivativeMetricAsserter derivative() { 22 | return new DerivativeMetricAsserter(metricName, points); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/Maps.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class Maps { 7 | 8 | @SuppressWarnings("unchecked") 9 | public static Map build(Class keyClas, Object... keysAndValues) { 10 | if (keysAndValues.length % 2 != 0) { 11 | throw new IllegalArgumentException("keysAndValues array must be even"); 12 | } 13 | Map map = new HashMap<>(); 14 | K key = null; 15 | for (int i = 0; i < keysAndValues.length; i++) { 16 | if (i % 2 == 0) { 17 | key = keyClas.cast(keysAndValues[i]); 18 | } else { 19 | map.put(key, (V) keysAndValues[i]); 20 | } 21 | } 22 | return map; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/ThrowingFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import java.util.function.Function; 4 | 5 | @FunctionalInterface 6 | public interface ThrowingFunction { 7 | 8 | static Function silent(ThrowingFunction throwing) { 9 | return silent(throwing, e -> { 10 | throw LamdaLuggageException.wrap(e); 11 | }); 12 | } 13 | 14 | static Function silent(ThrowingFunction throwing, 15 | Function errorHandler) { 16 | return t -> { 17 | try { 18 | return throwing.apply(t); 19 | } catch (Exception e) { 20 | return errorHandler.apply(e); 21 | } 22 | }; 23 | } 24 | 25 | R apply(T t) throws Exception; 26 | } 27 | -------------------------------------------------------------------------------- /samples/spring-automocker-property-source-sample/src/main/java/com/github/fridujo/sample/propertySource/TextService.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.propertySource; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Service; 5 | 6 | import java.util.Optional; 7 | 8 | @Service 9 | class TextService { 10 | 11 | private final String literalText; 12 | private final Optional optionalText; 13 | 14 | TextService(@Value("${text.literal}") 15 | String literalText, @Value("${text.optional:}") 16 | Optional optionalText) { 17 | this.literalText = literalText; 18 | this.optionalText = optionalText; 19 | } 20 | 21 | 22 | public String getLiteralText() { 23 | return literalText; 24 | } 25 | 26 | public String getOptionalText() { 27 | return optionalText.get(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/utils/MapsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Map; 6 | 7 | import static org.assertj.core.api.Assertions.assertThat; 8 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 9 | import static org.assertj.core.data.MapEntry.entry; 10 | 11 | class MapsTest { 12 | 13 | @Test 14 | void simple_case() { 15 | Map labelsByIndex = Maps.build(Integer.class, 1, "test1", 2, "test2"); 16 | assertThat(labelsByIndex).containsOnly(entry(1, "test1"), entry(2, "test2")); 17 | } 18 | 19 | @Test 20 | void odd_number_of_key_and_values() { 21 | assertThatExceptionOfType(IllegalArgumentException.class) 22 | .isThrownBy(() -> Maps.build(String.class, "key1")) 23 | .withMessage("keysAndValues array must be even"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/ErrorHandlerMock.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jms; 2 | 3 | import com.github.fridujo.automocker.api.Resettable; 4 | import org.springframework.util.ErrorHandler; 5 | 6 | import java.util.Optional; 7 | 8 | public class ErrorHandlerMock implements ErrorHandler, Resettable { 9 | 10 | private final Optional delegate; 11 | private Throwable lastCatched = null; 12 | 13 | ErrorHandlerMock(Optional delegate) { 14 | this.delegate = delegate; 15 | } 16 | 17 | @Override 18 | public void handleError(Throwable t) { 19 | lastCatched = t; 20 | delegate.ifPresent(e -> e.handleError(t)); 21 | } 22 | 23 | public Optional getLastCatched() { 24 | return Optional.ofNullable(lastCatched); 25 | } 26 | 27 | @Override 28 | public void reset() { 29 | this.lastCatched = null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/AfterBeanRegistration.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Repeatable; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | @Target(ElementType.ANNOTATION_TYPE) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Documented 14 | @Inherited 15 | @Repeatable(AfterBeanRegistration.AfterBeanRegistrations.class) 16 | public @interface AfterBeanRegistration { 17 | 18 | Class value(); 19 | 20 | @Target(ElementType.ANNOTATION_TYPE) 21 | @Retention(RetentionPolicy.RUNTIME) 22 | @Documented 23 | @Inherited 24 | @interface AfterBeanRegistrations { 25 | AfterBeanRegistration[] value(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/BeforeBeanRegistration.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Inherited; 6 | import java.lang.annotation.Repeatable; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | 11 | @Target(ElementType.ANNOTATION_TYPE) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Documented 14 | @Inherited 15 | @Repeatable(BeforeBeanRegistration.BeforeBeanRegistrations.class) 16 | public @interface BeforeBeanRegistration { 17 | 18 | Class value(); 19 | 20 | @Target(ElementType.ANNOTATION_TYPE) 21 | @Retention(RetentionPolicy.RUNTIME) 22 | @Documented 23 | @Inherited 24 | @interface BeforeBeanRegistrations { 25 | BeforeBeanRegistration[] value(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /spring-automocker/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36}.%L - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/java/com/github/fridujo/sample/jdbc/order/LineItem.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc.order; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import java.util.Objects; 7 | 8 | @Entity 9 | public class LineItem { 10 | 11 | private final String description; 12 | @Id 13 | @GeneratedValue 14 | private Long id; 15 | 16 | public LineItem() { 17 | description = null; 18 | } 19 | 20 | public LineItem(String description) { 21 | this.description = description; 22 | } 23 | 24 | @Override 25 | public boolean equals(Object o) { 26 | if (this == o) return true; 27 | if (o == null || getClass() != o.getClass()) return false; 28 | LineItem lineItem = (LineItem) o; 29 | return Objects.equals(id, lineItem.id); 30 | } 31 | 32 | @Override 33 | public int hashCode() { 34 | 35 | return Objects.hash(id); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/java/com/github/fridujo/sample/jms/utils/ActiveMQConnectionFactoryFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms.utils; 2 | 3 | import org.apache.activemq.ActiveMQConnectionFactory; 4 | import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQProperties; 5 | 6 | import javax.jms.ConnectionFactory; 7 | 8 | public class ActiveMQConnectionFactoryFactory { 9 | 10 | private final ActiveMQProperties activeMQProperties; 11 | 12 | public ActiveMQConnectionFactoryFactory(ActiveMQProperties activeMQProperties) { 13 | this.activeMQProperties = activeMQProperties; 14 | } 15 | 16 | public ConnectionFactory create() { 17 | String username = activeMQProperties.getUser(); 18 | String password = activeMQProperties.getPassword(); 19 | String brokerUrl = activeMQProperties.getBrokerUrl(); 20 | 21 | ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(username, password, brokerUrl); 22 | return connectionFactory; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/metrics/AbstractMetricAsserter.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.metrics; 2 | 3 | import java.util.List; 4 | 5 | public class AbstractMetricAsserter { 6 | 7 | protected final String metricName; 8 | protected final List points; 9 | 10 | protected AbstractMetricAsserter(String metricName, List points) { 11 | this.metricName = metricName; 12 | this.points = points; 13 | } 14 | 15 | protected Point getLastPoint() { 16 | if (points.isEmpty()) { 17 | throw new AssertionError("No values recorded for metric " + metricName); 18 | } 19 | return points.get(points.size() - 1); 20 | } 21 | 22 | protected Point getPenultimatePoint() { 23 | final Point penultimatePoint; 24 | if (points.size() > 1) { 25 | penultimatePoint = points.get(points.size() - 2); 26 | } else { 27 | penultimatePoint = Point.NEUTRAl_ELEMENT; 28 | } 29 | return penultimatePoint; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/metrics/GraphiteMock.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.metrics; 2 | 3 | import com.codahale.metrics.graphite.GraphiteReporter; 4 | 5 | public class GraphiteMock { 6 | 7 | private final GraphiteSenderMock graphiteSenderMock; 8 | private final GraphiteReporter graphiteReporter; 9 | 10 | public GraphiteMock(GraphiteSenderMock graphiteSenderMock, GraphiteReporter graphiteReporter) { 11 | this.graphiteSenderMock = graphiteSenderMock; 12 | this.graphiteReporter = graphiteReporter; 13 | } 14 | 15 | public MetricAsserter assertThatMetric(String metricName) { 16 | if (!graphiteSenderMock.getMetrics().containsKey(metricName)) { 17 | throw new IllegalArgumentException("No metric named [" + metricName + "] have been sent to Graphite"); 18 | } 19 | return new MetricAsserter(metricName, graphiteSenderMock.getMetrics().get(metricName)); 20 | } 21 | 22 | public GraphiteMock afterReporting() { 23 | graphiteReporter.report(); 24 | return this; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /starters/spring-automocker-starter-jdbc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | spring-automocker-reactor 8 | com.github.fridujo 9 | 1.2.2-SNAPSHOT 10 | ../../pom.xml 11 | 12 | 13 | spring-automocker-starter-jdbc 14 | 15 | 16 | 17 | com.github.fridujo 18 | spring-automocker-starter 19 | ${automocker.version} 20 | compile 21 | 22 | 23 | com.h2database 24 | h2 25 | ${h2.version} 26 | compile 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /starters/spring-automocker-starter-web/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | spring-automocker-reactor 8 | com.github.fridujo 9 | 1.2.2-SNAPSHOT 10 | ../../pom.xml 11 | 12 | 13 | spring-automocker-starter-web 14 | 15 | 16 | 17 | com.github.fridujo 18 | spring-automocker-starter 19 | ${automocker.version} 20 | compile 21 | 22 | 23 | org.hamcrest 24 | hamcrest-core 25 | ${hamcrest.version} 26 | compile 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/spring-automocker-property-source-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | spring-automocker-reactor 8 | com.github.fridujo 9 | 1.2.2-SNAPSHOT 10 | ../../pom.xml 11 | 12 | 13 | spring-automocker-property-source-sample 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-autoconfigure 19 | ${spring-boot.version} 20 | 21 | 22 | 23 | 24 | com.github.fridujo 25 | spring-automocker-starter 26 | ${automocker.version} 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /starters/spring-automocker-starter-jms/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | spring-automocker-reactor 8 | com.github.fridujo 9 | 1.2.2-SNAPSHOT 10 | ../../pom.xml 11 | 12 | 13 | spring-automocker-starter-jms 14 | 15 | 16 | 17 | com.github.fridujo 18 | spring-automocker-starter 19 | ${automocker.version} 20 | compile 21 | 22 | 23 | com.mockrunner 24 | mockrunner-jms 25 | ${mockrunner.version} 26 | compile 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /starters/spring-automocker-starter-amqp/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | spring-automocker-reactor 8 | com.github.fridujo 9 | 1.2.2-SNAPSHOT 10 | ../../pom.xml 11 | 12 | 13 | spring-automocker-starter-amqp 14 | 15 | 16 | 17 | com.github.fridujo 18 | spring-automocker-starter 19 | ${automocker.version} 20 | compile 21 | 22 | 23 | com.github.fridujo 24 | rabbitmq-mock 25 | ${rabbitmq-mock.version} 26 | compile 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/metrics/GraphiteSenderMock.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.metrics; 2 | 3 | import com.codahale.metrics.graphite.GraphiteSender; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedHashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | public class GraphiteSenderMock implements GraphiteSender { 11 | 12 | private final Map> metrics = new LinkedHashMap<>(); 13 | 14 | @Override 15 | public void connect() { 16 | } 17 | 18 | @Override 19 | public void send(String name, String value, long timestamp) { 20 | if (!metrics.containsKey(name)) { 21 | metrics.put(name, new ArrayList<>()); 22 | } 23 | metrics.get(name).add(new Point(timestamp, Double.valueOf(value))); 24 | } 25 | 26 | @Override 27 | public void flush() { 28 | } 29 | 30 | @Override 31 | public boolean isConnected() { 32 | return true; 33 | } 34 | 35 | @Override 36 | public int getFailures() { 37 | return 0; 38 | } 39 | 40 | @Override 41 | public void close() { 42 | } 43 | 44 | public Map> getMetrics() { 45 | return metrics; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/base/RegisterTools.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.base; 2 | 3 | import com.github.fridujo.automocker.api.AfterBeanRegistration; 4 | import com.github.fridujo.automocker.api.AfterBeanRegistrationExecutable; 5 | import com.github.fridujo.automocker.api.ExtendedBeanDefinitionRegistry; 6 | import com.github.fridujo.automocker.api.tools.BeanLocator; 7 | 8 | import java.lang.annotation.Annotation; 9 | import java.lang.annotation.Documented; 10 | import java.lang.annotation.ElementType; 11 | import java.lang.annotation.Retention; 12 | import java.lang.annotation.RetentionPolicy; 13 | import java.lang.annotation.Target; 14 | 15 | /** 16 | * Register utilities. 17 | */ 18 | @Target(ElementType.TYPE) 19 | @Retention(RetentionPolicy.RUNTIME) 20 | @Documented 21 | 22 | @AfterBeanRegistration(RegisterTools.RegisterToolsExecutable.class) 23 | public @interface RegisterTools { 24 | 25 | class RegisterToolsExecutable implements AfterBeanRegistrationExecutable { 26 | 27 | @Override 28 | public void execute(Annotation annotation, ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry) { 29 | extendedBeanDefinitionRegistry.registerBeanDefinition(BeanLocator.class); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/test/java/com/github/fridujo/sample/jms/JmsApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms; 2 | 3 | import com.github.fridujo.automocker.api.jms.JmsMock; 4 | import com.github.fridujo.automocker.base.Automocker; 5 | import org.assertj.core.api.AbstractAssert; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.jupiter.api.extension.ExtendWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.test.context.ContextConfiguration; 10 | import org.springframework.test.context.junit.jupiter.SpringExtension; 11 | 12 | @Automocker 13 | @ExtendWith(SpringExtension.class) 14 | @ContextConfiguration(classes = JmsApplication.class) 15 | class JmsApplicationTest { 16 | 17 | @Autowired 18 | @Broker(Broker.Type.BUYER) 19 | private JmsMock buyerJmsMock; 20 | 21 | @Test 22 | void buyer_receives_item_when_available() { 23 | String item = "available AC/DC concert tickets"; 24 | buyerJmsMock.sendText("REQUEST_ITEM", item); 25 | 26 | buyerJmsMock.assertThatDestination("BOUGHT") 27 | .consumingFirstMessage() 28 | .textSatisfies(actual -> actual.isEqualTo(item)) 29 | .headerSatisfies(BusinessHeaders.BUYER_ID, AbstractAssert::isNotNull) 30 | .headerSatisfies(BusinessHeaders.SELLER_ID, AbstractAssert::isNotNull); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/utils/VersionTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.params.ParameterizedTest; 5 | import org.junit.jupiter.params.provider.Arguments; 6 | import org.junit.jupiter.params.provider.MethodSource; 7 | 8 | import java.util.stream.Stream; 9 | 10 | import static com.github.fridujo.automocker.utils.Version.major; 11 | import static com.github.fridujo.automocker.utils.Version.spring; 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | 14 | class VersionTest { 15 | 16 | static Stream before_behaves_as_expected() { 17 | return Stream.of( 18 | Arguments.of(major(0).minor(0), major(0).minor(1), true), 19 | Arguments.of(major(0).minor(0), major(1).minor(0), true), 20 | Arguments.of(major(1).minor(0), major(0).minor(1), false), 21 | Arguments.of(major(1).minor(4), major(1).minor(4), false) 22 | ); 23 | } 24 | 25 | @ParameterizedTest(name = "{0} is before {1} = {2}") 26 | @MethodSource 27 | void before_behaves_as_expected(Version first, Version second, boolean before) { 28 | assertThat(first.isBefore(second)).isEqualTo(before); 29 | } 30 | 31 | @Test 32 | void spring_version_is_after_4_3() { 33 | assertThat(major(4).minor(3).isBefore(spring())); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jdbc/DataSourceResetter.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jdbc; 2 | 3 | 4 | import com.github.fridujo.automocker.api.Resettable; 5 | 6 | import javax.sql.DataSource; 7 | import java.util.Map; 8 | 9 | public class DataSourceResetter implements Resettable { 10 | 11 | private final Map datasourcesByName; 12 | 13 | DataSourceResetter(Map datasourcesByName) { 14 | this.datasourcesByName = datasourcesByName; 15 | } 16 | 17 | @Override 18 | public void reset() { 19 | datasourcesByName.forEach((dbName, dataSource) -> { 20 | reset(dbName, dataSource); 21 | }); 22 | } 23 | 24 | private void reset(String dbName, DataSource dataSource) { 25 | try { 26 | DataSources.doInConnection(dataSource, c -> { 27 | Connections.execute(c, "SET REFERENTIAL_INTEGRITY FALSE"); 28 | try { 29 | Connections.tables(c) 30 | .forEach(tableName -> Connections.truncate(c, tableName)); 31 | } finally { 32 | Connections.execute(c, "SET REFERENTIAL_INTEGRITY TRUE"); 33 | } 34 | }); 35 | } catch (RuntimeException e) { 36 | throw new IllegalStateException("Could not reset DB[" + dbName + "]", e); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/java/com/github/fridujo/sample/jdbc/order/Order.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc.order; 2 | 3 | import com.github.fridujo.sample.jdbc.customer.Customer; 4 | import org.springframework.util.Assert; 5 | 6 | import javax.persistence.CascadeType; 7 | import javax.persistence.Entity; 8 | import javax.persistence.FetchType; 9 | import javax.persistence.GeneratedValue; 10 | import javax.persistence.Id; 11 | import javax.persistence.OneToMany; 12 | import javax.persistence.Table; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | @Entity 17 | // Needs to be explicitly named as Order is a reserved keyword 18 | @Table(name = "SampleOrder") 19 | public class Order { 20 | 21 | private final Customer.CustomerId customer; 22 | @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) 23 | private final List lineItems = new ArrayList<>(); 24 | @Id 25 | @GeneratedValue 26 | private Long id; 27 | 28 | public Order() { 29 | customer = null; 30 | } 31 | 32 | public Order(Customer.CustomerId customer) { 33 | this.customer = customer; 34 | } 35 | 36 | public void add(LineItem lineItem) { 37 | Assert.notNull(lineItem, "Line item must not be null!"); 38 | 39 | this.lineItems.add(lineItem); 40 | } 41 | 42 | public List getLineItems() { 43 | return lineItems; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/DestinationManagerResetter.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jms; 2 | 3 | import com.github.fridujo.automocker.api.Resettable; 4 | import com.mockrunner.jms.DestinationManager; 5 | import com.mockrunner.mock.jms.MockDestination; 6 | import org.springframework.test.util.ReflectionTestUtils; 7 | 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | public class DestinationManagerResetter implements Resettable { 12 | 13 | private final Set destinationManagers; 14 | 15 | public DestinationManagerResetter(Set destinationManagers) { 16 | this.destinationManagers = destinationManagers; 17 | } 18 | 19 | @SuppressWarnings("unchecked") 20 | @Override 21 | public void reset() { 22 | for (DestinationManager destinationManager : destinationManagers) { 23 | // TODO make a PR to mockrunner-jms to avoid these reflective accesses 24 | Map queues = 25 | (Map) ReflectionTestUtils.getField(destinationManager, "queues"); 26 | Map topics = 27 | (Map) ReflectionTestUtils.getField(destinationManager, "topics"); 28 | queues.values().forEach(d -> d.reset()); 29 | topics.values().forEach(d -> d.reset()); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | spring-automocker-reactor 6 | com.github.fridujo 7 | 1.2.2-SNAPSHOT 8 | ../../pom.xml 9 | 10 | 4.0.0 11 | 12 | spring-automocker-jdbc-sample 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-data-jpa 18 | ${spring-boot.version} 19 | 20 | 21 | org.hsqldb 22 | hsqldb 23 | ${hsqldb.version} 24 | 25 | 26 | 27 | 28 | com.github.fridujo 29 | spring-automocker-starter-jdbc 30 | ${automocker.version} 31 | test 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /samples/spring-automocker-mvc-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | spring-automocker-reactor 6 | com.github.fridujo 7 | 1.2.2-SNAPSHOT 8 | ../../pom.xml 9 | 10 | 4.0.0 11 | 12 | spring-automocker-mvc-sample 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | ${spring-boot.version} 19 | 20 | 21 | org.slf4j 22 | slf4j-api 23 | ${slf4j.version} 24 | 25 | 26 | 27 | 28 | com.github.fridujo 29 | spring-automocker-starter-web 30 | ${automocker.version} 31 | test 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/java/com/github/fridujo/sample/jdbc/customer/Customer.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc.customer; 2 | 3 | import javax.persistence.Embeddable; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import java.io.Serializable; 8 | 9 | @Entity 10 | public class Customer { 11 | private final String firstname; 12 | private final String lastname; 13 | @Id 14 | @GeneratedValue 15 | private Long id; 16 | 17 | public Customer() { 18 | firstname = null; 19 | lastname = null; 20 | } 21 | 22 | public Customer(String firstname, String lastname) { 23 | this.firstname = firstname; 24 | this.lastname = lastname; 25 | } 26 | 27 | public CustomerId getId() { 28 | return new CustomerId(id); 29 | } 30 | 31 | public String getFirstname() { 32 | return firstname; 33 | } 34 | 35 | public String getLastname() { 36 | return lastname; 37 | } 38 | 39 | @Embeddable 40 | public static class CustomerId implements Serializable { 41 | private final Long customerId; 42 | 43 | CustomerId() { 44 | this.customerId = null; 45 | } 46 | 47 | CustomerId(Long id) { 48 | this.customerId = id; 49 | } 50 | 51 | public Long getCustomerId() { 52 | return customerId; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /samples/spring-automocker-graphite-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | spring-automocker-reactor 8 | com.github.fridujo 9 | 1.2.2-SNAPSHOT 10 | ../../pom.xml 11 | 12 | 13 | spring-automocker-graphite-sample 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-actuator 19 | ${spring-boot.version} 20 | 21 | 22 | io.micrometer 23 | micrometer-registry-graphite 24 | ${micrometer.version} 25 | 26 | 27 | 28 | 29 | com.github.fridujo 30 | spring-automocker-starter 31 | ${automocker.version} 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /samples/spring-automocker-property-source-sample/src/test/java/com/github/fridujo/sample/propertySource/PropertySourceApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.propertySource; 2 | 3 | 4 | import com.github.fridujo.automocker.base.Automocker; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.test.context.ContextConfiguration; 10 | import org.springframework.test.context.TestPropertySource; 11 | import org.springframework.test.context.junit.jupiter.SpringExtension; 12 | 13 | import java.util.Optional; 14 | 15 | import static org.assertj.core.api.Assertions.assertThat; 16 | 17 | @Automocker 18 | @ExtendWith(SpringExtension.class) 19 | @ContextConfiguration(classes = PropertySourceApplication.class) 20 | @TestPropertySource(properties = { 21 | "text.literal = literal Test Text", 22 | "text.optional=optionalText"}) 23 | class PropertySourceApplicationTest { 24 | 25 | @Autowired 26 | private TextService service; 27 | 28 | @Value("${missing.key:}") 29 | private Optional emptyOptional; 30 | 31 | @Test 32 | void property_source_is_mocked() { 33 | assertThat(service.getLiteralText()).isEqualTo("literal Test Text"); 34 | assertThat(service.getOptionalText()).isEqualTo("optionalText"); 35 | assertThat(emptyOptional).isEmpty(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/JmsDestinationAssert.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jms; 2 | 3 | import com.mockrunner.mock.jms.MockDestination; 4 | import org.assertj.core.api.Assertions; 5 | 6 | import javax.jms.Message; 7 | import java.util.List; 8 | 9 | public class JmsDestinationAssert { 10 | 11 | private final String destinationName; 12 | private final MockDestination destination; 13 | 14 | public JmsDestinationAssert(MockDestination mockDestination, String destinationName) { 15 | this.destination = mockDestination; 16 | this.destinationName = destinationName; 17 | } 18 | 19 | public JmsDestinationAssert hasSize(int expected) { 20 | Assertions.assertThat(destination.getReceivedMessageList() 21 | .size()) 22 | .isEqualTo(expected); 23 | return this; 24 | } 25 | 26 | public JmsMessageAssert consumingFirstMessage() { 27 | if (destination.isEmpty()) { 28 | throw new IllegalArgumentException( 29 | "No message available on destination [" + destinationName + "]"); 30 | } 31 | return new JmsMessageAssert(destination.getMessage()); 32 | } 33 | 34 | @SuppressWarnings("unchecked") 35 | public List getMessages() { 36 | return destination.getCurrentMessageList(); 37 | } 38 | 39 | public String toString() { 40 | return "Asserter on JMS destination [" + destinationName + "]"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/context/ResettableTestExecutionListener.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.context; 2 | 3 | import com.github.fridujo.automocker.api.ResetMocks; 4 | import com.github.fridujo.automocker.api.Resettable; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.core.annotation.AnnotationUtils; 7 | import org.springframework.test.context.TestContext; 8 | import org.springframework.test.context.support.AbstractTestExecutionListener; 9 | 10 | public class ResettableTestExecutionListener extends AbstractTestExecutionListener { 11 | 12 | @Override 13 | public void afterTestMethod(TestContext testContext) { 14 | resetAll(testContext); 15 | } 16 | 17 | @Override 18 | public void afterTestClass(TestContext testContext) { 19 | resetAll(testContext); 20 | } 21 | 22 | @Override 23 | public void afterTestExecution(TestContext testContext) { 24 | resetAll(testContext); 25 | } 26 | 27 | private void resetAll(TestContext testContext) { 28 | ResetMocks resetMocks = AnnotationUtils.getAnnotation(testContext.getTestClass(), ResetMocks.class); 29 | if (resetMocks != null && !resetMocks.disable()) { 30 | ApplicationContext applicationContext = testContext.getApplicationContext(); 31 | for (Resettable resettable : applicationContext.getBeansOfType(Resettable.class).values()) { 32 | resettable.reset(); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/java/com/github/fridujo/sample/jdbc/JdbcApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc; 2 | 3 | import com.github.fridujo.sample.jdbc.customer.Customer; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 8 | import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; 9 | import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; 10 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 11 | import org.springframework.transaction.annotation.EnableTransactionManagement; 12 | 13 | import javax.annotation.PostConstruct; 14 | 15 | @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, 16 | DataSourceTransactionManagerAutoConfiguration.class}) 17 | @EnableTransactionManagement 18 | @EnableConfigurationProperties 19 | public class JdbcApplication { 20 | 21 | @Autowired 22 | DataInitializer initializer; 23 | 24 | public static void main(String[] args) { 25 | SpringApplication.run(JdbcApplication.class, args); 26 | } 27 | 28 | @PostConstruct 29 | public void init() { 30 | Customer.CustomerId customerId = initializer.initializeCustomer(); 31 | initializer.initializeOrder(customerId); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/java/com/github/fridujo/sample/jms/buyer/Buyer.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms.buyer; 2 | 3 | import com.github.fridujo.sample.jms.Broker; 4 | import com.github.fridujo.sample.jms.BusinessHeaders; 5 | import com.github.fridujo.sample.jms.JmsListenerContainerFactories; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.jms.annotation.JmsListener; 9 | import org.springframework.jms.core.JmsTemplate; 10 | import org.springframework.messaging.handler.annotation.Payload; 11 | import org.springframework.stereotype.Component; 12 | 13 | import javax.jms.TextMessage; 14 | import java.util.UUID; 15 | 16 | @Component 17 | class Buyer { 18 | private final Logger logger = LoggerFactory.getLogger("buyer"); 19 | private final JmsTemplate sellerSender; 20 | private final String id; 21 | 22 | Buyer(@Broker(Broker.Type.SELLER) JmsTemplate sellerSender) { 23 | this.sellerSender = sellerSender; 24 | this.id = UUID.randomUUID().toString(); 25 | } 26 | 27 | @JmsListener(destination = "REQUEST_ITEM", containerFactory = JmsListenerContainerFactories.BUYER) 28 | void onItemRequest(@Payload String item) { 29 | sellerSender.send("REQUESTED_ITEM", session -> { 30 | TextMessage textMessage = session.createTextMessage(item); 31 | textMessage.setStringProperty(BusinessHeaders.BUYER_ID, id); 32 | return textMessage; 33 | }); 34 | logger.info("Buyer " + id + " sent request for [" + item + "]"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/api/jms/JmsMockLocatorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jms; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import javax.jms.ConnectionFactory; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | import static org.mockito.Mockito.mock; 11 | 12 | class JmsMockLocatorTest { 13 | 14 | @Test 15 | void getJmsMockByConnectionFactory_returns_matching_object() { 16 | ConnectionFactory connectionFactory = mock(ConnectionFactory.class); 17 | ConnectionFactory connectionFactory2 = mock(ConnectionFactory.class); 18 | ConnectionFactory connectionFactory3 = mock(ConnectionFactory.class); 19 | JmsMock jmsMock = new JmsMock(connectionFactory, null); 20 | JmsMock jmsMock2 = new JmsMock(connectionFactory2, null); 21 | 22 | assertThat(connectionFactory == connectionFactory2).isFalse(); 23 | assertThat(jmsMock == jmsMock2).isFalse(); 24 | 25 | Set jmsMocks = new HashSet<>(); 26 | jmsMocks.add(jmsMock); 27 | jmsMocks.add(jmsMock2); 28 | 29 | JmsMockLocator jmsMockLocator = new JmsMockLocator(jmsMocks); 30 | 31 | assertThat(jmsMockLocator.getJmsMockByConnectionFactory(connectionFactory)).contains(jmsMock); 32 | assertThat(jmsMockLocator.getJmsMockByConnectionFactory(connectionFactory2)).contains(jmsMock2); 33 | assertThat(jmsMockLocator.getJmsMockByConnectionFactory(connectionFactory3)).isEmpty(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/JmsListenerContainerFactoryConfigurer.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jms; 2 | 3 | import org.springframework.jms.config.AbstractJmsListenerContainerFactory; 4 | import org.springframework.test.util.ReflectionTestUtils; 5 | import org.springframework.util.ErrorHandler; 6 | 7 | import javax.jms.ConnectionFactory; 8 | import java.util.Optional; 9 | import java.util.Set; 10 | 11 | public class JmsListenerContainerFactoryConfigurer { 12 | 13 | JmsListenerContainerFactoryConfigurer(Set> jmsListenerContainerFactories, 14 | JmsMockLocator jmsMockLocator) { 15 | jmsListenerContainerFactories.forEach(jmsListenerContainerFactory -> { 16 | ConnectionFactory connectionFactory = (ConnectionFactory) ReflectionTestUtils.getField( 17 | jmsListenerContainerFactory, "connectionFactory"); 18 | Optional originalErrorHandler = Optional.ofNullable( 19 | (ErrorHandler) ReflectionTestUtils.getField(jmsListenerContainerFactory, "errorHandler")); 20 | 21 | ErrorHandlerMock automockerErrorHandler = new ErrorHandlerMock(originalErrorHandler); 22 | jmsListenerContainerFactory.setErrorHandler(automockerErrorHandler); 23 | 24 | Optional jmsMockOptional = jmsMockLocator.getJmsMockByConnectionFactory(connectionFactory); 25 | jmsMockOptional.ifPresent(jmsMock -> jmsMock.setErrorHandlerMock(automockerErrorHandler)); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/spring-automocker-graphite-sample/src/main/java/com/github/fridujo/sample/graphite/GraphiteApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.graphite; 2 | 3 | import io.micrometer.core.instrument.Counter; 4 | import io.micrometer.core.instrument.MeterRegistry; 5 | import org.springframework.boot.Banner; 6 | import org.springframework.boot.CommandLineRunner; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | 10 | import java.util.Optional; 11 | 12 | @SpringBootApplication 13 | public class GraphiteApplication implements CommandLineRunner { 14 | 15 | private final Counter runCounter; 16 | 17 | public GraphiteApplication(MeterRegistry meterRegistry) { 18 | this.runCounter = meterRegistry.counter("run"); 19 | } 20 | 21 | public static void main(String[] args) { 22 | SpringApplication app = new SpringApplication(GraphiteApplication.class); 23 | app.setBannerMode(Banner.Mode.OFF); 24 | app.run(args); 25 | } 26 | 27 | @Override 28 | public void run(String... args) { 29 | Optional.of(args) 30 | .filter(a -> a.length > 0) 31 | .map(a -> a[0]) 32 | .flatMap(this::tryParse) 33 | .ifPresent(incrementFactor -> runCounter.increment(incrementFactor)); 34 | } 35 | 36 | private Optional tryParse(String string) { 37 | try { 38 | return Optional.of(Double.parseDouble(string)); 39 | } catch (NumberFormatException e) { 40 | return Optional.empty(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/java/com/github/fridujo/sample/jms/JmsApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms; 2 | 3 | import com.github.fridujo.sample.jms.seller.Seller; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration; 7 | import org.springframework.context.ConfigurableApplicationContext; 8 | import org.springframework.jms.annotation.EnableJms; 9 | import org.springframework.jms.core.JmsTemplate; 10 | 11 | import javax.jms.TextMessage; 12 | import java.util.concurrent.Semaphore; 13 | 14 | @SpringBootApplication(exclude = {JmsAutoConfiguration.class}) 15 | @EnableJms 16 | public class JmsApplication { 17 | 18 | public static void main(String[] args) throws InterruptedException { 19 | try (ConfigurableApplicationContext applicationContext = SpringApplication.run(JmsApplication.class)) { 20 | Semaphore waitForSellerToSendItem = new Semaphore(0); 21 | Seller buyer = applicationContext.getBean(Seller.class); 22 | buyer.addItemSoldListener(item -> waitForSellerToSendItem.release()); 23 | JmsTemplate buyerJmsTemplate = applicationContext.getBean("buyerJmsTemplate", JmsTemplate.class); 24 | buyerJmsTemplate.send("REQUEST_ITEM", session -> { 25 | TextMessage textMessage = session.createTextMessage("available concert tickets"); 26 | return textMessage; 27 | }); 28 | waitForSellerToSendItem.acquire(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /samples/spring-automocker-graphite-sample/src/test/java/com/github/fridujo/sample/graphite/GraphiteApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.graphite; 2 | 3 | import com.github.fridujo.automocker.api.metrics.GraphiteMock; 4 | import com.github.fridujo.automocker.base.Automocker; 5 | import org.junit.jupiter.api.extension.ExtendWith; 6 | import org.junit.jupiter.params.ParameterizedTest; 7 | import org.junit.jupiter.params.provider.CsvSource; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.CommandLineRunner; 10 | import org.springframework.test.context.ContextConfiguration; 11 | import org.springframework.test.context.junit.jupiter.SpringExtension; 12 | 13 | @Automocker 14 | @ExtendWith(SpringExtension.class) 15 | @ContextConfiguration(classes = GraphiteApplication.class) 16 | class GraphiteApplicationTest { 17 | 18 | private final CommandLineRunner commandLineRunner; 19 | private final GraphiteMock graphiteMock; 20 | 21 | GraphiteApplicationTest(@Autowired CommandLineRunner commandLineRunner, @Autowired GraphiteMock graphiteMock) { 22 | this.commandLineRunner = commandLineRunner; 23 | this.graphiteMock = graphiteMock; 24 | } 25 | 26 | @ParameterizedTest 27 | @CsvSource({"1, 1", "3, 3", "7, 7", "test, 0"}) 28 | void metric_is_sent_to_graphite(String appParameter, int expectedIncrement) throws Exception { 29 | commandLineRunner.run(appParameter); 30 | 31 | graphiteMock.afterReporting().assertThatMetric("run.count") 32 | .derivative() 33 | .hasLastValue(expectedIncrement); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/java/com/github/fridujo/sample/jdbc/DataInitializer.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc; 2 | 3 | import com.github.fridujo.sample.jdbc.customer.Customer; 4 | import com.github.fridujo.sample.jdbc.customer.CustomerRepository; 5 | import com.github.fridujo.sample.jdbc.order.LineItem; 6 | import com.github.fridujo.sample.jdbc.order.Order; 7 | import com.github.fridujo.sample.jdbc.order.OrderRepository; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.transaction.annotation.Transactional; 10 | import org.springframework.util.Assert; 11 | 12 | @Component 13 | public class DataInitializer { 14 | 15 | private final OrderRepository orders; 16 | private final CustomerRepository customers; 17 | 18 | public DataInitializer(OrderRepository orders, CustomerRepository customers) { 19 | this.orders = orders; 20 | this.customers = customers; 21 | } 22 | 23 | @Transactional("customerTransactionManager") 24 | public Customer.CustomerId initializeCustomer() { 25 | return customers.save(new Customer("Dave", "Matthews")) 26 | .getId(); 27 | } 28 | 29 | @Transactional("orderTransactionManager") 30 | public void initializeOrder(Customer.CustomerId customer) { 31 | Assert.notNull(customer, "Customer identifier must not be null!"); 32 | 33 | Order order1 = new Order(customer); 34 | order1.add(new LineItem("Fender Jag-Stang Guitar")); 35 | orders.save(order1); 36 | 37 | Order order2 = new Order(customer); 38 | order2.add(new LineItem("Gene Simmons Axe Bass")); 39 | orders.save(order2); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/Version.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import com.google.common.base.Splitter; 4 | import com.google.common.primitives.Ints; 5 | import org.springframework.context.ApplicationContext; 6 | 7 | import java.util.List; 8 | 9 | public class Version { 10 | 11 | private final int major; 12 | private final int minor; 13 | 14 | private Version(int major, int minor) { 15 | this.major = major; 16 | this.minor = minor; 17 | } 18 | 19 | public static Version major(int major) { 20 | return new Version(major, 0); 21 | } 22 | 23 | public static Version spring() { 24 | String springVersion = ApplicationContext.class.getPackage().getImplementationVersion(); 25 | List tokenizedSpringVersion = Splitter.on('.').splitToList(springVersion); 26 | int major = Ints.tryParse(tokenizedSpringVersion.get(0)); 27 | int minor = Ints.tryParse(tokenizedSpringVersion.get(1)); 28 | 29 | return major(major).minor(minor); 30 | } 31 | 32 | public Version minor(int minor) { 33 | return new Version(this.major, minor); 34 | } 35 | 36 | public boolean isBefore(Version otherVersion) { 37 | final boolean before; 38 | if (major < otherVersion.major) { 39 | before = true; 40 | } else if (major == otherVersion.major) { 41 | before = minor < otherVersion.minor; 42 | } else { 43 | before = false; 44 | } 45 | return before; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "v" + major + "." + minor; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/Classes.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | public final class Classes { 6 | 7 | private Classes() { 8 | } 9 | 10 | public static T instanciate(Class clazz) { 11 | try { 12 | return clazz.newInstance(); 13 | } catch (InstantiationException | IllegalAccessException e) { 14 | throw new IllegalStateException("Cannot instanciate class " + clazz.getName() + ": " + e.getMessage(), e); 15 | } 16 | } 17 | 18 | public static boolean isPresent(String className) { 19 | try { 20 | Class.forName(className); 21 | return true; 22 | } catch (ClassNotFoundException | NoClassDefFoundError e) { 23 | return false; 24 | } 25 | } 26 | 27 | public static Class forName(String className) { 28 | try { 29 | return Class.forName(className); 30 | } catch (ClassNotFoundException e) { 31 | throw new IllegalStateException("Cannot load class " + className); 32 | } 33 | } 34 | 35 | public static T getValueFromProtectedField(Object object, String fieldName) { 36 | Class clazz = object.getClass(); 37 | try { 38 | Field field = clazz.getDeclaredField(fieldName); 39 | if (!field.isAccessible()) { 40 | field.setAccessible(true); 41 | } 42 | return (T) field.get(object); 43 | } catch (NoSuchFieldException | IllegalAccessException e) { 44 | throw new IllegalStateException("Cannot find field " + fieldName + " in class " + clazz.getName(), e); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /samples/spring-automocker-mvc-sample/src/test/java/com/github/fridujo/sample/mvc/MvcApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.mvc; 2 | 3 | import com.github.fridujo.automocker.base.Automocker; 4 | import org.junit.jupiter.api.Test; 5 | import org.junit.jupiter.api.extension.ExtendWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.test.context.ContextConfiguration; 8 | import org.springframework.test.context.junit.jupiter.SpringExtension; 9 | import org.springframework.test.web.servlet.MockMvc; 10 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 11 | import org.springframework.test.web.servlet.result.MockMvcResultMatchers; 12 | 13 | @Automocker 14 | @ExtendWith(SpringExtension.class) 15 | @ContextConfiguration(classes = MvcApplication.class) 16 | class MvcApplicationTest { 17 | 18 | @Autowired 19 | private MockMvc mvc; 20 | 21 | @Test 22 | public void repository_is_available_and_consistent() throws Exception { 23 | mvc.perform(MockMvcRequestBuilders.get("/create_user?firstName=Alyson&lastName=Hannigan")) 24 | .andExpect(MockMvcResultMatchers.status() 25 | .isOk()); 26 | 27 | mvc.perform(MockMvcRequestBuilders.get("/create_user?firstName=Angelina&lastName=Jolie")) 28 | .andExpect(MockMvcResultMatchers.status() 29 | .isOk()); 30 | 31 | mvc.perform(MockMvcRequestBuilders.get("/list_users")) 32 | .andExpect(MockMvcResultMatchers.status() 33 | .isOk()) 34 | .andExpect(MockMvcResultMatchers.content() 35 | .string("[{\"firstName\":\"Alyson\",\"lastName\":\"Hannigan\"},{\"firstName\":\"Angelina\",\"lastName\":\"Jolie\"}]")); 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /samples/spring-automocker-mvc-sample/src/main/java/com/github/fridujo/sample/mvc/MvcApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.mvc; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import java.util.Collection; 12 | import java.util.LinkedHashMap; 13 | import java.util.Map; 14 | import java.util.concurrent.atomic.AtomicInteger; 15 | 16 | /** 17 | * Sample web application.
18 | * Run {@link #main(String[])} to launch. 19 | */ 20 | @SpringBootApplication 21 | @RestController 22 | public class MvcApplication { 23 | 24 | private static final Logger LOGGER = LoggerFactory.getLogger(MvcApplication.class); 25 | 26 | private final Map database = new LinkedHashMap<>(); 27 | private final AtomicInteger sequenceGenerator = new AtomicInteger(); 28 | 29 | public MvcApplication() { 30 | LOGGER.info("Initiating web server"); 31 | } 32 | 33 | public static void main(String[] args) { 34 | SpringApplication.run(MvcApplication.class); 35 | } 36 | 37 | @RequestMapping("/create_user") 38 | Customer createUser(@RequestParam("firstName") String firstName, 39 | @RequestParam("lastName") String lastName) { 40 | int id = sequenceGenerator.incrementAndGet(); 41 | Customer newCustomer = new Customer(id, firstName, lastName); 42 | database.put(id, newCustomer); 43 | return newCustomer; 44 | } 45 | 46 | @RequestMapping("/list_users") 47 | Collection listUsers() { 48 | return database.values(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /samples/spring-automocker-amqp-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | spring-automocker-reactor 8 | com.github.fridujo 9 | 1.2.2-SNAPSHOT 10 | ../../pom.xml 11 | 12 | 13 | spring-automocker-amqp-sample 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-amqp 19 | ${spring-boot.version} 20 | 21 | 22 | com.rabbitmq 23 | http-client 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-actuator 30 | ${spring-boot.version} 31 | 32 | 33 | io.micrometer 34 | micrometer-registry-graphite 35 | ${micrometer.version} 36 | 37 | 38 | 39 | 40 | com.github.fridujo 41 | spring-automocker-starter-amqp 42 | ${automocker.version} 43 | test 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /samples/spring-automocker-property-source-sample/src/main/java/com/github/fridujo/sample/propertySource/PropertySourceApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.propertySource; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 6 | import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; 7 | import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; 8 | import org.springframework.context.ConfigurableApplicationContext; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.ComponentScan; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.context.annotation.PropertySource; 13 | import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; 14 | 15 | @Configuration 16 | @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, 17 | DataSourceTransactionManagerAutoConfiguration.class}) 18 | @ComponentScan 19 | @PropertySource("classpath:appli.properties") 20 | public class PropertySourceApplication { 21 | 22 | @Bean 23 | public static PropertySourcesPlaceholderConfigurer configurer() { 24 | PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer(); 25 | // Necessary to properly inject java.util.Optional values 26 | configurer.setNullValue(""); 27 | return configurer; 28 | } 29 | 30 | public static void main(String[] args) { 31 | try (ConfigurableApplicationContext context = SpringApplication.run(PropertySourceApplication.class, args)) { 32 | TextService service = context.getBean(TextService.class); 33 | 34 | System.out.println(service.getLiteralText()); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/java/com/github/fridujo/sample/jms/seller/SellerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms.seller; 2 | 3 | import com.github.fridujo.sample.jms.Broker; 4 | import com.github.fridujo.sample.jms.JmsListenerContainerFactories; 5 | import com.github.fridujo.sample.jms.utils.ActiveMQConnectionFactoryFactory; 6 | import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQProperties; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.jms.config.DefaultJmsListenerContainerFactory; 11 | import org.springframework.jms.core.JmsTemplate; 12 | 13 | import javax.jms.ConnectionFactory; 14 | 15 | @Configuration 16 | class SellerConfiguration { 17 | 18 | @Bean 19 | @ConfigurationProperties(prefix = "seller.activemq") 20 | @Broker(Broker.Type.SELLER) 21 | ActiveMQProperties sellerActiveMQProperties() { 22 | return new ActiveMQProperties(); 23 | } 24 | 25 | @Bean 26 | @Broker(Broker.Type.SELLER) 27 | ConnectionFactory sellerConnectionFactory(@Broker(Broker.Type.SELLER) ActiveMQProperties activeMQProperties) { 28 | return new ActiveMQConnectionFactoryFactory(activeMQProperties).create(); 29 | } 30 | 31 | @Bean(name = JmsListenerContainerFactories.SELLER) 32 | @Broker(Broker.Type.SELLER) 33 | DefaultJmsListenerContainerFactory sellerJmsListenerContainerFactory(@Broker(Broker.Type.SELLER) ConnectionFactory connectionFactory) { 34 | DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); 35 | factory.setConnectionFactory(connectionFactory); 36 | return factory; 37 | } 38 | 39 | @Bean 40 | @Broker(Broker.Type.SELLER) 41 | JmsTemplate sellerJmsTemplate(@Broker(Broker.Type.SELLER) ConnectionFactory connectionFactory) { 42 | return new JmsTemplate(connectionFactory); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jdbc/DataSources.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jdbc; 2 | 3 | import com.github.fridujo.automocker.utils.ThrowingConsumer; 4 | 5 | import javax.sql.DataSource; 6 | import java.sql.Connection; 7 | import java.sql.PreparedStatement; 8 | import java.sql.SQLException; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | import java.util.stream.IntStream; 12 | 13 | public final class DataSources { 14 | 15 | private DataSources() { 16 | } 17 | 18 | public static void doInConnection(DataSource datasource, ThrowingConsumer task) { 19 | try (Connection c = datasource.getConnection()) { 20 | ThrowingConsumer.silent(task) 21 | .accept(c); 22 | c.commit(); 23 | } catch (SQLException e) { 24 | throw new IllegalStateException(e); 25 | } 26 | } 27 | 28 | public static void populateTable(DataSource datasource, String tableName, List columns, 29 | List> values) { 30 | StringBuilder sql = new StringBuilder("INSERT INTO "); 31 | sql.append(tableName) 32 | .append(" ("); 33 | sql.append(columns.stream() 34 | .map(String::toUpperCase) 35 | .collect(Collectors.joining(", "))); 36 | sql.append(") VALUES ("); 37 | sql.append(IntStream.range(0, columns.size()) 38 | .mapToObj(i -> "?") 39 | .collect(Collectors.joining(", "))); 40 | sql.append(")"); 41 | doInConnection(datasource, c -> { 42 | try (PreparedStatement ps = c.prepareStatement(sql.toString())) { 43 | for (List line : values) { 44 | int i = 1; 45 | for (String value : line) { 46 | ps.setString(i, value); 47 | i++; 48 | } 49 | ps.addBatch(); 50 | } 51 | ps.executeBatch(); 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/java/com/github/fridujo/sample/jms/buyer/BuyerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms.buyer; 2 | 3 | import com.github.fridujo.sample.jms.Broker; 4 | import com.github.fridujo.sample.jms.JmsListenerContainerFactories; 5 | import com.github.fridujo.sample.jms.utils.ActiveMQConnectionFactoryFactory; 6 | import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQProperties; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.jms.config.DefaultJmsListenerContainerFactory; 11 | import org.springframework.jms.config.JmsListenerContainerFactory; 12 | import org.springframework.jms.core.JmsTemplate; 13 | import org.springframework.jms.listener.DefaultMessageListenerContainer; 14 | 15 | import javax.jms.ConnectionFactory; 16 | 17 | @Configuration 18 | class BuyerConfiguration { 19 | 20 | @Bean 21 | @ConfigurationProperties(prefix = "buyer.activemq") 22 | @Broker(Broker.Type.BUYER) 23 | ActiveMQProperties buyerActiveMQProperties() { 24 | return new ActiveMQProperties(); 25 | } 26 | 27 | @Bean 28 | @Broker(Broker.Type.BUYER) 29 | ConnectionFactory buyerConnectionFactory(@Broker(Broker.Type.BUYER) ActiveMQProperties activeMQProperties) { 30 | return new ActiveMQConnectionFactoryFactory(activeMQProperties).create(); 31 | } 32 | 33 | @Bean(name = JmsListenerContainerFactories.BUYER) 34 | @Broker(Broker.Type.BUYER) 35 | JmsListenerContainerFactory buyerJmsListenerContainerFactory(@Broker(Broker.Type.BUYER) ConnectionFactory connectionFactory) { 36 | DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory(); 37 | factory.setConnectionFactory(connectionFactory); 38 | return factory; 39 | } 40 | 41 | @Bean 42 | @Broker(Broker.Type.BUYER) 43 | JmsTemplate buyerJmsTemplate(@Broker(Broker.Type.BUYER) ConnectionFactory connectionFactory) { 44 | return new JmsTemplate(connectionFactory); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/utils/AnnotationsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import org.assertj.core.api.Condition; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.lang.annotation.Annotation; 7 | import java.lang.annotation.ElementType; 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.RetentionPolicy; 10 | import java.lang.annotation.Target; 11 | import java.util.Set; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | 15 | class AnnotationsTest { 16 | 17 | @Test 18 | void search_annotated_annotations() { 19 | Set> annotationSet = Annotations.getAnnotationsAnnotatedWith(SampleAnnotatedClass.class, MarkingAnnotation.class); 20 | 21 | assertThat(annotationSet) 22 | .as("Annotated annotations") 23 | .hasSize(2) 24 | .are(new Condition<>( 25 | aa -> isAnnotationOfType(aa.parentAnnotation(), MarkingAnnotation.class), 26 | "@MarkingAnnotation is always the parent") 27 | ) 28 | .>extracting(aa -> aa.annotation().annotationType()) 29 | .containsOnly(AnnotatedAnnotation1.class, AnnotatedAnnotation2.class); 30 | } 31 | 32 | private boolean isAnnotationOfType(Annotation a, Class type) { 33 | return type.isAssignableFrom(a.annotationType()); 34 | } 35 | 36 | @Target(ElementType.ANNOTATION_TYPE) 37 | @Retention(RetentionPolicy.RUNTIME) 38 | private @interface MarkingAnnotation { 39 | 40 | } 41 | 42 | @Target(ElementType.TYPE) 43 | @Retention(RetentionPolicy.RUNTIME) 44 | 45 | @MarkingAnnotation 46 | private @interface AnnotatedAnnotation1 { 47 | 48 | } 49 | 50 | @Target(ElementType.TYPE) 51 | @Retention(RetentionPolicy.RUNTIME) 52 | 53 | @MarkingAnnotation 54 | @AnnotatedAnnotation1 55 | private @interface AnnotatedAnnotation2 { 56 | 57 | } 58 | 59 | @AnnotatedAnnotation1 60 | @AnnotatedAnnotation2 61 | private static class SampleAnnotatedClass { 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jdbc/Connections.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jdbc; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class Connections { 11 | 12 | public static List tables(Connection c) { 13 | List tables = new ArrayList<>(); 14 | try (PreparedStatement ps = c.prepareStatement("SHOW TABLES"); ResultSet rs = ps.executeQuery()) { 15 | while (rs.next()) { 16 | tables.add(rs.getString(1)); 17 | } 18 | } catch (SQLException e) { 19 | throw new IllegalStateException("Unable to list tables", e); 20 | } 21 | return tables; 22 | } 23 | 24 | public static void execute(Connection c, String statement) { 25 | try (PreparedStatement p = c.prepareStatement(statement)) { 26 | p.execute(); 27 | } catch (SQLException e) { 28 | throw new IllegalStateException("Could not execute Statement [" + statement + "]", e); 29 | } 30 | } 31 | 32 | public static void truncate(Connection c, String tableName) { 33 | execute(c, "TRUNCATE TABLE " + tableName); 34 | } 35 | 36 | public static Object selectFirstLines(Connection c, String tableName, int maxLines) { 37 | try (PreparedStatement p = c.prepareStatement("SELECT TOP " + maxLines + " * FROM " + tableName); 38 | ResultSet rs = p.executeQuery()) { 39 | 40 | int columns = rs.getMetaData() 41 | .getColumnCount(); 42 | List> result = new ArrayList<>(); 43 | while (rs.next()) { 44 | List line = new ArrayList<>(); 45 | for (int i = 1; i <= columns; i++) { 46 | line.add(rs.getObject(i)); 47 | } 48 | result.add(line); 49 | } 50 | return result; 51 | } catch (SQLException e) { 52 | throw new IllegalStateException("Could not select Table [" + tableName + "]", e); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /samples/spring-automocker-amqp-sample/src/test/java/com/github/fridujo/sample/amqp/AmqpApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.amqp; 2 | 3 | import com.github.fridujo.automocker.api.metrics.GraphiteMock; 4 | import com.github.fridujo.automocker.base.Automocker; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.extension.ExtendWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.test.context.ContextConfiguration; 9 | import org.springframework.test.context.junit.jupiter.SpringExtension; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import static java.time.Duration.ofMillis; 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; 18 | 19 | @Automocker 20 | @ExtendWith(SpringExtension.class) 21 | @ContextConfiguration(classes = AmqpApplication.class) 22 | class AmqpApplicationTest { 23 | 24 | private final Sender sender; 25 | private final Receiver receiver; 26 | private final GraphiteMock graphiteMock; 27 | 28 | AmqpApplicationTest( 29 | @Autowired Sender sender, 30 | @Autowired Receiver receiver, 31 | @Autowired GraphiteMock graphiteMock) { 32 | this.sender = sender; 33 | this.receiver = receiver; 34 | this.graphiteMock = graphiteMock; 35 | } 36 | 37 | @Test 38 | void message_is_received_when_sent_by_sender() { 39 | sender.send(); 40 | List receivedMessages = new ArrayList<>(); 41 | assertTimeoutPreemptively(ofMillis(500L), () -> { 42 | while (receivedMessages.isEmpty()) { 43 | receivedMessages.addAll(receiver.getMessages()); 44 | TimeUnit.MILLISECONDS.sleep(100L); 45 | } 46 | } 47 | ); 48 | 49 | assertThat(receivedMessages).containsExactly("Hello from RabbitMQ!"); 50 | 51 | 52 | graphiteMock.afterReporting() 53 | .assertThatMetric("rabbitmqPublished.name.rabbit.count").hasLastValue(1); 54 | graphiteMock.assertThatMetric("rabbitmqConsumed.name.rabbit.count").hasLastValue(1); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /starters/spring-automocker-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | spring-automocker-reactor 8 | com.github.fridujo 9 | 1.2.2-SNAPSHOT 10 | ../../pom.xml 11 | 12 | 13 | spring-automocker-starter 14 | 15 | 16 | 17 | com.github.fridujo 18 | spring-automocker 19 | ${automocker.version} 20 | compile 21 | 22 | 23 | org.springframework 24 | spring-test 25 | ${spring.version} 26 | compile 27 | 28 | 29 | org.assertj 30 | assertj-core 31 | ${assertj.version} 32 | compile 33 | 34 | 35 | org.junit.jupiter 36 | junit-jupiter-api 37 | ${junit-jupiter.version} 38 | compile 39 | 40 | 41 | org.junit.jupiter 42 | junit-jupiter-engine 43 | ${junit-jupiter.version} 44 | compile 45 | 46 | 47 | org.junit.jupiter 48 | junit-jupiter-params 49 | ${junit-jupiter.version} 50 | compile 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockPropertySources.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.base; 2 | 3 | import com.github.fridujo.automocker.api.BeforeBeanRegistration; 4 | import com.github.fridujo.automocker.api.BeforeBeanRegistrationExecutable; 5 | import org.springframework.context.ConfigurableApplicationContext; 6 | import org.springframework.core.io.ByteArrayResource; 7 | import org.springframework.core.io.ProtocolResolver; 8 | import org.springframework.core.io.Resource; 9 | import org.springframework.core.io.ResourceLoader; 10 | 11 | import java.lang.annotation.Documented; 12 | import java.lang.annotation.ElementType; 13 | import java.lang.annotation.Retention; 14 | import java.lang.annotation.RetentionPolicy; 15 | import java.lang.annotation.Target; 16 | 17 | /** 18 | * Make Spring ignore {@link org.springframework.context.annotation.PropertySource} annotations. 19 | */ 20 | @Target(ElementType.TYPE) 21 | @Retention(RetentionPolicy.RUNTIME) 22 | @Documented 23 | 24 | @BeforeBeanRegistration(MockPropertySources.MockPropertySourcesExecutable.class) 25 | public @interface MockPropertySources { 26 | 27 | class MockPropertySourcesExecutable implements BeforeBeanRegistrationExecutable { 28 | static final ProtocolResolver MOCK_PROPERTIES_PROTOCOL_RESOLVER = new MockPropertiesProtocolResolver(); 29 | 30 | @Override 31 | public void execute(MockPropertySources annotation, ConfigurableApplicationContext context) { 32 | context.addProtocolResolver(MOCK_PROPERTIES_PROTOCOL_RESOLVER); 33 | } 34 | 35 | private static class MockPropertiesProtocolResolver implements ProtocolResolver { 36 | @Override 37 | public Resource resolve(String location, ResourceLoader resourceLoader) { 38 | // TODO improve to exclude only files that are detected through class scanning 39 | if (location.endsWith(".properties") 40 | && !location.contains("META-INF") 41 | && !location.contains("git.properties")) { 42 | 43 | return new ByteArrayResource(new byte[0]); 44 | } else { 45 | return null; 46 | } 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/tools/BeanLocator.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.tools; 2 | 3 | import com.google.common.base.Joiner; 4 | import org.springframework.context.ApplicationContext; 5 | 6 | import java.util.Map; 7 | import java.util.stream.Collectors; 8 | 9 | public class BeanLocator { 10 | 11 | private final ApplicationContext applicationContext; 12 | 13 | public BeanLocator(ApplicationContext applicationContext) { 14 | this.applicationContext = applicationContext; 15 | } 16 | 17 | /** 18 | * @throws IllegalArgumentException when zero or more than one beans matches 19 | */ 20 | public T getBean(Class beanClass) throws IllegalArgumentException { 21 | Map matchingBeansByName = applicationContext.getBeansOfType(beanClass); 22 | return getOnlyOneOrThrow(beanClass.getSimpleName(), matchingBeansByName); 23 | } 24 | 25 | /** 26 | * @throws IllegalArgumentException when zero or more than one beans matches 27 | */ 28 | public T getBeanByPartialName(String partialName, Class beanClass) { 29 | Map matchingBeansByName = applicationContext.getBeansOfType(beanClass) 30 | .entrySet() 31 | .stream() 32 | .filter(beanAndName -> beanAndName.getKey().contains(partialName)) 33 | .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 34 | return getOnlyOneOrThrow(beanClass.getSimpleName() + "{name: *" + partialName + "*}", matchingBeansByName); 35 | } 36 | 37 | private T getOnlyOneOrThrow(String descriptor, Map matchingBeansByName) throws IllegalArgumentException { 38 | if (matchingBeansByName.size() == 1) { 39 | return matchingBeansByName.values() 40 | .iterator() 41 | .next(); 42 | } else if (matchingBeansByName.isEmpty()) { 43 | throw new IllegalArgumentException("No bean matching " + descriptor); 44 | } else { 45 | throw new IllegalArgumentException("Multiple beans matching " + 46 | descriptor + 47 | ". Available: " + 48 | Joiner.on(", ").join(matchingBeansByName.keySet()) 49 | ); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | spring-automocker-reactor 7 | com.github.fridujo 8 | 1.2.2-SNAPSHOT 9 | ../../pom.xml 10 | 11 | 4.0.0 12 | 13 | spring-automocker-jms-sample 14 | 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-starter-activemq 19 | ${spring-boot.version} 20 | 21 | 22 | org.apache.activemq 23 | activemq-broker 24 | ${activemq.version} 25 | 26 | 27 | com.fasterxml.jackson.core 28 | jackson-databind 29 | 30 | 31 | com.google.guava 32 | guava 33 | 34 | 35 | 36 | 37 | com.fasterxml.jackson.core 38 | jackson-databind 39 | ${jackson.version} 40 | 41 | 42 | com.google.guava 43 | guava 44 | ${guava.version} 45 | 46 | 47 | 48 | 49 | com.github.fridujo 50 | spring-automocker-starter-jms 51 | ${automocker.version} 52 | test 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/java/com/github/fridujo/sample/jdbc/order/OrderConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc.order; 2 | 3 | import org.springframework.beans.factory.annotation.Qualifier; 4 | import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 9 | import org.springframework.orm.jpa.JpaTransactionManager; 10 | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; 11 | import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; 12 | import org.springframework.transaction.PlatformTransactionManager; 13 | 14 | import javax.persistence.EntityManagerFactory; 15 | import javax.sql.DataSource; 16 | 17 | @Configuration 18 | @EnableJpaRepositories(entityManagerFactoryRef = "orderEntityManagerFactory", transactionManagerRef = "orderTransactionManager") 19 | class OrderConfig { 20 | 21 | @Bean 22 | PlatformTransactionManager orderTransactionManager(@Qualifier("order") EntityManagerFactory entityManagerFactory) { 23 | return new JpaTransactionManager(entityManagerFactory); 24 | } 25 | 26 | @Bean 27 | @Qualifier("order") 28 | LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(@Qualifier("order") DataSource dataSource) { 29 | HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 30 | vendorAdapter.setGenerateDdl(true); 31 | 32 | LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); 33 | 34 | factoryBean.setDataSource(dataSource); 35 | factoryBean.setJpaVendorAdapter(vendorAdapter); 36 | factoryBean.setPackagesToScan(OrderConfig.class.getPackage().getName()); 37 | 38 | return factoryBean; 39 | } 40 | 41 | @Bean 42 | @ConfigurationProperties("order.datasource") 43 | @Qualifier("order") 44 | DataSourceProperties orderDataSourceProperties() { 45 | return new DataSourceProperties(); 46 | } 47 | 48 | @Bean 49 | @Qualifier("order") 50 | DataSource orderDataSource(@Qualifier("order") DataSourceProperties dataSourceProperties) { 51 | return dataSourceProperties.initializeDataSourceBuilder().build(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/main/java/com/github/fridujo/sample/jdbc/customer/CustomerConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc.customer; 2 | 3 | import org.springframework.beans.factory.annotation.Qualifier; 4 | import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 9 | import org.springframework.orm.jpa.JpaTransactionManager; 10 | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; 11 | import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; 12 | import org.springframework.transaction.PlatformTransactionManager; 13 | 14 | import javax.persistence.EntityManagerFactory; 15 | import javax.sql.DataSource; 16 | 17 | @Configuration 18 | @EnableJpaRepositories(entityManagerFactoryRef = "customerEntityManagerFactory", transactionManagerRef = "customerTransactionManager") 19 | class CustomerConfig { 20 | 21 | @Bean 22 | PlatformTransactionManager customerTransactionManager(@Qualifier("customer") EntityManagerFactory entityManagerFactory) { 23 | return new JpaTransactionManager(entityManagerFactory); 24 | } 25 | 26 | @Bean 27 | @Qualifier("customer") 28 | LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(@Qualifier("customer") DataSource dataSource) { 29 | HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter(); 30 | jpaVendorAdapter.setGenerateDdl(true); 31 | 32 | LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); 33 | 34 | factoryBean.setDataSource(dataSource); 35 | factoryBean.setJpaVendorAdapter(jpaVendorAdapter); 36 | factoryBean.setPackagesToScan(CustomerConfig.class.getPackage().getName()); 37 | 38 | return factoryBean; 39 | } 40 | 41 | @Bean 42 | @ConfigurationProperties("customer.datasource") 43 | @Qualifier("customer") 44 | DataSourceProperties customerDataSourceProperties() { 45 | return new DataSourceProperties(); 46 | } 47 | 48 | @Bean 49 | @Qualifier("customer") 50 | DataSource customerDataSource(@Qualifier("customer") DataSourceProperties dataSourceProperties) { 51 | return dataSourceProperties.initializeDataSourceBuilder().build(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /samples/spring-automocker-amqp-sample/src/main/java/com/github/fridujo/sample/amqp/AmqpApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.amqp; 2 | 3 | import org.springframework.amqp.core.Binding; 4 | import org.springframework.amqp.core.BindingBuilder; 5 | import org.springframework.amqp.core.Queue; 6 | import org.springframework.amqp.core.TopicExchange; 7 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 8 | import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; 9 | import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; 10 | import org.springframework.boot.SpringApplication; 11 | import org.springframework.boot.autoconfigure.SpringBootApplication; 12 | import org.springframework.context.ConfigurableApplicationContext; 13 | import org.springframework.context.annotation.Bean; 14 | 15 | import java.util.concurrent.TimeUnit; 16 | 17 | @SpringBootApplication 18 | public class AmqpApplication { 19 | 20 | final static String QUEUE_NAME = "spring-boot"; 21 | 22 | public static void main(String[] args) throws InterruptedException { 23 | try (ConfigurableApplicationContext context = SpringApplication.run(AmqpApplication.class, args)) { 24 | context.getBean(Sender.class).send(); 25 | Receiver receiver = context.getBean(Receiver.class); 26 | while (receiver.getMessages().isEmpty()) { 27 | TimeUnit.MILLISECONDS.sleep(100L); 28 | } 29 | } 30 | } 31 | 32 | @Bean 33 | Queue queue() { 34 | return new Queue(QUEUE_NAME, false); 35 | } 36 | 37 | @Bean 38 | TopicExchange exchange() { 39 | return new TopicExchange("spring-boot-exchange"); 40 | } 41 | 42 | @Bean 43 | Binding binding(Queue queue, TopicExchange exchange) { 44 | return BindingBuilder.bind(queue).to(exchange).with(QUEUE_NAME); 45 | } 46 | 47 | @Bean 48 | SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, 49 | MessageListenerAdapter listenerAdapter) { 50 | SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); 51 | container.setConnectionFactory(connectionFactory); 52 | container.setQueueNames(QUEUE_NAME); 53 | container.setMessageListener(listenerAdapter); 54 | return container; 55 | } 56 | 57 | @Bean 58 | MessageListenerAdapter listenerAdapter(Receiver receiver) { 59 | return new MessageListenerAdapter(receiver, "receiveMessage"); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/Annotations.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.AnnotatedElement; 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | import java.util.LinkedHashSet; 8 | import java.util.Set; 9 | 10 | public final class Annotations { 11 | private Annotations() { 12 | } 13 | 14 | /** 15 | * @return all {@link Annotation Annotations} found on given {@link AnnotatedElement} that have a meta-annotation of given type {@link A} 16 | */ 17 | // TODO make this recursive on superclass and interfaces 18 | public static Set> getAnnotationsAnnotatedWith(AnnotatedElement annotatedElement, Class annotationType) { 19 | return getAnnotationsAnnotatedWith(annotatedElement, annotationType, new LinkedHashSet<>()); 20 | } 21 | 22 | private static Set> getAnnotationsAnnotatedWith(AnnotatedElement annotatedElement, Class annotationType, Set visited) { 23 | Set> result = new HashSet<>(); 24 | 25 | if (visited.add(annotatedElement)) { 26 | Arrays.stream(annotatedElement.getDeclaredAnnotations()).forEach(annotation -> { 27 | Annotation superAnnotation = annotation.annotationType().getAnnotation(annotationType); 28 | if (superAnnotation != null) { 29 | result.add(new AnnotatedAnnotation(superAnnotation, annotation)); 30 | } else { 31 | result.addAll(getAnnotationsAnnotatedWith(annotation.annotationType(), annotationType, visited)); 32 | } 33 | }); 34 | } 35 | 36 | return result; 37 | } 38 | 39 | /** 40 | * Describe an annotation annotated by another annotation. 41 | * 42 | * @param type of the meta-annotation 43 | */ 44 | public static class AnnotatedAnnotation { 45 | 46 | private final A parentAnnotation; 47 | private final Annotation annotation; 48 | 49 | private AnnotatedAnnotation(A parentAnnotation, Annotation annotation) { 50 | this.parentAnnotation = parentAnnotation; 51 | this.annotation = annotation; 52 | } 53 | 54 | public A parentAnnotation() { 55 | return parentAnnotation; 56 | } 57 | 58 | public Annotation annotation() { 59 | return annotation; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/context/ResettableTestExecutionListenerTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.context; 2 | 3 | import com.github.fridujo.automocker.api.Resettable; 4 | import com.github.fridujo.automocker.base.Automocker; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.test.context.TestContext; 7 | import org.springframework.test.context.TestExecutionListener; 8 | 9 | import java.util.Set; 10 | import java.util.concurrent.atomic.AtomicInteger; 11 | import java.util.stream.Collectors; 12 | import java.util.stream.Stream; 13 | 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | import static org.mockito.Mockito.RETURNS_DEEP_STUBS; 16 | import static org.mockito.Mockito.eq; 17 | import static org.mockito.Mockito.mock; 18 | import static org.mockito.Mockito.when; 19 | 20 | class ResettableTestExecutionListenerTest { 21 | 22 | @Test 23 | void all_beans_implementing_resettable_are_reset() throws Exception { 24 | TestExecutionListener resettableTestExecutionListener = new ResettableTestExecutionListener(); 25 | 26 | Set resettableBeans = Stream.generate(ResettableBean::new).limit(3).collect(Collectors.toSet()); 27 | 28 | TestContext testContext = mock(TestContext.class, RETURNS_DEEP_STUBS); 29 | when(testContext.getTestClass()).thenReturn((Class) TestClass.class); 30 | when(testContext.getApplicationContext().getBeansOfType(eq(Resettable.class)).values()) 31 | .thenReturn(resettableBeans); 32 | resettableTestExecutionListener.afterTestMethod(testContext); 33 | 34 | assertThat(resettableBeans) 35 | .extracting("resetCount") 36 | .as("Reset field collection") 37 | .containsExactlyInAnyOrder(1, 1, 1); 38 | 39 | resettableTestExecutionListener.afterTestClass(testContext); 40 | 41 | assertThat(resettableBeans) 42 | .extracting("resetCount") 43 | .as("Reset field collection") 44 | .containsExactlyInAnyOrder(2, 2, 2); 45 | 46 | resettableTestExecutionListener.afterTestExecution(testContext); 47 | 48 | assertThat(resettableBeans) 49 | .extracting("resetCount") 50 | .as("Reset field collection") 51 | .containsExactlyInAnyOrder(3, 3, 3); 52 | } 53 | 54 | @Automocker 55 | static class TestClass { 56 | } 57 | 58 | static class ResettableBean implements Resettable { 59 | 60 | private int resetCount = 0; 61 | 62 | @Override 63 | public void reset() { 64 | resetCount ++; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/JmsMessageAssert.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jms; 2 | 3 | import com.github.fridujo.automocker.utils.ThrowingFunction; 4 | import org.assertj.core.api.AbstractCharSequenceAssert; 5 | import org.assertj.core.api.ObjectAssert; 6 | 7 | import javax.jms.JMSException; 8 | import javax.jms.Message; 9 | import javax.jms.TextMessage; 10 | import java.util.Collections; 11 | import java.util.Map; 12 | import java.util.function.Consumer; 13 | import java.util.function.Function; 14 | import java.util.stream.Collectors; 15 | 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | 18 | public class JmsMessageAssert { 19 | 20 | private Message message; 21 | 22 | JmsMessageAssert(Message message) { 23 | this.message = message; 24 | } 25 | 26 | public ObjectAssert header(String name) { 27 | try { 28 | return assertThat(message.getObjectProperty(name)).as("JMS property [" + name + "]"); 29 | } catch (JMSException e) { 30 | throw new IllegalStateException("Unable to read JMS property [" + name + "]", e); 31 | } 32 | } 33 | 34 | public JmsMessageAssert headerSatisfies(String name, Consumer> matcherUse) { 35 | matcherUse.accept(header(name)); 36 | return this; 37 | } 38 | 39 | public Map getHeaders() { 40 | try { 41 | return (Map) Collections.list(message.getPropertyNames()) 42 | .stream() 43 | .collect(Collectors.toMap(Function.identity(), ThrowingFunction.silent(propertyName -> message.getObjectProperty((String) propertyName)))); 44 | } catch (JMSException e) { 45 | throw new IllegalStateException("Unable to read JMS properties", e); 46 | } 47 | } 48 | 49 | public AbstractCharSequenceAssert text() { 50 | assertThat(message).isInstanceOf(TextMessage.class); 51 | try { 52 | return assertThat(((TextMessage) message).getText()); 53 | } catch (JMSException e) { 54 | throw new IllegalStateException("Unable to retrieve 'text' from a " + TextMessage.class.getName(), e); 55 | } 56 | } 57 | 58 | public JmsMessageAssert textSatisfies(Consumer> matcherUse) { 59 | matcherUse.accept(text()); 60 | return this; 61 | } 62 | 63 | public String getText() { 64 | assertThat(message).isInstanceOf(TextMessage.class); 65 | try { 66 | return ((TextMessage) message).getText(); 67 | } catch (JMSException e) { 68 | throw new IllegalStateException("Unable to retrieve 'text' from a " + TextMessage.class.getName(), e); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/utils/ClassesTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.assertj.core.api.Assertions.assertThat; 6 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 7 | 8 | class ClassesTest { 9 | 10 | @Test 11 | void successful_instanciation() { 12 | Instanciable instance = Classes.instanciate(Instanciable.class); 13 | 14 | assertThat(instance).isExactlyInstanceOf(Instanciable.class); 15 | } 16 | 17 | @Test 18 | void failed_instanciation() { 19 | assertThatExceptionOfType(IllegalStateException.class) 20 | .isThrownBy(() -> Classes.instanciate(Uninstanciable.class)) 21 | .withMessage("Cannot instanciate class " + 22 | Uninstanciable.class.getName() + 23 | ": Class " + Classes.class.getName() + 24 | " can not access a member of class " + 25 | Uninstanciable.class.getName() + 26 | " with modifiers \"private\"" 27 | ); 28 | } 29 | 30 | @Test 31 | void isPresent_returns_true_when_class_is_on_classpath() { 32 | assertThat(Classes.isPresent("java.lang.String")).isTrue(); 33 | } 34 | 35 | @Test 36 | void isPresent_returns_false_when_class_is_not_on_classpath() { 37 | assertThat(Classes.isPresent("missing.Someclass")).isFalse(); 38 | } 39 | 40 | @Test 41 | void forName_returns_class_object_when_present_on_classpath() { 42 | assertThat(Classes.forName("java.lang.String")).isEqualTo(String.class); 43 | } 44 | 45 | @Test 46 | void forName_throws_when_class_is_not_on_classpath() { 47 | assertThatExceptionOfType(IllegalStateException.class) 48 | .isThrownBy(() -> Classes.forName("missing.Someclass")) 49 | .withMessage("Cannot load class missing.Someclass"); 50 | } 51 | 52 | @Test 53 | void getValueFromProtectedField_when_field_exists() { 54 | Object object = new Instanciable(); 55 | String existingFieldValue = Classes.getValueFromProtectedField(object, "existingField"); 56 | assertThat(existingFieldValue).as("Existing field value").isEqualTo("test"); 57 | } 58 | 59 | @Test 60 | void getValueFromProtectedField_when_field_does_not_exist() { 61 | Object object = new Instanciable(); 62 | assertThatExceptionOfType(IllegalStateException.class) 63 | .isThrownBy(() -> Classes.getValueFromProtectedField(object, "missingField")) 64 | .withMessage("Cannot find field missingField in class com.github.fridujo.automocker.utils.ClassesTest$Instanciable"); 65 | } 66 | 67 | public static class Instanciable { 68 | private final String existingField = "test"; 69 | } 70 | 71 | private static class Uninstanciable { 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/context/AutomockerContextCustomizer.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.context; 2 | 3 | import org.springframework.beans.factory.config.BeanDefinition; 4 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.context.ConfigurableApplicationContext; 7 | import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; 8 | import org.springframework.context.support.AbstractApplicationContext; 9 | import org.springframework.test.context.ContextCustomizer; 10 | import org.springframework.test.context.MergedContextConfiguration; 11 | 12 | class AutomockerContextCustomizer implements ContextCustomizer { 13 | 14 | private final Class testClass; 15 | 16 | AutomockerContextCustomizer(Class testClass) { 17 | this.testClass = testClass; 18 | } 19 | 20 | @Override 21 | public void customizeContext(ConfigurableApplicationContext context, 22 | MergedContextConfiguration mergedContextConfiguration) { 23 | BeanDefinitionRegistry registry = getBeanDefinitionRegistry(context); 24 | AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader( 25 | registry); 26 | registerCleanupPostProcessor(registry, reader, context); 27 | } 28 | 29 | private void registerCleanupPostProcessor(BeanDefinitionRegistry registry, 30 | AnnotatedBeanDefinitionReader reader, ConfigurableApplicationContext context) { 31 | BeanDefinition definition = registerBean(registry, reader, 32 | AutomockerPostProcessor.BEAN_NAME, AutomockerPostProcessor.class); 33 | definition.getConstructorArgumentValues().addIndexedArgumentValue(0, 34 | this.testClass); 35 | definition.getConstructorArgumentValues().addIndexedArgumentValue(1, 36 | context); 37 | 38 | } 39 | 40 | private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) { 41 | if (context instanceof BeanDefinitionRegistry) { 42 | return (BeanDefinitionRegistry) context; 43 | } 44 | if (context instanceof AbstractApplicationContext) { 45 | return (BeanDefinitionRegistry) ((AbstractApplicationContext) context) 46 | .getBeanFactory(); 47 | } 48 | throw new IllegalStateException("Could not locate BeanDefinitionRegistry"); 49 | } 50 | 51 | @SuppressWarnings("unchecked") 52 | private BeanDefinition registerBean(BeanDefinitionRegistry registry, 53 | AnnotatedBeanDefinitionReader reader, String beanName, Class type) { 54 | reader.registerBean(type, beanName); 55 | BeanDefinition definition = registry.getBeanDefinition(beanName); 56 | return definition; 57 | } 58 | 59 | @Override 60 | public boolean equals(Object other) { 61 | return (this == other || (other != null && getClass() == other.getClass())); 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | return getClass().hashCode(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockJdbc.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.base; 2 | 3 | import com.github.fridujo.automocker.api.AfterBeanRegistration; 4 | import com.github.fridujo.automocker.api.AfterBeanRegistrationExecutable; 5 | import com.github.fridujo.automocker.api.ExtendedBeanDefinitionRegistry; 6 | import com.github.fridujo.automocker.api.jdbc.DataSourceResetter; 7 | import com.github.fridujo.automocker.utils.Classes; 8 | import com.github.fridujo.automocker.utils.PropertiesBuilder; 9 | import org.springframework.util.PropertyPlaceholderHelper; 10 | 11 | import javax.sql.DataSource; 12 | import java.lang.annotation.Documented; 13 | import java.lang.annotation.ElementType; 14 | import java.lang.annotation.Retention; 15 | import java.lang.annotation.RetentionPolicy; 16 | import java.lang.annotation.Target; 17 | import java.util.Set; 18 | import java.util.stream.Collectors; 19 | 20 | /** 21 | * Alter bean definitions of {@link DataSource DataSources} by setting the URL of an embedded memory one. 22 | */ 23 | @Target(ElementType.TYPE) 24 | @Retention(RetentionPolicy.RUNTIME) 25 | @Documented 26 | 27 | @AfterBeanRegistration(MockJdbc.MockJdbcExecutable.class) 28 | public @interface MockJdbc { 29 | 30 | String url() default "jdbc:h2:mem:${beanName};DB_CLOSE_DELAY=-1"; 31 | 32 | class MockJdbcExecutable implements AfterBeanRegistrationExecutable { 33 | private static final String H2_DATASOURCE_CLASS = "org.h2.jdbcx.JdbcDataSource"; 34 | private static final PropertyPlaceholderHelper PROPERTY_PLACEHOLDER_HELPER 35 | = new PropertyPlaceholderHelper("${", "}"); 36 | 37 | @Override 38 | public void execute(MockJdbc annotation, ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry) { 39 | Set dataSourceBeans = extendedBeanDefinitionRegistry 40 | .getBeanDefinitionsForClass(DataSource.class); 41 | 42 | if (!dataSourceBeans.isEmpty()) { 43 | if (Classes.isPresent(H2_DATASOURCE_CLASS)) { 44 | dataSourceBeans.forEach(meta -> { 45 | meta.beanDefinitionModifier() 46 | .copyFactoryQualifiersAsDetached() 47 | .reset() 48 | .setBeanClass(Classes.forName(H2_DATASOURCE_CLASS)) 49 | .addPropertyValue("url", 50 | PROPERTY_PLACEHOLDER_HELPER.replacePlaceholders(annotation.url(), PropertiesBuilder.of("beanName", meta.name()))); 51 | }); 52 | } else { 53 | throw new IllegalStateException("\nAutomocker is missing class [" + H2_DATASOURCE_CLASS + "] to mock " + dataSourceBeans.size() + " bean(s) of type [" + DataSource.class.getName() + "]: " + 54 | dataSourceBeans.stream().map(ExtendedBeanDefinitionRegistry.BeanDefinitionMetadata::name).collect(Collectors.joining(", ")) + 55 | "\nMake sure h2.jar is in the test classpath"); 56 | } 57 | extendedBeanDefinitionRegistry.registerBeanDefinition(DataSourceResetter.class); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/context/AutomockerPostProcessor.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.context; 2 | 3 | import com.github.fridujo.automocker.api.AfterBeanRegistration; 4 | import com.github.fridujo.automocker.api.BeforeBeanRegistration; 5 | import com.github.fridujo.automocker.utils.Annotations; 6 | import com.github.fridujo.automocker.utils.Classes; 7 | import com.github.fridujo.automocker.utils.Version; 8 | import org.springframework.beans.BeansException; 9 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 10 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 11 | import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; 12 | import org.springframework.context.ConfigurableApplicationContext; 13 | import org.springframework.core.Ordered; 14 | import org.springframework.core.PriorityOrdered; 15 | 16 | import java.util.Set; 17 | 18 | class AutomockerPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered { 19 | 20 | static final String BEAN_NAME = AutomockerPostProcessor.class.getName(); 21 | static final Version SPRING_MIN_VERSION = Version.major(4).minor(3); 22 | 23 | private final Class testClass; 24 | 25 | AutomockerPostProcessor(Class testClass, ConfigurableApplicationContext context) { 26 | this.testClass = testClass; 27 | checkSpringVersion(); 28 | invokeBeforeBeanRegistrationHooks(context); 29 | } 30 | 31 | private void checkSpringVersion() { 32 | Version springVersion = Version.spring(); 33 | if (springVersion.isBefore(SPRING_MIN_VERSION)) { 34 | throw new IllegalStateException("Automocker needs Spring in version >= " + SPRING_MIN_VERSION + ", found " + springVersion); 35 | } 36 | } 37 | 38 | private void invokeBeforeBeanRegistrationHooks(ConfigurableApplicationContext context) { 39 | Set> beforeBeanRegistrationAnnotations 40 | = Annotations.getAnnotationsAnnotatedWith(testClass, BeforeBeanRegistration.class); 41 | beforeBeanRegistrationAnnotations 42 | .forEach(annotatedAnnotation -> Classes 43 | .instanciate(annotatedAnnotation.parentAnnotation().value()) 44 | .execute(annotatedAnnotation.annotation(), context) 45 | ); 46 | } 47 | 48 | @Override 49 | public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 50 | throws BeansException { 51 | } 52 | 53 | @Override 54 | public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 55 | throws BeansException { 56 | ExtendedBeanDefinitionRegistryImpl extendedBeanDefinitionRegistry = new ExtendedBeanDefinitionRegistryImpl(registry); 57 | 58 | Set> beforeBeanRegistrationAnnotations 59 | = Annotations.getAnnotationsAnnotatedWith(testClass, AfterBeanRegistration.class); 60 | beforeBeanRegistrationAnnotations.forEach(annotatedAnnotation -> Classes 61 | .instanciate(annotatedAnnotation.parentAnnotation().value()) 62 | .execute(annotatedAnnotation.annotation(), extendedBeanDefinitionRegistry) 63 | ); 64 | } 65 | 66 | @Override 67 | public int getOrder() { 68 | return Ordered.LOWEST_PRECEDENCE; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /samples/spring-automocker-jms-sample/src/main/java/com/github/fridujo/sample/jms/seller/Seller.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jms.seller; 2 | 3 | import com.github.fridujo.sample.jms.Broker; 4 | import com.github.fridujo.sample.jms.BusinessHeaders; 5 | import com.github.fridujo.sample.jms.JmsListenerContainerFactories; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.jms.annotation.JmsListener; 9 | import org.springframework.jms.core.JmsTemplate; 10 | import org.springframework.messaging.handler.annotation.Header; 11 | import org.springframework.messaging.handler.annotation.Payload; 12 | import org.springframework.stereotype.Component; 13 | 14 | import javax.jms.TextMessage; 15 | import java.util.LinkedHashSet; 16 | import java.util.Set; 17 | import java.util.UUID; 18 | import java.util.function.Consumer; 19 | 20 | @Component 21 | public class Seller { 22 | private final Logger logger = LoggerFactory.getLogger("seller"); 23 | 24 | private final JmsTemplate sellerSender; 25 | private final JmsTemplate buyerSender; 26 | private final String id; 27 | private final Set> onItemSoldListeners = new LinkedHashSet<>(); 28 | 29 | Seller(@Broker(Broker.Type.SELLER) JmsTemplate sellerSender, @Broker(Broker.Type.BUYER) JmsTemplate buyerSender) { 30 | this.sellerSender = sellerSender; 31 | this.buyerSender = buyerSender; 32 | this.id = UUID.randomUUID().toString(); 33 | } 34 | 35 | public void addItemSoldListener(Consumer onItemSoldListener) { 36 | onItemSoldListeners.add(onItemSoldListener); 37 | } 38 | 39 | @JmsListener(destination = "REQUESTED_ITEM", containerFactory = JmsListenerContainerFactories.SELLER) 40 | void onRequestedItem(@Payload String item, 41 | @Header(BusinessHeaders.BUYER_ID) String buyerId) { 42 | if (item.startsWith("available")) { 43 | sellItem(item, buyerId); 44 | logger.info("Seller " + id + " sold item [" + item + "] to buyer " + buyerId); 45 | } else { 46 | logger.info("Seller " + id + " cannot sold unavailable item [" + item + "] to buyer " + buyerId); 47 | } 48 | } 49 | 50 | @JmsListener(destination = "SOLD", containerFactory = JmsListenerContainerFactories.SELLER) 51 | void onSoldItem(@Payload String item, 52 | @Header(BusinessHeaders.BUYER_ID) String buyerId, 53 | @Header(BusinessHeaders.SELLER_ID) String sellerId) { 54 | buyerSender.send("BOUGHT", session -> { 55 | TextMessage textMessage = session.createTextMessage(item); 56 | textMessage.setStringProperty(BusinessHeaders.BUYER_ID, buyerId); 57 | textMessage.setStringProperty(BusinessHeaders.SELLER_ID, sellerId); 58 | return textMessage; 59 | }); 60 | logger.info("Seller " + id + " sent item [" + item + "] to buyer " + buyerId); 61 | onItemSoldListeners.forEach(onItemSoldListener -> onItemSoldListener.accept(item)); 62 | } 63 | 64 | private void sellItem(String item, String buyerId) { 65 | sellerSender.send("SOLD", session -> { 66 | TextMessage textMessage = session.createTextMessage(item); 67 | textMessage.setStringProperty(BusinessHeaders.BUYER_ID, buyerId); 68 | textMessage.setStringProperty(BusinessHeaders.SELLER_ID, id); 69 | return textMessage; 70 | }); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/api/ExtendedBeanDefinitionRegistryTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.mockito.ArgumentCaptor; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.beans.factory.support.AbstractBeanDefinition; 7 | import org.springframework.beans.factory.support.AutowireCandidateQualifier; 8 | import org.springframework.beans.factory.support.RootBeanDefinition; 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | import static org.mockito.ArgumentMatchers.any; 15 | import static org.mockito.ArgumentMatchers.eq; 16 | import static org.mockito.Mockito.doCallRealMethod; 17 | import static org.mockito.Mockito.mock; 18 | import static org.mockito.Mockito.times; 19 | import static org.mockito.Mockito.verify; 20 | 21 | class ExtendedBeanDefinitionRegistryTest { 22 | 23 | @Test 24 | void registerBeanDefinition_by_class_registers_it_with_custom_name() { 25 | ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry = mock(ExtendedBeanDefinitionRegistry.class); 26 | doCallRealMethod().when(extendedBeanDefinitionRegistry).registerBeanDefinition(any()); 27 | 28 | extendedBeanDefinitionRegistry.registerBeanDefinition(String.class); 29 | 30 | ArgumentCaptor beanDefinitionArgumentCaptor = ArgumentCaptor.forClass(AbstractBeanDefinition.class); 31 | verify(extendedBeanDefinitionRegistry, times(1)).registerBeanDefinition(eq("AutomockerString"), beanDefinitionArgumentCaptor.capture()); 32 | 33 | AbstractBeanDefinition registeredBeanDefinition = beanDefinitionArgumentCaptor.getValue(); 34 | assertThat(registeredBeanDefinition).isInstanceOf(RootBeanDefinition.class); 35 | assertThat(registeredBeanDefinition.getBeanClass()).isEqualTo(String.class); 36 | } 37 | 38 | @Test 39 | void registerBeanDefinition_with_qualifiers_adds_them_before_registering() { 40 | ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry = mock(ExtendedBeanDefinitionRegistry.class); 41 | doCallRealMethod().when(extendedBeanDefinitionRegistry).registerBeanDefinition(any(), any(), any()); 42 | 43 | Map qualifiers = new HashMap<>(); 44 | qualifiers.put(Qualifier.class.getName(), "test1"); 45 | AbstractBeanDefinition beanDefinition = mock(AbstractBeanDefinition.class); 46 | extendedBeanDefinitionRegistry.registerBeanDefinition("testBeanName", beanDefinition, qualifiers); 47 | 48 | ArgumentCaptor beanDefinitionArgumentCaptor = ArgumentCaptor.forClass(AbstractBeanDefinition.class); 49 | verify(extendedBeanDefinitionRegistry, times(1)).registerBeanDefinition(eq("testBeanName"), eq(beanDefinition)); 50 | 51 | ArgumentCaptor autowireCandidateQualifierArgumentCaptor = ArgumentCaptor.forClass(AutowireCandidateQualifier.class); 52 | verify(beanDefinition, times(1)).addQualifier(autowireCandidateQualifierArgumentCaptor.capture()); 53 | AutowireCandidateQualifier autowireCandidateQualifier = autowireCandidateQualifierArgumentCaptor.getValue(); 54 | assertThat(autowireCandidateQualifier.getTypeName()).isEqualTo(Qualifier.class.getName()); 55 | assertThat(autowireCandidateQualifier.getAttribute("value")).isEqualTo("test1"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /samples/spring-automocker-jdbc-sample/src/test/java/com/github/fridujo/sample/jdbc/JdbcApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.sample.jdbc; 2 | 3 | import com.github.fridujo.automocker.api.ResetMocks; 4 | import com.github.fridujo.automocker.base.Automocker; 5 | import com.github.fridujo.sample.jdbc.customer.CustomerRepository; 6 | import com.github.fridujo.sample.jdbc.order.OrderRepository; 7 | import org.assertj.core.groups.Tuple; 8 | import org.assertj.core.util.Sets; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.extension.ExtendWith; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.jdbc.support.JdbcUtils; 13 | import org.springframework.jdbc.support.MetaDataAccessException; 14 | import org.springframework.test.context.ContextConfiguration; 15 | import org.springframework.test.context.junit.jupiter.SpringExtension; 16 | 17 | import javax.sql.DataSource; 18 | import java.sql.ResultSet; 19 | import java.sql.SQLException; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.stream.Collectors; 24 | 25 | import static org.assertj.core.api.Assertions.assertThat; 26 | 27 | @Automocker 28 | @ResetMocks(disable = true) 29 | @ExtendWith(SpringExtension.class) 30 | @ContextConfiguration(classes = JdbcApplication.class) 31 | class JdbcApplicationTest { 32 | 33 | @Autowired 34 | private CustomerRepository customerRepo; 35 | 36 | @Autowired 37 | private OrderRepository orderRepo; 38 | @Autowired 39 | private Map datasources; 40 | 41 | @SuppressWarnings("unchecked") 42 | private static List listTables(DataSource dataSource) 43 | throws MetaDataAccessException { 44 | return (List) JdbcUtils.extractDatabaseMetaData(dataSource, dbmd -> { 45 | ResultSet rs = dbmd.getTables(null, null, null, new String[]{"TABLE"}); 46 | List names = new ArrayList<>(); 47 | while (rs.next()) { 48 | names.add(rs.getString(3)); 49 | } 50 | return names; 51 | }); 52 | } 53 | 54 | @Test 55 | public void data_initializer_have_already_persisted_customer() { 56 | assertThat(customerRepo.findAll()).hasSize(1) 57 | .extracting("firstname", "lastname") 58 | .contains(new Tuple("Dave", "Matthews")); 59 | } 60 | 61 | @Test 62 | public void data_initializer_have_already_persisted_orders() { 63 | assertThat(orderRepo.findAll()).hasSize(2); 64 | assertThat(Sets.newHashSet(orderRepo.findAll()) 65 | .stream() 66 | .flatMap(o -> o.getLineItems() 67 | .stream()) 68 | .collect(Collectors.toList())).extracting("description") 69 | .contains("Fender Jag-Stang Guitar", "Gene Simmons Axe Bass"); 70 | } 71 | 72 | @Test 73 | public void datasources_are_different_and_data_is_not_shared() 74 | throws MetaDataAccessException, SQLException { 75 | assertThat(datasources).containsOnlyKeys("customerDataSource", "orderDataSource"); 76 | 77 | assertThat(listTables(datasources.get("customerDataSource"))) 78 | .as("Tables of customer database") 79 | .containsExactlyInAnyOrder("CUSTOMER"); 80 | 81 | assertThat(listTables(datasources.get("orderDataSource"))) 82 | .as("Tables of order database") 83 | .containsExactlyInAnyOrder("SAMPLEORDER", "LINEITEM", "SAMPLEORDER_LINEITEM"); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /spring-automocker/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | com.github.fridujo 8 | spring-automocker-reactor 9 | 1.2.2-SNAPSHOT 10 | 11 | 12 | spring-automocker 13 | 14 | 15 | 16 | 17 | org.springframework 18 | spring-context 19 | ${spring.version} 20 | provided 21 | 22 | 23 | org.springframework 24 | spring-test 25 | ${spring.version} 26 | provided 27 | 28 | 29 | 30 | 31 | org.slf4j 32 | slf4j-api 33 | ${slf4j.version} 34 | 35 | 36 | com.google.guava 37 | guava 38 | ${guava.version} 39 | 40 | 41 | 42 | 43 | org.springframework 44 | spring-web 45 | provided 46 | 47 | 48 | javax.servlet 49 | javax.servlet-api 50 | provided 51 | 52 | 53 | org.hamcrest 54 | hamcrest-core 55 | provided 56 | 57 | 58 | org.springframework 59 | spring-jms 60 | provided 61 | 62 | 63 | javax.jms 64 | javax.jms-api 65 | provided 66 | 67 | 68 | com.mockrunner 69 | mockrunner-jms 70 | provided 71 | 72 | 73 | org.assertj 74 | assertj-core 75 | provided 76 | 77 | 78 | io.dropwizard.metrics 79 | metrics-graphite 80 | provided 81 | 82 | 83 | io.micrometer 84 | micrometer-registry-graphite 85 | provided 86 | 87 | 88 | org.springframework.amqp 89 | spring-rabbit 90 | provided 91 | 92 | 93 | com.github.fridujo 94 | rabbitmq-mock 95 | provided 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | cache: 3 | directories: 4 | - "$HOME/.m2" 5 | script: mvn test cobertura:cobertura -P samples 6 | after_success: 7 | - bash <(curl -s https://codecov.io/bash) 8 | - openssl aes-256-cbc -pass pass:$ENCRYPTION_PASSWORD -in $GPG_DIR/pubring.gpg.enc -out $GPG_DIR/pubring.gpg -d 9 | - openssl aes-256-cbc -pass pass:$ENCRYPTION_PASSWORD -in $GPG_DIR/secring.gpg.enc -out $GPG_DIR/secring.gpg -d 10 | - "$GPG_DIR/publish.sh" 11 | env: 12 | global: 13 | - secure: hcgiY7uLLUG+InmCpLTIXTw8RQGEVVBuSLz3rQwKqG2keF7GpzIbfB4B9q/Q3YIqFXsdduCTREEqTsKfkPQom1s7fvUKNzFj+eYxJlkjs1upA+8ZcbDehEiq4AeG2m/pJar/mRKsKmeg2S/kOKWyadhYPhtcHX58sS8xCpAmj4VygMDAoBI0QquT8l9H5A8h/N9lH/JMrRewkZSaxRBL0O+Ea3FqmbTXyOBkGcWbKRCRHYUPr5CHi45G2EvkSka7bAhWyLojz07TYfjo3g3LNUkzc+/J+KsMop8lGi115o50ICcicr8YeytzbnGmigkA6/OYosi11FUonFCCCAZ+GlvHqPNCGvnLOzlZzTFVocupSLwdg8fn2Eie3HaXmeORoDF6y6hZ3/c1efUglc+NA1eKWbL2knvr5YRl/T7JNywk8WRBGB+1myhyVe6OHbaJdmzLH9+PNx0XPDh4WgJrAXK1wixEwyja1Tv9MQjuxwYkUUUgpQWXdMJprbUnLeigz3BExgLIST8sVOXl61YudfTtMspjhg+Qv3RokHneZFF+708QOB6fyiof9E+KL6n5NtshNIika5e0ll3pyd15yCQqhwjxLOZ2bF2KNLuNepXnxsy5upbxzfIncR7P73r8CLdNIYIGkLzRCHbkWx9YEc9rpeeEG/1+q+/lTe8aJFY= 14 | - secure: M48iG9NBTDcgpAsaWqQN/yr69RoB8vlKJxpk3J3whR6tsxIm4h4GdY7UGGDpTh8+HNOf6z5+/+fdr+pdIQfcdgObZ3thNpeY2b39dhWkzbbwfidM0vIezTsifJFTKdBB7fGc5skrhWGlL1ZTg8Hzi6TlRY6mkcTtevCr96UQ5xlfM2fXrTbuqIsUUh6u2tkEHJWzpDvX4VpK2bSLH5jALR+0o3eR6/zWE12jFfpm/dZ7lWe7OjGCYqaGnwHrR9vY5GucWJGdiXXy8opcDJP++VE4iTIy/nUUB6NpUjQxDXnBxD+HEygPh0i6M07Ur3STnIHupf2+fjRsOenzQxVPk7bv6Rr14MCBdSqAQSTWcHRagQgQW13xG2etOywgwm8u2HwDELhGhAz/Zv+FUOKiqOBS7BUQdhV42TPjzwGrR3vwUBDvW7hB/D6GVftNbXOqA3LVE3JIyQNigzSuLZRVQ9lDsB13SoqWe7Qo+ukJrYVR9ZbCnAVCrKM4fKc0X+UZPp6NDpL2EUqdbN48RR4nUEJ27367j/oxPCoE3kG3tgG8icKFDGqSJPnrH70kyRL/i5oHygYePC167lqZx3CfZwI89AHsBWlBrNkXQJbX0tcCVTal5RM9uns0APGhcU+xS1BXI76oWwq/KFMgeDWvHMvmjE2X6EGesUb8qrFxSW0= 15 | - secure: Kmtovk3HTrJkAExeeAWMqzkSQMmDz68pMesbG8/SayWGeXpIPwSWuIQS4dRerkxNKcNNC34OjLDuSPvQwbyHhGhbfLG9YctuaxYCioXys5PNSihJkG4sTzu/cXdeO+q/lxQ/DRkSi/8cU0ZkAQwVeAPB8ftCJhsYwkSDU35DdteamwzImuR3eDTouYh2neRPiIpyxLx4Cn9n/YQIhQovTIKbySmircxMt9vSMAnP4BHen5xp5eXd3bw3EBgMZnyCSU9J4U1Y0NdQFihw/LStvSu/eDXUogFHa3Yk50h1ennxGyksM0NSLvqBi1SSGCwiNPJlwGgbFiopmUTct6Wssc8q6fM7dWg+HidrHs2wvOU46D8jLRsV/v8zwoFp8PDQC6TtWFcd2+ufakY3EE0yief9quB1GvECQgoiLY8pb3YGfq83hueRM8LXYwXbvRCZQXV6wvJMB92XcCUotN9KzlgQUWlD/WjML9RZxNvi1vJoKRUFFxfP5vh29l0qbeatUZywFCkneHgdKrjbB0hrlfJ+ugG+OE596rD1LXlMbdnh9ywh3IEVYBLRvKvGVz37ydUMAWJwuHBqW+3VwTpP3jY5DJ4I/sG8A0lvMH1UAGMJ3HHP9uYGFWZ6szupDLsgTmiN9+kt5mJLBPhOBlF3yvYIBSVGaW3FnRGo21WCvoY= 16 | - secure: oE8w90NOj+kub6ZFlBW98GpSrZo7cIUZJLKMzj+oWC7exqCBSIVcN+UUK3BNVkQWS8tHBXml+2wsn5l++EPnjVcDHfGgANZaapJYa68WTt4MsKOkrrtiuPS79TfoZTtutAetc8dhGCKZRbCfDCdeVrOnJ8vbnevFv3zYZ39NigqHXpzo28QfQObREYWADwWmaXbjFTVBBCtVONZ+LL2Izkip1Au+zE3WsZ3bjDHYw81joTUSZvD9flKedIfDsVF33V1qSug3gqcLijCsP7H/+Mruf2lY5Oxgadx/otNv3/d8UEhPvAO6htPsjSnMGa4dswaMXfhKhwO8eCEmsHTDkfc4BQ98duyGR5GIGxxU4EvWFMIiA+FoCxJSWf2xBwGau3ExHXYWCfDLlgUwgo1hLtRXF0IvCMt8+creozPecZzCdcKNTxJWf1jmf9I4th8+QJ/Hfs0M2xj9DdNdQdCr4m0x+seCoKzU32deUyKrZYFcQwiM/eNCEr4JQ4Da+5xzoKFpPvgNtXfyVhsIMm0KGQA/RdQGnCAQ5zYniS1AZJu3DjMBn2ZZQgB+bEP3PelvRUgH3iQkSI0kVZ5gbkaKfshqam6Uz/L0hD7uKJl+sGB9iGekNZk4gUQF8u+TQalYNqWX6+5YFopO7iZDDG8SlXuWpRvW1OU3gDoPDikXEiI= 17 | - secure: nddqx1kwbsef1ThpGngWCwg8E95IBV9hPVszM4S6sOFwVjldE3u6fTTWwVU/6sMBPpo/s1zyzcvFwJN2ds86z+KqBg+u05o31H3dA7lokvhSfb7Il1BjpmYL+jv4OmSTGWk1/EJIbUgQv+OH+tkvQE1yNV4ORYjzBu6r+0q59/wEQK6HygvK1egzorIHtHES5UA6QN57kEAe9EVIzDogQVG8UcNIU5VNg5VRLJ3xeRJ/pVoQuz1RlaAHnSsWaBUg+G9ZNFQ019sIpeWeTXTWXQZDeJslEXoIQlbNsmbsY7wfzmSjQ9JCIk+ADtEzgXa0rm7N+bE2Gf2HtEg5bWinXRDkMg5CmyDITFEYuOd1HSgMGXyM8dlm9//5+TO9j/YUttQ6EVx6HfH906rStJWiR9/9tjhVHcUX5mS8eJv9crjnDTntp75W0iG93mPW32VSrP61IYfBfKQ2BwYKYJ+Uy7cFXno2o7oZjkza9WB0yYwsqPnwRyPW6oKgVlVjfGlRZBGj27Msf4tK2dycvXK8dBV1PscKE01Wf2EI2YPVv/71DvzlazGX+Bp5vL/r/zjt91ljkVjL9dtz79+J7XWuxCjkVsTrmibAM0HGcbRkRaDXeZwfHmOxC4E4r6cdk/qnCKkyk0oaxHGpyLZulHezvdb3Ck7NkBATssV3r53ngX0= 18 | - GPG_DIR="`pwd`/deploy" 19 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockAmqp.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.base; 2 | 3 | import com.github.fridujo.automocker.api.AfterBeanRegistration; 4 | import com.github.fridujo.automocker.api.AfterBeanRegistrationExecutable; 5 | import com.github.fridujo.automocker.api.ExtendedBeanDefinitionRegistry; 6 | import com.github.fridujo.automocker.utils.Classes; 7 | import com.github.fridujo.rabbitmq.mock.MockConnectionFactory; 8 | import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; 9 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 10 | import org.springframework.beans.factory.config.RuntimeBeanReference; 11 | import org.springframework.beans.factory.support.RootBeanDefinition; 12 | 13 | import java.lang.annotation.Documented; 14 | import java.lang.annotation.ElementType; 15 | import java.lang.annotation.Retention; 16 | import java.lang.annotation.RetentionPolicy; 17 | import java.lang.annotation.Target; 18 | import java.util.Set; 19 | import java.util.stream.Collectors; 20 | 21 | /** 22 | * Alter bean definitions of {@link ConnectionFactory ConnectionFactories} by changing bean class with {@link MockConnectionFactory}. 23 | */ 24 | @Target(ElementType.TYPE) 25 | @Retention(RetentionPolicy.RUNTIME) 26 | @Documented 27 | 28 | @AfterBeanRegistration(MockAmqp.MockAmqpExecutable.class) 29 | public @interface MockAmqp { 30 | 31 | class MockAmqpExecutable implements AfterBeanRegistrationExecutable { 32 | 33 | private static final String RABBITMQ_MOCK_CONNECTION_FACTORY_CLASS = "com.github.fridujo.rabbitmq.mock.MockConnectionFactory"; 34 | 35 | @Override 36 | public void execute(MockAmqp annotation, ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry) { 37 | if (Classes.isPresent("org.springframework.amqp.rabbit.connection.ConnectionFactory")) { 38 | modifyConnectionFactoryBeanDefinitions(extendedBeanDefinitionRegistry); 39 | } 40 | } 41 | 42 | private void modifyConnectionFactoryBeanDefinitions(ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry) { 43 | Class clazzToMock = ConnectionFactory.class; 44 | Set connectionFactoryBeans = extendedBeanDefinitionRegistry 45 | .getBeanDefinitionsForClass(clazzToMock); 46 | if (!connectionFactoryBeans.isEmpty()) { 47 | if (Classes.isPresent(RABBITMQ_MOCK_CONNECTION_FACTORY_CLASS)) { 48 | connectionFactoryBeans.forEach(meta -> { 49 | 50 | String mockConnectionFactoryBeanName = extendedBeanDefinitionRegistry.registerBeanDefinition( 51 | "Automocker" + meta.name() + "MockConnectionFactory", 52 | new RootBeanDefinition(MockConnectionFactory.class), 53 | meta.getBeanQualifiers()); 54 | 55 | meta.beanDefinitionModifier() 56 | .copyFactoryQualifiersAsDetached() 57 | .reset() 58 | .setBeanClass(CachingConnectionFactory.class) 59 | .addConstructorIndexedArgumentValue(0, new RuntimeBeanReference(mockConnectionFactoryBeanName)); 60 | }); 61 | } else { 62 | throw new IllegalStateException("\nAutomocker is missing class [" + RABBITMQ_MOCK_CONNECTION_FACTORY_CLASS + "] to mock " + connectionFactoryBeans.size() + " bean(s) of type [" + clazzToMock.getName() + "]: " + 63 | connectionFactoryBeans.stream().map(ExtendedBeanDefinitionRegistry.BeanDefinitionMetadata::name).collect(Collectors.joining(", ")) + 64 | "\nMake sure rabbitmq-mock.jar is in the test classpath"); 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/context/ExtendedBeanDefinitionRegistryImplTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.context; 2 | 3 | import com.github.fridujo.automocker.api.ExtendedBeanDefinitionRegistry; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.beans.factory.support.AbstractBeanDefinition; 7 | import org.springframework.beans.factory.support.AutowireCandidateQualifier; 8 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 9 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | import java.util.Set; 14 | import java.util.stream.Stream; 15 | 16 | import static org.assertj.core.api.Assertions.assertThat; 17 | import static org.mockito.ArgumentMatchers.any; 18 | import static org.mockito.Mockito.mock; 19 | import static org.mockito.Mockito.times; 20 | import static org.mockito.Mockito.verify; 21 | 22 | class ExtendedBeanDefinitionRegistryImplTest { 23 | 24 | @Test 25 | void list_bean_definitions_by_type() { 26 | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtendedBeanDefinitionRegistryImplTest.TestConfiguration.class); 27 | ExtendedBeanDefinitionRegistry extendedRegistry = new ExtendedBeanDefinitionRegistryImpl(context); 28 | 29 | Set beanDefinitions = extendedRegistry.getBeanDefinitionsForClass(Stream.class); 30 | 31 | assertThat(beanDefinitions) 32 | .hasOnlyOneElementSatisfying(beanDefinitionMetadata -> { 33 | assertThat(beanDefinitionMetadata.name()).isEqualTo("testBean"); 34 | assertThat(beanDefinitionMetadata.beanClass()).isEqualTo(Stream.class); 35 | assertThat(beanDefinitionMetadata.beanDefinition()).isNotNull(); 36 | assertThat(beanDefinitionMetadata.beanDefinitionModifier()).isNotNull(); 37 | }); 38 | } 39 | 40 | @Test 41 | void register_bean_definition_delegates() { 42 | BeanDefinitionRegistry delegate = mock(BeanDefinitionRegistry.class); 43 | ExtendedBeanDefinitionRegistry extendedRegistry = new ExtendedBeanDefinitionRegistryImpl(delegate); 44 | 45 | extendedRegistry.registerBeanDefinition("test", null); 46 | 47 | verify(delegate, times(1)).registerBeanDefinition(any(), any()); 48 | } 49 | 50 | @Test 51 | void register_linked_bean_definition_delegates() { 52 | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ExtendedBeanDefinitionRegistryImplTest.TestConfiguration.class); 53 | ExtendedBeanDefinitionRegistry extendedRegistry = new ExtendedBeanDefinitionRegistryImpl(context); 54 | Set beanDefinitions = extendedRegistry.getBeanDefinitionsForClass(Stream.class); 55 | 56 | assertThat(beanDefinitions).hasSize(1); 57 | 58 | ExtendedBeanDefinitionRegistry.BeanDefinitionMetadata metadata = beanDefinitions.iterator().next(); 59 | 60 | String linkedBeanName = metadata.registerLinkedBeanDefinition(String.class); 61 | AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) context.getBeanDefinition(linkedBeanName); 62 | 63 | assertThat(linkedBeanName).contains(metadata.name()); 64 | assertThat(beanDefinition.getBeanClassName()).isEqualTo(String.class.getName()); 65 | assertThat(beanDefinition.getQualifiers()).hasSize(1); 66 | AutowireCandidateQualifier qualifier = beanDefinition.getQualifiers().iterator().next(); 67 | assertThat(qualifier.getTypeName()).isEqualTo(Qualifier.class.getName()); 68 | assertThat(qualifier.getAttribute(AutowireCandidateQualifier.VALUE_KEY)).isEqualTo("testQ"); 69 | } 70 | 71 | @Configuration 72 | public static class TestConfiguration { 73 | 74 | @Bean 75 | @Qualifier("testQ") 76 | Stream testBean() { 77 | return Stream.of("test"); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockWebMvc.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.base; 2 | 3 | import com.github.fridujo.automocker.api.AfterBeanRegistration; 4 | import com.github.fridujo.automocker.api.AfterBeanRegistrationExecutable; 5 | import com.github.fridujo.automocker.api.ExtendedBeanDefinitionRegistry; 6 | import com.github.fridujo.automocker.utils.Classes; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.BeansException; 10 | import org.springframework.beans.factory.FactoryBean; 11 | import org.springframework.beans.factory.InitializingBean; 12 | import org.springframework.beans.factory.support.RootBeanDefinition; 13 | import org.springframework.context.ApplicationContext; 14 | import org.springframework.context.ApplicationContextAware; 15 | import org.springframework.stereotype.Controller; 16 | import org.springframework.test.web.servlet.MockMvc; 17 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 18 | import org.springframework.web.context.WebApplicationContext; 19 | 20 | import java.lang.annotation.Documented; 21 | import java.lang.annotation.ElementType; 22 | import java.lang.annotation.Retention; 23 | import java.lang.annotation.RetentionPolicy; 24 | import java.lang.annotation.Target; 25 | import java.util.Map; 26 | 27 | /** 28 | * Setup {@link MockMvc} for available {@link Controller Controllers}. 29 | */ 30 | @Target(ElementType.TYPE) 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Documented 33 | 34 | @AfterBeanRegistration(MockWebMvc.MockWebMvcExecutable.class) 35 | public @interface MockWebMvc { 36 | 37 | class MockWebMvcExecutable implements AfterBeanRegistrationExecutable { 38 | 39 | @Override 40 | public void execute(MockWebMvc annotation, ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry) { 41 | if (Classes.isPresent("org.springframework.test.web.servlet.MockMvc")) { 42 | extendedBeanDefinitionRegistry.registerBeanDefinition("mockMvc", new RootBeanDefinition(MockMvcFactory.class)); 43 | } 44 | } 45 | } 46 | 47 | class MockMvcFactory implements FactoryBean, ApplicationContextAware, InitializingBean { 48 | 49 | private static final Logger LOGGER = LoggerFactory.getLogger(MockMvcFactory.class); 50 | 51 | private ApplicationContext applicationContext; 52 | private MockMvc singleton; 53 | 54 | @Override 55 | public MockMvc getObject() { 56 | return singleton; 57 | } 58 | 59 | @Override 60 | public Class getObjectType() { 61 | return MockMvc.class; 62 | } 63 | 64 | @Override 65 | public boolean isSingleton() { 66 | return true; 67 | } 68 | 69 | @Override 70 | public void afterPropertiesSet() { 71 | if (Classes.isPresent("org.springframework.web.context.WebApplicationContext") && isWebContext()) { 72 | this.singleton = MockMvcBuilders.webAppContextSetup((WebApplicationContext) applicationContext).build(); 73 | LOGGER.debug("Setting up " + MockMvc.class.getSimpleName() + " for WebApplicationContext"); 74 | } else { 75 | Map controllersByName = applicationContext.getBeansWithAnnotation(Controller.class); 76 | if (controllersByName.size() > 0) { 77 | this.singleton = MockMvcBuilders.standaloneSetup(controllersByName.values() 78 | .toArray()) 79 | .build(); 80 | LOGGER.debug("Setting up " + MockMvc.class.getSimpleName() + " for controllers " 81 | + controllersByName.keySet()); 82 | } else { 83 | this.singleton = null; 84 | } 85 | } 86 | } 87 | 88 | @Override 89 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 90 | this.applicationContext = applicationContext; 91 | } 92 | 93 | public boolean isWebContext() { 94 | return applicationContext instanceof WebApplicationContext; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/context/ExtendedBeanDefinitionRegistryImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.context; 2 | 3 | import com.github.fridujo.automocker.api.ExtendedBeanDefinitionRegistry; 4 | import com.github.fridujo.automocker.utils.BeanDefinitions; 5 | import org.springframework.beans.factory.config.BeanDefinition; 6 | import org.springframework.beans.factory.support.AbstractBeanDefinition; 7 | import org.springframework.beans.factory.support.BeanDefinitionRegistry; 8 | import org.springframework.beans.factory.support.RootBeanDefinition; 9 | 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | 13 | class ExtendedBeanDefinitionRegistryImpl implements ExtendedBeanDefinitionRegistry { 14 | 15 | private final BeanDefinitionRegistry registry; 16 | 17 | ExtendedBeanDefinitionRegistryImpl(BeanDefinitionRegistry registry) { 18 | this.registry = registry; 19 | } 20 | 21 | @Override 22 | public Set getBeanDefinitionsForClass(Class clazz) { 23 | Set result = new HashSet<>(); 24 | 25 | for (String beanName : registry.getBeanDefinitionNames()) { 26 | BeanDefinition beanDefinition = registry.getBeanDefinition(beanName); 27 | if (beanDefinition instanceof AbstractBeanDefinition) { 28 | Class beanClass = BeanDefinitions.extractClass((AbstractBeanDefinition) beanDefinition); 29 | if (clazz.isAssignableFrom(beanClass)) { 30 | result.add(new ImmutableBeanDefinitionMetadata( 31 | this, 32 | beanName, 33 | beanClass, 34 | (AbstractBeanDefinition) beanDefinition, 35 | new BeanDefinitionModifier((AbstractBeanDefinition) beanDefinition))); 36 | } 37 | } 38 | } 39 | 40 | return result; 41 | } 42 | 43 | @Override 44 | public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) { 45 | registry.registerBeanDefinition(beanName, beanDefinition); 46 | } 47 | 48 | private static class ImmutableBeanDefinitionMetadata implements BeanDefinitionMetadata { 49 | private final ExtendedBeanDefinitionRegistryImpl extendedBeanDefinitionRegistry; 50 | private final String name; 51 | private final Class beanClass; 52 | private final AbstractBeanDefinition beanDefinition; 53 | private final BeanDefinitionModifier beanDefinitionModifier; 54 | 55 | private ImmutableBeanDefinitionMetadata(ExtendedBeanDefinitionRegistryImpl extendedBeanDefinitionRegistry, String name, 56 | Class beanClass, 57 | AbstractBeanDefinition beanDefinition, 58 | BeanDefinitionModifier beanDefinitionModifier) { 59 | this.extendedBeanDefinitionRegistry = extendedBeanDefinitionRegistry; 60 | this.name = name; 61 | this.beanClass = beanClass; 62 | this.beanDefinition = beanDefinition; 63 | this.beanDefinitionModifier = beanDefinitionModifier; 64 | } 65 | 66 | 67 | @Override 68 | public String name() { 69 | return name; 70 | } 71 | 72 | @Override 73 | public Class beanClass() { 74 | return beanClass; 75 | } 76 | 77 | @Override 78 | public AbstractBeanDefinition beanDefinition() { 79 | return beanDefinition; 80 | } 81 | 82 | @Override 83 | public BeanDefinitionModifier beanDefinitionModifier() { 84 | return beanDefinitionModifier; 85 | } 86 | 87 | @Override 88 | public String registerLinkedBeanDefinition(Class beanClass) { 89 | String linkedBeanName = "Automocker" + name() + beanClass.getSimpleName(); 90 | RootBeanDefinition linkedBeanDefinition = new RootBeanDefinition(beanClass); 91 | extendedBeanDefinitionRegistry.registerBeanDefinition(linkedBeanName, linkedBeanDefinition, getBeanQualifiers()); 92 | return linkedBeanName; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/api/tools/BeanLocatorTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.tools; 2 | 3 | import com.github.fridujo.automocker.utils.Maps; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.context.ApplicationContext; 6 | 7 | import java.util.Collections; 8 | 9 | import static org.assertj.core.api.Assertions.assertThat; 10 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 11 | import static org.mockito.Mockito.mock; 12 | import static org.mockito.Mockito.when; 13 | 14 | class BeanLocatorTest { 15 | 16 | @Test 17 | void getBean_returns_when_one_bean_matches() { 18 | ApplicationContext applicationContext = mock(ApplicationContext.class); 19 | BeanLocator beanLocator = new BeanLocator(applicationContext); 20 | 21 | when(applicationContext.getBeansOfType(String.class)) 22 | .thenReturn(Maps.build(String.class, "testBeanName", "testBean")); 23 | 24 | assertThat(beanLocator.getBean(String.class)).isEqualTo("testBean"); 25 | } 26 | 27 | @Test 28 | void getBean_throws_when_no_bean_matches() { 29 | ApplicationContext applicationContext = mock(ApplicationContext.class); 30 | BeanLocator beanLocator = new BeanLocator(applicationContext); 31 | 32 | when(applicationContext.getBeansOfType(String.class)) 33 | .thenReturn(Collections.emptyMap()); 34 | 35 | assertThatExceptionOfType(IllegalArgumentException.class) 36 | .isThrownBy(() -> beanLocator.getBean(String.class)) 37 | .withMessage("No bean matching String"); 38 | } 39 | 40 | @Test 41 | void getBean_throws_when_more_than_one_bean_matches() { 42 | ApplicationContext applicationContext = mock(ApplicationContext.class); 43 | BeanLocator beanLocator = new BeanLocator(applicationContext); 44 | 45 | when(applicationContext.getBeansOfType(String.class)) 46 | .thenReturn(Maps.build(String.class, 47 | "testBeanName1", "testBean1", 48 | "testBeanName2", "testBean2" 49 | )); 50 | 51 | assertThatExceptionOfType(IllegalArgumentException.class) 52 | .isThrownBy(() -> beanLocator.getBean(String.class)) 53 | .withMessage("Multiple beans matching String. Available: testBeanName1, testBeanName2"); 54 | } 55 | 56 | @Test 57 | void getBeanByPartialName_returns_when_one_bean_matches() { 58 | ApplicationContext applicationContext = mock(ApplicationContext.class); 59 | BeanLocator beanLocator = new BeanLocator(applicationContext); 60 | 61 | when(applicationContext.getBeansOfType(String.class)) 62 | .thenReturn(Maps.build(String.class, "someTestBeanName", "testBean", "otherBeanName", "otherBean")); 63 | 64 | assertThat(beanLocator.getBeanByPartialName("Test", String.class)).isEqualTo("testBean"); 65 | } 66 | 67 | @Test 68 | void getBeanByPartialName_throws_when_no_bean_matches() { 69 | ApplicationContext applicationContext = mock(ApplicationContext.class); 70 | BeanLocator beanLocator = new BeanLocator(applicationContext); 71 | 72 | when(applicationContext.getBeansOfType(String.class)) 73 | .thenReturn(Collections.emptyMap()); 74 | 75 | assertThatExceptionOfType(IllegalArgumentException.class) 76 | .isThrownBy(() -> beanLocator.getBeanByPartialName("Test", String.class)) 77 | .withMessage("No bean matching String{name: *Test*}"); 78 | } 79 | 80 | @Test 81 | void getBeanByPartialName_throws_when_more_than_one_bean_matches() { 82 | ApplicationContext applicationContext = mock(ApplicationContext.class); 83 | BeanLocator beanLocator = new BeanLocator(applicationContext); 84 | 85 | when(applicationContext.getBeansOfType(String.class)) 86 | .thenReturn(Maps.build(String.class, 87 | "testBeanName1", "testBean1", 88 | "testBeanName2", "testBean2" 89 | )); 90 | 91 | assertThatExceptionOfType(IllegalArgumentException.class) 92 | .isThrownBy(() -> beanLocator.getBeanByPartialName("Bean", String.class)) 93 | .withMessage("Multiple beans matching String{name: *Bean*}. Available: testBeanName1, testBeanName2"); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/utils/ThrowingTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import org.junit.jupiter.api.Nested; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.function.BiConsumer; 7 | import java.util.function.Consumer; 8 | import java.util.function.Function; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 12 | 13 | class ThrowingTest { 14 | 15 | private static String behave(Behavior input) throws Exception { 16 | if (Behavior.DO_NOT_THROW == input) { 17 | return "test"; 18 | } else if (Behavior.THROW_CHECKED == input) { 19 | throw new TestException(); 20 | } else { 21 | throw new TestRuntimeException(); 22 | } 23 | } 24 | 25 | private enum Behavior { 26 | DO_NOT_THROW, THROW_CHECKED, THROW_UNCHECKED 27 | } 28 | 29 | @Nested 30 | static class ThrowingFunctionTest { 31 | Function silenced = ThrowingFunction.silent(ThrowingTest::behave); 32 | 33 | @Test 34 | void silenced_function_when_not_throwing() { 35 | assertThat(silenced.apply(Behavior.DO_NOT_THROW)).isEqualTo("test"); 36 | } 37 | 38 | @Test 39 | void silenced_function_when_throwing() { 40 | assertThatExceptionOfType(LamdaLuggageException.class) 41 | .isThrownBy(() -> silenced.apply(Behavior.THROW_CHECKED)) 42 | .withCauseExactlyInstanceOf(TestException.class); 43 | } 44 | 45 | @Test 46 | void silenced_function_when_throwing_unchecked() { 47 | assertThatExceptionOfType(TestRuntimeException.class) 48 | .isThrownBy(() -> silenced.apply(Behavior.THROW_UNCHECKED)) 49 | .withCause(null); 50 | } 51 | } 52 | 53 | @Nested 54 | static class ThrowingConsumerTest { 55 | Consumer silenced = ThrowingConsumer.silent(ThrowingTest::behave); 56 | 57 | @Test 58 | void silenced_consumer_when_not_throwing() { 59 | silenced.accept(Behavior.DO_NOT_THROW); 60 | } 61 | 62 | @Test 63 | void silenced_function_when_throwing() { 64 | assertThatExceptionOfType(LamdaLuggageException.class) 65 | .isThrownBy(() -> silenced.accept(Behavior.THROW_CHECKED)) 66 | .withCauseExactlyInstanceOf(TestException.class); 67 | } 68 | 69 | @Test 70 | void silenced_function_when_throwing_unchecked() { 71 | assertThatExceptionOfType(TestRuntimeException.class) 72 | .isThrownBy(() -> silenced.accept(Behavior.THROW_UNCHECKED)) 73 | .withCause(null); 74 | } 75 | } 76 | 77 | @Nested 78 | static class ThrowingBiConsumerTest { 79 | BiConsumer silenced = ThrowingBiConsumer.silent(ThrowingBiConsumerTest::behave); 80 | 81 | private static String behave(Behavior input, String secondParameter) throws Exception { 82 | if (Behavior.DO_NOT_THROW == input) { 83 | return "test"; 84 | } else if (Behavior.THROW_CHECKED == input) { 85 | throw new TestException(); 86 | } else { 87 | throw new TestRuntimeException(); 88 | } 89 | } 90 | 91 | @Test 92 | void silenced_consumer_when_not_throwing() { 93 | silenced.accept(Behavior.DO_NOT_THROW, null); 94 | } 95 | 96 | @Test 97 | void silenced_function_when_throwing() { 98 | assertThatExceptionOfType(LamdaLuggageException.class) 99 | .isThrownBy(() -> silenced.accept(Behavior.THROW_CHECKED, null)) 100 | .withCauseExactlyInstanceOf(TestException.class); 101 | } 102 | 103 | @Test 104 | void silenced_function_when_throwing_unchecked() { 105 | assertThatExceptionOfType(TestRuntimeException.class) 106 | .isThrownBy(() -> silenced.accept(Behavior.THROW_UNCHECKED, null)) 107 | .withCause(null); 108 | } 109 | } 110 | 111 | private static class TestException extends Exception { 112 | } 113 | 114 | private static class TestRuntimeException extends RuntimeException { 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/ExtendedBeanDefinitionRegistry.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api; 2 | 3 | import com.github.fridujo.automocker.utils.BeanDefinitions; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.beans.factory.config.BeanDefinition; 6 | import org.springframework.beans.factory.support.AbstractBeanDefinition; 7 | import org.springframework.beans.factory.support.AutowireCandidateQualifier; 8 | import org.springframework.beans.factory.support.RootBeanDefinition; 9 | 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | public interface ExtendedBeanDefinitionRegistry { 14 | 15 | Set getBeanDefinitionsForClass(Class clazz); 16 | 17 | void registerBeanDefinition(String beanName, BeanDefinition beanDefinition); 18 | 19 | default String registerBeanDefinition(Class beanClass) { 20 | String beanName = "Automocker" + beanClass.getSimpleName(); 21 | registerBeanDefinition(beanName, new RootBeanDefinition(beanClass)); 22 | return beanName; 23 | } 24 | 25 | default String registerBeanDefinition(String beanName, AbstractBeanDefinition abstractBeanDefinition, Map qualifiers) { 26 | qualifiers.forEach((qualifierType, qualifierValue) -> abstractBeanDefinition.addQualifier(new AutowireCandidateQualifier(qualifierType, qualifierValue))); 27 | registerBeanDefinition(beanName, abstractBeanDefinition); 28 | return beanName; 29 | } 30 | 31 | interface BeanDefinitionMetadata { 32 | String name(); 33 | 34 | Class beanClass(); 35 | 36 | AbstractBeanDefinition beanDefinition(); 37 | 38 | BeanDefinitionModifier beanDefinitionModifier(); 39 | 40 | default Map getBeanQualifiers() { 41 | return BeanDefinitions.extractQualifiers(beanDefinition()); 42 | } 43 | 44 | String registerLinkedBeanDefinition(Class beanClass); 45 | } 46 | 47 | class BeanDefinitionModifier { 48 | 49 | private static final String QUALIFIER_CLASS_NAME = Qualifier.class.getName(); 50 | private static final String VALUE_FIELD_NAME = "value"; 51 | 52 | private final AbstractBeanDefinition beanDefinition; 53 | 54 | public BeanDefinitionModifier(AbstractBeanDefinition beanDefinition) { 55 | this.beanDefinition = beanDefinition; 56 | } 57 | 58 | public BeanDefinitionModifier setFactoryBeanName(String factoryBeanName) { 59 | beanDefinition.setFactoryBeanName(factoryBeanName); 60 | return this; 61 | } 62 | 63 | public BeanDefinitionModifier setFactoryMethodName(String factoryMethodName) { 64 | beanDefinition.setFactoryMethodName(factoryMethodName); 65 | return this; 66 | } 67 | 68 | public BeanDefinitionModifier addConstructorIndexedArgumentValue(int index, Object value) { 69 | beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(index, value); 70 | return this; 71 | } 72 | 73 | public BeanDefinitionModifier setBeanClass(Class beanClass) { 74 | beanDefinition.setBeanClass(beanClass); 75 | return this; 76 | } 77 | 78 | public BeanDefinitionModifier removeConstructorArgumentValues() { 79 | beanDefinition.setConstructorArgumentValues(null); 80 | return this; 81 | } 82 | 83 | public BeanDefinitionModifier removePropertyValues() { 84 | beanDefinition.setPropertyValues(null); 85 | return this; 86 | } 87 | 88 | public BeanDefinitionModifier addPropertyValue(String propertyName, Object propertyValue) { 89 | beanDefinition.getPropertyValues().add(propertyName, propertyValue); 90 | return this; 91 | } 92 | 93 | public BeanDefinitionModifier copyFactoryQualifiersAsDetached() { 94 | BeanDefinitions.extractQualifiers(beanDefinition) 95 | .forEach((qualifierType, qualifierValue) -> beanDefinition.addQualifier(new AutowireCandidateQualifier(qualifierType, qualifierValue))); 96 | return this; 97 | } 98 | 99 | public BeanDefinitionModifier reset() { 100 | setFactoryBeanName(null); 101 | setFactoryMethodName(null); 102 | removeConstructorArgumentValues(); 103 | removePropertyValues(); 104 | return this; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/JmsMock.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jms; 2 | 3 | import com.mockrunner.jms.DestinationManager; 4 | import com.mockrunner.mock.jms.MockDestination; 5 | import org.springframework.jms.config.AbstractJmsListenerContainerFactory; 6 | import org.springframework.jms.core.JmsTemplate; 7 | import org.springframework.util.ErrorHandler; 8 | 9 | import javax.jms.ConnectionFactory; 10 | import java.util.Optional; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | public final class JmsMock { 14 | 15 | final ConnectionFactory connectionFactory; 16 | private final JmsTemplate jmsTemplate; 17 | private final DestinationManager destinationManager; 18 | 19 | private Optional errorHandlerMock = Optional.empty(); 20 | 21 | public JmsMock(ConnectionFactory connectionFactory, DestinationManager destinationManager) { 22 | this.connectionFactory = connectionFactory; 23 | this.jmsTemplate = new JmsTemplate(connectionFactory); 24 | this.destinationManager = destinationManager; 25 | } 26 | 27 | public void sendText(String destinationName, String textPayload) { 28 | sendText(destinationName, JmsMessageBuilder.newTextMessage(textPayload)); 29 | } 30 | 31 | public void sendText(String destinationName, String textPayload, Object... properties) { 32 | sendText(destinationName, JmsMessageBuilder.newTextMessage(textPayload) 33 | .addProperties(properties)); 34 | } 35 | 36 | public void sendText(String destinationName, JmsMessageBuilder messageBuilder) { 37 | jmsTemplate.send(destinationName, messageBuilder::toMessage); 38 | } 39 | 40 | /** 41 | * May wait until 1500 ms for the destination to exists (be dynamically created). 42 | * 43 | * @throws IllegalArgumentException if the destination can not be found after 1500 ms 44 | * @throws IllegalStateException if interrupted while waiting for destination to exists 45 | */ 46 | public JmsDestinationAssert assertThatDestination(String destinationName) throws IllegalArgumentException, IllegalStateException { 47 | Optional potentialDestination = tryGettingDestination(destinationName, 3, 500L); 48 | if (potentialDestination.isPresent()) { 49 | return new JmsDestinationAssert(potentialDestination.get(), destinationName); 50 | } else { 51 | throw new IllegalArgumentException("Destination [" + destinationName + "] does not exists"); 52 | } 53 | 54 | } 55 | 56 | private Optional tryGettingDestination(String destinationName, int tryNumber, long durationInMsBetweenTries) throws IllegalStateException { 57 | Optional potentialDestination = Optional.empty(); 58 | for (int tryIndex = 0; tryIndex < tryNumber; tryIndex++) { 59 | potentialDestination = immediatlyGetDestination(destinationManager, destinationName); 60 | if (potentialDestination.isPresent()) { 61 | break; 62 | } 63 | try { 64 | TimeUnit.MILLISECONDS.sleep(durationInMsBetweenTries); 65 | } catch (InterruptedException e) { 66 | throw new IllegalStateException("Interrupted while waiting for destination [" + destinationName + "] to exists"); 67 | } 68 | } 69 | return potentialDestination; 70 | } 71 | 72 | private Optional immediatlyGetDestination(DestinationManager destinationManager, String destinationName) { 73 | final Optional destination; 74 | if (destinationManager.existsQueue(destinationName)) { 75 | destination = Optional.of(destinationManager.getQueue(destinationName)); 76 | } else if (destinationManager.existsTopic(destinationName)) { 77 | destination = Optional.of(destinationManager.getTopic(destinationName)); 78 | } else { 79 | destination = Optional.empty(); 80 | } 81 | return destination; 82 | } 83 | 84 | public ErrorHandlerMock containerErrorHandler() { 85 | if (!errorHandlerMock.isPresent()) { 86 | throw new IllegalStateException("No " + ErrorHandler.class.getSimpleName() 87 | + " available, make sure @MockJms is present and an " 88 | + AbstractJmsListenerContainerFactory.class.getSimpleName() 89 | + " is configured in your Spring configuration"); 90 | } 91 | return errorHandlerMock.get(); 92 | } 93 | 94 | void setErrorHandlerMock(ErrorHandlerMock errorHandlerMock) { 95 | this.errorHandlerMock = Optional.of(errorHandlerMock); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/utils/BeanDefinitions.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; 4 | import org.springframework.beans.factory.annotation.Qualifier; 5 | import org.springframework.beans.factory.config.BeanDefinition; 6 | import org.springframework.beans.factory.support.AbstractBeanDefinition; 7 | import org.springframework.core.annotation.AnnotationUtils; 8 | import org.springframework.core.type.MethodMetadata; 9 | import org.springframework.core.type.StandardMethodMetadata; 10 | import org.springframework.core.type.classreading.MethodMetadataReadingVisitor; 11 | import org.springframework.util.ClassUtils; 12 | 13 | import java.lang.annotation.Annotation; 14 | import java.util.HashMap; 15 | import java.util.LinkedHashMap; 16 | import java.util.Map; 17 | import java.util.Set; 18 | 19 | import static org.springframework.beans.factory.support.AutowireCandidateQualifier.VALUE_KEY; 20 | 21 | public final class BeanDefinitions { 22 | 23 | private static final ClassLoader BEAN_CLASS_LOADER = ClassUtils.getDefaultClassLoader(); 24 | private static final String QUALIFIER_CLASS_NAME = Qualifier.class.getName(); 25 | 26 | private BeanDefinitions() { 27 | } 28 | 29 | public static Class extractClass(AbstractBeanDefinition beanDefinition) { 30 | AbstractBeanDefinition abd = beanDefinition; 31 | try { 32 | Class beanClazz = abd.resolveBeanClass(BEAN_CLASS_LOADER); 33 | MethodMetadata factoryMetadata = getMethodMetadata(beanDefinition); 34 | if (beanClazz != null) { 35 | return beanClazz; 36 | } else if (factoryMetadata != null) { 37 | return Class.forName(factoryMetadata.getReturnTypeName()); 38 | } else { 39 | throw new IllegalStateException( 40 | "Unable to resolve target class for BeanDefinition [" + beanDefinition + "]"); 41 | } 42 | } catch (ClassNotFoundException ex) { 43 | throw new IllegalStateException("Cannot load class: " + ex.getMessage(), ex); 44 | } 45 | } 46 | 47 | private static MethodMetadata getMethodMetadata(BeanDefinition beanDef) { 48 | return AnnotatedBeanDefinition.class.isAssignableFrom(beanDef.getClass()) 49 | ? ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata() : null; 50 | } 51 | 52 | public static Map extractQualifiers(BeanDefinition beanDefinition) { 53 | Map qualifiers = new LinkedHashMap<>(); 54 | if (beanDefinition instanceof AnnotatedBeanDefinition) { 55 | MethodMetadata factoryMethodMetadata = ((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata(); 56 | if (factoryMethodMetadata instanceof MethodMetadataReadingVisitor) { 57 | Map qualityQualifiers = listQualityQualifiers((MethodMetadataReadingVisitor) factoryMethodMetadata); 58 | qualifiers.putAll(qualityQualifiers); 59 | } else if (factoryMethodMetadata instanceof StandardMethodMetadata) { 60 | Map qualityQualifiers = listQualityQualifiers((StandardMethodMetadata) factoryMethodMetadata); 61 | qualifiers.putAll(qualityQualifiers); 62 | } 63 | 64 | Map annotationAttributes = factoryMethodMetadata.getAnnotationAttributes(QUALIFIER_CLASS_NAME); 65 | if (annotationAttributes != null) { 66 | Object qualifierValue = annotationAttributes.get(VALUE_KEY); 67 | if (!"".equals(qualifierValue)) { 68 | qualifiers.put(QUALIFIER_CLASS_NAME, qualifierValue); 69 | } 70 | } 71 | } 72 | return qualifiers; 73 | } 74 | 75 | private static Map listQualityQualifiers(MethodMetadataReadingVisitor factoryMethodMetadata) { 76 | // TODO make a PR to Spring to add a method in AnnotatedTypeMetadata for annotation search 77 | Map> metaAnnotationMap = Classes.getValueFromProtectedField(factoryMethodMetadata, "metaAnnotationMap"); 78 | Map qualityQualifiers = new HashMap<>(); 79 | for (Map.Entry> annotationData : metaAnnotationMap.entrySet()) { 80 | if (annotationData.getValue().contains(QUALIFIER_CLASS_NAME)) { 81 | Object qualifierValue = factoryMethodMetadata.getAnnotationAttributes(annotationData.getKey()).get(VALUE_KEY); 82 | if (qualifierValue != null) { 83 | qualityQualifiers.put(annotationData.getKey(), qualifierValue); 84 | } 85 | } 86 | } 87 | return qualityQualifiers; 88 | } 89 | 90 | private static Map listQualityQualifiers(StandardMethodMetadata factoryMethodMetadata) { 91 | Set> annotationsAnnotatedWithQualifier = Annotations.getAnnotationsAnnotatedWith(factoryMethodMetadata.getIntrospectedMethod(), Qualifier.class); 92 | Map qualityQualifiers = new HashMap<>(); 93 | annotationsAnnotatedWithQualifier.forEach(annotationAnnotatedWithQualifier -> { 94 | Annotation qualityQualifier = annotationAnnotatedWithQualifier.annotation(); 95 | Map annotationAttributes = AnnotationUtils.getAnnotationAttributes(qualityQualifier); 96 | if (annotationAttributes.containsKey(VALUE_KEY)) { 97 | qualityQualifiers.put(qualityQualifier.annotationType().getName(), annotationAttributes.get(VALUE_KEY)); 98 | } 99 | }); 100 | return qualityQualifiers; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockJms.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.base; 2 | 3 | import com.github.fridujo.automocker.api.AfterBeanRegistration; 4 | import com.github.fridujo.automocker.api.AfterBeanRegistrationExecutable; 5 | import com.github.fridujo.automocker.api.ExtendedBeanDefinitionRegistry; 6 | import com.github.fridujo.automocker.api.jms.DestinationManagerResetter; 7 | import com.github.fridujo.automocker.api.jms.JmsListenerContainerFactoryConfigurer; 8 | import com.github.fridujo.automocker.api.jms.JmsMock; 9 | import com.github.fridujo.automocker.api.jms.JmsMockLocator; 10 | import com.github.fridujo.automocker.utils.Classes; 11 | import com.mockrunner.jms.ConfigurationManager; 12 | import com.mockrunner.jms.DestinationManager; 13 | import com.mockrunner.mock.jms.MockConnectionFactory; 14 | import org.springframework.beans.factory.config.ConstructorArgumentValues; 15 | import org.springframework.beans.factory.config.RuntimeBeanReference; 16 | import org.springframework.beans.factory.support.AbstractBeanDefinition; 17 | import org.springframework.beans.factory.support.RootBeanDefinition; 18 | 19 | import javax.jms.ConnectionFactory; 20 | import javax.sql.DataSource; 21 | import java.lang.annotation.Documented; 22 | import java.lang.annotation.ElementType; 23 | import java.lang.annotation.Retention; 24 | import java.lang.annotation.RetentionPolicy; 25 | import java.lang.annotation.Target; 26 | import java.util.Map; 27 | import java.util.Set; 28 | import java.util.stream.Collectors; 29 | 30 | 31 | @Target(ElementType.TYPE) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | @Documented 34 | 35 | @AfterBeanRegistration(MockJms.MockJmsExecutable.class) 36 | public @interface MockJms { 37 | 38 | class MockJmsExecutable implements AfterBeanRegistrationExecutable { 39 | private static final String MOCKRUNNER_CONNECTION_FACTORY_CLASS = "com.mockrunner.mock.jms.MockConnectionFactory"; 40 | 41 | @Override 42 | public void execute(MockJms annotation, ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry) { 43 | if (Classes.isPresent("javax.jms.ConnectionFactory")) { 44 | modifyConnectionFactoryBeanDefinitions(extendedBeanDefinitionRegistry); 45 | } 46 | } 47 | 48 | private void modifyConnectionFactoryBeanDefinitions(ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry) { 49 | Class clazzToMock = ConnectionFactory.class; 50 | Set connectionFactoryBeans = extendedBeanDefinitionRegistry 51 | .getBeanDefinitionsForClass(clazzToMock); 52 | 53 | if (!connectionFactoryBeans.isEmpty()) { 54 | if (Classes.isPresent(MOCKRUNNER_CONNECTION_FACTORY_CLASS)) { 55 | connectionFactoryBeans.forEach(meta -> { 56 | String destinationManagerBeanName = "Automocker" + meta.name() + "DestinationManager"; 57 | String configurationManagerBeanName = "Automocker" + meta.name() + "ConfigurationManager"; 58 | String jmsMockBeanName = "Automocker" + meta.name() + "JmsMock"; 59 | 60 | Map qualifiers = meta.getBeanQualifiers(); 61 | 62 | meta.beanDefinitionModifier() 63 | .copyFactoryQualifiersAsDetached() 64 | .reset() 65 | .setBeanClass(MockConnectionFactory.class) 66 | .addConstructorIndexedArgumentValue(0, new RuntimeBeanReference(destinationManagerBeanName)) 67 | .addConstructorIndexedArgumentValue(1, new RuntimeBeanReference(configurationManagerBeanName)); 68 | 69 | 70 | extendedBeanDefinitionRegistry.registerBeanDefinition(destinationManagerBeanName, new RootBeanDefinition(DestinationManager.class), qualifiers); 71 | extendedBeanDefinitionRegistry.registerBeanDefinition(configurationManagerBeanName, new RootBeanDefinition(ConfigurationManager.class), qualifiers); 72 | 73 | AbstractBeanDefinition jmsMockBeanDefinition = new RootBeanDefinition(JmsMock.class); 74 | ConstructorArgumentValues jmsMockBeanDefinitionCav = new ConstructorArgumentValues(); 75 | jmsMockBeanDefinitionCav.addIndexedArgumentValue(0, new RuntimeBeanReference(meta.name())); 76 | jmsMockBeanDefinitionCav.addIndexedArgumentValue(1, new RuntimeBeanReference(destinationManagerBeanName)); 77 | jmsMockBeanDefinition.setConstructorArgumentValues(jmsMockBeanDefinitionCav); 78 | extendedBeanDefinitionRegistry.registerBeanDefinition(jmsMockBeanName, jmsMockBeanDefinition, qualifiers); 79 | }); 80 | extendedBeanDefinitionRegistry.registerBeanDefinition(JmsMockLocator.class); 81 | extendedBeanDefinitionRegistry.registerBeanDefinition(DestinationManagerResetter.class); 82 | if (Classes.isPresent("org.springframework.jms.config.AbstractJmsListenerContainerFactory")) { 83 | extendedBeanDefinitionRegistry.registerBeanDefinition(JmsListenerContainerFactoryConfigurer.class); 84 | } 85 | } else { 86 | throw new IllegalStateException("\nAutomocker is missing class [" + MOCKRUNNER_CONNECTION_FACTORY_CLASS + "] to mock " + connectionFactoryBeans.size() + " bean(s) of type [" + clazzToMock.getName() + "]: " + 87 | connectionFactoryBeans.stream().map(ExtendedBeanDefinitionRegistry.BeanDefinitionMetadata::name).collect(Collectors.joining(", ")) + 88 | "\nMake sure mockrunner-jms.jar is in the test classpath"); 89 | } 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /spring-automocker/src/test/java/com/github/fridujo/automocker/utils/BeanDefinitionsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.utils; 2 | 3 | import org.assertj.core.data.MapEntry; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.beans.factory.config.BeanDefinition; 7 | import org.springframework.beans.factory.support.AbstractBeanDefinition; 8 | import org.springframework.beans.factory.support.RootBeanDefinition; 9 | import org.springframework.context.ApplicationContext; 10 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.ComponentScan; 13 | import org.springframework.context.annotation.Configuration; 14 | 15 | import java.io.Serializable; 16 | import java.lang.annotation.ElementType; 17 | import java.lang.annotation.Retention; 18 | import java.lang.annotation.RetentionPolicy; 19 | import java.lang.annotation.Target; 20 | import java.util.Map; 21 | import java.util.stream.Stream; 22 | 23 | import static org.assertj.core.api.Assertions.assertThat; 24 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 25 | 26 | class BeanDefinitionsTest { 27 | 28 | @Test 29 | void extract_class_from_java_config_bean_definition() { 30 | ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class); 31 | 32 | BeanDefinition beanDefinition = ((AnnotationConfigApplicationContext) context).getBeanDefinition("testBean"); 33 | 34 | assertThat(BeanDefinitions.extractClass((AbstractBeanDefinition) beanDefinition)).isEqualTo(Stream.class); 35 | } 36 | 37 | @Test 38 | void extract_class_from_custom_bean_definition() { 39 | RootBeanDefinition beanDefinition = new RootBeanDefinition(); 40 | beanDefinition.setBeanClass(Stream.class); 41 | 42 | assertThat(BeanDefinitions.extractClass(beanDefinition)).isEqualTo(Stream.class); 43 | } 44 | 45 | @Test 46 | void extract_class_throws_when_beanclass_is_not_set() { 47 | RootBeanDefinition beanDefinition = new RootBeanDefinition(); 48 | 49 | assertThatExceptionOfType(IllegalStateException.class) 50 | .isThrownBy(() -> BeanDefinitions.extractClass(beanDefinition)) 51 | .withMessageContaining("Unable to resolve target class for BeanDefinition"); 52 | } 53 | 54 | @Test 55 | void extract_class_throws_when_beanclass_is_not_in_classpath() { 56 | RootBeanDefinition beanDefinition = new RootBeanDefinition(); 57 | beanDefinition.setBeanClassName("missing.Someclass"); 58 | 59 | assertThatExceptionOfType(IllegalStateException.class) 60 | .isThrownBy(() -> BeanDefinitions.extractClass(beanDefinition)) 61 | .withMessage("Cannot load class: missing.Someclass"); 62 | } 63 | 64 | @Test 65 | void extractQualifier_for_simple_qualifier() { 66 | ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class); 67 | 68 | BeanDefinition beanDefinition = ((AnnotationConfigApplicationContext) context).getBeanDefinition("test1_serializable"); 69 | 70 | Map qualifiers = BeanDefinitions.extractQualifiers(beanDefinition); 71 | 72 | assertThat(qualifiers).containsOnly(MapEntry.entry(Qualifier.class.getName(), "test1")); 73 | } 74 | 75 | @Test 76 | void extractQualifier_for_scanned_quality_qualifier() { 77 | ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class); 78 | 79 | BeanDefinition beanDefinition = ((AnnotationConfigApplicationContext) context).getBeanDefinition("test2_serializable"); 80 | 81 | Map qualifiers = BeanDefinitions.extractQualifiers(beanDefinition); 82 | 83 | assertThat(qualifiers).containsOnly(MapEntry.entry(Platform.class.getName(), Platform.OperatingSystems.IOS)); 84 | } 85 | 86 | @Test 87 | void extractQualifier_for_read_quality_qualifier() { 88 | ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class); 89 | 90 | BeanDefinition beanDefinition = ((AnnotationConfigApplicationContext) context).getBeanDefinition("test3_serializable"); 91 | 92 | Map qualifiers = BeanDefinitions.extractQualifiers(beanDefinition); 93 | 94 | assertThat(qualifiers).containsOnly(MapEntry.entry(Platform.class.getName(), Platform.OperatingSystems.ANDROID)); 95 | } 96 | 97 | @Target({ElementType.FIELD, 98 | ElementType.METHOD, 99 | ElementType.TYPE, 100 | ElementType.PARAMETER}) 101 | @Retention(RetentionPolicy.RUNTIME) 102 | @Qualifier 103 | public @interface Platform { 104 | 105 | OperatingSystems value(); 106 | 107 | enum OperatingSystems { 108 | IOS, 109 | ANDROID 110 | } 111 | } 112 | 113 | @Configuration 114 | @ComponentScan 115 | public static class TestConfiguration { 116 | 117 | @Bean 118 | Stream testBean() { 119 | return Stream.of("test"); 120 | } 121 | 122 | @Bean 123 | @Qualifier("test1") 124 | Serializable test1_serializable() { 125 | return new Serializable() { 126 | }; 127 | } 128 | 129 | @Bean 130 | @Platform(Platform.OperatingSystems.ANDROID) 131 | Serializable test3_serializable() { 132 | return new Serializable() { 133 | }; 134 | } 135 | } 136 | 137 | @Configuration 138 | public static class SecondTestConfiguration { 139 | @Bean 140 | @Platform(Platform.OperatingSystems.IOS) 141 | Serializable test2_serializable() { 142 | return new Serializable() { 143 | }; 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring-Automocker 2 | [![Build Status](https://travis-ci.org/fridujo/spring-automocker.svg?branch=master)](https://travis-ci.org/fridujo/spring-automocker) 3 | [![codecov](https://codecov.io/gh/fridujo/spring-automocker/branch/master/graph/badge.svg)](https://codecov.io/gh/fridujo/spring-automocker) 4 | [![Maven Central](https://img.shields.io/maven-central/v/com.github.fridujo/spring-automocker.svg)](https://search.maven.org/#search|ga|1|a:"spring-automocker") 5 | [![License](https://img.shields.io/github/license/fridujo/spring-automocker.svg)](https://opensource.org/licenses/Apache-2.0) 6 | 7 | Automatic detection and mocking of Spring IO components. 8 | 9 | ### Motivation 10 | 11 | Writing integration tests for Spring application is often writing the same glue code over and over again. 12 | Spring-Automocker was created to avoid re-writing the same boilerplate code and focus on test added value. 13 | 14 | ### Mocking strategies 15 | 16 | ##### Property sources 17 | The extension [`@MockPropertySources`](spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockPropertySources.java) adds a `ProtocolResolver` to Spring context resolving *properties file* as empty ones. 18 | 19 | ##### MVC controllers 20 | The extension [`@MockWebMvc`](spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockWebMvc.java) sets up a `MockMvc`. 21 | This `MockMvc` instance is either wired on : 22 | * the `org.springframework.web.context.WebApplicationContext` if the current context is of such type 23 | * the `@Controller` annotated beans otherwise 24 | 25 | ##### JDBC Data Sources 26 | The extension [`@MockJdbc`](spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockJdbc.java) 27 | * modifies `javax.sql.DataSource` beans by making them point to a dedicated H2 in-memory database. 28 | * adds a [`DataSourceResetter`](spring-automocker/src/main/java/com/github/fridujo/automocker/api/jdbc/DataSourceResetter.java) to truncate all tables after each test 29 | 30 | ##### JMS Connection Factories 31 | The extension [`@MockJms`](spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockJms.java) 32 | * replace all `javax.jms.ConnectionFactory` beans by **mockrunner-jms** `MockConnectionFactory` ones 33 | * for each `javax.jms.ConnectionFactory` beans adds a [`JmsMock`](spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/JmsMock.java) with the same qualifiers for simplified JMS operations usage 34 | * adds a [`DestinationManagerResetter`](spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/DestinationManagerResetter.java) to remove messages from all queues after each test 35 | * if available, wraps the `ErrorHandler` of `JmsListenerContainerFactory` to access errors from matching [`JmsMock`](spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/JmsMock.java) 36 | 37 | ##### Micrometer Graphite Meter Registry 38 | The extension [`@MockMicrometerGraphite`](spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockMicrometerGraphite.java) replaces the default `GraphiteReporter` by one baked by [`GraphiteMock`](spring-automocker/src/main/java/com/github/fridujo/automocker/api/metrics/GraphiteMock.java) which can be injected like any other bean. 39 | 40 | ##### RabbitMQ Connection Factories 41 | The extension [`@MockAmqp`](spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockAmqp.java) replaces all `org.springframework.amqp.rabbit.connection.ConnectionFactory` beans by **rabbitmq-mock** ones. 42 | 43 | ### Utilities 44 | The extension [`@RegisterTools`](spring-automocker/src/main/java/com/github/fridujo/automocker/base/RegisterTools.java) registers a [`BeanLocator`](spring-automocker/src/main/java/com/github/fridujo/automocker/api/tools/BeanLocator.java) to easily access beans by partial name. 45 | 46 | ## Example Use 47 | 48 | As Spring-Automocker uses **spring-test** `org.springframework.test.context.ContextCustomizerFactory` extension mechanism, it is compatible with Spring >= 4.3 (so spring-boot >= 1.4). 49 | 50 | ### Using JUnit 4 51 | 52 | Use `SpringJUnit4ClassRunner` in conjuction with `@Automocker` 53 | 54 | ```java 55 | @Automocker 56 | @RunWith(SpringJUnit4ClassRunner.class) 57 | @ContextConfiguration(classes = MyApplication.class) 58 | public class MyApplicationTest { 59 | 60 | @Autowired 61 | private MyService service; 62 | 63 | @Test 64 | public void my_test() { 65 | // test injected service 66 | } 67 | } 68 | ``` 69 | 70 | ### Using JUnit 5 71 | 72 | Use `@ExtendWith(SpringExtension.class)` in conjuction with `@Automocker` 73 | 74 | ```java 75 | @Automocker 76 | @ExtendWith(SpringExtension.class) 77 | @ContextConfiguration(classes = MyApplication.class) 78 | public class MyApplicationTest { 79 | 80 | @Autowired 81 | private MyService service; 82 | 83 | @Test 84 | public void my_test() { 85 | // test injected service 86 | } 87 | } 88 | ``` 89 | 90 | ## Getting Started 91 | 92 | ### Maven 93 | Add the following dependency to your **pom.xml** 94 | ```xml 95 | 96 | com.github.fridujo 97 | spring-automocker 98 | 1.1.0 99 | test 100 | 101 | ``` 102 | 103 | ### Gradle 104 | Add the following dependency to your **build.gradle** 105 | ```groovy 106 | repositories { 107 | mavenCentral() 108 | } 109 | 110 | // ... 111 | 112 | dependencies { 113 | // ... 114 | testCompile('com.github.fridujo:spring-automocker:1.1.0') 115 | // ... 116 | } 117 | ``` 118 | 119 | ### Building from Source 120 | 121 | You need [JDK-8](http://jdk.java.net/8/) to build Spring-Automocker. Core and samples can be built with Maven using the following command. 122 | ``` 123 | mvn clean package 124 | ``` 125 | 126 | All features can be tested through samples with Maven using the following command. 127 | ``` 128 | mvn clean test 129 | ``` 130 | 131 | Since Maven has incremental build support, you can usually omit executing the clean goal. 132 | 133 | ### Installing in the Local Maven Repository 134 | 135 | Core and samples can be installed in a local Maven Repository for usage in other projects via the following command. 136 | ``` 137 | mvn clean install 138 | ``` 139 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/api/jms/JmsMessageBuilder.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.api.jms; 2 | 3 | import com.github.fridujo.automocker.utils.Maps; 4 | import com.github.fridujo.automocker.utils.ThrowingBiConsumer; 5 | import com.github.fridujo.automocker.utils.ThrowingConsumer; 6 | 7 | import javax.jms.JMSException; 8 | import javax.jms.MapMessage; 9 | import javax.jms.Message; 10 | import javax.jms.Session; 11 | import java.io.Serializable; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.Optional; 15 | 16 | public abstract class JmsMessageBuilder { 17 | 18 | private String messageId; 19 | private Long timestamp; 20 | private String correlationId; 21 | private String replyTo; 22 | private Integer deliveryMode; 23 | private Boolean redelivered; 24 | private String type; 25 | private Long expiration; 26 | private Integer priority; 27 | 28 | private Map properties = new HashMap<>(); 29 | 30 | private JmsMessageBuilder() { 31 | } 32 | 33 | public static TextMessageBuilder newTextMessage(String text) { 34 | return new TextMessageBuilder(text); 35 | } 36 | 37 | public static ObjectMessageBuilder newObjectMessage(Serializable object) { 38 | return new ObjectMessageBuilder(object); 39 | } 40 | 41 | public static MapMessageBuilder newMapMessage(Map objects) { 42 | return new MapMessageBuilder().setObjects(objects); 43 | } 44 | 45 | public static MapMessageBuilder newMapMessage(Object... objects) { 46 | return new MapMessageBuilder().setObjects(objects); 47 | } 48 | 49 | public JmsMessageBuilder addProperty(String name, Object value) { 50 | this.properties.put(name, value); 51 | return this; 52 | } 53 | 54 | public JmsMessageBuilder addProperties(Object... properties) { 55 | Maps.build(String.class, properties) 56 | .forEach((k, v) -> this.properties.put(k, v)); 57 | return this; 58 | } 59 | 60 | public JmsMessageBuilder setJMSMessageID(String messageId) { 61 | this.messageId = messageId; 62 | return this; 63 | } 64 | 65 | public JmsMessageBuilder setJMSTimestamp(long timestamp) { 66 | this.timestamp = timestamp; 67 | return this; 68 | } 69 | 70 | public JmsMessageBuilder setJMSCorrelationID(String correlationId) { 71 | this.correlationId = correlationId; 72 | return this; 73 | } 74 | 75 | public JmsMessageBuilder setJMSReplyTo(String replyTo) { 76 | this.replyTo = replyTo; 77 | return this; 78 | } 79 | 80 | public JmsMessageBuilder setJMSDeliveryMode(int deliveryMode) { 81 | this.deliveryMode = deliveryMode; 82 | return this; 83 | } 84 | 85 | public JmsMessageBuilder setJMSRedelivered(boolean redelivered) { 86 | this.redelivered = redelivered; 87 | return this; 88 | } 89 | 90 | public JmsMessageBuilder setJMSType(String type) { 91 | this.type = type; 92 | return this; 93 | } 94 | 95 | public JmsMessageBuilder setJMSExpiration(long expiration) { 96 | this.expiration = expiration; 97 | return this; 98 | } 99 | 100 | public JmsMessageBuilder setJMSPriority(int priority) { 101 | this.priority = priority; 102 | return this; 103 | } 104 | 105 | protected abstract Message toMessageInternal(Session session) throws JMSException; 106 | 107 | public Message toMessage(Session session) throws JMSException { 108 | Message message = toMessageInternal(session); 109 | if (messageId != null) 110 | message.setJMSMessageID(messageId); 111 | if (timestamp != null) 112 | message.setJMSTimestamp(timestamp); 113 | if (correlationId != null) 114 | message.setJMSCorrelationID(correlationId); 115 | if (replyTo != null) 116 | message.setJMSReplyTo(session.createQueue(replyTo)); 117 | if (deliveryMode != null) 118 | message.setJMSDeliveryMode(deliveryMode); 119 | if (redelivered != null) 120 | message.setJMSRedelivered(redelivered); 121 | if (type != null) 122 | message.setJMSType(type); 123 | if (expiration != null) 124 | message.setJMSExpiration(expiration); 125 | if (priority != null) 126 | message.setJMSPriority(priority); 127 | 128 | properties.entrySet() 129 | .forEach(ThrowingConsumer.silent(e -> message.setObjectProperty(e.getKey(), e.getValue()))); 130 | return message; 131 | } 132 | 133 | public static final class TextMessageBuilder extends JmsMessageBuilder { 134 | private final String text; 135 | 136 | private TextMessageBuilder(String text) { 137 | this.text = text; 138 | } 139 | 140 | @Override 141 | public Message toMessageInternal(Session session) throws JMSException { 142 | return session.createTextMessage(text); 143 | } 144 | } 145 | 146 | public static final class ObjectMessageBuilder extends JmsMessageBuilder { 147 | private final Serializable object; 148 | 149 | private ObjectMessageBuilder(Serializable object) { 150 | this.object = object; 151 | } 152 | 153 | @Override 154 | public Message toMessageInternal(Session session) throws JMSException { 155 | return session.createObjectMessage(object); 156 | } 157 | } 158 | 159 | public static final class MapMessageBuilder extends JmsMessageBuilder { 160 | private final Map map = new HashMap<>(); 161 | 162 | private MapMessageBuilder() { 163 | } 164 | 165 | public MapMessageBuilder setObject(String name, Object value) { 166 | this.map.put(name, value); 167 | return this; 168 | } 169 | 170 | public MapMessageBuilder setObjects(Object... namesAndValues) { 171 | setObjects(Maps.build(String.class, namesAndValues)); 172 | return this; 173 | } 174 | 175 | public MapMessageBuilder setObjects(Map map) { 176 | Optional.ofNullable(map) 177 | .ifPresent(m -> m.forEach((k, v) -> this.map.put(k, v))); 178 | return this; 179 | } 180 | 181 | @Override 182 | public Message toMessageInternal(Session session) throws JMSException { 183 | MapMessage message = session.createMapMessage(); 184 | map.forEach(ThrowingBiConsumer.silent((k, v) -> message.setObject(k, v))); 185 | return message; 186 | } 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /spring-automocker/src/main/java/com/github/fridujo/automocker/base/MockMicrometerGraphite.java: -------------------------------------------------------------------------------- 1 | package com.github.fridujo.automocker.base; 2 | 3 | import com.codahale.metrics.MetricRegistry; 4 | import com.codahale.metrics.graphite.GraphiteReporter; 5 | import com.github.fridujo.automocker.api.AfterBeanRegistration; 6 | import com.github.fridujo.automocker.api.AfterBeanRegistrationExecutable; 7 | import com.github.fridujo.automocker.api.ExtendedBeanDefinitionRegistry; 8 | import com.github.fridujo.automocker.api.metrics.GraphiteMock; 9 | import com.github.fridujo.automocker.api.metrics.GraphiteSenderMock; 10 | import com.github.fridujo.automocker.utils.Classes; 11 | import io.micrometer.core.instrument.Clock; 12 | import io.micrometer.graphite.GraphiteConfig; 13 | import io.micrometer.graphite.GraphiteHierarchicalNameMapper; 14 | import io.micrometer.graphite.GraphiteMeterRegistry; 15 | import org.springframework.beans.factory.config.RuntimeBeanReference; 16 | import org.springframework.beans.factory.support.RootBeanDefinition; 17 | 18 | import java.lang.annotation.Documented; 19 | import java.lang.annotation.ElementType; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.RetentionPolicy; 22 | import java.lang.annotation.Target; 23 | import java.util.Set; 24 | 25 | @Target(ElementType.TYPE) 26 | @Retention(RetentionPolicy.RUNTIME) 27 | @Documented 28 | 29 | @AfterBeanRegistration(MockMicrometerGraphite.MockGraphiteExecutable.class) 30 | public @interface MockMicrometerGraphite { 31 | 32 | class MockGraphiteExecutable implements AfterBeanRegistrationExecutable { 33 | 34 | @Override 35 | public void execute(MockMicrometerGraphite annotation, ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry) { 36 | if (Classes.isPresent("io.micrometer.graphite.GraphiteMeterRegistry")) { 37 | modifyGraphiteMeterRegistryBeanDefinitions(extendedBeanDefinitionRegistry); 38 | } 39 | } 40 | 41 | private void modifyGraphiteMeterRegistryBeanDefinitions(ExtendedBeanDefinitionRegistry extendedBeanDefinitionRegistry) { 42 | Set graphiteSenderBeans = extendedBeanDefinitionRegistry 43 | .getBeanDefinitionsForClass(GraphiteMeterRegistry.class); 44 | if (!graphiteSenderBeans.isEmpty()) { 45 | String graphiteConfigBeanName = extendedBeanDefinitionRegistry.getBeanDefinitionsForClass(GraphiteConfig.class).iterator().next().name(); 46 | 47 | String graphiteReporterFactoryBeanName = extendedBeanDefinitionRegistry.registerBeanDefinition(GraphiteReporterFactory.class); 48 | String graphiteMeterRegistryFactoryBeanName = extendedBeanDefinitionRegistry.registerBeanDefinition(GraphiteMeterRegistryFactory.class); 49 | graphiteSenderBeans.forEach(meta -> { 50 | String graphiteSenderMockBeanName = meta.registerLinkedBeanDefinition(GraphiteSenderMock.class); 51 | String metricRegistryBeanName = meta.registerLinkedBeanDefinition(MetricRegistry.class); 52 | 53 | String graphiteReporterBeanName = "Automocker" + meta.name() + "GraphiteReporter"; 54 | RootBeanDefinition graphiteReporterBeanDefinition = new RootBeanDefinition(GraphiteReporter.class); 55 | graphiteReporterBeanDefinition.setFactoryBeanName(graphiteReporterFactoryBeanName); 56 | graphiteReporterBeanDefinition.setFactoryMethodName("createGraphiteReporter"); 57 | graphiteReporterBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new RuntimeBeanReference(metricRegistryBeanName)); 58 | graphiteReporterBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1, new RuntimeBeanReference(graphiteConfigBeanName)); 59 | graphiteReporterBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(2, new RuntimeBeanReference(graphiteSenderMockBeanName)); 60 | extendedBeanDefinitionRegistry.registerBeanDefinition(graphiteReporterBeanName, graphiteReporterBeanDefinition, meta.getBeanQualifiers()); 61 | 62 | String graphiteMockBeanName = "Automocker" + meta.name() + "GraphiteMock"; 63 | RootBeanDefinition graphiteMockBeanDefinition = new RootBeanDefinition(GraphiteMock.class); 64 | graphiteMockBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new RuntimeBeanReference(graphiteSenderMockBeanName)); 65 | graphiteMockBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1, new RuntimeBeanReference(graphiteReporterBeanName)); 66 | extendedBeanDefinitionRegistry.registerBeanDefinition(graphiteMockBeanName, graphiteMockBeanDefinition, meta.getBeanQualifiers()); 67 | 68 | RootBeanDefinition graphiteMeterRegistryBeanDefinition = new RootBeanDefinition(GraphiteMeterRegistry.class); 69 | graphiteMeterRegistryBeanDefinition.setFactoryBeanName(graphiteMeterRegistryFactoryBeanName); 70 | graphiteMeterRegistryBeanDefinition.setFactoryMethodName("createGraphiteMeterRegistry"); 71 | graphiteMeterRegistryBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new RuntimeBeanReference(metricRegistryBeanName)); 72 | graphiteMeterRegistryBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1, new RuntimeBeanReference(graphiteConfigBeanName)); 73 | graphiteMeterRegistryBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(2, new RuntimeBeanReference(graphiteReporterBeanName)); 74 | extendedBeanDefinitionRegistry.registerBeanDefinition(meta.name(), graphiteMeterRegistryBeanDefinition, meta.getBeanQualifiers()); 75 | }); 76 | } 77 | } 78 | } 79 | 80 | class GraphiteReporterFactory { 81 | GraphiteReporter createGraphiteReporter(MetricRegistry metricRegistry, GraphiteConfig config, GraphiteSenderMock graphiteSenderMock) { 82 | return GraphiteReporter 83 | .forRegistry(metricRegistry) 84 | .convertRatesTo(config.rateUnits()) 85 | .convertDurationsTo(config.durationUnits()) 86 | .build(graphiteSenderMock); 87 | } 88 | } 89 | 90 | class GraphiteMeterRegistryFactory { 91 | GraphiteMeterRegistry createGraphiteMeterRegistry(MetricRegistry metricRegistry, GraphiteConfig config, GraphiteReporter graphiteReporter) { 92 | return new GraphiteMeterRegistry(config, Clock.SYSTEM, new GraphiteHierarchicalNameMapper(config.tagsAsPrefix()), metricRegistry, graphiteReporter); 93 | } 94 | } 95 | } 96 | --------------------------------------------------------------------------------