Files
sqltoolsservice/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ServiceHost/LoggerTests.cs
David Shiflet 839acf67cd Convert most tools service tests to nunit (#1037)
* Remove xunit dependency from testdriver

* swap expected/actual as needed

* Convert Test.Common to nunit

* port hosting unit tests to nunit

* port batchparser integration tests to nunit

* port testdriver.tests to nunit

* fix target to copy dependency

* port servicelayer unittests to nunit

* more unit test fixes

* port integration tests to nunit

* fix test method type

* try using latest windows build for PRs

* reduce test memory use
2020-08-05 13:43:14 -04:00

491 lines
24 KiB
C#

//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Test.Common;
using Microsoft.SqlTools.Utility;
using NUnit.Framework;
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ServiceHost
{
/// <summary>
/// Logger test cases
/// </summary>
public class LoggerTests
{
/// <summary>
/// Test to verify that the logger initialization is generating a valid file
/// Verifies that a test log entries is succesfully written to a default log file.
/// </summary>
[Test]
public void LoggerDefaultFile()
{
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
EventType = TraceEventType.Information,
TracingLevel = SourceLevels.Verbose,
};
test.Initialize();
test.Write();
test.Verify();
test.Cleanup();
}
/// <summary>
/// Test to verify that the logger initialization works using various possibilities.
/// </summary>
[Test]
public void LoggerTestInitialization()
{
int? testNo = 1;
//Test 1: Initialization with all defaults. Logfile names get autogenerated with the well known prefix.
{
SourceLevels expectedTracingLevel = Logger.defaultTracingLevel;
string expectedTraceSource = Logger.defaultTraceSource;
Logger.Initialize();
bool isLogFileExpectedToExist = ((uint)expectedTracingLevel >= (uint)SourceLevels.Information);
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
//Test 2: Initialization with TracingLevel set to Critical. Logfile names get autogenerated with the well known prefix. Before we do a write at Critical level the logfile must not get even created.
{
SourceLevels expectedTracingLevel = SourceLevels.Critical;
string expectedTraceSource = Logger.defaultTraceSource;
Logger.Initialize(expectedTracingLevel);
bool isLogFileExpectedToExist = ((uint)expectedTracingLevel >= (uint)SourceLevels.Information);
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
//Test 3: Initialization with TraceSourceName set to specified name. Logfile names get autogenerated with the well known prefix.
{
SourceLevels expectedTracingLevel = Logger.defaultTracingLevel;
string expectedTraceSource = nameof(LoggerTestInitialization);
Logger.Initialize(traceSource:expectedTraceSource);
bool isLogFileExpectedToExist = ((uint)expectedTracingLevel >= (uint)SourceLevels.Information);
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
//Test 4: Initialization with logfile set to specified random filepath.
{
SourceLevels expectedTracingLevel = Logger.defaultTracingLevel;
string expectedTraceSource = Logger.defaultTraceSource;
string logFilePath = Path.Combine(Path.GetRandomFileName(), nameof(LoggerTestInitialization));
Logger.Initialize(traceSource: expectedTraceSource, logFilePath: logFilePath);
Assert.True(string.Compare(logFilePath, Logger.LogFileFullPath, ignoreCase: true) == 0, "The logfile path of the Logger should be the one specified");
bool isLogFileExpectedToExist = ((uint)expectedTracingLevel >= (uint)SourceLevels.Information);
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, logFilePath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
//Test 5: Initialization with logfile generated from log directory and LogFilePrefix using Logger.GenerateLogFielPath method.
{
SourceLevels expectedTracingLevel = Logger.defaultTracingLevel;
string expectedTraceSource = Logger.defaultTraceSource;
string logFilePath = Logger.GenerateLogFilePath(Path.Combine(Directory.GetCurrentDirectory(), nameof(LoggerTestInitialization)));
Assert.True(string.Compare(Path.GetDirectoryName(logFilePath), Directory.GetCurrentDirectory(), ignoreCase: true) == 0, "The directory path of the logfile should match the directory path specified");
Logger.Initialize(traceSource: expectedTraceSource, logFilePath: logFilePath);
Assert.True(string.Compare(logFilePath, Logger.LogFileFullPath, ignoreCase: true) == 0, "The logfile path of the Logger should be the one specified");
bool isLogFileExpectedToExist = ((uint)expectedTracingLevel >= (uint)SourceLevels.Information);
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
#region TracingLevel Settings
//Test 6: Initialization tracingLevel specified as a null string.
{
string tracingLevel = null;
SourceLevels expectedTracingLevel = Logger.defaultTracingLevel;
string expectedTraceSource = Logger.defaultTraceSource;
Logger.Initialize(tracingLevel);
bool isLogFileExpectedToExist = false;
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
//Test 7: Initialization tracingLevel specified as an empty string.
{
string tracingLevel = null;
SourceLevels expectedTracingLevel = Logger.defaultTracingLevel;
string expectedTraceSource = Logger.defaultTraceSource;
Logger.Initialize(tracingLevel);
bool isLogFileExpectedToExist = false;
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
//Test 8: Initialization tracingLevel specified as an invalid string.
{
string tracingLevel = "invalid";
SourceLevels expectedTracingLevel = Logger.defaultTracingLevel;
string expectedTraceSource = Logger.defaultTraceSource;
Logger.Initialize(tracingLevel);
bool isLogFileExpectedToExist = false;
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
//Test 9: Initialization with logfile set to empty string.
{
SourceLevels expectedTracingLevel = SourceLevels.All;
string expectedTraceSource = Logger.defaultTraceSource;
string logFilePath = string.Empty;
Logger.Initialize(traceSource: expectedTraceSource, logFilePath: logFilePath, tracingLevel:expectedTracingLevel);
bool isLogFileExpectedToExist = ((uint)expectedTracingLevel >= (uint)SourceLevels.Information);
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
//Test 10: Initialization with logfile set to null.
{
SourceLevels expectedTracingLevel = SourceLevels.All;
string expectedTraceSource = Logger.defaultTraceSource;
string logFilePath = null;
Logger.Initialize(traceSource: expectedTraceSource, logFilePath: logFilePath, tracingLevel: expectedTracingLevel);
bool isLogFileExpectedToExist = ((uint)expectedTracingLevel >= (uint)SourceLevels.Information);
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
//Test 11: Initialization with LogDirectory in Logger.GenerateLogFilePath set to empty string.
{
SourceLevels expectedTracingLevel = SourceLevels.All;
string expectedTraceSource = Logger.defaultTraceSource;
string logFilePath = Logger.GenerateLogFilePath(Path.Combine(string.Empty, nameof(LoggerTestInitialization)));
Logger.Initialize(traceSource: expectedTraceSource, logFilePath: logFilePath, tracingLevel: expectedTracingLevel);
Assert.True(string.Compare(logFilePath, Logger.LogFileFullPath, ignoreCase: true) == 0, "The logfile should match the path specified");
bool isLogFileExpectedToExist = ((uint)expectedTracingLevel >= (uint)SourceLevels.Information);
TestLogger.VerifyInitialization(expectedTracingLevel, expectedTraceSource, Logger.LogFileFullPath, isLogFileExpectedToExist, testNo++);
TestLogger.Cleanup(Logger.LogFileFullPath);
}
#endregion
}
/// <summary>
/// Test to verify that there is no log file created if TracingLevel is set to off.
/// </summary>
[Test]
public void LoggerTracingLevelOff()
{
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
EventType = TraceEventType.Information,
TracingLevel = SourceLevels.Off,
};
test.Initialize();
test.Write();
Assert.False(File.Exists(Logger.LogFileFullPath), $"Log file must not exist when tracing level is: {test.TracingLevel}");
test.Verify(expectLogMessage: false); // The log message should be absent since the tracing level is set to Off.
test.Cleanup();
}
/// <summary>
/// Test to verify that the tracinglevel setting filters message logged at lower levels.
/// Verifies that a test log entries logged at Information level are not present in log when tracingLevel
/// is set to 'Critical'
/// </summary>
[Test]
public void LoggerInformationalNotLoggedWithCriticalTracingLevel()
{
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
EventType = TraceEventType.Information,
TracingLevel = SourceLevels.Critical,
};
test.Initialize();
test.Write();
test.Verify(expectLogMessage:false); // The log message should be absent since the tracing level is set to collect messages only at 'Critical' logging level
test.Cleanup();
}
/// <summary>
/// Test to verify that WriteWithCallstack() method turns on the callstack logging
/// </summary>
[Test]
public void LoggerWithCallstack()
{
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
EventType = TraceEventType.Warning,
TracingLevel = SourceLevels.Information,
};
test.Initialize();
test.WriteWithCallstack();
test.Verify(); // This should verify the logging of callstack fields as well.
test.Cleanup();
}
/// <summary>
/// Test to verify that callstack logging is turned on, it does not get logged because tracing level filters them out.
/// </summary>
[Test]
public void LoggerWithCallstackFilteredOut()
{
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
EventType = TraceEventType.Information,
TracingLevel = SourceLevels.Error,
};
test.Initialize();
test.WriteWithCallstack();
test.Verify(expectLogMessage:false); // The log message and corresponding callstack details should be absent since the tracing level is set to collect messages only at 'Error' logging level
test.Cleanup();
}
/// <summary>
/// No TraceSource test to verify that WriteWithCallstack() method turns on the callstack logging
/// </summary>
[Test]
public void LoggerNoTraceSourceWithCallstack()
{
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
EventType = TraceEventType.Warning,
TracingLevel = SourceLevels.Information,
DoNotUseTraceSource = true,
};
test.Initialize();
test.WriteWithCallstack();
test.Verify(); // This should verify the logging of callstack fields as well.
test.Cleanup();
}
/// <summary>
/// No TraceSrouce test to verify that callstack logging is turned on, it does not get logged because tracing level filters them out.
/// </summary>
[Test]
public void LoggerNoTraceSourceWithCallstackFilteredOut()
{
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
EventType = TraceEventType.Information,
TracingLevel = SourceLevels.Error,
DoNotUseTraceSource = true,
};
test.Initialize();
test.WriteWithCallstack();
test.Verify(expectLogMessage: false); // The log message and corresponding callstack details should be absent since the tracing level is set to collect messages only at 'Error' logging level
test.Cleanup();
}
/// <summary>
/// Tests to verify that upon changing TracingLevel from Warning To Error,
/// after the change, messages of Error type are present in the log and those logged with warning type are not present.
/// </summary>
[Test]
public void LoggerTracingLevelFromWarningToError()
{
// setup the test object
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
};
TestTracingLevelChangeFromWarningToError(test);
}
/// <summary>
/// Tests to verify that upon changing TracingLevel from Error To Warning,
/// after the change, messages of Warning as well as of Error type are present in the log.
/// </summary>
[Test]
public void LoggerTracingLevelFromErrorToWarning()
{
// setup the test object
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
};
TestTracingLevelChangeFromErrorToWarning(test);
}
/// <summary>
/// When not use TraceSource, test to verify that upon changing TracingLevel from Warning To Error,
/// after the change, messages of Error type are present in the log and those logged with warning type are not present.
/// </summary>
[Test]
public void LoggerNoTraceSourceTracingLevelFromWarningToError()
{
// setup the test object
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
DoNotUseTraceSource = true,
};
TestTracingLevelChangeFromWarningToError(test);
}
/// <summary>
/// Tests out AutoFlush funcitonality. The verification is two fold.
/// 1st is to verify that the setting is persistent.
/// 2nd that after a lot of log entries are written with AutoFlush on, explicitly flushing and closing the Tracing does not increase the file size
/// thereby verifying that there was no leftover log entries being left behind to be flushed.
/// </summary>
[Test]
public void LoggerAutolFlush()
{
// setup the test object
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
AutoFlush = true,
TracingLevel = SourceLevels.All
};
test.Initialize();
// Write 10000 lines of log
Parallel.For(0, 100, (i) => test.Write($"Message Number:{i}, Message:{test.LogMessage}"));
long logContentsSizeBeforeExplicitFlush = (new FileInfo(test.LogFileName)).Length;
// Please note that Logger.Close() first flushes the logs before closing them out.
Logger.Flush();
long logContentsSizeAfterExplicitFlush = (new FileInfo(test.LogFileName)).Length;
Assert.True(logContentsSizeBeforeExplicitFlush == logContentsSizeAfterExplicitFlush, "The length of log file with autoflush before and after explicit flush must be same");
test.Cleanup();
}
/// <summary>
/// When not use TraceSource, test to verify that upon changing TracingLevel from Error To Warning,
/// after the change, messages of Warning as well as of Error type are present in the log.
/// </summary>
[Test]
public void LoggerNoTraceSourceTracingLevelFromErrorToWarning()
{
// setup the test object
TestLogger test = new TestLogger()
{
TraceSource = MethodInfo.GetCurrentMethod().Name,
DoNotUseTraceSource = true,
};
TestTracingLevelChangeFromErrorToWarning(test);
}
private static void TestTracingLevelChangeFromWarningToError(TestLogger test)
{
test.Initialize();
Logger.TracingLevel = SourceLevels.Warning;
string oldMessage = @"Old Message with Tracing Level set to Warning";
test.LogMessage = oldMessage;
// Initially with TracingLevel at Warning, logging of Warning type does not get filtered out.
Assert.AreEqual(SourceLevels.Warning, Logger.TracingLevel);
{
test.EventType = TraceEventType.Warning;
test.Write();
test.PendingVerifications.Add(() =>
{
test.Verify(eventType: TraceEventType.Warning, message: oldMessage, callstackMessage: null, shouldVerifyCallstack: false, expectLogMessage: true);
});
}
// and logging of Error type also succeeeds
{
test.EventType = TraceEventType.Error;
test.Write();
test.PendingVerifications.Add(() =>
{
test.Verify(eventType: TraceEventType.Error, message: oldMessage, callstackMessage: null, shouldVerifyCallstack: false, expectLogMessage: true);
});
}
//Now Update the tracing level to Error. Now logging both of Warning type gets filtered and only Error type should succeed.
Logger.TracingLevel = SourceLevels.Error;
Assert.AreEqual(SourceLevels.Error, Logger.TracingLevel);
string newMessage = @"New Message After Tracing Level set to Error";
test.LogMessage = newMessage;
// Now with TracingLevel at Error, logging of Warning type gets filtered out.
{
test.EventType = TraceEventType.Warning;
test.Write();
test.PendingVerifications.Add(() =>
{
test.Verify(eventType: TraceEventType.Warning, message: newMessage, callstackMessage: null, shouldVerifyCallstack: false, expectLogMessage: false);
});
}
// but logging of Error type succeeds
{
test.EventType = TraceEventType.Error;
test.Write();
test.PendingVerifications.Add(() =>
{
test.Verify(eventType: TraceEventType.Error, message: newMessage, callstackMessage: null, shouldVerifyCallstack: false, expectLogMessage: true);
});
}
test.VerifyPending();
test.Cleanup();
}
private static void TestTracingLevelChangeFromErrorToWarning(TestLogger test)
{
test.Initialize();
Logger.TracingLevel = SourceLevels.Error;
string oldMessage = @"Old Message with Tracing Level set to Error";
test.LogMessage = oldMessage;
// Initially with TracingLevel at Error, logging of Warning type gets filtered out.
Assert.AreEqual(SourceLevels.Error, Logger.TracingLevel);
{
test.EventType = TraceEventType.Warning;
test.Write();
test.PendingVerifications.Add(() =>
{
test.Verify(eventType: TraceEventType.Warning, message: oldMessage, callstackMessage: null, shouldVerifyCallstack: false, expectLogMessage: false);
});
}
// But logging of Error type succeeeds
{
test.EventType = TraceEventType.Error;
test.Write();
test.PendingVerifications.Add(() =>
{
test.Verify(eventType: TraceEventType.Error, message: oldMessage, callstackMessage: null, shouldVerifyCallstack: false, expectLogMessage: true);
});
}
//Now Update the tracing level to Warning. Now logging both of Error type and Warning type should succeed.
Logger.TracingLevel = SourceLevels.Warning;
Assert.AreEqual(SourceLevels.Warning, Logger.TracingLevel);
string newMessage = @"New Message After Tracing Level set to Warning";
test.LogMessage = newMessage;
// Now with TracingLevel at Warning, logging of Warning type does not get filtered out.
{
test.EventType = TraceEventType.Warning;
test.Write();
test.PendingVerifications.Add(() =>
{
test.Verify(eventType: TraceEventType.Warning, message: newMessage, callstackMessage: null, shouldVerifyCallstack: false, expectLogMessage: true);
});
}
// and logging of Error type also succeeds
{
test.EventType = TraceEventType.Error;
test.Write();
test.PendingVerifications.Add(() =>
{
test.Verify(eventType: TraceEventType.Error, message: newMessage, callstackMessage: null, shouldVerifyCallstack: false, expectLogMessage: true);
});
}
test.VerifyPending();
test.Cleanup();
}
}
}