Skip to content

Commit 3163a25

Browse files
Babcock, ScottBabcock, Scott
authored andcommitted
Merge pull request #5 in MFATT/junit-foundation from pr/revise-default-artifact-path to master
* commit 'fff78e233680aaf5a61c67345bd55173ac5572b3': Finish JavaDoc Add JavaDoc Revise hook install to prevent re-application
2 parents ac774e1 + fff78e2 commit 3163a25

File tree

5 files changed

+126
-22
lines changed

5 files changed

+126
-22
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<properties>
1515
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1616
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
17-
<nordstrom-common.version>1.2.2.0</nordstrom-common.version>
17+
<nordstrom-common.version>1.3.0.0</nordstrom-common.version>
1818
<surefire-plugin.version>2.19.1</surefire-plugin.version>
1919
<compiler-plugin.version>3.6.0</compiler-plugin.version>
2020
<source-plugin.version>3.0.1</source-plugin.version>

src/main/java/com/nordstrom/automation/junit/ArtifactCollector.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import java.io.IOException;
44
import java.nio.file.Files;
55
import java.nio.file.Path;
6-
import java.nio.file.Paths;
76
import java.util.ArrayList;
87
import java.util.Arrays;
98
import java.util.List;
@@ -109,8 +108,8 @@ public Optional<Path> captureArtifact(Throwable reason) {
109108
* @return path of artifact storage directory
110109
*/
111110
private Path getCollectionPath() {
112-
Path collectionPath = Paths.get(System.getProperty("user.dir"));
113-
return collectionPath.resolve(provider.getArtifactPath());
111+
Path collectionPath = PathUtils.ReportsDirectory.getPathForObject(instance);
112+
return collectionPath.resolve(provider.getArtifactPath(instance));
114113
}
115114

116115
/**

src/main/java/com/nordstrom/automation/junit/ArtifactType.java

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,73 @@
11
package com.nordstrom.automation.junit;
22

33
import java.nio.file.Path;
4-
import java.nio.file.Paths;
5-
64
import org.slf4j.Logger;
75

6+
import com.nordstrom.common.file.PathUtils;
7+
8+
/**
9+
* This interface defines the contract fulfilled by artifact capture providers. Instances of this interface supply the
10+
* scenario-specify implementation for artifact capture through the {@link ArtifactCollector} listener.
11+
* <br><br>
12+
* <b>IMPLEMENTING ARTIFACTTYPE</b>
13+
* <pre><code>
14+
* package com.nordstrom.example;
15+
*
16+
* import java.nio.file.Path;
17+
*
18+
* import org.slf4j.Logger;
19+
* import org.slf4j.LoggerFactory;
20+
* import org.testng.ITestResult;
21+
*
22+
* import com.nordstrom.automation.junit.ArtifactType;
23+
*
24+
* public class MyArtifactType implements ArtifactType {
25+
*
26+
* private static final String ARTIFACT_PATH = "artifacts";
27+
* private static final String EXTENSION = "txt";
28+
* private static final String ARTIFACT = "This text artifact was captured for '%s'";
29+
* private static final Logger LOGGER = LoggerFactory.getLogger(MyArtifactType.class);
30+
*
31+
* &#64;Override
32+
* public boolean canGetArtifact(Object instance) {
33+
* return true;
34+
* }
35+
*
36+
* &#64;Override
37+
* public byte[] getArtifact(Object instance, Throwable reason) {
38+
* return String.format(ARTIFACT, instance.getSimpleName()).getBytes().clone();
39+
* }
40+
*
41+
* &#64;Override
42+
* public Page getArtifactPath(Object instance) {
43+
* return ArtifactType.super.getArtifactPath(instance).resolve(ARTIFACT_PATH);
44+
* }
45+
*
46+
* &#64;Override
47+
* public String getArtifactExtension() {
48+
* return EXTENSION;
49+
* }
50+
*
51+
* &#64;Override
52+
* public Logger getLogger() {
53+
* return LOGGER;
54+
* }
55+
* }
56+
* </code></pre>
57+
* <b>CREATING A TYPE-SPECIFIC ARTIFACT COLLECTOR</b>
58+
* <pre><code>
59+
* package com.nordstrom.example;
60+
*
61+
* import com.nordstrom.automation.testng.ArtifactCollector;
62+
*
63+
* public class MyArtifactCapture extends ArtifactCollector<MyArtifactType> {
64+
*
65+
* public MyArtifactCapture() {
66+
* super(new MyArtifactType());
67+
* }
68+
* }
69+
* </code></pre>
70+
*/
871
public interface ArtifactType {
972

1073
/**
@@ -34,12 +97,14 @@ public interface ArtifactType {
3497
/**
3598
* Get the path at which to store artifacts.
3699
*
100+
* @param instance JUnit test class instance
37101
* @return artifact storage path
38102
*/
39-
default Path getArtifactPath() {
40-
return Paths.get("");
103+
default Path getArtifactPath(Object instance) {
104+
return PathUtils.ReportsDirectory.getPathForObject(instance);
41105
}
42106

107+
43108
/**
44109
* Get the extension for artifact files of this type.
45110
* <br><br>

src/main/java/com/nordstrom/automation/junit/HookInstallingPlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class HookInstallingPlugin implements Plugin {
1717

1818
@Override
1919
public boolean matches(TypeDescription target) {
20-
return true;
20+
return ! target.isAssignableTo(Hooked.class);
2121
}
2222

2323
@Override

src/main/java/com/nordstrom/automation/junit/HookInstallingRunner.java

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
import static net.bytebuddy.matcher.ElementMatchers.*;
44

5+
import java.util.HashMap;
6+
import java.util.Map;
7+
58
import org.junit.After;
69
import org.junit.Before;
710
import org.junit.Test;
811
import org.junit.runners.BlockJUnit4ClassRunner;
912
import org.junit.runners.model.InitializationError;
1013

1114
import com.nordstrom.common.base.UncheckedThrow;
15+
import com.nordstrom.common.file.PathUtils.ReportsDirectory;
1216

1317
import net.bytebuddy.ByteBuddy;
1418
import net.bytebuddy.implementation.MethodDelegation;
@@ -21,6 +25,8 @@
2125
*/
2226
public final class HookInstallingRunner extends BlockJUnit4ClassRunner {
2327

28+
private static Map<Class<?>, Class<?>> proxyMap = new HashMap<>();
29+
2430
public HookInstallingRunner(Class<?> klass) throws InitializationError {
2531
super(klass);
2632
}
@@ -39,28 +45,36 @@ public Object createTest() throws Exception {
3945
* @param testObj test class object to be enhanced
4046
* @return enhanced test class object
4147
*/
42-
private Object installHooks(Object testObj) {
48+
private synchronized Object installHooks(Object testObj) {
4349
Class<?> testClass = testObj.getClass();
4450
MethodInterceptor.attachWatchers(testClass);
4551

4652
if (testObj instanceof Hooked) {
4753
return testObj;
4854
}
4955

50-
try {
51-
52-
Class<?> proxyType = new ByteBuddy()
53-
.subclass(testClass)
54-
.method(isAnnotatedWith(anyOf(Test.class, Before.class, After.class)))
55-
.intercept(MethodDelegation.to(MethodInterceptor.class))
56-
.implement(Hooked.class)
57-
.make()
58-
.load(testClass.getClassLoader())
59-
.getLoaded();
56+
Class<?> proxyType = proxyMap.get(testClass);
57+
58+
if (proxyType == null) {
59+
try {
60+
proxyType = new ByteBuddy()
61+
.subclass(testClass)
62+
.name(getSubclassName(testObj))
63+
.method(isAnnotatedWith(anyOf(Test.class, Before.class, After.class)))
64+
.intercept(MethodDelegation.to(MethodInterceptor.class))
65+
.implement(Hooked.class)
66+
.make()
67+
.load(testClass.getClassLoader())
68+
.getLoaded();
69+
proxyMap.put(testClass, proxyType);
70+
} catch (SecurityException | IllegalArgumentException e) {
71+
throw UncheckedThrow.throwUnchecked(e);
72+
}
73+
}
6074

75+
try {
6176
return proxyType.newInstance();
62-
63-
} catch (SecurityException | IllegalAccessException | IllegalArgumentException | InstantiationException e) {
77+
} catch (InstantiationException | IllegalAccessException e) {
6478
throw UncheckedThrow.throwUnchecked(e);
6579
}
6680
}
@@ -75,4 +89,30 @@ public static Class<?> getInstanceClass(Object instance) {
7589
Class<?> clazz = instance.getClass();
7690
return (instance instanceof Hooked) ? clazz.getSuperclass() : clazz;
7791
}
92+
93+
/**
94+
* Get fully-qualified name to use for hooked test class.
95+
*
96+
* @param testObj test class object being hooked
97+
* @return fully-qualified name for hooked subclass
98+
*/
99+
private static String getSubclassName(Object testObj) {
100+
Class<?> testClass = testObj.getClass();
101+
String testClassName = testClass.getSimpleName();
102+
String testPackageName = testClass.getPackage().getName();
103+
ReportsDirectory constant = ReportsDirectory.fromObject(testObj);
104+
105+
switch (constant) {
106+
case FAILSAFE_2:
107+
case FAILSAFE_3:
108+
case SUREFIRE_2:
109+
case SUREFIRE_3:
110+
case SUREFIRE_4:
111+
return testPackageName + ".Hooked" + testClassName;
112+
113+
default:
114+
return testClass.getCanonicalName() + "Hooked";
115+
}
116+
117+
}
78118
}

0 commit comments

Comments
 (0)