Skip to content

Commit

Permalink
add state 'unhealthy'
Browse files Browse the repository at this point in the history
  • Loading branch information
agebhar1 committed Sep 12, 2023
1 parent 49f0bd0 commit bb0e73a
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 21 deletions.
55 changes: 42 additions & 13 deletions graph/planner/planner.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ class Planner:
_state: DirectAcyclicGraph
_target: DirectAcyclicGraph
_modified: list[str]
_unhealthy: list[str]
_selected: Union[str, list[str]] = "*"

def __init__(
self,
state: DirectAcyclicGraph,
target: DirectAcyclicGraph,
modified: list[str] = None, # TODO naming
unhealthy: list[str] = None, # TODO naming
selected: Union[str, list[str]] = "*", # TODO naming
):
self._state = state
self._target = target
self._modified = modified or []
self._unhealthy = unhealthy or []
self._selected = selected

def apply(self) -> tuple[list[str], dict[str, bool | set[str]]]:
Expand All @@ -29,6 +32,7 @@ def apply(self) -> tuple[list[str], dict[str, bool | set[str]]]:
nodes_delete = set()
nodes_with_edge_type_tool_delete = set()
modified_transitive = set()
unhealthy_transitive = set()

node_action_cause = {node: dict() for node in nodes_state.union(nodes_target)}

Expand All @@ -42,6 +46,12 @@ def apply(self) -> tuple[list[str], dict[str, bool | set[str]]]:
node, accept=lambda adjacent: adjacent[1] != EdgeType.TOOL
).union({node})
)
for node in self._unhealthy:
unhealthy_transitive = unhealthy_transitive.union(
self._state.childs_transitive(
node, accept=lambda adjacent: adjacent[1] != EdgeType.TOOL
).union({node})
)
else:
# partial apply mode
for item in self._selected:
Expand All @@ -55,15 +65,15 @@ def apply(self) -> tuple[list[str], dict[str, bool | set[str]]]:
self._state.parents_transitive(
node,
accept=lambda adjacent: adjacent[1] == EdgeType.TOOL
and adjacent[0] in self._modified,
and adjacent[0] in self._unhealthy,
)
)
modified_transitive = modified_transitive.union(
unhealthy_transitive = unhealthy_transitive.union(
parents_edge_type_tool_transitive
)
for reachable in parents_edge_type_tool_transitive:
if reachable != node:
node_action_cause[reachable] |= {"modified": "True"}
node_action_cause[reachable] |= {"unhealthy": "True"}
if "parent" in node_action_cause[reachable]:
node_action_cause[reachable]["parent"].add(node)
else:
Expand Down Expand Up @@ -102,18 +112,32 @@ def apply(self) -> tuple[list[str], dict[str, bool | set[str]]]:
else:
node = item
node_action_cause[node] |= {"selected": True}
if node in self._modified: # and node in node_states <- implicit

is_node_modified = node in self._modified
is_node_unhealthy = node in self._unhealthy

if (
is_node_modified or is_node_unhealthy
): # and node in node_states <- implicit
childs_transitive = self._state.childs_transitive(
node,
accept=lambda adjacent: adjacent[1] != EdgeType.TOOL,
).union({node})

modified_transitive = modified_transitive.union(
childs_transitive
)
key = "modified"
if is_node_modified:
modified_transitive = modified_transitive.union(
childs_transitive
)
if is_node_unhealthy and not is_node_modified:
key = "unhealthy"
unhealthy_transitive = unhealthy_transitive.union(
childs_transitive
)

for reachable in childs_transitive:
if reachable != node:
node_action_cause[reachable] |= {"modified": True}
node_action_cause[reachable] |= {key: True}
if "child" in node_action_cause[reachable]:
node_action_cause[reachable]["child"].add(node)
else:
Expand All @@ -134,14 +158,16 @@ def apply(self) -> tuple[list[str], dict[str, bool | set[str]]]:
for node_add in nodes_add:
parent_transitive = self._target.parents_transitive(
node_add,
accept=lambda adjacent: (adjacent[0] in self._modified),
accept=lambda adjacent: (
adjacent[0] in self._unhealthy
),
)
modified_transitive = modified_transitive.union(
unhealthy_transitive = unhealthy_transitive.union(
parent_transitive
)
for reachable in parent_transitive:
if reachable != node:
node_action_cause[reachable] |= {"modified": True}
node_action_cause[reachable] |= {"unhealthy": True}
if "parent" in node_action_cause[reachable]:
node_action_cause[reachable]["parent"].add(node)
else:
Expand All @@ -160,13 +186,16 @@ def apply(self) -> tuple[list[str], dict[str, bool | set[str]]]:
for node in modified_transitive:
node_action[node] = "modified"

for node in unhealthy_transitive:
node_action[node] = "unhealthy"

operations = []
for node in self._state.topological_order():
if node_action[node] in ["delete", "modified"]:
if node_action[node] in ["delete", "modified", "unhealthy"]:
operations.append(f"-{node}")

for node in reversed(self._target.topological_order()):
if node_action[node] in ["add", "modified"]:
if node_action[node] in ["add", "modified", "unhealthy"]:
operations.append(f"+{node}")

# handle node deletion of nodes w/ edges of type TOOL
Expand Down
168 changes: 160 additions & 8 deletions graph/planner/planner_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

class PlanerTestCase(unittest.TestCase):
def test_no_action(self):
planner = Planner(state=DAG1, target=DAG1, modified=[])
planner = Planner(state=DAG1, target=DAG1)

self.assertEqual(([], {}), planner.apply())

Expand All @@ -54,6 +54,32 @@ def test_apply_DAG1_modified_multiple(self):
planner.apply(),
)

def test_apply_DAG1_unhealthy_multiple(self):
planner = Planner(state=DAG1, target=DAG1, unhealthy=["b", "d"])

self.assertEqual(
(["-a", "-b", "-c", "-d", "+d", "+c", "+b", "+a"], {}),
planner.apply(),
)

def test_apply_DAG1_unhealthy_and_modified(self):
planner = Planner(
state=DAG1, target=DAG1, modified=["b", "d"], unhealthy=["b", "d"]
)

self.assertEqual(
(["-a", "-b", "-c", "-d", "+d", "+c", "+b", "+a"], {}),
planner.apply(),
)

def test_apply_DAG1_unhealthy_or_modified(self):
planner = Planner(state=DAG1, target=DAG1, modified=["b"], unhealthy=["d"])

self.assertEqual(
(["-a", "-b", "-c", "-d", "+d", "+c", "+b", "+a"], {}),
planner.apply(),
)

def test_apply_DAG1_modified_root(self):
planner = Planner(state=DAG1, target=DAG1, modified=["e"])

Expand All @@ -62,6 +88,14 @@ def test_apply_DAG1_modified_root(self):
planner.apply(),
)

def test_apply_DAG1_unhealthy_root(self):
planner = Planner(state=DAG1, target=DAG1, unhealthy=["e"])

self.assertEqual(
(["-a", "-b", "-c", "-d", "-e", "+e", "+d", "+c", "+b", "+a"], {}),
planner.apply(),
)

def test_apply_DAG3_modified_single(self):
planner = Planner(state=DAG3, target=DAG3, modified=["d"])

Expand Down Expand Up @@ -223,11 +257,30 @@ def test_apply_delete_with_modified_one_TOOL_edge(self):
modified=["b"],
selected=["-c"],
)
self.assertEqual(
(
["-c"],
{
"c": {"selected": True},
},
),
planner.apply(),
)

def test_apply_delete_with_unhealthy_one_TOOL_edge(self):
planner = Planner(
state=DirectAcyclicGraph(g={"a": [], "b": dependency("a"), "c": tool("b")}),
target=DirectAcyclicGraph(
g={"a": [], "b": dependency("a"), "c": tool("b")}
),
unhealthy=["b"],
selected=["-c"],
)
self.assertEqual(
(
["-b", "+b", "-c"],
{
"b": {"modified": "True", "parent": {"c"}},
"b": {"unhealthy": "True", "parent": {"c"}},
"c": {"selected": True},
},
),
Expand All @@ -245,11 +298,32 @@ def test_apply_delete_with_one_modified_two_TOOL_edge_in_chain(self):
modified=["b2"],
selected=["-c"],
)
self.assertEqual(
(
["-c"],
{
"c": {"selected": True},
},
),
planner.apply(),
)

def test_apply_delete_with_one_unhealthy_two_TOOL_edge_in_chain(self):
planner = Planner(
state=DirectAcyclicGraph(
g={"a": [], "b1": dependency("a"), "b2": tool("b1"), "c": tool("b2")}
),
target=DirectAcyclicGraph(
g={"a": [], "b1": dependency("a"), "b2": tool("b1"), "c": tool("b2")}
),
unhealthy=["b2"],
selected=["-c"],
)
self.assertEqual(
(
["-b2", "+b2", "-c"],
{
"b2": {"modified": "True", "parent": {"c"}},
"b2": {"unhealthy": "True", "parent": {"c"}},
"c": {"selected": True},
},
),
Expand All @@ -267,12 +341,33 @@ def test_apply_delete_with_two_modified_two_TOOL_edge_in_chain(self):
modified=["b1", "b2"],
selected=["-c"],
)
self.assertEqual(
(
["-c"],
{
"c": {"selected": True},
},
),
planner.apply(),
)

def test_apply_delete_with_two_unhealthy_two_TOOL_edge_in_chain(self):
planner = Planner(
state=DirectAcyclicGraph(
g={"a": [], "b1": dependency("a"), "b2": tool("b1"), "c": tool("b2")}
),
target=DirectAcyclicGraph(
g={"a": [], "b1": dependency("a"), "b2": tool("b1"), "c": tool("b2")}
),
unhealthy=["b1", "b2"],
selected=["-c"],
)
self.assertEqual(
(
["-b2", "-b1", "+b1", "+b2", "-c"],
{
"b1": {"modified": "True", "parent": {"c"}},
"b2": {"modified": "True", "parent": {"c"}},
"b1": {"unhealthy": "True", "parent": {"c"}},
"b2": {"unhealthy": "True", "parent": {"c"}},
"c": {"selected": True},
},
),
Expand Down Expand Up @@ -335,11 +430,30 @@ def test_apply_DAG3_selected_target_modified(self):
selected=["c"],
)

self.assertEqual(
(
["+b", "+c"],
{
"b": {"parent": {"c"}},
"c": {"selected": True},
},
),
planner.apply(),
)

def test_apply_DAG3_selected_target_unhealthy(self):
planner = Planner(
state=DirectAcyclicGraph(g={"a": dependency()}),
target=DAG3,
unhealthy=["a"],
selected=["c"],
)

self.assertEqual(
(
["-a", "+a", "+b", "+c"],
{
"a": {"modified": True, "parent": {"c"}},
"a": {"unhealthy": True, "parent": {"c"}},
"b": {"parent": {"c"}},
"c": {"selected": True},
},
Expand All @@ -357,11 +471,31 @@ def test_apply_DAG3_selected_target_modified_one_TOOL_edge(self):
selected=["c"],
)

self.assertEqual(
(
["+c"],
{
"c": {"selected": True},
},
),
planner.apply(),
)

def test_apply_DAG3_selected_target_unhealthy_one_TOOL_edge(self):
planner = Planner(
state=DirectAcyclicGraph(g={"a": [], "b": dependency("a")}),
target=DirectAcyclicGraph(
g={"a": [], "b": dependency("a"), "c": tool("b")}
),
unhealthy=["b"],
selected=["c"],
)

self.assertEqual(
(
["-b", "+b", "+c"],
{
"b": {"modified": True, "parent": {"c"}},
"b": {"unhealthy": True, "parent": {"c"}},
"c": {"selected": True},
},
),
Expand Down Expand Up @@ -403,12 +537,30 @@ def test_apply_selected_TOOL_edge_modified(self):
selected=["-a"],
)

self.assertEqual(
(
["-a"],
{
"a": {"selected": True},
},
),
planner.apply(),
)

def test_apply_selected_TOOL_edge_unhealthy(self):
planner = Planner(
state=DirectAcyclicGraph(g={"a": tool("b"), "b": []}),
target=DirectAcyclicGraph(g={"a": tool("b"), "b": []}),
unhealthy=["b"],
selected=["-a"],
)

self.assertEqual(
(
["-b", "+b", "-a"],
{
"a": {"selected": True},
"b": {"modified": "True", "parent": {"a"}},
"b": {"unhealthy": "True", "parent": {"a"}},
},
),
planner.apply(),
Expand Down

0 comments on commit bb0e73a

Please sign in to comment.