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

Drop py2.7 and add trio support! #55

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
701dca4
Add some additional `logdir` passing tests
goodboy Jul 5, 2019
b833789
Assign kwargs to `Scenario.defaults` at creation
goodboy Jul 5, 2019
c3d6bbd
Add official release stamp and be looser on pluggy version
goodboy Jul 5, 2019
c275334
Raise `ValueError` on non-tuple assignment
goodboy Jul 5, 2019
4bfe5db
Further fixes
goodboy Jul 5, 2019
7544b5d
Doc tweak
goodboy Jul 5, 2019
8ecbdb0
Use latest official sipp release in CI
goodboy Jul 5, 2019
a41df32
Moderninze setup.py to new PyPa standards
goodboy Jul 6, 2019
1ecc513
Drop runner related hooks
goodboy Jul 11, 2019
060e9b5
Use `trio` for process and scenario launching!
goodboy Jul 11, 2019
de44f50
Adjust tests to match new `trio` apis
goodboy Jul 11, 2019
3911de9
Drop py2.7 from CI
goodboy Jul 11, 2019
d11fe44
Prepare setup script for 1.0 release
goodboy Jul 11, 2019
53bf511
trio.open_process() isn't released yet
goodboy Jul 12, 2019
e8a819a
Raise `ValueError` on non-tuple assignment
goodboy Jul 5, 2019
0492895
Drop runner related hooks
goodboy Jul 11, 2019
3df7a5f
Use `trio` for process and scenario launching!
goodboy Jul 11, 2019
90e8f1d
Adjust tests to match new `trio` apis
goodboy Jul 11, 2019
6d31c32
Drop py2.7 from CI
goodboy Jul 11, 2019
dbc8274
Prepare setup script for 1.0 release
goodboy Jul 11, 2019
6394960
trio.open_process() isn't released yet
goodboy Jul 12, 2019
77cf11a
Fix running agents with trio
kontsaki Dec 26, 2020
576b5be
Merge remote-tracking branch 'upstream/drop_py27' into drop_py27
kontsaki Dec 26, 2020
e58c5ed
Merge branch 'drop_py27' into drop_py27_more
kontsaki Dec 26, 2020
2d30b87
Fix ScenarioType uninitialized attribute
kontsaki Dec 26, 2020
50cf7a1
Merge pull request #63 from kontsaki/drop_py27_more
goodboy Jan 14, 2021
403c46e
Be explicit on dev version
goodboy Feb 12, 2021
ab27aa5
Update readme to reflect python version requirement
goodboy Feb 13, 2021
87f8efc
Merge branch 'master' into drop_py27
kontsaki Feb 13, 2021
acf8374
Merge pull request #69 from kontsaki/drop_py27
goodboy May 28, 2021
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ nosetests.xml
coverage.xml
*,cover

# virtual environment
venv

# Translations
*.mo
*.pot
Expand Down
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ cache:
- pip

python:
- 2.7
- 3.5
- 3.6
# - 3.7
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ but (want to) use it for automated testing because it gets the job done...


## What is it?
Python configuring and launching the infamous
[SIPp](http://sipp.sourceforge.net/) using an api inspired by
[requests](http://docs.python-requests.org/)
Python 3.6+ configuring and launching the infamous
[SIPp](http://sipp.sourceforge.net/) using a simple API to
generate commands and spawn them in subprocesses.

Command subprocess launching now uses
[`trio`](https://trio.readthedocs.io/en/stable/reference-io.html#spawning-subprocesses)!

## It definitely lets you

Expand All @@ -25,7 +28,7 @@ Python configuring and launching the infamous


## Basic Usage
Launching the default UAC scenario is a short line:
Launching the default UAC script is a short line:

```python
import pysipp
Expand Down
66 changes: 5 additions & 61 deletions pysipp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,11 @@
"""
import sys
from os.path import dirname
from . import launch, report, plugin, netplug, agent
from . import plugin, netplug, agent
from .load import iter_scen_dirs
from .agent import client, server


class SIPpFailure(RuntimeError):
"""SIPp commands failed"""


__package__ = "pysipp"
__author__ = "Tyler Goodlet ([email protected])"

Expand Down Expand Up @@ -97,10 +93,12 @@ def scenario(dirpath=None, proxyaddr=None, autolocalsocks=True, **scenkwargs):

# same as above
scen = plugin.mng.hook.pysipp_conf_scen_protocol(
agents=[uas, uac], confpy=None, scenkwargs=scenkwargs
agents=[uas, uac],
confpy=None,
scenkwargs=scenkwargs,
)

if proxyaddr:
if proxyaddr is not None:
assert isinstance(proxyaddr, tuple), "proxyaddr must be a (addr, port) tuple"
scen.clientdefaults.proxyaddr = proxyaddr

Expand Down Expand Up @@ -188,59 +186,5 @@ def pysipp_conf_scen(agents, scen):
ua.rtp_echo = True


@plugin.hookimpl
def pysipp_new_runner():
"""Provision and assign a default cmd runner"""
return launch.PopenRunner()


@plugin.hookimpl
def pysipp_run_protocol(scen, runner, block, timeout, raise_exc):
""" "Run all rendered commands with the provided runner or the built-in
PopenRunner which runs commands locally.
"""
# use provided runner or default provided by hook
runner = runner or plugin.mng.hook.pysipp_new_runner()
agents = scen.prepare()

def finalize(cmds2procs=None, timeout=180, raise_exc=True):
"""Wait for all remaining agents in the scenario to finish executing
and perform error and logfile reporting.
"""
cmds2procs = cmds2procs or runner.get(timeout=timeout)
agents2procs = list(zip(agents, cmds2procs.values()))
msg = report.err_summary(agents2procs)
if msg:
# report logs and stderr
report.emit_logfiles(agents2procs)
if raise_exc:
# raise RuntimeError on agent failure(s)
# (HINT: to rerun type `scen()` from the debugger)
raise SIPpFailure(msg)

return cmds2procs

try:
# run all agents (raises RuntimeError on timeout)
cmds2procs = runner(
(ua.render() for ua in agents), block=block, timeout=timeout
)
except launch.TimeoutError: # sucessful timeout
cmds2procs = finalize(timeout=0, raise_exc=False)
if raise_exc:
raise
else:
# async
if not block:
# XXX async run must bundle up results for later processing
scen.finalize = finalize
return finalize

# sync
finalize(cmds2procs, raise_exc=raise_exc)

return runner


# register the default hook set
plugin.mng.register(sys.modules[__name__])
69 changes: 43 additions & 26 deletions pysipp/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@
import re
import itertools
import tempfile
from functools import partial
from copy import deepcopy
from distutils import spawn
from collections import namedtuple, OrderedDict
from . import command, plugin, utils

import trio

from . import command, plugin, utils, launch, report

log = utils.get_logger()

SocketAddr = namedtuple("SocketAddr", "ip port")

DEFAULT_RUNNER_TIMEOUT = 180


def tuple_property(attrs):
def getter(self):
Expand Down Expand Up @@ -61,24 +67,18 @@ def name(self):
ipcaddr = tuple_property(("ipc_host", "ipc_port"))
call_load = tuple_property(("rate", "limit", "call_count"))

def __call__(self, block=True, timeout=180, runner=None, raise_exc=True, **kwargs):
def __call__(self, *args, **kwargs):
return self.run(*args, **kwargs)

def run(self, timeout=180, **kwargs):

# create and configure a temp scenario
scen = plugin.mng.hook.pysipp_conf_scen_protocol(
agents=[self],
confpy=None,
scenkwargs={},
)
# run the standard protocol
# (attach allocted runner for reuse/post-portem)
return plugin.mng.hook.pysipp_run_protocol(
scen=scen,
block=block,
timeout=timeout,
runner=runner,
raise_exc=raise_exc,
**kwargs
)
return scen.run(timeout=timeout, **kwargs)

def is_client(self):
return "uac" in self.name.lower()
Expand Down Expand Up @@ -262,8 +262,12 @@ def __init__(
confpy=None,
enable_screen_file=True,
):
# placeholder for process "runner"
self._runner = None

# agents iterable in launch-order
self._agents = agents
self._prepared_agents = None
ua_attrs = UserAgent.keys()

# default settings
Expand Down Expand Up @@ -431,21 +435,34 @@ def from_agents(self, agents=None, autolocalsocks=True, **scenkwargs):
"""Create a new scenario from prepared agents."""
return type(self)(self.prepare(agents), self._defaults, confpy=self.mod)

def __call__(
async def arun(
self,
agents=None,
block=True,
timeout=180,
timeout=DEFAULT_RUNNER_TIMEOUT,
runner=None,
raise_exc=True,
copy_agents=False,
**kwargs
block=True,
):
return plugin.mng.hook.pysipp_run_protocol(
scen=self,
block=block,
timeout=timeout,
runner=runner,
raise_exc=raise_exc,
**kwargs
self._prepared_agents = agents = self.prepare()
self._runner = runner = runner or launch.TrioRunner()

return await launch.run_all_agents(runner, agents, timeout=timeout, block=block)

def finalize(self, *, timeout=DEFAULT_RUNNER_TIMEOUT):
assert (
self._prepared_agents and self._runner
), "Must run scenario before finalizing."
return trio.run(
partial(
launch.finalize,
self._runner,
self._prepared_agents,
timeout=timeout,
)
)

def run(self, timeout=180, **kwargs):
"""Run scenario blocking to completion."""
return trio.run(partial(self.arun, timeout=timeout, **kwargs))

def __call__(self, *args, **kwargs):
# TODO: deprecation warning here
return self.run(*args, **kwargs)
15 changes: 0 additions & 15 deletions pysipp/hookspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,3 @@ def pysipp_conf_scen(agents, scen):
socket arguments. It it the recommended hook for applying a default
scenario configuration.
"""


@hookspec(firstresult=True)
def pysipp_new_runner():
"""Create and return a runner instance to be used for invoking
multiple SIPp commands. The runner must be callable and support both a
`block` and `timeout` kwarg.
"""


@hookspec(firstresult=True)
def pysipp_run_protocol(scen, runner, block, timeout, raise_exc):
"""Perform steps to execute all SIPp commands usually by calling a
preconfigured command launcher/runner.
"""
Loading