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

Fix and enable test accoring to #1716 #486

Merged
merged 22 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
291f57c
Fix and enable test accoring to #1716:
voodam Jul 7, 2023
fa9a819
Rename:
voodam Jul 7, 2023
7c11795
- Document errorneous behaviour in CurlClient (TODO #488) and write s…
voodam Jul 11, 2023
81ca1db
Fix tests:
voodam Jul 11, 2023
e34301d
Added timeout to wait_while_busy. Before it waited for finish forever.
voodam Jul 13, 2023
66686a6
Minor fixes: remove unused method, improve logging
voodam Jul 18, 2023
4d9b651
Fix all the mess with IP passing:
voodam Jul 18, 2023
045f0c3
Rename: get_kwargs -> get_arg_names
voodam Jul 18, 2023
7032fd9
Minor improvements
voodam Jul 18, 2023
88e1797
Add framework/asserts.py layer
voodam Jul 20, 2023
af2a742
Rework ip_block tests significantly: now ip blocking and sending RST …
voodam Jul 20, 2023
fe80766
Remove small timeout from wait_for_conection_close. We don't need it …
voodam Jul 20, 2023
49a33ba
Change some annoying debug messages level to 6
voodam Sep 7, 2023
455ce40
Fix "local variable 'sent' referenced before assignment" error
voodam Sep 7, 2023
3152394
Fix errorneous and excess behaviour of DmesgFinder:
voodam Sep 7, 2023
3c62495
Fix tests.
voodam Sep 10, 2023
4e46ac5
Improve deproxy logging:
voodam Sep 10, 2023
69dec23
Fix miscofigurated tests
voodam Sep 15, 2023
aecb91e
Add --choice parameter: tests selection from interactive input.
voodam Sep 17, 2023
3f6937d
Add tests with 'ip_block on' to tests_disabled_remote.json
voodam Sep 24, 2023
291da54
Disable broken for remote configuration tests
voodam Oct 2, 2023
16752be
Dmesg reworked:
voodam Oct 3, 2023
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ failed, `u` — unexpected success, `x` — expected failure. `s` — skipped;
- `2` — Show tests names and performance counters;
- `3` — Full debug output.

The current state: be sure that verbose is set at least to 2 level, otherwise
you may find it difficult to detect errors, because some of exceptions are silently suppressed.

`duration` option controls duration in seconds of each workload test. Use small
values to obtain results quickly add large for more heavy stress tests. Default
is `10` seconds.
Expand Down
8 changes: 4 additions & 4 deletions access_log/test_access_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def start_all(self):
class AccessLogTest(CheckedResponses):
def test_success_path_http1x(self):
self.start_all()
klog = dmesg.DmesgFinder(ratelimited=False)
klog = dmesg.DmesgFinder(disable_ratelimit=True)
for status, body in [
(200, "body http ok"),
(204, None),
Expand All @@ -158,7 +158,7 @@ def test_success_path_http1x(self):

def test_uri_truncate(self):
self.start_all()
klog = dmesg.DmesgFinder(ratelimited=False)
klog = dmesg.DmesgFinder(disable_ratelimit=True)
req = self.make_request(
"/too-long-uri_" + "1" * 4000, user_agent="user-agent", referer="referer"
)
Expand All @@ -176,7 +176,7 @@ def test_uri_truncate(self):

def test_bad_user_agent(self):
self.start_all()
klog = dmesg.DmesgFinder(ratelimited=False)
klog = dmesg.DmesgFinder(disable_ratelimit=True)
req = self.make_request("/some-uri", user_agent="bad\nagent", referer="Ok-Referer")
msg = self.send_request_and_get_dmesg(klog, req)
self.assertTrue(msg is not None, "No access_log message in dmesg")
Expand Down Expand Up @@ -206,7 +206,7 @@ class AccessLogFrang(CheckedResponses):

def test_frang(self):
self.start_all()
klog = dmesg.DmesgFinder(ratelimited=False)
klog = dmesg.DmesgFinder(disable_ratelimit=True)
req = self.make_request(
"/longer-than-10-symbols-uri", user_agent="user-agent", referer="referer"
)
Expand Down
2 changes: 1 addition & 1 deletion access_log/test_access_log_h2.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def run_curl(self, curl):
curl.stop()

def run_test(self, status_code=200, is_frang=False):
klog = dmesg.DmesgFinder(ratelimited=False)
klog = dmesg.DmesgFinder(disable_ratelimit=True)
curl = self.get_client("curl")
referer = "http2-referer-%d" % status_code
user_agent = "http2-user-agent-%d" % status_code
Expand Down
6 changes: 2 additions & 4 deletions cache/test_purge.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,8 +570,6 @@ def test_purge_without_get_completed_with_no_warnings(self):
response = client.last_response

self.assertEqual(response.status, 200, response)
self.assertEqual(
self.oops.warn_count(dmesg.WARN_GENERIC),
0,
f"Warnings: {self.oops.warn_match('Warning: .*')}",
self.assertTrue(
self.oops.find(dmesg.WARN_GENERIC, cond=dmesg.amount_zero), f"Some warnings were found"
)
1 change: 1 addition & 0 deletions error
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Root privileges are required: need access to module loading on localhost.
9 changes: 4 additions & 5 deletions framework/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import multiprocessing
import os

from helpers import remote, stateful, tf_cfg
from helpers import remote, stateful, tf_cfg, util


def _run_client(client, resq: multiprocessing.Queue):
Expand Down Expand Up @@ -83,7 +83,7 @@ def cleanup(self):
self.node.remove_file(f)

def copy_files(self):
for (name, content) in self.files:
for name, content in self.files:
self.node.copy_file(name, content)

def is_busy(self, verbose=True):
Expand Down Expand Up @@ -163,6 +163,5 @@ def add_option_file(self, option, filename, content):
def set_user_agent(self, ua):
self.options.append("-H 'User-Agent: %s'" % ua)

def wait_for_finish(self):
while self.is_busy(verbose=False):
pass
def wait_for_finish(self, timeout=5):
return util.wait_until(lambda: self.is_busy(verbose=False), timeout)
73 changes: 59 additions & 14 deletions framework/curl_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,12 @@ class CurlArguments:
load_cookies: bool = False
ssl: bool = False
http2: bool = False
curl_iface: str = None
insecure: bool = True
parallel: int = None

@classmethod
def get_kwargs(cls) -> List[str]:
def get_arg_names(cls) -> List[str]:
"""Returns list of `CurlClient` supported argument names."""
return list(cls.__dataclass_fields__.keys())

Expand All @@ -115,15 +116,21 @@ class CurlClient(CurlArguments, client.Client):
cmd_args (str): additional curl options
data (str): data to POST
headers (dict[str, str]): headers to include in the request
dump_headers (bool): dump headers to the workdir, and enable response parsing.
Enabled by default.
dump_headers (bool): dump headers to the workdir, and enable response parsing
Enabled by default. In combination with parallel
can provide inaccurate results #488.
disable_output (bool): do not output results but only errors
save_cookies (bool): save cookies to the workdir
save_cookies (bool): Save cookies to the workdir.
Be aware: cookies are shared among all clients.
load_cookies (bool): load and send cookies from the workdir
ssl (bool): use SSL/TLS for the connection
http2 (bool): use HTTP version 2
curl_iface (str): Interface name, IP address or host name using for performing request.
Don't mess with "interface" argument, used by framework
for creating alias interfaces.
insecure (bool): Ignore SSL certificate errors. Enabled by default.
parallel (int): Enable parallel mode, with maximum <int> simultaneous transfers
parallel (int): Enable parallel mode, with maximum <int> simultaneous transfers.
In combination with dump_headers can provide inaccurate results #488.
"""

def __init__(self, **kwargs):
Expand Down Expand Up @@ -152,38 +159,72 @@ def requests(self, value):

@property
def responses(self) -> List[CurlResponse]:
"""List of all received responses."""
"""List of all received responses.
Can provide inaccurate results in some cases, (see dump_headers comment).
If dump_headers disabled, will be empty.
"""
return list(self._responses)

@property
def last_response(self) -> Optional[CurlResponse]:
"""Last parsed response if any."""
"""Last parsed response if any.
Can provide inaccurate results in some cases, (see dump_headers comment).
If dump_headers disabled, will be empty.
"""
return (self.responses or [None])[-1]

@property
def statuses(self) -> Dict[int, int]:
"""Received statuses counters, like:
"""Received statuses counters from headers, like:
{200: 1, 400: 2}
Can provide inaccurate results in some cases, (see dump_headers comment).
If dump_headers disabled, will be empty.
"""
return dict(self._statuses)

@statuses.setter
def statuses(self, value):
self._statuses = defaultdict(lambda: 0, value)

def statuses_from_stats(self) -> Dict[int, int]:
"""Received statuses counters from curl output, like:
{200: 1, 400: 2}
statuses property can provide inaccurate results in some cases,
(see dump_headers comment) - the function will be useful so.
"""
r = defaultdict(lambda: 0)
for s in self.stats:
r[int(s["response_code"])] += 1
return dict(r)

@property
def last_stats(self) -> Dict[str, Any]:
"""Information about last completed transfer.
See https://curl.se/docs/manpage.html#-w
for the list of available variables.
If disable_output enabled, will be empty.
"""
return (self._stats or [None])[-1]

@property
def stats(self) -> List[Dict[int, int]]:
"""List of stats of all transfers"""
def stats(self) -> List[Dict[str, Any]]:
"""List of stats of all transfers.
See https://curl.se/docs/manpage.html#-w
for the list of available variables.
If disable_output enabled, will be empty.
"""
return list(self._stats)

@property
def reset_conn_n(self) -> int:
"""
Amount of connections reseted by server (by RST).
"""
return sum(
"Connection reset by peer" in (s["errormsg"] or "") and s["response_code"] == 0
for s in self.stats
)

@property
def binary_version(self) -> Optional[str]:
"""curl binary version, parsed from the latest transfer."""
Expand All @@ -198,12 +239,14 @@ def cookie_jar_path(self):
@property
def output_path(self):
"""Path to write stdout (response)."""
return Path(self.workdir) / "curl-output"
# id(self) for the case of several client instances
return Path(self.workdir) / f"curl-output-{id(self)}"

@property
def headers_dump_path(self):
"""Path do dump received headers."""
return Path(self.workdir) / "curl-default.hdr"
# id(self) for the case of several client instances
return Path(self.workdir) / f"curl-{id(self)}.hdr"

@property
def cookie_string(self) -> str:
Expand Down Expand Up @@ -249,6 +292,9 @@ def form_command(self):
else:
options.append("--http1.1")

if self.curl_iface:
options.append(f"--interface {self.curl_iface}")

if self.ssl and self.insecure:
options.append("--insecure")

Expand All @@ -258,13 +304,12 @@ def form_command(self):
options.append(f"--parallel-max {self.parallel}")

cmd = " ".join([self.bin] + options + self.options + [f"'{self.uri}'"])
tf_cfg.dbg(3, f"Curl command formatted: {cmd}")
tf_cfg.dbg(2, f"Curl command formatted: {cmd}")
return cmd

def parse_out(self, stdout, stderr):
if self.dump_headers:
for dump in filter(None, self._read_headers_dump().split(b"\r\n\r\n")):

response = CurlResponse(
headers_dump=dump,
stdout_raw=self._read_output() if not self.disable_output else b"",
Expand Down
Loading