com.applitools.eyes.visualgridclient.services.VisualGridRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eyes-common-java3 Show documentation
Show all versions of eyes-common-java3 Show documentation
Common code for Applitools Eyes Java SDK projects
package com.applitools.eyes.visualgridclient.services;
import com.applitools.ICheckSettings;
import com.applitools.eyes.Logger;
import com.applitools.eyes.visualgridclient.model.*;
import com.applitools.utils.GeneralUtils;
import java.util.*;
import java.util.concurrent.*;
public class VisualGridRunner extends EyesRunner {
private int concurrentOpenSessions;
//For Testing...
private final Object openerServiceDebugLock;
private final Object checkerServiceDebugLock;
private final Object closerServiceDebugLock;
private final Object renderServiceDebugLock;
private OpenerService eyesOpenerService;
private EyesService eyesCloserService;
private EyesService eyesCheckerService;
private RenderingGridService renderingGridService;
private ThreadGroup servicesGroup = new ThreadGroup("Services Group");
private final List eyesToOpenList = Collections.synchronizedList(new ArrayList(200));
private final List allEyes = Collections.synchronizedList(new ArrayList(200));
private Map cachedResources = Collections.synchronizedMap(new HashMap());
private Map putResourceCache = Collections.synchronizedMap(new HashMap());
private final Object openerServiceConcurrencyLock = new Object();
private final Object openerServiceLock = new Object();
private final Object checkerServiceLock = new Object();
private final Object closerServiceLock = new Object();
private final Object renderingServiceLock = new Object();
private final List renderingTaskList = Collections.synchronizedList(new ArrayList());
private RenderingInfo renderingInfo;
private IDebugResourceWriter debugResourceWriter;
private RateLimiter rateLimiter;
private String serverUrl;
private static final String DEFAULT_API_KEY = System.getenv("APPLITOOLS_API_KEY");
private String apiKey = DEFAULT_API_KEY;
private boolean isDisabled;
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
private FutureTask getOrWaitForTask(Object lock, @SuppressWarnings("SpellCheckingInspection") EyesService.Tasker tasker,
String serviceName) {
FutureTask nextTestToOpen = tasker.getNextTask();
if (nextTestToOpen == null) {
try {
// logger.verbose("locking " + serviceName);
synchronized (lock) {
lock.wait(500);
}
// logger.verbose("releasing " + serviceName);
nextTestToOpen = tasker.getNextTask();
// logger.verbose(serviceName + " tasker returned " + nextTestToOpen);
} catch (Exception e) {
GeneralUtils.logExceptionStackTrace(logger, e);
}
}
return nextTestToOpen;
}
public void pauseAllService() {
eyesOpenerService.debugPauseService();
eyesCloserService.debugPauseService();
eyesCheckerService.debugPauseService();
renderingGridService.debugPauseService();
}
public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
public String getServerUrl() {
return this.serverUrl;
}
public String getApiKey() {
return this.apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey != null ? apiKey : DEFAULT_API_KEY;
}
public void setIsDisabled(boolean isDisabled) {
this.isDisabled = isDisabled;
}
public boolean getIsDisabled() {
return this.isDisabled;
}
public interface RenderListener {
void onRenderSuccess();
void onRenderFailed(Exception e);
}
private IRenderingEyes.EyesListener eyesListener = new IRenderingEyes.EyesListener() {
@Override
public void onTaskComplete(VisualGridTask visualGridTask, IRenderingEyes eyes) {
logger.verbose("Enter with: " + visualGridTask.getType());
VisualGridTask.TaskType type = visualGridTask.getType();
try {
switch (type) {
case OPEN:
logger.verbose("locking eyesToOpenList");
synchronized (eyesToOpenList) {
logger.verbose("removing visualGridTask " + visualGridTask.toString());
eyesToOpenList.remove(eyes);
}
logger.verbose("releasing eyesToOpenList");
break;
case CLOSE:
logger.verbose("VisualGridTask Close.");
eyesOpenerService.decrementConcurrency();
synchronized (openerServiceConcurrencyLock) {
openerServiceConcurrencyLock.notify();
}
logger.verbose("releasing openerServiceConcurrencyLock");
break;
case ABORT:
synchronized (openerServiceConcurrencyLock) {
openerServiceConcurrencyLock.notify();
}
break;
case CHECK:
logger.verbose("Check complete.");
}
} catch (Exception e) {
GeneralUtils.logExceptionStackTrace(logger, e);
}
notifyAllServices();
}
@Override
public void onRenderComplete() {
notifyAllServices();
}
};
public VisualGridRunner(int concurrentOpenSessions) {
this(concurrentOpenSessions, null, null, null, null);
}
public VisualGridRunner(int concurrentOpenSessions,
Object openerServiceDebugLock,
Object checkerServiceDebugLock,
Object closerServiceDebugLock,
Object renderServiceDebugLock) {
this.concurrentOpenSessions = concurrentOpenSessions;
this.openerServiceDebugLock = openerServiceDebugLock;
this.checkerServiceDebugLock = checkerServiceDebugLock;
this.closerServiceDebugLock = closerServiceDebugLock;
this.renderServiceDebugLock = renderServiceDebugLock;
this.rateLimiter = new RateLimiter(logger, 20);
init();
startServices();
logger.verbose("rendering grid manager is built");
}
public Map getCachedResources() {
return cachedResources;
}
public Map getPutResourceCache() {
return putResourceCache;
}
public RenderingInfo getRenderingInfo() {
return renderingInfo;
}
private void init() {
this.eyesOpenerService = new OpenerService("eyesOpenerService", servicesGroup,
logger, this.concurrentOpenSessions, openerServiceConcurrencyLock, new EyesService.EyesServiceListener() {
@Override
public FutureTask getNextTask(@SuppressWarnings("SpellCheckingInspection") EyesService.Tasker tasker) {
return getOrWaitForTask(openerServiceLock, tasker, "eyesOpenerService");
}
}, openerServiceDebugLock, new EyesService.Tasker() {
@Override
public FutureTask getNextTask() {
return getNextTestToOpen();
}
});
this.eyesCloserService = new EyesService("eyesCloserService", servicesGroup, logger, concurrentOpenSessions, closerServiceDebugLock, new EyesService.EyesServiceListener() {
@Override
public FutureTask getNextTask(@SuppressWarnings("SpellCheckingInspection") EyesService.Tasker tasker) {
return getOrWaitForTask(closerServiceLock, tasker, "eyesCloserService");
}
}, new EyesService.Tasker() {
@Override
public FutureTask getNextTask() {
return getNextTestToClose();
}
});
this.renderingGridService = new RenderingGridService("renderingGridService", servicesGroup, logger, this.concurrentOpenSessions, renderServiceDebugLock, new RenderingGridService.RGServiceListener() {
@Override
public RenderingTask getNextTask() {
RenderingTask nextTestToRender = getNextRenderingTask();
if (nextTestToRender == null) {
synchronized (renderingServiceLock) {
try {
nextTestToRender = getNextRenderingTask();
if (nextTestToRender == null) {
renderingServiceLock.wait(500);
// logger.log("Rendering service woke up");
nextTestToRender = getNextRenderingTask();
}
} catch (Exception e) {
GeneralUtils.logExceptionStackTrace(logger, e);
}
}
}
return nextTestToRender;
}
});
this.eyesCheckerService = new EyesService("eyesCheckerService", servicesGroup, logger, this.concurrentOpenSessions, checkerServiceDebugLock, new EyesService.EyesServiceListener() {
@Override
public FutureTask getNextTask(@SuppressWarnings("SpellCheckingInspection") EyesService.Tasker tasker) {
return getOrWaitForTask(checkerServiceLock, tasker, "eyesCheckerService");
}
}, new EyesService.Tasker() {
@Override
public FutureTask getNextTask() {
return getNextCheckTask();
}
});
}
private FutureTask getNextCheckTask() {
VisualGridTask visualGridTask = null;
try {
ScoreTask bestScoreTask = null;
int bestScore = -1;
synchronized (allEyes) {
for (IRenderingEyes eyes : allEyes) {
ScoreTask currentScoreTask = eyes.getBestScoreTaskForCheck();
if (currentScoreTask == null) continue;
int currentTestMark = currentScoreTask.getScore();
if (bestScore < currentTestMark) {
bestScoreTask = currentScoreTask;
bestScore = currentTestMark;
}
}
}
if (bestScoreTask == null) {
return null;
}
visualGridTask = bestScoreTask.getVisualGridTask();
} catch (Exception e) {
GeneralUtils.logExceptionStackTrace(logger, e);
}
return new FutureTask<>(visualGridTask);
}
private RenderingTask getNextRenderingTask() {
if (this.renderingTaskList.isEmpty()) {
return null;
}
RenderingTask renderingTask = null;
synchronized (this.renderingTaskList) {
if (!this.renderingTaskList.isEmpty()) {
renderingTask = this.renderingTaskList.get(0);
this.renderingTaskList.remove(renderingTask);
}
}
// logger.log("Starting to renderTask - " + renderingTask);
return renderingTask;
}
private FutureTask getNextTestToClose() {
RunningTest runningTest;
synchronized (allEyes) {
for (IRenderingEyes eyes : allEyes) {
runningTest = eyes.getNextTestToClose();
if (runningTest != null) {
return runningTest.getNextCloseTask();
}
}
}
return null;
}
private synchronized FutureTask getNextTestToOpen() {
ScoreTask bestScoreTask = null;
int bestMark = -1;
// logger.verbose("looking for best test in a list of " + allEyes.size());
synchronized (allEyes) {
for (IRenderingEyes eyes : allEyes) {
ScoreTask currentTestMark = null;
try {
currentTestMark = eyes.getBestScoreTaskForOpen();
} catch (Exception e) {
GeneralUtils.logExceptionStackTrace(logger,e);
}
if (currentTestMark == null) continue;
int currentScore = currentTestMark.getScore();
if (bestMark < currentScore) {
bestMark = currentScore;
bestScoreTask = currentTestMark;
}
}
}
if (bestScoreTask == null) {
// logger.verbose("no test found.");
return null;
}
logger.verbose("found test with mark " + bestMark);
logger.verbose("calling getNextOpenTaskAndRemove on " + bestScoreTask.toString());
VisualGridTask nextOpenVisualGridTask = bestScoreTask.getVisualGridTask();
return new FutureTask<>(nextOpenVisualGridTask);
}
public void open(IRenderingEyes eyes, RenderingInfo renderingInfo) {
logger.verbose("enter");
if (this.renderingInfo == null) {
this.renderingInfo = renderingInfo;
}
// logger.verbose("locking eyesToOpenList");
synchronized (eyesToOpenList) {
eyesToOpenList.add(eyes);
}
// logger.verbose("releasing eyesToOpenList");
// logger.verbose("locking allEyes");
synchronized (allEyes) {
allEyes.add(eyes);
}
logger.verbose("releasing allEyes");
eyes.setListener(eyesListener);
logger.log("concurrencyLock.notify()");
}
private void startServices() {
logger.verbose("enter");
this.eyesOpenerService.start();
this.eyesCloserService.start();
this.renderingGridService.start();
this.eyesCheckerService.start();
this.servicesGroup.setDaemon(false);
logger.verbose("exit");
}
private void stopServices() {
logger.verbose("enter");
this.eyesOpenerService.stopService();
this.eyesCloserService.stopService();
this.renderingGridService.stopService();
this.eyesCheckerService.stopService();
logger.verbose("exit");
}
public TestResultSummary getAllTestResults() {
return getAllTestResults(false);
}
public TestResultSummary getAllTestResults(boolean shouldThrowException) {
logger.verbose("enter");
Map>> allFutures = new HashMap<>();
for (IRenderingEyes eyes : allEyes) {
List> futureList = eyes.close();
List> futures = allFutures.get(eyes);
if (futures != null && !futures.isEmpty()) {
futureList.addAll(futures);
}
allFutures.put(eyes, futureList);
}
notifyAllServices();
List allResults = new ArrayList<>();
logger.verbose("trying to call future.get on " + allFutures.size() + " future lists.");
for (Map.Entry>> entry : allFutures.entrySet()) {
List> value = entry.getValue();
IRenderingEyes key = entry.getKey();
logger.verbose("trying to call future.get on " + value.size() + " futures of " + key);
for (Future future : value) {
logger.verbose("calling future.get on " + key);
TestResultContainer obj = null;
try {
obj = future.get(10, TimeUnit.MINUTES);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
GeneralUtils.logExceptionStackTrace(logger, e);
if (shouldThrowException) {
throw new Error(e);
}
}
logger.verbose("got TestResultContainer: " + obj);
allResults.add(obj);
}
}
stopServices();
notifyAllServices();
logger.verbose("exit");
return new TestResultSummary(allResults);
}
public void close(IRenderingEyes eyes) {
logger.verbose("adding eyes to close list: " + eyes);
notifyAllServices();
}
public synchronized void check(ICheckSettings settings, IDebugResourceWriter debugResourceWriter, String script,
IEyesConnector connector, List visualGridTaskList, List openVisualGridTasks, ICheckSettings checkSettings, final RenderListener listener, List selectors, boolean forceFullPageScreenshot) {
if (debugResourceWriter == null) {
debugResourceWriter = this.debugResourceWriter;
}
if (debugResourceWriter == null) {
debugResourceWriter = new NullDebugResourceWriter();
}
RenderingTask renderingTask = new RenderingTask(connector, script, settings, visualGridTaskList,
openVisualGridTasks, this, debugResourceWriter, new RenderingTask.RenderTaskListener() {
@Override
public void onRenderSuccess() {
logger.verbose("enter");
listener.onRenderSuccess();
notifyAllServices();
logger.verbose("exit");
}
@Override
public void onRenderFailed(Exception e) {
listener.onRenderFailed(e);
}
}, selectors, forceFullPageScreenshot);
logger.verbose("locking renderingTaskList");
synchronized (renderingTaskList) {
this.renderingTaskList.add(renderingTask);
}
logger.verbose("releasing renderingTaskList");
notifyAllServices();
// logger.verbose("exit");
}
private void notifyAllServices() {
logger.verbose("enter");
notifyOpenerService();
notifyCloserService();
notifyCheckerService();
notifyRenderingService();
logger.verbose("exit");
}
private void notifyRenderingService() {
logger.log("trying to notify rendering service");
synchronized (renderingServiceLock) {
renderingServiceLock.notify();
}
logger.verbose("renderingLockFree");
}
private void notifyCloserService() {
logger.log("trying to notify closer service");
synchronized (closerServiceLock) {
closerServiceLock.notifyAll();
}
logger.verbose("closerLockFree");
}
private void notifyOpenerService() {
logger.log("trying to notify opener service");
synchronized (openerServiceLock) {
openerServiceLock.notifyAll();
logger.verbose("openerLockFree");
}
}
private void notifyCheckerService() {
logger.log("trying to notify checker service");
synchronized (checkerServiceLock) {
checkerServiceLock.notifyAll();
logger.verbose("checkerLockFree");
}
}
public List getAllTasksByType(VisualGridTask.TaskType type) {
List allTasks = new ArrayList<>();
for (IRenderingEyes eyes : allEyes) {
for (RunningTest runningTest : eyes.getAllRunningTests()) {
for (VisualGridTask visualGridTask : runningTest.getVisualGridTaskList()) {
if (visualGridTask.getType() == type) {
allTasks.add(visualGridTask);
}
}
}
}
return allTasks;
}
public List extends CompletableTask> getAllRenderingTasks() {
return this.renderingTaskList;
}
public void setDebugResourceWriter(IDebugResourceWriter debugResourceWriter) {
this.debugResourceWriter = debugResourceWriter;
}
public IDebugResourceWriter getDebugResourceWriter() {
return this.debugResourceWriter;
}
public RateLimiter getRateLimiter() {
return rateLimiter;
}
public void setLogger(Logger logger){
eyesCheckerService.setLogger(logger);
eyesCloserService.setLogger(logger);
eyesOpenerService.setLogger(logger);
renderingGridService.setLogger(logger);
this.logger = logger;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy