Skip to content

Commit

Permalink
Revisions inspired by PR for issue #8
Browse files Browse the repository at this point in the history
  • Loading branch information
sbabcoc committed Jan 8, 2018
1 parent 3cf5381 commit 7db3e4c
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 168 deletions.
87 changes: 70 additions & 17 deletions src/main/java/com/nordstrom/automation/testng/ListenerChain.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
package com.nordstrom.automation.testng;

import com.google.common.collect.Lists;
import org.testng.*;
import org.testng.annotations.*;
import org.testng.internal.InvokedMethod;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;

import org.testng.IAnnotationTransformer;
import org.testng.IAnnotationTransformer2;
import org.testng.IAnnotationTransformer3;
import org.testng.IClassListener;
import org.testng.IConfigurationListener;
import org.testng.IConfigurationListener2;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.IInvokedMethodListener2;
import org.testng.IMethodInstance;
import org.testng.IMethodInterceptor;
import org.testng.ISuite;
import org.testng.ISuiteListener;
import org.testng.ITestClass;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestNGListener;
import org.testng.ITestResult;
import org.testng.annotations.IConfigurationAnnotation;
import org.testng.annotations.IDataProviderAnnotation;
import org.testng.annotations.IFactoryAnnotation;
import org.testng.annotations.IListenersAnnotation;
import org.testng.annotations.ITestAnnotation;
import org.testng.internal.InvokedMethod;

import com.google.common.collect.Lists;

/**
* This TestNG listener enables the addition of other listeners at runtime and guarantees the order in which they're
Expand Down Expand Up @@ -142,10 +171,7 @@ public void transform(IDataProviderAnnotation annotation, Method method) {
*/
@Override
public void transform(IFactoryAnnotation annotation, Method method) {
if(method != null)
attachListeners(method);
else
attachListeners(annotation.getDataProviderClass());
attachListeners(method);

synchronized(annotationXformers2) {
for (IAnnotationTransformer2 annotationXformer : annotationXformers2) {
Expand Down Expand Up @@ -570,14 +596,26 @@ public void onAfterClass(ITestClass testClass) {
* @param listenerType listener type
* @return optional listener instance
*/
@SuppressWarnings("unchecked")
public static <T extends ITestNGListener> Optional<T>
getAttachedListener(ISuite suite, Class<T> listenerType) {

Objects.requireNonNull(suite, "[suite] must be non-null");
Objects.requireNonNull(listenerType, "[listenerType] must be non-null");
ListenerChain chain = (ListenerChain) suite.getAttribute(LISTENER_CHAIN);
for (ITestNGListener listener : chain.listeners) {
Objects.requireNonNull(chain, "Specified suite has no ListenerChain");
return chain.getAttachedListener(listenerType);
}

/**
* Get reference to an instance of the specified listener type.
*
* @param <T> listener type
* @param listenerType listener type
* @return optional listener instance
*/
@SuppressWarnings("unchecked")
public <T extends ITestNGListener> Optional<T> getAttachedListener(Class<T> listenerType) {
for (ITestNGListener listener : listeners) {
if (listener.getClass() == listenerType) {
return Optional.of((T) listener);
}
Expand All @@ -591,7 +629,9 @@ public void onAfterClass(ITestClass testClass) {
* @param testMethod test method
*/
private void attachListeners(Method testMethod) {
attachListeners(testMethod.getDeclaringClass());
if (testMethod != null) {
processLinkedListeners(testMethod.getDeclaringClass());
}
}

/**
Expand All @@ -606,11 +646,11 @@ private void attachListeners(Method testMethod) {
*/
private void attachListeners(Class<?> testClass, Constructor<?> testCtor, Method testMethod) {
if (testClass != null) {
attachListeners(testClass);
processLinkedListeners(testClass);
} else if (testCtor != null) {
attachListeners(testCtor.getDeclaringClass());
} else {
attachListeners(testMethod.getDeclaringClass());
processLinkedListeners(testCtor.getDeclaringClass());
} else if (testMethod != null) {
processLinkedListeners(testMethod.getDeclaringClass());
}
}

Expand All @@ -620,6 +660,19 @@ private void attachListeners(Class<?> testClass, Constructor<?> testCtor, Method
* @param testClass test class
*/
private void attachListeners(Class<?> testClass) {
if (testClass != null) {
processLinkedListeners(testClass);
}
}

/**
* Process the {@link LinkedListeners} annotation of the specified test class.
*
* @param testClass test class
*/
private void processLinkedListeners(Class<?> testClass) {
Objects.requireNonNull(testClass, "[testClass] must be non-null");

LinkedListeners annotation = testClass.getAnnotation(LinkedListeners.class);
if (null != annotation) {
Class<?> markedClass = testClass;
Expand Down
64 changes: 34 additions & 30 deletions src/test/java/com/nordstrom/automation/testng/ChainedListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,39 @@ public class ChainedListener
implements IAnnotationTransformer3, ISuiteListener, IConfigurationListener2,
IInvokedMethodListener, ITestListener, IMethodInterceptor, IClassListener {

static Set<String> configSuccess = Collections.synchronizedSet(new HashSet<>());
static Set<String> configFailure = Collections.synchronizedSet(new HashSet<>());
static Set<String> configSkipped = Collections.synchronizedSet(new HashSet<>());
static Set<String> beforeConfig = Collections.synchronizedSet(new HashSet<>());
Set<String> configSuccess = Collections.synchronizedSet(new HashSet<>());
Set<String> configFailure = Collections.synchronizedSet(new HashSet<>());
Set<String> configSkipped = Collections.synchronizedSet(new HashSet<>());
Set<String> beforeConfig = Collections.synchronizedSet(new HashSet<>());

static Set<String> beforeMethodBefore = Collections.synchronizedSet(new HashSet<>());
static Set<String> beforeMethodAfter = Collections.synchronizedSet(new HashSet<>());
static Set<String> testMethodBefore = Collections.synchronizedSet(new HashSet<>());
static Set<String> testMethodAfter = Collections.synchronizedSet(new HashSet<>());
static Set<String> afterMethodBefore = Collections.synchronizedSet(new HashSet<>());
static Set<String> afterMethodAfter = Collections.synchronizedSet(new HashSet<>());
Set<String> beforeMethodBefore = Collections.synchronizedSet(new HashSet<>());
Set<String> beforeMethodAfter = Collections.synchronizedSet(new HashSet<>());
Set<String> testMethodBefore = Collections.synchronizedSet(new HashSet<>());
Set<String> testMethodAfter = Collections.synchronizedSet(new HashSet<>());
Set<String> afterMethodBefore = Collections.synchronizedSet(new HashSet<>());
Set<String> afterMethodAfter = Collections.synchronizedSet(new HashSet<>());

static Set<String> beforeClass = Collections.synchronizedSet(new HashSet<>());
static Set<String> afterClass = Collections.synchronizedSet(new HashSet<>());
Set<String> beforeClass = Collections.synchronizedSet(new HashSet<>());
Set<String> afterClass = Collections.synchronizedSet(new HashSet<>());

static Set<String> testStarted = Collections.synchronizedSet(new HashSet<>());
static Set<String> testSuccess = Collections.synchronizedSet(new HashSet<>());
static Set<String> testFailure = Collections.synchronizedSet(new HashSet<>());
static Set<String> testSkipped = Collections.synchronizedSet(new HashSet<>());
static Set<String> testCurved = Collections.synchronizedSet(new HashSet<>());
static Set<String> testsBegun = Collections.synchronizedSet(new HashSet<>());
static Set<String> testsEnded = Collections.synchronizedSet(new HashSet<>());
Set<String> testStarted = Collections.synchronizedSet(new HashSet<>());
Set<String> testSuccess = Collections.synchronizedSet(new HashSet<>());
Set<String> testFailure = Collections.synchronizedSet(new HashSet<>());
Set<String> testSkipped = Collections.synchronizedSet(new HashSet<>());
Set<String> testCurved = Collections.synchronizedSet(new HashSet<>());
Set<String> testsBegun = Collections.synchronizedSet(new HashSet<>());
Set<String> testsEnded = Collections.synchronizedSet(new HashSet<>());

static Set<String> suiteBegun = Collections.synchronizedSet(new HashSet<>());
static Set<String> suiteEnded = Collections.synchronizedSet(new HashSet<>());
Set<String> suiteBegun = Collections.synchronizedSet(new HashSet<>());
Set<String> suiteEnded = Collections.synchronizedSet(new HashSet<>());

static Set<String> xformTest = Collections.synchronizedSet(new HashSet<>());
static Set<String> xformConfig = Collections.synchronizedSet(new HashSet<>());
static Set<String> xformProvider = Collections.synchronizedSet(new HashSet<>());
static Set<String> xformFactory = Collections.synchronizedSet(new HashSet<>());
static Set<String> xformListeners = Collections.synchronizedSet(new HashSet<>());
Set<String> xformTest = Collections.synchronizedSet(new HashSet<>());
Set<String> xformConfig = Collections.synchronizedSet(new HashSet<>());
Set<String> xformProvider = Collections.synchronizedSet(new HashSet<>());
Set<String> xformFactory = Collections.synchronizedSet(new HashSet<>());
Set<String> xformListeners = Collections.synchronizedSet(new HashSet<>());

static Set<String> interceptor = Collections.synchronizedSet(new HashSet<>());
Set<String> interceptor = Collections.synchronizedSet(new HashSet<>());

@Override
public void onConfigurationSuccess(ITestResult itr) {
Expand Down Expand Up @@ -191,18 +191,22 @@ public void transform(IConfigurationAnnotation annotation, Class testClass,

@Override
public void transform(IDataProviderAnnotation annotation, Method method) {
xformProvider.add(method.getName());
xformProvider.add("method: " + method.getName());
}

@Override
public void transform(IFactoryAnnotation annotation, Method method) {
xformFactory.add(method.getName());
if (method != null) {
xformFactory.add("method: " + method.getName());
} else {
xformFactory.add("ctor: (unknown)");
}
}

@SuppressWarnings("rawtypes")
@Override
public void transform(IListenersAnnotation annotation, Class testClass) {
xformListeners.add(testClass.getSimpleName());
xformListeners.add("class: " + testClass.getSimpleName());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
package com.nordstrom.automation.testng;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;

public class ConstructorFactory {

public ConstructorFactory(){}

@DataProvider
public Object[] ints(){return new Object[]{1, 2, 3};}

@Factory(dataProvider = "ints", dataProviderClass = ConstructorFactory.class)
public ConstructorFactory(int i){ }

@Test
public void test(){}
}
package com.nordstrom.automation.testng;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;

@LinkedListeners({ChainedListener.class, ExecutionFlowController.class})
public class ConstructorFactory {

public ConstructorFactory() {
}

@Factory(dataProvider = "ints")
public ConstructorFactory(final int i) {
// not important
}

@DataProvider
public Object[] ints() {
return new Object[]{1, 2, 3};
}

@Test
public void fakeTest() {
// not important
}
}
Loading

0 comments on commit 7db3e4c

Please sign in to comment.