Skip to content

Commit

Permalink
Add conditions for setup, teardown functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Thevakumar-Luheerathan committed Jan 17, 2024
1 parent 88e784e commit 988ab03
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,18 @@ public class TestFunctionVisitor extends NodeVisitor {

static final List<String> TEST_STATIC_ANNOTATION_NAMES = List.of(
"Config", "BeforeSuite", "AfterSuite", "BeforeGroups", "AfterGroups", "BeforeEach", "AfterEach");
static final String CONFIG_ANNOTATION = "Config";
private static final String TEST_DYNAMIC_ANNOTATION_NAME = "Factory";
private static final String TEST_MODULE_NAME = "test";

private final List<FunctionDefinitionNode> testStaticFunctions;
private final List<FunctionDefinitionNode> testSetUpTearDownFunctions;
private final List<FunctionDefinitionNode> testDynamicFunctions;
private final List<FunctionDefinitionNode> testFunctions;

public TestFunctionVisitor() {
this.testStaticFunctions = new ArrayList<>();
this.testSetUpTearDownFunctions = new ArrayList<>();
this.testDynamicFunctions = new ArrayList<>();
this.testFunctions = new ArrayList<>();
}

@Override
Expand All @@ -73,7 +76,11 @@ public void visit(FunctionDefinitionNode functionDefinitionNode) {
String identifier = qualifiedNameReferenceNode.identifier().text();
if (TEST_MODULE_NAME.equals(modulePrefix)) {
if (TEST_STATIC_ANNOTATION_NAMES.contains(identifier)) {
testStaticFunctions.add(functionDefinitionNode);
if (CONFIG_ANNOTATION.equals(identifier)) {
testFunctions.add(functionDefinitionNode);
} else {
testSetUpTearDownFunctions.add(functionDefinitionNode);
}
} else if (TEST_DYNAMIC_ANNOTATION_NAME.equals(identifier)) {
testDynamicFunctions.add(functionDefinitionNode);
}
Expand All @@ -83,7 +90,9 @@ public void visit(FunctionDefinitionNode functionDefinitionNode) {
}

public List<FunctionDefinitionNode> getTestStaticFunctions() {
return this.testStaticFunctions;
List<FunctionDefinitionNode> testStaticFunctions = new ArrayList<>(testSetUpTearDownFunctions);
testStaticFunctions.addAll(testFunctions);
return testStaticFunctions;
}

public List<FunctionDefinitionNode> getTestDynamicFunctions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
type AnnotationProcessor function (string name, function f) returns boolean;

AnnotationProcessor[] annotationProcessors = [
processConfigAnnotation,
processBeforeSuiteAnnotation,
processAfterSuiteAnnotation,
processBeforeEachAnnotation,
processAfterEachAnnotation,
processBeforeGroupsAnnotation,
processAfterGroupsAnnotation
processAfterGroupsAnnotation,
processConfigAnnotation
];

public function registerTest(string name, function f) {
Expand All @@ -50,16 +50,16 @@ function processConfigAnnotation(string name, function f) returns boolean {
boolean isTestFunctionIsolated = f is isolated function;
boolean isDataProviderIsolated = true;
boolean isTestFunctionParamSafe = true;
boolean isSatisfiedParallelizableConditions = isTestFunctionIsolated;
string[] reasonForSerialExecution = [];
boolean isSatisfiedParallelizableConditions = isTestFunctionIsolated && isBeforeAfterFuncSetIsolated(config, reasonForSerialExecution);
DataProviderReturnType? params = ();
error? diagnostics = ();
if config.dataProvider != () {
var providerFn = config.dataProvider;
if providerFn is function () returns (DataProviderReturnType?) {
isDataProviderIsolated = (<function>providerFn is isolated function);
isTestFunctionParamSafe = isFunctionParamConcurrencySafe(f);
isSatisfiedParallelizableConditions = isTestFunctionIsolated && isDataProviderIsolated && isTestFunctionParamSafe;
isSatisfiedParallelizableConditions = isSatisfiedParallelizableConditions && isDataProviderIsolated && isTestFunctionParamSafe;
DataProviderReturnType providerOutput = providerFn();
params = <DataProviderReturnType>providerOutput;
} else {
Expand All @@ -80,7 +80,7 @@ function processConfigAnnotation(string name, function f) returns boolean {

// If the test function is not parallelizable, then print the reason for serial execution.
if !isSatisfiedParallelizableConditions && !config.serialExecution && (conMgr.getConfiguredWorkers() > 1) {
println("WARNING: Test function '" + name + "' cannot be parallelized, reason: " + string:'join(",", ...reasonForSerialExecution));
println("WARNING: Test function '" + name + "' cannot be parallelized, reason: " + string:'join(", ", ...reasonForSerialExecution));
}

boolean enabled = config.enable && (filterGroups.length() == 0 ? true : hasGroup(config.groups, filterGroups))
Expand All @@ -96,6 +96,57 @@ function processConfigAnnotation(string name, function f) returns boolean {
return false;
}

function isBeforeAfterFuncSetIsolated(TestConfig config, string[] reasonForSerialExecution) returns boolean {
boolean isBeforeAfterFunctionSetIsolated = true;
if config.before != () {
if !(<function>config.before is isolated function) {
isBeforeAfterFunctionSetIsolated = false;
reasonForSerialExecution.push("non-isolated before function");
}
}
if config.after != () {
if !(<function>config.after is isolated function) {
isBeforeAfterFunctionSetIsolated = false;
reasonForSerialExecution.push("non-isolated after function");
}
}
foreach string 'group in config.groups {
TestFunction[]? beforeGroupFunctions = beforeGroupsRegistry.getFunctions('group);
if beforeGroupFunctions != () {
foreach TestFunction beforeGroupFunction in beforeGroupFunctions {
if !(beforeGroupFunction.executableFunction is isolated function) {
isBeforeAfterFunctionSetIsolated = false;
reasonForSerialExecution.push("non-isolated before group function");
}
}
}
TestFunction[]? afterGroupFunctions = afterGroupsRegistry.getFunctions('group);
if afterGroupFunctions != () {
foreach TestFunction afterGroupFunction in afterGroupFunctions {
if !(afterGroupFunction.executableFunction is isolated function) {
isBeforeAfterFunctionSetIsolated = false;
reasonForSerialExecution.push("non-isolated after group function");
}
}
}
}
TestFunction[] beforeEachFunctions = beforeEachRegistry.getFunctions();
foreach TestFunction beforeEachFunction in beforeEachFunctions {
if !(beforeEachFunction.executableFunction is isolated function) {
isBeforeAfterFunctionSetIsolated = false;
reasonForSerialExecution.push("non-isolated before each function");
}
}
TestFunction[] afterEachFunctions = afterEachRegistry.getFunctions();
foreach TestFunction afterEachFunction in afterEachFunctions {
if !(afterEachFunction.executableFunction is isolated function) {
isBeforeAfterFunctionSetIsolated = false;
reasonForSerialExecution.push("non-isolated after each function");
}
}
return isBeforeAfterFunctionSetIsolated;
}

function processBeforeSuiteAnnotation(string name, function f) returns boolean {
boolean? isTrue = (typeof f).@BeforeSuite;
if isTrue == true {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ type TestFunction record {|
function? before = ();
function? after = ();
boolean alwaysRun = false;
string[] groups = [];
readonly & string[] groups = [];
error? diagnostics = ();
function[] dependsOn = [];
readonly & function[] dependsOn = [];
boolean parallelizable = true;
TestConfig? config = ();
|} & readonly;
Expand Down Expand Up @@ -447,7 +447,7 @@ isolated class TestRegistry {

isolated function getFunctions() returns TestFunction[] {
lock {
return self.rootRegistry.sort(array:ASCENDING, (item) => item.name).cloneReadOnly();
return self.rootRegistry.sort(array:ASCENDING, (item) => item.name).clone();
}
}

Expand All @@ -474,7 +474,7 @@ isolated class GroupRegistry {
isolated function getFunctions(string 'group) returns TestFunction[]? {
lock {
if self.registry.hasKey('group) {
return self.registry.get('group).cloneReadOnly();
return self.registry.get('group).clone();
}
return;
}
Expand Down

0 comments on commit 988ab03

Please sign in to comment.