/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.tck;
import static java.util.Collections.unmodifiableList;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import org.mule.runtime.api.exception.MuleException;
import org.mule.runtime.api.lifecycle.Stoppable;
import org.mule.runtime.api.scheduler.Scheduler;
import org.mule.runtime.core.api.scheduler.SchedulerConfig;
import org.mule.runtime.core.api.scheduler.SchedulerPoolsConfigFactory;
import org.mule.runtime.core.api.scheduler.SchedulerService;
import org.mule.runtime.core.util.concurrent.NamedThreadFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
/**
* {@link SchedulerService} implementation that provides a shared {@link SimpleUnitTestSupportScheduler}.
*
* @since 4.0
*/
public class SimpleUnitTestSupportSchedulerService implements SchedulerService, Stoppable {
private SimpleUnitTestSupportScheduler scheduler =
new SimpleUnitTestSupportScheduler(8, new NamedThreadFactory(SimpleUnitTestSupportScheduler.class.getSimpleName()),
new AbortPolicy());
private List<Scheduler> customSchedulers = new ArrayList<>();
private List<Scheduler> decorators = new ArrayList<>();
@Override
public String getName() {
return SchedulerService.class.getSimpleName();
}
@Override
public Scheduler cpuLightScheduler() {
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(scheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler ioScheduler() {
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(scheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler cpuIntensiveScheduler() {
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(scheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler cpuLightScheduler(SchedulerConfig config) {
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(scheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler ioScheduler(SchedulerConfig config) {
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(scheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler cpuIntensiveScheduler(SchedulerConfig config) {
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(scheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler cpuLightScheduler(SchedulerConfig config, SchedulerPoolsConfigFactory poolsConfigFactory) {
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(scheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler ioScheduler(SchedulerConfig config, SchedulerPoolsConfigFactory poolsConfigFactory) {
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(scheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler cpuIntensiveScheduler(SchedulerConfig config, SchedulerPoolsConfigFactory poolsConfigFactory) {
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(scheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler customScheduler(SchedulerConfig config) {
final SimpleUnitTestSupportScheduler customScheduler =
new SimpleUnitTestSupportCustomScheduler(config.getMaxConcurrentTasks(),
new NamedThreadFactory(config
.getSchedulerName() != null
? config.getSchedulerName()
: "SimpleUnitTestSupportSchedulerService_custom"),
new AbortPolicy());
customSchedulers.add(customScheduler);
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(customScheduler);
decorators.add(decorator);
return decorator;
}
@Override
public Scheduler customScheduler(SchedulerConfig config, int queueSize) {
final SimpleUnitTestSupportScheduler customScheduler =
new SimpleUnitTestSupportCustomScheduler(config.getMaxConcurrentTasks(),
new NamedThreadFactory(config
.getSchedulerName() != null
? config.getSchedulerName()
: "SimpleUnitTestSupportSchedulerService_custom"),
new AbortPolicy());
customSchedulers.add(customScheduler);
final SimpleUnitTestSupportLifecycleSchedulerDecorator decorator = decorateScheduler(customScheduler);
decorators.add(decorator);
return decorator;
}
protected SimpleUnitTestSupportLifecycleSchedulerDecorator decorateScheduler(SimpleUnitTestSupportScheduler scheduler) {
SimpleUnitTestSupportLifecycleSchedulerDecorator spied =
spy(new SimpleUnitTestSupportLifecycleSchedulerDecorator(resolveSchedulerCreationLocation(), scheduler, this));
doReturn(mock(ScheduledFuture.class)).when(spied).scheduleWithCronExpression(any(), anyString());
doReturn(mock(ScheduledFuture.class)).when(spied).scheduleWithCronExpression(any(), anyString(), any());
return spied;
}
private String resolveSchedulerCreationLocation() {
int i = 0;
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
StackTraceElement ste = stackTrace[i++];
// We have to go deep enough, right before the mockito call
while (skip(ste) && i < stackTrace.length) {
ste = stackTrace[i++];
}
if (skip(ste)) {
ste = stackTrace[3];
} else {
ste = stackTrace[i];
}
return ste.getClassName() + "." + ste.getMethodName() + ":" + ste.getLineNumber();
}
private boolean skip(StackTraceElement ste) {
return ste.getClassName().startsWith(SimpleUnitTestSupportSchedulerService.class.getName())
|| ste.getClassName().startsWith("org.mockito")
|| !ste.getClassName().contains("$Proxy");
}
@Override
public void stop() throws MuleException {
if (!scheduler.isShutdown()) {
scheduler.shutdownNow();
}
for (Scheduler customScheduler : customSchedulers) {
customScheduler.shutdownNow();
}
}
@Override
public List<Scheduler> getSchedulers() {
return unmodifiableList(new ArrayList<>(decorators));
}
public void clearCreatedSchedulers() {
decorators.clear();
}
void stoppedScheduler(Scheduler scheduler) {
decorators.remove(scheduler);
}
public int getScheduledTasks() {
return scheduler.getScheduledTasks();
}
}