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

test: add test script #169

Closed
wants to merge 65 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
47eba8f
docs: add README file into manual-tests directory
PhilipTamb Oct 10, 2023
c91c36c
feat(test): add automated-tests
PhilipTamb Oct 17, 2023
980f98f
style: clean automated-test code
PhilipTamb Oct 17, 2023
0a16a71
feat(test): update after first PR, add requirements.txt
PhilipTamb Oct 18, 2023
a2f8716
feat(test): add getting-started test
PhilipTamb Oct 19, 2023
78a49b6
feat(test): update after Second Review
PhilipTamb Oct 23, 2023
d44041f
feat(test): add automated-test into workflow
PhilipTamb Oct 24, 2023
b3947b1
feat(test): fix zenoh-flow path into test
PhilipTamb Oct 25, 2023
3b290d8
ci: 1t CI workflow test
PhilipTamb Oct 27, 2023
e046371
ci: 2t CI workflow test
PhilipTamb Oct 27, 2023
067860c
ci: 3t CI workflow test
PhilipTamb Oct 27, 2023
29c278d
ci: 4t CI workflow test
PhilipTamb Oct 27, 2023
af3a05a
ci: 5t CI workflow test
PhilipTamb Oct 27, 2023
dfd04fd
ci: 6ts CI workflow test
PhilipTamb Oct 27, 2023
9d27dd4
ci: 7ts CI workflow test
PhilipTamb Oct 27, 2023
cba4d03
ci: 8st CI workflow test
PhilipTamb Oct 28, 2023
60c6201
ci: 9st CI workflow test
PhilipTamb Oct 28, 2023
302ddd9
ci: 10st CI workflow test
PhilipTamb Oct 29, 2023
c8f7dc5
ci: 11st CI workflow test
PhilipTamb Oct 29, 2023
c30b29d
ci: 12st CI workflow test
PhilipTamb Oct 29, 2023
1dfc64b
ci: 12st CI workflow test
PhilipTamb Oct 29, 2023
36199f9
ci: 13st CI workflow test
PhilipTamb Oct 29, 2023
921cebf
ci: 14 CI workflow test
PhilipTamb Oct 30, 2023
0390228
ci: 15 CI workflow test
PhilipTamb Oct 30, 2023
ebddd4e
ci: 16 CI workflow test
PhilipTamb Oct 30, 2023
3498e99
ci: 17 CI workflow test
PhilipTamb Oct 30, 2023
664f26c
ci: 18 CI workflow test
PhilipTamb Oct 30, 2023
c92bee4
ci: 18 CI workflow test
PhilipTamb Oct 30, 2023
ca6ce2b
ci: 19 CI workflow test
PhilipTamb Oct 30, 2023
6b86541
ci: 20 CI workflow test
PhilipTamb Oct 30, 2023
72bbeee
ci: 21 CI workflow test
PhilipTamb Oct 30, 2023
10cc755
ci: 21 CI workflow test
PhilipTamb Oct 31, 2023
5278a3b
ci: 22 CI workflow test
PhilipTamb Oct 31, 2023
a74117f
ci: 23 CI workflow test
PhilipTamb Oct 31, 2023
4582202
ci: 24 CI workflow test, update automated-test.py
PhilipTamb Oct 31, 2023
4e086ff
ci: 24 CI workflow test, update automated-test.py
PhilipTamb Oct 31, 2023
5767b6c
ci: 24 CI workflow test, update automated-test.py
PhilipTamb Oct 31, 2023
e68346e
ci: 25 CI workflow test
PhilipTamb Nov 1, 2023
d05d5fd
ci: 26 CI workflow test, update automated-test.py
PhilipTamb Nov 2, 2023
772c5d5
ci: 27 CI workflow test
PhilipTamb Nov 2, 2023
bb10085
ci: 28 CI workflow test
PhilipTamb Nov 2, 2023
c3ff32e
ci: 28 CI workflow test
PhilipTamb Nov 2, 2023
d8ee7b0
ci: 30 CI workflow test
PhilipTamb Nov 2, 2023
7b655af
ci: 31 CI workflow test
PhilipTamb Nov 2, 2023
300ac39
ci: 32 CI workflow test
PhilipTamb Nov 3, 2023
19bab28
ci: 33 CI workflow test
PhilipTamb Nov 3, 2023
4c98504
ci: 34 CI workflow test
PhilipTamb Nov 3, 2023
c22d71a
ci: 35 CI workflow test
PhilipTamb Nov 3, 2023
e3d4fd9
ci: 36 CI workflow test
PhilipTamb Nov 3, 2023
0d73741
ci: 37 CI workflow test
PhilipTamb Nov 4, 2023
c68eb94
ci: 38 CI workflow test
PhilipTamb Nov 4, 2023
f990ab5
ci: 39 CI workflow test
PhilipTamb Nov 6, 2023
c90d6d8
ci: 40 CI workflow test
PhilipTamb Nov 6, 2023
6f25443
ci: 40 CI workflow test
PhilipTamb Nov 6, 2023
49a3b21
ci: 41 CI workflow test
PhilipTamb Nov 6, 2023
67b1366
ci: 42 CI workflow test
PhilipTamb Nov 6, 2023
2c9d31c
ci: 43 CI workflow test
PhilipTamb Nov 6, 2023
5b16f1b
ci: 43 CI workflow test
PhilipTamb Nov 6, 2023
b44f2b5
ci: 44 CI workflow test
PhilipTamb Nov 6, 2023
83db30d
ci: 45 CI workflow test
PhilipTamb Nov 7, 2023
d92f145
ci: 46 CI workflow test
PhilipTamb Nov 8, 2023
15dcbe1
feat: update automated-test with standalone feature
PhilipTamb Jan 2, 2024
b2e9608
refacto: update zenoh-flow build step
PhilipTamb Jan 2, 2024
cb060ea
refacto: update zenoh-flow build step
PhilipTamb Jan 2, 2024
6a5732e
refacto: update zenoh-flow build step
PhilipTamb Jan 2, 2024
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
25 changes: 25 additions & 0 deletions manual-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Automated Test
## What the script does
In this folder there is a python script to automatically test that zenoh-flow works.

At first the script starts to find the zenoh and zenoh-flow executables and the configuration file paths, this is necessary to build the command to be able to run Zenoh with Zenoh-Flow as plugin.
Furthermore the test makes sure that the zenoh configuration is able to run zenoh-flow as a plugin.

## How does the test work?
This test use the getting-started example to validate the zenoh-flow functionality.

The script test verifies:
- Zenoh with zenoh-flow plugin is up and running.
- The example runs correctly.
- That the number of active Zenoh-Flow nodes is equal to the number of nodes declared into the yaml file.

## How to run
To do this you need to run :
```bash
pip install -r requirements.txt
python3 automated-test.py
```

```bash
usage: automated-test.py -h/--help: to show the script options.
```
342 changes: 342 additions & 0 deletions manual-tests/automated-test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
import argparse
import fnmatch
import os
import platform
import shutil
import signal
import time

import psutil
import yaml
from yaml.loader import SafeLoader


class ZF_conf:
def __init__(self):
self.zenohd_path = None
self.zf_plugin_path = None
self.zf_router_path = None
self.zenohd_process = None
self.zfctl_path = None
self.zfctl_json_path = None
self.zf_deamon_yaml = None
self.zenoh_flow_daemon = None
self.uuid_runtimes = None
self.libzenoh_plugin = None


zf_conf = ZF_conf()

zf_command = {
"zenohd_cmd": None,
"runtimes_cmd": None,
"dataflow_yaml_cmd": None,
"instances_cmd": None,
}
instance = {
"uuid_instances": None,
"flow": None,
"operators": None,
"sinks": None,
"sources": None,
"connectors": None,
"links": None,
}


def find_dir(name, path):
for root, dirs, files in os.walk(path):
if name in dirs:
return os.path.join(root, name)


def find(pattern, path):
result = []
for root, dirs, files in os.walk(path):
for name in files:
if fnmatch.fnmatch(name, pattern):
result.append(os.path.join(root, name))
return result


pid_zenohd = 0
json_flag = False

zenohflow_release_flag = False

parser = argparse.ArgumentParser(
description="Script to automatically test that zenoh-flow works"
)

parser.add_argument(
"-b",
"--build",
nargs="?",
type=str,
default="False",
help="Specifies a different directory for Zenoh-Flow artifacts (default=debug)",
J-Loudet marked this conversation as resolved.
Show resolved Hide resolved
)
parser.add_argument(
"-z",
"--zenohd",
nargs="?",
type=str,
default="/.local/bin/zenohd",
help="Specifies a different path for the zenohd process (default=/.local/bin/zenohd)",
)
parser.add_argument(
"-c",
"--zfctl",
nargs="?",
type=str,
default="/.config/zenoh-flow/zfctl.json",
help="Specifies a different path for the zenoctl process (default=/.config/zenoh-flow/zfctl.json)",
)
parser.add_argument(
"-p",
"--plugin",
nargs="?",
type=str,
default="/.config/zenoh-flow/zenoh-zf-plugin-01.json",
help="Specifies a different path for Zenoh-Flow plugin file (default=/.config/zenoh-flow/zenoh-zf-plugin-01.json)",
)
args = parser.parse_args()

home_path = os.path.expanduser("~")
zenoh_release_flag = args.build

if (
args.zenohd == "/.local/bin/zenohd"
or args.zfctl == "/.config/zenoh-flow/zfctl.json"
):
print(home_path)
zf_conf.zenohd_path = home_path + str(args.zenohd)
zf_conf.zfctl_path = home_path + str(args.zfctl)
zf_conf.zf_plugin_path = home_path + str(args.plugin)
else:
zf_conf.zenohd_path = args.zenohd
zf_conf.zfctl_path = args.zfctl
zf_conf.zf_plugin_path = args.plugin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to put the correct path in the default options. If users run the "help" option and see "/.config/…" they can assume that something is wrong.

There is the function: os.path.expanduser().

What I suggest you do: provide a default option with ~ in the path & call expanduser in all cases (be it the default option or provided by the user).


print("[Info] Looking for paths...")
manual_tests_path = os.getcwd()
zenoh_flow_path = os.path.abspath(os.path.join(manual_tests_path, os.pardir))

print(f"Path of zenohd: {zf_conf.zenohd_path}")
print(f"Path of zenoh-Flow path: {zenoh_flow_path}")

if os.path.exists("./../examples/flows/getting-started.yaml"):
data_flow_path = os.path.join(
zenoh_flow_path, "examples/flows/getting-started.yaml"
)

print(f"Path of getting-started example: {data_flow_path}")

dir_zenoh_zf_plugin = zenoh_flow_path + "/zenoh-flow-plugin/etc/"
zenoh_zf_plugin_path = zenoh_flow_path + "/zenoh-flow-plugin/etc/zenoh-zf-plugin.json"
print(f"Path of plugin library: {zenoh_zf_plugin_path}")

lib_name = ""
if platform.system() == "Windows":
lib_name = "libzenoh_plugin_zenoh_flow.dll"
elif platform.system() == "Linux":
lib_name = "libzenoh_plugin_zenoh_flow.so"
elif platform.system() == "Darwin":
lib_name = "libzenoh_plugin_zenoh_flow.dylib"

if zenoh_release_flag == "release":
libzenoh_plugin_path = os.path.join(zenoh_flow_path, "target/release/")
elif zenoh_release_flag == "debug":
libzenoh_plugin_path = os.path.join(zenoh_flow_path, "target/debug/")

print(f"Path of zfctl: {zf_conf.zfctl_path}")

p = "zenoh-zf-plugin-01.json".__len__()
if zf_conf.zf_plugin_path[-p:] != "zenoh-zf-plugin-01.json":
print("[Info] Zenoh-Flow as Zenoh plugin")
if os.path.exists(os.path.join(manual_tests_path, "zenoh-zf-plugin.json")) is False:
print(zenoh_zf_plugin_path)
shutil.copy(zenoh_zf_plugin_path, manual_tests_path)
add_lib_folder = ""

zf_conf.zf_plugin_path = os.path.join(manual_tests_path, "zenoh-zf-plugin.json")
with open(zenoh_zf_plugin_path) as json_file:
json_string = json_file.read()
if json_string.find(dir_zenoh_zf_plugin) == -1:
start_row = json_string.find('"plugins_search_dirs":[')
index = (start_row - 1) + '"plugins_search_dirs": ['.__len__()
add_lib_folder = (
json_string[:index]
+ '"'
+ dir_zenoh_zf_plugin
+ '",'
+ json_string[index:]
)

if add_lib_folder != "":
with open(zf_conf.zf_plugin_path, "w", encoding="utf8") as json_file:
json_file.write(add_lib_folder)

print("[Info] Commands:")
if (
zf_conf.zenohd_path != home_path + "/.local/bin/zenohd"
or zf_conf.zfctl_path != home_path + "/.config/zenoh-flow/zfctl.json"
):
zf_command["zenohd_cmd"] = zf_conf.zenohd_path + " -c " + zf_conf.zf_plugin_path
print(f'Lauch Zenoh with Zenoh-Flow plugin: \n {zf_command["zenohd_cmd"]}')
zf_command["runtimes_cmd"] = zf_conf.zfctl_path + " list runtimes"
print(f'show the list of runtimes: \n {zf_command["runtimes_cmd"]}')
zf_command["dataflow_yaml_cmd"] = zf_conf.zfctl_path + " launch " + data_flow_path
print(f'Lauch Zenoh-Flow configuration: \n {zf_command["dataflow_yaml_cmd"]}')
zf_command["instances_cmd"] = zf_conf.zfctl_path + " list instances"
print(f'show list of Zenoh-Flow instances: \n {zf_command["instances_cmd"]}')
else:
zf_command["zenohd_cmd"] = zf_conf.zenohd_path + " -c " + zf_conf.zf_plugin_path
print(f'Lauch Zenoh with Zenoh-Flow plugin: \n {zf_command["zenohd_cmd"]}')
zf_command["runtimes_cmd"] = (
"ZFCTL_CFG="
+ zf_conf.zfctl_path
+ " "
+ home_path
+ "/.local/bin/zfctl"
+ " list runtimes"
)
print(f'show the list of runtimes: \n {zf_command["runtimes_cmd"]}')
zf_command["dataflow_yaml_cmd"] = (
"ZFCTL_CFG="
+ zf_conf.zfctl_path
+ " "
+ home_path
+ "/.local/bin/zfctl"
+ " launch "
+ data_flow_path
)
print(f'Lauch Zenoh-Flow configuration: \n {zf_command["dataflow_yaml_cmd"]}')
zf_command["instances_cmd"] = (
"ZFCTL_CFG="
+ zf_conf.zfctl_path
+ " "
+ home_path
+ "/.local/bin/zfctl"
+ " list instances"
)
print(f'show list of Zenoh-Flow instances: \n {zf_command["instances_cmd"]}')

print("[Info] Looking for Zenohd process...")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that you are not just looking for zenohd processes, I would rather write:

Suggested change
print("[Info] Looking for Zenohd process...")
print("[Info] Killing extra `zenohd` processes...")

process_name = "zenohd"
pid = None
for process in psutil.process_iter():
if process_name in process.name():
pid = process.pid
print(f"[Info] kill process: {pid}")
os.kill(pid, signal.SIGKILL)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't this be simplified like so?

Suggested change
pid = process.pid
print(f"[Info] kill process: {pid}")
os.kill(pid, signal.SIGKILL)
print(f"[Info] kill process: {process.pid}")
process.kill()



print(f'[Info] Launching Zenod process: {zf_command["zenohd_cmd"]}')
launch_zenohd = os.popen(zf_command["zenohd_cmd"])
print("Waiting for zenohd...")
time.sleep(5)
pid = ""
for process in psutil.process_iter():
if process_name in process.name():
pid = process.pid
break

print(f"[Info] Test {process_name} process pid {pid}")
zf_conf.zenohd_process = pid
if zf_conf.zenohd_process is not None:
print(f'[Info] Launching list runtimes command: {zf_command["runtimes_cmd"]}')
launch_runtimes = os.popen(zf_command["runtimes_cmd"])
runtimes_string = launch_runtimes.read().split()
for i in range(runtimes_string.__len__()):
if runtimes_string[i].__len__() == 32 and runtimes_string[i - 2][0] == "+":
print("[Info] test runtime: SUCCESS.")
print(f"[Info] UUID runtime: {runtimes_string[i]}")
zf_conf.uuid_runtimes = runtimes_string[i]
if zf_conf.uuid_runtimes is None:
print("[Info] test runtime: FAILED.")

print(f'[Info] Launching Zenoh-Flow example: {zf_command["dataflow_yaml_cmd"]}')

launch_zf_yaml = os.popen(zf_command["dataflow_yaml_cmd"])

zf_example_string = launch_zf_yaml.read()
print(f"[Info] zf_example_string: {zf_example_string}")
if zf_example_string.__len__() == 0:
print("[Error] Zenoh-Flow example: FAILED.")
else:
zf_conf.uuid_runtimes = zf_example_string
print(f"[Info] Zenoh-Flow example UUID: {zf_conf.uuid_runtimes}")

print(f'[Info] Launching list instances: {zf_command["instances_cmd"]}')
launch_instances = os.popen(zf_command["instances_cmd"])
count = 0
instances_string = launch_instances.read().split()
for i in range(instances_string.__len__()):
if instances_string[i][0] == "+":
count = count + 1
if count <= 2:
print("[Error] test data flow: FAILED.")
exit()
else:
print("[Info] test data flow instance: SUCCESS.")
instance["uuid_instances"] = instances_string[23]
instance["flow"] = instances_string[25]
instance["operators"] = instances_string[27]
instance["sinks"] = instances_string[29]
instance["sources"] = instances_string[31]
instance["connectors"] = instances_string[33]
instance["links"] = instances_string[35]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove these lines, they are too specific and will quickly return false negatives.
They are referred to as "magic numbers" and are considered bad practice.

else:
print("[Error] test zenohd process: FAILED.")


with open(data_flow_path, "r") as f:
try:
data = yaml.load(f, Loader=SafeLoader)
except yaml.YAMLError as e:
print(f"[Error] {e}")

if str(tuple(data["sources"]).__len__()) == instance["sources"]:
print(
f'[Info] test active Source nodes: SUCCESS, the active Source nodes [{str(tuple(data["sources"]).__len__())}] are equal to declared Source nodes [{instance["sources"]}]'
)
if str(tuple(data["sinks"]).__len__()) == instance["sinks"]:
print(
f'[Info] test active Sink nodes: SUCCESS, the active Sink nodes [{str(tuple(data["sinks"]).__len__())}] are equal to those declared Sinks nodes [{instance["sinks"]}]'
)
if str(tuple(data["operators"]).__len__()) == instance["operators"]:
print(
f'[Info] test active Operator nodes: SUCCESS, the active Operator nodes [{str(tuple(data["operators"]).__len__())}] are equal declared Operator nodes [{instance["operators"]}]'
)
if (
str(tuple(data["sources"]).__len__()) != instance["sources"]
or str(tuple(data["sinks"]).__len__()) != instance["sinks"]
or str(tuple(data["operators"]).__len__()) != instance["operators"]
):
print("[Error] Test Zenoh-Flow configuration nodesSome nodes: FAILED.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the previous change I asked you to do, these lines need to be removed as well.


os.popen(
"curl -X PUT -H 'content-type:text/plain' -d 'Test' http://localhost:8000/zf/getting-started/hello"
)
time.sleep(1)
txt_res = open("/tmp/greetings.txt", "r")
res = txt_res.read()
if res.split()[1] == "Test!":
print(f"\n[Info] Test Recive: SUCCESS, {res}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the test to be more reliable, you need to:

  1. open the file, count the number of lines,
  2. do the curl
  3. ensure that the file contains one more line and check that that extra line is equal to "Hello, Test!"

else:
print("\n[Error] Test Recive: FAILED.")

process_name = "zenohd"
pid = None
for process in psutil.process_iter():
if process_name in process.name():
pid = process.pid
print(f"[Info] kill process: {pid}")
os.kill(pid, signal.SIGKILL)

print("\n[Info] Commands:")
print(zf_command["zenohd_cmd"])
print(zf_command["runtimes_cmd"])
print(zf_command["dataflow_yaml_cmd"])
print(zf_command["instances_cmd"])
2 changes: 2 additions & 0 deletions manual-tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
psutil==5.9.6
PyYAML==6.0.1
Loading