From 811797e6a74aa18035e2cd6d0d643033c4c19c93 Mon Sep 17 00:00:00 2001 From: "Y. Luis" <yluisrojo@gmail.com> Date: Fri, 27 Jul 2018 00:23:57 +0100 Subject: [PATCH 01/23] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ff9e857..0ec6cd3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ install: before_script: - git clone https://github.com/SIPp/sipp.git - cd sipp - - ./build.sh + - ./build.sh --full - export PATH="$PWD:$PATH" - cd .. From 67370d7e0dc5f85cfd8c9cf75eb5b45261e4838c Mon Sep 17 00:00:00 2001 From: Yunior Luis <yluisrojo@gmail.com> Date: Mon, 20 Aug 2018 11:23:48 +0200 Subject: [PATCH 02/23] Fix sipp build. Test with default Trusty. --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0ec6cd3..144d9b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,4 @@ language: python -sudo: false -dist: precise cache: - bundler @@ -29,11 +27,13 @@ install: - pip list before_script: - - git clone https://github.com/SIPp/sipp.git - - cd sipp - - ./build.sh --full + - wget https://github.com/SIPp/sipp/releases/download/v3.5.2/sipp-3.5.2.tar.gz + - tar -xvzf sipp-3.5.2.tar.gz + - cd sipp-3.5.2 + - ./configure + - make - export PATH="$PWD:$PATH" - cd .. script: - - pytest tests/ + - pytest tests/ \ No newline at end of file From 4c955a00e7fa165fbdc50538cc8159aed1792782 Mon Sep 17 00:00:00 2001 From: Yunior Luis <yl.rojo@zaleos.net> Date: Tue, 31 Jul 2018 18:58:42 +0200 Subject: [PATCH 03/23] remote-host as last position argument Fix sipp build. Test with default Trusty. --- pysipp/command.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pysipp/command.py b/pysipp/command.py index 0000184..417bc6e 100644 --- a/pysipp/command.py +++ b/pysipp/command.py @@ -188,8 +188,6 @@ def todict(self): # contact info '{prefix} ', '{bin_path} ', - ('{remote_host}', AddrField), # NOTE: no space - ':{remote_port} ', ('-i {local_host} ', AddrField), '-p {local_port} ', '-s {uri_username} ', @@ -244,6 +242,8 @@ def todict(self): ('-trace_logs {trace_log}', BoolField), ('-trace_screen {trace_screen}', BoolField), ('-error_overwrite {error_overwrite}', BoolField), + ('{remote_host}', AddrField), # NOTE: no space + ':{remote_port}', ] From 06bff09dd457bf3b932d250c9d6830451ef0989f Mon Sep 17 00:00:00 2001 From: Yunior Luis <yl.rojo@zaleos.net> Date: Tue, 31 Jul 2018 18:58:42 +0200 Subject: [PATCH 04/23] Allow disable screen_file argument. Added description in README. --- README.md | 9 +++++++++ pysipp/agent.py | 20 ++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 96868c6..d1860ad 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,15 @@ scen = pysipp.scenario(dirpath='path/to/test_scenario/', scen() ``` +**pysipp** by default uses `-screen_file` SIPp argument to redirect output, + but this argument is only available in SIPp version >= [3.5.0](https://sourceforge.net/p/sipp/mailman/message/34041962/), + for lower versions to run properly, this argument must be + disable setting `enable_screen_file` to `False`: + +```python +scen = pysipp.scenario(enable_screen_file=False) +``` + If you've got multiple such scenario directories you can iterate over them: diff --git a/pysipp/agent.py b/pysipp/agent.py index 1c0881d..a57a312 100644 --- a/pysipp/agent.py +++ b/pysipp/agent.py @@ -16,7 +16,6 @@ def tuple_property(attrs): - def getter(self): tup = tuple(getattr(self, attr) for attr in attrs) if all(tup): @@ -77,10 +76,11 @@ def is_client(self): def is_server(self): return 'uas' in self.name.lower() - def iter_logfile_items(self, types_attr='_log_types'): + def iter_logfile_items(self, types_attr='_log_types', enable_screen_file=True): for name in getattr(self, types_attr): - attr_name = name + '_file' - yield attr_name, getattr(self, attr_name) + if name != 'screen' or enable_screen_file: + attr_name = name + '_file' + yield attr_name, getattr(self, attr_name) def iter_toconsole_items(self): yield 'screen_file', self.screen_file @@ -118,11 +118,11 @@ def enable_tracing(self): attr_name = 'trace_' + name setattr(self, attr_name, True) - def enable_logging(self, logdir=None, debug=False): + def enable_logging(self, logdir=None, debug=False, enable_screen_file=True): """Enable agent logging by appending appropriately named log file arguments to the underlying command. """ - logattrs = self.iter_logfile_items() + logattrs = self.iter_logfile_items(enable_screen_file=enable_screen_file) if debug: logattrs = itertools.chain( logattrs, @@ -233,8 +233,9 @@ class ScenarioType(object): If called it will invoke the standard run hooks. """ + def __init__(self, agents, defaults, clientdefaults=None, - serverdefaults=None, confpy=None): + serverdefaults=None, confpy=None, enable_screen_file=True): # agents iterable in launch-order self._agents = agents ua_attrs = UserAgent.keys() @@ -253,6 +254,7 @@ def __init__(self, agents, defaults, clientdefaults=None, # hook module self.mod = confpy + self.enable_screen_file = enable_screen_file @property def agents(self): @@ -330,6 +332,7 @@ def prepare_agent(self, agent): """Return a new agent with all default settings applied from this scenario """ + def merge(dicts): """Merge dicts without clobbering up to 1 level deep's worth of sub-dicts @@ -364,7 +367,8 @@ def merge(dicts): params = merge(ordered) log.debug("merged contents:\n{}".format(params)) ua = UserAgent(defaults=params) - ua.enable_logging() + + ua.enable_logging(enable_screen_file=self.enable_screen_file) # call post defaults hook plugin.mng.hook.pysipp_post_ua_defaults(ua=ua) From ff6ef74e2b8885c018fe41fe7fa7a5eb45970508 Mon Sep 17 00:00:00 2001 From: Konstantinos Tsakiltzidis <ktsakiltzidis@modulus.gr> Date: Wed, 26 Jun 2019 18:19:04 +0300 Subject: [PATCH 05/23] Add `auth_username` in command sipp_spec --- pysipp/command.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pysipp/command.py b/pysipp/command.py index 417bc6e..e9d4d35 100644 --- a/pysipp/command.py +++ b/pysipp/command.py @@ -212,6 +212,7 @@ def todict(self): # SIP vars '-cid_str {cid_str} ', '-base_cseq {base_cseq} ', + '-au {auth_username}', '-ap {auth_password} ', # load settings '-r {rate} ', From 5f6a05dbce669d42dcb56e2b9c7f4c855abfa2c8 Mon Sep 17 00:00:00 2001 From: Konstantinos Tsakiltzidis <ktsakiltzidis@modulus.gr> Date: Wed, 3 Jul 2019 11:46:21 +0300 Subject: [PATCH 06/23] Fix missing space for `auth_username` in command sipp_spec --- pysipp/command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysipp/command.py b/pysipp/command.py index e9d4d35..6b87066 100644 --- a/pysipp/command.py +++ b/pysipp/command.py @@ -212,7 +212,7 @@ def todict(self): # SIP vars '-cid_str {cid_str} ', '-base_cseq {base_cseq} ', - '-au {auth_username}', + '-au {auth_username} ', '-ap {auth_password} ', # load settings '-r {rate} ', From 436431c62b7112f7a3e258a715ff768423a24b48 Mon Sep 17 00:00:00 2001 From: Konstantinos Tsakiltzidis <ktsakiltzidis@modulus.gr> Date: Wed, 3 Jul 2019 12:04:44 +0300 Subject: [PATCH 07/23] Add Authentication section in README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index d1860ad..20cc728 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,15 @@ uas(block=False) # returns a `pysipp.launch.PopenRunner` instance by default uac() # run client synchronously ``` +## Authentication +When using the `[authentication]` (sipp keyword)[https://sipp.readthedocs.io/en/latest/scenarios/keywords.html#authentication] +in scenarios, providing the credentials can be done with the +`auth_username` and `auth_password` arguments, for example: + +```python +pysipp.client(auth_username='sipp', auth_password='sipp-pass') +``` + ## Multiple Agents For multi-UA orchestrations we can use a `pysipp.scenario`. The scenario from above is the default agent configuration: From 7ade10cb11dfd0a220612e6bd09921a8f2fd3510 Mon Sep 17 00:00:00 2001 From: Konstantinos Tsakiltzidis <ktsakiltzidis@modulus.gr> Date: Wed, 3 Jul 2019 12:06:14 +0300 Subject: [PATCH 08/23] Fix Authentication link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20cc728..1494dab 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ uac() # run client synchronously ``` ## Authentication -When using the `[authentication]` (sipp keyword)[https://sipp.readthedocs.io/en/latest/scenarios/keywords.html#authentication] +When using the `[authentication]` [sipp keyword](https://sipp.readthedocs.io/en/latest/scenarios/keywords.html#authentication) in scenarios, providing the credentials can be done with the `auth_username` and `auth_password` arguments, for example: From 3c80ff13266b543ba2cb8964d1833114816ad50b Mon Sep 17 00:00:00 2001 From: Tyler Goodlet <jgbt@protonmail.com> Date: Thu, 4 Jul 2019 14:54:23 -0400 Subject: [PATCH 09/23] Go easy on ol' `sippy_cup` Resolves #48 --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1494dab..e9dc7ad 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ Python configuring and launching the infamous ## It doesn't try to - Auto-generate SIPp XML scripts like [sippy_cup](https://github.com/mojolingo/sippy_cup) - * we believe this is the wrong way to work around the problem of SIPp's shitty XML control language + * `pysipp` in no way tries to work around the problem of SIPp's awful + XML control language; your current scenario scripts are compatible! ## Basic Usage @@ -175,7 +176,8 @@ pysipp.utils.log_to_stderr("DEBUG") ### Applying default settings For now see [#4](https://github.com/SIPp/pysipp/issues/4) -More to come... +## More to come? +- document attributes / flags - writing plugins - using a `pysipp_conf.py` - remote execution From 5d25d26da8a1e552e76d90d112c81ddd4157bd70 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet <jgbt@protonmail.com> Date: Thu, 4 Jul 2019 14:55:33 -0400 Subject: [PATCH 10/23] Drop pypy from CI for now --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 144d9b6..1d07d66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,9 @@ python: - 2.7 - 3.5 - 3.6 + # - 3.7 - nightly - - pypy + # - pypy # - pypy3 addons: @@ -36,4 +37,4 @@ before_script: - cd .. script: - - pytest tests/ \ No newline at end of file + - pytest tests/ From 1adf41f18628eb35ba022dff803a3a5ce55c866a Mon Sep 17 00:00:00 2001 From: Tyler Goodlet <tgoodlet@gmail.com> Date: Fri, 12 Oct 2018 10:35:20 -0400 Subject: [PATCH 11/23] Add test for #36 Add a test which demonstrates a bug where if a scenario is loaded from a directory that the `proxyaddr` is never set. --- tests/test_stack.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_stack.py b/tests/test_stack.py index 346df9c..3aa9b82 100644 --- a/tests/test_stack.py +++ b/tests/test_stack.py @@ -52,6 +52,25 @@ def test_confpy_hooks(scendir): assert agent.uri_username == 'doggy' +def test_proxyaddr_with_scendir(scendir): + """When building a scenario from a xml file directory the + `proxyaddr` kwarg should be assigned. + """ + remoteaddr = ('9.9.9.9', 80) + scen = pysipp.scenario( + dirpath=scendir + '/default_with_confpy', + proxyaddr=remoteaddr + ) + + assert scen.clientdefaults.proxyaddr == remoteaddr + for name, cmd in scen.cmditems(): + if name == 'uac': + assert "-rsa '{}':'{}'".format(*remoteaddr) in cmd + assert "'{}':'{}'".format(*scen.clientdefaults.destaddr) in cmd + elif name == 'uas': + assert "-rsa '{}':'{}'".format(*remoteaddr) not in cmd + + def test_sync_run(scenwalk): """Ensure all scenarios in the test run to completion in synchronous mode """ From 79b75345aedded392ae71e83ad80d4dbbf0a31a0 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet <tgoodlet@gmail.com> Date: Fri, 12 Oct 2018 10:37:30 -0400 Subject: [PATCH 12/23] Fix #36 Thanks to @y-luis for originally finding and fixing this problem. The original PR (#35) was discarded accidentally. --- pysipp/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pysipp/__init__.py b/pysipp/__init__.py index 3e68a6b..46eb248 100644 --- a/pysipp/__init__.py +++ b/pysipp/__init__.py @@ -109,10 +109,10 @@ def scenario(dirpath=None, proxyaddr=None, autolocalsocks=True, scenkwargs=scenkwargs ) - if proxyaddr: - assert isinstance( - proxyaddr, tuple), 'proxyaddr must be a (addr, port) tuple' - scen.clientdefaults.proxyaddr = proxyaddr + if proxyaddr: + assert isinstance( + proxyaddr, tuple), 'proxyaddr must be a (addr, port) tuple' + scen.clientdefaults.proxyaddr = proxyaddr return scen From 9dddfe8bb7e7c01d08e2cbd7e7467b6d21d7cb06 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet <tgoodlet@gmail.com> Date: Fri, 12 Oct 2018 11:01:29 -0400 Subject: [PATCH 13/23] Add agent name to options merge logging --- pysipp/agent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pysipp/agent.py b/pysipp/agent.py index a57a312..2947755 100644 --- a/pysipp/agent.py +++ b/pysipp/agent.py @@ -362,10 +362,10 @@ def merge(dicts): # apply defaults ordered = [self._defaults, secondary, agent.todict()] for name, defs in zip(['defaults', dname, 'agent.todict()'], ordered): - log.debug("'{}' contents:\n{}".format(name, defs)) + log.debug("{} '{}' contents:\n{}".format(agent.name, name, defs)) params = merge(ordered) - log.debug("merged contents:\n{}".format(params)) + log.debug("{} merged contents:\n{}".format(agent.name, params)) ua = UserAgent(defaults=params) ua.enable_logging(enable_screen_file=self.enable_screen_file) From e2ef59b16d0e59acef68b6792d2b98e1c13a3410 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet <jgbt@protonmail.com> Date: Mon, 27 May 2019 09:49:40 -0400 Subject: [PATCH 14/23] Use pluggy 0.11.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 80128cd..a13dc99 100755 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ url='https://github.com/SIPp/pysipp', platforms=['linux'], packages=['pysipp', 'pysipp.cli'], - install_requires=['pluggy==0.3.1'], + install_requires=['pluggy==0.11.0'], tests_require=['pytest'], entry_points={ 'console_scripts': [ From 1e6f97c17e9315b5d1ebeeb2fcd30807db110074 Mon Sep 17 00:00:00 2001 From: Yunior Luis <yl.rojo@zaleos.net> Date: Tue, 31 Jul 2018 18:58:42 +0200 Subject: [PATCH 15/23] Support disabling logging files. --- pysipp/agent.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pysipp/agent.py b/pysipp/agent.py index 2947755..7c1e303 100644 --- a/pysipp/agent.py +++ b/pysipp/agent.py @@ -235,7 +235,7 @@ class ScenarioType(object): """ def __init__(self, agents, defaults, clientdefaults=None, - serverdefaults=None, confpy=None, enable_screen_file=True): + serverdefaults=None, confpy=None, logs=True, enable_screen_file=True): # agents iterable in launch-order self._agents = agents ua_attrs = UserAgent.keys() @@ -255,6 +255,7 @@ def __init__(self, agents, defaults, clientdefaults=None, # hook module self.mod = confpy self.enable_screen_file = enable_screen_file + self.logs = logs @property def agents(self): @@ -369,6 +370,8 @@ def merge(dicts): ua = UserAgent(defaults=params) ua.enable_logging(enable_screen_file=self.enable_screen_file) + if self.logs: + ua.enable_logging() # call post defaults hook plugin.mng.hook.pysipp_post_ua_defaults(ua=ua) From 551042b32f8533df55cb761a7425f11424fb819f Mon Sep 17 00:00:00 2001 From: Yunior Luis <yluisrojo@gmail.com> Date: Mon, 20 Aug 2018 16:58:35 +0200 Subject: [PATCH 16/23] Log sipp stdout. --- pysipp/launch.py | 19 +++++++++---------- pysipp/report.py | 7 +++++++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/pysipp/launch.py b/pysipp/launch.py index a750128..9d63958 100644 --- a/pysipp/launch.py +++ b/pysipp/launch.py @@ -28,11 +28,12 @@ class PopenRunner(object): Adheres to an interface similar to `multiprocessing.pool.AsyncResult`. """ + def __init__( - self, - subprocmod=subprocess, - osmod=os, - poller=select.epoll, + self, + subprocmod=subprocess, + osmod=os, + poller=select.epoll, ): # these could optionally be rpyc proxy objs self.spm = subprocmod @@ -53,8 +54,6 @@ def __call__(self, cmds, block=True, rate=300, **kwargs): "Process results have not been cleared from previous run" ) sp = self.spm - os = self.osm - DEVNULL = open(os.devnull, 'wb') fds2procs = OrderedDict() # run agent commands in sequence @@ -63,15 +62,15 @@ def __call__(self, cmds, block=True, rate=300, **kwargs): "launching cmd:\n\"{}\"\n".format(cmd)) proc = sp.Popen( shlex.split(cmd), - stdout=DEVNULL, - stderr=sp.PIPE + stdout=sp.PIPE, + stderr=sp.STDOUT ) - fd = proc.stderr.fileno() + fd = proc.stdout.fileno() log.debug("registering fd '{}' for pid '{}'".format( fd, proc.pid)) fds2procs[fd] = self._procs[cmd] = proc # register for stderr hangup events - self.poller.register(proc.stderr.fileno(), select.EPOLLHUP) + self.poller.register(proc.stdout.fileno(), select.EPOLLHUP) # limit launch rate time.sleep(1. / rate) diff --git a/pysipp/report.py b/pysipp/report.py index 9643892..9fff885 100644 --- a/pysipp/report.py +++ b/pysipp/report.py @@ -54,6 +54,13 @@ def emit_logfiles(agents2procs, level='warn', max_lines=100): # logging mod bug? time.sleep(0.01) + # print stdout + emit("stdout for '{}' @ {}\n{}\n".format( + ua.name, ua.srcaddr, proc.streams.stdout)) + # FIXME: no idea, but some logs are not being printed without this + # logging mod bug? + time.sleep(0.01) + # print log file contents for name, fpath in ua.iter_toconsole_items(): if fpath and path.isfile(fpath): From d06379caf7bdc2aa3cb2a9bb2feb9e76148608cd Mon Sep 17 00:00:00 2001 From: "Y. Luis" <yluisrojo@gmail.com> Date: Mon, 20 Aug 2018 17:25:49 +0100 Subject: [PATCH 17/23] Revert "Log sipp stdout." --- pysipp/launch.py | 19 ++++++++++--------- pysipp/report.py | 7 ------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/pysipp/launch.py b/pysipp/launch.py index 9d63958..a750128 100644 --- a/pysipp/launch.py +++ b/pysipp/launch.py @@ -28,12 +28,11 @@ class PopenRunner(object): Adheres to an interface similar to `multiprocessing.pool.AsyncResult`. """ - def __init__( - self, - subprocmod=subprocess, - osmod=os, - poller=select.epoll, + self, + subprocmod=subprocess, + osmod=os, + poller=select.epoll, ): # these could optionally be rpyc proxy objs self.spm = subprocmod @@ -54,6 +53,8 @@ def __call__(self, cmds, block=True, rate=300, **kwargs): "Process results have not been cleared from previous run" ) sp = self.spm + os = self.osm + DEVNULL = open(os.devnull, 'wb') fds2procs = OrderedDict() # run agent commands in sequence @@ -62,15 +63,15 @@ def __call__(self, cmds, block=True, rate=300, **kwargs): "launching cmd:\n\"{}\"\n".format(cmd)) proc = sp.Popen( shlex.split(cmd), - stdout=sp.PIPE, - stderr=sp.STDOUT + stdout=DEVNULL, + stderr=sp.PIPE ) - fd = proc.stdout.fileno() + fd = proc.stderr.fileno() log.debug("registering fd '{}' for pid '{}'".format( fd, proc.pid)) fds2procs[fd] = self._procs[cmd] = proc # register for stderr hangup events - self.poller.register(proc.stdout.fileno(), select.EPOLLHUP) + self.poller.register(proc.stderr.fileno(), select.EPOLLHUP) # limit launch rate time.sleep(1. / rate) diff --git a/pysipp/report.py b/pysipp/report.py index 9fff885..9643892 100644 --- a/pysipp/report.py +++ b/pysipp/report.py @@ -54,13 +54,6 @@ def emit_logfiles(agents2procs, level='warn', max_lines=100): # logging mod bug? time.sleep(0.01) - # print stdout - emit("stdout for '{}' @ {}\n{}\n".format( - ua.name, ua.srcaddr, proc.streams.stdout)) - # FIXME: no idea, but some logs are not being printed without this - # logging mod bug? - time.sleep(0.01) - # print log file contents for name, fpath in ua.iter_toconsole_items(): if fpath and path.isfile(fpath): From 650eec18b492e7ddcca089cefde282906276d2e3 Mon Sep 17 00:00:00 2001 From: Yunior Luis <yluisrojo@gmail.com> Date: Mon, 20 Aug 2018 20:00:21 +0200 Subject: [PATCH 18/23] Beta release. --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index a13dc99..b932c6a 100755 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name="pysipp", - version='0.1.alpha', + version='0.1.beta', description='pysipp is a SIPp scenario launcher for for use in' ' automated VoIP testing', long_description=readme, @@ -44,7 +44,7 @@ ], }, classifiers=[ - 'Development Status :: 3 - Alpha', + 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License v2', 'Operating System :: Linux', From e890e23ae0bd37472c449de409d8653976860531 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet <tgoodlet@gmail.com> Date: Fri, 17 Jun 2016 18:37:21 -0400 Subject: [PATCH 19/23] Use a plain old select loop Use `select.select` to track subproc completion since `select.epoll` isn't available on OSX. Resolves #16 --- pysipp/launch.py | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/pysipp/launch.py b/pysipp/launch.py index a750128..ddb3131 100644 --- a/pysipp/launch.py +++ b/pysipp/launch.py @@ -32,12 +32,12 @@ def __init__( self, subprocmod=subprocess, osmod=os, - poller=select.epoll, + select=select.select, ): # these could optionally be rpyc proxy objs self.spm = subprocmod self.osm = osmod - self.poller = poller() + self.select = select # collector thread placeholder self._waiter = None # store proc results @@ -67,11 +67,9 @@ def __call__(self, cmds, block=True, rate=300, **kwargs): stderr=sp.PIPE ) fd = proc.stderr.fileno() - log.debug("registering fd '{}' for pid '{}'".format( - fd, proc.pid)) + log.debug("registering fd '{}' for pid '{}'".format(fd, proc.pid)) fds2procs[fd] = self._procs[cmd] = proc - # register for stderr hangup events - self.poller.register(proc.stderr.fileno(), select.EPOLLHUP) + # limit launch rate time.sleep(1. / rate) @@ -87,15 +85,39 @@ def _wait(self, fds2procs): signalled = None left = len(fds2procs) collected = 0 + p2fd = {p: p.stderr for p in fds2procs.values()} + stderrs = {p: [] for p in fds2procs.values()} + + # wait on stderr hangup events while collected < left: - pairs = self.poller.poll() # wait on hangup events - log.debug("received hangup for pairs '{}'".format(pairs)) - for fd, status in pairs: + try: + fds, _, _ = self.select(list(p2fd.values()), [], []) + except ValueError: + # all fds are now closed + hungup = p2fd.keys() + else: + hungup = [] + for proc in (fds2procs[fd.fileno()] for fd in fds): + data = proc.stderr.read() + if data != '': + stderrs[proc].append(data) # append stderr + continue + + p2fd.pop(proc) + hungup.append(proc) + + if not hungup: + continue + + for proc in hungup: + log.debug("received hangup for pid '{}'".format(proc.pid)) collected += 1 - proc = fds2procs[fd] # attach streams so they can be read more then once log.debug("collecting streams for {}".format(proc)) - proc.streams = Streams(*proc.communicate()) # timeout=2)) + proc.streams = Streams( + stdout=proc.communicate()[0], + stderr=''.join(stderrs[proc]), + ) # timeout=2)) if proc.returncode != 0 and not signalled: # stop all other agents if there is a failure signalled = self.stop() From 611ead886cd8bcfbe04dcb95189baa173eebf2c5 Mon Sep 17 00:00:00 2001 From: Tyler Goodlet <tgoodlet@gmail.com> Date: Fri, 17 Jun 2016 18:40:22 -0400 Subject: [PATCH 20/23] Tweak unit test exit code checking --- tests/test_launcher.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_launcher.py b/tests/test_launcher.py index e1d435a..48e2dc9 100644 --- a/tests/test_launcher.py +++ b/tests/test_launcher.py @@ -29,12 +29,12 @@ def test_agent_fails(): assert uasproc.streams.stderr assert uasproc.returncode == 255, uasproc.streams.stderr - # killed by signal + # times out (can't do by signal - SIPp issue #176) uacproc = runner.get(timeout=0)[uac.render()] # assert not uacproc.streams.stderr # sometimes this has a log msg? ret = uacproc.returncode - # killed by SIGUSR1 or terminates before it starts (racy) - assert ret == -10 or ret == 0 + # timed out or terminates before it starts (racy) + assert ret == -10 or ret == 0 or ret == 1 def test_default_scen(default_agents): From d522d6b1dd0cedcd5eaec6cb17983127c27b7148 Mon Sep 17 00:00:00 2001 From: Yunior Luis <yluisrojo@gmail.com> Date: Sun, 14 Oct 2018 19:21:53 +0200 Subject: [PATCH 21/23] Fix default host retrieving random socket from local OS. --- pysipp/netplug.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pysipp/netplug.py b/pysipp/netplug.py index 4d2e87a..8004b1c 100644 --- a/pysipp/netplug.py +++ b/pysipp/netplug.py @@ -10,12 +10,12 @@ def getsockaddr(host, family=socket.AF_INET, port=0, sockmod=socket): binding to an ip, acquiring a random port and then closing the socket and returning that address. - ..warning:: Obviously this is not guarateed to be an unused address + ..warning:: Obviously this is not guaranteed to be an unused address since we don't actually keep it bound, so there may be a race with other processes acquiring the addr before our SIPp process re-binds. """ for fam, stype, proto, _, sa in socket.getaddrinfo( - host, port, family, socket.SOCK_DGRAM, 0, socket.AI_PASSIVE, + host if host else '127.0.0.1', port, family, socket.SOCK_DGRAM, 0, socket.AI_PASSIVE, ): s = socket.socket(family, stype, proto) s.bind(sa) From 00694f34a2c513359086d0275bf94adc9b32f8de Mon Sep 17 00:00:00 2001 From: Yunior Luis <yluisrojo@gmail.com> Date: Sun, 14 Oct 2018 19:22:35 +0200 Subject: [PATCH 22/23] Git ignore PyCharm and pytest related folders. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index ba74660..a32a803 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ htmlcov/ nosetests.xml coverage.xml *,cover +.pytest_cache # Translations *.mo @@ -55,3 +56,6 @@ docs/_build/ # PyBuilder target/ + +# PyCharm +.idea/ \ No newline at end of file From 466ffa4547dc01c0397baef616422b3413d69c2e Mon Sep 17 00:00:00 2001 From: Luis Rojo <yluisrojo@gmail.com> Date: Fri, 5 Jul 2019 13:56:23 +0100 Subject: [PATCH 23/23] Revert setup status --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index b932c6a..a13dc99 100755 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name="pysipp", - version='0.1.beta', + version='0.1.alpha', description='pysipp is a SIPp scenario launcher for for use in' ' automated VoIP testing', long_description=readme, @@ -44,7 +44,7 @@ ], }, classifiers=[ - 'Development Status :: 4 - Beta', + 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License v2', 'Operating System :: Linux',