def __init__(self, input_stream=None, output_stream=None): """ Initializes the sql tools client. Input and output streams for JsonRpcClient are taken as optional params, Else a SqlToolsService process is started and its stdin and stdout is used. """ self.current_id = 1 self.tools_service_process = None if input_stream and output_stream: self.json_rpc_client = json_rpc_client.JsonRpcClient( input_stream, output_stream) else: self.tools_service_process = subprocess.Popen( sqltoolsservice_args, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE) self.json_rpc_client = json_rpc_client.JsonRpcClient( self.tools_service_process.stdin, io.open(self.tools_service_process.stdout.fileno(), u'rb', buffering=0, closefd=False)) logger.info(u'SqlToolsService process id: {0}'.format( self.tools_service_process.pid)) self.json_rpc_client.start() logger.info(u'Sql Tools Client Initialized')
def test_request_enqueued(self): """ Verify requests are enqueued. """ input_stream = io.BytesIO() output_stream = io.BytesIO(b'sample output') test_client = json_rpc_client.JsonRpcClient( input_stream, output_stream) test_client.submit_request( u'scriptingService/ScriptDatabase', {u'ScriptDatabaseOptions': u'True'}) test_client = json_rpc_client.JsonRpcClient( input_stream, output_stream) test_client.submit_request( u'scriptingService/ScriptDatabase', {u'ScriptDatabaseOptions': u'True'}) request = test_client.request_queue.get() self.assertEqual( request[u'method'], u'scriptingService/ScriptDatabase') self.assertEqual( request[u'params'], { u'ScriptDatabaseOptions': u'True'})
def test_submit_simple_request(self): """ Verify simple request submitted. """ input_stream = io.BytesIO() output_stream = io.BytesIO( b'Content-Length: 15\r\n\r\n{"key":"value"}') test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() time.sleep(.5) # Verify threads are alive and running. self.assertTrue(test_client.request_thread.is_alive()) self.assertFalse(test_client.response_thread.is_alive()) test_client.submit_request(u'scriptingService/ScriptDatabase', {u'ScriptDatabaseOptions': u'True'}) JsonRpcClientTests.shutdown_background_threads(test_client) # check stream contents. input_stream.seek(0) expected = ( b'Content-Length: 120\r\n\r\n{"id": null, "jsonrpc": "2.0", ' b'"method": "scriptingService/ScriptDatabase", ' b'"params": {"ScriptDatabaseOptions": "True"}}') self.assertEqual(input_stream.getvalue(), expected) self.assertFalse(test_client.request_thread.is_alive()) self.assertFalse(test_client.response_thread.is_alive())
def test_query_retrieve_correct_response(self): """ Verify a query execute request never retrieves query request responses for a different query. """ with open(self.get_baseline(\ u'test_query_retrieve_correct_response.txt'), u'r+b', buffering=0) as response_file: request_stream = io.BytesIO() rpc_client = json_rpc_client.JsonRpcClient( in_stream=request_stream, out_stream=response_file) rpc_client.start() owner_uri = u'mismatchquerycompleteresponse_2' parameters = { u'OwnerUri': owner_uri, u'Query': "select * from HumanResources.Department" } request = queryservice.QueryExecuteStringRequest( request_id=u'3', owner_uri=owner_uri, json_rpc_client=rpc_client, parameters=parameters) # The baseline file contains responses for a different owner uri, which # this request should not receive. Receiving a query complete event with # a error message indicates we did not retrieve a wrong event. self.verify_query_service_response(request=request, expected_complete_event=1, expected_error_count=1) rpc_client.shutdown()
def test_malformed_query_AdventureWorks2014(self): """ Verify a failed query execute response for "select * from [HumanResources.Department" """ with open(self.get_baseline(\ u'test_malformed_query.txt'), u'r+b', buffering=0) as response_file: request_stream = io.BytesIO() rpc_client = json_rpc_client.JsonRpcClient( in_stream=request_stream, out_stream=response_file) rpc_client.start() # Submit a dummy request. owner_uri = u'connectionservicetest' parameters = { u'OwnerUri': owner_uri, u'Query': "select * from [HumanResources.Department" } request = queryservice.QueryExecuteStringRequest( request_id=u'2', owner_uri=owner_uri, json_rpc_client=rpc_client, parameters=parameters) self.verify_query_service_response(request=request, expected_error_count=1) rpc_client.shutdown()
def test_successful_connection_AdventureWorks2014(self): """ Verify a successful connection response """ with open(self.get_baseline(\ u'test_simple_query.txt'), u'r+b', buffering=0) as response_file: request_stream = io.BytesIO() rpc_client = json_rpc_client.JsonRpcClient( in_stream=request_stream, out_stream=response_file) rpc_client.start() owner_uri = u'connectionservicetest' parameters = { u'OwnerUri': owner_uri, u'ServerName': u'bro-hb', u'DatabaseName': u'AdventureWorks2014', u'UserName': u'*', u'Password': u'*', u'AuthenticationType': u'Integrated', u'MultipleActiveResultSets': True } request = connectionservice.ConnectionRequest( request_id=u'1', owner_uri=owner_uri, json_rpc_client=rpc_client, parameters=parameters) self.verify_connection_service_response(request=request, expected_response_event=1, expected_complete_event=1) rpc_client.shutdown()
def test_query_execute_response_AdventureWorks2014(self): """ Verify a successful query execute response for "select * from HumanResources.Department" """ with open(self.get_baseline(\ u'test_simple_query.txt'), u'r+b', buffering=0) as response_file: request_stream = io.BytesIO() rpc_client = json_rpc_client.JsonRpcClient( in_stream=request_stream, out_stream=response_file) rpc_client.start() # Submit a dummy request. owner_uri = u'connectionservicetest' parameters = { u'OwnerUri': owner_uri, u'Query': "select * from HumanResources.Department" } request = queryservice.QueryExecuteStringRequest( request_id=2, owner_uri=owner_uri, json_rpc_client=rpc_client, parameters=parameters) self.verify_query_service_response(request=request, expected_message_event=1, expected_complete_event=1, expected_batch_summaries=1, expected_result_set_summaries=1, expected_row_count=16) rpc_client.shutdown()
def test_query_subset_response_AdventureWorks2014(self): """ Test the retrieval of the actual rows for "select * from HumanResources.Department" """ with open(self.get_baseline(\ u'test_simple_query.txt'), u'r+b', buffering=0) as response_file: request_stream = io.BytesIO() rpc_client = json_rpc_client.JsonRpcClient(request_stream, response_file) rpc_client.start() # Submit a dummy request. owner_uri = u'connectionservicetest' parameters = { u'OwnerUri': u'connectionservicetest', u'BatchIndex': 0, u'ResultSetIndex': 0, u'RowsStartIndex': 0, u'RowCount': 16 } request = queryservice.QuerySubsetRequest( request_id=u'3', owner_uri=owner_uri, json_rpc_client=rpc_client, parameters=parameters) self.verify_query_service_response(request=request, expected_result_subsets=1, expected_row_count=16) rpc_client.shutdown()
def test_successful_connection_AdventureWorks2014(self): """ Verify a successful connection response """ with open(self.get_test_baseline( u'select_from_humanresources_department_adventureworks2014.txt' ), u'r+b', buffering=0) as response_file: request_stream = io.BytesIO() rpc_client = json_rpc_client.JsonRpcClient(request_stream, response_file) rpc_client.start() # Submit a dummy request. parameters = { u'OwnerUri': u'connectionservicetest', u'ServerName': u'bro-hb', u'DatabaseName': u'AdventureWorks2014', u'UserName': u'*', u'Password': u'*', u'AuthenticationType': u'Integrated', u'MultipleActiveResultSets': True } request = connectionservice.ConnectionRequest( 1, rpc_client, parameters) self.verify_success_response(request=request) rpc_client.shutdown()
def test_get_response_with_id(self): """ Verify response retrieval with id returns global event or response. """ input_stream = io.BytesIO() output_stream = io.BytesIO( b'Content-Length: 86\r\n\r\n{"params": {"Key": "Value"}, "jsonrpc": "2.0", ' b'"method": "testMethod/DoThis", "id": 1}') test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() # Sleeping to give background threads a chance to process response. time.sleep(1) # Sleeping to give background threads a chance to process response. time.sleep(1) baseline = { u'jsonrpc': u'2.0', u'params': { u'Key': u'Value' }, u'method': u'testMethod/DoThis', u'id': 1 } response = test_client.get_response(request_id=1) self.assertEqual(response, baseline) test_client.shutdown()
def test_stream_closed_during_process(self): """ Verify request stream closed, exception returned and request thread died. """ input_stream = io.BytesIO() output_stream = io.BytesIO( b'Content-Length: 15\r\n\r\n{"key":"value"}') test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() input_stream.close() test_client.submit_request('scriptingService/ScriptDatabase', {'ScriptLogins': 'True'}) # sleep 1 second for request thread to process. time.sleep(1) try: test_client.get_response() except ValueError as exception: # Verify the background thread communicated the exception. self.assertEqual(str(exception), u'I/O operation on closed file.') # Verify response thread is dead. self.assertFalse(test_client.request_thread.is_alive()) test_client.shutdown()
def test_send_invalid_request(self): """ Verifies that a request with a null method or parameter is not enqueued. """ input_stream = io.BytesIO() output_stream = io.BytesIO(b'sample output') test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) with self.assertRaises(ValueError): test_client.submit_request(None, None)
def __init__(self, input_stream=None, output_stream=None, enable_logging=False): """ Initializes the sql tools client. Input and output streams for JsonRpcClient are taken as optional params, Else a SqlToolsService process is started and its stdin and stdout is used. """ self.current_id = uuid.uuid4().int self.tools_service_process = None sqltoolsservice_args = [mssqltoolsservice.get_executable_path()] if enable_logging: sqltoolsservice_args.append('--enable-logging') sqltoolsservice_args.append('--log-dir') sqltoolsservice_args.append(config_location()) if input_stream and output_stream: self.json_rpc_client = json_rpc_client.JsonRpcClient( input_stream, output_stream) else: self.tools_service_process = subprocess.Popen( sqltoolsservice_args, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE) self.json_rpc_client = json_rpc_client.JsonRpcClient( self.tools_service_process.stdin, io.open(self.tools_service_process.stdout.fileno(), u'rb', buffering=0, closefd=False)) logger.info(u'SqlToolsService process id: {0}'.format( self.tools_service_process.pid)) self.json_rpc_client.start() logger.info(u'Sql Tools Client Initialized')
def test_send_multiple_request(self): """ Verifies we can successfully submit multiple requests. """ input_stream = io.BytesIO() output_stream = io.BytesIO( b'Content-Length: 15\r\n\r\n{"key":"value"}') test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() time.sleep(.5) # request thread is alive. # response thread is dead due to reaching EOF. self.assertTrue(test_client.request_thread.is_alive()) self.assertFalse(test_client.response_thread.is_alive()) test_client.submit_request(u'scriptingService/ScriptDatabase', {u'ScriptDatabaseOptions': u'True'}) test_client.submit_request(u'scriptingService/ScriptDatabase', {u'ScriptCollations': u'True'}) test_client.submit_request(u'scriptingService/ScriptDatabase', {u'ScriptDefaults': u'True'}) # Minimum sleep time for main thread, so background threads can process # the requests. time.sleep(1) # Kill the threads so we can just verify the queues. JsonRpcClientTests.shutdown_background_threads(test_client) input_stream.seek(0) expected = ( b'Content-Length: 120\r\n\r\n{"id": null, "jsonrpc": "2.0", ' b'"method": "scriptingService/ScriptDatabase", ' b'"params": {"ScriptDatabaseOptions": "True"}}' b'Content-Length: 115\r\n\r\n{"id": null, "jsonrpc": "2.0", ' b'"method": "scriptingService/ScriptDatabase", "params": {"ScriptCollations": "True"}}' b'Content-Length: 113\r\n\r\n{"id": null, "jsonrpc": "2.0", ' b'"method": "scriptingService/ScriptDatabase", "params": {"ScriptDefaults": "True"}}' ) self.assertEqual(input_stream.getvalue(), expected) self.assertFalse(test_client.request_thread.is_alive()) self.assertFalse(test_client.response_thread.is_alive())
def test_query_execute_response_AdventureWorks2014(self): """ Verify a successful query execute response for "select * from HumanResources.Department" """ with open(self.get_test_baseline(u'select_from_humanresources_department_adventureworks2014.txt'), u'r+b', buffering=0) as response_file: request_stream = io.BytesIO() rpc_client = json_rpc_client.JsonRpcClient( request_stream, response_file) rpc_client.start() # Submit a dummy request. parameters = {u'OwnerUri': u'connectionservicetest', u'Query': "select * from HumanResources.Department"} request = queryservice.QueryExecuteStringRequest( 2, rpc_client, parameters) self.verify_query_response(request=request) rpc_client.shutdown()
def test_stream_has_no_response(self): """ Verify response thread is alive while output stream has no output. """ input_stream = io.BytesIO() output_stream = io.BytesIO() test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() response = test_client.get_response() self.assertEqual(response, None) self.assertTrue(test_client.request_thread.is_alive()) self.assertTrue(test_client.response_thread.is_alive()) test_client.shutdown() self.assertFalse(test_client.request_thread.is_alive()) self.assertFalse(test_client.response_thread.is_alive())
def test_receive_invalid_response_exception(self): """ Verify invalid response has exception queued and response thread dies. """ input_stream = io.BytesIO() output_stream = io.BytesIO(b'Cntent-Lenth:15\r\n\r\n') test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() try: # Retrieve the latest response or earliest exception. test_client.get_response() except LookupError as exception: # Verify the background thread communicated the exception. self.assertEqual( str(exception), u'Content-Length was not found in headers received.') # flaky test fix: logic that waits until threads shut down count = 0 while count < 5: active_threads = threading.enumerate() if test_client.request_thread not in active_threads or \ test_client.response_thread in active_threads: time.sleep(5) count += 1 else: break # Lookup exception for invalid content length spelling. self.assertTrue(test_client.request_thread.is_alive()) self.assertFalse(test_client.response_thread.is_alive()) test_client.shutdown() self.assertFalse(test_client.request_thread.is_alive()) except Exception as exception: raise AssertionError("Expected LookupError but caught a different exception: {}"\ .format(exception)) else: raise AssertionError("LookupError should have been thrown.") finally: test_client.shutdown()
def test_response_stream_closed_exception(self): """ Verify response stream closed, exception returned and response thread died. """ input_stream = io.BytesIO() output_stream = io.BytesIO(b'Content-Lenth:15\r\n\r\n') output_stream.close() test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() try: test_client.get_response() except ValueError as exception: # Verify the background thread communicated the exception. self.assertEqual(str(exception), u'I/O operation on closed file.') test_client.shutdown()
def test_response_dequeued(self): """ Verify response was read. """ input_stream = io.BytesIO() output_stream = io.BytesIO( b'Content-Length: 15\r\n\r\n{"key":"value"}') test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() time.sleep(.2) response = test_client.get_response() baseline = {u'key': u'value'} self.assertEqual(response, baseline) JsonRpcClientTests.shutdown_background_threads(test_client) # All background threads should be shut down. self.assertFalse(test_client.request_thread.is_alive()) self.assertFalse(test_client.response_thread.is_alive())
def test_query_subset_response_AdventureWorks2014(self): """ Test the retrieval of the actual rows for "select * from HumanResources.Department" """ with open(self.get_test_baseline(u'select_from_humanresources_department_adventureworks2014.txt'), u'r+b', buffering=0) as response_file: request_stream = io.BytesIO() rpc_client = json_rpc_client.JsonRpcClient( request_stream, response_file) rpc_client.start() # Submit a dummy request. parameters = {u'OwnerUri': u'connectionservicetest', u'BatchIndex': 0, u'ResultSetIndex': 0, u'RowsStartIndex': 0, u'RowCount': 16} request = queryservice.QuerySubsetRequest( 3, rpc_client, parameters) self.verify_subset_response(request=request) rpc_client.shutdown()
def test_normal_shutdown(self): """ Verify normal shutdown. """ input_stream = io.BytesIO() output_stream = io.BytesIO( b'Content-Length: 15\r\n\r\n{"key":"value"}') test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() time.sleep(.5) # Verify threads alive. self.assertTrue(test_client.request_thread.is_alive()) # Response thread is dead due to EOF. self.assertFalse(test_client.response_thread.is_alive()) test_client.shutdown() self.assertFalse(test_client.request_thread.is_alive()) self.assertFalse(test_client.response_thread.is_alive())
def test_response_stream_closed_exception(self): """ Verify response stream closed, exception returned and response thread died. """ input_stream = io.BytesIO() output_stream = io.BytesIO(b'Content-Lenth:15\r\n\r\n') output_stream.close() test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() try: test_client.get_response() except ValueError as exception: # Verify the background thread communicated the exception. self.assertEqual(str(exception), u'I/O operation on closed file.') except Exception as exception: raise AssertionError("Expected ValueError but caught a different exception: {}"\ .format(exception)) else: raise AssertionError("ValueError should have been thrown.") finally: test_client.shutdown()
def test_receive_invalid_response_exception(self): """ Verify invalid response has exception queued and response thread dies. """ input_stream = io.BytesIO() output_stream = io.BytesIO(b'Cntent-Lenth:15\r\n\r\n') test_client = json_rpc_client.JsonRpcClient(input_stream, output_stream) test_client.start() try: # Retrieve the latest response or earliest exception. test_client.get_response() except LookupError as exception: # Verify the background thread communicated the exception. self.assertEqual( str(exception), u'Content-Length was not found in headers received.') # Lookup exception for invalid content length spelling. self.assertTrue(test_client.request_thread.is_alive()) self.assertFalse(test_client.response_thread.is_alive()) test_client.shutdown() self.assertFalse(test_client.request_thread.is_alive())