mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-20 01:25:41 -05:00
Include ManagedBatchParser tests to improve code coverage (#793)
* Include ManagedBatchParser test to improve code coverage * Fix some failing test cases and revert appveyor.yml
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode;
|
||||
|
||||
namespace Microsoft.SqlTools.ManagedBatchParser.UnitTests.BatchParser
|
||||
{
|
||||
internal class BatchParserMockEventHandler : IBatchEventsHandler
|
||||
{
|
||||
public SqlError Error { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// fired when there is an error message from the server
|
||||
/// </summary>
|
||||
public void OnBatchError(object sender, BatchErrorEventArgs args)
|
||||
{
|
||||
Debug.WriteLine("{0}", args.Message);
|
||||
Error = args.Error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// fired when there is a message from the server
|
||||
/// </summary>
|
||||
public void OnBatchMessage(object sender, BatchMessageEventArgs args)
|
||||
{
|
||||
Debug.WriteLine("{0}", args.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// fired when there is a new result set available. It is guarnteed
|
||||
/// to be fired from the same thread that called Execute method
|
||||
/// </summary>
|
||||
public void OnBatchResultSetProcessing(object sender, BatchResultSetEventArgs args) { }
|
||||
|
||||
/// <summary>
|
||||
/// fired when we've done absolutely all actions for the current result set
|
||||
/// </summary>
|
||||
public void OnBatchResultSetFinished(object sender, EventArgs args) { }
|
||||
|
||||
/// <summary>
|
||||
/// fired when the batch recieved cancel request BEFORE it
|
||||
/// initiates cancel operation. Note that it is fired from a
|
||||
/// different thread then the one used to kick off execution
|
||||
/// </summary>
|
||||
public void OnBatchCancelling(object sender, EventArgs args) { }
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ManagedBatchParser.UnitTests.BatchParser
|
||||
{
|
||||
public class BatchParserSqlCmdTests : IDisposable
|
||||
{
|
||||
private BatchParserSqlCmd bpcmd;
|
||||
private PositionStruct testPOS;
|
||||
public BatchParserSqlCmdTests()
|
||||
{
|
||||
bpcmd = new BatchParserSqlCmd();
|
||||
testPOS = new PositionStruct();
|
||||
bpcmd.SetVariable(testPOS, "variable1", "test1");
|
||||
bpcmd.SetVariable(testPOS, "variable2", "test2");
|
||||
bpcmd.SetVariable(testPOS, "variable3", "test3");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (bpcmd != null)
|
||||
{
|
||||
bpcmd = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckSetVariable()
|
||||
{
|
||||
Assert.Equal(bpcmd.InternalVariables.Count, 3);
|
||||
bpcmd.SetVariable(testPOS, "variable4", "test4");
|
||||
bpcmd.SetVariable(testPOS, "variable5", "test5");
|
||||
bpcmd.SetVariable(testPOS, "variable6", "test6");
|
||||
Assert.Equal(bpcmd.InternalVariables.Count, 6);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckSetNullValueVariable()
|
||||
{
|
||||
Assert.Equal(bpcmd.InternalVariables.Count, 3);
|
||||
bpcmd.SetVariable(testPOS, "variable4", "test4");
|
||||
Assert.Equal(bpcmd.InternalVariables.Count, 4);
|
||||
bpcmd.SetVariable(testPOS, "variable4", null);
|
||||
Assert.Equal(bpcmd.InternalVariables.Count, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckGetVariable()
|
||||
{
|
||||
string value = bpcmd.GetVariable(testPOS, "variable1");
|
||||
Assert.Equal("test1", value);
|
||||
value = bpcmd.GetVariable(testPOS, "variable2");
|
||||
Assert.Equal("test2", value);
|
||||
value = bpcmd.GetVariable(testPOS, "variable3");
|
||||
Assert.Equal("test3", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckGetNullVariable()
|
||||
{
|
||||
Assert.Null(bpcmd.GetVariable(testPOS, "variable6"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckInclude()
|
||||
{
|
||||
TextReader textReader = null;
|
||||
string outString = "out";
|
||||
var result = bpcmd.Include(null, out textReader, out outString);
|
||||
Assert.Equal(result, BatchParserAction.Abort);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckOnError()
|
||||
{
|
||||
var errorActionChanged = bpcmd.ErrorActionChanged;
|
||||
var action = new OnErrorAction();
|
||||
var result = bpcmd.OnError(null, action);
|
||||
Assert.Equal(result, BatchParserAction.Continue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckConnectionChangedDelegate()
|
||||
{
|
||||
var initial = bpcmd.ConnectionChanged;
|
||||
bpcmd.ConnectionChanged = null;
|
||||
Assert.Null(bpcmd.ConnectionChanged);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckVariableSubstitutionDisabled()
|
||||
{
|
||||
bpcmd.DisableVariableSubstitution();
|
||||
bpcmd.SetVariable(testPOS, "variable1", "test");
|
||||
var result = bpcmd.GetVariable(testPOS, "variable1");
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,292 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Common.Baselined;
|
||||
using Xunit;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.TSQLExecutionEngine;
|
||||
|
||||
namespace Microsoft.SqlTools.ManagedBatchParser.UnitTests.BatchParser
|
||||
{
|
||||
public class BatchParserTests : BaselinedTest
|
||||
{
|
||||
private bool testFailed = false;
|
||||
|
||||
public BatchParserTests()
|
||||
{
|
||||
InitializeTest();
|
||||
}
|
||||
|
||||
public void InitializeTest()
|
||||
{
|
||||
CategoryName = "BatchParser";
|
||||
this.TraceOutputDirectory = RunEnvironmentInfo.GetTraceOutputLocation();
|
||||
TestInitialize();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VerifyThrowOnUnresolvedVariable()
|
||||
{
|
||||
string script = "print '$(NotDefined)'";
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
TestCommandHandler handler = new TestCommandHandler(output);
|
||||
IVariableResolver resolver = new TestVariableResolver(new StringBuilder());
|
||||
using (Parser p = new Parser(
|
||||
handler,
|
||||
resolver,
|
||||
new StringReader(script),
|
||||
"test"))
|
||||
{
|
||||
p.ThrowOnUnresolvedVariable = true;
|
||||
handler.SetParser(p);
|
||||
|
||||
Assert.Throws<BatchParserException>(() => p.Parse());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VerifyExecuteScript()
|
||||
{
|
||||
string query = "select @@version";
|
||||
ExecutionEngineTest executionEngineTest = new ExecutionEngineTest();
|
||||
executionEngineTest.TestInitialize();
|
||||
using (ExecutionEngine engine = new ExecutionEngine())
|
||||
{
|
||||
engine.ExecuteScript(query);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanceltheBatch()
|
||||
{
|
||||
Batch batch = new Batch();
|
||||
batch.Cancel();
|
||||
}
|
||||
|
||||
private static Stream GenerateStreamFromString(string s)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
StreamWriter writer = new StreamWriter(stream);
|
||||
writer.Write(s);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
|
||||
public void TokenizeWithLexer(string filename, StringBuilder output)
|
||||
{
|
||||
// Create a new file by changing CRLFs to LFs and generate a new steam
|
||||
// or the tokens generated by the lexer will always have off by one errors
|
||||
string input = File.ReadAllText(filename).Replace("\r\n", "\n");
|
||||
var inputStream = GenerateStreamFromString(input);
|
||||
using (Lexer lexer = new Lexer(new StreamReader(inputStream), filename))
|
||||
{
|
||||
|
||||
string inputText = File.ReadAllText(filename);
|
||||
inputText = inputText.Replace("\r\n", "\n");
|
||||
StringBuilder roundtripTextBuilder = new StringBuilder();
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
StringBuilder tokenizedInput = new StringBuilder();
|
||||
bool lexerError = false;
|
||||
|
||||
Token token = null;
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
lexer.ConsumeToken();
|
||||
token = lexer.CurrentToken;
|
||||
roundtripTextBuilder.Append(token.Text.Replace("\r\n", "\n"));
|
||||
outputBuilder.AppendLine(GetTokenString(token));
|
||||
tokenizedInput.Append('[').Append(GetTokenCode(token.TokenType)).Append(':').Append(token.Text.Replace("\r\n", "\n")).Append(']');
|
||||
} while (token.TokenType != LexerTokenType.Eof);
|
||||
}
|
||||
catch (BatchParserException ex)
|
||||
{
|
||||
lexerError = true;
|
||||
outputBuilder.AppendLine(string.Format(CultureInfo.CurrentCulture, "[ERROR: code {0} at {1} - {2} in {3}, message: {4}]", ex.ErrorCode, GetPositionString(ex.Begin), GetPositionString(ex.End), GetFilenameOnly(ex.Begin.Filename), ex.Message));
|
||||
}
|
||||
output.AppendLine("Lexer tokenized input:");
|
||||
output.AppendLine("======================");
|
||||
output.AppendLine(tokenizedInput.ToString());
|
||||
output.AppendLine("Tokens:");
|
||||
output.AppendLine("=======");
|
||||
output.AppendLine(outputBuilder.ToString());
|
||||
|
||||
if (lexerError == false)
|
||||
{
|
||||
// Verify that all text from tokens can be recombined into original string
|
||||
Assert.Equal<string>(inputText, roundtripTextBuilder.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetTokenCode(LexerTokenType lexerTokenType)
|
||||
{
|
||||
switch (lexerTokenType)
|
||||
{
|
||||
case LexerTokenType.Text:
|
||||
return "T";
|
||||
case LexerTokenType.Whitespace:
|
||||
return "WS";
|
||||
case LexerTokenType.NewLine:
|
||||
return "NL";
|
||||
case LexerTokenType.Comment:
|
||||
return "C";
|
||||
default:
|
||||
return lexerTokenType.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CopyToOutput(string sourceDirectory, string filename)
|
||||
{
|
||||
File.Copy(Path.Combine(sourceDirectory, filename), filename, true);
|
||||
FileUtilities.SetFileReadWrite(filename);
|
||||
}
|
||||
|
||||
// [Fact]
|
||||
public void BatchParserTest()
|
||||
{
|
||||
CopyToOutput(FilesLocation, "TS-err-cycle1.txt");
|
||||
CopyToOutput(FilesLocation, "cycle2.txt");
|
||||
Start("err-blockComment");
|
||||
Start("err-blockComment2");
|
||||
Start("err-varDefinition");
|
||||
Start("err-varDefinition2");
|
||||
Start("err-varDefinition3");
|
||||
Start("err-varDefinition4");
|
||||
Start("err-varDefinition5");
|
||||
Start("err-varDefinition6");
|
||||
Start("err-varDefinition7");
|
||||
Start("err-varDefinition8");
|
||||
Start("err-varDefinition9");
|
||||
Start("err-variableRef");
|
||||
Start("err-variableRef2");
|
||||
Start("err-variableRef3");
|
||||
Start("err-variableRef4");
|
||||
Start("err-cycle1");
|
||||
Start("input");
|
||||
Start("input2");
|
||||
Start("pass-blockComment");
|
||||
Start("pass-lineComment");
|
||||
Start("pass-lineComment2");
|
||||
Start("pass-noBlockComments");
|
||||
Start("pass-noLineComments");
|
||||
Start("pass-varDefinition");
|
||||
Start("pass-varDefinition2");
|
||||
Start("pass-varDefinition3");
|
||||
Start("pass-varDefinition4");
|
||||
Start("pass-command-and-comment");
|
||||
Assert.False(testFailed, "At least one of test cases failed. Check output for details.");
|
||||
}
|
||||
|
||||
public void TestParser(string filename, StringBuilder output)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create a new file by changing CRLFs to LFs and generate a new steam
|
||||
// or the tokens generated by the lexer will always have off by one errors
|
||||
TestCommandHandler commandHandler = new TestCommandHandler(output);
|
||||
string input = File.ReadAllText(filename).Replace("\r\n", "\n");
|
||||
var inputStream = GenerateStreamFromString(input);
|
||||
StreamReader streamReader = new StreamReader(inputStream);
|
||||
|
||||
using (Parser parser = new Parser(
|
||||
commandHandler,
|
||||
new TestVariableResolver(output),
|
||||
streamReader,
|
||||
filename))
|
||||
{
|
||||
commandHandler.SetParser(parser);
|
||||
parser.Parse();
|
||||
}
|
||||
}
|
||||
catch (BatchParserException ex)
|
||||
{
|
||||
output.AppendLine(string.Format(CultureInfo.CurrentCulture, "[PARSER ERROR: code {0} at {1} - {2} in {3}, token text: {4}, message: {5}]", ex.ErrorCode, GetPositionString(ex.Begin), GetPositionString(ex.End), GetFilenameOnly(ex.Begin.Filename), ex.Text, ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
private string GetPositionString(PositionStruct pos)
|
||||
{
|
||||
return string.Format(CultureInfo.InvariantCulture, "{0}:{1} [{2}]", pos.Line, pos.Column, pos.Offset);
|
||||
}
|
||||
|
||||
private string GetTokenString(Token token)
|
||||
{
|
||||
if (token == null)
|
||||
{
|
||||
return "(null)";
|
||||
}
|
||||
else
|
||||
{
|
||||
string tokenText = token.Text;
|
||||
if (tokenText != null)
|
||||
{
|
||||
tokenText = tokenText.Replace("\r\n", "\\n").Replace("\n", "\\n").Replace("\r", "\\r").Replace("\t", "\\t");
|
||||
}
|
||||
string tokenFilename = token.Filename;
|
||||
tokenFilename = GetFilenameOnly(tokenFilename);
|
||||
return string.Format(CultureInfo.CurrentCulture, "[Token {0} at {1}({2}:{3} [{4}] - {5}:{6} [{7}]): '{8}']",
|
||||
token.TokenType,
|
||||
tokenFilename,
|
||||
token.Begin.Line, token.Begin.Column, token.Begin.Offset,
|
||||
token.End.Line, token.End.Column, token.End.Offset,
|
||||
tokenText);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetFilenameOnly(string fullPath)
|
||||
{
|
||||
return fullPath != null ? Path.GetFileName(fullPath) : null;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
string inputFilename = GetTestscriptFilePath(CurrentTestName);
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
TokenizeWithLexer(inputFilename, output);
|
||||
TestParser(inputFilename, output);
|
||||
|
||||
string baselineFilename = GetBaselineFilePath(CurrentTestName);
|
||||
string baseline;
|
||||
|
||||
try
|
||||
{
|
||||
baseline = GetFileContent(baselineFilename).Replace("\r\n", "\n");
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
baseline = string.Empty;
|
||||
}
|
||||
|
||||
string outputString = output.ToString().Replace("\r\n", "\n");
|
||||
|
||||
//Console.WriteLine(baselineFilename);
|
||||
|
||||
if (string.Compare(baseline, outputString, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
DumpToTrace(CurrentTestName, outputString);
|
||||
string outputFilename = Path.Combine(TraceFilePath, GetBaselineFileName(CurrentTestName));
|
||||
Console.WriteLine(":: Output does not match the baseline!");
|
||||
Console.WriteLine("code --diff \"" + baselineFilename + "\" \"" + outputFilename + "\"");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(":: To update the baseline:");
|
||||
Console.WriteLine("copy \"" + outputFilename + "\" \"" + baselineFilename + "\"");
|
||||
Console.WriteLine();
|
||||
testFailed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ManagedBatchParser.UnitTests.BatchParser
|
||||
{
|
||||
public class BatchParserWrapperTests
|
||||
{
|
||||
[Fact]
|
||||
public void CheckSimpleSingleSQLBatchStatement()
|
||||
{
|
||||
using (BatchParserWrapper parserWrapper = new BatchParserWrapper())
|
||||
{
|
||||
string sqlScript = "select * from sys.objects";
|
||||
var batches = parserWrapper.GetBatches(sqlScript);
|
||||
Assert.Equal(1, batches.Count);
|
||||
BatchDefinition batch = batches[0];
|
||||
Assert.Equal(sqlScript, batch.BatchText);
|
||||
Assert.Equal(1, batch.StartLine);
|
||||
Assert.Equal(1, batch.StartColumn);
|
||||
Assert.Equal(2, batch.EndLine);
|
||||
Assert.Equal(sqlScript.Length + 1, batch.EndColumn);
|
||||
Assert.Equal(1, batch.BatchExecutionCount);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckSQLBatchStatementWithRepeatExecution()
|
||||
{
|
||||
using (BatchParserWrapper parserWrapper = new BatchParserWrapper())
|
||||
{
|
||||
string sqlScript = "select * from sys.object" + Environment.NewLine + "GO 2";
|
||||
var batches = parserWrapper.GetBatches(sqlScript);
|
||||
Assert.Equal(1, batches.Count);
|
||||
BatchDefinition batch = batches[0];
|
||||
Assert.Equal(2, batch.BatchExecutionCount);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckComment()
|
||||
{
|
||||
using (BatchParserWrapper parserWrapper = new BatchParserWrapper())
|
||||
{
|
||||
string sqlScript = "-- this is a comment --";
|
||||
var batches = parserWrapper.GetBatches(sqlScript);
|
||||
Assert.Equal(1, batches.Count);
|
||||
BatchDefinition batch = batches[0];
|
||||
Assert.Equal(sqlScript, batch.BatchText);
|
||||
Assert.Equal(1, batch.StartLine);
|
||||
Assert.Equal(1, batch.StartColumn);
|
||||
Assert.Equal(2, batch.EndLine);
|
||||
Assert.Equal(sqlScript.Length + 1, batch.EndColumn);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckNoOps()
|
||||
{
|
||||
using (BatchParserWrapper parserWrapper = new BatchParserWrapper())
|
||||
{
|
||||
string sqlScript = "GO";
|
||||
var batches = parserWrapper.GetBatches(sqlScript);
|
||||
Assert.Equal(0, batches.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser;
|
||||
|
||||
namespace Microsoft.SqlTools.ManagedBatchParser.UnitTests.BatchParser
|
||||
{
|
||||
internal class TestCommandHandler : ICommandHandler
|
||||
{
|
||||
private Parser parser;
|
||||
private StringBuilder outputString;
|
||||
|
||||
public TestCommandHandler(StringBuilder outputString)
|
||||
{
|
||||
this.outputString = outputString;
|
||||
}
|
||||
|
||||
public void SetParser(Parser parser)
|
||||
{
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
public BatchParserAction Go(TextBlock batch, int repeatCount)
|
||||
{
|
||||
string textWithVariablesResolved;
|
||||
string textWithVariablesUnresolved;
|
||||
LineInfo lineInfoVarsResolved;
|
||||
LineInfo lineInfoVarsUnresolved;
|
||||
|
||||
batch.GetText(true, out textWithVariablesResolved, out lineInfoVarsResolved);
|
||||
batch.GetText(false, out textWithVariablesUnresolved, out lineInfoVarsUnresolved);
|
||||
outputString.AppendFormat(CultureInfo.InvariantCulture, "*** Execute batch ({0})\n", repeatCount);
|
||||
|
||||
if (string.Compare(textWithVariablesUnresolved, textWithVariablesResolved, StringComparison.Ordinal) != 0)
|
||||
{
|
||||
outputString.AppendLine("Text with variables not resolved:");
|
||||
outputString.AppendLine(textWithVariablesResolved);
|
||||
outputString.AppendLine("Text with variables not resolved:");
|
||||
outputString.AppendLine(textWithVariablesUnresolved);
|
||||
int i = 0;
|
||||
outputString.AppendLine("Mapping from resolved string to unresolved:");
|
||||
while (i <= textWithVariablesResolved.Length)
|
||||
{
|
||||
PositionStruct pos = lineInfoVarsResolved.GetStreamPositionForOffset(i);
|
||||
string character = i < textWithVariablesResolved.Length ? ("" + textWithVariablesResolved[i]).Replace("\n", @"\n").Replace("\r", @"\r") : "EOF";
|
||||
outputString.AppendFormat(CultureInfo.InvariantCulture, "Pos [{0}] {1}:{2} \"{3}\"",
|
||||
i,
|
||||
BatchParserTests.GetFilenameOnly(pos.Filename),
|
||||
pos.Offset,
|
||||
character);
|
||||
outputString.AppendLine();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outputString.AppendLine("Batch text:");
|
||||
outputString.AppendLine(textWithVariablesUnresolved);
|
||||
}
|
||||
outputString.AppendLine();
|
||||
return BatchParserAction.Continue;
|
||||
}
|
||||
|
||||
public BatchParserAction OnError(Token token, OnErrorAction action)
|
||||
{
|
||||
outputString.AppendFormat(CultureInfo.InvariantCulture, "*** PARSER: On error: {0}", action.ToString());
|
||||
outputString.AppendLine();
|
||||
return BatchParserAction.Continue;
|
||||
}
|
||||
|
||||
public BatchParserAction Include(TextBlock filename, out TextReader stream, out string newFilename)
|
||||
{
|
||||
string resolvedFilename;
|
||||
LineInfo lineInfo;
|
||||
|
||||
filename.GetText(true, out resolvedFilename, out lineInfo);
|
||||
outputString.AppendFormat(CultureInfo.InvariantCulture, "*** PARSER: Include file \"{0}\"\n", resolvedFilename);
|
||||
outputString.AppendLine();
|
||||
string currentFilename = lineInfo.GetStreamPositionForOffset(0).Filename;
|
||||
string currentFilePath = Path.Combine(Path.GetDirectoryName(currentFilename), resolvedFilename);
|
||||
stream = new StreamReader(File.Open(currentFilePath, FileMode.Open));
|
||||
newFilename = resolvedFilename;
|
||||
return BatchParserAction.Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser;
|
||||
|
||||
namespace Microsoft.SqlTools.ManagedBatchParser.UnitTests.BatchParser
|
||||
{
|
||||
internal sealed class TestVariableResolver : IVariableResolver
|
||||
{
|
||||
Dictionary<string, string> variables = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
private StringBuilder outputString;
|
||||
|
||||
public TestVariableResolver(StringBuilder outputString)
|
||||
{
|
||||
this.outputString = outputString;
|
||||
}
|
||||
|
||||
public string GetVariable(PositionStruct pos, string name)
|
||||
{
|
||||
if (variables.ContainsKey(name))
|
||||
{
|
||||
return variables[name];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVariable(PositionStruct pos, string name, string value)
|
||||
{
|
||||
outputString.AppendFormat("Setting variable {0} to [{1}]\n", name, value);
|
||||
if (value == null)
|
||||
{
|
||||
variables.Remove(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
variables[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode;
|
||||
using System.Data.SqlClient;
|
||||
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.TSQLExecutionEngine
|
||||
{
|
||||
internal class BatchEventHandler: IBatchEventsHandler
|
||||
{
|
||||
List<int> resultCounts = new List<int>();
|
||||
List<string> sqlMessages = new List<string>();
|
||||
List<string> errorMessage = new List<string>();
|
||||
int batchfinishedEventCounter = 0;
|
||||
SqlDataReader dr = null;
|
||||
bool cancelEventFired = false;
|
||||
|
||||
#region Public properties
|
||||
public List<int> ResultCounts
|
||||
{
|
||||
get
|
||||
{
|
||||
return resultCounts;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> SqlMessages
|
||||
{
|
||||
get
|
||||
{
|
||||
return sqlMessages;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> ErrorMessages
|
||||
{
|
||||
get
|
||||
{
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public int BatchfinishedEventCounter
|
||||
{
|
||||
get
|
||||
{
|
||||
return batchfinishedEventCounter;
|
||||
}
|
||||
}
|
||||
public bool CancelFired
|
||||
{
|
||||
get
|
||||
{
|
||||
return cancelEventFired;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IBatchEventHandlers Members
|
||||
public void OnBatchCancelling(object sender, EventArgs args)
|
||||
{
|
||||
Console.WriteLine("\tOnBatchCancelling:");
|
||||
cancelEventFired = true;
|
||||
}
|
||||
|
||||
public void OnBatchError(object sender, BatchErrorEventArgs args)
|
||||
{
|
||||
Console.WriteLine("\tOnBatchError:");
|
||||
Console.WriteLine("\t\tLine {0} has error: ", args.Line);
|
||||
Console.WriteLine("\t\tError description: " + args.Description);
|
||||
Console.WriteLine("\t\tError message: " + args.Message);
|
||||
Console.WriteLine("\t\tError Line: " + args.TextSpan.iStartLine);
|
||||
|
||||
errorMessage.Add(args.Description);
|
||||
}
|
||||
|
||||
public void OnBatchMessage(object sender, BatchMessageEventArgs args)
|
||||
{
|
||||
Console.WriteLine("\tOnBatchMessage ...");
|
||||
Console.WriteLine("\t\tMessage: " + args.Message);
|
||||
Console.WriteLine("\t\tDetail message:" + args.DetailedMessage);
|
||||
|
||||
if (args.DetailedMessage != "")
|
||||
{
|
||||
sqlMessages.Add(args.DetailedMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
SqlMessages.Add(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBatchResultSetFinished(object sender, EventArgs args)
|
||||
{
|
||||
Console.WriteLine("\tOnBatchResultSetFinished...");
|
||||
Console.WriteLine("\t\tBatch result set finished");
|
||||
batchfinishedEventCounter++;
|
||||
}
|
||||
|
||||
public void OnBatchResultSetProcessing(object sender, BatchResultSetEventArgs args)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
Console.WriteLine("\tOnBatchResultProcessing...");
|
||||
dr = args.DataReader as SqlDataReader;
|
||||
int count = 0;
|
||||
while (dr.Read() && !cancelEventFired)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
Console.WriteLine("\t\tOnBatchResultProcessing: Records returned: " + count);
|
||||
resultCounts.Add(count);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,898 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Threading;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection;
|
||||
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Test.Common;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.TSQLExecutionEngine
|
||||
{
|
||||
/// <summary>
|
||||
///This is a test class for Microsoft.Data.Tools.Schema.Common.ExecutionEngine.ExecutionEngine and is intended
|
||||
///to contain all Microsoft.Data.Tools.Schema.Common.ExecutionEngine.ExecutionEngine Unit Tests
|
||||
///</summary>
|
||||
|
||||
public class ExecutionEngineTest : IDisposable
|
||||
{
|
||||
private SqlConnection connection;
|
||||
private List<int> expResultCounts = new List<int>();
|
||||
private List<string> expErrorMessage = new List<string>();
|
||||
|
||||
#region Test Initialize And Cleanup
|
||||
|
||||
public ExecutionEngineTest()
|
||||
{
|
||||
TestInitialize();
|
||||
}
|
||||
|
||||
// Initialize the tests
|
||||
public void TestInitialize()
|
||||
{
|
||||
expResultCounts = new List<int>();
|
||||
expErrorMessage = new List<string>();
|
||||
connection = SetUpConnection("test");
|
||||
}
|
||||
|
||||
// helper method to set up a Sql Connection to a database
|
||||
private SqlConnection SetUpConnection(string name)
|
||||
{
|
||||
SqlTestDb testDb = SqlTestDb.CreateNew(TestServerType.OnPrem, false, name);
|
||||
ConnectionInfo connInfo = LiveConnectionHelper.InitLiveConnectionInfoForDefinition(testDb.DatabaseName);
|
||||
string connectionString = ConnectionService.BuildConnectionString(connInfo.ConnectionDetails);
|
||||
SqlConnection resultConnection = new SqlConnection(connectionString);
|
||||
resultConnection.Open();
|
||||
return resultConnection;
|
||||
}
|
||||
|
||||
// Helper method to close a connection completely
|
||||
private void CloseConnection(SqlConnection conn)
|
||||
{
|
||||
if (conn != null)
|
||||
{
|
||||
conn.Close();
|
||||
conn.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//Use Dispose to close connection after each test has run
|
||||
//
|
||||
public void Dispose()
|
||||
{
|
||||
//Task.Run(() => SqlTestDb.DropDatabase(connection.Database));
|
||||
CloseConnection(connection);
|
||||
connection = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Valid scripts
|
||||
/// <summary>
|
||||
///A test for a simple SQL script
|
||||
///</summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_SimpleTest()
|
||||
{
|
||||
string sqlStatement = "SELECT * FROM sysobjects";
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Success, executor.ExecutionResult);
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
Assert.Equal(1, executor.BatchFinshedEventCounter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test with a valid script using default execution condition
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_DefaultCondition_ValidScript()
|
||||
{
|
||||
string sqlStatement = "select * from sysobjects\nGo\n";
|
||||
|
||||
//Use default execution condition
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions, false);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Success, executor.ExecutionResult);
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Test with multiple valid scripts in multiple batches
|
||||
// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_MultiValidScripts()
|
||||
{
|
||||
string sqlStatement = "select * from sys.databases\ngo\nselect name from sys.databases\ngo\nprint 'test'\ngo";
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions, false);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Success, executor.ExecutionResult);
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test with SQL comment
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_TestComment()
|
||||
{
|
||||
string sqlStatement = "/*test comments*/";
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Success, executor.ExecutionResult);
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Invalid Scripts
|
||||
/// <summary>
|
||||
/// Test with a invalid query using the default execution condition
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_DefaultCondition_InvalidScript()
|
||||
{
|
||||
string sqlStatement = "select ** from sysobjects";
|
||||
//Use default execution condition
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions, false);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal( ScriptExecutionResult.Success | ScriptExecutionResult.Failure, executor.ExecutionResult);
|
||||
Assert.True(!executor.ParserExecutionError);
|
||||
Assert.True(CompareTwoStringLists(executor.ErrorMessageQueue, expErrorMessage));
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
Assert.Equal(0, executor.BatchFinshedEventCounter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test with an invalid query using a defined execution condition
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_InvalidScriptWithCondition()
|
||||
{
|
||||
string sqlStatement = "select * from authors";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(executor.ExecutionResult, ScriptExecutionResult.Success | ScriptExecutionResult.Failure);
|
||||
Assert.True(!executor.ParserExecutionError);
|
||||
Assert.True(CompareTwoStringLists(executor.ErrorMessageQueue, expErrorMessage));
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test with multiple invalid scripts in multiple batches
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_MultipleInvalidScript()
|
||||
{
|
||||
string sqlStatement = "select ** from products \ngo\n insert into products values (1,'abc')\n go \n";
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(executor.ExecutionResult, ScriptExecutionResult.Success | ScriptExecutionResult.Failure);
|
||||
Assert.True(!executor.ParserExecutionError);
|
||||
Assert.True(CompareTwoStringLists(executor.ErrorMessageQueue, expErrorMessage));
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test with invalid scripts within a single batch
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_MultipleInvalidScript_SingleBatch()
|
||||
{
|
||||
string sqlStatement = "select ** from products \n insert into products values (1,'abc')\n go \n";
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Success | ScriptExecutionResult.Failure, executor.ExecutionResult);
|
||||
Assert.True(!executor.ParserExecutionError);
|
||||
Assert.True(CompareTwoStringLists(executor.ErrorMessageQueue, expErrorMessage));
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test with mixed valid and invalid scripts
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_MixedValidandInvalidScript()
|
||||
{
|
||||
string sqlStatement = "SELECT * FROM Authors \n Go\n select * from sysobjects \n go\nif exists (select * from sysobjects where id = object_id('MyTab')) DROP TABLE MyTab2";
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(executor.ExecutionResult, ScriptExecutionResult.Success | ScriptExecutionResult.Failure);
|
||||
Assert.True(!executor.ParserExecutionError);
|
||||
Assert.True(CompareTwoStringLists(executor.ErrorMessageQueue, expErrorMessage));
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_DiscardConnection()
|
||||
{
|
||||
ExecutionEngine engine = new ExecutionEngine();
|
||||
Assert.True(ConnectionDiscardWrapper(engine));
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Different execution conditions
|
||||
/// <summary>
|
||||
/// Test HaltOnError execution condition
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_HaltOnError()
|
||||
{
|
||||
string sqlStatement = "select * from authors\n go\n select * from sysbojects \n go \n";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = true;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Halted | ScriptExecutionResult.Failure, executor.ExecutionResult);
|
||||
Assert.True(CompareTwoStringLists(executor.ErrorMessageQueue, expErrorMessage));
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
Assert.True(executor.ResultCountQueue.Count == 0);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HaltOnError with a single batch
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_HaltOnError_OneBatch()
|
||||
{
|
||||
string sqlStatement = "select * from authors\n go 30\n";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = true;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Halted | ScriptExecutionResult.Failure, executor.ExecutionResult);
|
||||
Assert.True(CompareTwoStringLists(executor.ErrorMessageQueue, expErrorMessage));
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
Assert.True(executor.ResultCountQueue.Count == 0);
|
||||
Assert.Equal(0, executor.BatchFinshedEventCounter);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test ParseOnly execution condition with valid scripts
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_ParseOnly_ValidScript()
|
||||
{
|
||||
string sqlStatement = "select * from sysobjects";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = true;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Success, executor.ExecutionResult);
|
||||
Assert.True(executor.ResultCountQueue.Count == 0);
|
||||
Assert.Equal(0, executor.BatchFinshedEventCounter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test HaltOnError execution condition with invalid scripts
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_ParseOnly_InvalidScript()
|
||||
{
|
||||
string sqlStatement = "select ** from authors";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = true;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Success | ScriptExecutionResult.Failure, executor.ExecutionResult);
|
||||
Assert.True(!executor.ParserExecutionError);
|
||||
Assert.True(executor.ResultCountQueue.Count == 0);
|
||||
Assert.True(CompareTwoStringLists(executor.ErrorMessageQueue, expErrorMessage));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse script only without transaction wrapper
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_ParseOnly_ValidScriptWithoutTransaction()
|
||||
{
|
||||
string sqlStatement = "select * from sysobjects";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = false;
|
||||
conditions.IsParseOnly = true;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Success, executor.ExecutionResult);
|
||||
Assert.True(executor.ResultCountQueue.Count == 0);
|
||||
Assert.Equal(0, executor.BatchFinshedEventCounter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test with execution timeout value
|
||||
/// </summary>
|
||||
//TEST_DOESNOTWORK[TestMethod()]
|
||||
public void ExecutionEngineTest_TimeOut()
|
||||
{
|
||||
string sqlStatement = "select * from sysobjects\n go 10\n";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions, -1);
|
||||
executor.Run();
|
||||
Assert.Equal(executor.ExecutionResult, ScriptExecutionResult.Success);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test with invalid connection
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_InvalidConnection()
|
||||
{
|
||||
string sqlStatement = "select * from sysobjects\n go 100\n";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
connection.Close();
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions);
|
||||
executor.Run();
|
||||
|
||||
// Note: this used to also return Halted at some point in the distant past.
|
||||
// However since that gets mapped to Failure anyhow, consider "Failure" as acceptable here
|
||||
Assert.True(executor.ExecutionResult.HasFlag(ScriptExecutionResult.Failure), "Expected failure when invalid connection is present" );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test with multiple conditions true
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void TestExecutionEngineConditions()
|
||||
{
|
||||
string sqlStatement = "select * from sys.databases\ngo\nselect name from sys.databases\ngo\nprint 'test'\ngo";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsNoExec = true;
|
||||
conditions.IsStatisticsIO = true;
|
||||
conditions.IsStatisticsTime = true;
|
||||
conditions.IsEstimatedShowPlan = true;
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions, false);
|
||||
executor.Run();
|
||||
|
||||
//Get the expected values
|
||||
List<string> batchScripts = executor.BatchScripts;
|
||||
ExecuteSqlBatch(batchScripts, connection);
|
||||
|
||||
Assert.Equal(ScriptExecutionResult.Success, executor.ExecutionResult);
|
||||
Assert.True(CompareTwoIntLists(executor.ResultCountQueue, expResultCounts));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SQL Commands
|
||||
/// <summary>
|
||||
/// Test with SQL commands
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_SQLCmds()
|
||||
{
|
||||
string[] sqlStatements = {
|
||||
"select $(INVALIDVAR) from sysobjects",
|
||||
":help",
|
||||
"exit",
|
||||
"quit",
|
||||
"!! dir",
|
||||
"ed",
|
||||
"reset",
|
||||
":list",
|
||||
":listvar",
|
||||
":serverlist",
|
||||
":on error ignore",
|
||||
":connect hypothermia -t 300 -U foo -P bar",
|
||||
":out $(SystemDrive)\\test.txt",
|
||||
":r $(SystemDrive)\\test.txt",
|
||||
":error STDOUT",
|
||||
":perftrace STDOUT",
|
||||
"exit (Select count(*) from sysobjects)"
|
||||
};
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
|
||||
foreach (string stmt in sqlStatements)
|
||||
{
|
||||
TestExecutor executor = new TestExecutor(stmt, connection, conditions);
|
||||
executor.Run();
|
||||
Assert.True(executor.ResultCountQueue.Count == 0);
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Threading
|
||||
/// <summary>
|
||||
/// Test synchronous cancel
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_SyncCancel()
|
||||
{
|
||||
string sqlStatement = "waitfor delay '0:0:10'";
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions, true);
|
||||
executor.CancelTimeOut = 3000;
|
||||
executor.Run();
|
||||
|
||||
Assert.NotNull(executor.ScriptExecuteThread);
|
||||
Assert.Equal(ScriptExecutionResult.Cancel, executor.ExecutionResult);
|
||||
Assert.True(executor.CancelEventFired);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test asynchronous cancel
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_ASyncCancel()
|
||||
{
|
||||
//string sqlStatement = "--This is a test\nSELECT * FROM sysobjects as t\nGO 50\n use pubsplus \n select * from titles\n go" ;
|
||||
|
||||
string sqlStatement = "waitfor delay '0:0:10'";
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions, true);
|
||||
executor.SyncCancel = false;
|
||||
executor.Run();
|
||||
|
||||
Assert.True(executor.CancelEventFired);
|
||||
Assert.NotNull(executor.ScriptExecuteThread);
|
||||
if (executor.ScriptExecuteThread != null)
|
||||
Assert.True(!executor.ScriptExecuteThread.IsAlive);
|
||||
Assert.Equal(ScriptExecutionResult.Cancel, executor.ExecutionResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test sync cancel when the execution is done
|
||||
/// </summary>
|
||||
///
|
||||
/// Disabled test, has race condition where Sql statement will finish
|
||||
/// before harness has an opportunity to cancel.
|
||||
//TEST_DOESNOTWORK[TestMethod()]
|
||||
public void ExecutionEngineTest_SyncCancelAfterExecutionDone()
|
||||
{
|
||||
string sqlStatement = "select 1" ;
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions, true);
|
||||
executor.Run();
|
||||
|
||||
Assert.True(!executor.CancelEventFired);
|
||||
Assert.NotNull(executor.ScriptExecuteThread);
|
||||
if (executor.ScriptExecuteThread != null)
|
||||
Assert.True(!executor.ScriptExecuteThread.IsAlive);
|
||||
Assert.Equal(ScriptExecutionResult.Success | ScriptExecutionResult.Cancel, executor.ExecutionResult);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test async cancel when the execution is done
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ExecutionEngineTest_ASyncCancelAfterExecutionDone()
|
||||
{
|
||||
string sqlStatement ="select 1";
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
TestExecutor executor = new TestExecutor(sqlStatement, connection, conditions, true);
|
||||
executor.SyncCancel = false;
|
||||
executor.Run();
|
||||
|
||||
Assert.True(!executor.CancelEventFired);
|
||||
Assert.NotNull(executor.ScriptExecuteThread);
|
||||
if (executor.ScriptExecuteThread != null)
|
||||
Assert.True(!executor.ScriptExecuteThread.IsAlive);
|
||||
Assert.Equal(ScriptExecutionResult.Success | ScriptExecutionResult.Cancel, executor.ExecutionResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test multiple threads of execution engine with cancel operation
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ExecutionEngineTest_MultiThreading_WithCancel()
|
||||
{
|
||||
string[] sqlStatement = { "waitfor delay '0:0:10'",
|
||||
"waitfor delay '0:0:10'",
|
||||
"waitfor delay '0:0:10'"
|
||||
};
|
||||
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
conditions.IsTransactionWrapped = true;
|
||||
conditions.IsParseOnly = false;
|
||||
conditions.IsHaltOnError = false;
|
||||
|
||||
SqlConnection connection2 = SetUpConnection("test4");
|
||||
SqlConnection connection3 = SetUpConnection("test5");
|
||||
|
||||
TestExecutor executor1 = new TestExecutor(sqlStatement[0], connection, conditions, true);
|
||||
executor1.CancelTimeOut = 2000;
|
||||
TestExecutor executor2 = new TestExecutor(sqlStatement[1], connection2, conditions, true);
|
||||
executor1.CancelTimeOut = 2500;
|
||||
TestExecutor executor3 = new TestExecutor(sqlStatement[2], connection3, conditions, true);
|
||||
executor1.CancelTimeOut = 3000;
|
||||
|
||||
Thread t1 = new Thread(new ThreadStart(executor1.Run));
|
||||
Thread t2 = new Thread(new ThreadStart(executor2.Run));
|
||||
Thread t3 = new Thread(new ThreadStart(executor3.Run));
|
||||
|
||||
t1.Name = "Executor1";
|
||||
t1.Start();
|
||||
t2.Name = "Executor2";
|
||||
t2.Start();
|
||||
t3.Name = "Executor3";
|
||||
t3.Start();
|
||||
|
||||
while ((t1.ThreadState != ThreadState.Stopped) &&
|
||||
(t2.ThreadState != ThreadState.Stopped) &&
|
||||
(t3.ThreadState != ThreadState.Stopped))
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
Assert.True(!executor1.ScriptExecuteThread.IsAlive);
|
||||
Assert.True(!executor2.ScriptExecuteThread.IsAlive);
|
||||
Assert.True(!executor3.ScriptExecuteThread.IsAlive);
|
||||
|
||||
Assert.True(executor1.CancelEventFired);
|
||||
Assert.True(executor2.CancelEventFired);
|
||||
Assert.True(executor3.CancelEventFired);
|
||||
|
||||
CloseConnection(connection2);
|
||||
CloseConnection(connection3);
|
||||
await SqlTestDb.DropDatabase(connection2.Database);
|
||||
await SqlTestDb.DropDatabase(connection3.Database);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get/Set Methods
|
||||
|
||||
[Fact]
|
||||
public void TestShowStatements()
|
||||
{
|
||||
Assert.NotNull(ExecutionEngineConditions.ShowPlanXmlStatement(true));
|
||||
Assert.NotNull(ExecutionEngineConditions.ShowPlanAllStatement(true));
|
||||
Assert.NotNull(ExecutionEngineConditions.ShowPlanTextStatement(true));
|
||||
Assert.NotNull(ExecutionEngineConditions.StatisticsXmlStatement(true));
|
||||
Assert.NotNull(ExecutionEngineConditions.StatisticsProfileStatement(true));
|
||||
Assert.NotNull(ExecutionEngineConditions.ParseOnlyStatement(true));
|
||||
Assert.NotNull(ExecutionEngineConditions.NoExecStatement(true));
|
||||
Assert.NotNull(ExecutionEngineConditions.StatisticsIOStatement(true));
|
||||
Assert.NotNull(ExecutionEngineConditions.StatisticsTimeStatement(true));
|
||||
Assert.NotNull(ExecutionEngineConditions.ResetStatement);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestExecutionEngineConditionsSetMethods()
|
||||
{
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
bool getValue = conditions.IsScriptExecutionTracked;
|
||||
conditions.IsScriptExecutionTracked = !getValue;
|
||||
Assert.Equal(conditions.IsScriptExecutionTracked, !getValue);
|
||||
|
||||
getValue = conditions.IsEstimatedShowPlan;
|
||||
conditions.IsEstimatedShowPlan = !getValue;
|
||||
Assert.Equal(conditions.IsEstimatedShowPlan, !getValue);
|
||||
|
||||
getValue = conditions.IsActualShowPlan;
|
||||
conditions.IsActualShowPlan = !getValue;
|
||||
Assert.Equal(conditions.IsActualShowPlan, !getValue);
|
||||
|
||||
getValue = conditions.IsSuppressProviderMessageHeaders;
|
||||
conditions.IsSuppressProviderMessageHeaders = !getValue;
|
||||
Assert.Equal(conditions.IsSuppressProviderMessageHeaders, !getValue);
|
||||
|
||||
getValue = conditions.IsNoExec;
|
||||
conditions.IsNoExec = !getValue;
|
||||
Assert.Equal(conditions.IsNoExec, !getValue);
|
||||
|
||||
getValue = conditions.IsStatisticsIO;
|
||||
conditions.IsStatisticsIO = !getValue;
|
||||
Assert.Equal(conditions.IsStatisticsIO, !getValue);
|
||||
|
||||
getValue = conditions.IsShowPlanText;
|
||||
conditions.IsShowPlanText = !getValue;
|
||||
Assert.Equal(conditions.IsShowPlanText, !getValue);
|
||||
|
||||
getValue = conditions.IsStatisticsTime;
|
||||
conditions.IsStatisticsTime = !getValue;
|
||||
Assert.Equal(conditions.IsStatisticsTime, !getValue);
|
||||
|
||||
getValue = conditions.IsSqlCmd;
|
||||
conditions.IsSqlCmd = !getValue;
|
||||
Assert.Equal(conditions.IsSqlCmd, !getValue);
|
||||
|
||||
conditions.BatchSeparator = "GO";
|
||||
Assert.Equal(conditions.BatchSeparator, "GO");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private methods
|
||||
/// <summary>
|
||||
/// Connection to a database
|
||||
/// </summary>
|
||||
/// <param name="server">Server name</param>
|
||||
/// <param name="database">DB name</param>
|
||||
/// <returns></returns>
|
||||
private SqlConnection ConnectToDB(string server, string database)
|
||||
{
|
||||
return new SqlConnection(string.Format("Data Source={0};Initial Catalog={1};Integrated Security=True;", server, database));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execution a script batch
|
||||
/// </summary>
|
||||
/// <param name="sqlBatch">A list of SQL queries</param>
|
||||
/// <param name="connection">SQL connection</param>
|
||||
private void ExecuteSqlBatch(List<string> sqlBatch, SqlConnection connection)
|
||||
{
|
||||
foreach (string script in sqlBatch)
|
||||
{
|
||||
ExecuteSqlCommand(script, connection);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execution one sql command
|
||||
/// </summary>
|
||||
/// <param name="sqlCmdTxt">SQL query</param>
|
||||
/// <param name="connection">SQL connection</param>
|
||||
private void ExecuteSqlCommand(string sqlCmdTxt, SqlConnection connection)
|
||||
{
|
||||
SqlCommand cmd = new SqlCommand(sqlCmdTxt, connection);
|
||||
SqlTransaction transaction = connection.BeginTransaction();
|
||||
cmd.Transaction = transaction;
|
||||
|
||||
try
|
||||
{
|
||||
using (SqlDataReader dr = cmd.ExecuteReader())
|
||||
{
|
||||
int count = 0;
|
||||
while (dr.Read())
|
||||
{
|
||||
count++;
|
||||
}
|
||||
if (count > 0)
|
||||
{
|
||||
expResultCounts.Add(count);
|
||||
}
|
||||
}
|
||||
transaction.Commit();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Executing command throws exception: " + e.Message);
|
||||
expErrorMessage.Add(e.Message);
|
||||
try
|
||||
{
|
||||
transaction.Rollback();
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
Console.WriteLine("Rollback throws exception");
|
||||
Console.WriteLine("Message: " + e2.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare two string lists
|
||||
/// </summary>
|
||||
/// <param name="l1">first list</param>
|
||||
/// <param name="l2">second list</param>
|
||||
/// <returns>True if the contents are same, otherwise false</returns>
|
||||
private bool CompareTwoStringLists(List<string> l1, List<string> l2)
|
||||
{
|
||||
bool isSame = true;
|
||||
if(l1.Count != l2.Count)
|
||||
{
|
||||
isSame = false;
|
||||
Console.WriteLine("The count of elements in two lists are not the same");
|
||||
return isSame;
|
||||
}
|
||||
|
||||
for (int i = 0; i < l1.Count; i++)
|
||||
{
|
||||
if (l1[i] != l2[i])
|
||||
{
|
||||
isSame = false;
|
||||
Console.WriteLine("l1: {0}, l2: {1}", l1[i], l2[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return isSame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare with integer list
|
||||
/// </summary>
|
||||
/// <param name="l1">first list</param>
|
||||
/// <param name="l2">second list</param>
|
||||
/// <returns>True if the two list's contents are same, otherwise false</returns>
|
||||
private bool CompareTwoIntLists(List<int> l1, List<int> l2)
|
||||
{
|
||||
bool isSame = true;
|
||||
if (l1.Count != l2.Count)
|
||||
{
|
||||
isSame = false;
|
||||
Console.WriteLine("The count of elements in two lists are not the same");
|
||||
return isSame;
|
||||
}
|
||||
|
||||
for (int i = 0; i < l1.Count; i++)
|
||||
{
|
||||
if (l1[i] != l2[i])
|
||||
{
|
||||
isSame = false;
|
||||
Console.WriteLine("l1: {0}, l2: {1}", l1[i], l2[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return isSame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper to test the Close method in ExecutionEngine
|
||||
/// </summary>
|
||||
/// <param name="engine"></param>
|
||||
/// <returns></returns>
|
||||
private bool ConnectionDiscardWrapper(ExecutionEngine engine)
|
||||
{
|
||||
if (engine == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
engine.Close(false, true, true);
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Threading;
|
||||
using Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.TSQLExecutionEngine
|
||||
{
|
||||
class TestExecutor : IDisposable
|
||||
{
|
||||
#region Private variables
|
||||
string sqlStatement;
|
||||
ExecutionEngineConditions conditions = new ExecutionEngineConditions();
|
||||
BatchEventHandler eventHandler = new BatchEventHandler();
|
||||
SqlConnection connection = null;
|
||||
static Thread _executionThread;
|
||||
bool _syncCancel = true;
|
||||
bool _isFinished = false;
|
||||
bool _cancel = false;
|
||||
int _cancelTimeout = 500;
|
||||
int exeTimeOut = 0;
|
||||
|
||||
//For verification
|
||||
List<int> resultCounts = new List<int>();
|
||||
List<string> sqlMessages = new List<string>();
|
||||
List<string> errorMessage = new List<string>();
|
||||
List<bool> batchFinished = new List<bool>();
|
||||
static ScriptExecutionResult execResult = ScriptExecutionResult.All;
|
||||
static List<string> batchScripts = new List<string>();
|
||||
static Thread exeThread = null;
|
||||
static bool parserExecutionError = false;
|
||||
#endregion
|
||||
|
||||
#region private methods
|
||||
/// <summary>
|
||||
/// Execut the script
|
||||
/// </summary>
|
||||
/// <param name="exec">Execution Engine</param>
|
||||
/// <param name="connection">SQL connection</param>
|
||||
/// <param name="script">script text</param>
|
||||
/// <param name="conditions">Execution condition</param>
|
||||
/// <param name="batchHandler">Batch event handler</param>
|
||||
/// <param name="timeout">time out value</param>
|
||||
static void ExecuteScript(ExecutionEngine exec, SqlConnection connection, string script, ExecutionEngineConditions conditions, IBatchEventsHandler batchHandler, int timeout)
|
||||
{
|
||||
Validate.IsNotNull(nameof(exec), exec);
|
||||
Validate.IsNotNull(nameof(connection), connection);
|
||||
Validate.IsNotNullOrEmptyString(nameof(script), script);
|
||||
Validate.IsNotNull(nameof(conditions), conditions);
|
||||
|
||||
Console.WriteLine("------------------------ Executing Script ----------------------");
|
||||
|
||||
//exec.BeginScriptExecution(script, connection, timeout, conditions, batchConsumer);
|
||||
ScriptExecutionArgs args = new ScriptExecutionArgs(script, connection, timeout, conditions, batchHandler);
|
||||
//exec.ExecuteScript(args);
|
||||
|
||||
_executionThread = new Thread(new ParameterizedThreadStart(exec.ExecuteScript));
|
||||
_executionThread.Start(args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancel the execution
|
||||
/// </summary>
|
||||
/// <param name="exec">Execution Engine</param>
|
||||
/// <param name="isSynchronous">Cancel the execution synchronously or not</param>
|
||||
/// <param name="timeout">sycn canceo timeout</param>
|
||||
static void Cancel(ExecutionEngine exec, bool isSynchronous, int millisecondsTimeOut)
|
||||
{
|
||||
//exec.BeginCancellingExecution(isSynchronous, timeout);
|
||||
|
||||
if (_executionThread == null ||
|
||||
_executionThread.ThreadState == System.Threading.ThreadState.Unstarted ||
|
||||
_executionThread.ThreadState == System.Threading.ThreadState.Stopped)
|
||||
{
|
||||
exec.Close(isSynchronous, /* isDiscard */ false, /* isFinishExecution */ true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// activates the cancel thread
|
||||
Thread cancelThread = new Thread(new ThreadStart(exec.CancelCurrentBatch));
|
||||
cancelThread.Name = "Cancelling thread";
|
||||
cancelThread.Start();
|
||||
|
||||
// in a syncrhonous call, we need to block and wait until the thread is stopped
|
||||
if (isSynchronous)
|
||||
{
|
||||
int totalSleep = 0;
|
||||
while (totalSleep < millisecondsTimeOut && _executionThread != null && _executionThread.IsAlive)
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
totalSleep += 50;
|
||||
}
|
||||
|
||||
if (_executionThread != null && _executionThread.IsAlive)
|
||||
{
|
||||
exec.Close(isSynchronous, /* isDiscard */ true);
|
||||
}
|
||||
else
|
||||
{
|
||||
exec.Close(/* isCloseConnection */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Thread.Sleep(5000);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public properties
|
||||
public bool SyncCancel
|
||||
{
|
||||
get
|
||||
{
|
||||
return _syncCancel;
|
||||
}
|
||||
set
|
||||
{
|
||||
_syncCancel = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int CancelTimeOut
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cancelTimeout;
|
||||
}
|
||||
set
|
||||
{
|
||||
_cancelTimeout = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptExecutionResult ExecutionResult
|
||||
{
|
||||
get
|
||||
{
|
||||
return execResult;
|
||||
}
|
||||
}
|
||||
|
||||
public List<int> ResultCountQueue
|
||||
{
|
||||
get
|
||||
{
|
||||
return resultCounts;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> SQLMessageQueue
|
||||
{
|
||||
get
|
||||
{
|
||||
return sqlMessages;
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> ErrorMessageQueue
|
||||
{
|
||||
get
|
||||
{
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> BatchScripts
|
||||
{
|
||||
get
|
||||
{
|
||||
return batchScripts;
|
||||
}
|
||||
}
|
||||
|
||||
public int BatchFinshedEventCounter
|
||||
{
|
||||
get
|
||||
{
|
||||
return eventHandler.BatchfinishedEventCounter;
|
||||
}
|
||||
}
|
||||
|
||||
public Thread ScriptExecuteThread
|
||||
{
|
||||
get
|
||||
{
|
||||
return exeThread;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CancelEventFired
|
||||
{
|
||||
get
|
||||
{
|
||||
return eventHandler.CancelFired;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ParserExecutionError
|
||||
{
|
||||
get
|
||||
{
|
||||
return parserExecutionError;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public TestExecutor(string batch, SqlConnection conn, ExecutionEngineConditions exeCondition): this(batch, conn, exeCondition, false)
|
||||
{
|
||||
}
|
||||
|
||||
public TestExecutor(string batch, SqlConnection conn, ExecutionEngineConditions exeCondition, bool cancelExecution)
|
||||
{
|
||||
sqlStatement = batch;
|
||||
conditions.IsHaltOnError = exeCondition.IsHaltOnError;
|
||||
conditions.IsParseOnly = exeCondition.IsParseOnly;
|
||||
conditions.IsTransactionWrapped = exeCondition.IsTransactionWrapped;
|
||||
conditions.IsNoExec = exeCondition.IsNoExec;
|
||||
conditions.IsStatisticsIO = exeCondition.IsStatisticsIO;
|
||||
conditions.IsStatisticsTime = exeCondition.IsStatisticsTime;
|
||||
|
||||
_cancel = cancelExecution;
|
||||
connection = conn;
|
||||
|
||||
//Initialize the static variables
|
||||
execResult = ScriptExecutionResult.All;
|
||||
batchScripts = new List<string>();
|
||||
exeThread = null;
|
||||
parserExecutionError = false;
|
||||
|
||||
}
|
||||
public TestExecutor(string batch, SqlConnection conn, ExecutionEngineConditions exeCondition, int timeOut)
|
||||
: this(batch, conn, exeCondition, false)
|
||||
{
|
||||
exeTimeOut = timeOut;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region public methods
|
||||
/// <summary>
|
||||
/// Execute the test engine
|
||||
/// </summary>
|
||||
public void Run()
|
||||
{
|
||||
Console.WriteLine("Executing scripts {0} ...", sqlStatement);
|
||||
|
||||
using (ExecutionEngine exec = new ExecutionEngine())
|
||||
{
|
||||
_isFinished = false;
|
||||
exec.BatchParserExecutionStart += new EventHandler<BatchParserExecutionStartEventArgs>(OnBatchParserExecutionStart);
|
||||
exec.BatchParserExecutionFinished += new EventHandler<BatchParserExecutionFinishedEventArgs>(OnBatchParserExecutionFinished);
|
||||
exec.BatchParserExecutionError += new EventHandler<BatchParserExecutionErrorEventArgs>(OnBatchParserExecutionError);
|
||||
exec.ScriptExecutionFinished += new EventHandler<ScriptExecutionFinishedEventArgs>(OnExecutionFinished);
|
||||
|
||||
ExecuteScript(exec, connection, sqlStatement, conditions, eventHandler, exeTimeOut);
|
||||
|
||||
if (!_cancel)
|
||||
{
|
||||
//Do not cancel the execution engine
|
||||
while (!_isFinished)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_isFinished)
|
||||
{
|
||||
Console.WriteLine("Need to cancel while the batch execution is not finished!");
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Canceling after the exe engine is disposed...");
|
||||
}
|
||||
Cancel(exec, _syncCancel, _cancelTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ParserEvent
|
||||
/// <summary>
|
||||
/// Called when batch is called
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
static void OnBatchParserExecutionStart(object sender, BatchParserExecutionStartEventArgs e)
|
||||
{
|
||||
Console.WriteLine("****************");
|
||||
Console.WriteLine(e.Batch.Text);
|
||||
batchScripts.Add(e.Batch.Text);
|
||||
Console.WriteLine("****************");
|
||||
|
||||
Console.WriteLine("ON_BATCH_PARSER_EXECUTION_START : Start executing batch... " + e.Batch + " at line " + e.TextSpan.iStartLine);
|
||||
exeThread = Thread.CurrentThread;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when batch is done
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
static void OnBatchParserExecutionFinished(object sender, BatchParserExecutionFinishedEventArgs e)
|
||||
{
|
||||
Console.WriteLine("ON_BATCH_PARSER_EXECUTION_FINISHED : Done executing batch \n\t{0}\n\t with result... {1} ", e.Batch.Text, e.ExecutionResult);
|
||||
if (execResult == ScriptExecutionResult.All)
|
||||
execResult = e.ExecutionResult;
|
||||
else
|
||||
execResult = execResult | e.ExecutionResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when batch pasing found a warning/error
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
static void OnBatchParserExecutionError(object sender, BatchParserExecutionErrorEventArgs e)
|
||||
{
|
||||
Console.WriteLine("ON_BATCH_PARSER_EXECUTION_ERROR : {0} found... at line {1}: {2}", e.MessageType.ToString(), e.Line.ToString(), e.Message);
|
||||
Console.WriteLine("\t Error Description: " + e.Description);
|
||||
parserExecutionError = true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when script is done
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void OnExecutionFinished(object sender, ScriptExecutionFinishedEventArgs e)
|
||||
{
|
||||
Console.WriteLine("ON_EXECUTION_FINISHED : Script execution done with result ..." + e.ExecutionResult);
|
||||
_isFinished = true;
|
||||
|
||||
if (execResult == ScriptExecutionResult.All)
|
||||
execResult = e.ExecutionResult;
|
||||
else
|
||||
execResult = execResult|e.ExecutionResult;
|
||||
|
||||
resultCounts = eventHandler.ResultCounts;
|
||||
sqlMessages = eventHandler.SqlMessages;
|
||||
errorMessage = eventHandler.ErrorMessages;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user