use of io.cdap.cdap.internal.app.runtime.ProgramControllerServiceAdapter in project cdap by caskdata.
the class ProgramControllerTest method testInitState.
@Test
public void testInitState() throws ExecutionException, InterruptedException {
// To test against race-condition, we start/stop service multiple times.
// If there is race, there is a chance that this test will fail in some env.
// Otherwise it should always pass
ExecutorService executor = Executors.newCachedThreadPool();
int serviceCount = 1000;
final CountDownLatch latch = new CountDownLatch(serviceCount);
ProgramId programId = new ApplicationId(NamespaceId.DEFAULT.getNamespace(), "test").service("test");
for (int i = 0; i < serviceCount; i++) {
// Creates a controller for a guava service do nothing in start/stop.
// The short time in start creates a chance to have out-of-order init() and alive() call if there is a race.
Service service = new TestService(0, 0);
ProgramController controller = new ProgramControllerServiceAdapter(service, programId.run(RunIds.generate()));
ListenableFuture<Service.State> startCompletion = service.start();
controller.addListener(new AbstractListener() {
private volatile boolean initCalled;
@Override
public void init(ProgramController.State currentState, @Nullable Throwable cause) {
initCalled = true;
if (currentState == ProgramController.State.ALIVE) {
latch.countDown();
}
}
@Override
public void alive() {
if (initCalled) {
latch.countDown();
} else {
LOG.error("init() not called before alive()");
}
}
}, executor);
startCompletion.get();
service.stopAndWait();
}
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
use of io.cdap.cdap.internal.app.runtime.ProgramControllerServiceAdapter in project cdap by caskdata.
the class AbstractProgramRuntimeServiceTest method testConcurrentStartLimit.
@Test
public void testConcurrentStartLimit() throws Exception {
Semaphore proceed = new Semaphore(0);
Set<String> threadNames = ConcurrentHashMap.newKeySet();
// Creates a runner factory that block start until a signal is received
ProgramRunnerFactory runnerFactory = programType -> (program, options) -> {
threadNames.add(Thread.currentThread().getName());
proceed.acquireUninterruptibly();
ProgramId programId = program.getId();
Service service = new FastService();
ProgramController controller = new ProgramControllerServiceAdapter(service, programId.run(RunIds.generate()));
service.start();
return controller;
};
Program program = createDummyProgram();
ProgramDescriptor descriptor = new ProgramDescriptor(program.getId(), null, NamespaceId.DEFAULT.artifact("test", "1.0"));
CConfiguration cConf = CConfiguration.create();
cConf.setInt(Constants.AppFabric.PROGRAM_LAUNCH_THREADS, 2);
ProgramRuntimeService runtimeService = new TestProgramRuntimeService(cConf, runnerFactory, program, null, null);
runtimeService.startAndWait();
try {
List<ProgramController> controllers = new ArrayList<>();
for (int i = 0; i < 5; i++) {
controllers.add(runtimeService.run(descriptor, new SimpleProgramOptions(program.getId()), RunIds.generate()).getController());
}
// There should be 2 program start threads running only
Tasks.waitFor(2, proceed::getQueueLength, 2, TimeUnit.SECONDS);
try {
// Shouldn't never have more than 2
Tasks.waitFor(true, () -> proceed.getQueueLength() > 2, 2, TimeUnit.SECONDS);
Assert.fail("Shouldn't have more than 2 program starting");
} catch (TimeoutException e) {
// expected
}
// Let all start to proceed. They should have all finished pretty quickly
proceed.release(5);
Tasks.waitFor(true, () -> controllers.stream().map(ProgramController::getState).allMatch(ProgramController.State.COMPLETED::equals), 5, TimeUnit.SECONDS);
Assert.assertEquals(2, threadNames.size());
} finally {
runtimeService.stopAndWait();
}
}
Aggregations