/*******************************************************************************
* ATE, Automation Test Engine
*
* Copyright 2015, Montreal PROT, or individual contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Montreal PROT.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package org.bigtester.ate.model.casestep;//NOPMD
import java.util.ArrayList;
import java.util.List;
import org.bigtester.ate.GlobalUtils;
import org.bigtester.ate.annotation.StepLoggable;
import org.bigtester.ate.constant.StepResultStatus;
import org.bigtester.ate.model.AbstractATEException;
import org.bigtester.ate.model.casestep.RepeatStepInOutEvent.RepeatStepInOut;
import org.bigtester.ate.model.data.IOnTheFlyData;
import org.bigtester.ate.model.data.IRepeatIncrementalIndex;
import org.bigtester.ate.model.data.IStepERValue;
import org.bigtester.ate.model.data.IStepInputData;
import org.bigtester.ate.model.data.exception.RuntimeDataException;
import org.bigtester.ate.model.page.atewebdriver.IMyWebDriver;
import org.bigtester.ate.model.page.exception.PageValidationException;
import org.bigtester.ate.model.page.exception.StepExecutionException;
import org.bigtester.ate.model.utils.ThinkTime;
import org.bigtester.ate.systemlogger.IATEProblemCreator;
import org.bigtester.ate.systemlogger.LogbackWriter;
import org.bigtester.ate.systemlogger.problems.IATEProblem;
import org.eclipse.jdt.annotation.Nullable;
import org.springframework.aop.support.AopUtils;
// TODO: Auto-generated Javadoc
/**
* This class RepeatStep defines ....
*
* @author Peidong Hu
*
*/
public class RepeatStep extends BaseTestStep implements ITestStep, Cloneable {
/** The start step id. */
private String startStepName;
/** The end step id. */
private String endStepName;
/** The continue on failure. */
private boolean continueOnFailure;
/** The asserter value remain same. */
private boolean asserterValuesRemainSame;
/** The repeat times. */
private int numberOfIterations;
/** The step i ds. */
final private List<Integer> repeatingStepIndexesInTestCase = new ArrayList<Integer>();
/** The repeating steps. */
final private List<ITestStep> repeatingSteps = new ArrayList<ITestStep>();
//TODO combine 3 refreshlist into one, no need to differentiate data type.
/** The refresh data values. */
final private List<IStepInputData> dataValuesNeedRefresh = new ArrayList<IStepInputData>();
/** The refresh er values. */
final private List<IStepERValue> erValuesNeedRefresh = new ArrayList<IStepERValue>();
/** The refresh on the fly values. */
final private List<IRepeatIncrementalIndex> repeatIndexValuesNeedRefresh = new ArrayList<IRepeatIncrementalIndex>();
/** The external repeat node of this step. */
private transient @Nullable RepeatStepExecutionLoggerNode externalRepeatNodeOfThisStep;
/** The current repeat node of this step. */
private transient @Nullable RepeatStepExecutionLoggerNode currentRepeatNodeOfThisStep;
// /** The input data holders. */
// final private List<IStepInputData> inputDataHolders;
//
// /** The data parsers. */
// final private List<IDataParser> dataParsers;
//
// final private List<IExpectedResultAsserter> expectedResultAsserters;
/**
* Instantiates a new repeat step.
*
* @param startStepName
* the start step name
* @param endStepName
* the end step name
* @param testCase
* the test case
*/
public RepeatStep(String startStepName, String endStepName) {
super();
this.startStepName = startStepName;
this.endStepName = endStepName;
this.continueOnFailure = false;
this.numberOfIterations = 1;
// this.testCase = testCase;
this.asserterValuesRemainSame = true;
}
private void buildRepeatStepContext() {
repeatingStepIndexesInTestCase.clear();
repeatingSteps.clear();
erValuesNeedRefresh.clear();
dataValuesNeedRefresh.clear();
int startIndex = -1; // NOPMD
int endIndex = -1; // NOPMD
for (int i = 0; i < getTestCase().getTestStepList().size(); i++) {
if (getTestCase().getTestStepList().get(i).getStepName()
.equals(this.startStepName)) {
startIndex = i;// NOPMD
}
if (getTestCase().getTestStepList().get(i).getStepName()
.equals(this.endStepName)) {
endIndex = i;// NOPMD
}
}
if (startIndex == -1 || endIndex == -1)
throw GlobalUtils
.createNotInitializedException("startStepName or endStepName");
for (int i = 0; i < getTestCase().getTestStepList().size(); i++) {
if (i >= startIndex && i <= endIndex) {
repeatingStepIndexesInTestCase.add(i);
ITestStep thisStep = getTestCase().getTestStepList().get(i);
repeatingSteps.add(thisStep);
// TODO in future version, We need to use the pubishevent to
// build these erValuesNeedRefresh list.
// for (int asserterIndex = 0; asserterIndex < thisStep
// .getExpectedResultAsserter().size(); asserterIndex++) {
// erValuesNeedRefresh.add((IStepERValue) GlobalUtils
// .getTargetObject(thisStep
// .getExpectedResultAsserter()
// .get(asserterIndex).getStepERValue()));
// }
// //TODO in future version, We need to use the pubishevent to
// build these dataValuesNeedRefresh list.
// if (thisStep instanceof IElementStep) {
// MyWebElement<?> webE = ((IElementStep) thisStep)
// .getMyWebElement();
// if (webE.getTestObjectAction() instanceof IElementAction) {
// ITestObjectAction<?> iTOA = webE.getTestObjectAction();
// if (null != iTOA
// && ((IElementAction) iTOA).getDataValue() != null) {
// dataValuesNeedRefresh.add((IStepInputData) GlobalUtils
// .getTargetObject(((IElementAction) iTOA)
// .getDataValue()));
// }
// }
// //TODO implement recursive IStepJumpingEnclosedContainer
// which handle recursive steptypeservice
// } else if (thisStep instanceof IStepJumpingEnclosedContainer)
// {
// for (int j=0;
// j<((IStepJumpingEnclosedContainer)thisStep).getContainerStepList().size();
// j++) {
// ITestStep tmpStep =
// ((IStepJumpingEnclosedContainer)thisStep).getContainerStepList().get(j);
// if (tmpStep instanceof IElementStep) {
// MyWebElement<?> webE = ((IElementStep) tmpStep)
// .getMyWebElement();
// if (webE.getTestObjectAction() instanceof IElementAction) {
// ITestObjectAction<?> iTOA = webE.getTestObjectAction();
// if (null != iTOA
// && ((IElementAction) iTOA).getDataValue() != null) {
// dataValuesNeedRefresh.add((IStepInputData) GlobalUtils
// .getTargetObject(((IElementAction) iTOA)
// .getDataValue()));
// }
// }
// }
// }
// }
}
}
}
private void buildStepAssertersNeedRefresh() {
erValuesNeedRefresh.clear();
StepDataLogger sdl = GlobalUtils
.findStepDataLoggerBean(getApplicationContext());
if (null != sdl.getRepeatStepDataRegistry().get(
GlobalUtils.getTargetObject(this))
&& !sdl.getRepeatStepDataRegistry()
.get(GlobalUtils.getTargetObject(this)).isEmpty()) {
for (Object data : sdl.getRepeatStepDataRegistry().get(
GlobalUtils.getTargetObject(this))) {
if (data instanceof IStepERValue) {
erValuesNeedRefresh.add((IStepERValue) data);
}
}
}
}
private void buildStepInputDatasNeedRefresh() {
dataValuesNeedRefresh.clear();
StepDataLogger sdl = GlobalUtils
.findStepDataLoggerBean(getApplicationContext());
if (null != sdl.getRepeatStepDataRegistry().get(
GlobalUtils.getTargetObject(this))
&& !sdl.getRepeatStepDataRegistry()
.get(GlobalUtils.getTargetObject(this)).isEmpty()) {
for (Object data : sdl.getRepeatStepDataRegistry().get(
GlobalUtils.getTargetObject(this))) {
if (data instanceof IStepInputData) {
dataValuesNeedRefresh.add((IStepInputData) data);
}
}
}
}
private void buildRepeatIndexes() {
repeatIndexValuesNeedRefresh.clear();
StepDataLogger sdl = GlobalUtils
.findStepDataLoggerBean(getApplicationContext());
if (null != sdl.getRepeatStepDataRegistry().get(
GlobalUtils.getTargetObject(this))
&& !sdl.getRepeatStepDataRegistry()
.get(GlobalUtils.getTargetObject(this)).isEmpty()) {
for (Object data : sdl.getRepeatStepDataRegistry().get(
GlobalUtils.getTargetObject(this))) {
if (data instanceof IOnTheFlyData<?>
&& data instanceof IRepeatIncrementalIndex) {
repeatIndexValuesNeedRefresh
.add((IRepeatIncrementalIndex) data);
}
}
}
}
/**
* {@inheritDoc}
*/
@StepLoggable(level = org.bigtester.ate.annotation.ATELogLevel.INFO)
@Override
public void doStep(@Nullable IStepJumpingEnclosedContainer jumpingContainer)
throws StepExecutionException, PageValidationException,
RuntimeDataException {
if (null == jumpingContainer)
jumpingContainer = (IStepJumpingEnclosedContainer) GlobalUtils
.getTargetObject(getTestCase());
repeatSteps(jumpingContainer);
}
/**
* run steps.
*
* @throws RuntimeDataException
* @throws StepExecutionException
* @throws PageValidationException
*/
private void repeatSteps(IStepJumpingEnclosedContainer jumpingContainer)
throws StepExecutionException, PageValidationException,
RuntimeDataException {
LogbackWriter.writeDebugInfo(
"entering repeatSteps:" + this.getStepName(), this.getClass());
buildRepeatStepContext();
getApplicationContext().publishEvent(
new RepeatStepInOutEvent(this, RepeatStepInOut.IN));
buildStepAssertersNeedRefresh();
buildStepInputDatasNeedRefresh();
buildRepeatIndexes();
Exception thr = null;// NOPMD
for (int iteration = 1; iteration <= getNumberOfIterations(); iteration++) {
LogbackWriter.writeDebugInfo(
"entering step iteration:" + this.getStepName() + ":"
+ iteration, this.getClass());
setCurrentIteration(iteration);
getApplicationContext().publishEvent(
new RepeatDataRefreshEvent(this, getRepeatStepLogger()
.getCurrentRepeatStepPathNodes(), iteration));
LogbackWriter.writeDebugInfo(
"finish first data refressh in step iteration:"
+ this.getStepName() + ":" + iteration,
this.getClass());
for (int i = 0; i < repeatingStepIndexesInTestCase.size(); i++) {
LogbackWriter.writeDebugInfo(
"run step (index:" + i + "), in iteration:" + iteration
+ " of step:" + this.getStepName(),
this.getClass());// NOPMD
ITestStep currentTestStepTmp = getTestCase().getTestStepList()
.get(repeatingStepIndexesInTestCase.get(i));
if (null == currentTestStepTmp) {
throw new IllegalStateException(
"Test Step List was not successfully initialized by ApplicationContext at list index"
+ i);
} else {
getTestCase().setCurrentTestStep(currentTestStepTmp);
}
if (AopUtils.getTargetClass(currentTestStepTmp) == RepeatStep.class) {
((RepeatStep) GlobalUtils
.getTargetObject(currentTestStepTmp))
.setAsserterValuesRemainSame(this
.isAsserterValuesRemainSame());
((RepeatStep) GlobalUtils
.getTargetObject(currentTestStepTmp))
.setContinueOnFailure(this.continueOnFailure);
LogbackWriter.writeDebugInfo(
"before entering repeat step, current test step in testcase is:"
+ getTestCase().getCurrentTestStep()
.getStepName()
+ ";"
+ " current test step optional value is:"
+ getTestCase().getCurrentTestStep()
.isOptionalStep()
+ " , in iteration:" + iteration
+ " of step:" + this.getStepName(), this
.getClass());
} else {
currentTestStepTmp.setStepDescription(currentTestStepTmp
.getStepDescription()
+ " | "
+ getRepeatStepLogger()
.getCurrentRepeatStepFullPathString());
}
String tmpStepDesc = currentTestStepTmp.getStepDescription();// NOPMD
try {
currentTestStepTmp.doStep(jumpingContainer);// NOPMD
currentTestStepTmp
.setStepResultStatus(StepResultStatus.PASS);
LogbackWriter.writeDebugInfo(
"current test step in testcase is:"
+ getTestCase().getCurrentTestStep()
.getStepName() + ", in iteration:"
+ iteration + " of step:"
+ this.getStepName(), this.getClass());
} catch (Exception e) { // NOPMD
IATEProblem prob;
if (e instanceof IATEProblemCreator) {// NOPMD
prob = ((IATEProblemCreator) e).getAteProblem();
ITestStep exceptionRaisingStep = ((AbstractATEException) e)
.getOriginalStepRaisingException();
if (prob == null) {
if (null == exceptionRaisingStep)
prob = ((IATEProblemCreator) e)
.initAteProblemInstance(currentTestStepTmp);
else
prob = ((IATEProblemCreator) e)
.initAteProblemInstance(exceptionRaisingStep);
}
boolean optionalStepRaisingException = false;// NOPMD
if (exceptionRaisingStep != null)
optionalStepRaisingException = exceptionRaisingStep
.isOptionalStep(); // NOPMD
if (!prob.isFatalProblem()
&& prob.getStepIndexSkipTo() > -1) { // NOPMD
i = repeatingStepIndexesInTestCase.indexOf(prob
.getStepIndexSkipTo()); // NOPMD
if (-1 == i)
thr = e;
if (AopUtils.getTargetClass(currentTestStepTmp) == RepeatStep.class)
currentTestStepTmp
.setStepResultStatus(StepResultStatus.NEUTRAL);
else
currentTestStepTmp
.setStepResultStatus(StepResultStatus.SKIP);
} else if (!prob.isFatalProblem()
&& optionalStepRaisingException) {
int correlatedOptionalStepsUtilInclusiveIndex = -1;// NOPMD
if (exceptionRaisingStep != null)
correlatedOptionalStepsUtilInclusiveIndex = exceptionRaisingStep
.getCorrelatedOptionalStepsUtilInclusiveIndex((IStepJumpingEnclosedContainer) GlobalUtils
.getTargetObject(getTestCase())); // NOPMD
if (correlatedOptionalStepsUtilInclusiveIndex > repeatingStepIndexesInTestCase
.get(i)) {
i = repeatingStepIndexesInTestCase
.indexOf(correlatedOptionalStepsUtilInclusiveIndex);// NOPMD
if (-1 == i) {
prob.setStepIndexSkipTo(correlatedOptionalStepsUtilInclusiveIndex);
thr = e;// NOPMD
}
}
if (AopUtils.getTargetClass(currentTestStepTmp) == RepeatStep.class)
currentTestStepTmp
.setStepResultStatus(StepResultStatus.NEUTRAL);
else
currentTestStepTmp
.setStepResultStatus(StepResultStatus.SKIP);
} else {
if (!this.continueOnFailure)
thr = e;// NOPMD
}
} else {
thr = e;// If exception was not handled, we don't know
// what the exception/throwable could cause in
// the ate, so we just stop the testcase.
}
}
if (AopUtils.getTargetClass(currentTestStepTmp) == RepeatStep.class) {
getApplicationContext().publishEvent(
new RepeatDataRefreshEvent(this,
getRepeatStepLogger()
.getCurrentRepeatStepPathNodes(),
iteration));
LogbackWriter.writeDebugInfo(
"finish 2nd data refressh in step iteration:"
+ this.getStepName() + ":" + iteration
+ ", triggered by:"
+ currentTestStepTmp.getStepName(),
this.getClass());
LogbackWriter.writeDebugInfo(
"before entering repeat step, current test step in testcase is:"
+ getTestCase().getCurrentTestStep()
.getStepName()
+ ";"
+ " current test step optional value is:"
+ getTestCase().getCurrentTestStep()
.isOptionalStep()
+ " , in iteration:" + iteration
+ " of step:" + this.getStepName(), this
.getClass());
}
getTestCase().setCurrentTestStep(currentTestStepTmp);
if (null == tmpStepDesc)
tmpStepDesc = ""; // NOPMD
else
currentTestStepTmp.setStepDescription(tmpStepDesc);
if (getTestCase().getStepThinkTime() > 0) {
ThinkTime thinkTimer = new ThinkTime(getTestCase()
.getStepThinkTime());
thinkTimer.setTimer();
}
if (null != thr) {
LogbackWriter.writeDebugInfo(
"exit repeat steps due to exception, step (index:"
+ i + "), in iteration:" + iteration
+ " of step:" + this.getStepName(),
this.getClass());
break;
}
LogbackWriter.writeDebugInfo(
"finish repeatingsteps iteration normally, step (index:"
+ i
+ " stepname: "
+ getTestCase().getTestStepList().get(i)
.getStepName() + "), in iteration:"
+ iteration + " of step:" + this.getStepName(),
this.getClass());
LogbackWriter
.writeDebugInfo(
"total repeating steps number is:"
+ repeatingStepIndexesInTestCase.size()
+ " and last repeating step is: "
+ getTestCase()
.getTestStepList()
.get(repeatingStepIndexesInTestCase
.get(repeatingStepIndexesInTestCase
.size() - 1))
.getStepName()
+ ", in iteration:" + iteration
+ " of step:" + this.getStepName(),
this.getClass());
}
if (null != thr) {
LogbackWriter.writeDebugInfo(
"exit repeat iteration due to exception, in iteration:"
+ iteration + " of step:" + this.getStepName(),
this.getClass());
break;
}
LogbackWriter
.writeDebugInfo(
"exit repeat iteration normally, in iteration:"
+ iteration + " of step:"
+ this.getStepName(), this.getClass());
}
getApplicationContext().publishEvent(
new RepeatStepInOutEvent(this, RepeatStepInOut.OUT));
if (null != thr) {
if (thr instanceof StepExecutionException)
throw (StepExecutionException) thr;
else if (thr instanceof PageValidationException)
throw (PageValidationException) thr;
else if (thr instanceof RuntimeDataException)
throw (RuntimeDataException) thr;
else
throw GlobalUtils
.createInternalError("uncaught throwable", thr);
}
}
/**
* @return the startStepID
*/
public String getStartStepName() {
return startStepName;
}
/**
* @param startStepName
* the startStepID to set
*/
public void setStartStepName(String startStepName) {
this.startStepName = startStepName;
}
/**
* @return the endStepID
*/
public String getEndStepName() {
return endStepName;
}
/**
* @param endStepName
* the endStepID to set
*/
public void setEndStepName(String endStepName) {
this.endStepName = endStepName;
}
/**
* @return the continueOnFailure
*/
public boolean isContinueOnFailure() {
return continueOnFailure;
}
/**
* @param continueOnFailure
* the continueOnFailure to set
*/
public void setContinueOnFailure(boolean continueOnFailure) {
this.continueOnFailure = continueOnFailure;
}
/**
* @return the repeatTimes
*/
public int getNumberOfIterations() {
return numberOfIterations;
}
/**
* @param numberOfIterations
* the repeatTimes to set
*/
public void setNumberOfIterations(int numberOfIterations) {
this.numberOfIterations = numberOfIterations;
}
/**
* {@inheritDoc}
*/
@Override
@Nullable
public IMyWebDriver getMyWebDriver() {
// TODO Auto-generated method stub
return null;
}
/**
* {@inheritDoc}
*/
public RepeatStep clone() throws CloneNotSupportedException {
RepeatStep retVal = (RepeatStep) super.clone();
if (null == retVal)
throw GlobalUtils.createInternalError("jvm clone");
return retVal;
}
/**
* @return the asserterValueRemainSame
*/
public boolean isAsserterValuesRemainSame() {
return asserterValuesRemainSame;
}
/**
* @param asserterValueRemainSame
* the asserterValueRemainSame to set
*/
public void setAsserterValuesRemainSame(boolean asserterValueRemainSame) {
this.asserterValuesRemainSame = asserterValueRemainSame;
}
/**
* @return the externalRepeatNodeOfThisStep
*/
@Nullable
public RepeatStepExecutionLoggerNode getExternalRepeatNodeOfThisStep() {
return externalRepeatNodeOfThisStep;
}
/**
* @param externalRepeatNodeOfThisStep
* the externalRepeatNodeOfThisStep to set
*/
public void setExternalRepeatNodeOfThisStep(
RepeatStepExecutionLoggerNode externalRepeatNodeOfThisStep) {
this.externalRepeatNodeOfThisStep = externalRepeatNodeOfThisStep;
}
/**
* @return the currentRepeatNodeOfThisStep
*/
@Nullable
public RepeatStepExecutionLoggerNode getCurrentRepeatNodeOfThisStep() {
return currentRepeatNodeOfThisStep;
}
/**
* @param currentRepeatNodeOfThisStep
* the currentRepeatNodeOfThisStep to set
*/
public void setCurrentRepeatNodeOfThisStep(
RepeatStepExecutionLoggerNode currentRepeatNodeOfThisStep) {
this.currentRepeatNodeOfThisStep = currentRepeatNodeOfThisStep;
}
/**
* @return the repeatingStepIndexesInTestCase
*/
public final List<Integer> getRepeatingStepIndexesInTestCase() {
return repeatingStepIndexesInTestCase;
}
/**
* @return the repeatingSteps
*/
public final List<ITestStep> getRepeatingSteps() {
return repeatingSteps;
}
/**
* @return the dataValuesNeedRefresh
*/
public final List<IStepInputData> getDataValuesNeedRefresh() {
return dataValuesNeedRefresh;
}
/**
* @return the erValuesNeedRefresh
*/
public final List<IStepERValue> getErValuesNeedRefresh() {
return erValuesNeedRefresh;
}
/**
* @return the repeatIndexValuesNeedRefresh
*/
public final List<IRepeatIncrementalIndex> getRepeatIndexValuesNeedRefresh() {
return repeatIndexValuesNeedRefresh;
}
}