diff --git a/providers/tutorial/bin/network_available.py b/providers/tutorial/bin/network_available.py new file mode 100755 index 0000000000..6e1fdb14fa --- /dev/null +++ b/providers/tutorial/bin/network_available.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +import sys +import argparse +import subprocess + + +def parse_args(argv): + parser = argparse.ArgumentParser() + parser.add_argument( + "interface", help="Interface which will be used to ping" + ) + parser.add_argument( + "--threshold", + "-t", + help="Maximum percentage of lost of packets to mark the test as ok", + default="90", + ) + return parser.parse_args(argv) + + +def network_available(interface, threshold): + print("Testing", interface) + ping_output = subprocess.check_output( + ["ping", "-I", interface, "-c", "10", "1.1.1.1"], + universal_newlines=True, + ) + print(ping_output) + if "% packet loss" not in ping_output: + raise SystemExit( + "Unable to determine the % packet loss from the output" + ) + perc_packet_loss = ping_output.rsplit("% packet loss", 1)[0].rsplit( + maxsplit=1 + )[1] + if float(perc_packet_loss) > float(threshold): + raise SystemExit( + "Detected packet loss ({}%) is higher than threshold ({}%)".format( + perc_packet_loss, threshold + ) + ) + print( + "Detected packet loss ({}%) is lower than threshold ({}%)".format( + perc_packet_loss, threshold + ) + ) + + +def main(argv=None): + if argv is None: + argv = sys.argv[1:] + args = parse_args(argv) + network_available(args.interface, args.threshold) + + +if __name__ == "__main__": + main() diff --git a/providers/tutorial/src/Makefile b/providers/tutorial/src/Makefile new file mode 100644 index 0000000000..1c4e6481b1 --- /dev/null +++ b/providers/tutorial/src/Makefile @@ -0,0 +1,10 @@ +.PHONY: +all: vfork_memory_share_test + +.PHONY: clean +clean: + rm -f vfork_memory_share_test + +vfork_memory_share_test: CFLAGS += -pedantic + +CFLAGS += -Wall diff --git a/providers/tutorial/src/vfork_memory_share_test.c b/providers/tutorial/src/vfork_memory_share_test.c new file mode 100644 index 0000000000..d50b282a28 --- /dev/null +++ b/providers/tutorial/src/vfork_memory_share_test.c @@ -0,0 +1,29 @@ +#include +#include + +#define MAGIC_NUMBER 24 + +static pid_t shared; + +int main(void){ + int pid = vfork(); + if(pid != 0){ + // we are in parent, we can't rely on us being suspended + // so let's give the children process 1s to write to the shared variable + // if we are not + if(shared != MAGIC_NUMBER){ + printf("Parent wasn't suspended when spawning child, waiting\n"); + sleep(1); + } + if(shared != MAGIC_NUMBER){ + printf("Child failed to set the variable\n"); + }else{ + printf("Child set the variable, vfork shares the memory\n"); + } + return shared != MAGIC_NUMBER; + } + // we are in children, we should now write to shared, parent will + // discover this if vfork implementation uses mamory sharing as expected + shared = MAGIC_NUMBER; + _exit(0); +} diff --git a/providers/tutorial/tests/test_network_available.py b/providers/tutorial/tests/test_network_available.py new file mode 100644 index 0000000000..3d115459cc --- /dev/null +++ b/providers/tutorial/tests/test_network_available.py @@ -0,0 +1,57 @@ +import unittest +import textwrap +from unittest import mock + +import network_available + + +class TestNetworkAvailable(unittest.TestCase): + + @mock.patch("subprocess.check_output") + def test_nominal(self, check_output_mock): + check_output_mock.return_value = textwrap.dedent( + """ + PING 1.1.1.1 (1.1.1.1) from 192.168.1.100 wlan0: 56(84) bytes + 64 bytes from 1.1.1.1: icmp_seq=1 ttl=53 time=39.0 ms + 64 bytes from 1.1.1.1: icmp_seq=2 ttl=53 time=143 ms + + --- 1.1.1.1 ping statistics --- + 2 packets transmitted, 2 received, 0% packet loss, time 170ms + rtt min/avg/max/mdev = 34.980/60.486/142.567/31.077 ms + """ + ).strip() + network_available.network_available("wlan0", "90") + self.assertTrue(check_output_mock.called) + + @mock.patch("subprocess.check_output") + def test_failure(self, check_output_mock): + check_output_mock.return_value = textwrap.dedent( + """ + PING 1.1.1.1 (1.1.1.1) from 192.168.1.100 wlan0: 56(84) bytes + 64 bytes from 1.1.1.1: icmp_seq=1 ttl=53 time=39.0 ms + + --- 1.1.1.1 ping statistics --- + 10 packets transmitted, a received, 90% packet loss, time 170ms + rtt min/avg/max/mdev = 34.980/60.486/142.567/31.077 ms + """ + ).strip() + with self.assertRaises(SystemExit): + network_available.network_available("wlan0", "0") + +class TestMain(unittest.TestCase): + + @mock.patch("subprocess.check_output") + def test_nominal(self, check_output_mock): + check_output_mock.return_value = textwrap.dedent( + """ + PING 1.1.1.1 (1.1.1.1) from 192.168.1.100 wlan0: 56(84) bytes + 64 bytes from 1.1.1.1: icmp_seq=1 ttl=53 time=39.0 ms + 64 bytes from 1.1.1.1: icmp_seq=2 ttl=53 time=143 ms + + --- 1.1.1.1 ping statistics --- + 2 packets transmitted, 2 received, 0% packet loss, time 170ms + rtt min/avg/max/mdev = 34.980/60.486/142.567/31.077 ms + """ + ).strip() + network_available.main(["--threshold", "20", "wlan0"]) + self.assertTrue(check_output_mock.called) diff --git a/providers/tutorial/units/extended_tutorial.pxu b/providers/tutorial/units/extended_tutorial.pxu new file mode 100644 index 0000000000..9eee435d92 --- /dev/null +++ b/providers/tutorial/units/extended_tutorial.pxu @@ -0,0 +1,55 @@ +id: network_iface_info +_summary: Fetches information of all network intefaces +plugin: resource +command: + ip -details -json link show | jq -r ' + .[] | "interface: " + .ifname + + "\nlink_info_kind: " + .linkinfo.info_kind + + "\nlink_type: " + .link_type + + "\noperstate: " + .operstate + "\n"' + +id: network_available +flags: simple +_summary: Test that the internet is reachable +requires: + (network_iface_info.link_info_kind == "" and network_iface_info.link_type == "ether") +command: + ping -c 1 1.1.1.1 + +id: network_speed +flags: simple +_summary: Test that the network speed is acceptable +depends: network_available +command: + curl -Y 600 -o /dev/null \ + https://cdimage.ubuntu.com/ubuntu-mini-iso/noble/daily-live/current/ + +id: network_speed_99 +flags: simple +_summary: Test that the network speed is acceptable +environ: + ACCEPTABLE_BYTES_PER_SECOND_SPEED +command: + echo Testing for the limit speed: "${ACCEPTABLE_BYTES_PER_SECOND_SPEED:-600}" + curl -Y "${ACCEPTABLE_BYTES_PER_SECOND_SPEED:-600}" -o /dev/null \ + "https://cdimage.ubuntu.com/ubuntu-mini-iso/noble/daily-live/current/" + +unit: template +template-resource: network_iface_info +template-unit: job +id: network_available_{interface} +template-id: network_available_interface +template-filter: + network_iface_info.link_type == "ether" and network_iface_info.link_info_kind == "" +requires: + (network_iface_info.interface == "{interface}" and network_iface_info.operstate == "UP") +command: + network_available.py {interface} +_summary: Test that the internet is reachable via {interface} +flags: simple + +id: vfork_memory_share +_summary: Check that vfork syscall shares the memory between parent and child +flags: simple +command: + vfork_memory_share_test