def process_file(path, qmin, prog_cfgs): """Parse scenario from a file object and create workdir.""" # Parse scenario case, cfg_text = scenario.parse_file(os.path.realpath(path)) cfg_ctx, ta_files = scenario.parse_config(cfg_text, qmin, INSTALLDIR) template_ctx = setup_network(cfg_ctx['_SOCKET_FAMILY'], prog_cfgs) # merge variables from scenario with generated network variables (scenario has priority) template_ctx.update(cfg_ctx) # Deckard will communicate with first program prog_under_test = prog_cfgs['programs'][0]['name'] prog_under_test_ip = template_ctx['IPADDRS'][prog_under_test] # get working directory and environment variables tmpdir = setup_common_env(cfg_ctx) shutil.copy2(path, os.path.join(tmpdir)) try: daemons = setup_daemons(tmpdir, prog_cfgs, template_ctx, ta_files) run_testcase(daemons, case, template_ctx['ROOT_ADDR'], template_ctx['_SOCKET_FAMILY'], prog_under_test_ip) if prog_cfgs.get('noclean'): logging.getLogger('deckard.hint').info( 'test working directory %s', tmpdir) else: shutil.rmtree(tmpdir) except: logging.getLogger('deckard.hint').info( 'test failed, inspect working directory %s', tmpdir) raise
def play_object(path, binary_name, config_name, j2template, binary_additional_pars): """ Play scenario from a file object. """ # Parse scenario case, config = scenario.parse_file(fileinput.input(path)) # Setup daemon environment daemon_env = os.environ.copy() setup_env(case, daemon_env, config, config_name, j2template) server = testserver.TestServer(case, config, DEFAULT_IFACE) server.start() # Start binary daemon_proc = None daemon_log = open('%s/server.log' % TMPDIR, 'w') daemon_args = [binary_name] + binary_additional_pars try: daemon_proc = subprocess.Popen(daemon_args, stdout=daemon_log, stderr=daemon_log, cwd=TMPDIR, preexec_fn=os.setsid, env=daemon_env) except Exception as e: server.stop() raise Exception("Can't start '%s': %s" % (daemon_args, str(e))) # Wait until the server accepts TCP clients sockfamily = socket.AF_INET if case.force_ipv6 == True: sockfamily = socket.AF_INET6
def empty_test_case(): """ Return (scenario, config) pair which answers to any query on 127.0.0.10. """ # Mirror server empty_test_path = os.path.dirname(os.path.realpath(__file__)) + "/empty.rpl" test_config = {'ROOT_ADDR': '127.0.0.10', '_SOCKET_FAMILY': socket.AF_INET} return scenario.parse_file(empty_test_path)[0], test_config
def standalone_self_test(): """ Self-test code Usage: unshare -rn $PYTHON -m pydnstest.testserver --help """ logging.basicConfig(level=logging.DEBUG) argparser = argparse.ArgumentParser() argparser.add_argument('--scenario', help='absolute path to test scenario', required=False) argparser.add_argument('--step', help='step # in the scenario (default: first)', required=False, type=int) args = argparser.parse_args() if args.scenario: test_scenario, test_config_text = scenario.parse_file(args.scenario) test_config = scenario.parse_config(test_config_text, True, os.getcwd()) else: test_scenario, test_config = empty_test_case() if args.step: for step in test_scenario.steps: if step.id == args.step: test_scenario.current_step = step if not test_scenario.current_step: raise ValueError('step ID %s not found in scenario' % args.step) else: test_scenario.current_step = test_scenario.steps[0] if_manager = InterfaceManager(interface="testserver") server = TestServer(test_scenario, test_config['_SOCKET_FAMILY'], if_manager=if_manager) server.start() logging.info("[==========] Mirror server running at %s", server.address()) def kill(signum, frame): # pylint: disable=unused-argument logging.info("[==========] Shutdown.") server.stop() sys.exit(128 + signum) signal.signal(signal.SIGINT, kill) signal.signal(signal.SIGTERM, kill) while True: time.sleep(0.5)
def standalone_self_test(): """ Self-test code Usage: LD_PRELOAD=libsocket_wrapper.so SOCKET_WRAPPER_DIR=/tmp $PYTHON -m pydnstest.testserver --help """ logging.basicConfig(level=logging.DEBUG) argparser = argparse.ArgumentParser() argparser.add_argument('--scenario', help='absolute path to test scenario', required=False) argparser.add_argument('--step', help='step # in the scenario (default: first)', required=False, type=int) args = argparser.parse_args() if args.scenario: test_scenario, test_config_text = scenario.parse_file(args.scenario) test_config, _ = scenario.parse_config(test_config_text, True, os.getcwd()) else: test_scenario, test_config = empty_test_case() if args.step: for step in test_scenario.steps: if step.id == args.step: test_scenario.current_step = step if not test_scenario.current_step: raise ValueError('step ID %s not found in scenario' % args.step) else: test_scenario.current_step = test_scenario.steps[0] server = TestServer(test_scenario, test_config['ROOT_ADDR'], test_config['_SOCKET_FAMILY']) server.start() logging.info("[==========] Mirror server running at %s", server.address()) def exit(signum, frame): logging.info("[==========] Shutdown.") server.stop() sys.exit(128 + signum) signal.signal(signal.SIGINT, exit) signal.signal(signal.SIGTERM, exit) while True: time.sleep(0.5)
def play_object(path, binary_name, config_name, j2template, binary_additional_pars): """ Play scenario from a file object. """ # Parse scenario case, config = scenario.parse_file(fileinput.input(path)) # Setup daemon environment daemon_env = os.environ.copy() setup_env(case, daemon_env, config, config_name, j2template) server = testserver.TestServer(case, config, DEFAULT_IFACE) server.start() # Start binary daemon_proc = None daemon_log = open('%s/server.log' % TMPDIR, 'w') daemon_args = [binary_name] + binary_additional_pars try : daemon_proc = subprocess.Popen(daemon_args, stdout=daemon_log, stderr=daemon_log, cwd=TMPDIR, preexec_fn=os.setsid, env=daemon_env) except Exception as e: server.stop() raise Exception("Can't start '%s': %s" % (daemon_args, str(e))) # Wait until the server accepts TCP clients sockfamily = socket.AF_INET if case.force_ipv6 == True: sockfamily = socket.AF_INET6 sock = socket.socket(sockfamily, socket.SOCK_STREAM) while True: time.sleep(0.1) if daemon_proc.poll() != None: server.stop() print(open('%s/server.log' % TMPDIR).read()) raise Exception('process died "%s", logs in "%s"' % (os.path.basename(binary_name), TMPDIR)) try: sock.connect((testserver.get_local_addr_str(sockfamily, CHILD_IFACE), 53)) except: continue break sock.close() # Bind to test servers for r in case.ranges: family = socket.AF_INET6 if ':' in r.address else socket.AF_INET server.start_srv((r.address, 53), family) # Bind addresses in ad-hoc REPLYs for s in case.steps: if s.type == 'REPLY': reply = s.data[0].message for rr in itertools.chain(reply.answer,reply.additional,reply.question,reply.authority): for rd in rr: if rd.rdtype == dns.rdatatype.A: server.start_srv((rd.address, 53), socket.AF_INET) elif rd.rdtype == dns.rdatatype.AAAA: server.start_srv((rd.address, 53), socket.AF_INET6) # Play test scenario try: server.play(CHILD_IFACE) if VERBOSE: print(open('%s/server.log' % TMPDIR).read()) except: print(open('%s/server.log' % TMPDIR).read()) raise finally: server.stop() daemon_proc.terminate() daemon_proc.wait() # Do not clear files if the server crashed (for analysis) del_files(TMPDIR, OWN_TMPDIR)
def play_object(path, binary_name, config_name, j2template, binary_additional_pars): """ Play scenario from a file object. """ # Parse scenario case, config = scenario.parse_file(fileinput.input(path)) # Setup daemon environment daemon_env = os.environ.copy() setup_env(case, daemon_env, config, config_name, j2template) server = testserver.TestServer(case, config, DEFAULT_IFACE) server.start() ignore_exit = bool(os.environ.get('IGNORE_EXIT_CODE', 0)) # Start binary daemon_proc = None daemon_log = open('%s/server.log' % TMPDIR, 'w') daemon_args = [binary_name] + binary_additional_pars try: daemon_proc = subprocess.Popen(daemon_args, stdout=daemon_log, stderr=daemon_log, cwd=TMPDIR, preexec_fn=os.setsid, env=daemon_env) except Exception as e: server.stop() raise Exception("Can't start '%s': %s" % (daemon_args, str(e))) # Wait until the server accepts TCP clients sock = socket.socket(case.sockfamily, socket.SOCK_STREAM) while True: time.sleep(0.1) if daemon_proc.poll(): server.stop() print(open('%s/server.log' % TMPDIR).read()) raise Exception('process died "%s", logs in "%s"' % (os.path.basename(binary_name), TMPDIR)) try: sock.connect( (testserver.get_local_addr_str(case.sockfamily, CHILD_IFACE), 53)) except: continue break sock.close() # Bind to test servers for r in case.ranges: for addr in r.addresses: family = socket.AF_INET6 if ':' in addr else socket.AF_INET server.start_srv((addr, 53), family) # Bind addresses in ad-hoc REPLYs for s in case.steps: if s.type == 'REPLY': reply = s.data[0].message for rr in itertools.chain(reply.answer, reply.additional, reply.question, reply.authority): for rd in rr: if rd.rdtype == dns.rdatatype.A: server.start_srv((rd.address, 53), socket.AF_INET) elif rd.rdtype == dns.rdatatype.AAAA: server.start_srv((rd.address, 53), socket.AF_INET6) # Play test scenario try: server.play(CHILD_IFACE) except Exception as exc: ex = exc raise else: ex = None finally: server.stop() daemon_proc.terminate() daemon_proc.wait() if VERBOSE or ex or (daemon_proc.returncode and not ignore_exit): print(open('%s/server.log' % TMPDIR).read()) if daemon_proc.returncode != 0 and not ignore_exit: raise ValueError('process terminated with return code %s' % daemon_proc.returncode) # Do not clear files if the server crashed (for analysis) del_files(TMPDIR, OWN_TMPDIR)