Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#121] Shared Patterns - use latest patterns of given suite name #286

Merged
merged 4 commits into from
Jul 11, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ All notable changes to AET will be documented in this file.
- [PR-268](https://github.com/Cognifide/aet/pull/268) Bobcat upgrade to version 1.4.0
- [PR-279](https://github.com/Cognifide/aet/pull/279) Upgrade for some of libraries used by AET
- [PR-281](https://github.com/Cognifide/aet/pull/281) No version in Bundle names (simpler deployment)
- [PR-286](https://github.com/Cognifide/aet/pull/286) Shared Patterns - use latest patterns of given suite name ([#121](https://github.com/Cognifide/aet/issues/121))

## Version 2.1.6

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ public class RunTestSuiteMojo extends AbstractMojo {
private String domain;

@Parameter(property = "pattern")
private String pattern;
private String patternCorrelationId;

@Parameter(property = "patternSuite")
private String patternSuite;

@Parameter(property = "timeout", defaultValue = "300000")
private int timeout;
Expand All @@ -61,7 +64,7 @@ public void execute() throws MojoExecutionException {
validateConfiguration();
try {
TestSuiteRunner testSuiteRunner = new TestSuiteRunner(endpointDomain,
mavenProject.getBuild().getDirectory(), timeout, name, domain, pattern, xUnit);
mavenProject.getBuild().getDirectory(), timeout, name, domain, patternCorrelationId, patternSuite, xUnit);
testSuiteRunner.runTestSuite(testSuite);

} catch (AETException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,8 @@ public class TestSuiteRunner {

private static final String DATE_FORMAT = "HH:mm:ss.SSS";

private static final ThreadLocal<DateFormat> DATE_FORMATTER = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat(DATE_FORMAT);
}
};
private static final ThreadLocal<DateFormat> DATE_FORMATTER =
ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_FORMAT));

private static final int STATUS_CHECK_INTERVAL_MILLIS = 1000;

Expand All @@ -64,19 +60,22 @@ protected DateFormat initialValue() {

private final String patternCorrelationId;

private final String patternSuite;

private final boolean xUnit;


public TestSuiteRunner(String endpointDomain, String buildDirectory, int timeout,
String name, String domain,
String patternCorrelationId, boolean xUnit) {
String patternCorrelationId, String patternSuite, boolean xUnit) {
this.redirectWriter = new RedirectWriter(buildDirectory);
this.buildDirectory = buildDirectory;
this.timeout = timeout;
this.endpointDomain = endpointDomain;
this.name = name;
this.domain = domain;
this.patternCorrelationId = patternCorrelationId;
this.patternSuite = patternSuite;
this.xUnit = xUnit;
suiteExecutionResponseHandler = new JsonResponseHandler<>(SuiteExecutionResult.class);
suiteStatusResponseHandler = new JsonResponseHandler<>(SuiteStatusResult.class);
Expand Down Expand Up @@ -140,6 +139,9 @@ private SuiteExecutionResult startSuiteExecution(File testSuite) {
if (patternCorrelationId != null) {
entityBuilder.addTextBody("pattern", patternCorrelationId);
}
if (patternSuite != null) {
entityBuilder.addTextBody("patternSuite", patternSuite);
}
HttpEntity entity = entityBuilder.build();

return retrieveSuiteExecutionResult(entity, timeout);
Expand Down
1 change: 1 addition & 0 deletions client/client-scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Usage:
Options:
-d --domain <DOMAIN> - Override domain attribute defined in suite file
-c --correlationId <CORRELATION_ID> - Set id of patterns to run test against
-p --patternSuite <SUITE_NAME> - Set the suite name to run test against its latest pattern (only used if -c is not set)
-i --interval <POLL_INTERVAL> - Set interval in seconds for polling suite status. Default interval : 1 sec
-w --waitForUnlock <TIMEOUT> - Set timeout for the script to wait for unlocked suite. Default timeout: 0 sec
-v --verbose - Make it more descriptive
Expand Down
10 changes: 9 additions & 1 deletion client/client-scripts/aet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ SUITE_ENDPOINT="/suite"
DOMAIN_BODY=""
SUITE_NAME_BODY=""
CORRELATION_ID_BODY=""
PATTERN_SUITE_BODY=""
function usage {
echo
echo "AET Test executor"
Expand All @@ -35,6 +36,7 @@ function usage {
echo -e "\t-d --domain <DOMAIN> - Override domain attribute defined in suite file"
echo -e "\t-n --name <SUITE_NAME> - Override name attribute defined in suite file"
echo -e "\t-c --correlationId <CORRELATION_ID> - Set id of patterns to run test against."
echo -e "\t-p --patternSuite <SUITE_NAME> - Set the suite name to run test against its latest pattern (only used if -c is not set)"
echo -e "\t-i --interval <POLL_INTERVAL> - Set interval in seconds for polling suite status. Default interval : 1 sec."
echo -e "\t-w --waitForUnlock <TIMEOUT> - Set timeout for the script to wait for unlocked suite. Default timeout: 0 sec."
echo -e "\t-v --verbose - Make it more descriptive"
Expand Down Expand Up @@ -87,7 +89,7 @@ function process_locked_suite {

# request /suite endpoint
function start_suite {
run_response=$(curl -sw "%{http_code}" -F "suite=@$suite_file_name"$DOMAIN_BODY$SUITE_NAME_BODY$CORRELATION_ID_BODY "$endpoint$SUITE_ENDPOINT")
run_response=$(curl -sw "%{http_code}" -F "suite=@$suite_file_name"$DOMAIN_BODY$SUITE_NAME_BODY$CORRELATION_ID_BODY$PATTERN_SUITE_BODY "$endpoint$SUITE_ENDPOINT")
extract_code_and_body "$run_response"

if [ $code -eq 200 ]; then
Expand Down Expand Up @@ -131,6 +133,11 @@ while [[ $# -gt 0 ]]; do
CORRELATION_ID_BODY=" -F pattern=$CORRELATION_ID"
shift 2
;;
-p | --patternSuite )
PATTERN_SUITE=$2
PATTERN_SUITE_BODY=" -F patternSuite=$PATTERN_SUITE"
shift 2
;;
-v | --verbose )
VERBOSE=1
shift 1
Expand All @@ -148,6 +155,7 @@ if [[ $VERBOSE -eq 1 ]]; then
echo -e "\tOverridden domain: ${DOMAIN-not set}"
echo -e "\tOverridden suite name: ${SUITE_NAME-not set}"
echo -e "\tPattern id: ${CORRELATION_ID-not set}"
echo -e "\tPattern suite: ${PATTERN_SUITE-not set}"
echo ""
fi

Expand Down
3 changes: 2 additions & 1 deletion documentation/src/main/wiki/ClientApplication.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ mvn aet:run -DtestSuite=FULL_PATH_TO_TEST_SUITE
| `name` | Overrides the *name* parameter value from the test suite definition. | - | no |
| `domain` | Overrides the *domain* parameter value from the test suite definition. | - | no |
| `timeout` | Milliseconds to detect the timeout since the last status received from AET. This is useful to abort the test run if there is no activity for a long time. | 300000 (5 minutes) | no |
| `pattern` | Id of suite that will be used as patterns source. Identical structure of pattern and current suites is assumed. | - | no |
| `pattern` | Correlation ID of suite that will be used as patterns source. Identical structure of pattern and current suites is assumed. If you want to use latest patterns of given suite without specifying full correlation ID, use `patternSuite` parameter instead. | - | no |
| `patternSuite` | Name of the suite, whose latest version will be used as patterns source. Identical structure of pattern and current suites is assumed. This parameter is ignored if `pattern` parameter is already specified. | - | no |
| `xUnit` | The flag that indicates whether the xUnit report should be generated and downloaded or not.| false | no |

##### Test results
Expand Down
7 changes: 5 additions & 2 deletions documentation/src/main/wiki/SharedPatterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@ you may use different set of [[Modifiers|Modifiers]]:

When you run `green` suite use [[following command|ClientApplication#parameters]] to use suite pattern from **master** suite execution.

`mvn aet:run -DtestSuite=green.xml -DpatternSuite=master`

This option will enforce AET to use patterns from latest version of `master` suite. Alternatively, if you want to use patterns from a specific version (i.e. correlation ID) of `master` suite, use:

`mvn aet:run -DtestSuite=green.xml -Dpattern=company-project-master-1495191612345`

This option will enforce AET to use patterns from specific version of `master` suite.
**Remember that `master` suite must be run before running `green` suite with `patternCorrelationId` option.**
**Remember that `master` suite must be run before running `green` suite with `pattern` or `patternSuite` option.**
In other case, running `green` suite will be treated as running it for the first time.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.cognifide.aet.executor.xmlparser.xml.XmlTestSuiteParser;
import com.cognifide.aet.rest.LockService;
import com.cognifide.aet.rest.helpers.ReportConfigurationManager;
import com.cognifide.aet.vs.MetadataDAO;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
Expand Down Expand Up @@ -95,6 +96,9 @@ public class SuiteExecutor {
@Reference
private SuiteValidator suiteValidator;

@Reference
private SuiteFactory suiteFactory;

private Cache<String, SuiteRunner> suiteRunnerCache;

private Cache<String, Queue<SuiteStatusResult>> suiteStatusCache;
Expand Down Expand Up @@ -126,24 +130,27 @@ public void activate(Map<String, Object> properties) {
*
* @param suiteString - content of the test suite XML file
* @param domain - overrides domain defined in the suite file
* @param pattern - optional pattern to set, this is a name of a suite that will be used as
* patterns source
* @param patternCorrelationId - optional pattern to set, this is a correlation ID of a suite
* that will be used as patterns source
* @param patternSuite - optional pattern to set, this is a name of a suite whose latest version
* will be used as patterns source. This parameter is ignored if patternCorrelationId is set
* @return status of the suite execution
*/
HttpSuiteExecutionResultWrapper execute(String suiteString, String name, String domain,
String pattern) {
String patternCorrelationId, String patternSuite) {
SuiteRunner suiteRunner = null;
HttpSuiteExecutionResultWrapper result;

TestSuiteParser xmlFileParser = new XmlTestSuiteParser();
try {
TestSuiteRun testSuiteRun = xmlFileParser.parse(suiteString);
testSuiteRun = overrideDomainOrNameIfDefined(testSuiteRun, name, domain);
testSuiteRun.setPatternCorrelationId(pattern);
testSuiteRun.setPatternCorrelationId(patternCorrelationId);
testSuiteRun.setPatternSuite(patternSuite);

String validationError = suiteValidator.validateTestSuiteRun(testSuiteRun);
if (validationError == null) {
final Suite suite = new SuiteFactory().suiteFromTestSuiteRun(testSuiteRun);
final Suite suite = suiteFactory.suiteFromTestSuiteRun(testSuiteRun);
suite.validate(Sets.newHashSet("version", "runTimestamp"));

if (lockTestSuite(suite)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,41 @@
import com.cognifide.aet.executor.model.ParametrizedStep;
import com.cognifide.aet.executor.model.TestRun;
import com.cognifide.aet.executor.model.TestSuiteRun;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.cognifide.aet.vs.MetadataDAO;
import com.cognifide.aet.vs.SimpleDBKey;
import com.cognifide.aet.vs.StorageException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class SuiteFactory {

@Service(SuiteFactory.class)
@Component(
label = "AET Suite Factory",
description = "Creates a new Suite object from the test suite",
immediate = true
)
public class SuiteFactory {

private static final Logger LOG = LoggerFactory.getLogger(SuiteFactory.class);

@Reference
private MetadataDAO metadataDao;

public SuiteFactory() {
// default constructor
}

// for unit tests
SuiteFactory(MetadataDAO metadataDAO) {
this.metadataDao = metadataDAO;
}

Suite suiteFromTestSuiteRun(TestSuiteRun testSuiteRun) {
Suite suite = suiteFromTestRun(testSuiteRun);
Expand Down Expand Up @@ -96,26 +124,37 @@ private Suite suiteFromTestRun(TestSuiteRun testSuiteRun) {
String company = testSuiteRun.getCompany();
String project = testSuiteRun.getProject();
String name = testSuiteRun.getName();
String patternCorrelationId = testSuiteRun.getPatternCorrelationId();

String patternCorrelationId = getPatternCorrelationId(testSuiteRun);
return new Suite(correlationId, company, project, name, patternCorrelationId);
}

private String getPatternCorrelationId(TestSuiteRun testSuiteRun) {
String result = testSuiteRun.getPatternCorrelationId();
if (result == null && testSuiteRun.getPatternSuite() != null) {
SimpleDBKey dbKey = new SimpleDBKey(testSuiteRun.getCompany(), testSuiteRun.getProject());
try {
Suite patternSuite = metadataDao.getLatestRun(dbKey, testSuiteRun.getPatternSuite());
result = patternSuite != null ? patternSuite.getCorrelationId() : null;
} catch (StorageException e) {
LOG.error("Error while retrieving suite from mongo db: '{}', suiteName: '{}'",
dbKey, testSuiteRun.getPatternSuite(), e);
}
}
return result;
}

private boolean comparatorMatchesCollector(CollectorStep collectorStep,
ComparatorStep comparatorStep) {
return StringUtils.isEmpty(comparatorStep.getCollectorName()) || StringUtils
.equals(comparatorStep.getCollectorName(), collectorStep.getName());
}

private List<Operation> extractOperations(List<? extends ParametrizedStep> steps) {
return FluentIterable.from(steps).transform(new Function<ParametrizedStep, Operation>() {
@Override
public Operation apply(ParametrizedStep step) {
final Operation operation = new Operation(step.getName());
operation.addParameters(step.getParameters());
return operation;
}
}).toList();
return steps.stream().map(step -> {
final Operation operation = new Operation(step.getName());
operation.addParameters(step.getParameters());
return operation;
}).collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public class SuiteServlet extends HttpServlet {
private static final String SUITE_PARAM = "suite";
private static final String NAME_PARAM = "name";
private static final String DOMAIN_PARAM = "domain";
private static final String PATTERN_PARAM = "pattern";
private static final String PATTERN_CORRELATION_ID_PARAM = "pattern";
private static final String PATTERN_SUITE_PARAM = "patternSuite";


@Reference
Expand All @@ -71,17 +72,18 @@ public class SuiteServlet extends HttpServlet {
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
throws IOException {
if (ServletFileUpload.isMultipartContent(request)) {
Map<String, String> requestData = getRequestData(request);
final String suite = requestData.get(SUITE_PARAM);
final String name = requestData.get(NAME_PARAM);
final String domain = requestData.get(DOMAIN_PARAM);
final String pattern = requestData.get(PATTERN_PARAM);
final String patternCorrelationId = requestData.get(PATTERN_CORRELATION_ID_PARAM);
final String patternSuite = requestData.get(PATTERN_SUITE_PARAM);

if (StringUtils.isNotBlank(suite)) {
HttpSuiteExecutionResultWrapper resultWrapper = suiteExecutor
.execute(suite, name, domain, pattern);
.execute(suite, name, domain, patternCorrelationId, patternSuite);
final SuiteExecutionResult suiteExecutionResult = resultWrapper.getExecutionResult();
Gson gson = new Gson();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ public class SuiteValidator {
@Reference
private MetadataDAO metadataDAO;

public SuiteValidator() {
// default constructor
}

// for unit tests
SuiteValidator(MetadataDAO metadataDAO) {
this.metadataDAO = metadataDAO;
}

public String validateTestSuiteRun(TestSuiteRun testSuiteRun) {
boolean patternFromSameProject = isPatternFromSameProject(testSuiteRun);
if (!patternFromSameProject) {
Expand All @@ -60,8 +69,9 @@ public String validateTestSuiteRun(TestSuiteRun testSuiteRun) {
}
boolean patternValid = isPatternInDatabase(testSuiteRun);
if (!patternValid) {
return String.format("Incorrect pattern: '%s'. Not found in database.",
testSuiteRun.getPatternCorrelationId());
return String
.format("Incorrect pattern: correlationId='%s', suiteName='%s'. Not found in database.",
testSuiteRun.getPatternCorrelationId(), testSuiteRun.getPatternSuite());
}
for (TestRun testRun : testSuiteRun.getTestRunMap().values()) {
if (hasScreenCollector(testRun) && !hasScreenComparator(testRun)) {
Expand All @@ -81,7 +91,7 @@ public String validateTestSuiteRun(TestSuiteRun testSuiteRun) {
* @return true if suite is OK
*/
private boolean isPatternFromSameProject(TestSuiteRun testSuiteRun) {
boolean sameProject = false;
boolean sameProject;
String pattern = testSuiteRun.getPatternCorrelationId();
if (pattern == null) {
// patterns will be taken from same suite automatically
Expand Down Expand Up @@ -121,15 +131,21 @@ private boolean isPatternInDatabase(TestSuiteRun testSuiteRun) {
boolean valid = false;
SimpleDBKey dbKey = new SimpleDBKey(testSuiteRun.getCompany(), testSuiteRun.getProject());
String patternCorrelationId = testSuiteRun.getPatternCorrelationId();
if (patternCorrelationId == null) {
String patternSuiteName = testSuiteRun.getPatternSuite();
if (patternCorrelationId == null && patternSuiteName == null) {
valid = true;
} else {
Suite patternSuite = null;
try {
patternSuite = metadataDAO.getSuite(dbKey, patternCorrelationId);
if (patternCorrelationId != null) {
patternSuite = metadataDAO.getSuite(dbKey, patternCorrelationId);
} else {
patternSuite = metadataDAO.getLatestRun(dbKey, patternSuiteName);
}
} catch (StorageException se) {
LOG.error("error while retrieving suite from mongo db: '{}', correlationId: '{}'",
dbKey, patternCorrelationId, se);
LOG.error(
"error while retrieving suite from mongo db: '{}', correlationId: '{}', suiteName: '{}'",
dbKey, patternCorrelationId, patternSuiteName, se);
}
if (patternSuite != null) {
valid = true;
Expand Down
Loading