Skip to content

Commit 82f0cb4

Browse files
author
Mike Reiche
authored
Merge pull request #151 from telekom/bugfix/intercept-crashing-dataproviders
Added MethodContext to execution even when the DataProvider crashes. …
2 parents 90142f7 + a0ef4bd commit 82f0cb4

File tree

7 files changed

+129
-137
lines changed

7 files changed

+129
-137
lines changed

core/src/main/java/eu/tsystems/mms/tic/testframework/execution/testng/ListenerUtils.java

Lines changed: 0 additions & 87 deletions
This file was deleted.

core/src/main/java/eu/tsystems/mms/tic/testframework/execution/testng/RetryAnalyzer.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,7 @@ private boolean shouldRetry(ITestResult testResult, MethodContext methodContext)
135135
return false;
136136
}
137137

138-
boolean retry = false;
139138
final String testMethodName = methodContext.getName();
140-
String retryReason = null;
141139

142140
/*
143141
check retry counter
@@ -174,13 +172,6 @@ private boolean shouldRetry(ITestResult testResult, MethodContext methodContext)
174172

175173
boolean containingFilteredThrowable = isTestResultContainingFilteredThrowable(testResult);
176174
if (containingFilteredThrowable) {
177-
retry = true;
178-
}
179-
180-
/*
181-
* process retry
182-
*/
183-
if (retry) {
184175
methodHasBeenRetried(methodContext);
185176
RETRIED_METHODS.add(methodContext);
186177

core/src/main/java/eu/tsystems/mms/tic/testframework/execution/testng/worker/start/MethodStartWorker.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ private void addRetryAnalyzer(MethodStartEvent event) {
5757
Method method = event.getMethod();
5858
if (retryAnalyzer == null || retryAnalyzer instanceof DisabledRetryAnalyzer) {
5959
testNGMethod.setRetryAnalyzerClass(RetryAnalyzer.class);
60-
} else {
61-
log().info("Using a non-default retry analyzer: " + retryAnalyzer + " on " + method.getName());
60+
} else if (!(retryAnalyzer instanceof RetryAnalyzer)){
61+
log().info("Using a non-default retry analyzer: " + retryAnalyzer.getClass().getSimpleName() + " on " + method.getName());
6262
}
6363
}
6464
}

core/src/main/java/eu/tsystems/mms/tic/testframework/report/TesterraListener.java

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import eu.tsystems.mms.tic.testframework.events.MethodEndEvent;
3434
import eu.tsystems.mms.tic.testframework.events.MethodStartEvent;
3535
import eu.tsystems.mms.tic.testframework.exceptions.SystemException;
36-
import eu.tsystems.mms.tic.testframework.execution.testng.ListenerUtils;
3736
import eu.tsystems.mms.tic.testframework.execution.testng.worker.finish.MethodContextUpdateWorker;
3837
import eu.tsystems.mms.tic.testframework.execution.testng.worker.finish.MethodEndWorker;
3938
import eu.tsystems.mms.tic.testframework.execution.testng.worker.start.MethodParametersWorker;
@@ -50,12 +49,16 @@
5049
import eu.tsystems.mms.tic.testframework.report.model.steps.TestStep;
5150
import eu.tsystems.mms.tic.testframework.report.utils.DefaultTestNGContextGenerator;
5251
import eu.tsystems.mms.tic.testframework.report.utils.ExecutionContextController;
52+
import java.util.Date;
53+
import java.util.Locale;
54+
import java.util.concurrent.ConcurrentHashMap;
5355
import org.apache.logging.log4j.Level;
5456
import org.apache.logging.log4j.core.LoggerContext;
5557
import org.apache.logging.log4j.core.config.Configurator;
5658
import org.apache.logging.log4j.core.config.DefaultConfiguration;
5759
import org.testng.IConfigurable;
5860
import org.testng.IConfigureCallBack;
61+
import org.testng.IDataProviderListener;
5962
import org.testng.IHookCallBack;
6063
import org.testng.IHookable;
6164
import org.testng.IInvokedMethod;
@@ -70,10 +73,10 @@
7073
import org.testng.ITestNGMethod;
7174
import org.testng.ITestResult;
7275
import org.testng.annotations.Test;
76+
import org.testng.internal.InvokedMethod;
77+
import org.testng.internal.TestResult;
7378
import org.testng.xml.XmlSuite;
74-
7579
import java.util.List;
76-
import java.util.Locale;
7780

7881
/**
7982
* Listener for JUnit and TestNg, collects test informations for testreport.
@@ -88,7 +91,9 @@ public class TesterraListener implements
8891
IMethodInterceptor,
8992
ITestListener,
9093
ISuiteListener,
91-
Loggable {
94+
Loggable,
95+
IDataProviderListener
96+
{
9297
/**
9398
* Default package namespace for project tests
9499
*/
@@ -111,6 +116,7 @@ public class TesterraListener implements
111116
private static final Report report;
112117
private static DefaultTestNGContextGenerator contextGenerator;
113118
private static final TestStatusController testStatusController = new TestStatusController();
119+
private static final ConcurrentHashMap<ITestNGMethod, Boolean> dataProviderSemaphore = new ConcurrentHashMap<>();
114120

115121
static {
116122
String logLevel = PropertyManager.getProperty("log4j.level");
@@ -276,30 +282,28 @@ public void beforeInvocation(
276282
* @param testResult result of invoked method.
277283
* @param testContext
278284
*/
279-
private void pBeforeInvocation(
285+
private MethodContext pBeforeInvocation(
280286
IInvokedMethod invokedMethod,
281287
ITestResult testResult,
282288
ITestContext testContext
283289
) {
284290
final String methodName = getMethodName(testResult);
285291

286-
if (ListenerUtils.wasMethodInvokedBefore("beforeInvocationFor" + methodName, invokedMethod, testResult)) {
287-
return;
288-
}
292+
// if (ListenerUtils.wasMethodInvokedBefore("beforeInvocationFor" + methodName, invokedMethod, testResult)) {
293+
// return null;
294+
// }
289295

290296
/*
291297
* store testresult, create method context
292298
*/
293299
MethodContext methodContext = ExecutionContextController.setCurrentTestResult(testResult); // stores the actual testresult, auto-creates the method context
294-
ExecutionContextController.setCurrentMethodContext(methodContext);
295-
296300
methodContext.getTestStep(TestStep.SETUP);
297301

298-
final String infoText = "beforeInvocation: " + invokedMethod.getTestMethod().getTestClass().getName() + "." +
299-
methodName +
300-
" - " + Thread.currentThread().getName();
301-
302-
log().trace(infoText);
302+
// final String infoText = "beforeInvocation: " + invokedMethod.getTestMethod().getTestClass().getName() + "." +
303+
// methodName +
304+
// " - " + Thread.currentThread().getName();
305+
//
306+
// log().trace(infoText);
303307

304308
AbstractMethodEvent event = new MethodStartEvent()
305309
.setTestResult(testResult)
@@ -312,6 +316,7 @@ private void pBeforeInvocation(
312316

313317
// We don't close teardown steps, because we want to collect further actions there
314318
//step.close();
319+
return methodContext;
315320
}
316321

317322
/**
@@ -361,38 +366,30 @@ private void pAfterInvocation(
361366
ITestContext testContext
362367
) {
363368

364-
final String methodName;
365-
final String testClassName;
366-
if (invokedMethod != null) {
367-
methodName = invokedMethod.getTestMethod().getMethodName();
368-
testClassName = invokedMethod.getTestMethod().getTestClass().getName();
369-
} else {
370-
methodName = testResult.getMethod().getConstructorOrMethod().getName();
371-
testClassName = testResult.getTestClass().getName();
372-
}
369+
// final String methodName;
370+
// final String testClassName;
371+
// if (invokedMethod != null) {
372+
// methodName = invokedMethod.getTestMethod().getMethodName();
373+
// testClassName = invokedMethod.getTestMethod().getTestClass().getName();
374+
// } else {
375+
// methodName = testResult.getMethod().getConstructorOrMethod().getName();
376+
// testClassName = testResult.getTestClass().getName();
377+
// }
373378

374379
// CHECKSTYLE:ON
375-
if (ListenerUtils.wasMethodInvokedBefore("afterInvocation", testClassName, methodName, testResult, testContext)) {
376-
return;
377-
}
378-
379-
/*
380-
Log
381-
*/
382-
final String infoText = "afterInvocation: " + testClassName + "." + methodName + " - " + Thread.currentThread().getName();
380+
// if (ListenerUtils.wasMethodInvokedBefore("afterInvocation", testClassName, methodName, testResult, testContext)) {
381+
// return;
382+
// }
383383

384-
log().trace(infoText);
384+
final String methodName = getMethodName(testResult);
385385

386386
/*
387387
* Get test method container
388388
*/
389389
MethodContext methodContext = ExecutionContextController.getCurrentMethodContext();
390390
if (methodContext == null) {
391391

392-
if (
393-
testResult.getStatus() == ITestResult.CREATED
394-
|| testResult.getStatus() == ITestResult.SKIP
395-
) {
392+
if (testResult.getStatus() == ITestResult.CREATED || testResult.getStatus() == ITestResult.SKIP) {
396393
/*
397394
* TestNG bug or whatever ?!?!
398395
*/
@@ -524,4 +521,25 @@ public void onFinish(ISuite iSuite) {
524521
public static boolean isActive() {
525522
return instances > 0;
526523
}
524+
525+
@Override
526+
public void onDataProviderFailure(ITestNGMethod testNGMethod, ITestContext testContext, RuntimeException exception) {
527+
/**
528+
* TestNG calls the data provider initialization for every thread.
529+
* Added a semaphore to prevent adding multiple method contexts.
530+
*/
531+
if (!dataProviderSemaphore.containsKey(testNGMethod)) {
532+
TestResult testResult = TestResult.newContextAwareTestResult(testNGMethod, testContext);
533+
InvokedMethod invokedMethod = new InvokedMethod(new Date().getTime(), testResult);
534+
MethodContext methodContext = pBeforeInvocation(invokedMethod, testResult, testContext);
535+
if (exception.getCause() != null) {
536+
methodContext.addError(exception.getCause());
537+
} else {
538+
methodContext.addError(exception);
539+
}
540+
pAfterInvocation(invokedMethod, testResult, testContext);
541+
542+
dataProviderSemaphore.put(testNGMethod, true);
543+
}
544+
}
527545
}

core/src/main/java/eu/tsystems/mms/tic/testframework/report/utils/ExecutionContextController.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,17 @@ public static MethodContext getMethodContextFromTestContextAndMethod(ITestContex
128128
*/
129129
public static MethodContext setCurrentTestResult(ITestResult iTestResult) {
130130
CURRENT_TEST_RESULT.set(iTestResult);
131-
return getMethodContextFromTestResult(iTestResult);
131+
MethodContext methodContext = getMethodContextFromTestResult(iTestResult);
132+
setCurrentMethodContext(methodContext);
133+
return methodContext;
132134
}
133135

134136
/**
135137
* Set currently active test.
136138
*
137139
* @param methodContext Method Context.
138140
*/
139-
public static void setCurrentMethodContext(final MethodContext methodContext) {
141+
private static void setCurrentMethodContext(final MethodContext methodContext) {
140142
CURRENT_METHOD_CONTEXT.set(methodContext);
141143
}
142144

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Testerra
3+
*
4+
* (C) 2021, Mike Reiche, T-Systems Multimedia Solutions GmbH, Deutsche Telekom AG
5+
*
6+
* Deutsche Telekom AG and all other contributors /
7+
* copyright owners license this file to you under the Apache
8+
* License, Version 2.0 (the "License"); you may not use this
9+
* file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
package eu.tsystems.mms.tic.testframework.test.common;
23+
24+
import eu.tsystems.mms.tic.testframework.annotations.Fails;
25+
import eu.tsystems.mms.tic.testframework.testing.TesterraTest;
26+
import org.testng.Assert;
27+
import org.testng.annotations.Test;
28+
29+
public class DataProviderTest extends TesterraTest {
30+
31+
@Test(dataProviderClass = MyDataProvider.class, dataProvider = "throwException")
32+
@Fails
33+
public void test_interceptCrashedDataProvider() {
34+
Assert.assertTrue(true);
35+
}
36+
37+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Testerra
3+
*
4+
* (C) 2021, Mike Reiche, T-Systems Multimedia Solutions GmbH, Deutsche Telekom AG
5+
*
6+
* Deutsche Telekom AG and all other contributors /
7+
* copyright owners license this file to you under the Apache
8+
* License, Version 2.0 (the "License"); you may not use this
9+
* file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
package eu.tsystems.mms.tic.testframework.test.common;
23+
24+
import org.testng.annotations.DataProvider;
25+
26+
public class MyDataProvider {
27+
@DataProvider
28+
public static Object[][] throwException() {
29+
throw new RuntimeException("I was told to throw that.");
30+
}
31+
}

0 commit comments

Comments
 (0)