fixed injection of HgContext, if no request scope is available

This commit is contained in:
Sebastian Sdorra
2019-02-18 12:01:34 +01:00
parent 080a0d55fd
commit 173e51096b
2 changed files with 131 additions and 21 deletions

View File

@@ -35,12 +35,16 @@ package sonia.scm.repository;
//~--- non-JDK imports -------------------------------------------------------- //~--- non-JDK imports --------------------------------------------------------
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.inject.Inject;
/** /**
* Injection provider for {@link HgContext}. * Injection provider for {@link HgContext}.
* This provider returns an instance {@link HgContext} from request scope, if no {@link HgContext} could be found in * This provider returns an instance {@link HgContext} from request scope, if no {@link HgContext} could be found in
@@ -52,31 +56,50 @@ public class HgContextProvider implements Provider<HgContext>
{ {
/** /**
* the logger for HgContextProvider * the LOG for HgContextProvider
*/ */
private static final Logger logger = private static final Logger LOG =
LoggerFactory.getLogger(HgContextProvider.class); LoggerFactory.getLogger(HgContextProvider.class);
//~--- get methods ---------------------------------------------------------- //~--- get methods ----------------------------------------------------------
/** private Provider<HgContextRequestStore> requestStoreProvider;
* Method description
* @Inject
* public HgContextProvider(Provider<HgContextRequestStore> requestStoreProvider) {
* @return this.requestStoreProvider = requestStoreProvider;
*/
@Override
public HgContext get() {
if (contextRequestStore == null) {
logger.trace("context is null, we are probably out of request scope");
return new HgContext();
}
logger.trace("return HgContext from request store");
return contextRequestStore.get();
} }
//~--- fields --------------------------------------------------------------- @VisibleForTesting
public HgContextProvider() {
}
@Inject(optional = true) @Override
private HgContextRequestStore contextRequestStore; public HgContext get() {
HgContext context = fetchContextFromRequest();
if (context != null) {
LOG.trace("return HgContext from request store");
return context;
}
LOG.trace("could not find context in request scope, returning new instance");
return new HgContext();
}
private HgContext fetchContextFromRequest() {
try {
if (requestStoreProvider != null) {
return requestStoreProvider.get().get();
} else {
LOG.trace("no request store provider defined, could not return context from request");
return null;
}
} catch (ProvisionException ex) {
if (ex.getCause() instanceof OutOfScopeException) {
LOG.trace("we are currently out of request scope, failed to retrieve context");
return null;
} else {
throw ex;
}
}
}
} }

View File

@@ -0,0 +1,87 @@
package sonia.scm.repository;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.Scope;
import com.google.inject.servlet.RequestScoped;
import com.google.inject.util.Providers;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class HgContextProviderTest {
@Mock
private Scope scope;
@Test
void shouldThrowNonOutOfScopeProvisionExceptions() {
Provider<HgContextRequestStore> provider = () -> {
throw new RuntimeException("something different");
};
when(scope.scope(any(Key.class), any(Provider.class))).thenReturn(provider);
Injector injector = Guice.createInjector(new HgContextModule(scope));
assertThrows(ProvisionException.class, () -> injector.getInstance(HgContext.class));
}
@Test
void shouldCreateANewInstanceIfOutOfRequestScope() {
Provider<HgContextRequestStore> provider = () -> {
throw new OutOfScopeException("no request");
};
when(scope.scope(any(Key.class), any(Provider.class))).thenReturn(provider);
Injector injector = Guice.createInjector(new HgContextModule(scope));
HgContext contextOne = injector.getInstance(HgContext.class);
HgContext contextTwo = injector.getInstance(HgContext.class);
assertThat(contextOne).isNotSameAs(contextTwo);
}
@Test
void shouldInjectFromRequestScope() {
HgContextRequestStore requestStore = new HgContextRequestStore();
Provider<HgContextRequestStore> provider = Providers.of(requestStore);
when(scope.scope(any(Key.class), any(Provider.class))).thenReturn(provider);
Injector injector = Guice.createInjector(new HgContextModule(scope));
HgContext contextOne = injector.getInstance(HgContext.class);
HgContext contextTwo = injector.getInstance(HgContext.class);
assertThat(contextOne).isSameAs(contextTwo);
}
private static class HgContextModule extends AbstractModule {
private Scope scope;
private HgContextModule(Scope scope) {
this.scope = scope;
}
@Override
protected void configure() {
bindScope(RequestScoped.class, scope);
bind(HgContextRequestStore.class);
bind(HgContext.class).toProvider(HgContextProvider.class);
}
}
}