diff --git a/tests/bluechi_test/config.py b/tests/bluechi_test/config.py index e8360b5198..ee5995104d 100644 --- a/tests/bluechi_test/config.py +++ b/tests/bluechi_test/config.py @@ -32,6 +32,8 @@ def __init__( name: str = "bluechi-controller", port: str = "8420", allowed_node_names: List[str] = [], + heartbeat_interval: str = "0", + node_heartbeat_threshold: str = "6000", log_level: str = "DEBUG", log_target: str = "journald", log_is_quiet: bool = False, @@ -41,6 +43,8 @@ def __init__( self.name = name self.port = port self.allowed_node_names = allowed_node_names + self.heartbeat_interval = heartbeat_interval + self.node_heartbeat_threshold = node_heartbeat_threshold self.log_level = log_level self.log_target = log_target self.log_is_quiet = log_is_quiet @@ -53,6 +57,8 @@ def serialize(self) -> str: return f"""[bluechi-controller] ControllerPort={self.port} AllowedNodeNames={allowed_node_names} +HeartbeatInterval={self.heartbeat_interval} +NodeHeartbeatThreshold={self.node_heartbeat_threshold} LogLevel={self.log_level} LogTarget={self.log_target} LogIsQuiet={self.log_is_quiet} diff --git a/tests/tests/tier0/bluechi-heartbeat-disabled/main.fmf b/tests/tests/tier0/bluechi-heartbeat-disabled/main.fmf new file mode 100644 index 0000000000..184c2b40cc --- /dev/null +++ b/tests/tests/tier0/bluechi-heartbeat-disabled/main.fmf @@ -0,0 +1,3 @@ +summary: Test if default configuration of controller disables periodic heartbeat of + the controller +id: a04517f6-8be1-468b-8dc0-f9674690f73f diff --git a/tests/tests/tier0/bluechi-heartbeat-disabled/python/is_node_connected.py b/tests/tests/tier0/bluechi-heartbeat-disabled/python/is_node_connected.py new file mode 100644 index 0000000000..3caa8b4f79 --- /dev/null +++ b/tests/tests/tier0/bluechi-heartbeat-disabled/python/is_node_connected.py @@ -0,0 +1,35 @@ +# +# Copyright Contributors to the Eclipse BlueChi project +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +import time +import unittest + +from dasbus.typing import Variant + +from bluechi.api import Node + + +class TestNodeIsConnected(unittest.TestCase): + def test_node_is_connected(self): + + def on_state_change(state: Variant): + assert False + + n = Node("node-foo") + assert n.status == "online" + + n.on_status_changed(on_state_change) + timestamp = n.last_seen_timestamp + + # verify that the node remains connected and LastSeenTimespamp is not + # updated after more than NodeHeartbeatThreshold seconds have elapsed + time.sleep(10) + + assert n.status == "online" + assert n.last_seen_timestamp == timestamp + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/tests/tier0/bluechi-heartbeat-disabled/test_bluechi_heartbeat_disabled.py b/tests/tests/tier0/bluechi-heartbeat-disabled/test_bluechi_heartbeat_disabled.py new file mode 100644 index 0000000000..9f1aae3238 --- /dev/null +++ b/tests/tests/tier0/bluechi-heartbeat-disabled/test_bluechi_heartbeat_disabled.py @@ -0,0 +1,36 @@ +# +# Copyright Contributors to the Eclipse BlueChi project +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +import os +from typing import Dict + +from bluechi_test.config import BluechiAgentConfig, BluechiControllerConfig +from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine +from bluechi_test.test import BluechiTest + +node_foo_name = "node-foo" + + +def exec(ctrl: BluechiControllerMachine, nodes: Dict[str, BluechiAgentMachine]): + result, output = ctrl.run_python(os.path.join("python", "is_node_connected.py")) + if result != 0: + raise Exception(output) + + +def test_bluechi_heartbeat_disabled( + bluechi_test: BluechiTest, + bluechi_ctrl_default_config: BluechiControllerConfig, + bluechi_node_default_config: BluechiAgentConfig, +): + + bluechi_ctrl_default_config.allowed_node_names = [node_foo_name] + + bluechi_node_default_config.node_name = node_foo_name + bluechi_node_default_config.heartbeat_interval = "0" + + bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) + bluechi_test.add_bluechi_agent_config(bluechi_node_default_config) + + bluechi_test.run(exec) diff --git a/tests/tests/tier0/bluechi-heartbeat-node-disconnected/main.fmf b/tests/tests/tier0/bluechi-heartbeat-node-disconnected/main.fmf new file mode 100644 index 0000000000..745433d523 --- /dev/null +++ b/tests/tests/tier0/bluechi-heartbeat-node-disconnected/main.fmf @@ -0,0 +1,3 @@ +summary: Test if the node gets disconnected when did not receive heartbeat since + threshold from node +id: 0b087ba3-25fc-46b0-9c01-31bc2edf5209 diff --git a/tests/tests/tier0/bluechi-heartbeat-node-disconnected/python/is_node_disconnected.py b/tests/tests/tier0/bluechi-heartbeat-node-disconnected/python/is_node_disconnected.py new file mode 100644 index 0000000000..dd915ef102 --- /dev/null +++ b/tests/tests/tier0/bluechi-heartbeat-node-disconnected/python/is_node_disconnected.py @@ -0,0 +1,43 @@ +# +# Copyright Contributors to the Eclipse BlueChi project +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +import time +import unittest + +from dasbus.loop import EventLoop +from dasbus.typing import Variant + +from bluechi.api import Node + + +class TestNodeIsDisconnected(unittest.TestCase): + + node_state = None + timestamp = None + + def test_node_is_disconnected(self): + loop = EventLoop() + + def on_state_change(state: Variant): + self.timestamp = round(time.time() * 1000000) + self.node_state = state.get_string() + loop.quit() + + n = Node("node-foo") + assert n.status == "online" + + n.on_status_changed(on_state_change) + timestamp = n.last_seen_timestamp + + loop.run() + + # verify that the node is disconnected after more than + # NodeHeartbeatThreshold seconds have elapsed + assert self.timestamp - timestamp > 6000000 + assert self.node_state == "offline" + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/tests/tier0/bluechi-heartbeat-node-disconnected/test_bluechi_heartbeat_node_disconnected.py b/tests/tests/tier0/bluechi-heartbeat-node-disconnected/test_bluechi_heartbeat_node_disconnected.py new file mode 100644 index 0000000000..0b3a637033 --- /dev/null +++ b/tests/tests/tier0/bluechi-heartbeat-node-disconnected/test_bluechi_heartbeat_node_disconnected.py @@ -0,0 +1,37 @@ +# +# Copyright Contributors to the Eclipse BlueChi project +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +import os +from typing import Dict + +from bluechi_test.config import BluechiAgentConfig, BluechiControllerConfig +from bluechi_test.machine import BluechiAgentMachine, BluechiControllerMachine +from bluechi_test.test import BluechiTest + +node_foo_name = "node-foo" + + +def exec(ctrl: BluechiControllerMachine, nodes: Dict[str, BluechiAgentMachine]): + result, output = ctrl.run_python(os.path.join("python", "is_node_disconnected.py")) + if result != 0: + raise Exception(output) + + +def test_bluechi_heartbeat_node_disconnected( + bluechi_test: BluechiTest, + bluechi_ctrl_default_config: BluechiControllerConfig, + bluechi_node_default_config: BluechiAgentConfig, +): + + bluechi_ctrl_default_config.allowed_node_names = [node_foo_name] + bluechi_ctrl_default_config.heartbeat_interval = "2000" + + bluechi_node_default_config.node_name = node_foo_name + bluechi_node_default_config.heartbeat_interval = "0" + + bluechi_test.set_bluechi_controller_config(bluechi_ctrl_default_config) + bluechi_test.add_bluechi_agent_config(bluechi_node_default_config) + + bluechi_test.run(exec)