Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing handling for LoggingEvent properties #7

Merged

added unit tests for all the various ways of handling contexts and ev…

…ent properties
  • Loading branch information
Asbjørn Hansen
Asbjørn Hansen committed Mar 9, 2017
commit f5c264734f7f102d6ecd4246406ed8266b332a9a
@@ -3,13 +3,15 @@
using System;
using FluentAssertions;
using JetBrains.Annotations;
using log4net;
using log4net.Core;
using log4net.loggly;
using log4net.Repository;
using log4net_loggly.UnitTests.Models;
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoMoq;
using Xunit;

[UsedImplicitly]
@@ -23,64 +25,64 @@ public ToJsonMethod()
{
_fixture = new Fixture();
_fixture.Customize(new SupportMutableValueTypesCustomization());
_fixture.Customize(new AutoMoqCustomization());
_fixture.Customize<LogglyFormatter>(c => c.With(x => x.Config, Mock.Of<ILogglyAppenderConfig>()));
_fixture.Customize<LogglyFormatter>(c => c.With(x => x.Config, _fixture.Freeze<Mock<ILogglyAppenderConfig>>().Object));
}

[Fact]
public void ShouldReturnValidJson()
public void ShouldAddAHostNameProperty()
{
var evt = _fixture.Create<LoggingEvent>();
var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
Action act = () => JObject.Parse(result);
dynamic json = JObject.Parse(result);

act.ShouldNotThrow<JsonException>("because the result should be a valid json document");
var hostName = (string) json.hostName;

hostName.Should().NotBeNullOrEmpty("because the machine name is used to set the hostname");
}

[Fact]
public void ShouldAddAValidTimestampProperty()
public void ShouldAddALevelProperty()
{
var evt = _fixture.Create<LoggingEvent>();
var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var timestamp = (string)json.timestamp;
DateTime voidDateTime;
var level = (string) json.level;

timestamp.Should().NotBeNullOrEmpty("because the timestamp property should always be set");
DateTime.TryParse(timestamp, out voidDateTime).Should().BeTrue("because the timestamp should always be a valid date");
level.Should().StartWith("levelName", "because the level name property on the event is used");
}

[Fact]
public void ShouldAddALevelProperty()
public void ShouldAddALoggerNameProperty()
{
var evt = _fixture.Create<LoggingEvent>();
var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var level = (string)json.level;
var loggerName = (string) json.loggerName;

level.Should().StartWith("levelName", "because the level name property on the event is used");
loggerName.Should().StartWith("LoggerName", "because this is the value of the LoggerName property on the event");
}

[Fact]
public void ShouldAddAHostNameProperty()
public void ShouldAddAMessagePropertyForEventsWithoutMessages()
{
var evt = _fixture.Create<LoggingEvent>();
var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var hostName = (string)json.hostName;
var message = (string) json.message;

hostName.Should().NotBeNullOrEmpty("because the machine name is used to set the hostname");
message.Should()
.Be("null", "because the MessageObject property is null but we want to log \"null\" to show this explicitly");
}

[Fact]
@@ -92,7 +94,7 @@ public void ShouldAddAProcessProperty()
var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var process = (string)json.process;
var process = (string) json.process;

process.Should().NotBeNullOrEmpty("because the value is taken from the current process which should always be set");
}
@@ -106,23 +108,252 @@ public void ShouldAddAThreadNameProperty()
var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var threadName = (string)json.threadName;
var threadName = (string) json.threadName;

threadName.Should().StartWith("ThreadName", "because this is the value of the ThreadName property on the event");
}

[Fact]
public void ShouldAddALoggerNameProperty()
public void ShouldAddAValidTimestampProperty()
{
var evt = _fixture.Create<LoggingEvent>();
var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var loggerName = (string)json.loggerName;
var timestamp = (string) json.timestamp;
DateTime voidDateTime;

loggerName.Should().StartWith("LoggerName", "because this is the value of the LoggerName property on the event");
timestamp.Should().NotBeNullOrEmpty("because the timestamp property should always be set");
DateTime.TryParse(timestamp, out voidDateTime).Should().BeTrue("because the timestamp should always be a valid date");
}

[Fact]
public void ShouldAddExtraPropertiesWhenMessageObjectIsAComplexType()
{
var evt = new LoggingEvent(
GetType(),
Mock.Of<ILoggerRepository>(),
_fixture.Create("loggerName"),
_fixture.Create<Level>(),
_fixture.Create<ComplexType>(),
null);
var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var propertyOne = (string) json.PropertyOne;
var propertyTwo = (int) json.PropertyTwo;

propertyOne.Should().StartWith("PropertyOne", "because the value from the PropertyOne property on the complex type is used");
propertyTwo.Should().BeGreaterThan(0, "because the value of the PropertyTwo property on the complex type is used");
}

[Fact]
public void ShouldReturnValidJson()
{
var evt = _fixture.Create<LoggingEvent>();
var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
Action act = () => JObject.Parse(result);

act.ShouldNotThrow<JsonException>("because the result should be a valid json document");
}

[Fact]
public void ShouldSerializeEventProperties()
{
var evt = _fixture.Create<LoggingEvent>();

evt.Properties["Key1"] = _fixture.Create("value1");
evt.Properties["Key2"] = _fixture.Create<int>();
evt.Properties["Key3"] = _fixture.Create<ComplexType>();
evt.Properties["Key4"] = _fixture.Create<FixedComplexType>();
evt.Properties["Key5"] = null;

var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var key1 = json.Key1;
var key2 = json.Key2;
var key3 = json.Key3;
var key4 = json.Key4;
var key5 = json.Key5;

((string) key1).Should().StartWith("value1", "because that's the value of the event property with this key");
((int) key2).Should().BeGreaterThan(0, "because the key is set to a positive value in the event properties");
((object) key3).Should().NotBeNull("because the key is set in the event properties");
((string) key3.PropertyOne).Should().StartWith("PropertyOne", "because the value of the complex type should be serialized");
((int) key3.PropertyTwo).Should().BeGreaterThan(0, "because the value of the complex type should be serialized");
((object) key4).Should().NotBeNull("because the key is set in the event properties");
((string) key4).Should().Be("I'm a fixed type!", "because the type of this property requires fixing");
((object) key5).Should().BeNull("because the key is set but the value is null");
}

[Fact]
public void ShouldSerializeGlobalThreadContextProperties()
{
var evt = _fixture.Create<LoggingEvent>();

GlobalContext.Properties["Key1"] = _fixture.Create("value1");
GlobalContext.Properties["Key2"] = _fixture.Create<int>();
GlobalContext.Properties["Key3"] = _fixture.Create<ComplexType>();
GlobalContext.Properties["Key4"] = _fixture.Create<FixedComplexType>();
GlobalContext.Properties["Key5"] = null;
GlobalContext.Properties["Key6"] = _fixture.Create("value1");

var instance = _fixture.Create<LogglyFormatter>();
_fixture.Freeze<Mock<ILogglyAppenderConfig>>().SetupGet(x => x.GlobalContextKeys).Returns("Key1,Key2,Key3,Key4,Key5");

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var key1 = json.Key1;
var key2 = json.Key2;
var key3 = json.Key3;
var key4 = json.Key4;
var key5 = json.Key5;

((string) key1).Should().StartWith("value1", "because that's the value of the event property with this key");
((int) key2).Should().BeGreaterThan(0, "because the key is set to a positive value in the event properties");
((object) key3).Should().NotBeNull("because the key is set in the event properties");
((string) key3.PropertyOne).Should().StartWith("PropertyOne", "because the value of the complex type should be serialized");
((int) key3.PropertyTwo).Should().BeGreaterThan(0, "because the value of the complex type should be serialized");
((object) key4).Should().NotBeNull("because the key is set in the event properties");
((string) key4).Should().Be("I'm a fixed type!", "because the type of this property requires fixing");
((object) key5).Should().BeNull("because the key is set but the value is null");
((object) json.Key6).Should().BeNull("because this key was not marked for serialization");
}

[Fact]
public void ShouldSerializeLogicalThreadContextProperties()
{
var evt = _fixture.Create<LoggingEvent>();

LogicalThreadContext.Properties["Key1"] = _fixture.Create("value1");
LogicalThreadContext.Properties["Key2"] = _fixture.Create<int>();
LogicalThreadContext.Properties["Key3"] = _fixture.Create<ComplexType>();
LogicalThreadContext.Properties["Key4"] = _fixture.Create<FixedComplexType>();
LogicalThreadContext.Properties["Key5"] = null;
LogicalThreadContext.Properties["Key6"] = _fixture.Create("value1");

var instance = _fixture.Create<LogglyFormatter>();
_fixture.Freeze<Mock<ILogglyAppenderConfig>>().SetupGet(x => x.LogicalThreadContextKeys).Returns("Key1,Key2,Key3,Key4,Key5");

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var key1 = json.Key1;
var key2 = json.Key2;
var key3 = json.Key3;
var key4 = json.Key4;
var key5 = json.Key5;

((string) key1).Should().StartWith("value1", "because that's the value of the event property with this key");
((int) key2).Should().BeGreaterThan(0, "because the key is set to a positive value in the event properties");
((object) key3).Should().NotBeNull("because the key is set in the event properties");
((string) key3.PropertyOne).Should().StartWith("PropertyOne", "because the value of the complex type should be serialized");
((int) key3.PropertyTwo).Should().BeGreaterThan(0, "because the value of the complex type should be serialized");
((object) key4).Should().NotBeNull("because the key is set in the event properties");
((string) key4).Should().Be("I'm a fixed type!", "because the type of this property requires fixing");
((object) key5).Should().BeNull("because the key is set but the value is null");
((object) json.Key6).Should().BeNull("because this key was not marked for serialization");
}

[Fact]
public void ShouldSerializeTheException()
{
// In order to populate the stacktrace.
Exception ex;
try
{
throw new ArgumentException();
}
catch (Exception e)
{
ex = e;
}

var evt = new LoggingEvent(
GetType(),
Mock.Of<ILoggerRepository>(),
_fixture.Create("loggerName"),
_fixture.Create<Level>(),
_fixture.Create("message"),
ex);
var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var exception = json.exception;

((object) exception).Should().NotBeNull("because an exception was specified in the event");

var message = (string) exception.exceptionMessage;
var type = (string) exception.exceptionType;
var stacktrace = (string) exception.stacktrace;

message.Should().NotBeNullOrEmpty("because an argument exception has a default message");
type.Should().Be(typeof(ArgumentException).FullName, "because we logged an argument exception");
stacktrace.Should().NotBeNull("because the exception has a stacktrace");
}

[Fact]
public void ShouldSerializeThreadContextProperties()
{
var evt = _fixture.Create<LoggingEvent>();

ThreadContext.Properties["Key1"] = _fixture.Create("value1");
ThreadContext.Properties["Key2"] = _fixture.Create<int>();
ThreadContext.Properties["Key3"] = _fixture.Create<ComplexType>();
ThreadContext.Properties["Key4"] = _fixture.Create<FixedComplexType>();
ThreadContext.Properties["Key5"] = null;

var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var key1 = json.Key1;
var key2 = json.Key2;
var key3 = json.Key3;
var key4 = json.Key4;
var key5 = json.Key5;

((string) key1).Should().StartWith("value1", "because that's the value of the event property with this key");
((int) key2).Should().BeGreaterThan(0, "because the key is set to a positive value in the event properties");
((object) key3).Should().NotBeNull("because the key is set in the event properties");
((string) key3.PropertyOne).Should().StartWith("PropertyOne", "because the value of the complex type should be serialized");
((int) key3.PropertyTwo).Should().BeGreaterThan(0, "because the value of the complex type should be serialized");
((object) key4).Should().NotBeNull("because the key is set in the event properties");
((string) key4).Should().Be("I'm a fixed type!", "because the type of this property requires fixing");
((object) key5).Should().BeNull("because the key is set but the value is null");
}

[Fact]
public void ShouldSetMessagePropertyWhenMessageObjectIsString()
{
var evt = new LoggingEvent(
GetType(),
Mock.Of<ILoggerRepository>(),
_fixture.Create("loggerName"),
_fixture.Create<Level>(),
_fixture.Create("message"),
null);
var instance = _fixture.Create<LogglyFormatter>();

var result = instance.ToJson(evt);
dynamic json = JObject.Parse(result);

var message = (string) json.message;

message.Should().StartWith("message", "because the MessageObject property value is used");
}
}
}
@@ -0,0 +1,9 @@
namespace log4net_loggly.UnitTests.Models
{
public class ComplexType
{
public string PropertyOne { get; set; }

public int PropertyTwo { get; set; }
}
}
@@ -0,0 +1,16 @@
namespace log4net_loggly.UnitTests.Models
{
using log4net.Core;

public class FixedComplexType : IFixingRequired
{
public string PropertyOne { get; set; }

public int PropertyTwo { get; set; }

public object GetFixedObject()
{
return "I'm a fixed type!";
}
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.