Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions src/SQLCover/SQLCoverLib/CodeCoverage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,17 @@ public CodeCoverage(string connectionString, string databaseName, string[] exclu
_source = new DatabaseSourceGateway(_database);
}

public bool Start(int timeOut = 30)
public bool Start(string sessionName = null, int timeOut = 30)
{
Exception = null;
try
{
_database.TimeOut = timeOut;
_trace = new TraceControllerBuilder().GetTraceController(_database, _databaseName, _traceType);
_trace.Start();
if (string.IsNullOrWhiteSpace(sessionName))
_trace = new TraceControllerBuilder().GetTraceController(_database, _databaseName, _traceType);
else
_trace = new TraceControllerBuilder().GetTraceController(_database, _databaseName, _traceType, sessionName);
_trace.Start(); // results in running ComposeLogFileName(), script CreateTrace, script StartTraceFormat
IsStarted = true;
return true;
}
Expand All @@ -90,10 +93,20 @@ private List<string> StopInternal()
return events;
}

public CoverageResult Stop()
public CoverageResult Stop(string sessionName = null)
{
if(!IsStarted)
throw new SqlCoverException("SQL Cover was not started, or did not start correctly.");
if (string.IsNullOrWhiteSpace(sessionName))
{
if (!IsStarted)
throw new SqlCoverException("SQL Cover was not started, or did not start correctly.");
}
else
{
// we're in the OnlyStopAndReport mode --> create SqlTraceController with THE SAME session name as was used in the OnlyStart mode:
_database.TimeOut = 30;
_trace = new TraceControllerBuilder().GetTraceController(_database, _databaseName, _traceType, sessionName);
_trace.ComposeLogFileName();
}

IsStarted = false;

Expand Down
4 changes: 4 additions & 0 deletions src/SQLCover/SQLCoverLib/Trace/AzureTraceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public AzureTraceController(DatabaseGateway gateway, string databaseName) : base
{
}

public override void ComposeLogFileName()
{

}

private void Create()
{
Expand Down
11 changes: 10 additions & 1 deletion src/SQLCover/SQLCoverLib/Trace/SqlTraceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ public SqlTraceController(DatabaseGateway gateway, string databaseName) : base(g

}

protected virtual void Create()
public SqlTraceController(DatabaseGateway gateway, string databaseName, string name) : base(gateway, databaseName, name)
{

}

public override void ComposeLogFileName()
{
var logDir = Gateway.GetRecords(GetLogDir).Rows[0].ItemArray[2].ToString();
if (string.IsNullOrEmpty(logDir))
Expand All @@ -45,7 +50,11 @@ protected virtual void Create()

logDir = logDir.ToUpper().Replace("Logging SQL Server messages in file '".ToUpper(), "").Replace("'", "").Replace("ERRORLOG.", "").Replace("ERROR.LOG", "");
FileName = Path.Combine(logDir, Name);
}

protected virtual void Create()
{
ComposeLogFileName();
RunScript(CreateTrace, "Error creating the extended events trace, error: {0}");
}

Expand Down
8 changes: 8 additions & 0 deletions src/SQLCover/SQLCoverLib/Trace/TraceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ public TraceController(DatabaseGateway gateway, string databaseName)
Name = string.Format("SQLCover-Trace-{0}", Guid.NewGuid().ToString().Replace("{", "").Replace("}", "").Replace("-", ""));
}

public TraceController(DatabaseGateway gateway, string databaseName, string name)
{
Gateway = gateway;
DatabaseId = gateway.GetString(string.Format("select db_id('{0}')", databaseName));
Name = string.Format("SQLCover-Trace-{0}", name);
}

public abstract void ComposeLogFileName();
public abstract void Start();
public abstract void Stop();
public abstract List<string> ReadTrace();
Expand Down
12 changes: 8 additions & 4 deletions src/SQLCover/SQLCoverLib/Trace/TraceControllerBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace SQLCover.Trace
{
class TraceControllerBuilder
{
public TraceController GetTraceController(DatabaseGateway gateway, string databaseName, TraceControllerType type)
public TraceController GetTraceController(DatabaseGateway gateway, string databaseName, TraceControllerType type, string sessionName = null)
{


Expand All @@ -16,7 +16,9 @@ public TraceController GetTraceController(DatabaseGateway gateway, string databa
case TraceControllerType.Azure:
return new AzureTraceController(gateway, databaseName);
case TraceControllerType.Sql:
return new SqlTraceController(gateway, databaseName);
return string.IsNullOrWhiteSpace(sessionName)
? new SqlTraceController(gateway, databaseName)
: new SqlTraceController(gateway, databaseName, sessionName);
case TraceControllerType.SqlLocalDb:
return new SqlLocalDbTraceController(gateway, databaseName);
}
Expand All @@ -32,8 +34,10 @@ public TraceController GetTraceController(DatabaseGateway gateway, string databa
var isAzure = source.IsAzure();

if(!isAzure)
return new SqlTraceController(gateway, databaseName);

return string.IsNullOrWhiteSpace(sessionName)
? new SqlTraceController(gateway, databaseName)
: new SqlTraceController(gateway, databaseName, sessionName);

var version = source.GetVersion();
if(version < SqlServerVersion.Sql120)
throw new Exception("SQL Azure is only supported from Version 12");
Expand Down
65 changes: 59 additions & 6 deletions src/SQLCover/SqlCoverCore/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public class Options
[Option('v', "verbose", Required = false, HelpText = "Set output to verbose messages.")]
public bool Verbose { get; set; }

[Option('c', "command", Required = true, HelpText = "Choose command to run from:Get-CoverTSql, Get-CoverExe, Get-CoverRedgateCITest.")]
[Option('c', "command", Required = true, HelpText = "Choose command to run from: Get-CoverTSql, Get-CoverExe, Get-CoverRedgateCITest.")]
public string Command { get; set; }
[Option('e', "exportCommand", Required = true, HelpText = "Choose command to run from:Export-OpenXml, Start-ReportGenerator, Export-Html.")]
[Option('e', "exportCommand", Required = true, HelpText = "Choose command to run from: Export-OpenXml, Start-ReportGenerator, Export-Html.")]
public string ExportCommand { get; set; }
[Option('b', "debug", Required = false, HelpText = "Prints out more output.")]
public bool Debug { get; set; }
Expand All @@ -33,6 +33,11 @@ public class Options
public string Args { get; set; }
[Option('t', "exeName", Required = false, HelpText = "executable name")]
public string ExeName { get; set; }

[Option('m', "mode", Required = false, HelpText = "Choose operation mode to run from: Normal (default), OnlyStart, OnlyStop (applicable only when command = GetCoverTSql)")]
public string Mode { get; set; }
[Option('s', "sessionName", Required = false, HelpText = "Specify unique event session name (required when mode = OnlyStart|OnlyStop)")]
public string SessionName { get; set; }
}
private enum CommandType
{
Expand All @@ -44,6 +49,12 @@ private enum CommandType
ExportHtml,
Unknown
}
public enum Mode // is considered only when command = GetCoverTSql
{
Normal, // normal work mode (tests are launched right from this executable; option --query is mandatory)
OnlyStart, // this executable only starts session; requires option --sessionName to be specified, and option --query is meaningless
OnlyStopAndReport // this executable only stops session and generates report; requires option --sessionName to be specified, and option --query is meaningless
}
/// <summary>
/// should minic arguments from example\SQLCover.ps1
/// run by `dotnet run -- -c Get-CoverTSql -r`
Expand All @@ -68,8 +79,28 @@ static void Main(string[] args)
}
var cType = CommandType.Unknown;
var eType = CommandType.Unknown;
var mType = Mode.Normal;
string[] requiredParameters = null;
string[] requiredExportParameters = null;

switch (o.Mode)
{
case "OnlyStart":
mType = Mode.OnlyStart;
requiredParameters = new string[]{
"sessionName"};
break;
case "OnlyStopAndReport":
mType = Mode.OnlyStopAndReport;
requiredParameters = new string[]{
"sessionName"};
break;
default:
mType = Mode.Normal;
Console.WriteLine("Option '--mode' not supplied or invalid, assuming 'Normal' mode");
break;
}

switch (o.Command)
{
case "Get-CoverTSql":
Expand Down Expand Up @@ -119,7 +150,7 @@ static void Main(string[] args)
break;
}

var validParams = eType != CommandType.Unknown && cType != CommandType.Unknown ? validateRequired(o, requiredParameters) : false;
var validParams = eType != CommandType.Unknown && cType != CommandType.Unknown ? validateRequired(o, requiredParameters, mType) : false;
validParams = validParams ? validateRequired(o, requiredExportParameters) : validParams;

if (validParams)
Expand All @@ -139,7 +170,21 @@ static void Main(string[] args)
{
case CommandType.GetCoverTSql:
coverage = new CodeCoverage(o.ConnectionString, o.databaseName, null, true, o.Debug);
results = coverage.Cover(o.Query);
switch (mType)
{
case Mode.Normal:
results = coverage.Cover(o.Query);
break;
case Mode.OnlyStart:
Console.WriteLine("Starting event session '" + o.SessionName + "'...");
coverage.Start(o.SessionName);
Console.WriteLine("Event session '" + o.SessionName + "' started. Exiting.");
return; // only start event session and exit immediately
case Mode.OnlyStopAndReport:
Console.WriteLine("Stopping event session '" + o.SessionName + "'...");
results = coverage.Stop(o.SessionName); // stop event session and then generate report (as we do for Mode.Normal)
break;
}
break;
case CommandType.GetCoverExe:
coverage = new CodeCoverage(o.ConnectionString, o.databaseName, null, true, o.Debug);
Expand Down Expand Up @@ -198,7 +243,7 @@ static void Main(string[] args)
});
}

private static bool validateRequired(Options o, string[] requiredParameters, bool export = false)
private static bool validateRequired(Options o, string[] requiredParameters, Mode mode = Mode.Normal, bool export = false)
{
var valid = true;
var requiredString = export ? " is required for this exportCommand" : " is required for this command";
Expand All @@ -221,7 +266,7 @@ private static bool validateRequired(Options o, string[] requiredParameters, boo
}
break;
case "query":
if (string.IsNullOrWhiteSpace(o.Query))
if (string.IsNullOrWhiteSpace(o.Query) && mode == Mode.Normal)
{
Console.WriteLine("query" + requiredString);
valid = false;
Expand Down Expand Up @@ -258,6 +303,14 @@ private static bool validateRequired(Options o, string[] requiredParameters, boo
}
break;

case "sessionName":
if (string.IsNullOrWhiteSpace(o.SessionName))
{
Console.WriteLine("sessionName" + requiredString);
valid = false;
}
break;

default:
Console.WriteLine("Required check on:" + param + " ignored");
// will always be invalid for commands not validated on a required param
Expand Down