/* Copyright 2012 Google, Inc.
*
* 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.arbeitspferde.groningen;
import com.google.inject.Provider;
import org.arbeitspferde.groningen.common.BlockScope;
import org.arbeitspferde.groningen.common.SimpleScope;
import org.arbeitspferde.groningen.config.ConfigManager;
import org.arbeitspferde.groningen.config.GroningenConfig;
import org.arbeitspferde.groningen.proto.Params.GroningenParams;
import org.arbeitspferde.groningen.proto.Params.GroningenParams.PipelineSynchMode;
import org.arbeitspferde.groningen.scorer.HistoricalBestPerformerScorer;
import junit.framework.TestCase;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
/**
* Test for {@link PipelineManager}
*
* @author mbushkov@google.com (Mikhail Bushkov)
*/
public class PipelineManagerTest extends TestCase {
private BlockScope pipelineScope;
private Pipeline pipelineMock;
private Datastore dataStoreMock;
private PipelineIdGenerator pipelineIdGeneratorMock;
private Provider<Pipeline> pipelineProvider;
private Map<PipelineSynchMode, Provider<PipelineSynchronizer>> pipelineSyncProviderMap;
private PipelineSynchronizer defaultPipelineSynchronizer;
private PipelineManager pipelineManager;
private HistoricalBestPerformerScorer bestPerformerScorer;
private Provider<HistoricalBestPerformerScorer> bestPerformerScorerProvider;
@Override
protected void setUp() throws Exception {
super.setUp();
pipelineMock = EasyMock.createNiceMock(Pipeline.class);
dataStoreMock = EasyMock.createNiceMock(Datastore.class);
pipelineIdGeneratorMock = EasyMock.createNiceMock(PipelineIdGenerator.class);
pipelineScope = new SimpleScope();
pipelineSyncProviderMap = new HashMap<>();
defaultPipelineSynchronizer = new EmptyPipelineSynchronizer();
bestPerformerScorer = EasyMock.createNiceMock(HistoricalBestPerformerScorer.class);
Provider<PipelineSynchronizer> emptySynchronizerProvider =
new Provider<PipelineSynchronizer>() {
@Override
public PipelineSynchronizer get() {
return defaultPipelineSynchronizer;
}
};
pipelineSyncProviderMap.put(PipelineSynchMode.NONE, emptySynchronizerProvider);
pipelineProvider = new Provider<Pipeline>() {
@Override
public Pipeline get() {
return pipelineMock;
}
};
bestPerformerScorerProvider = new Provider<HistoricalBestPerformerScorer>() {
@Override
public HistoricalBestPerformerScorer get() {
return bestPerformerScorer;
}
};
pipelineManager = new PipelineManager(pipelineIdGeneratorMock, pipelineScope,
pipelineProvider, dataStoreMock, pipelineSyncProviderMap, bestPerformerScorerProvider);
}
public void testGetRequestedPipelineSynchronizerWithDefaultParamBlock() {
GroningenConfig config = EasyMock.createNiceMock(GroningenConfig.class);
GroningenParams paramBlock = GroningenParams.newBuilder().build();
EasyMock.expect(config.getParamBlock()).andReturn(paramBlock);
EasyMock.replay(config);
PipelineSynchronizer synchronizer = pipelineManager.getRequestedPipelineSynchronizer(config);
assertEquals(pipelineSyncProviderMap.get(PipelineSynchMode.NONE).get(), synchronizer);
}
public void testGetRequestedPipelineSynchronizerWithNamedSynchronizer() {
GroningenConfig config = EasyMock.createNiceMock(GroningenConfig.class);
GroningenParams paramBlock = GroningenParams.newBuilder()
.setPipelineSyncType(GroningenParams.PipelineSynchMode.ITERATION_FINALIZATION_ONLY)
.build();
final PipelineSynchronizer finalizationSynchronizer = new IterationFinalizationSynchronizer();
Provider<PipelineSynchronizer> localSynchronizerProvider =
new Provider<PipelineSynchronizer>() {
@Override
public PipelineSynchronizer get() {
return finalizationSynchronizer;
}
};
pipelineSyncProviderMap.put(
PipelineSynchMode.ITERATION_FINALIZATION_ONLY, localSynchronizerProvider);
EasyMock.expect(config.getParamBlock()).andReturn(paramBlock);
EasyMock.replay(config);
PipelineSynchronizer synchronizer = pipelineManager.getRequestedPipelineSynchronizer(config);
assertEquals(finalizationSynchronizer, synchronizer);
}
public void testGetRequestedPipelineSynchronizerWithNonexistantSynchronizer() {
GroningenConfig config = EasyMock.createNiceMock(GroningenConfig.class);
GroningenParams paramBlock = GroningenParams.newBuilder()
.setPipelineSyncType(GroningenParams.PipelineSynchMode.BASIC_SEMAPHORE)
.build();
EasyMock.expect(config.getParamBlock()).andReturn(paramBlock);
EasyMock.replay(config);
PipelineSynchronizer synchronizer = pipelineManager.getRequestedPipelineSynchronizer(config);
assertEquals(defaultPipelineSynchronizer, synchronizer);
}
/**
* Test that when Pipeline is created in non-blocking mode, it eventually gets executed
* and we can find it by its' pipeline id.
*/
public void testStartsPipelineWithSpecificSynchronizerRequested() throws InterruptedException {
ConfigManager configManager = EasyMock.createNiceMock(ConfigManager.class);
GroningenConfig config = EasyMock.createNiceMock(GroningenConfig.class);
GroningenParams paramBlock = GroningenParams.newBuilder()
.setPipelineSyncType(GroningenParams.PipelineSynchMode.ITERATION_FINALIZATION_ONLY)
.build();
final PipelineSynchronizer finalizationSynchronizer = new IterationFinalizationSynchronizer();
Provider<PipelineSynchronizer> localSynchronizerProvider =
new Provider<PipelineSynchronizer>() {
@Override
public PipelineSynchronizer get() {
return finalizationSynchronizer;
}
};
pipelineSyncProviderMap.put(
PipelineSynchMode.ITERATION_FINALIZATION_ONLY, localSynchronizerProvider);
EasyMock.expect(configManager.queryConfig()).andReturn(config).anyTimes();
EasyMock.expect(config.getParamBlock()).andReturn(paramBlock);
PipelineId referenceId = new PipelineId("pipelineid");
EasyMock.expect(
pipelineIdGeneratorMock.generatePipelineId(EasyMock.anyObject(GroningenConfig.class))).
andReturn(referenceId);
BlockScope localPipelineScope = EasyMock.createMock(BlockScope.class);
localPipelineScope.enter();
localPipelineScope.seed(PipelineSynchronizer.class, finalizationSynchronizer);
localPipelineScope.seed(PipelineId.class, referenceId);
localPipelineScope.seed(ConfigManager.class, configManager);
localPipelineScope.seed(
EasyMock.same(PipelineStageInfo.class), EasyMock.anyObject(PipelineStageInfo.class));
localPipelineScope.seed(HistoricalBestPerformerScorer.class, bestPerformerScorer);
final ReentrantLock lock = new ReentrantLock();
pipelineMock.run();
localPipelineScope.exit();
EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
@Override
public Void answer() throws Throwable {
// Pausing pipeline until main thread explicitly unlocks the lock
lock.lock();
lock.unlock();
return null;
}});
EasyMock.replay(configManager, config, pipelineMock, pipelineIdGeneratorMock,
localPipelineScope, bestPerformerScorer);
pipelineManager = new PipelineManager(pipelineIdGeneratorMock, localPipelineScope,
pipelineProvider, dataStoreMock, pipelineSyncProviderMap, bestPerformerScorerProvider);
lock.lock();
try {
PipelineId id = pipelineManager.startPipeline(configManager, false);
Thread.sleep(500);
assertNotNull(pipelineManager.findPipelineById(id));
} finally {
lock.unlock();
}
EasyMock.verify(localPipelineScope);
}
/**
* Test that when Pipeline is created in non-blocking mode, it eventually gets executed
* and we can find it by its' pipeline id.
*/
public void testStartsPipelineInNonBlockingMode() throws InterruptedException {
ConfigManager configManager = EasyMock.createNiceMock(ConfigManager.class);
GroningenConfig config = EasyMock.createNiceMock(GroningenConfig.class);
GroningenParams paramBlock = GroningenParams.newBuilder()
.setPipelineSyncType(GroningenParams.PipelineSynchMode.NONE)
.build();
EasyMock.expect(configManager.queryConfig()).andReturn(config).anyTimes();
EasyMock.expect(config.getParamBlock()).andReturn(paramBlock);
EasyMock.expect(
pipelineIdGeneratorMock.generatePipelineId(EasyMock.anyObject(GroningenConfig.class))).
andReturn(new PipelineId("pipelineId"));
final ReentrantLock lock = new ReentrantLock();
pipelineMock.run();
EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
@Override
public Void answer() throws Throwable {
// Pausing pipeline until main thread explicitly unlocks the lock
lock.lock();
lock.unlock();
return null;
}});
EasyMock.replay(configManager, config, pipelineMock, pipelineIdGeneratorMock);
lock.lock();
try {
PipelineId id = pipelineManager.startPipeline(configManager, false);
Thread.sleep(500);
assertNotNull(pipelineManager.findPipelineById(id));
} finally {
lock.unlock();
}
}
/**
* Test that when Pipeline is created in blocking mode, we can find it by its' id immediately
* after the startPipeline() call.
*/
public void testStartsPipelineInBlockingMode() {
ConfigManager configManager = EasyMock.createNiceMock(ConfigManager.class);
GroningenConfig config = EasyMock.createNiceMock(GroningenConfig.class);
GroningenParams paramBlock = GroningenParams.newBuilder()
.setPipelineSyncType(GroningenParams.PipelineSynchMode.NONE)
.build();
EasyMock.expect(configManager.queryConfig()).andReturn(config).anyTimes();
EasyMock.expect(config.getParamBlock()).andReturn(paramBlock);
EasyMock.expect(
pipelineIdGeneratorMock.generatePipelineId(EasyMock.anyObject(GroningenConfig.class))).
andReturn(new PipelineId("pipelineId"));
EasyMock.expectLastCall().andAnswer(new IAnswer<Void>() {
@Override
public Void answer() throws Throwable {
Thread.sleep(500);
return null;
}});
EasyMock.replay(configManager, config, pipelineMock, pipelineIdGeneratorMock);
PipelineId id = pipelineManager.startPipeline(configManager, true);
assertNotNull(pipelineManager.findPipelineById(id));
}
}