diff --git a/test/case/infix_containers/basic/test.py b/test/case/infix_containers/basic/test.py index e28b4bb8e..09e048f48 100755 --- a/test/case/infix_containers/basic/test.py +++ b/test/case/infix_containers/basic/test.py @@ -8,13 +8,14 @@ The RPC actions: stop + start, and restart are also verified. """ import infamy -from infamy.util import until +from infamy.util import until, curl def _verify(server): # TODO: Should really use mDNS here.... - url = infamy.Furl(f"http://[{server}]:91/index.html") - return url.check("It works") + url = f"http://[{server}]:91/index.html" + response = curl(url) + return response is not None and "It works" in response with infamy.Test() as test: diff --git a/test/case/infix_containers/bridge/test.py b/test/case/infix_containers/bridge/test.py index 66584988e..55c2839b2 100755 --- a/test/case/infix_containers/bridge/test.py +++ b/test/case/infix_containers/bridge/test.py @@ -11,7 +11,7 @@ """ import base64 import infamy -from infamy.util import until, to_binary +from infamy.util import until, to_binary, curl with infamy.Test() as test: NAME = "web-docker0" @@ -81,7 +81,6 @@ until(lambda: c.running(NAME), attempts=60) _, hport = env.ltop.xlate("host", "data") - url = infamy.Furl(URL) with infamy.IsolatedMacVlan(hport) as ns: ns.addip(OURIP) @@ -90,6 +89,6 @@ ns.must_reach(DUTIP) with test.step("Verify container is reachable on http://10.0.0.2:8080"): - until(lambda: url.nscheck(ns, MESG), attempts=10) + until(lambda: MESG in ns.call(lambda: curl(URL)), attempts=10) test.succeed() diff --git a/test/case/infix_containers/environment/test.py b/test/case/infix_containers/environment/test.py index eb2d5189c..a10e1a6c1 100755 --- a/test/case/infix_containers/environment/test.py +++ b/test/case/infix_containers/environment/test.py @@ -10,7 +10,7 @@ 3. Verify served content against environment variables """ import infamy -from infamy.util import until, to_binary +from infamy.util import until, to_binary, curl with infamy.Test() as test: @@ -23,7 +23,7 @@ NAME = "web-env" DUTIP = "10.0.0.2" OURIP = "10.0.0.1" - url = infamy.Furl(f"http://{DUTIP}:8080/cgi-bin/env.cgi") + URL =f"http://{DUTIP}:8080/cgi-bin/env.cgi" with test.step("Set up topology and attach to target DUT"): env = infamy.Env() @@ -103,6 +103,6 @@ for var in ENV_VARS: expected_strings.append(f'{var["key"]}={var["value"]}') - until(lambda: url.nscheck(ns, expected_strings)) + until(lambda: all(string in ns.call(lambda: curl(URL)) for string in expected_strings)) test.succeed() diff --git a/test/case/infix_containers/firewall_basic/test.py b/test/case/infix_containers/firewall_basic/test.py index d9c90d75e..d5cd9c951 100755 --- a/test/case/infix_containers/firewall_basic/test.py +++ b/test/case/infix_containers/firewall_basic/test.py @@ -26,7 +26,7 @@ only reachable from the public interface `ext0`, on 192.168.0.1:8080. """ import infamy -from infamy.util import until, to_binary +from infamy.util import until, to_binary, curl with infamy.Test() as test: @@ -181,15 +181,14 @@ until(lambda: c.running(WEBNM), attempts=60) with infamy.IsolatedMacVlan(hport) as ns: - NEEDLE = "tiny web server from the curiOS docker" + MESG = "tiny web server from the curiOS docker" ns.addip(OURIP) with test.step("Verify connectivity, host can reach target:ext0"): ns.must_reach(EXTIP) with test.step("Verify 'web' is NOT reachable on http://container-host.local:91"): - url = infamy.Furl(BAD_URL) - until(lambda: not url.nscheck(ns, NEEDLE)) + until(lambda: not ns.call(lambda: curl(BAD_URL))) with test.step("Verify 'web' is reachable on http://container-host.local:8080"): - url = infamy.Furl(GOOD_URL) - until(lambda: url.nscheck(ns, NEEDLE)) + until(lambda: MESG in ns.call(lambda: curl(GOOD_URL))) + test.succeed() diff --git a/test/case/infix_containers/phys/test.py b/test/case/infix_containers/phys/test.py index 1459444f6..534ac232e 100755 --- a/test/case/infix_containers/phys/test.py +++ b/test/case/infix_containers/phys/test.py @@ -6,14 +6,15 @@ given a physical interface instead of an end of a VETH pair. """ import infamy -from infamy.util import until, to_binary +from infamy.util import until, to_binary, curl with infamy.Test() as test: NAME = "web-phys" DUTIP = "10.0.0.2" OURIP = "10.0.0.1" - MESG = "Kilroy was here" - BODY = f"

{MESG}

" + MESG1 = "It works" + MESG2 = "Kilroy was here" + BODY = f"

{MESG2}

" URL = f"http://{DUTIP}:91/index.html" with test.step("Set up topology and attach to target DUT"): @@ -60,7 +61,6 @@ until(lambda: c.running(NAME), attempts=60) _, hport = env.ltop.xlate("host", "data") - url = infamy.Furl(URL) with infamy.IsolatedMacVlan(hport) as ns: ns.addip(OURIP) @@ -68,7 +68,7 @@ ns.must_reach(DUTIP) with test.step("Verify container is reachable on http://10.0.0.2:91"): - until(lambda: url.nscheck(ns, "It works"), attempts=10) + until(lambda: MESG1 in ns.call(lambda: curl(URL)), attempts=10) with test.step("Add a content mount, overriding index.html"): # Verify modifying a running container takes, issue #930 @@ -88,6 +88,6 @@ }) with test.step("Verify server is restarted and returns new content"): - until(lambda: url.nscheck(ns, MESG), attempts=60) + until(lambda: MESG2 in ns.call(lambda: curl(URL)), attempts=60) test.succeed() diff --git a/test/case/infix_containers/veth/test.py b/test/case/infix_containers/veth/test.py index fb72c47c4..028bf63fe 100755 --- a/test/case/infix_containers/veth/test.py +++ b/test/case/infix_containers/veth/test.py @@ -18,13 +18,14 @@ """ import base64 import infamy -from infamy.util import until +from infamy.util import until, curl with infamy.Test() as test: NAME = "web-br0-veth" DUTIP = "10.0.0.2" OURIP = "10.0.0.1" URL = f"http://{DUTIP}:91/index.html" + MESG = "It works" with test.step("Set up topology and attach to target DUT"): env = infamy.Env() @@ -97,13 +98,12 @@ until(lambda: c.running(NAME), attempts=60) _, hport = env.ltop.xlate("host", "data") - url = infamy.Furl(URL) with infamy.IsolatedMacVlan(hport) as ns: ns.addip(OURIP) with test.step("Verify basic DUT connectivity, host:data can ping DUT 10.0.0.2"): ns.must_reach(DUTIP) with test.step("Verify container 'web-br0-veth' is reachable on http://10.0.0.2:91"): - until(lambda: url.nscheck(ns, "It works"), attempts=10) + until(lambda: MESG in ns.call(lambda: curl(URL)), attempts=10) test.succeed() diff --git a/test/case/infix_containers/volume/test.py b/test/case/infix_containers/volume/test.py index 896b8ea85..0be586097 100755 --- a/test/case/infix_containers/volume/test.py +++ b/test/case/infix_containers/volume/test.py @@ -7,7 +7,7 @@ """ import infamy -from infamy.util import until +from infamy.util import until, curl with infamy.Test() as test: NAME = "web-volume" @@ -19,7 +19,7 @@ target = env.attach("target", "mgmt") tgtssh = env.attach("target", "mgmt", "ssh") addr = target.get_mgmt_ip() - url = infamy.Furl(f"http://[{addr}]:{PORT}/index.html") + URL = f"http://[{addr}]:{PORT}/index.html" if not target.has_model("infix-containers"): test.skip() @@ -53,7 +53,7 @@ tgtssh.runsh(cmd) with test.step("Verify container volume content"): - until(lambda: url.check(MESG), attempts=10) + until(lambda: MESG in curl(URL), attempts=10) with test.step("Upgrade container"): out = tgtssh.runsh(f"sudo container upgrade {NAME}") @@ -66,6 +66,6 @@ # print(f"Container {NAME} upgraded: {out.stdout}") with test.step("Verify container volume content survived upgrade"): - until(lambda: url.check(MESG), attempts=60) + until(lambda: MESG in curl(URL), attempts=60) test.succeed() diff --git a/test/case/use_case/ospf_container/test.py b/test/case/use_case/ospf_container/test.py index 1568f8d99..3b4c11a5f 100755 --- a/test/case/use_case/ospf_container/test.py +++ b/test/case/use_case/ospf_container/test.py @@ -58,7 +58,6 @@ import infamy import infamy.util as util import infamy.route as route -from infamy.furl import Furl BODY = "

Router responding

" @@ -647,12 +646,13 @@ def config_abr(target, data, link1, link2, link3): ns.addroute("0.0.0.0/0", "192.168.100.1") # breakpoint() with test.step("Verify ABR:data can access container A on R1 (10.1.1.101)"): - furl = Furl("http://10.1.1.101:8080") - util.until(lambda: furl.nscheck(ns, BODY)) + URL = "http://10.1.1.101:8080" + util.until(lambda: BODY in ns.call(lambda: util.curl(URL))) with test.step("Verify ABR:data can access container A on R2 (10.1.2.101)"): - furl = Furl("http://10.1.2.101:8080") - util.until(lambda: furl.nscheck(ns, BODY)) + URL = "http://10.1.2.101:8080" + util.until(lambda: BODY in ns.call(lambda: util.curl(URL))) with test.step("Verify ABR:data can access container A on R3 (10.1.3.101)"): - furl = Furl("http://10.1.3.101:8080") - util.until(lambda: furl.nscheck(ns, BODY)) + URL = "http://10.1.3.101:8080" + util.until(lambda: BODY in ns.call(lambda: util.curl(URL))) + test.succeed() diff --git a/test/infamy/__init__.py b/test/infamy/__init__.py index f5397d93c..c3abc6f19 100644 --- a/test/infamy/__init__.py +++ b/test/infamy/__init__.py @@ -5,7 +5,6 @@ from .env import ArgumentParser from .env import test_argument from .firewall import Firewall -from .furl import Furl from .netns import IsolatedMacVlan,IsolatedMacVlans from .portscanner import PortScanner from .sniffer import Sniffer diff --git a/test/infamy/furl.py b/test/infamy/furl.py deleted file mode 100644 index bfb40bd48..000000000 --- a/test/infamy/furl.py +++ /dev/null @@ -1,72 +0,0 @@ -"""Simple HTTP URL fetcher and content checker - -This module provides the a lightweight wrapper around urllib for testing -HTTP endpoints. It's designed specifically for test scenarios where you -need to: - -- Fetch HTTP content and verify it contains expected strings -- Perform checks from within network namespaces -- Validate multiple content patterns in a single request -- Handle network errors gracefully in test environments - -Example usage: - # Single needle check - url = Furl("http://example.com/api") - if url.check("success"): - print("API returned success") - - # Multiple needle check (all must match) - if url.check(["user: alice", "status: active", "role: admin"]): - print("All user details found") - - # Check from network namespace - with IsolatedMacVlan("eth0") as ns: - if url.nscheck(ns, "expected content"): - print("Content verified from namespace") -""" - -import urllib.error -import urllib.parse -import urllib.request - - -class Furl: - """Furl wraps urllib in a way similar to curl""" - def __init__(self, url): - """Create new URL checker""" - self.url = urllib.parse.quote(url, safe='/:') - - def check(self, needles, timeout=10): - """Connect to web server URL, fetch body and check for needle(s) - - Args: - needles: String or list of strings to search for in response - timeout: Request timeout in seconds - - Returns: - bool: True if all needles found in response, False otherwise - """ - # Backwards compat, make needles a list for uniform processing - if isinstance(needles, str): - needles = [needles] - - try: - with urllib.request.urlopen(self.url, timeout=timeout) as response: - text = response.read().decode('utf-8') - return all(needle in text for needle in needles) - except urllib.error.URLError: - return False - except ConnectionResetError: - return False - - def nscheck(self, netns, needles): - """"Call check() from netns - - Args: - netns: Network namespace to call from - needles: String or list of strings to search for in response - - Returns: - bool: True if all needles found in response, False otherwise - """ - return netns.call(lambda: self.check(needles)) diff --git a/test/infamy/util.py b/test/infamy/util.py index 96a8370ef..4a7c80e76 100644 --- a/test/infamy/util.py +++ b/test/infamy/util.py @@ -5,6 +5,7 @@ import infamy.neigh from infamy import netconf from infamy import restconf +import urllib.request class ParallelFn(threading.Thread): @@ -97,3 +98,22 @@ def warn(msg): YELLOW = "\033[93m" RST = "\033[0m" print(f"{YELLOW}warn - {msg}{RST}") + +def curl(url, timeout=10): + """Fetch a URL and return its response body as a UTF-8 string. + + Args: + url (str): The full URL to fetch. + timeout (int): Request timeout in seconds. + + Returns: + str | None: Response body as text, or None if the request failed. + """ + url = urllib.parse.quote(url, safe='/:') + + try: + with urllib.request.urlopen(url, timeout=timeout) as response: + return response.read().decode('utf-8', errors='replace') + except (urllib.error.URLError, ConnectionResetError, UnicodeEncodeError) as e: + print(f"[WARN] curl: failed to fetch {url}: {e}") + return "" \ No newline at end of file