/*
* Copyright (c) 2010 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.action.execution;
import static org.junit.Assert.assertTrue;
import org.apache.commons.logging.Log;
import org.eurekastreams.commons.exceptions.ExecutionException;
import org.eurekastreams.commons.logging.LogFactory;
import org.eurekastreams.commons.search.bootstrap.EntityReindexer;
import org.jmock.Expectations;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Test;
/**
* Test suite for the {@link ReindexEntitiesExecution} class.
*
*/
public class ReindexEntitiesExecutionTest
{
/**
* Context for mocking.
*/
private final JUnit4Mockery context = new JUnit4Mockery()
{
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
/**
* Mocked instance of the EntityReindexer.
*/
private final EntityReindexer reindexerMock = context.mock(EntityReindexer.class);
/**
* Test execute().
*
* @throws Exception
* on error
*/
@Test
public void testExecute() throws Exception
{
context.checking(new Expectations()
{
{
one(reindexerMock).reindex();
}
});
// SUT
ReindexEntitiesExecution strategy = new ReindexEntitiesExecution(reindexerMock);
strategy.execute(null);
// assertions met?
context.assertIsSatisfied();
}
/**
* Test performAction() throws a RuntimeException when another thread is trying to do the same thing.
*/
@Test
public void testExecuteWhenAlreadyRunning()
{
// start running another instance of the action in a separate thread
TestSleeperActionRunner sleeperActionRunner = new TestSleeperActionRunner();
boolean exceptionThrown = false;
try
{
sleeperActionRunner.start();
// wait a split second to give the thread a chance of beating us
final int maxIterations = 20; // 1 second
int iteration = 0;
while (!sleeperActionRunner.getDidStart())
{
// just in case:
if (++iteration == maxIterations)
{
throw new RuntimeException("Sleeper test action never reported that it was running.");
}
wait50ms();
}
// wait a tad bit longer because there's still a race condition
wait50ms();
// try running it for real, expecting a RuntimeException
try
{
ReindexEntitiesExecution strategy = new ReindexEntitiesExecution(reindexerMock);
strategy.execute(null);
}
catch (ExecutionException re)
{
if (re.getMessage().indexOf("Cannot perform a reindexing right now - it's already in progress.") > -1)
{
exceptionThrown = true;
}
}
}
finally
{
// ask the sleeper action to kindly stop running
sleeperActionRunner.stopRunning();
}
assertTrue("Expected RuntimeException to be thrown when attempting two concurrent reindexes.", exceptionThrown);
}
/**
* Wait 50 milliseconds.
*/
private void wait50ms()
{
try
{
final int sleepDuration = 50;
Thread.sleep(sleepDuration);
}
catch (InterruptedException e)
{
log.error(e);
}
}
/**
* Logger.
*/
private Log log = LogFactory.make();
/**
* Test class that performs the EntityReindexerAction off in a separate thread, keeping it running until the thread
* is killed.
*/
private class TestSleeperActionRunner extends Thread
{
/**
* Keep track if the fake reindexing is running.
*/
private boolean didStart = false;
/**
* Whether we should keep running.
*/
private boolean shouldKeepRunning = true;
/**
* Stop running.
*/
public void stopRunning()
{
shouldKeepRunning = false;
}
/**
* Return whether the fake indexing is running.
*
* @return whether the fake indexing is running
*/
public boolean getDidStart()
{
return didStart;
}
/**
* Kick off the performAction method call in a separate thread.
*/
@Override
public void run()
{
log.debug("Thread started - running stalling performAction()");
didStart = true;
// kick off the fake indexing
EntityReindexer reindexer = new EntityReindexerFake();
ReindexEntitiesExecution strategy = new ReindexEntitiesExecution(reindexer);
strategy.execute(null);
}
/**
* Fake EntityReindexer - runs in a separate thread until it's told to stop.
*/
private class EntityReindexerFake extends EntityReindexer
{
/**
* faked-out method - will keep sleeping until dead.
*/
@Override
public void reindex()
{
final int maxIterations = 20; // 1 second
int iteration = 0;
while (shouldKeepRunning)
{
// just in case:
if (++iteration == maxIterations)
{
throw new RuntimeException("Sleeper test action never told to stop running.");
}
wait50ms();
}
}
}
}
}