From 81f84d252f4659bba18bac35187722539d0c4414 Mon Sep 17 00:00:00 2001 From: "roman.ivanitsky" Date: Thu, 4 Oct 2018 13:06:05 +0300 Subject: [PATCH 1/5] add cache for module injectors --- .../testing/junit/guice/GuiceExtension.java | 19 +++++++++++---- .../junit/guice/GuiceExtensionTest.java | 24 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java index 37afb6b..3c92515 100644 --- a/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java +++ b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java @@ -25,6 +25,8 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.stream.Stream; import javax.inject.Qualifier; import org.junit.jupiter.api.extension.ExtensionContext; @@ -39,6 +41,8 @@ public final class GuiceExtension implements TestInstancePostProcessor, Paramete private static final Namespace NAMESPACE = Namespace.create("name", "falgout", "jeffrey", "testing", "junit", "guice"); + private static final ConcurrentMap>, Injector> INJECTOR_CACHE = new ConcurrentHashMap<>(); + public GuiceExtension() {} @Override @@ -79,10 +83,17 @@ private static Injector createInjector(ExtensionContext context) InvocationTargetException { Optional parentInjector = getParentInjector(context); List modules = getNewModules(context); - - return parentInjector - .map(injector -> injector.createChildInjector(modules)) - .orElseGet(() -> Guice.createInjector(modules)); + Set> modulClass = modules.stream().map(Object::getClass).collect(toSet()); + if (!modulClass.isEmpty() && INJECTOR_CACHE.containsKey(modulClass)) { + return INJECTOR_CACHE.get(modulClass); + } + Injector createdInjector = parentInjector + .map(injector -> injector.createChildInjector(modules)) + .orElseGet(() -> Guice.createInjector(modules)); + if (!modulClass.isEmpty()) { + INJECTOR_CACHE.put(modulClass, createdInjector); + } + return createdInjector; } private static Optional getParentInjector(ExtensionContext context) diff --git a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java index 094c976..cd49bd3 100644 --- a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java +++ b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java @@ -2,12 +2,14 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.google.inject.Key; import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicLong; import javax.inject.Inject; import name.falgout.jeffrey.testing.junit.guice.GuiceExtensionTest.TestModule; import name.falgout.jeffrey.testing.junit.testing.ExpectFailure; @@ -168,6 +170,20 @@ void doesNotHaveInjectConstructor(NotInjectable.Arg arg) {} void cannotBeInjected(NotInjectable notInjectable) {} } + @Nested + @IncludeModule(CachedModule.class) + class CachedInjector { + + @Test + void firstTest(long i) { + assertEquals(CachedModule.ATOMIC_LONG.get(), i); + } + @Test + void secondTest(long i) { + assertEquals(CachedModule.ATOMIC_LONG.get(), i); + } + } + static final class FooBarExtension implements ParameterResolver { @Override public boolean supportsParameter(ParameterContext parameterContext, @@ -250,4 +266,12 @@ private static class Arg { private Arg(String s) {} } } + + static final class CachedModule extends AbstractModule { + static final AtomicLong ATOMIC_LONG = new AtomicLong(0); + @Override + protected void configure() { + bind(long.class).toInstance(ATOMIC_LONG.incrementAndGet()); + } + } } From f1aa2ed60f907e0c1398ab2f969ec92f72e9977a Mon Sep 17 00:00:00 2001 From: "roman.ivanitsky" Date: Thu, 4 Oct 2018 13:15:22 +0300 Subject: [PATCH 2/5] provider better test --- .../junit/guice/GuiceExtensionTest.java | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java index cd49bd3..5f6f2d5 100644 --- a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java +++ b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java @@ -170,19 +170,33 @@ void doesNotHaveInjectConstructor(NotInjectable.Arg arg) {} void cannotBeInjected(NotInjectable notInjectable) {} } - @Nested - @IncludeModule(CachedModule.class) - class CachedInjector { - - @Test - void firstTest(long i) { - assertEquals(CachedModule.ATOMIC_LONG.get(), i); + @Nested + @IncludeModule(CachedModule.class) + class FirstCachedInjectorTest { + + @Test + void firstTest(long i) { + assertEquals(1, i); + } + @Test + void secondTest(long i) { + assertEquals(1, i); + } } - @Test - void secondTest(long i) { - assertEquals(CachedModule.ATOMIC_LONG.get(), i); + + @Nested + @IncludeModule(CachedModule.class) + class SecondCachedInjectorTest { + + @Test + void firstTest(long i) { + assertEquals(1, i); + } + @Test + void secondTest(long i) { + assertEquals(1, i); + } } - } static final class FooBarExtension implements ParameterResolver { @Override From 4922ca32c0a3ed58f01cdb702809d44dad203c67 Mon Sep 17 00:00:00 2001 From: "roman.ivanitsky" Date: Fri, 5 Oct 2018 20:02:04 +0300 Subject: [PATCH 3/5] provide SharedInjectors annotation --- .../testing/junit/guice/GuiceExtension.java | 42 +++++++++++++++---- .../testing/junit/guice/SharedInjectors.java | 20 +++++++++ .../junit/guice/GuiceExtensionTest.java | 37 ++++++++++++++++ 3 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectors.java diff --git a/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java index 3c92515..598f1df 100644 --- a/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java +++ b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java @@ -2,6 +2,7 @@ import static java.util.stream.Collectors.toSet; import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; +import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; import com.google.common.collect.Iterables; import com.google.common.reflect.TypeToken; @@ -83,17 +84,44 @@ private static Injector createInjector(ExtensionContext context) InvocationTargetException { Optional parentInjector = getParentInjector(context); List modules = getNewModules(context); - Set> modulClass = modules.stream().map(Object::getClass).collect(toSet()); - if (!modulClass.isEmpty() && INJECTOR_CACHE.containsKey(modulClass)) { - return INJECTOR_CACHE.get(modulClass); + if (isSharedInjector(context)) { + return createCachedInjector(modules, parentInjector); } - Injector createdInjector = parentInjector + return parentInjector .map(injector -> injector.createChildInjector(modules)) .orElseGet(() -> Guice.createInjector(modules)); - if (!modulClass.isEmpty()) { - INJECTOR_CACHE.put(modulClass, createdInjector); + } + + private static Injector createCachedInjector(List modules, + Optional parentInjector) { + Set> modulClass = modules.stream().map(Object::getClass).collect(toSet()); + Optional cachedInjector = getCachedInjector(modulClass); + if (cachedInjector.isPresent()) { + return cachedInjector.get(); + } else { + Injector createdInjector = parentInjector + .map(injector -> injector.createChildInjector(modules)) + .orElseGet(() -> Guice.createInjector(modules)); + if (!modulClass.isEmpty()) { + INJECTOR_CACHE.put(modulClass, createdInjector); + } + return createdInjector; } - return createdInjector; + } + + private static boolean isSharedInjector(ExtensionContext context) { + if (!context.getElement().isPresent()) { + return false; + } + AnnotatedElement element = context.getElement().get(); + return findAnnotation(element, SharedInjectors.class).isPresent(); + } + + private static Optional getCachedInjector(Set> modulClasses) { + if (!modulClasses.isEmpty() && INJECTOR_CACHE.containsKey(modulClasses)) { + return Optional.of(INJECTOR_CACHE.get(modulClasses)); + } + return Optional.empty(); } private static Optional getParentInjector(ExtensionContext context) diff --git a/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectors.java b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectors.java new file mode 100644 index 0000000..823fa33 --- /dev/null +++ b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectors.java @@ -0,0 +1,20 @@ +package name.falgout.jeffrey.testing.junit.guice; + +import org.junit.jupiter.api.extension.ExtendWith; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Retention(RUNTIME) +@Target({TYPE, METHOD}) +@Inherited +@ExtendWith(GuiceExtension.class) +public @interface SharedInjectors { +} diff --git a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java index 5f6f2d5..013717b 100644 --- a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java +++ b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java @@ -9,6 +9,7 @@ import com.google.inject.Injector; import com.google.inject.Key; import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import javax.inject.Inject; import name.falgout.jeffrey.testing.junit.guice.GuiceExtensionTest.TestModule; @@ -172,6 +173,7 @@ void cannotBeInjected(NotInjectable notInjectable) {} @Nested @IncludeModule(CachedModule.class) + @SharedInjectors class FirstCachedInjectorTest { @Test @@ -186,6 +188,7 @@ void secondTest(long i) { @Nested @IncludeModule(CachedModule.class) + @SharedInjectors class SecondCachedInjectorTest { @Test @@ -198,6 +201,28 @@ void secondTest(long i) { } } + @Nested + @IncludeModule(NonCachedModule.class) + class FirstNonCachedInjectorTest { + @Test + void test(long i) { + long expectedValue = NonCachedModule.SECOND_EXECUTED.get() ? 2 : 1; + assertEquals(expectedValue, i); + NonCachedModule.FIRST_EXECUTED.set(true); + } + } + + @Nested + @IncludeModule(NonCachedModule.class) + class SecondNonCachedInjectorTest { + @Test + void test(long i) { + long expectedValue = NonCachedModule.FIRST_EXECUTED.get() ? 2 : 1; + assertEquals(expectedValue, i); + NonCachedModule.SECOND_EXECUTED.set(true); + } + } + static final class FooBarExtension implements ParameterResolver { @Override public boolean supportsParameter(ParameterContext parameterContext, @@ -288,4 +313,16 @@ protected void configure() { bind(long.class).toInstance(ATOMIC_LONG.incrementAndGet()); } } + + static final class NonCachedModule extends AbstractModule { + static final AtomicLong ATOMIC_LONG = new AtomicLong(0); + //depend on which test executed first + static final AtomicBoolean FIRST_EXECUTED = new AtomicBoolean(false); + static final AtomicBoolean SECOND_EXECUTED = new AtomicBoolean(false); + + @Override + protected void configure() { + bind(long.class).toInstance(ATOMIC_LONG.incrementAndGet()); + } + } } From 3dd0e4ec064d053bfa89fae62e86021376c869b4 Mon Sep 17 00:00:00 2001 From: "roman.ivanitsky" Date: Wed, 10 Oct 2018 15:40:25 +0300 Subject: [PATCH 4/5] use not only new module classes as a key for cache --- .../testing/junit/guice/GuiceExtension.java | 35 ++- .../junit/guice/GuiceExtensionTest.java | 75 ------- .../junit/guice/SharedInjectorsTest.java | 209 ++++++++++++++++++ 3 files changed, 222 insertions(+), 97 deletions(-) create mode 100644 guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectorsTest.java diff --git a/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java index 598f1df..556e734 100644 --- a/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java +++ b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java @@ -2,7 +2,7 @@ import static java.util.stream.Collectors.toSet; import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; +import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated; import com.google.common.collect.Iterables; import com.google.common.reflect.TypeToken; @@ -84,8 +84,9 @@ private static Injector createInjector(ExtensionContext context) InvocationTargetException { Optional parentInjector = getParentInjector(context); List modules = getNewModules(context); + Set> moduleClasses = getContextModuleTypes(context); if (isSharedInjector(context)) { - return createCachedInjector(modules, parentInjector); + return createCachedInjector(modules, parentInjector, moduleClasses); } return parentInjector .map(injector -> injector.createChildInjector(modules)) @@ -93,20 +94,17 @@ private static Injector createInjector(ExtensionContext context) } private static Injector createCachedInjector(List modules, - Optional parentInjector) { - Set> modulClass = modules.stream().map(Object::getClass).collect(toSet()); - Optional cachedInjector = getCachedInjector(modulClass); - if (cachedInjector.isPresent()) { - return cachedInjector.get(); - } else { - Injector createdInjector = parentInjector + Optional parentInjector, Set> moduleClasses) { + return INJECTOR_CACHE.computeIfAbsent(moduleClasses, classes -> { + if (classes.isEmpty()) { + //no value for empty moduleClasses + return null; + } + return parentInjector .map(injector -> injector.createChildInjector(modules)) .orElseGet(() -> Guice.createInjector(modules)); - if (!modulClass.isEmpty()) { - INJECTOR_CACHE.put(modulClass, createdInjector); - } - return createdInjector; - } + } + ); } private static boolean isSharedInjector(ExtensionContext context) { @@ -114,14 +112,7 @@ private static boolean isSharedInjector(ExtensionContext context) { return false; } AnnotatedElement element = context.getElement().get(); - return findAnnotation(element, SharedInjectors.class).isPresent(); - } - - private static Optional getCachedInjector(Set> modulClasses) { - if (!modulClasses.isEmpty() && INJECTOR_CACHE.containsKey(modulClasses)) { - return Optional.of(INJECTOR_CACHE.get(modulClasses)); - } - return Optional.empty(); + return isAnnotated(element, SharedInjectors.class); } private static Optional getParentInjector(ExtensionContext context) diff --git a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java index 013717b..094c976 100644 --- a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java +++ b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtensionTest.java @@ -2,15 +2,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.google.inject.Key; import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; import javax.inject.Inject; import name.falgout.jeffrey.testing.junit.guice.GuiceExtensionTest.TestModule; import name.falgout.jeffrey.testing.junit.testing.ExpectFailure; @@ -171,58 +168,6 @@ void doesNotHaveInjectConstructor(NotInjectable.Arg arg) {} void cannotBeInjected(NotInjectable notInjectable) {} } - @Nested - @IncludeModule(CachedModule.class) - @SharedInjectors - class FirstCachedInjectorTest { - - @Test - void firstTest(long i) { - assertEquals(1, i); - } - @Test - void secondTest(long i) { - assertEquals(1, i); - } - } - - @Nested - @IncludeModule(CachedModule.class) - @SharedInjectors - class SecondCachedInjectorTest { - - @Test - void firstTest(long i) { - assertEquals(1, i); - } - @Test - void secondTest(long i) { - assertEquals(1, i); - } - } - - @Nested - @IncludeModule(NonCachedModule.class) - class FirstNonCachedInjectorTest { - @Test - void test(long i) { - long expectedValue = NonCachedModule.SECOND_EXECUTED.get() ? 2 : 1; - assertEquals(expectedValue, i); - NonCachedModule.FIRST_EXECUTED.set(true); - } - } - - @Nested - @IncludeModule(NonCachedModule.class) - class SecondNonCachedInjectorTest { - @Test - void test(long i) { - long expectedValue = NonCachedModule.FIRST_EXECUTED.get() ? 2 : 1; - assertEquals(expectedValue, i); - NonCachedModule.SECOND_EXECUTED.set(true); - } - } - static final class FooBarExtension implements ParameterResolver { @Override public boolean supportsParameter(ParameterContext parameterContext, @@ -305,24 +250,4 @@ private static class Arg { private Arg(String s) {} } } - - static final class CachedModule extends AbstractModule { - static final AtomicLong ATOMIC_LONG = new AtomicLong(0); - @Override - protected void configure() { - bind(long.class).toInstance(ATOMIC_LONG.incrementAndGet()); - } - } - - static final class NonCachedModule extends AbstractModule { - static final AtomicLong ATOMIC_LONG = new AtomicLong(0); - //depend on which test executed first - static final AtomicBoolean FIRST_EXECUTED = new AtomicBoolean(false); - static final AtomicBoolean SECOND_EXECUTED = new AtomicBoolean(false); - - @Override - protected void configure() { - bind(long.class).toInstance(ATOMIC_LONG.incrementAndGet()); - } - } } diff --git a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectorsTest.java b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectorsTest.java new file mode 100644 index 0000000..6ccf0eb --- /dev/null +++ b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectorsTest.java @@ -0,0 +1,209 @@ +package name.falgout.jeffrey.testing.junit.guice; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import com.google.inject.AbstractModule; +import com.google.inject.name.Names; +import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import javax.inject.Named; +import name.falgout.jeffrey.testing.junit.guice.SharedInjectorsTest.OuterClassModule; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(GuiceExtension.class) +@IncludeModule(OuterClassModule.class) +@SharedInjectors +class SharedInjectorsTest { + + private static final Random RANDOM = new Random(); + + private static String getRandomString() { + return String.valueOf(RANDOM.nextInt(Integer.MAX_VALUE)); + } + + @Test + @IncludeModule(TestCaseModule.class) + @SharedInjectors + void test1(@Named("base") String base, @Named("test") String test) { + assertNotNull(base); + assertNotNull(test); + } + + @Test + @SharedInjectors + @IncludeModule(OuterSharedClassModule.class) + void testCase2(int value) { + assertEquals(1, value); + } + + + @IncludeModule(InnerClassModule.class) + @Nested + class InnerClass { + + @SharedInjectors + @IncludeModule(TestCaseModule.class) + @Test + void test1(@Named("base") String base, + @Named("inner") String inner, + @Named("test") String test) { + assertNotNull(base); + assertNotNull(test); + assertNotNull(inner); + } + } + + @Nested + @IncludeModule(CachedModule.class) + @SharedInjectors + class FirstCachedInjectorTest { + + @Test + void firstTest(long i) { + assertEquals(1, i); + } + + @Test + void secondTest(long i) { + assertEquals(1, i); + } + } + + @Nested + @IncludeModule(CachedModule.class) + @SharedInjectors + class SecondCachedInjectorTest { + + @Test + void firstTest(long i) { + assertEquals(1, i); + } + + @Test + void secondTest(long i) { + assertEquals(1, i); + } + } + + @Nested + @IncludeModule(NonCachedModule.class) + class FirstNonCachedInjectorTest { + + @Test + void test(long i) { + long expectedValue = NonCachedModule.SECOND_EXECUTED.get() ? 2 : 1; + assertEquals(expectedValue, i); + NonCachedModule.FIRST_EXECUTED.set(true); + } + } + + @Nested + @IncludeModule(NonCachedModule.class) + class SecondNonCachedInjectorTest { + + @Test + void test(long i) { + long expectedValue = NonCachedModule.FIRST_EXECUTED.get() ? 2 : 1; + assertEquals(expectedValue, i); + NonCachedModule.SECOND_EXECUTED.set(true); + } + } + + @IncludeModule(OuterSharedClassModule.class) + @SharedInjectors + @Nested + class OuterSharedClass { + + @IncludeModule(ExtraModule.class) + @Test + void testCase1(int value, @Named("extra") int extra) { + assertEquals(1, value); + assertEquals(ExtraModule.EXTRA2_EXECUTED.get() ? 2 : 1, extra); + ExtraModule.EXTRA1_EXECUTED.set(true); + } + + @Test + @IncludeModule(ExtraModule.class) + void testCase2(int value, @Named("extra") int extra) { + assertEquals(1, value); + assertEquals(ExtraModule.EXTRA1_EXECUTED.get() ? 2 : 1, extra); + ExtraModule.EXTRA2_EXECUTED.set(true); + } + } + + static class OuterSharedClassModule extends AbstractModule { + + private final static AtomicInteger ATOMIC_INTEGER = new AtomicInteger(0); + + @Override + protected void configure() { + int value = ATOMIC_INTEGER.incrementAndGet(); + bind(int.class).toInstance(value); + assertEquals(1, value); + } + } + + static class ExtraModule extends AbstractModule { + + static final AtomicBoolean EXTRA1_EXECUTED = new AtomicBoolean(false); + static final AtomicBoolean EXTRA2_EXECUTED = new AtomicBoolean(false); + static final AtomicInteger INTEGER = new AtomicInteger(0); + + @Override + protected void configure() { + bind(int.class).annotatedWith(Names.named("extra")).toInstance(INTEGER.incrementAndGet()); + } + } + + static class OuterClassModule extends AbstractModule { + + @Override + protected void configure() { + bind(String.class).annotatedWith(Names.named("base")).toInstance(getRandomString()); + } + } + + static class InnerClassModule extends AbstractModule { + + @Override + protected void configure() { + bind(String.class).annotatedWith(Names.named("inner")).toInstance(getRandomString()); + } + } + + static class TestCaseModule extends AbstractModule { + + @Override + protected void configure() { + bind(String.class).annotatedWith(Names.named("test")).toInstance(getRandomString()); + } + } + + static final class CachedModule extends AbstractModule { + + static final AtomicLong ATOMIC_LONG = new AtomicLong(0); + + @Override + protected void configure() { + bind(long.class).toInstance(ATOMIC_LONG.incrementAndGet()); + } + } + + static final class NonCachedModule extends AbstractModule { + + static final AtomicLong ATOMIC_LONG = new AtomicLong(0); + //depend on which test executed first + static final AtomicBoolean FIRST_EXECUTED = new AtomicBoolean(false); + static final AtomicBoolean SECOND_EXECUTED = new AtomicBoolean(false); + + @Override + protected void configure() { + bind(long.class).toInstance(ATOMIC_LONG.incrementAndGet()); + } + } +} From 1d55037b62b1fa24a18b032004a1f2b5a8d6ce1a Mon Sep 17 00:00:00 2001 From: "roman.ivanitsky" Date: Mon, 15 Oct 2018 14:56:43 +0300 Subject: [PATCH 5/5] move cached logic to getOrCreateInjector --- .../testing/junit/guice/GuiceExtension.java | 34 ++++++------------- .../junit/guice/SharedInjectorsTest.java | 24 +++++-------- 2 files changed, 19 insertions(+), 39 deletions(-) diff --git a/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java index 556e734..a6c0f1f 100644 --- a/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java +++ b/guice-extension/src/main/java/name/falgout/jeffrey/testing/junit/guice/GuiceExtension.java @@ -64,16 +64,22 @@ private static Optional getOrCreateInjector(ExtensionContext context) if (!context.getElement().isPresent()) { return Optional.empty(); } - AnnotatedElement element = context.getElement().get(); Store store = context.getStore(NAMESPACE); - Injector injector = store.get(element, Injector.class); + boolean sharedInjector = isSharedInjector(context); + Set> moduleClasses = Collections.emptySet(); + if (injector == null && sharedInjector) { + moduleClasses = getContextModuleTypes(context); + injector = INJECTOR_CACHE.get(moduleClasses); + } if (injector == null) { injector = createInjector(context); store.put(element, injector); + if (sharedInjector && !moduleClasses.isEmpty()) { + INJECTOR_CACHE.put(moduleClasses, injector); + } } - return Optional.of(injector); } @@ -84,27 +90,9 @@ private static Injector createInjector(ExtensionContext context) InvocationTargetException { Optional parentInjector = getParentInjector(context); List modules = getNewModules(context); - Set> moduleClasses = getContextModuleTypes(context); - if (isSharedInjector(context)) { - return createCachedInjector(modules, parentInjector, moduleClasses); - } return parentInjector - .map(injector -> injector.createChildInjector(modules)) - .orElseGet(() -> Guice.createInjector(modules)); - } - - private static Injector createCachedInjector(List modules, - Optional parentInjector, Set> moduleClasses) { - return INJECTOR_CACHE.computeIfAbsent(moduleClasses, classes -> { - if (classes.isEmpty()) { - //no value for empty moduleClasses - return null; - } - return parentInjector - .map(injector -> injector.createChildInjector(modules)) - .orElseGet(() -> Guice.createInjector(modules)); - } - ); + .map(injector -> injector.createChildInjector(modules)) + .orElseGet(() -> Guice.createInjector(modules)); } private static boolean isSharedInjector(ExtensionContext context) { diff --git a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectorsTest.java b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectorsTest.java index 6ccf0eb..e5dfc40 100644 --- a/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectorsTest.java +++ b/guice-extension/src/test/java/name/falgout/jeffrey/testing/junit/guice/SharedInjectorsTest.java @@ -1,11 +1,9 @@ package name.falgout.jeffrey.testing.junit.guice; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import com.google.inject.AbstractModule; import com.google.inject.name.Names; -import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -20,18 +18,12 @@ @SharedInjectors class SharedInjectorsTest { - private static final Random RANDOM = new Random(); - - private static String getRandomString() { - return String.valueOf(RANDOM.nextInt(Integer.MAX_VALUE)); - } - @Test @IncludeModule(TestCaseModule.class) @SharedInjectors void test1(@Named("base") String base, @Named("test") String test) { - assertNotNull(base); - assertNotNull(test); + assertEquals("base", base); + assertEquals("test", test); } @Test @@ -52,9 +44,9 @@ class InnerClass { void test1(@Named("base") String base, @Named("inner") String inner, @Named("test") String test) { - assertNotNull(base); - assertNotNull(test); - assertNotNull(inner); + assertEquals("base", base); + assertEquals("test", test); + assertEquals("inner", inner); } } @@ -164,7 +156,7 @@ static class OuterClassModule extends AbstractModule { @Override protected void configure() { - bind(String.class).annotatedWith(Names.named("base")).toInstance(getRandomString()); + bind(String.class).annotatedWith(Names.named("base")).toInstance("base"); } } @@ -172,7 +164,7 @@ static class InnerClassModule extends AbstractModule { @Override protected void configure() { - bind(String.class).annotatedWith(Names.named("inner")).toInstance(getRandomString()); + bind(String.class).annotatedWith(Names.named("inner")).toInstance("inner"); } } @@ -180,7 +172,7 @@ static class TestCaseModule extends AbstractModule { @Override protected void configure() { - bind(String.class).annotatedWith(Names.named("test")).toInstance(getRandomString()); + bind(String.class).annotatedWith(Names.named("test")).toInstance("test"); } }