Skip to content

Commit

Permalink
Merge pull request #9 from merodriguezblanco/slack-support
Browse files Browse the repository at this point in the history
Slack support
  • Loading branch information
merodriguezblanco authored Jan 13, 2019
2 parents 7958a18 + a60339a commit 74c20ea
Show file tree
Hide file tree
Showing 20 changed files with 321 additions and 15 deletions.
8 changes: 4 additions & 4 deletions ExceptionNotification.Core.Tests/Email/EmailBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace ExceptionNotification.Core.Tests.Email
{
[Trait("Category", "Unit")]
public class EmailBuilderTests
{
private readonly Exception _exception;
Expand Down Expand Up @@ -44,7 +45,7 @@ public void EmailBuilderThrowsExceptionWhenSenderIsNull()
_emailConfiguration.Sender = null;

var exception = Assert.Throws<SenderNullException>(() => new EmailBuilder(_emailConfiguration, _exception, _notifierOptions, null));
Assert.Equal("ComposeEmail failure: Sender is null.", exception.Message);
Assert.Equal("EmailBuilder failure: Sender is null.", exception.Message);
}

[Fact]
Expand All @@ -53,13 +54,12 @@ public void EmailBuilderThrowsExceptionWhenRecipientsCollectionIsEmpty()
_emailConfiguration.Recipients = null;

var exception = Assert.Throws<EmptyRecipientsException>(() => new EmailBuilder(_emailConfiguration, _exception, _notifierOptions, null));
Assert.Equal("ComposeEmail failure: Recipients collection is empty.", exception.Message);
Assert.Equal("EmailBuilder failure: Recipients collection is empty.", exception.Message);

_emailConfiguration.Recipients = new List<EmailAddress>();

exception = Assert.Throws<EmptyRecipientsException>(() => new EmailBuilder(_emailConfiguration, _exception, _notifierOptions, null));
Assert.Equal("ComposeEmail failure: Recipients collection is empty.", exception.Message);

Assert.Equal("EmailBuilder failure: Recipients collection is empty.", exception.Message);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace ExceptionNotification.Core.Tests.Email
{
[Trait("Category", "Unit")]
public class EmailNotifierTests
{
[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

namespace ExceptionNotification.Core.Tests
{
[Trait("Category", "Unit")]
public class ExceptionMessageBuilderTests
{
private readonly NotifierOptions _notifierOptions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace ExceptionNotification.Core.Tests.Hipchat
{
[Trait("Category", "Unit")]
public class HipchatMessageBuilderTests
{
[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace ExceptionNotification.Core.Tests.Hipchat
{
[Trait("Category", "Unit")]
public class HipchatNotifierTests
{
[Fact]
Expand Down
26 changes: 26 additions & 0 deletions ExceptionNotification.Core.Tests/Slack/SlackClientTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using ExceptionNotification.Core.Exceptions;
using ExceptionNotification.Core.Slack;
using Xunit;

namespace ExceptionNotification.Core.Tests.Slack
{
[Trait("Category", "Unit")]
public class SlackClientTests
{
[Fact]
public void SlackClientThrowsExceptionWhenMalformedWebhookUri()
{
var uri = "";
var exception = Assert.Throws<MalformedUriException>(() => new SlackClient(uri));
Assert.Equal("SlackClient failure: Slack's webhook URI is invalid.", exception.Message);

uri = null;
exception = Assert.Throws<MalformedUriException>(() => new SlackClient(uri));
Assert.Equal("SlackClient failure: Slack's webhook URI is invalid.", exception.Message);

uri = "invalid/uri";
exception = Assert.Throws<MalformedUriException>(() => new SlackClient(uri));
Assert.Equal("SlackClient failure: Slack's webhook URI is invalid.", exception.Message);
}
}
}
54 changes: 54 additions & 0 deletions ExceptionNotification.Core.Tests/Slack/SlackMessageBuilderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using ExceptionNotification.Core.Exceptions;
using ExceptionNotification.Core.Slack;
using Xunit;

namespace ExceptionNotification.Core.Tests.Slack
{
[Trait("Category", "Unit")]
public class SlackMessageBuilderTests
{
private readonly Exception _exception;

private readonly NotifierOptions _notifierOptions;

private readonly SlackConfiguration _slackConfiguration;

public SlackMessageBuilderTests()
{
_exception = new Exception("This is an exception!");
_notifierOptions = new NotifierOptions
{
ProjectName = "Fried Chicken",
Environment = "Development"
};
_slackConfiguration = new SlackConfiguration
{
Channel = "the chicken channel",
Username = "achicken",
WebhookUri = "http://chicken-channel.slack.com/services/hooks/incomig-webhook?token=123"
};
}

[Fact]
public void SlackMessageBuilderThrowsExceptionWhenInvalidWebhookUri()
{
_slackConfiguration.WebhookUri = "invalid";

var exception = Assert.Throws<MalformedUriException>(() => new SlackMessageBuilder(_slackConfiguration, _exception, _notifierOptions, null));
Assert.Equal("SlackMessageBuilder failure: Slack's webhook URI is invalid.", exception.Message);
}

[Fact]
public void ComposeMessageBuildsExceptionMessage()
{
var message = new SlackMessageBuilder(_slackConfiguration, _exception, _notifierOptions, null).ComposeMessage();

Assert.IsType<SlackMessage>(message);
Assert.Equal("the chicken channel", message.Channel);
Assert.Equal("achicken", message.Username);
Assert.Contains("[Fried Chicken - Development] EXCEPTION!", message.Text);
Assert.Contains("This is an exception!", message.Text);
}
}
}
29 changes: 29 additions & 0 deletions ExceptionNotification.Core.Tests/Slack/SlackNotifierTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using ExceptionNotification.Core.Exceptions;
using ExceptionNotification.Core.Slack;
using Xunit;

namespace ExceptionNotification.Core.Tests.Slack
{
[Trait("Category", "Unit")]
public class SlackNotifierTests
{
[Fact]
public void FireExceptionThrowsExceptionWhenConfigurationIsNull()
{
var notifier = new SlackNotifier(null);

var exception = Assert.Throws<ConfigurationMissingException>(() => notifier.FireNotification(new Exception(), null));
Assert.Equal("FireNotification failure: configuration is null.", exception.Message);
}

[Fact]
public void FireExceptionThrowsExceptionWhenExceptionIsNull()
{
var notifier = new SlackNotifier(new SlackConfiguration());

var exception = Assert.Throws<ExceptionMissingException>(() => notifier.FireNotification(null, null));
Assert.Equal("FireNotification failure: exception is null.", exception.Message);
}
}
}
4 changes: 2 additions & 2 deletions ExceptionNotification.Core/Email/EmailBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ public EmailBuilder(EmailConfiguration configuration, Exception exception, Notif
{
if (IsSenderNull(configuration.Sender))
{
throw new SenderNullException("ComposeEmail failure: Sender is null.");
throw new SenderNullException("EmailBuilder failure: Sender is null.");
}

if (IsRecipientsCollectionEmpty(configuration.Recipients))
{
throw new EmptyRecipientsException("ComposeEmail failure: Recipients collection is empty.");
throw new EmptyRecipientsException("EmailBuilder failure: Recipients collection is empty.");
}

_configuration = configuration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<RepositoryUrl>https://github.com/merodriguezblanco/ExceptionNotification.Core</RepositoryUrl>
<PackageTags>dotnet dotnetcore-2 exception-handling</PackageTags>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<Version>1.3.0</Version>
<Version>1.4.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions ExceptionNotification.Core/ExceptionNotifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using ExceptionNotification.Core.Email;
using ExceptionNotification.Core.Hipchat;
using ExceptionNotification.Core.Slack;
using Microsoft.AspNetCore.Http;

namespace ExceptionNotification.Core
Expand All @@ -25,6 +26,11 @@ public static void Setup(IExceptionNotifierConfiguration configuration)
{
_notifiers.Add(new HipchatNotifier(_configuration.Hipchat));
}

if (_configuration.Slack != null)
{
_notifiers.Add(new SlackNotifier(_configuration.Slack));
}
}

public static void NotifyException(Exception exception)
Expand Down
3 changes: 3 additions & 0 deletions ExceptionNotification.Core/ExceptionNotifierConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using ExceptionNotification.Core.Email;
using ExceptionNotification.Core.Hipchat;
using ExceptionNotification.Core.Slack;

namespace ExceptionNotification.Core
{
Expand All @@ -8,5 +9,7 @@ public class ExceptionNotifierConfiguration : IExceptionNotifierConfiguration
public EmailConfiguration Email { get; set; }

public HipchatConfiguration Hipchat { get; set; }

public SlackConfiguration Slack { get; set; }
}
}
13 changes: 13 additions & 0 deletions ExceptionNotification.Core/Exceptions/MalformedUriException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;

namespace ExceptionNotification.Core.Exceptions
{
public class MalformedUriException : Exception
{
public MalformedUriException(string message) : this(message, null)
{ }

public MalformedUriException(string message, Exception innerException) : base(message, innerException)
{ }
}
}
3 changes: 3 additions & 0 deletions ExceptionNotification.Core/IExceptionNotifierConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using ExceptionNotification.Core.Email;
using ExceptionNotification.Core.Hipchat;
using ExceptionNotification.Core.Slack;

namespace ExceptionNotification.Core
{
Expand All @@ -8,5 +9,7 @@ public interface IExceptionNotifierConfiguration
EmailConfiguration Email { get; set; }

HipchatConfiguration Hipchat { get; set; }

SlackConfiguration Slack { get; set; }
}
}
41 changes: 41 additions & 0 deletions ExceptionNotification.Core/Slack/SlackClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using ExceptionNotification.Core.Exceptions;
using Newtonsoft.Json;

namespace ExceptionNotification.Core.Slack
{
public class SlackClient
{
private readonly Uri _webhookUri;

public SlackClient(Uri webhookUri)
{
_webhookUri = webhookUri;
}

public SlackClient(string webhookUri)
{
if (!Uri.IsWellFormedUriString(webhookUri, UriKind.Absolute))
{
throw new MalformedUriException("SlackClient failure: Slack's webhook URI is invalid.");
}

_webhookUri = new Uri(webhookUri);
}

public async Task<HttpResponseMessage> SendNotificationAsync(SlackMessage message)
{
using (var client = new HttpClient())
{
var serializedPayload = JsonConvert.SerializeObject(message);
var payload = new StringContent(serializedPayload, Encoding.UTF8, "application/json");
var response = await client.PostAsync(_webhookUri, payload);

return response;
}
}
}
}
11 changes: 11 additions & 0 deletions ExceptionNotification.Core/Slack/SlackConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace ExceptionNotification.Core.Slack
{
public class SlackConfiguration
{
public string WebhookUri { get; set; }

public string Channel { get; set; }

public string Username { get; set; }
}
}
16 changes: 16 additions & 0 deletions ExceptionNotification.Core/Slack/SlackMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Newtonsoft.Json;

namespace ExceptionNotification.Core.Slack
{
public class SlackMessage
{
[JsonProperty("channel")]
public string Channel { get; set; }

[JsonProperty("username")]
public string Username { get; set; }

[JsonProperty("text")]
public string Text { get; set; }
}
}
35 changes: 35 additions & 0 deletions ExceptionNotification.Core/Slack/SlackMessageBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using ExceptionNotification.Core.Exceptions;
using Microsoft.AspNetCore.Http;

namespace ExceptionNotification.Core.Slack
{
public class SlackMessageBuilder : ExceptionMessageBuilder
{
private readonly SlackConfiguration _configuration;

public SlackMessageBuilder(SlackConfiguration configuration, Exception exception,
NotifierOptions notifierOptions, HttpRequest request) : base(exception, notifierOptions, request)
{
if (!Uri.IsWellFormedUriString(configuration.WebhookUri, UriKind.Absolute))
{
throw new MalformedUriException("SlackMessageBuilder failure: Slack's webhook URI is invalid.");
}

_configuration = configuration;
}

public SlackMessage ComposeMessage()
{
var messageBody = $"{ComposeSubject()}\n\n {ComposeContent()}";
var message = new SlackMessage
{
Channel = _configuration.Channel,
Username = _configuration.Username,
Text = messageBody
};

return message;
}
}
}
Loading

0 comments on commit 74c20ea

Please sign in to comment.