/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.test.searchfactory;
import static java.lang.annotation.ElementType.FIELD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Set;
import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.cfg.SearchMapping;
import org.hibernate.search.exception.SearchException;
import org.hibernate.search.metadata.IndexedTypeDescriptor;
import org.hibernate.search.spi.SearchIntegrator;
import org.hibernate.search.spi.SearchIntegratorBuilder;
import org.hibernate.search.testsupport.BytemanHelper;
import org.hibernate.search.testsupport.TestForIssue;
import org.hibernate.search.testsupport.BytemanHelper.BytemanAccessor;
import org.hibernate.search.testsupport.BytemanHelper.SimulatedFailureException;
import org.hibernate.search.testsupport.junit.ElasticsearchSupportInProgress;
import org.hibernate.search.testsupport.setup.SearchConfigurationForTest;
import org.jboss.byteman.contrib.bmunit.BMRule;
import org.jboss.byteman.contrib.bmunit.BMRules;
import org.jboss.byteman.contrib.bmunit.BMUnitRunner;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
/**
* @author Hardy Ferentschik
*/
@RunWith(BMUnitRunner.class)
public class SearchFactoryTest {
@Rule
public BytemanAccessor bytemanAccessor = BytemanHelper.createAccessor();
@Test
public void testTypeWithNoDocumentIdThrowsException() {
SearchConfigurationForTest cfg = getManualConfiguration();
SearchMapping mapping = new SearchMapping();
mapping
.entity( Foo.class ).indexed()
;
cfg.setProgrammaticMapping( mapping );
try {
new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator();
fail( "Invalid configuration should have thrown an exception" );
}
catch (SearchException e) {
assertTrue( e.getMessage().startsWith( "HSEARCH000177" ) );
}
}
@Test
@Category(ElasticsearchSupportInProgress.class) // HSEARCH-2481 Byteman-based tests re-executed in the Elasticsearch module won't work
@TestForIssue(jiraKey = "HSEARCH-2277")
@BMRules(rules = {
@BMRule(
name = "Simulate failure on index manager initialization",
isInterface = true,
targetClass = "org.hibernate.search.indexes.spi.IndexManager",
targetMethod = "initialize(String, Properties, Similarity, WorkerBuildContext)",
helper = "org.hibernate.search.testsupport.BytemanHelper",
action = "simulateFailure()"
),
@BMRule(
name = "Track calls to ServiceManager.releaseAllServices",
targetClass = "org.hibernate.search.engine.service.impl.StandardServiceManager",
targetMethod = "releaseAllServices()",
helper = "org.hibernate.search.testsupport.BytemanHelper",
action = "countInvocation()"
)
} )
public void testServicesStoppedAfterIndexInitializationException() {
SearchConfigurationForTest cfg = new SearchConfigurationForTest()
.addClass( AnnotatedClass.class ).addClass( SecondAnnotatedClass.class );
try {
new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator();
failBecauseBytemanRulesDidNotWork();
}
catch (SearchException e) {
assertEquals( 1, bytemanAccessor.getAndResetInvocationCount() );
}
}
@Test
@Category(ElasticsearchSupportInProgress.class) // HSEARCH-2481 Byteman-based tests re-executed in the Elasticsearch module won't work
@TestForIssue(jiraKey = "HSEARCH-2277")
@BMRules(rules = {
@BMRule(
name = "Skip failure on second index manager initialization",
isInterface = true,
targetClass = "org.hibernate.search.indexes.spi.IndexManager",
targetMethod = "initialize(String, Properties, Similarity, WorkerBuildContext)",
helper = "org.hibernate.search.testsupport.BytemanHelper",
// Only fail after at least one index manager was successfully initialized
condition = "incrementCounter(\"indexManagerInitialize\") >= 2",
action = "simulateFailure()"
),
@BMRule(
name = "Track calls to IndexManager.destroy",
isInterface = true,
targetClass = "org.hibernate.search.indexes.spi.IndexManager",
targetMethod = "destroy()",
helper = "org.hibernate.search.testsupport.BytemanHelper",
action = "countInvocation()"
)
} )
public void testIndexManagerStoppedAfterIndexInitializationException() {
SearchConfigurationForTest cfg = new SearchConfigurationForTest()
.addClass( AnnotatedClass.class ).addClass( SecondAnnotatedClass.class );
try {
new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator();
failBecauseBytemanRulesDidNotWork();
}
catch (SearchException e) {
/*
* Expect only one index manager to be cleaned up
* (the initialization failed for the other one, so we shouldn't attempt to clean it up)
*/
assertEquals( 1, bytemanAccessor.getAndResetInvocationCount() );
}
}
@Test
@Category(ElasticsearchSupportInProgress.class) // HSEARCH-2481 Byteman-based tests re-executed in the Elasticsearch module won't work
@TestForIssue(jiraKey = "HSEARCH-2277")
@BMRules(rules = {
@BMRule(
name = "Simulate failure on index manager search factory setup",
targetClass = "org.hibernate.search.engine.impl.MutableSearchFactoryState",
targetMethod = "setActiveSearchIntegrator(ExtendedSearchIntegratorWithShareableState)",
helper = "org.hibernate.search.testsupport.BytemanHelper",
action = "simulateFailure()"
),
@BMRule(
name = "Track calls to ServiceManager.releaseAllServices",
targetClass = "org.hibernate.search.engine.service.impl.StandardServiceManager",
targetMethod = "releaseAllServices()",
helper = "org.hibernate.search.testsupport.BytemanHelper",
action = "countInvocation()"
)
} )
public void testServicesStoppedAfterIndexManagerSearchFactorySetupException() {
SearchConfigurationForTest cfg = new SearchConfigurationForTest().addClass( AnnotatedClass.class );
try {
new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator();
failBecauseBytemanRulesDidNotWork();
}
catch (SimulatedFailureException e) {
assertEquals( 1, bytemanAccessor.getAndResetInvocationCount() );
}
}
@Test
@Category(ElasticsearchSupportInProgress.class) // HSEARCH-2481 Byteman-based tests re-executed in the Elasticsearch module won't work
@TestForIssue(jiraKey = "HSEARCH-2277")
@BMRules(rules = {
@BMRule(
name = "Simulate failure on index manager search factory setup",
targetClass = "org.hibernate.search.engine.impl.MutableSearchFactoryState",
targetMethod = "setActiveSearchIntegrator(ExtendedSearchIntegratorWithShareableState)",
helper = "org.hibernate.search.testsupport.BytemanHelper",
action = "simulateFailure()"
),
@BMRule(
name = "Track calls to IndexManager.destroy",
isInterface = true,
targetClass = "org.hibernate.search.indexes.spi.IndexManager",
targetMethod = "destroy()",
helper = "org.hibernate.search.testsupport.BytemanHelper",
action = "countInvocation()"
)
} )
public void testIndexManagerStoppedAfterIndexManagerSearchFactorySetupException() {
SearchConfigurationForTest cfg = new SearchConfigurationForTest()
.addClass( AnnotatedClass.class ).addClass( SecondAnnotatedClass.class );
try {
new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator();
failBecauseBytemanRulesDidNotWork();
}
catch (SimulatedFailureException e) {
// Expect both index managers to be cleaned up
assertEquals( 2, bytemanAccessor.getAndResetInvocationCount() );
}
}
@Test
public void testGetIndexedTypesNoTypeIndexed() {
SearchConfigurationForTest cfg = getManualConfiguration();
try ( SearchIntegrator si = new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator() ) {
Set<Class<?>> indexedClasses = si.getIndexedTypes();
assertEquals( "Wrong number of indexed entities", 0, indexedClasses.size() );
}
}
@Test
public void testGetIndexedTypeSingleIndexedType() {
SearchConfigurationForTest cfg = getManualConfiguration();
SearchMapping mapping = new SearchMapping();
mapping
.entity( Foo.class ).indexed()
.property( "id", FIELD ).documentId()
;
cfg.setProgrammaticMapping( mapping );
try ( SearchIntegrator si = new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator() ) {
Set<Class<?>> indexedClasses = si.getIndexedTypes();
assertEquals( "Wrong number of indexed entities", 1, indexedClasses.size() );
assertTrue( indexedClasses.iterator().next().equals( Foo.class ) );
}
}
@Test
public void testGetIndexedTypesMultipleTypes() {
SearchConfigurationForTest cfg = getManualConfiguration();
SearchMapping mapping = new SearchMapping();
mapping
.entity( Foo.class ).indexed()
.property( "id", FIELD ).documentId()
.entity( Bar.class ).indexed()
.property( "id", FIELD ).documentId()
;
cfg.setProgrammaticMapping( mapping );
SearchIntegrator si = new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator();
Set<Class<?>> indexedClasses = si.getIndexedTypes();
assertEquals( "Wrong number of indexed entities", 2, indexedClasses.size() );
}
@Test
public void testGetTypeDescriptorForUnindexedType() {
SearchConfigurationForTest cfg = getManualConfiguration();
try ( SearchIntegrator si = new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator() ) {
IndexedTypeDescriptor indexedTypeDescriptor = si.getIndexedTypeDescriptor( Foo.class );
assertNotNull( indexedTypeDescriptor );
assertFalse( indexedTypeDescriptor.isIndexed() );
}
}
@Test
public void testGetTypeDescriptorForIndexedType() {
SearchConfigurationForTest cfg = getManualConfiguration();
SearchMapping mapping = new SearchMapping();
mapping
.entity( Foo.class ).indexed()
.property( "id", FIELD ).documentId()
;
cfg.setProgrammaticMapping( mapping );
try ( SearchIntegrator si = new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator() ) {
IndexedTypeDescriptor indexedTypeDescriptor = si.getIndexedTypeDescriptor( Foo.class );
assertNotNull( indexedTypeDescriptor );
assertTrue( indexedTypeDescriptor.isIndexed() );
}
}
private SearchConfigurationForTest getManualConfiguration() {
return new SearchConfigurationForTest()
.addClass( Foo.class )
.addClass( Bar.class );
}
private void failBecauseBytemanRulesDidNotWork() {
fail( "The test could not run because some ByteMan rule did not execute properly." );
}
public static class Foo {
private long id;
}
public static class Bar {
private long id;
}
@Indexed
private static class AnnotatedClass {
@DocumentId
private long id;
@Field
private String field;
}
@Indexed
private static class SecondAnnotatedClass {
@DocumentId
private long id;
@Field
private String field;
}
}