Skip to content

Commit

Permalink
HSEARCH-3950 Pass backend behavior to the stub backend directly inste…
Browse files Browse the repository at this point in the history
…ad of relying on a static map

This should make the next commits simpler.
  • Loading branch information
yrodiere committed Jul 10, 2020
1 parent 5ed1c7c commit 9fe459b
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 130 deletions.
Expand Up @@ -31,7 +31,6 @@
import org.hibernate.search.util.common.impl.Closer;
import org.hibernate.search.util.impl.integrationtest.common.rule.BackendMock;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.index.StubSchemaManagementWork;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.index.impl.StubBackendFactory;
import org.hibernate.search.util.impl.integrationtest.mapper.orm.OrmUtils;
import org.hibernate.search.util.impl.integrationtest.mapper.orm.SimpleSessionFactoryBuilder;

Expand Down Expand Up @@ -120,7 +119,7 @@ private HibernateOrmIntegrationBooter createBooter(Class<?> ... entityClasses) {
registryBuilder.applySetting(
EngineSettings.BACKENDS
+ "." + backendMock.getBackendName() + "." + BackendSettings.TYPE,
StubBackendFactory.class.getName()
backendMock.factory()
);

StandardServiceRegistry serviceRegistry = registryBuilder.build();
Expand Down
Expand Up @@ -17,18 +17,19 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.hibernate.search.engine.backend.common.DocumentReference;
import org.hibernate.search.engine.backend.spi.BackendBuildContext;
import org.hibernate.search.engine.backend.work.execution.DocumentCommitStrategy;
import org.hibernate.search.engine.backend.work.execution.DocumentRefreshStrategy;
import org.hibernate.search.engine.backend.common.DocumentReference;
import org.hibernate.search.util.common.AssertionFailure;
import org.hibernate.search.util.common.logging.impl.Log;
import org.hibernate.search.util.common.logging.impl.LoggerFactory;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.StubBackendBehavior;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.document.StubDocumentNode;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.document.model.StubIndexSchemaNode;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.index.StubDocumentWork;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.index.StubIndexScaleWork;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.index.StubSchemaManagementWork;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.index.impl.StubBackendFactory;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.search.StubSearchWork;

import org.junit.rules.TestRule;
Expand All @@ -42,7 +43,10 @@ public class BackendMock implements TestRule {
private static final Log log = LoggerFactory.make( Log.class, MethodHandles.lookup() );

private final String backendName;
private final VerifyingStubBackendBehavior behaviorMock = new VerifyingStubBackendBehavior();

private final VerifyingStubBackendBehavior backendBehavior = new VerifyingStubBackendBehavior();

private boolean started = false;

public BackendMock() {
this( "stubBackend" );
Expand All @@ -61,55 +65,51 @@ public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
setup();
started = true;
try {
base.evaluate();
verifyExpectationsMet();
}
finally {
resetExpectations();
tearDown();
started = false;
}
}
};
}

public void resetExpectations() {
behaviorMock.resetExpectations();
public StubBackendFactory factory() {
return new StubBackendFactory( backendBehavior );
}

public void verifyExpectationsMet() {
behaviorMock.verifyExpectationsMet();
}

private void setup() {
StubBackendBehavior.set( backendName, behaviorMock );
public void resetExpectations() {
backendBehavior().resetExpectations();
}

private void tearDown() {
StubBackendBehavior.unset( backendName, behaviorMock );
public void verifyExpectationsMet() {
backendBehavior().verifyExpectationsMet();
}

public void inLenientMode(Runnable action) {
behaviorMock.setLenient( true );
backendBehavior().setLenient( true );
try {
action.run();
}
finally {
behaviorMock.setLenient( false );
backendBehavior().setLenient( false );
}
}

public BackendMock onCreate(Consumer<BackendBuildContext> behavior) {
behaviorMock.addCreateBackendBehavior( context -> {
backendBehavior().addCreateBackendBehavior( context -> {
behavior.accept( context );
return null;
} );
return this;
}

public BackendMock onStop(Runnable behavior) {
behaviorMock.addStopBackendBehavior( () -> {
backendBehavior().addStopBackendBehavior( () -> {
behavior.run();
return null;
} );
Expand All @@ -118,7 +118,7 @@ public BackendMock onStop(Runnable behavior) {

public BackendMock expectFailingField(String indexName, String absoluteFieldPath,
Supplier<RuntimeException> exceptionSupplier) {
behaviorMock.setIndexFieldAddBehavior( indexName, absoluteFieldPath, () -> {
backendBehavior().setIndexFieldAddBehavior( indexName, absoluteFieldPath, () -> {
throw exceptionSupplier.get();
} );
return this;
Expand All @@ -130,21 +130,21 @@ public BackendMock expectSchema(String indexName, Consumer<StubIndexSchemaNode.B

public BackendMock expectSchema(String indexName, Consumer<StubIndexSchemaNode.Builder> contributor,
Capture<StubIndexSchemaNode> capture) {
CallQueue<SchemaDefinitionCall> callQueue = behaviorMock.getSchemaDefinitionCalls( indexName );
CallQueue<SchemaDefinitionCall> callQueue = backendBehavior().getSchemaDefinitionCalls( indexName );
StubIndexSchemaNode.Builder builder = StubIndexSchemaNode.schema();
contributor.accept( builder );
callQueue.expectOutOfOrder( new SchemaDefinitionCall( indexName, builder.build(), capture ) );
return this;
}

public BackendMock expectAnySchema(String indexName) {
CallQueue<SchemaDefinitionCall> callQueue = behaviorMock.getSchemaDefinitionCalls( indexName );
CallQueue<SchemaDefinitionCall> callQueue = backendBehavior().getSchemaDefinitionCalls( indexName );
callQueue.expectOutOfOrder( new SchemaDefinitionCall( indexName, null ) );
return this;
}

public SchemaManagementWorkCallListContext expectSchemaManagementWorks(String indexName) {
CallQueue<SchemaManagementWorkCall> callQueue = behaviorMock.getSchemaManagementWorkCalls( indexName );
CallQueue<SchemaManagementWorkCall> callQueue = backendBehavior().getSchemaManagementWorkCalls( indexName );
return new SchemaManagementWorkCallListContext(
indexName,
callQueue::expectInOrder
Expand All @@ -159,7 +159,7 @@ public DocumentWorkCallListContext expectWorks(String indexName) {
public DocumentWorkCallListContext expectWorks(String indexName,
DocumentCommitStrategy commitStrategy,
DocumentRefreshStrategy refreshStrategy) {
CallQueue<DocumentWorkCall> callQueue = behaviorMock.getDocumentWorkCalls( indexName );
CallQueue<DocumentWorkCall> callQueue = backendBehavior().getDocumentWorkCalls( indexName );
return new DocumentWorkCallListContext(
indexName,
commitStrategy, refreshStrategy,
Expand All @@ -170,7 +170,7 @@ public DocumentWorkCallListContext expectWorks(String indexName,
public DocumentWorkCallListContext expectWorksAnyOrder(String indexName,
DocumentCommitStrategy commitStrategy,
DocumentRefreshStrategy refreshStrategy) {
CallQueue<DocumentWorkCall> callQueue = behaviorMock.getDocumentWorkCalls( indexName );
CallQueue<DocumentWorkCall> callQueue = backendBehavior().getDocumentWorkCalls( indexName );
return new DocumentWorkCallListContext(
indexName,
commitStrategy, refreshStrategy,
Expand All @@ -183,7 +183,7 @@ public IndexScaleWorkCallListContext expectIndexScaleWorks(String indexName) {
}

public IndexScaleWorkCallListContext expectIndexScaleWorks(String indexName, String tenantId) {
CallQueue<IndexScaleWorkCall> callQueue = behaviorMock.getIndexScaleWorkCalls();
CallQueue<IndexScaleWorkCall> callQueue = backendBehavior().getIndexScaleWorkCalls();
return new IndexScaleWorkCallListContext(
indexName, tenantId,
callQueue::expectInOrder
Expand Down Expand Up @@ -217,19 +217,29 @@ public BackendMock expectSearchProjection(Collection<String> indexNames, Consume

private BackendMock expectSearch(Collection<String> indexNames, Consumer<StubSearchWork.Builder> contributor,
StubSearchWork.ResultType resultType, StubSearchWorkBehavior<?> behavior) {
CallQueue<SearchWorkCall<?>> callQueue = behaviorMock.getSearchWorkCalls();
CallQueue<SearchWorkCall<?>> callQueue = backendBehavior().getSearchWorkCalls();
StubSearchWork.Builder builder = StubSearchWork.builder( resultType );
contributor.accept( builder );
callQueue.expectInOrder( new SearchWorkCall<>( new LinkedHashSet<>( indexNames ), builder.build(), behavior ) );
return this;
}

public BackendMock expectCount(Collection<String> indexNames, long expectedResult) {
CallQueue<CountWorkCall> callQueue = behaviorMock.getCountWorkCalls();
CallQueue<CountWorkCall> callQueue = backendBehavior().getCountWorkCalls();
callQueue.expectInOrder( new CountWorkCall( new LinkedHashSet<>( indexNames ), expectedResult ) );
return this;
}

private VerifyingStubBackendBehavior backendBehavior() {
if ( !started ) {
throw new AssertionFailure( "The backend mock was not configured as a JUnit @Rule/@ClassRule,"
+ " or its statement wrapper hasn't started executing yet,"
+ " or its statement wrapper has finished executing."
+ " Double check the @Rule/@ClassRule annotations and the execution order of rules." );
}
return backendBehavior;
}

public static class SchemaManagementWorkCallListContext {
private final String indexName;
private final Consumer<SchemaManagementWorkCall> expectationConsumer;
Expand Down
Expand Up @@ -11,7 +11,6 @@
import org.hibernate.search.engine.cfg.EngineSettings;
import org.hibernate.search.util.common.impl.CollectionHelper;
import org.hibernate.search.util.impl.integrationtest.common.TestConfigurationProvider;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.index.impl.StubBackendFactory;

class BackendMockSetupStrategy implements BackendSetupStrategy {
private final String defaultBackendName;
Expand All @@ -27,9 +26,8 @@ class BackendMockSetupStrategy implements BackendSetupStrategy {
public <C extends MappingSetupHelper<C, ?, ?>.AbstractSetupContext> C start(C setupContext,
TestConfigurationProvider configurationProvider) {
for ( BackendMock backendMock : backendMocks ) {
setupContext = setupContext.withBackendProperty(
backendMock.getBackendName(), "type", StubBackendFactory.class.getName()
);
setupContext = setupContext.withBackendProperty( backendMock.getBackendName(),
"type", backendMock.factory() );
}
return setupContext.withProperty( EngineSettings.DEFAULT_BACKEND, defaultBackendName );
}
Expand Down
Expand Up @@ -6,8 +6,6 @@
*/
package org.hibernate.search.util.impl.integrationtest.common.stub.backend;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

Expand All @@ -25,95 +23,6 @@

public abstract class StubBackendBehavior {

private static final StubBackendBehavior DEFAULT = new StubBackendBehavior() {
@Override
public void onCreateBackend(BackendBuildContext context) {
throw new IllegalStateException( "The stub backend behavior was not set when creating a backend." );
}

@Override
public void onStopBackend() {
// This is acceptable: we probably just ended the test before the backend was stopped.
}

@Override
public void onAddField(String indexName, String absoluteFieldPath) {
throw new IllegalStateException( "The stub backend behavior was not set when a field was added to index '"
+ indexName + "': " + absoluteFieldPath );
}

@Override
public void defineSchema(String indexName, StubIndexSchemaNode rootSchemaNode) {
throw new IllegalStateException( "The stub backend behavior was not set when a schema was pushed for index '"
+ indexName + "': " + rootSchemaNode );
}

@Override
public CompletableFuture<?> executeSchemaManagementWork(String indexName, StubSchemaManagementWork work,
ContextualFailureCollector failureCollector) {
throw new IllegalStateException( "The stub backend behavior was not set during execution of a schema management work for index "
+ indexName + ": " + work );
}

@Override
public void processDocumentWork(String indexName, StubDocumentWork work) {
throw new IllegalStateException( "The stub backend behavior was not set when a work was prepared for index '"
+ indexName + "': " + work );
}

@Override
public void discardDocumentWork(String indexName, StubDocumentWork work) {
throw new IllegalStateException( "The stub backend behavior was not set when a work was discarded from index '"
+ indexName + "': " + work );
}

@Override
public CompletableFuture<?> executeDocumentWork(String indexName, StubDocumentWork work) {
throw new IllegalStateException( "The stub backend behavior was not set when a work was executed for index '"
+ indexName + "': " + work );
}

@Override
public CompletableFuture<?> processAndExecuteDocumentWork(String indexName, StubDocumentWork work) {
throw new IllegalStateException( "The stub backend behavior was not set when work were prepared and executed for index '"
+ indexName + "': " + work );
}

@Override
public <T> SearchResult<T> executeSearchWork(Set<String> indexNames, StubSearchWork work,
StubSearchProjectionContext projectionContext,
LoadingContext<?, ?> loadingContext, StubSearchProjection<T> rootProjection) {
throw new IllegalStateException( "The stub backend behavior was not set when a search work was executed for indexes "
+ indexNames + ": " + work );
}

@Override
public CompletableFuture<?> executeIndexScaleWork(String indexName, StubIndexScaleWork work) {
throw new IllegalStateException( "The stub backend behavior was not set during execution of an index-scale work for index "
+ indexName + ": " + work );
}

@Override
public long executeCountWork(Set<String> indexNames) {
throw new IllegalStateException( "The stub backend behavior was not set when a count work was executed for indexes "
+ indexNames );
}
};

private static final Map<String, StubBackendBehavior> BEHAVIORS = new HashMap<>();

public static void set(String backendName, StubBackendBehavior behavior) {
BEHAVIORS.put( backendName, behavior );
}

public static void unset(String backendName, StubBackendBehavior behavior) {
BEHAVIORS.remove( backendName, behavior );
}

public static StubBackendBehavior get(String backendName) {
return BEHAVIORS.getOrDefault( backendName, DEFAULT );
}

protected StubBackendBehavior() {
}

Expand Down
Expand Up @@ -20,10 +20,12 @@
public class StubBackend implements BackendImplementor, Backend {

private final String name;
private final StubBackendBehavior behavior;

StubBackend(String name, BackendBuildContext context) {
StubBackend(String name, BackendBuildContext context, StubBackendBehavior behavior) {
this.name = name;
getBehavior().onCreateBackend( context );
this.behavior = behavior;
behavior.onCreateBackend( context );
}

@Override
Expand All @@ -48,7 +50,7 @@ public CompletableFuture<?> preStop() {

@Override
public void stop() {
getBehavior().onStopBackend();
behavior.onStopBackend();
}

@Override
Expand All @@ -62,7 +64,7 @@ public Backend toAPI() {
}

public StubBackendBehavior getBehavior() {
return StubBackendBehavior.get( name );
return behavior;
}

@Override
Expand Down
Expand Up @@ -10,10 +10,18 @@
import org.hibernate.search.engine.backend.spi.BackendFactory;
import org.hibernate.search.engine.cfg.spi.ConfigurationPropertySource;
import org.hibernate.search.engine.backend.spi.BackendBuildContext;
import org.hibernate.search.util.impl.integrationtest.common.stub.backend.StubBackendBehavior;

public class StubBackendFactory implements BackendFactory {

private final StubBackendBehavior behavior;

public StubBackendFactory(StubBackendBehavior behavior) {
this.behavior = behavior;
}

@Override
public BackendImplementor create(String name, BackendBuildContext context, ConfigurationPropertySource propertySource) {
return new StubBackend( name, context );
return new StubBackend( name, context, behavior );
}
}

0 comments on commit 9fe459b

Please sign in to comment.