mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 09:13:01 +02:00
Refactor Furl into general curl
Signed-off-by: Ejub Sabic <ejub1946@outlook.com>
This commit is contained in:
@@ -8,13 +8,14 @@ simple GET request for index.html and checking for a key phrase.
|
||||
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:
|
||||
|
||||
@@ -11,7 +11,7 @@ port accessed from the host.
|
||||
"""
|
||||
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 @@ with infamy.Test() as test:
|
||||
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 @@ with infamy.Test() as test:
|
||||
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()
|
||||
|
||||
@@ -10,7 +10,7 @@ and are available inside the running container.
|
||||
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 @@ with infamy.Test() as test:
|
||||
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 @@ with infamy.Test() as test:
|
||||
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()
|
||||
|
||||
@@ -26,7 +26,7 @@ external port 8080 to ensure the web page, with a known key phrase, is
|
||||
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 @@ table ip nat {
|
||||
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()
|
||||
|
||||
@@ -6,14 +6,15 @@ Verify connectivity with a simple web server container that's been
|
||||
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"<html><body><p>{MESG}</p></body></html>"
|
||||
MESG1 = "It works"
|
||||
MESG2 = "Kilroy was here"
|
||||
BODY = f"<html><body><p>{MESG2}</p></body></html>"
|
||||
URL = f"http://{DUTIP}:91/index.html"
|
||||
|
||||
with test.step("Set up topology and attach to target DUT"):
|
||||
@@ -60,7 +61,6 @@ with infamy.Test() as test:
|
||||
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 @@ with infamy.Test() as test:
|
||||
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 infamy.Test() as test:
|
||||
})
|
||||
|
||||
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()
|
||||
|
||||
@@ -18,13 +18,14 @@ regular bridge, a VETH pair connects the container to the bridge.
|
||||
"""
|
||||
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 @@ with infamy.Test() as test:
|
||||
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()
|
||||
|
||||
@@ -7,7 +7,7 @@ content in the volume on restart.
|
||||
|
||||
"""
|
||||
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 @@ with infamy.Test() as test:
|
||||
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 @@ with infamy.Test() as test:
|
||||
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 @@ with infamy.Test() as test:
|
||||
# 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()
|
||||
|
||||
@@ -58,7 +58,6 @@ image::internal-network.svg[Internal networks]
|
||||
import infamy
|
||||
import infamy.util as util
|
||||
import infamy.route as route
|
||||
from infamy.furl import Furl
|
||||
|
||||
BODY = "<html><body><p>Router responding</p></body></html>"
|
||||
|
||||
@@ -647,12 +646,13 @@ with infamy.Test() as test:
|
||||
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()
|
||||
|
||||
@@ -5,7 +5,6 @@ from .env import Env
|
||||
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
|
||||
|
||||
@@ -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))
|
||||
@@ -5,6 +5,7 @@ import threading
|
||||
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 ""
|
||||
Reference in New Issue
Block a user