pytact.fake_coq_client
1import contextlib 2import socket 3import argparse 4import signal 5from subprocess import Popen 6import capnp 7import pytact.graph_api_capnp as graph_api_capnp 8from pytact.data_reader import capnp_message_generator_from_file_lowlevel, record_lowlevel_generator 9 10def run_fake_client(server_socket, messages_generator): 11 socket_reader = graph_api_capnp.PredictionProtocol.Response.read_multiple_packed( 12 server_socket, traversal_limit_in_words=2**64-1) 13 for msg in messages_generator: 14 msg.dynamic.as_builder().write_packed(server_socket) 15 prev_sig = signal.signal(signal.SIGINT, signal.SIG_DFL) # SIGINT catching OFF 16 response = next(socket_reader) 17 signal.signal(signal.SIGINT, prev_sig) # SIGINT catching ON 18 messages_generator.send(response.as_builder()) 19 20def compare(request, response, recorded_response): 21 if response.to_dict() == recorded_response.to_dict(): 22 print(f'The servers response to a {request.which.name} message was equal to the ' 23 f'recorded response') 24 else: 25 raise ValueError( 26 f"The servers response to a {request.which.name} message was not equal to the " + 27 f"recorded response.\n" 28 f"Recorded response: {recorded_response}\n" 29 f"Servers response: {response}\n" 30 ) 31 32def main(): 33 parser = argparse.ArgumentParser( 34 description = 'A fake Coq client that connects to a prediction server and feeds it a stream of previously ' + 35 'recorded messages.', 36 formatter_class=argparse.ArgumentDefaultsHelpFormatter) 37 parser.add_argument('data', 38 type=str, 39 help='A file that contains a previously recorded communication sequence between Coq ' + 40 'and a prediction server.') 41 parser.add_argument('--check', 42 action=argparse.BooleanOptionalAction, 43 default = True, 44 help='Wether or not to compare the response messages of the server to recorded messages.') 45 parser.add_argument('--record', 46 dest="record_file", 47 type = str, 48 default = None, 49 help='Re-record the interaction with the server to a new file (useful when you want to ' + 50 'update the trace with a new response behavior of a server)') 51 connect_group = parser.add_mutually_exclusive_group(required=True) 52 connect_group.add_argument('--tcp', 53 dest='tcp_location', 54 type = str, 55 default = None, 56 help='Connect to a prediction server on the specified ip:port.') 57 connect_group.add_argument('--stdin', 58 dest='executable', 59 type = str, 60 default = None, 61 help='Start the specified prediction server and connect to it through stdin.') 62 cmd_args = parser.parse_args() 63 64 with open(cmd_args.data, 'rb') as message_file: 65 messages_generator = capnp_message_generator_from_file_lowlevel( 66 message_file, 67 check= compare if cmd_args.check else None) 68 if cmd_args.record_file is not None: 69 record_context = open(cmd_args.record_file, 'wb') 70 else: 71 record_context = contextlib.nullcontext() 72 with record_context as record_file: 73 if record_file is not None: 74 messages_generator = record_lowlevel_generator(record_file, messages_generator) 75 if cmd_args.tcp_location is not None: 76 addr, port = cmd_args.tcp_location.split(':') 77 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket: 78 server_socket.connect((addr, int(port))) 79 run_fake_client(server_socket, messages_generator) 80 else: 81 our_sock, their_sock = socket.socketpair() 82 process = Popen(cmd_args.executable, shell=True, stdin=their_sock) 83 their_sock.close() 84 run_fake_client(our_sock, messages_generator) 85 our_sock.close() 86 process.communicate() 87 88if __name__ == '__main__': 89 main()
def
run_fake_client(server_socket, messages_generator):
11def run_fake_client(server_socket, messages_generator): 12 socket_reader = graph_api_capnp.PredictionProtocol.Response.read_multiple_packed( 13 server_socket, traversal_limit_in_words=2**64-1) 14 for msg in messages_generator: 15 msg.dynamic.as_builder().write_packed(server_socket) 16 prev_sig = signal.signal(signal.SIGINT, signal.SIG_DFL) # SIGINT catching OFF 17 response = next(socket_reader) 18 signal.signal(signal.SIGINT, prev_sig) # SIGINT catching ON 19 messages_generator.send(response.as_builder())
def
compare(request, response, recorded_response):
21def compare(request, response, recorded_response): 22 if response.to_dict() == recorded_response.to_dict(): 23 print(f'The servers response to a {request.which.name} message was equal to the ' 24 f'recorded response') 25 else: 26 raise ValueError( 27 f"The servers response to a {request.which.name} message was not equal to the " + 28 f"recorded response.\n" 29 f"Recorded response: {recorded_response}\n" 30 f"Servers response: {response}\n" 31 )
def
main():
33def main(): 34 parser = argparse.ArgumentParser( 35 description = 'A fake Coq client that connects to a prediction server and feeds it a stream of previously ' + 36 'recorded messages.', 37 formatter_class=argparse.ArgumentDefaultsHelpFormatter) 38 parser.add_argument('data', 39 type=str, 40 help='A file that contains a previously recorded communication sequence between Coq ' + 41 'and a prediction server.') 42 parser.add_argument('--check', 43 action=argparse.BooleanOptionalAction, 44 default = True, 45 help='Wether or not to compare the response messages of the server to recorded messages.') 46 parser.add_argument('--record', 47 dest="record_file", 48 type = str, 49 default = None, 50 help='Re-record the interaction with the server to a new file (useful when you want to ' + 51 'update the trace with a new response behavior of a server)') 52 connect_group = parser.add_mutually_exclusive_group(required=True) 53 connect_group.add_argument('--tcp', 54 dest='tcp_location', 55 type = str, 56 default = None, 57 help='Connect to a prediction server on the specified ip:port.') 58 connect_group.add_argument('--stdin', 59 dest='executable', 60 type = str, 61 default = None, 62 help='Start the specified prediction server and connect to it through stdin.') 63 cmd_args = parser.parse_args() 64 65 with open(cmd_args.data, 'rb') as message_file: 66 messages_generator = capnp_message_generator_from_file_lowlevel( 67 message_file, 68 check= compare if cmd_args.check else None) 69 if cmd_args.record_file is not None: 70 record_context = open(cmd_args.record_file, 'wb') 71 else: 72 record_context = contextlib.nullcontext() 73 with record_context as record_file: 74 if record_file is not None: 75 messages_generator = record_lowlevel_generator(record_file, messages_generator) 76 if cmd_args.tcp_location is not None: 77 addr, port = cmd_args.tcp_location.split(':') 78 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket: 79 server_socket.connect((addr, int(port))) 80 run_fake_client(server_socket, messages_generator) 81 else: 82 our_sock, their_sock = socket.socketpair() 83 process = Popen(cmd_args.executable, shell=True, stdin=their_sock) 84 their_sock.close() 85 run_fake_client(our_sock, messages_generator) 86 our_sock.close() 87 process.communicate()