| #!/usr/bin/env python3 |
| # |
| # (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de> |
| # All rights reserved. |
| # |
| # Author: Neels Hofmeyr <nhofmeyr@sysmocom.de> |
| # |
| # This program is free software: you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation, either version 3 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| |
| ''' |
| Run CTRL commands or test transcripts against a given application. Commandline |
| invocation exposes only direct command piping, the transcript verification code |
| is exposed as commandline args by osmo_verify_transcript_ctrl.py. |
| ''' |
| |
| import re |
| |
| from .common import * |
| from osmopy.osmo_ipa import Ctrl, IPA |
| |
| class InteractCtrl(Interact): |
| next_id = 1 |
| keep_ids = True |
| re_command = re.compile('^(SET|GET) ([^ ]*) (.*)$') |
| |
| class CtrlStep(Interact.StepBase): |
| |
| @staticmethod |
| def is_next_step(line, interact_instance): |
| m = InteractCtrl.re_command.match(line) |
| if not m: |
| return None |
| next_step = InteractCtrl.CtrlStep() |
| |
| set_get = m.group(1) |
| cmd_id = m.group(2) |
| var_val = m.group(3) |
| if not interact_instance.keep_ids: |
| cmd_id = interact_instance.next_id |
| interact_instance.next_id += 1 |
| next_step.command = '%s %s %s' % (set_get, cmd_id, var_val) |
| |
| return next_step |
| |
| def __init__(self, port, host, verbose=False, update=False, keep_ids=True): |
| if not update: |
| keep_ids = True |
| self.keep_ids = keep_ids |
| super().__init__(InteractCtrl.CtrlStep, port=port, host=host, verbose=verbose, update=update) |
| |
| def connect(self): |
| self.next_id = 1 |
| super().connect() |
| |
| def send(self, data): |
| data = Ctrl().add_header(data) |
| return self.socket.send(data) == len(data) |
| |
| def receive(self): |
| responses = [] |
| data = self.socket.recv(4096) |
| while (len(data)>0): |
| (response_with_header, data) = IPA().split_combined(data) |
| response = Ctrl().rem_header(response_with_header) |
| responses.append(response.decode('utf-8')) |
| return responses |
| |
| def command(self, command): |
| assert self.send(command) |
| res = self.receive() |
| split_responses = [] |
| for r in res: |
| split_responses.extend(r.splitlines()) |
| sys.stdout.flush() |
| sys.stderr.flush() |
| return split_responses |
| |
| def main_interact_ctrl(): |
| ''' |
| Run CTRL commands against a given application by stdin/stdout piping. |
| |
| Optionally, this can launch and tear down the application with -r. |
| |
| For example, to start a session that allows typing CTRL commands on stdin: |
| |
| osmo_interact_ctrl.py -p 4259 \\ |
| -r 'osmo-hlr -c /etc/osmocom/osmo-hlr.cfg -l /tmp/hlr.db' |
| |
| Where 4259 is OsmoHLR's CTRL port number, see |
| https://osmocom.org/projects/cellular-infrastructure/wiki/Port_Numbers |
| |
| If osmo-hlr is already running, this shortens to just |
| |
| osmo_interact_ctrl.py -p 4259 |
| |
| See also osmo_verify_transcript_vty.py, which allows verifying and updating |
| complete CTRL session transcripts, in essence to write CTRL tests from a screen |
| dump of a CTRL session. |
| |
| A VTY equivalent is osmo_interact_vty.py. |
| ''' |
| parser = common_parser(__doc__) |
| parser_add_run_args(parser) |
| args = parser.parse_args() |
| |
| interact = InteractCtrl(args.port, args.host, verbose=False, update=False, |
| keep_ids=True) |
| |
| main_run_commands(args.run_app_str, args.output_path, args.cmd_str, |
| args.cmd_files, interact) |
| |
| |
| def main_verify_transcript_ctrl(): |
| ''' |
| A CTRL transcript contains CTRL commands and their expected results. |
| It looks like: |
| |
| " |
| SET 1 var val |
| SET_REPLY 1 var OK |
| |
| GET 2 var |
| GET_REPLY 2 var val |
| " |
| |
| Optionally, this can launch and tear down the application with -r. |
| |
| For example, if above transcript example is in file test.ctrl, you can verify |
| that OsmoHLR still shows this behavior by: |
| |
| osmo_interact_ctrl.py -p 4259 \\ |
| -r 'osmo-hlr -c /etc/osmocom/osmo-hlr.cfg -l /tmp/hlr.db' \\ |
| test.ctrl |
| |
| Where 4259 is OsmoHLR's CTRL port number, see |
| https://osmocom.org/projects/cellular-infrastructure/wiki/Port_Numbers |
| |
| If osmo-hlr is already running, this shortens to just |
| |
| osmo_interact_ctrl.py -p 4259 test.ctrl |
| |
| If osmo-hlr has changed its behavior, e.g. some reply changed, the transcript |
| can be automatically updated, which overwrites the file, like: |
| |
| osmo_interact_ctrl.py -p 4259 -u test.ctrl |
| |
| See also osmo_interact_ctrl.py, which allows piping CTRL commands to stdin. |
| |
| A VTY equivalent is osmo_verify_transcript_vty.py. |
| ''' |
| parser = common_parser(__doc__) |
| parser_add_verify_args(parser) |
| parser.add_argument('-i', '--keep-ids', dest='keep_ids', action='store_true', |
| help='With --update, default is to overwrite the command IDs' |
| ' so that they are consecutive numbers starting from 1.' |
| ' With --keep-ids, do not change these command IDs.') |
| args = parser.parse_args() |
| |
| interact = InteractCtrl(args.port, args.host, args.verbose, args.update, args.keep_ids) |
| |
| main_verify_transcripts(args.run_app_str, args.transcript_files, interact, args.verbose) |
| |
| # vim: tabstop=4 shiftwidth=4 expandtab nocin ai |