com.browserstack.automate.testassist.TestSessionRecorder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of automate-testassist Show documentation
Show all versions of automate-testassist Show documentation
Library provides classes that Assist the Automate Build plugins to capture Selenium session id and test
case names.
/*
* Copyright (c) BrowserStack, Inc. Proprietary content. All rights reserved. Unauthorized use,
* copies, and derivatives of this file via any medium is strictly prohibited.
*/
package com.browserstack.automate.testassist;
import org.aspectj.lang.JoinPoint;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.HttpCommandExecutor;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
class TestSessionRecorder {
static boolean DEBUG = System.getProperty("browserstack.automate.debug", "false").equals("true");
private static final String HUB_BROWSERSTACK_COM =
System.getProperty("browserstack.automate.hub", "browserstack.com");
private static final String ENV_BROWSERSTACK_BUILD = "BROWSERSTACK_BUILD";
private static final String BROWSERSTACK_CAPABILITY_BUILD = "build";
private static final String OBJECT_CLASS_NAME = Object.class.getCanonicalName();
// thread-id <-> UnitTestCase[]
private final Map> testCases;
// test-case-id <-> test-index
private final Map testCaseIndices;
// thread-id <-> sessionId
private final Map> webDrivers;
// thread-id <-> last-event-type
private final Map lastEventType;
// thread-id <-> sessionId (stale)
private final Map lastSessionId;
// sessionId <-> test-id
private final Map sessionTestMap;
// Class <-> sessionId
private final Map clazzSessionMap;
// Class <-> class-hierarchy
private final Map> clazzHierarchyMap;
private final XmlReporter xmlReporter;
private final Map sessionWebDriverInstanceMap;
private static class InstanceHolder {
private static final TestSessionRecorder INSTANCE = new TestSessionRecorder();
}
private TestSessionRecorder() {
testCases = new ConcurrentHashMap>();
testCaseIndices = new ConcurrentHashMap();
webDrivers = new ConcurrentHashMap>();
lastEventType = new ConcurrentHashMap();
lastSessionId = new ConcurrentHashMap();
sessionTestMap = new ConcurrentHashMap();
clazzSessionMap = new ConcurrentHashMap();
clazzHierarchyMap = new ConcurrentHashMap>();
xmlReporter = new XmlReporter();
sessionWebDriverInstanceMap = new ConcurrentHashMap();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
xmlReporter.saveXML();
} catch (Exception e) {
if (DEBUG) {
System.out.println("[ERROR] Failed to save report");
e.printStackTrace();
}
}
}
});
}
static TestSessionRecorder getInstance() {
return InstanceHolder.INSTANCE;
}
RecordedData findAndRemoveEvent(String key, LinkedList queue) {
Iterator iterator = queue.iterator();
while (iterator.hasNext()) {
RecordedData capturedEvent = iterator.next();
if (capturedEvent.data.equals(key)) {
if (DEBUG)
System.out.println(">>> REMOVE: " + capturedEvent.data + " | Count: " + testCases.size());
iterator.remove();
return capturedEvent;
}
}
return null;
}
LinkedList getCapturedTestCases() {
long threadId = Thread.currentThread().getId();
if (!testCases.containsKey(threadId)) {
testCases.put(threadId, new LinkedList());
}
return testCases.get(threadId);
}
LinkedList getCapturedWebDrivers() {
long threadId = Thread.currentThread().getId();
if (!webDrivers.containsKey(threadId)) {
webDrivers.put(threadId, new LinkedList());
}
return webDrivers.get(threadId);
}
void captureWebDriver(WebDriverInstance webDriverInstance) {
long threadId = Thread.currentThread().getId();
if (!webDrivers.containsKey(threadId)) {
webDrivers.put(threadId, new LinkedList());
}
webDrivers.get(threadId).add(webDriverInstance);
/*
* Add session id and instance to map for retrieval using sessionId. This is being done because
* old structure is binded with sessionId.
*/
sessionWebDriverInstanceMap.put(webDriverInstance.data, webDriverInstance);
}
boolean isWebDriverCaptured(WebDriverInstance webDriverInstance) {
long threadId = Thread.currentThread().getId();
return webDrivers.containsKey(threadId) && webDrivers.get(threadId).contains(webDriverInstance);
}
EventType getLastEventType() {
long threadId = Thread.currentThread().getId();
if (lastEventType.containsKey(threadId)) {
return lastEventType.get(threadId);
}
return EventType.UNKNOWN;
}
void linkSessionIdToTestCase(String sessionId, UnitTestCase testCase) {
sessionTestMap.put(sessionId, testCase.data);
String projectType = ProjectType.AUTOMATE.toString(); // Default
if (sessionWebDriverInstanceMap.containsKey(sessionId)) {
projectType = sessionWebDriverInstanceMap.get(sessionId).getProjectType().toString();
}
try {
xmlReporter.appendTest(testCase, sessionId, projectType);
} catch (Exception e) {
// ignore?
if (DEBUG)
System.out.println("[ERROR] " + e.getMessage());
}
if (DEBUG)
System.out.println(String.format(">>>> LINK: %s <=> %s <<<<", sessionId, testCase));
}
Map getSessionTestMap() {
return sessionTestMap;
}
void setLastEventType(EventType eventType) {
lastEventType.put(Thread.currentThread().getId(), eventType);
}
String getLastSessionId() {
long threadId = Thread.currentThread().getId();
return lastSessionId.containsKey(threadId) ? lastSessionId.get(threadId) : null;
}
void setLastSessionId(String sessionId) {
lastSessionId.put(Thread.currentThread().getId(), sessionId);
}
Long getTestCaseIndex(JoinPoint joinPoint) {
synchronized (testCaseIndices) {
String testCaseSignature = joinPoint.getSignature().toLongString();
Long index =
testCaseIndices.containsKey(testCaseSignature) ? testCaseIndices.get(testCaseSignature)
: -1L;
testCaseIndices.put(testCaseSignature, ++index);
if (DEBUG)
System.out.println(String.format("%s => %d", testCaseSignature, index));
return index;
}
}
String recordClassHierarchy(Object obj) {
// Stores a list of class names that appear in an object's class hierarchy.
if (obj == null) {
return null;
}
String clazzCanonicalName = obj.getClass().getCanonicalName();
if (!clazzHierarchyMap.containsKey(clazzCanonicalName)) {
Class clazz = obj.getClass();
List clazzList = new ArrayList();
while (clazz != null) {
if (clazz.getCanonicalName().equals(OBJECT_CLASS_NAME)) {
break;
}
clazzList.add(clazz.getCanonicalName());
clazz = clazz.getSuperclass();
}
clazzHierarchyMap.put(clazzCanonicalName, Collections.unmodifiableList(clazzList));
}
return clazzCanonicalName;
}
String findSessionIdForClass(Object obj) {
// Returns any previously recorded sessionId for the object.
// SessionId could have been associated with either the current class or any parent.
if (obj == null || obj.getClass().getCanonicalName() == null) {
return null;
}
for (String clazzName : clazzHierarchyMap.get(obj.getClass().getCanonicalName())) {
if (clazzSessionMap.containsKey(clazzName)) {
return clazzSessionMap.get(clazzName);
}
}
return null;
}
void registerSessionIdForCurrentClass(String sessionId) {
// Each time a webdriver is created, we *try* to record what class it was created in
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
String clazzName = null;
for (StackTraceElement st : stackTrace) {
if (st.isNativeMethod()) {
break;
}
clazzName = st.getClassName();
}
if (clazzName != null) {
clazzSessionMap.put(clazzName, sessionId);
}
}
static String getSignature(JoinPoint joinPoint) {
return joinPoint.getSignature().toString() + "@" + joinPoint.getTarget().hashCode();
}
static void setBuild(DesiredCapabilities capabilities) {
String build = (String) capabilities.getCapability(BROWSERSTACK_CAPABILITY_BUILD);
if (build == null || build.trim().length() == 0) {
String buildTag = System.getenv(ENV_BROWSERSTACK_BUILD);
if (buildTag != null && buildTag.trim().length() > 0) {
capabilities.setCapability(BROWSERSTACK_CAPABILITY_BUILD, buildTag.trim());
}
}
}
static boolean isBrowserStackWebDriver(JoinPoint joinPoint) {
Object[] constructorArgs = joinPoint.getArgs();
if (constructorArgs.length > 0) {
URL hubUrl = null;
if (constructorArgs[0] instanceof URL) {
hubUrl = (URL) constructorArgs[0];
} else if (constructorArgs[0] instanceof HttpCommandExecutor) {
hubUrl = ((HttpCommandExecutor) constructorArgs[0]).getAddressOfRemoteServer();
}
if (hubUrl != null && hubUrl.toString().contains(HUB_BROWSERSTACK_COM)) {
return true;
}
}
return false;
}
}