Hey Deprecated
Use rakyll/hey to test a web application with a load of requests.
python · Developer Tools
Source
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 import re import subprocess # ---------- CONSTANTS ---------- # FLOAT_RE = r'\d+\.\d+' INT_RE = r'\d+' BYTES_RE = r'\d+ bytes' # ---------- HELPER FUNCTIONS ---------- # def try_re(pattern: str, string: str, i: int = 0) -> Optional[Any]: re_res = re.findall(pattern, string) if len(re_res) == i + 1: # ignore cases where len is greater than expected return re_res[i] return None def name_value_arg_to_dict(arg: Optional[str]): parsed_input: dict[str, str] = {} if arg: args = argToList(arg) for item in args: if isinstance(item, str): key_val = item.split('=') if len(key_val) <= 1: raise DemistoException(f'Invalid arg provided {item}. expected comma separated list of "key=value"') else: key = key_val[0] val = item[len(key) + 1:] parsed_input[key] = val return parsed_input def construct_hey_query(url: str, requests_number: Optional[str] = None, timeout: Optional[str] = None, concurrency: Optional[str] = None, duration: Optional[str] = None, method: Optional[str] = None, disable_compression: Optional[str] = None, headers: Optional[str] = None, body: Optional[str] = None, proxy: Optional[str] = None, enable_http2: Optional[str] = None, disable_redirects: Optional[str] = None): hey_map = assign_params( t=timeout, n=requests_number, c=concurrency, m=method, z=duration + 's' if duration else None, d=body, x=proxy ) query_args = ["hey"] if disable_compression == 'true': query_args.append('--disable-compression') if enable_http2 == 'true': query_args.append('-h2') if disable_redirects == 'true': query_args.append('-disable-redirects') if headers: for header_key, header_val in name_value_arg_to_dict(headers).items(): query_args.extend(('-H', f'{header_key}:{header_val}')) for k, v in hey_map.items(): query_args.extend([f"-{k}", v]) query_args.append(url) return hey_map, query_args # ---------- CLASSES ---------- # class HeyPerformanceResult: def __init__(self, result: str, results_map: Optional[str], t: Optional[str] = None, c: Optional[str] = None, n: Optional[str] = None, z: Optional[str] = None, **args): self._t = int(t or 20) self._c = int(c or 50) self._z = int(z[:-1]) if z else None # remove 's' from z before parsing int _n = int(n or 200) self._n = _n - (_n % self._c) # remove c remainder self._result = result or '' self._ext_outputs = name_value_arg_to_dict(results_map) def _get_summary(self, result: List[str]) -> tuple[dict, int]: """Returns summary dictionary and index after the summary""" summary = {} i = 0 for i in range(len(result)): if 'Summary' in result[i]: continue if 'Response' in result[i]: break if 'Total:' in result[i]: if self._z: continue total_time = try_re(FLOAT_RE, result[i]) if total_time: total_time = float(total_time) / self._c summary['TotalTime'] = total_time if 'Slowest' in result[i]: summary['SlowestTime'] = try_re(FLOAT_RE, result[i]) if 'Fastest' in result[i]: summary['FastestTime'] = try_re(FLOAT_RE, result[i]) if 'Average' in result[i]: summary['AverageTime'] = try_re(FLOAT_RE, result[i]) if 'Requests' in result[i]: summary['RequestsPerSecond'] = try_re(FLOAT_RE, result[i]) if 'Total data' in result[i]: summary['TotalData'] = try_re(BYTES_RE, result[i]) if 'Size' in result[i]: summary['SizePerRequest'] = try_re(BYTES_RE, result[i]) return summary, i @staticmethod def _get_successful_responses(result: List[str], result_i: int) -> int: """Returns number of successful responses in the result""" for i in range(result_i, len(result)): if '[200]' in result[i]: return try_re(INT_RE, result[i], 1) or 0 return 0 def human_readable_to_outputs(self): result = [line for line in self._result.split('\n') if line.strip() != ''] outputs, response_i = self._get_summary(result) outputs['SuccessfulResponses'] = self._get_successful_responses(result, response_i) outputs.update({ "TimeoutPerRequest": self._t, "Concurrency": self._c, "Requests": self._n, }) if self._ext_outputs: outputs.update(self._ext_outputs) return outputs def to_results(self) -> CommandResults: outputs = self.human_readable_to_outputs() if self._z: outputs['TotalTime'] = self._z return CommandResults(outputs=outputs, outputs_prefix="Hey", readable_output=self._result) def run_hey_test(url: str, requests_number: Optional[str] = None, timeout: Optional[str] = None, concurrency: Optional[str] = None, duration: Optional[str] = None, method: Optional[str] = None, disable_compression: Optional[str] = None, results_map: Optional[str] = None, headers: Optional[str] = None, body: Optional[str] = None, proxy: Optional[str] = None, enable_http2: Optional[str] = None, disable_redirects: Optional[str] = None, *_args, **_kwargs) -> CommandResults: hey_map, hey_query = construct_hey_query(url, requests_number, timeout, concurrency, duration, method, disable_compression, headers, body, proxy, enable_http2, disable_redirects) result = subprocess.check_output(hey_query, stderr=subprocess.STDOUT, text=True) return HeyPerformanceResult(result=result, results_map=results_map, **hey_map).to_results() def main() -> None: # pragma: no cover args = demisto.args() try: return_results(run_hey_test(**args)) # Log exceptions and return errors except Exception as e: return_error(f'Error:\n{str(e)}') if __name__ in ('__main__', '__builtin__', 'builtins'): main()
README
Use rakyll/hey to test a web application with a load of requests.
Inputs
| Argument Name | Description |
|---|---|
| url | URL to query. |
| requests_number | Number of requests to run. Default is 200. |
| timeout | Timeout for each request in seconds. Default is 20, use 0 for infinite. |
| concurrency | Number of workers to run concurrently. |
| duration | Duration of application to send requests (in seconds). |
| method | HTTP method. |
| headers | Custom HTTP header. Comma separated list of “key=value”. e.g. Type=IP,Size=100. |
| disable_compression | Disable compression. |
| results_map | Additional information to add to the result. Comma separated list of “key=value”. e.g. Content-Type=text/plain,Accept=*/*. |
| body | HTTP request body. |
| proxy | HTTP Proxy address as host:port. |
| enable_http2 | Enable HTTP/2. |
| disable_redirects | Disable following of HTTP redirects. |
Outputs
| Path | Description | Type |
|---|---|---|
| Hey.Timeout | Timeout for each request. | number |
| Hey.Concurrency | Max number of concurrent workers. | number |
| Hey.Requests | Number of requests sent to URL. | number |
| Hey.SlowestTime | The slowest time it took for a request to finish. | number |
| Hey.FastestTime | The fastest time it took for a request to finish. | number |
| Hey.SuccessfulResponses | The number of responses that returned with 200 status code. | number |
| Hey.AverageTime | The average time it took for a request to finish. | number |
| Hey.Result | The full result in text format when output is set to “human_readable” | number |