Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def _evaluate_expressions(
if not attribute.startswith("_") and not callable(getattr(obj, attribute))
]
for attribute_name in attribute_names:
if "activities" in attribute_name:
if self._is_nested_activities_name(attribute_name):
continue

attribute = getattr(obj, attribute_name)
Expand All @@ -98,7 +98,7 @@ def _evaluate_expressions(
# Dictionary
if isinstance(obj, dict):
for key in obj.keys():
if "activities" in key:
if self._is_nested_activities_name(key):
continue

self._evaluate_expressions(obj[key], state, visited, types_to_ignore)
Expand All @@ -116,6 +116,12 @@ def _evaluate_expressions(

self._evaluate_expressions(item, state, visited, types_to_ignore)

@staticmethod
def _is_nested_activities_name(name: str) -> bool:
# Nested activities (activities, ifTrueActivities, ifFalseActivities, defaultActivities, ...)
# are evaluated by the control activity in their own scope, never eagerly with the parent.
return "activities" in name.lower()

def set_result(self, result: DependencyCondition, output: Optional[Any] = None) -> None: # noqa: ANN401
self.status = result
self.output = output
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "if_condition_branch",
"properties": {
"activities": [
{
"name": "Has_Date",
"type": "IfCondition",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"expression": {
"value": "@empty(pipeline().parameters.date)",
"type": "Expression"
},
"ifTrueActivities": [
{
"name": "Set_Today",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "day",
"value": {
"value": "@formatDateTime(utcNow(), 'yyyy-MM-dd')",
"type": "Expression"
}
}
}
],
"ifFalseActivities": [
{
"name": "Set_Given_Date",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "day",
"value": {
"value": "@formatDateTime(pipeline().parameters.date, 'yyyy-MM-dd')",
"type": "Expression"
}
}
}
]
}
}
],
"parameters": {
"date": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"day": {
"type": "String"
}
},
"annotations": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"name": "switch_default_branch",
"properties": {
"activities": [
{
"name": "On_Mode",
"type": "Switch",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"on": {
"value": "@pipeline().parameters.mode",
"type": "Expression"
},
"cases": [
{
"value": "today",
"activities": [
{
"name": "Set_Today",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "day",
"value": {
"value": "@formatDateTime(utcNow(), 'yyyy-MM-dd')",
"type": "Expression"
}
}
}
]
}
],
"defaultActivities": [
{
"name": "Set_Given_Date",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "day",
"value": {
"value": "@formatDateTime(pipeline().parameters.date, 'yyyy-MM-dd')",
"type": "Expression"
}
}
}
]
}
}
],
"parameters": {
"mode": {
"type": "string",
"defaultValue": "today"
},
"date": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"day": {
"type": "String"
}
},
"annotations": []
}
}
78 changes: 78 additions & 0 deletions tests/functional/branch_not_taken/test_branch_not_taken.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import pytest
from data_factory_testing_framework import TestFramework, TestFrameworkType
from data_factory_testing_framework.state import RunParameter, RunParameterType


@pytest.mark.parametrize(
"date,expected_activity_name,expected_day",
[
("", "Set_Today", None),
("2024-01-31T00:00:00Z", "Set_Given_Date", "2024-01-31"),
],
)
def test_if_condition_only_evaluates_the_branch_taken(
date: str,
expected_activity_name: str,
expected_day: str,
request: pytest.FixtureRequest,
) -> None:
# Arrange
test_framework = TestFramework(
framework_type=TestFrameworkType.DataFactory,
root_folder_path=request.fspath.dirname,
)
pipeline = test_framework.get_pipeline_by_name("if_condition_branch")

# Act
activities = test_framework.evaluate_pipeline(
pipeline,
[
RunParameter(RunParameterType.Pipeline, "date", date),
],
)

# Assert
activity = next(activities)
assert activity.name == expected_activity_name
if expected_day is not None:
assert activity.type_properties["value"].result == expected_day

with pytest.raises(StopIteration):
next(activities)


@pytest.mark.parametrize(
"mode,date,expected_activity_name",
[
("today", "", "Set_Today"),
("given", "2024-01-31T00:00:00Z", "Set_Given_Date"),
],
)
def test_switch_only_evaluates_the_case_taken(
mode: str,
date: str,
expected_activity_name: str,
request: pytest.FixtureRequest,
) -> None:
# Arrange
test_framework = TestFramework(
framework_type=TestFrameworkType.DataFactory,
root_folder_path=request.fspath.dirname,
)
pipeline = test_framework.get_pipeline_by_name("switch_default_branch")

# Act
activities = test_framework.evaluate_pipeline(
pipeline,
[
RunParameter(RunParameterType.Pipeline, "mode", mode),
RunParameter(RunParameterType.Pipeline, "date", date),
],
)

# Assert
activity = next(activities)
assert activity.name == expected_activity_name

with pytest.raises(StopIteration):
next(activities)
37 changes: 37 additions & 0 deletions tests/unit/models/activities/base/test_activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,40 @@ def test_evaluate_is_evaluating_expressions_inside_dict() -> None:

# Assert
assert pipeline_activity.type_properties["parameters"]["url"].result == "example.com"


@pytest.mark.parametrize(
"nested_activities_key",
["activities", "ifTrueActivities", "ifFalseActivities", "defaultActivities"],
)
def test_evaluate_does_not_evaluate_expressions_of_nested_activities(nested_activities_key: str) -> None:
# Arrange
activity = Activity(
name="activity",
type="Container",
typeProperties={
"url": DataFactoryElement("@pipeline().parameters.url"),
nested_activities_key: [
{
"name": "nested",
"type": "SetVariable",
"typeProperties": {
"variableName": "variable",
"value": DataFactoryElement("@pipeline().parameters.not_in_scope"),
},
},
],
},
)
state = PipelineRunState(
parameters=[
RunParameter(RunParameterType.Pipeline, "url", "example.com"),
],
)

# Act
activity.evaluate(state)

# Assert
assert activity.type_properties["url"].result == "example.com"
assert activity.type_properties[nested_activities_key][0]["typeProperties"]["value"].result is None
Loading