def test_compile_process(self): async def main(): loop = asyncio.get_running_loop() if sys.version_info >= (3, 7) \ else asyncio.get_event_loop() exec = ExecutionEnvironment(loop) diagnostics, rpc_error = await exec.execute( exec.process_executor, EBNFServer.compile_EBNF, ('', )) json_obj = json.loads(diagnostics) assert json_obj[0]['code'] >= ERROR diagnostics, rpc_error = await exec.execute( exec.process_executor, EBNFServer.compile_EBNF, ('document = /.*/', )) assert diagnostics == '[]' diagnostics, rpc_error = await exec.execute( exec.thread_executor, EBNFServer.compile_EBNF, ('', )) json_obj = json.loads(diagnostics) assert json_obj[0]['code'] >= ERROR diagnostics, rpc_error = await exec.execute( exec.thread_executor, EBNFServer.compile_EBNF, ('document = /.*/', )) assert diagnostics == '[]' exec.shutdown() asyncio_run(main())
def test_initialization_sequence(self): self.start_server() async def initialization_sequence(): reader, writer = await asyncio_connect('127.0.0.1', TEST_PORT) writer.write( json_rpc( 'initialize', { 'processId': 702, 'rootUri': 'file://~/tmp', 'capabilities': {} }).encode()) response = (await reader.read(8192)).decode() i = response.find('{') res = json.loads(response[i:]) assert 'result' in res and 'capabilities' in res['result'], str( res) writer.write(json_rpc('initialized', {}).encode()) writer.write(json_rpc('custom', {'test': 1}).encode()) response = (await reader.read(8192)).decode() assert response.find('test') >= 0 writer.close() if sys.version_info >= (3, 7): await writer.wait_closed() asyncio_run(initialization_sequence())
def test_varying_data_chunk_sizes(self): self.start_server() async def initialization_sequence(): reader, writer = await asyncio_connect('127.0.0.1', TEST_PORT) writer.write( json_rpc( 'initialize', { 'processId': 702, 'rootUri': 'file://~/tmp', 'capabilities': {} }).encode()) response = (await reader.read(8192)).decode() i = response.find('{') res = json.loads(response[i:]) assert 'result' in res and 'capabilities' in res['result'], str( res) # several commands in one chunk writer.write( json_rpc('initialized', {}).encode() + json_rpc('custom', { 'test': 1 }).encode()) response = (await reader.read(8192)).decode() assert response.find('test') >= 0 data = json_rpc('custom', {'test': 2}).encode() i = data.find(b'\n\n') assert i > 0, str(data) writer.write(data[:i + 2]) await asyncio.sleep(1) writer.write(data[i + 2:]) response = (await reader.read(8192)).decode() assert response.find('test') >= 0 data = json_rpc('custom', {'test': 3}).encode() i = data.find(b'\n\n') assert i > 0, str(data) writer.write(data[:i + 2]) await asyncio.sleep(0.1) writer.write(data[i + 2:] + json_rpc('custom', { 'test': 4 }).encode()) response = (await reader.read(8192)).decode() assert response.find('test') >= 0 writer.write(b'') await writer.drain() writer.write_eof() await writer.drain() writer.close() if sys.version_info >= (3, 7): await writer.wait_closed() asyncio_run(initialization_sequence())
def send_request(request: str, expect_response: bool = True) -> str: response = '' async def send(request): nonlocal response reader, writer = await asyncio_connect('127.0.0.1', TEST_PORT) writer.write(request.encode()) if expect_response: response = (await reader.read(8192)).decode() writer.close() if sys.version_info >= (3, 7): await writer.wait_closed() asyncio_run(send(request)) return response
def test_terminate(self): """Test different ways of sending a termination message to server: http-request, plain-text and json-rpc.""" async def terminate_server(termination_request, expected_response): reader, writer = await asyncio_connect('127.0.0.1', TEST_PORT) writer.write(termination_request) data = await reader.read(500) writer.close() if sys.version_info >= (3, 7): await writer.wait_closed() assert data.find(expected_response) >= 0, str(data) p = None try: # plain text stop request p = spawn_tcp_server('127.0.0.1', TEST_PORT, (compiler_dummy, set())) asyncio_run( terminate_server( STOP_SERVER_REQUEST_BYTES, b'DHParser server at 127.0.0.1:%i stopped!' % TEST_PORT)) assert asyncio_run(has_server_stopped('127.0.0.1', TEST_PORT)) # http stop request p = spawn_tcp_server('127.0.0.1', TEST_PORT, (compiler_dummy, set())) asyncio_run( terminate_server( b'GET ' + STOP_SERVER_REQUEST_BYTES + b' HTTP', b'DHParser server at 127.0.0.1:%i stopped!' % TEST_PORT)) assert asyncio_run(has_server_stopped('127.0.0.1', TEST_PORT)) # json_rpc stop request p = spawn_tcp_server('127.0.0.1', TEST_PORT, (compiler_dummy, set())) jsonrpc = json.dumps({ "jsonrpc": "2.0", "method": STOP_SERVER_REQUEST_BYTES.decode(), 'id': 1 }) asyncio_run( terminate_server( jsonrpc.encode(), b'DHParser server at 127.0.0.1:%i stopped!' % TEST_PORT)) assert asyncio_run(has_server_stopped('127.0.0.1', TEST_PORT)) finally: stop_tcp_server('127.0.0.1', TEST_PORT) if p is not None: p.join()
def test_server_process(self): """Basic Test of server module.""" async def compile_remote(src): reader, writer = await asyncio_connect('127.0.0.1', TEST_PORT) writer.write(src.encode()) data = await reader.read(500) writer.close() if sys.version_info >= (3, 7): await writer.wait_closed() assert data.decode() == "Test", data.decode() p = None try: p = spawn_tcp_server('127.0.0.1', TEST_PORT, (compiler_dummy, set())) asyncio_run(compile_remote('Test')) finally: stop_tcp_server('127.0.0.1', TEST_PORT) if p is not None: p.join()
def test_reader_writer_simple(self): async def main(): self.writer.write(b'Hello\n') await self.writer.drain() data = await self.reader.read() self.writer.close() return data data = asyncio_run(main()) assert data == b'Hello\n', str(data) assert self.pipe.closed
def test_service_call(self): async def identify_server(): main_reader, main_writer = await asyncio_connect( '127.0.0.1', TEST_PORT) main_writer.write(IDENTIFY_REQUEST.encode()) data = await main_reader.read(500) assert b'already connected' not in data service_reader, service_writer = await asyncio_connect( '127.0.0.1', TEST_PORT) service_writer.write(IDENTIFY_REQUEST.encode()) data = await service_reader.read(500) assert b'already connected' in data await asyncio.sleep(0.01) assert service_reader.at_eof() service_writer.close() if sys.version_info >= (3, 7): await service_writer.wait_closed() service_reader, service_writer = await asyncio_connect( '127.0.0.1', TEST_PORT) service_writer.write(json_rpc('identify', {}).encode()) data = await service_reader.read(500) assert b'already connected' in data await asyncio.sleep(0.01) assert service_reader.at_eof() service_writer.close() if sys.version_info >= (3, 7): await service_writer.wait_closed() main_writer.close() if sys.version_info >= (3, 7): await main_writer.wait_closed() p = None try: p = spawn_tcp_server('127.0.0.1', TEST_PORT) asyncio_run(identify_server()) finally: stop_tcp_server('127.0.0.1', TEST_PORT) if p is not None: p.join()
def test_spawn(self): spawn_tcp_server('127.0.0.1', TEST_PORT) async def identify(): try: reader, writer = await asyncio_connect('127.0.0.1', TEST_PORT) writer.write(IDENTIFY_REQUEST.encode()) data = await reader.read(500) await writer.drain() writer.close() if sys.version_info >= (3, 7): await writer.wait_closed() return data.decode() except ConnectionRefusedError: return '' result = asyncio_run(identify()) assert result.startswith('DHParser'), result
def test_identify(self): """Test server's 'identify/'-command.""" async def send_request(request): reader, writer = await asyncio_connect('127.0.0.1', TEST_PORT) writer.write( request.encode() if isinstance(request, str) else request) data = await reader.read(500) await writer.drain() writer.close() if sys.version_info >= (3, 7): await writer.wait_closed() return data.decode() p = None try: from timeit import timeit p = spawn_tcp_server('127.0.0.1', TEST_PORT, compiler_dummy) result = asyncio_run(send_request(IDENTIFY_REQUEST)) assert isinstance(result, str) and result.startswith('DHParser'), result finally: stop_tcp_server('127.0.0.1', TEST_PORT) if p is not None: p.join()
def test_server_process(self): """Basic Test of server module.""" async def compile_remote(src, reader, writer) -> bytes: writer.write(add_header(src.encode())) await writer.drain() data = await read_full_content(reader) # writer.close() # if sys.version_info >= (3, 7): await writer.wait_closed() header, data, backlog = split_header(data) return data.decode() # assert data.decode() == "Test", data.decode() p = None try: p = spawn_stream_server(self.readerA, self.writerB, (mock_compiler, set()), threading.Thread) data = asyncio_run( compile_remote('Test', self.readerB, self.writerA)) assert data == "tEST" finally: if p is not None: stop_stream_server(self.readerB, self.writerA) p.join()
def test_reader_writer(self): async def write(writer): writer.write(JSONRPC_HEADER_BYTES % len(IDENTIFY_REQUEST_BYTES) + IDENTIFY_REQUEST_BYTES) await writer.drain() async def read(reader): return await read_full_content(reader) async def main(): if sys.version_info >= (3, 7): read_task = asyncio.create_task(read(self.reader)) write_task = asyncio.create_task(write(self.writer)) else: read_task = asyncio.ensure_future(read(self.reader)) write_task = asyncio.ensure_future(write(self.writer)) data = await read_task await write_task self.writer.close() return data data = asyncio_run(main()) assert data == b'Content-Length: 10\r\n\r\nidentify()', str(data) assert self.pipe.closed
def test_initialize(self): self.start_server() async def sequence_test(): reader, writer = await asyncio_connect('127.0.0.1', TEST_PORT) async def send(request: str, expect_response: bool = True) -> str: writer.write(request.encode()) await writer.drain() if expect_response: return (await reader.read(8192)).decode() return '' response = await send( json_rpc( 'initialize', { 'processId': 701, 'rootUri': 'file://~/tmp', 'capabilities': {} })) i = response.find('{') - 1 res = json.loads(response[i:]) assert 'result' in res and 'capabilities' in res['result'], str( res) r2, w2 = await asyncio_connect('127.0.0.1', TEST_PORT) w2.write( json_rpc( 'initialize', { 'processId': 701, 'rootUri': 'file://~/tmp', 'capabilities': {} }).encode()) fail = await r2.read(8192) assert b'error' in fail and b'already connected' in fail w2.write_eof() w2.close() if sys.version_info >= (3, 7): await w2.wait_closed() r2, w2 = await asyncio_connect('127.0.0.1', TEST_PORT) w2.write(json_rpc('custom', {}).encode()) fail = await r2.read(8192) assert b'result' not in fail assert b'not a service function' in fail w2.write_eof() w2.close() if sys.version_info >= (3, 7): await w2.wait_closed() response = await send(json_rpc('custom', {})) assert response.find('error') >= 0 response = await send(json_rpc('initialized', {}), expect_response=False) assert response == '', response response = await send(json_rpc('custom', {'test': 1})) assert response.find('test') >= 0, str(response) response = await send(json_rpc('check', {})) assert response.find('701') >= 0 response = await send(json_rpc('non_existant_function', {})) assert response.find('-32601') >= 0 # method not found response = await send( json_rpc('non_existant_function', { 'a': 1, 'b': 2, 'c': 3 })) assert response.find('-32601') >= 0 # method not found # test plain-data call response = await send('custom(1)') assert response.find('1') >= 0 # test plain-data false call response = await send('non_existant_function()') assert response.find('No function named "non_extistant_function"') response = await send('non_existant_function(1)') assert response.find('No function named "non_extistant_function"') response = await send(json_rpc('shutdown', {})) assert response.find('error') < 0 # after shutdown, any function call except "exit()" should yield error response = await send(json_rpc('custom', {})) assert response.find('error') >= 0 response = await send(json_rpc('exit', {})) assert response == '', response writer.close() if sys.version_info >= (3, 7): await writer.wait_closed() asyncio_run(sequence_test())
def test_long_running_task(self): """Test, whether delegation of (long-running) tasks to processes or threads works.""" sequence = [] if self.spawn: SLOW, FAST = 0.1, 0.01 else: SLOW, FAST = 0.02, 0.001 async def run_tasks(): def extract_result(data: bytes): header, data, backlog = split_header(data) return json.loads(data.decode())['result'] reader, writer = await asyncio_connect('127.0.0.1', TEST_PORT) sequence.append(SLOW) sequence.append(FAST) writer.write(json_rpc('long_running', {'duration': SLOW}).encode()) writer.write(json_rpc('long_running', {'duration': FAST}).encode()) await writer.drain() sequence.append(extract_result(await reader.read(500))) sequence.append(extract_result(await reader.read(500))) writer.close() if sys.version_info >= (3, 7): await writer.wait_closed() if sys.version_info >= (3, 6): p = None try: p = spawn_tcp_server( '127.0.0.1', TEST_PORT, (long_running, frozenset(['long_running']), frozenset(), connection_cb_dummy, 'Long-Running-Test', False)) asyncio_run(run_tasks()) assert sequence == [SLOW, FAST, FAST, SLOW], str(sequence) finally: stop_tcp_server('127.0.0.1', TEST_PORT) if p is not None: p.join() sequence = [] p = None try: p = spawn_tcp_server( '127.0.0.1', TEST_PORT, (long_running, frozenset(), frozenset(['long_running']), connection_cb_dummy, 'Long-Running-Test', False)) asyncio_run(run_tasks()) assert sequence == [SLOW, FAST, FAST, SLOW], str(sequence) finally: stop_tcp_server('127.0.0.1', TEST_PORT) if p is not None: p.join() sequence = [] p = None try: p = spawn_tcp_server( '127.0.0.1', TEST_PORT, (long_running, frozenset(), frozenset(), connection_cb_dummy, 'Long-Running-Test', False)) asyncio_run(run_tasks()) assert sequence.count(SLOW) == 2 and sequence.count(FAST) == 2 finally: stop_tcp_server('127.0.0.1', TEST_PORT) if p is not None: p.join() sequence = []
def test_server_processes(self): # This test takes a few seconds! async def test_interaction(reader, writer) -> bool: async def send(json_obj: str): writer.write(add_header(json.dumps(json_obj).encode())) await writer.drain() async def receive() -> str: package = await read_full_content(reader) header, raw_data, backlog = split_header(package) return json.loads(raw_data.decode()) publishDiagnosticsCounter = 0 await send(initialize_request) data = await receive() assert "result" in data and data['id'] == initialize_request['id'] await send(initialized_notification) await send(didOpen_notification) await asyncio.sleep(EBNFServer.RECOMPILE_DELAY + 2) await send(didChange_notifictaion_1) await asyncio.sleep(0.1) await send(completion_request) await asyncio.sleep(EBNFServer.RECOMPILE_DELAY + 0.5) await send(didSave_notification_1) await asyncio.sleep(0.1) await send(didChange_notification_2) await asyncio.sleep(EBNFServer.RECOMPILE_DELAY + 0.5) await send(didSave_notification_2) await asyncio.sleep(0.1) data = await receive() while 'method' in data: assert data['method'] == 'textDocument/publishDiagnostics' publishDiagnosticsCounter += 1 data = await receive() assert publishDiagnosticsCounter == 1 assert 'id' in data and data['id'] == completion_request['id'] while self.pipeB.data_available(): data = await receive() if 'method' in data: assert data['method'] == 'textDocument/publishDiagnostics' publishDiagnosticsCounter += 1 await asyncio.sleep(0.1) assert publishDiagnosticsCounter == 3 await send(shutdown_request) data = await receive() assert 'id' in data and data['id'] == shutdown_request['id'] await send(exit_notification) await asyncio.sleep(0.5) p = None try: p = spawn_stream_server( self.readerA, self.writerB, { 'rpc_functions': self.lsp_table, 'cpu_bound': set(self.EBNF_lsp.cpu_bound.lsp_table.keys()), 'blocking': set(self.EBNF_lsp.blocking.lsp_table.keys()), 'connection_callback': self.EBNF_lsp.connect, 'server_name': 'EBNFServer', 'strict_lsp': True }, threading.Thread) asyncio_run(test_interaction(self.readerB, self.writerA)) finally: if p is not None: value_error = stop_stream_server(self.readerB, self.writerA) # assert value_error, "server hasn't been shutdown orderly" p.join()