From 29d27c23416e7b6e425c907df7f07b2f99fb3b1b Mon Sep 17 00:00:00 2001 From: Benjamin Russell Date: Tue, 7 Mar 2017 12:27:48 -0800 Subject: [PATCH] Block Initializing Edit Sessions When In Progress (#265) * Implementation of a wait handle for initialize * WIP * Adding more initialize unit tests --- .../EditData/EditDataService.cs | 40 +- .../Localization/sr.cs | 11 + .../Localization/sr.resx | 4 + .../Localization/sr.strings | 2 + .../Localization/sr.xlf | 1085 +++++++++-------- .../EditData/ServiceIntegrationTests.cs | 136 +++ 6 files changed, 735 insertions(+), 543 deletions(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/EditData/EditDataService.cs b/src/Microsoft.SqlTools.ServiceLayer/EditData/EditDataService.cs index 09ca5119..2f755021 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/EditData/EditDataService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/EditData/EditDataService.cs @@ -57,6 +57,10 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData private readonly Lazy> editSessions = new Lazy>( () => new ConcurrentDictionary()); + private readonly Lazy>> initializeWaitHandles = + new Lazy>>( + () => new ConcurrentDictionary>()); + #endregion #region Properties @@ -66,6 +70,12 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData /// internal ConcurrentDictionary ActiveSessions => editSessions.Value; + /// + /// Dictionary mapping OwnerURIs to wait handlers for initialize tasks. Pretty much only + /// provided for unit test scenarios. + /// + internal ConcurrentDictionary> InitializeWaitHandles => initializeWaitHandles.Value; + #endregion /// @@ -160,7 +170,14 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData // Make sure we have info to process this request Validate.IsNotNullOrWhitespaceString(nameof(initParams.OwnerUri), initParams.OwnerUri); Validate.IsNotNullOrWhitespaceString(nameof(initParams.ObjectName), initParams.ObjectName); + Validate.IsNotNullOrWhitespaceString(nameof(initParams.ObjectType), initParams.ObjectType); + // Try to add a new wait handler to the + if (!InitializeWaitHandles.TryAdd(initParams.OwnerUri, new TaskCompletionSource())) + { + throw new InvalidOperationException(SR.EditDataInitializeInProgress); + } + // Setup a callback for when the query has successfully created Func> queryCreateSuccessCallback = async query => { @@ -169,21 +186,26 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData }; // Setup a callback for when the query failed to be created - Func queryCreateFailureCallback = requestContext.SendError; + Func queryCreateFailureCallback = async message => + { + await requestContext.SendError(message); + CompleteInitializeWaitHandler(initParams.OwnerUri, false); + }; // Setup a callback for when the query completes execution successfully Query.QueryAsyncEventHandler queryCompleteSuccessCallback = q => QueryCompleteCallback(q, initParams, requestContext); // Setup a callback for when the query completes execution with failure - Query.QueryAsyncEventHandler queryCompleteFailureCallback = query => + Query.QueryAsyncEventHandler queryCompleteFailureCallback = async query => { EditSessionReadyParams readyParams = new EditSessionReadyParams { OwnerUri = initParams.OwnerUri, Success = false }; - return requestContext.SendEvent(EditSessionReadyEvent.Type, readyParams); + await requestContext.SendEvent(EditSessionReadyEvent.Type, readyParams); + CompleteInitializeWaitHandler(initParams.OwnerUri, false); }; // Put together a query for the results and execute it @@ -199,6 +221,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData catch (Exception e) { await requestContext.SendError(e.Message); + CompleteInitializeWaitHandler(initParams.OwnerUri, false); } } @@ -304,6 +327,17 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData // Send the edit session ready notification await requestContext.SendEvent(EditSessionReadyEvent.Type, readyParams); + CompleteInitializeWaitHandler(initParams.OwnerUri, true); + } + + private void CompleteInitializeWaitHandler(string ownerUri, bool result) + { + // If there isn't a wait handler, just ignore it + TaskCompletionSource initializeWaiter; + if (ownerUri != null && InitializeWaitHandles.TryRemove(ownerUri, out initializeWaiter)) + { + initializeWaiter.SetResult(result); + } } #endregion diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs index 693aa48e..50bccdc7 100755 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs @@ -501,6 +501,14 @@ namespace Microsoft.SqlTools.ServiceLayer } } + public static string EditDataInitializeInProgress + { + get + { + return Keys.GetString(Keys.EditDataInitializeInProgress); + } + } + public static string EE_BatchSqlMessageNoProcedureInfo { get @@ -1046,6 +1054,9 @@ namespace Microsoft.SqlTools.ServiceLayer public const string EditDataCommitInProgress = "EditDataCommitInProgress"; + public const string EditDataInitializeInProgress = "EditDataInitializeInProgress"; + + public const string EE_BatchSqlMessageNoProcedureInfo = "EE_BatchSqlMessageNoProcedureInfo"; diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx index fbb62c0f..c7f5ae88 100755 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx @@ -423,6 +423,10 @@ A commit task is in progress. Please wait for completion. + + Another edit data initialize is in progress for this owner URI. Please wait for completion. + + Msg {0}, Level {1}, State {2}, Line {3} diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings index 04784fe4..72ad9a72 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings @@ -200,6 +200,8 @@ EditDataScriptFilePathNull = An output filename must be provided EditDataCommitInProgress = A commit task is in progress. Please wait for completion. +EditDataInitializeInProgress = Another edit data initialize is in progress for this owner URI. Please wait for completion. + ############################################################################ # DacFx Resources diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf index 88a6570c..fd16ede6 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf @@ -1,541 +1,546 @@ - - - - - - Connection parameters cannot be null - Connection parameters cannot be null - - - - OwnerUri cannot be null or empty - OwnerUri cannot be null or empty - - - - SpecifiedUri '{0}' does not have existing connection - SpecifiedUri '{0}' does not have existing connection - . - Parameters: 0 - uri (string) - - - Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. - Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. - . - Parameters: 0 - authType (string) - - - Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. - Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. - . - Parameters: 0 - intent (string) - - - Connection canceled - Connection canceled - - - - OwnerUri cannot be null or empty - OwnerUri cannot be null or empty - - - - Connection details object cannot be null - Connection details object cannot be null - - - - ServerName cannot be null or empty - ServerName cannot be null or empty - - - - {0} cannot be null or empty when using SqlLogin authentication - {0} cannot be null or empty when using SqlLogin authentication - . - Parameters: 0 - component (string) - - - The query has already completed, it cannot be cancelled - The query has already completed, it cannot be cancelled - - - - Query successfully cancelled, failed to dispose query. Owner URI not found. - Query successfully cancelled, failed to dispose query. Owner URI not found. - - - - Query was canceled by user - Query was canceled by user - - - - The batch has not completed, yet - The batch has not completed, yet - - - - Batch index cannot be less than 0 or greater than the number of batches - Batch index cannot be less than 0 or greater than the number of batches - - - - Result set index cannot be less than 0 or greater than the number of result sets - Result set index cannot be less than 0 or greater than the number of result sets - - - - Maximum number of bytes to return must be greater than zero - Maximum number of bytes to return must be greater than zero - - - - Maximum number of chars to return must be greater than zero - Maximum number of chars to return must be greater than zero - - - - Maximum number of XML bytes to return must be greater than zero - Maximum number of XML bytes to return must be greater than zero - - - - Access method cannot be write-only - Access method cannot be write-only - - - - FileStreamWrapper must be initialized before performing operations - FileStreamWrapper must be initialized before performing operations - - - - This FileStreamWrapper cannot be used for writing - This FileStreamWrapper cannot be used for writing - - - - (1 row affected) - (1 row affected) - - - - ({0} rows affected) - ({0} rows affected) - . - Parameters: 0 - rows (long) - - - Commands completed successfully. - Commands completed successfully. - - - - Msg {0}, Level {1}, State {2}, Line {3}{4}{5} - Msg {0}, Level {1}, State {2}, Line {3}{4}{5} - . - Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) - - - Query failed: {0} - Query failed: {0} - . - Parameters: 0 - message (string) - - - (No column name) - (No column name) - - - - The requested query does not exist - The requested query does not exist - - - - This editor is not connected to a database - This editor is not connected to a database - - - - A query is already in progress for this editor session. Please cancel this query or wait for its completion. - A query is already in progress for this editor session. Please cancel this query or wait for its completion. - - - - Sender for OnInfoMessage event must be a SqlConnection - Sender for OnInfoMessage event must be a SqlConnection - - - - Result cannot be saved until query execution has completed - Result cannot be saved until query execution has completed - - - - Internal error occurred while starting save task - Internal error occurred while starting save task - - - - A save request to the same path is in progress - A save request to the same path is in progress - - - - Failed to save {0}: {1} - Failed to save {0}: {1} - . - Parameters: 0 - fileName (string), 1 - message (string) - - - Cannot read subset unless the results have been read from the server - Cannot read subset unless the results have been read from the server - - - - Start row cannot be less than 0 or greater than the number of rows in the result set - Start row cannot be less than 0 or greater than the number of rows in the result set - - - - Row count must be a positive integer - Row count must be a positive integer - - - - Could not retrieve column schema for result set - Could not retrieve column schema for result set - - - - Could not retrieve an execution plan from the result set - Could not retrieve an execution plan from the result set - - - - This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} - This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} - . - Parameters: 0 - errorMessage (string) - - - An unexpected error occurred during Peek Definition execution: {0} - An unexpected error occurred during Peek Definition execution: {0} - . - Parameters: 0 - errorMessage (string) - - - No results were found. - No results were found. - - - - No database object was retrieved. - No database object was retrieved. - - - - Please connect to a server. - Please connect to a server. - - - - Operation timed out. - Operation timed out. - - - - This object type is currently not supported by this feature. - This object type is currently not supported by this feature. - - - - Position is outside of file line range - Position is outside of file line range - - - - Position is outside of column range for line {0} - Position is outside of column range for line {0} - . - Parameters: 0 - line (int) - - - Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) - Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) - . - Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) - - - Msg {0}, Level {1}, State {2}, Line {3} - Msg {0}, Level {1}, State {2}, Line {3} - - - - Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} - Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} - - - - Msg {0}, Level {1}, State {2} - Msg {0}, Level {1}, State {2} - - - - An error occurred while the batch was being processed. The error message is: {0} - An error occurred while the batch was being processed. The error message is: {0} - - - - ({0} row(s) affected) - ({0} row(s) affected) - - - - The previous execution is not yet complete. - The previous execution is not yet complete. - - - - A scripting error occurred. - A scripting error occurred. - - - - Incorrect syntax was encountered while {0} was being parsed. - Incorrect syntax was encountered while {0} was being parsed. - - - - A fatal error occurred. - A fatal error occurred. - - - - Execution completed {0} times... - Execution completed {0} times... - - - - You cancelled the query. - You cancelled the query. - - - - An error occurred while the batch was being executed. - An error occurred while the batch was being executed. - - - - An error occurred while the batch was being executed, but the error has been ignored. - An error occurred while the batch was being executed, but the error has been ignored. - - - - Starting execution loop of {0} times... - Starting execution loop of {0} times... - - - - Command {0} is not supported. - Command {0} is not supported. - - - - The variable {0} could not be found. - The variable {0} could not be found. - - - - SQL Execution error: {0} - SQL Execution error: {0} - - - - Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} - Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} - - - - Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} - Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} - - - - Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} - Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} - - - - Batch parser wrapper execution engine batch ResultSet finished. - Batch parser wrapper execution engine batch ResultSet finished. - - - - Canceling batch parser wrapper batch execution. - Canceling batch parser wrapper batch execution. - - - - Scripting warning. - Scripting warning. - - - - For more information about this error, see the troubleshooting topics in the product documentation. - For more information about this error, see the troubleshooting topics in the product documentation. - - - - File '{0}' recursively included. - File '{0}' recursively included. - - - - Missing end comment mark '*/'. - Missing end comment mark '*/'. - - - - Unclosed quotation mark after the character string. - Unclosed quotation mark after the character string. - - - - Incorrect syntax was encountered while parsing '{0}'. - Incorrect syntax was encountered while parsing '{0}'. - - - - Variable {0} is not defined. - Variable {0} is not defined. - - - - EN_LOCALIZATION - EN_LOCALIZATION - - - - Cannot convert SqlCodeObject Type {0} to Type {1} - Cannot convert SqlCodeObject Type {0} to Type {1} - - - - Replacement of an empty string by an empty string. - Replacement of an empty string by an empty string. - - - - Edit session does not exist. - Edit session does not exist. - - - - Query has not completed execution - Query has not completed execution - - - - Query did not generate exactly one result set - Query did not generate exactly one result set - - - - Failed to add new row to update cache - Failed to add new row to update cache - - - - Given row ID is outside the range of rows in the edit cache - Given row ID is outside the range of rows in the edit cache - - - - An update is already pending for this row and must be reverted first - An update is already pending for this row and must be reverted first - - - - Given row ID does not have pending updated - Given row ID does not have pending updated - - - - Table or view metadata could not be found - Table or view metadata could not be found - - - - Invalid format for binary column - Invalid format for binary column - - - - Allowed values for boolean columns are 0, 1, "true", or "false" - Boolean columns must be numeric 1 or 0, or string true or false - - - - A required cell value is missing - A required cell value is missing - - - - A delete is pending for this row, a cell update cannot be applied. - A delete is pending for this row, a cell update cannot be applied. - - - - Column ID must be in the range of columns for the query - Column ID must be in the range of columns for the query - - - - Column cannot be edited - Column cannot be edited - - - - No key columns were found - No key columns were found - - - - An output filename must be provided - An output filename must be provided - - - - Database object {0} cannot be used for editing. - Database object {0} cannot be used for editing. - . - Parameters: 0 - typeName (string) - - - Specified URI '{0}' does not have a default connection - Specified URI '{0}' does not have a default connection - . - Parameters: 0 - uri (string) - - - A commit task is in progress. Please wait for completion. - A commit task is in progress. Please wait for completion. - - - - Decimal column is missing numeric precision or numeric scale - Decimal column is missing numeric precision or numeric scale - - - - Cannot add row to result buffer, data reader does not contain rows - Cannot add row to result buffer, data reader does not contain rows - - - - + + + + + + Connection parameters cannot be null + Connection parameters cannot be null + + + + OwnerUri cannot be null or empty + OwnerUri cannot be null or empty + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri '{0}' does not have existing connection + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + . + Parameters: 0 - intent (string) + + + Connection canceled + Connection canceled + + + + OwnerUri cannot be null or empty + OwnerUri cannot be null or empty + + + + Connection details object cannot be null + Connection details object cannot be null + + + + ServerName cannot be null or empty + ServerName cannot be null or empty + + + + {0} cannot be null or empty when using SqlLogin authentication + {0} cannot be null or empty when using SqlLogin authentication + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + The query has already completed, it cannot be cancelled + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + Query successfully cancelled, failed to dispose query. Owner URI not found. + + + + Query was canceled by user + Query was canceled by user + + + + The batch has not completed, yet + The batch has not completed, yet + + + + Batch index cannot be less than 0 or greater than the number of batches + Batch index cannot be less than 0 or greater than the number of batches + + + + Result set index cannot be less than 0 or greater than the number of result sets + Result set index cannot be less than 0 or greater than the number of result sets + + + + Maximum number of bytes to return must be greater than zero + Maximum number of bytes to return must be greater than zero + + + + Maximum number of chars to return must be greater than zero + Maximum number of chars to return must be greater than zero + + + + Maximum number of XML bytes to return must be greater than zero + Maximum number of XML bytes to return must be greater than zero + + + + Access method cannot be write-only + Access method cannot be write-only + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper must be initialized before performing operations + + + + This FileStreamWrapper cannot be used for writing + This FileStreamWrapper cannot be used for writing + + + + (1 row affected) + (1 row affected) + + + + ({0} rows affected) + ({0} rows affected) + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + Commands completed successfully. + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + Query failed: {0} + . + Parameters: 0 - message (string) + + + (No column name) + (No column name) + + + + The requested query does not exist + The requested query does not exist + + + + This editor is not connected to a database + This editor is not connected to a database + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + + + + Sender for OnInfoMessage event must be a SqlConnection + Sender for OnInfoMessage event must be a SqlConnection + + + + Result cannot be saved until query execution has completed + Result cannot be saved until query execution has completed + + + + Internal error occurred while starting save task + Internal error occurred while starting save task + + + + A save request to the same path is in progress + A save request to the same path is in progress + + + + Failed to save {0}: {1} + Failed to save {0}: {1} + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + Cannot read subset unless the results have been read from the server + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + Start row cannot be less than 0 or greater than the number of rows in the result set + + + + Row count must be a positive integer + Row count must be a positive integer + + + + Could not retrieve column schema for result set + Could not retrieve column schema for result set + + + + Could not retrieve an execution plan from the result set + Could not retrieve an execution plan from the result set + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + An unexpected error occurred during Peek Definition execution: {0} + . + Parameters: 0 - errorMessage (string) + + + No results were found. + No results were found. + + + + No database object was retrieved. + No database object was retrieved. + + + + Please connect to a server. + Please connect to a server. + + + + Operation timed out. + Operation timed out. + + + + This object type is currently not supported by this feature. + This object type is currently not supported by this feature. + + + + Position is outside of file line range + Position is outside of file line range + + + + Position is outside of column range for line {0} + Position is outside of column range for line {0} + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + Msg {0}, Level {1}, State {2}, Line {3} + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + + + + Msg {0}, Level {1}, State {2} + Msg {0}, Level {1}, State {2} + + + + An error occurred while the batch was being processed. The error message is: {0} + An error occurred while the batch was being processed. The error message is: {0} + + + + ({0} row(s) affected) + ({0} row(s) affected) + + + + The previous execution is not yet complete. + The previous execution is not yet complete. + + + + A scripting error occurred. + A scripting error occurred. + + + + Incorrect syntax was encountered while {0} was being parsed. + Incorrect syntax was encountered while {0} was being parsed. + + + + A fatal error occurred. + A fatal error occurred. + + + + Execution completed {0} times... + Execution completed {0} times... + + + + You cancelled the query. + You cancelled the query. + + + + An error occurred while the batch was being executed. + An error occurred while the batch was being executed. + + + + An error occurred while the batch was being executed, but the error has been ignored. + An error occurred while the batch was being executed, but the error has been ignored. + + + + Starting execution loop of {0} times... + Starting execution loop of {0} times... + + + + Command {0} is not supported. + Command {0} is not supported. + + + + The variable {0} could not be found. + The variable {0} could not be found. + + + + SQL Execution error: {0} + SQL Execution error: {0} + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + Batch parser wrapper execution engine batch ResultSet finished. + Batch parser wrapper execution engine batch ResultSet finished. + + + + Canceling batch parser wrapper batch execution. + Canceling batch parser wrapper batch execution. + + + + Scripting warning. + Scripting warning. + + + + For more information about this error, see the troubleshooting topics in the product documentation. + For more information about this error, see the troubleshooting topics in the product documentation. + + + + File '{0}' recursively included. + File '{0}' recursively included. + + + + Missing end comment mark '*/'. + Missing end comment mark '*/'. + + + + Unclosed quotation mark after the character string. + Unclosed quotation mark after the character string. + + + + Incorrect syntax was encountered while parsing '{0}'. + Incorrect syntax was encountered while parsing '{0}'. + + + + Variable {0} is not defined. + Variable {0} is not defined. + + + + EN_LOCALIZATION + EN_LOCALIZATION + + + + Cannot convert SqlCodeObject Type {0} to Type {1} + Cannot convert SqlCodeObject Type {0} to Type {1} + + + + Replacement of an empty string by an empty string. + Replacement of an empty string by an empty string. + + + + Edit session does not exist. + Edit session does not exist. + + + + Query has not completed execution + Query has not completed execution + + + + Query did not generate exactly one result set + Query did not generate exactly one result set + + + + Failed to add new row to update cache + Failed to add new row to update cache + + + + Given row ID is outside the range of rows in the edit cache + Given row ID is outside the range of rows in the edit cache + + + + An update is already pending for this row and must be reverted first + An update is already pending for this row and must be reverted first + + + + Given row ID does not have pending updated + Given row ID does not have pending updated + + + + Table or view metadata could not be found + Table or view metadata could not be found + + + + Invalid format for binary column + Invalid format for binary column + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Boolean columns must be numeric 1 or 0, or string true or false + + + + A required cell value is missing + A required cell value is missing + + + + A delete is pending for this row, a cell update cannot be applied. + A delete is pending for this row, a cell update cannot be applied. + + + + Column ID must be in the range of columns for the query + Column ID must be in the range of columns for the query + + + + Column cannot be edited + Column cannot be edited + + + + No key columns were found + No key columns were found + + + + An output filename must be provided + An output filename must be provided + + + + Database object {0} cannot be used for editing. + Database object {0} cannot be used for editing. + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + Specified URI '{0}' does not have a default connection + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + A commit task is in progress. Please wait for completion. + + + + Decimal column is missing numeric precision or numeric scale + Decimal column is missing numeric precision or numeric scale + + + + Cannot add row to result buffer, data reader does not contain rows + Cannot add row to result buffer, data reader does not contain rows + + + + Another edit data initialize is in progress for this owner URI. Please wait for completion. + Another edit data initialize is in progress for this owner URI. Please wait for completion. + + + + \ No newline at end of file diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/ServiceIntegrationTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/ServiceIntegrationTests.cs index f820a3dd..fabfd9ad 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/ServiceIntegrationTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/EditData/ServiceIntegrationTests.cs @@ -215,6 +215,142 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData edit.Verify(e => e.SetCell(It.IsAny(), It.IsAny()), Times.Once); } + [Theory] + [InlineData(null, "table", "table")] // Null owner URI + [InlineData(Common.OwnerUri, null, "table")] // Null object name + [InlineData(Common.OwnerUri, "table", null)] // Null object type + public async Task InitializeNullParams(string ownerUri, string objName, string objType) + { + // Setup: Create an edit data service without a session + var eds = new EditDataService(null, null, null); + + // If: + // ... I have init params with a null parameter + var initParams = new EditInitializeParams + { + ObjectName = objName, + OwnerUri = ownerUri, + ObjectType = objType + }; + + // ... And I initialize an edit session with that + var efv = new EventFlowValidator() + .AddErrorValidation(Assert.NotNull) + .Complete(); + await eds.HandleInitializeRequest(initParams, efv.Object); + + // Then: + // ... An error event should have been raised + efv.Validate(); + + // ... There should not be a session + Assert.Empty(eds.ActiveSessions); + + // ... There should not be a wait handler + Assert.Empty(eds.InitializeWaitHandles); + } + + [Fact] + public async Task InitializeInProgress() + { + // Setup: Create an edit data service with an "in-progress initialize" + var eds = new EditDataService(null, null, null); + eds.InitializeWaitHandles[Common.OwnerUri] = new TaskCompletionSource(); + + // If: + // ... I ask to initialize a session when an initialize task is already in progress + var initParams = new EditInitializeParams + { + ObjectName = "table", + OwnerUri = Common.OwnerUri, + ObjectType = "table" + }; + var efv = new EventFlowValidator() + .AddErrorValidation(Assert.NotNull) + .Complete(); + await eds.HandleInitializeRequest(initParams, efv.Object); + + // Then: + // ... An error event should have been raised + efv.Validate(); + + // ... There should not be a session + Assert.Empty(eds.ActiveSessions); + } + + [Fact] + public async Task InitializeQueryCreateFailed() + { + // Setup: + // ... Create a query execution service that will throw on creation of the query + var qes = QueryExecution.Common.GetPrimedExecutionService(null, false, false, null); + + // ... Create an edit data service that uses the mocked up query service + var eds = new EditDataService(qes, null, null); + + // If: + // ... I initialize a session + var initParams = new EditInitializeParams + { + ObjectName = "table", + OwnerUri = Common.OwnerUri, + ObjectType = "table" + }; + var efv = new EventFlowValidator() + .AddErrorValidation(Assert.NotEmpty) + .Complete(); + await eds.HandleInitializeRequest(initParams, efv.Object); + + // Then: + // ... We should have gotten an error back + efv.Validate(); + + // ... There should not be any sessions created + Assert.Empty(eds.ActiveSessions); + + // ... There should not be a wait handle + Assert.Empty(eds.InitializeWaitHandles); + } + + [Fact] + public async Task InitializeQueryExecutionFails() + { + // Setup: + // ... Create a query execution service that will throw on execution of the query + var qes = QueryExecution.Common.GetPrimedExecutionService(null, true, true, null); + + // ... Create an edit data service that uses the mocked up query service + var eds = new EditDataService(qes, null, null); + + // If: + // ... I initialize a session + var initParams = new EditInitializeParams + { + ObjectName = "table", + OwnerUri = Common.OwnerUri, + ObjectType = "table" + }; + var efv = new EventFlowValidator() + .AddResultValidation(Assert.NotNull) + .AddEventValidation(EditSessionReadyEvent.Type, esrp => + { + Assert.NotNull(esrp); + Assert.False(esrp.Success); + }).Complete(); + await eds.HandleInitializeRequest(initParams, efv.Object); + await eds.InitializeWaitHandles[Common.OwnerUri].Task; + + // Then: + // ... We should have started execution, but failed + efv.Validate(); + + // ... There should not be any sessions created + Assert.Empty(eds.ActiveSessions); + + // ... There should not be a wait handle. It should have been cleaned up by now + Assert.Empty(eds.InitializeWaitHandles); + } + private static EditSession GetDefaultSession() { // ... Create a session with a proper query and metadata