From c1c4b5cfcc4ce960c5529682f4d96814b9e72344 Mon Sep 17 00:00:00 2001 From: rohitkrsoni Date: Thu, 25 Apr 2024 21:34:46 +0930 Subject: [PATCH 1/7] Add project files. --- SMSMicroService.sln | 25 ++++++++ SMSMicroService/Helper/PhoneNumberHelper.cs | 11 ++++ SMSMicroService/Helper/TextMessageHelper.cs | 31 ++++++++++ .../Implementations/ConsoleLogger.cs | 17 ++++++ SMSMicroService/Implementations/EventBus.cs | 37 +++++++++++ .../Implementations/MessageQueue.cs | 48 +++++++++++++++ SMSMicroService/Interfaces/IEventBus.cs | 13 ++++ SMSMicroService/Interfaces/ILogger.cs | 13 ++++ SMSMicroService/Interfaces/IMessageQueue.cs | 14 +++++ SMSMicroService/Program.cs | 18 ++++++ SMSMicroService/SMSMicroService.csproj | 10 +++ SMSMicroService/SendSmsCommand.cs | 9 +++ SMSMicroService/SmsMicroservice.cs | 61 +++++++++++++++++++ SMSMicroService/SmsSentEvent.cs | 15 +++++ 14 files changed, 322 insertions(+) create mode 100644 SMSMicroService.sln create mode 100644 SMSMicroService/Helper/PhoneNumberHelper.cs create mode 100644 SMSMicroService/Helper/TextMessageHelper.cs create mode 100644 SMSMicroService/Implementations/ConsoleLogger.cs create mode 100644 SMSMicroService/Implementations/EventBus.cs create mode 100644 SMSMicroService/Implementations/MessageQueue.cs create mode 100644 SMSMicroService/Interfaces/IEventBus.cs create mode 100644 SMSMicroService/Interfaces/ILogger.cs create mode 100644 SMSMicroService/Interfaces/IMessageQueue.cs create mode 100644 SMSMicroService/Program.cs create mode 100644 SMSMicroService/SMSMicroService.csproj create mode 100644 SMSMicroService/SendSmsCommand.cs create mode 100644 SMSMicroService/SmsMicroservice.cs create mode 100644 SMSMicroService/SmsSentEvent.cs diff --git a/SMSMicroService.sln b/SMSMicroService.sln new file mode 100644 index 0000000..372ed2f --- /dev/null +++ b/SMSMicroService.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMSMicroService", "SMSMicroService\SMSMicroService.csproj", "{7C478F74-3D1C-4897-8F18-D6ABA883E53C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7C478F74-3D1C-4897-8F18-D6ABA883E53C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C478F74-3D1C-4897-8F18-D6ABA883E53C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C478F74-3D1C-4897-8F18-D6ABA883E53C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C478F74-3D1C-4897-8F18-D6ABA883E53C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AD5ECFDB-20BA-4998-A637-FE9B8711FED6} + EndGlobalSection +EndGlobal diff --git a/SMSMicroService/Helper/PhoneNumberHelper.cs b/SMSMicroService/Helper/PhoneNumberHelper.cs new file mode 100644 index 0000000..9dd44cb --- /dev/null +++ b/SMSMicroService/Helper/PhoneNumberHelper.cs @@ -0,0 +1,11 @@ +namespace SMSMicroService.Helper +{ + internal class PhoneNumberHelper + { + public static string GenerateRandomPhoneNumber() + { + Random random = new(); + return string.Format("{0:000}{1:000}{2:0000}", random.Next(700, 999), random.Next(0, 999), random.Next(0, 9999)); + } + } +} diff --git a/SMSMicroService/Helper/TextMessageHelper.cs b/SMSMicroService/Helper/TextMessageHelper.cs new file mode 100644 index 0000000..20283da --- /dev/null +++ b/SMSMicroService/Helper/TextMessageHelper.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SMSMicroService.Helper +{ + internal class TextMessageHelper + { + public static string GenerateRandomTextMessage() + { + Random random = new(); + string[] messages = + [ + "Thank you for choosing us! We appreciate your business.", + "Hi! Just a quick note to say thank you for your support.", + "Your satisfaction is our top priority. Let us know if you need assistance.", + "Hello! We're here to provide you with excellent service.", + "Thanks for being a valued customer! Have a great day!", + "We're grateful for your trust in us. Have a fantastic day!", + "Dear client, your feedback is important to us. Let us know how we're doing!", + "Thanks for choosing us. We're committed to your satisfaction.", + "Hello! We appreciate your business. Wishing you a wonderful day!", + "Your satisfaction is important to us. We're here to help!" + ]; + + return messages[random.Next(0,9)]; + } + } +} diff --git a/SMSMicroService/Implementations/ConsoleLogger.cs b/SMSMicroService/Implementations/ConsoleLogger.cs new file mode 100644 index 0000000..ec53daa --- /dev/null +++ b/SMSMicroService/Implementations/ConsoleLogger.cs @@ -0,0 +1,17 @@ +using SMSMicroService.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SMSMicroService.Implementations +{ + internal class ConsoleLogger: ILogger + { + public void Log(string message) + { + Console.WriteLine($"[{DateTime.UtcNow}] {message}"); + } + } +} diff --git a/SMSMicroService/Implementations/EventBus.cs b/SMSMicroService/Implementations/EventBus.cs new file mode 100644 index 0000000..cbf9871 --- /dev/null +++ b/SMSMicroService/Implementations/EventBus.cs @@ -0,0 +1,37 @@ +using SMSMicroService.Interfaces; + + +namespace SMSMicroService.Implementations +{ + internal class EventBus: IEventBus + { + private readonly Dictionary>> _eventHandlers; + + public EventBus() + { + _eventHandlers = new Dictionary>>(); + } + + public void Subscribe(Func handler) + { + if (!_eventHandlers.TryGetValue(typeof(T), out var handlers)) + { + handlers = new List>(); + _eventHandlers.Add(typeof(T), handlers); + } + + handlers.Add(async @event => await handler((T)@event)); + } + + public async Task PublishEventAsync(T @event) + { + if (_eventHandlers.TryGetValue(typeof(T), out var handlers)) + { + foreach (var handler in handlers) + { + await handler(@event); + } + } + } + } +} diff --git a/SMSMicroService/Implementations/MessageQueue.cs b/SMSMicroService/Implementations/MessageQueue.cs new file mode 100644 index 0000000..1a923b4 --- /dev/null +++ b/SMSMicroService/Implementations/MessageQueue.cs @@ -0,0 +1,48 @@ +using SMSMicroService.Interfaces; +using System.Collections.Concurrent; +using SMSMicroService.Helper; + +namespace SMSMicroService.Implementations +{ + internal class MessageQueue: IMessageQueue + { + private readonly ConcurrentQueue _queue; + + public MessageQueue() + { + _queue = new ConcurrentQueue(); + } + + public void SendMessage(T message) + { + if (message != null) + { + _queue.Enqueue(message); + + } + } + + public async Task ReceiveMessageAsync() + { + while (true) + { + if (_queue.TryDequeue(out var message)) + { + return (T)message; + } + await Task.Delay(1000); // Adjust delay according to your requirement + } + } + + public void StartAddingRandomMessagesAsync() + { + while (true) + { + var phoneNumber = PhoneNumberHelper.GenerateRandomPhoneNumber(); + var smsText = TextMessageHelper.GenerateRandomTextMessage(); + SendMessage(new SendSmsCommand { PhoneNumber = phoneNumber, SmsText = smsText }); + Thread.Sleep(1500); // Adjust delay according to your requirement + } + } + } +} diff --git a/SMSMicroService/Interfaces/IEventBus.cs b/SMSMicroService/Interfaces/IEventBus.cs new file mode 100644 index 0000000..02243e9 --- /dev/null +++ b/SMSMicroService/Interfaces/IEventBus.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SMSMicroService.Interfaces +{ + internal interface IEventBus + { + Task PublishEventAsync(T @event); + } +} diff --git a/SMSMicroService/Interfaces/ILogger.cs b/SMSMicroService/Interfaces/ILogger.cs new file mode 100644 index 0000000..a8cea5a --- /dev/null +++ b/SMSMicroService/Interfaces/ILogger.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SMSMicroService.Interfaces +{ + internal interface ILogger + { + void Log(string message); + } +} diff --git a/SMSMicroService/Interfaces/IMessageQueue.cs b/SMSMicroService/Interfaces/IMessageQueue.cs new file mode 100644 index 0000000..fce71b4 --- /dev/null +++ b/SMSMicroService/Interfaces/IMessageQueue.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SMSMicroService.Interfaces +{ + internal interface IMessageQueue + { + Task ReceiveMessageAsync(); + public void SendMessage(T message); + } +} diff --git a/SMSMicroService/Program.cs b/SMSMicroService/Program.cs new file mode 100644 index 0000000..834ca65 --- /dev/null +++ b/SMSMicroService/Program.cs @@ -0,0 +1,18 @@ +using SMSMicroService.Implementations; + +namespace SMSMicroService +{ + internal class Program + { + static async Task Main(string[] args) + { + var messageQueue = new MessageQueue(); + var eventBus = new EventBus(); + var logger = new ConsoleLogger(); + var smsMicroservice = new SmsMicroservice(messageQueue, eventBus, logger); + Thread addRandomMessages = new(() => messageQueue.StartAddingRandomMessagesAsync()); + addRandomMessages.Start(); + await smsMicroservice.Start(); + } + } +} diff --git a/SMSMicroService/SMSMicroService.csproj b/SMSMicroService/SMSMicroService.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/SMSMicroService/SMSMicroService.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/SMSMicroService/SendSmsCommand.cs b/SMSMicroService/SendSmsCommand.cs new file mode 100644 index 0000000..db0b5f0 --- /dev/null +++ b/SMSMicroService/SendSmsCommand.cs @@ -0,0 +1,9 @@ +namespace SMSMicroService +{ + internal class SendSmsCommand + { + public required string PhoneNumber { get; set; } + public required string SmsText { get; set; } + + } +} diff --git a/SMSMicroService/SmsMicroservice.cs b/SMSMicroService/SmsMicroservice.cs new file mode 100644 index 0000000..2dbb804 --- /dev/null +++ b/SMSMicroService/SmsMicroservice.cs @@ -0,0 +1,61 @@ +using SMSMicroService.Interfaces; + +namespace SMSMicroService +{ + internal class SmsMicroservice + { + private readonly IMessageQueue _messageQueue; + private readonly IEventBus _eventBus; + private readonly ILogger _logger; + + public SmsMicroservice(IMessageQueue messageQueue, IEventBus eventBus, ILogger logger) + { + _messageQueue = messageQueue; + _eventBus = eventBus; + _logger = logger; + } + + public async Task Start() + { + _logger.Log("SMS Microservice started."); + + while (true) + { + var command = await _messageQueue.ReceiveMessageAsync(); + + _logger.Log($"Received SendSms command for phone number: {command.PhoneNumber}"); + + var smsSentEvent = await SendSmsAsync(command); + + await _eventBus.PublishEventAsync(smsSentEvent); + } + } + + private async Task SendSmsAsync(SendSmsCommand command) + { + try + { + using (var httpClient = new HttpClient()) + { + var requestContent = new StringContent($"{{'PhoneNumber': '{command.PhoneNumber}', 'SmsText': '{command.SmsText}'}}"); + var response = await httpClient.PostAsync("https://4kvv1.wiremockapi.cloud/sendSms", requestContent); + + if (!response.IsSuccessStatusCode) + { + _logger.Log($"Failed to send SMS to {command.PhoneNumber}. Status code: {response.StatusCode}"); + // Retry can be implemented + } + + _logger.Log($"SMS sent successfully to {command.PhoneNumber}"); + + return new SmsSentEvent { PhoneNumber = command.PhoneNumber, SmsText = command.SmsText, Timestamp = DateTime.UtcNow }; + } + } + catch (Exception ex) + { + _logger.Log($"Error sending SMS to {command.PhoneNumber}: {ex.Message}"); + throw; + } + } + } +} diff --git a/SMSMicroService/SmsSentEvent.cs b/SMSMicroService/SmsSentEvent.cs new file mode 100644 index 0000000..ee88062 --- /dev/null +++ b/SMSMicroService/SmsSentEvent.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SMSMicroService +{ + internal class SmsSentEvent + { + public required string PhoneNumber { get; set; } + public required string SmsText { get; set; } + public required DateTime Timestamp { get; set; } + } +} From 83b7e5b5beae2b50e109bb1585acddda5a8ea429 Mon Sep 17 00:00:00 2001 From: rohitkrsoni Date: Fri, 26 Apr 2024 01:35:54 +0930 Subject: [PATCH 2/7] EventHub Fixed --- SMSMicroService/Implementations/EventBus.cs | 26 +++++---------------- SMSMicroService/SmsMicroservice.cs | 26 ++++++++++----------- SMSMicroService/SmsSentEvent.cs | 1 + 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/SMSMicroService/Implementations/EventBus.cs b/SMSMicroService/Implementations/EventBus.cs index cbf9871..63f32fb 100644 --- a/SMSMicroService/Implementations/EventBus.cs +++ b/SMSMicroService/Implementations/EventBus.cs @@ -5,33 +5,19 @@ namespace SMSMicroService.Implementations { internal class EventBus: IEventBus { - private readonly Dictionary>> _eventHandlers; + private readonly List _publishedEvents; public EventBus() { - _eventHandlers = new Dictionary>>(); + _publishedEvents = []; } - public void Subscribe(Func handler) + public async Task PublishEventAsync(T evt) { - if (!_eventHandlers.TryGetValue(typeof(T), out var handlers)) - { - handlers = new List>(); - _eventHandlers.Add(typeof(T), handlers); - } - - handlers.Add(async @event => await handler((T)@event)); - } - - public async Task PublishEventAsync(T @event) - { - if (_eventHandlers.TryGetValue(typeof(T), out var handlers)) - { - foreach (var handler in handlers) - { - await handler(@event); - } + if (evt != null) { + _publishedEvents.Add(evt); } + await Task.Delay(0); } } } diff --git a/SMSMicroService/SmsMicroservice.cs b/SMSMicroService/SmsMicroservice.cs index 2dbb804..ac0cbcb 100644 --- a/SMSMicroService/SmsMicroservice.cs +++ b/SMSMicroService/SmsMicroservice.cs @@ -35,22 +35,22 @@ private async Task SendSmsAsync(SendSmsCommand command) { try { - using (var httpClient = new HttpClient()) - { - var requestContent = new StringContent($"{{'PhoneNumber': '{command.PhoneNumber}', 'SmsText': '{command.SmsText}'}}"); - var response = await httpClient.PostAsync("https://4kvv1.wiremockapi.cloud/sendSms", requestContent); + using var httpClient = new HttpClient(); - if (!response.IsSuccessStatusCode) - { - _logger.Log($"Failed to send SMS to {command.PhoneNumber}. Status code: {response.StatusCode}"); - // Retry can be implemented - } + var requestContent = new StringContent($"{{'PhoneNumber': '{command.PhoneNumber}', 'SmsText': '{command.SmsText}'}}"); + var response = await httpClient.PostAsync("https://4kvv1.wiremockapi.cloud/sendSms", requestContent); - _logger.Log($"SMS sent successfully to {command.PhoneNumber}"); + if (!response.IsSuccessStatusCode) + { + _logger.Log($"Failed to send SMS to {command.PhoneNumber}. Status code: {response.StatusCode}"); + return new SmsSentEvent { SmsSent = false, PhoneNumber = command.PhoneNumber, SmsText = command.SmsText, Timestamp = DateTime.UtcNow }; + // Retry can be implemented + } - return new SmsSentEvent { PhoneNumber = command.PhoneNumber, SmsText = command.SmsText, Timestamp = DateTime.UtcNow }; - } - } + _logger.Log($"SMS sent successfully to {command.PhoneNumber}"); + + return new SmsSentEvent { SmsSent = true, PhoneNumber = command.PhoneNumber, SmsText = command.SmsText, Timestamp = DateTime.UtcNow }; + } catch (Exception ex) { _logger.Log($"Error sending SMS to {command.PhoneNumber}: {ex.Message}"); diff --git a/SMSMicroService/SmsSentEvent.cs b/SMSMicroService/SmsSentEvent.cs index ee88062..787421f 100644 --- a/SMSMicroService/SmsSentEvent.cs +++ b/SMSMicroService/SmsSentEvent.cs @@ -8,6 +8,7 @@ namespace SMSMicroService { internal class SmsSentEvent { + public required bool SmsSent { get; set; } public required string PhoneNumber { get; set; } public required string SmsText { get; set; } public required DateTime Timestamp { get; set; } From 53b7a3319519de0577b7b5aeca72773698ea72b9 Mon Sep 17 00:00:00 2001 From: rohitkrsoni Date: Fri, 26 Apr 2024 04:48:04 +0930 Subject: [PATCH 3/7] Changed access modifiers and added test project --- SMSMicroService.sln | 6 +++ .../Implementations/ConsoleLogger.cs | 2 +- SMSMicroService/Implementations/EventBus.cs | 2 +- .../Implementations/MessageQueue.cs | 2 +- SMSMicroService/Interfaces/IEventBus.cs | 2 +- SMSMicroService/Interfaces/ILogger.cs | 2 +- SMSMicroService/Interfaces/IMessageQueue.cs | 2 +- SMSMicroService/SMSMicroService.csproj | 4 ++ SMSMicroService/SendSmsCommand.cs | 2 +- SMSMicroService/SmsMicroservice.cs | 5 +- SMSMicroService/SmsSentEvent.cs | 2 +- .../SmsMicroservice.Tests.csproj | 27 +++++++++++ SmsMicroservice.Tests/SmsServiceTests.cs | 47 +++++++++++++++++++ 13 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 SmsMicroservice.Tests/SmsMicroservice.Tests.csproj create mode 100644 SmsMicroservice.Tests/SmsServiceTests.cs diff --git a/SMSMicroService.sln b/SMSMicroService.sln index 372ed2f..84d10fb 100644 --- a/SMSMicroService.sln +++ b/SMSMicroService.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.9.34728.123 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMSMicroService", "SMSMicroService\SMSMicroService.csproj", "{7C478F74-3D1C-4897-8F18-D6ABA883E53C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmsMicroservice.Tests", "SmsMicroservice.Tests\SmsMicroservice.Tests.csproj", "{258FD611-0DFB-48B9-84B4-19EC5DB6185D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {7C478F74-3D1C-4897-8F18-D6ABA883E53C}.Debug|Any CPU.Build.0 = Debug|Any CPU {7C478F74-3D1C-4897-8F18-D6ABA883E53C}.Release|Any CPU.ActiveCfg = Release|Any CPU {7C478F74-3D1C-4897-8F18-D6ABA883E53C}.Release|Any CPU.Build.0 = Release|Any CPU + {258FD611-0DFB-48B9-84B4-19EC5DB6185D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {258FD611-0DFB-48B9-84B4-19EC5DB6185D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {258FD611-0DFB-48B9-84B4-19EC5DB6185D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {258FD611-0DFB-48B9-84B4-19EC5DB6185D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SMSMicroService/Implementations/ConsoleLogger.cs b/SMSMicroService/Implementations/ConsoleLogger.cs index ec53daa..2aea94a 100644 --- a/SMSMicroService/Implementations/ConsoleLogger.cs +++ b/SMSMicroService/Implementations/ConsoleLogger.cs @@ -7,7 +7,7 @@ namespace SMSMicroService.Implementations { - internal class ConsoleLogger: ILogger + public class ConsoleLogger: ILogger { public void Log(string message) { diff --git a/SMSMicroService/Implementations/EventBus.cs b/SMSMicroService/Implementations/EventBus.cs index 63f32fb..36220b5 100644 --- a/SMSMicroService/Implementations/EventBus.cs +++ b/SMSMicroService/Implementations/EventBus.cs @@ -3,7 +3,7 @@ namespace SMSMicroService.Implementations { - internal class EventBus: IEventBus + public class EventBus: IEventBus { private readonly List _publishedEvents; diff --git a/SMSMicroService/Implementations/MessageQueue.cs b/SMSMicroService/Implementations/MessageQueue.cs index 1a923b4..8b6e5a7 100644 --- a/SMSMicroService/Implementations/MessageQueue.cs +++ b/SMSMicroService/Implementations/MessageQueue.cs @@ -4,7 +4,7 @@ namespace SMSMicroService.Implementations { - internal class MessageQueue: IMessageQueue + public class MessageQueue: IMessageQueue { private readonly ConcurrentQueue _queue; diff --git a/SMSMicroService/Interfaces/IEventBus.cs b/SMSMicroService/Interfaces/IEventBus.cs index 02243e9..19b933d 100644 --- a/SMSMicroService/Interfaces/IEventBus.cs +++ b/SMSMicroService/Interfaces/IEventBus.cs @@ -6,7 +6,7 @@ namespace SMSMicroService.Interfaces { - internal interface IEventBus + public interface IEventBus { Task PublishEventAsync(T @event); } diff --git a/SMSMicroService/Interfaces/ILogger.cs b/SMSMicroService/Interfaces/ILogger.cs index a8cea5a..05003e9 100644 --- a/SMSMicroService/Interfaces/ILogger.cs +++ b/SMSMicroService/Interfaces/ILogger.cs @@ -6,7 +6,7 @@ namespace SMSMicroService.Interfaces { - internal interface ILogger + public interface ILogger { void Log(string message); } diff --git a/SMSMicroService/Interfaces/IMessageQueue.cs b/SMSMicroService/Interfaces/IMessageQueue.cs index fce71b4..351fbe4 100644 --- a/SMSMicroService/Interfaces/IMessageQueue.cs +++ b/SMSMicroService/Interfaces/IMessageQueue.cs @@ -6,7 +6,7 @@ namespace SMSMicroService.Interfaces { - internal interface IMessageQueue + public interface IMessageQueue { Task ReceiveMessageAsync(); public void SendMessage(T message); diff --git a/SMSMicroService/SMSMicroService.csproj b/SMSMicroService/SMSMicroService.csproj index 2150e37..e976d42 100644 --- a/SMSMicroService/SMSMicroService.csproj +++ b/SMSMicroService/SMSMicroService.csproj @@ -7,4 +7,8 @@ enable + + + + diff --git a/SMSMicroService/SendSmsCommand.cs b/SMSMicroService/SendSmsCommand.cs index db0b5f0..ed3cd11 100644 --- a/SMSMicroService/SendSmsCommand.cs +++ b/SMSMicroService/SendSmsCommand.cs @@ -1,6 +1,6 @@ namespace SMSMicroService { - internal class SendSmsCommand + public class SendSmsCommand { public required string PhoneNumber { get; set; } public required string SmsText { get; set; } diff --git a/SMSMicroService/SmsMicroservice.cs b/SMSMicroService/SmsMicroservice.cs index ac0cbcb..8ed3d0f 100644 --- a/SMSMicroService/SmsMicroservice.cs +++ b/SMSMicroService/SmsMicroservice.cs @@ -2,13 +2,12 @@ namespace SMSMicroService { - internal class SmsMicroservice + public class SmsMicroservice { private readonly IMessageQueue _messageQueue; private readonly IEventBus _eventBus; private readonly ILogger _logger; - - public SmsMicroservice(IMessageQueue messageQueue, IEventBus eventBus, ILogger logger) + public SmsMicroservice(IMessageQueue messageQueue, IEventBus eventBus, ILogger logger) { _messageQueue = messageQueue; _eventBus = eventBus; diff --git a/SMSMicroService/SmsSentEvent.cs b/SMSMicroService/SmsSentEvent.cs index 787421f..2782e67 100644 --- a/SMSMicroService/SmsSentEvent.cs +++ b/SMSMicroService/SmsSentEvent.cs @@ -6,7 +6,7 @@ namespace SMSMicroService { - internal class SmsSentEvent + public class SmsSentEvent { public required bool SmsSent { get; set; } public required string PhoneNumber { get; set; } diff --git a/SmsMicroservice.Tests/SmsMicroservice.Tests.csproj b/SmsMicroservice.Tests/SmsMicroservice.Tests.csproj new file mode 100644 index 0000000..7269cb5 --- /dev/null +++ b/SmsMicroservice.Tests/SmsMicroservice.Tests.csproj @@ -0,0 +1,27 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + diff --git a/SmsMicroservice.Tests/SmsServiceTests.cs b/SmsMicroservice.Tests/SmsServiceTests.cs new file mode 100644 index 0000000..8d1acb0 --- /dev/null +++ b/SmsMicroservice.Tests/SmsServiceTests.cs @@ -0,0 +1,47 @@ +using SMSMicroService; +using SMSMicroService.Implementations; + +namespace SmsMicroservice.Tests +{ + public class SmsMicroserviceTests + { + private readonly SMSMicroService.SmsMicroservice _smsMicroservice; + private readonly EventBus _eventBus; + + + public SmsMicroserviceTests() + { + _eventBus = new EventBus(); + _smsMicroservice = new SMSMicroService.SmsMicroservice(new MessageQueue(), _eventBus, new ConsoleLogger()); + } + + private async Task InvokeSendSmsAsync(SendSmsCommand command) + { + var methodInfo = typeof(SMSMicroService.SmsMicroservice).GetMethod("SendSmsAsync", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + return await (Task)methodInfo.Invoke(_smsMicroservice, [command]); + } + + [Fact] + public async Task SendSmsAsync_ValidCommand_ReturnsSmsSentEvent() + { + // Arrange + var command = new SendSmsCommand + { + PhoneNumber = "7001239875", + SmsText = "Hello from Test Project" + }; + + // Act + var result = await InvokeSendSmsAsync(command); + + // Assert + Assert.NotNull(result); + Assert.Equal(command.PhoneNumber, result.PhoneNumber); + Assert.Equal(command.SmsText, result.SmsText); + } + + + + + } +} From 2165c7af255031af46337043f739b2ded2bc5f2e Mon Sep 17 00:00:00 2001 From: rohitkrsoni Date: Sat, 27 Apr 2024 11:35:04 +0930 Subject: [PATCH 4/7] Added Test for event bus --- SMSMicroService/Implementations/EventBus.cs | 5 +++++ SMSMicroService/Implementations/MessageQueue.cs | 4 ++-- SmsMicroservice.Tests/SmsServiceTests.cs | 17 ++++++++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/SMSMicroService/Implementations/EventBus.cs b/SMSMicroService/Implementations/EventBus.cs index 36220b5..4721910 100644 --- a/SMSMicroService/Implementations/EventBus.cs +++ b/SMSMicroService/Implementations/EventBus.cs @@ -19,5 +19,10 @@ public async Task PublishEventAsync(T evt) } await Task.Delay(0); } + + public List GetPublishedEvents() + { + return _publishedEvents; + } } } diff --git a/SMSMicroService/Implementations/MessageQueue.cs b/SMSMicroService/Implementations/MessageQueue.cs index 8b6e5a7..32e8c86 100644 --- a/SMSMicroService/Implementations/MessageQueue.cs +++ b/SMSMicroService/Implementations/MessageQueue.cs @@ -30,7 +30,7 @@ public async Task ReceiveMessageAsync() { return (T)message; } - await Task.Delay(1000); // Adjust delay according to your requirement + await Task.Delay(1000); } } @@ -41,7 +41,7 @@ public void StartAddingRandomMessagesAsync() var phoneNumber = PhoneNumberHelper.GenerateRandomPhoneNumber(); var smsText = TextMessageHelper.GenerateRandomTextMessage(); SendMessage(new SendSmsCommand { PhoneNumber = phoneNumber, SmsText = smsText }); - Thread.Sleep(1500); // Adjust delay according to your requirement + Thread.Sleep(1500); } } } diff --git a/SmsMicroservice.Tests/SmsServiceTests.cs b/SmsMicroservice.Tests/SmsServiceTests.cs index 8d1acb0..a5aa253 100644 --- a/SmsMicroservice.Tests/SmsServiceTests.cs +++ b/SmsMicroservice.Tests/SmsServiceTests.cs @@ -36,12 +36,27 @@ public async Task SendSmsAsync_ValidCommand_ReturnsSmsSentEvent() // Assert Assert.NotNull(result); + Assert.True(result.SmsSent); Assert.Equal(command.PhoneNumber, result.PhoneNumber); Assert.Equal(command.SmsText, result.SmsText); } + [Fact] + public async Task PublishEventAsync_AddsEventToList() + { + // Arrange + var testEvent = new SmsSentEvent() { + SmsSent=true, + PhoneNumber="7006789876", + SmsText="Hello from test", + Timestamp=DateTime.Now + }; + // Act + await _eventBus.PublishEventAsync(testEvent); - + // Assert + Assert.Contains(testEvent, _eventBus.GetPublishedEvents()); + } } } From f00562a814e5234bc2c5b201d349d345982960e8 Mon Sep 17 00:00:00 2001 From: rohitkrsoni Date: Sun, 28 Apr 2024 20:25:22 +0930 Subject: [PATCH 5/7] Added readme file --- Readme.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Readme.md diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..c518eb7 --- /dev/null +++ b/Readme.md @@ -0,0 +1,59 @@ +# SMS Microservice + +The SMS Microservice is a simple microservice that acts as a wrapper around the API for a third-party SMS service. It listens for `SendSms` commands on a message queue, sends an HTTP request to the third-party SMS service, and then publishes an `SmsSent` event to a global event bus upon successful SMS delivery. + +## How to Build and Run the Application + +1. **Download the Files**: + +2. **Open the solution file**: + + - Navigate to the `SMSMicroservice` directory. + - Open the `SMSMicroservice.sln` solution file in Visual Studio. + +3. **Build the solution**: + + - Build the solution by clicking on the "Build" menu and selecting "Build Solution", or by pressing `Ctrl+Shift+B`. + +4. **Run the application**: + + - Open the `Program.cs` file in the `SMSMicroservice` project. + - Run the `Main` method. + +## How to Run Tests + +1. **Open the solution file**: + + - Navigate to the `SMSMicroservice` directory. + - Open the `SMSMicroservice.sln` solution file in Visual Studio. + +2. **Run the tests**: + + - Open the Test Explorer window by clicking on "Test" > "Test Explorer" from the top menu. + - Run all tests by clicking on "Run All" in the Test Explorer window. + +## Additional Information + +### Components Used + +- `IMessageQueue`: Interface for the message queue. +- `IEventBus`: Interface for the event bus. +- `ILogger`: Interface for the logger. +- `MessageQueue`: Concrete implementation of `IMessageQueue`. +- `EventBus`: Concrete implementation of `IEventBus`. +- `ConsoleLogger`: Concrete implementation of `ILogger`. +- `SendSmsCommand`: Command class for sending SMS. +- `SmsSentEvent`: Event class for successful SMS delivery. + +### Features + +- Asynchronous message-based communication. +- Reliable SMS delivery using an async flow. +- Basic error handling and logging. + +### Next Steps + +- Implement concrete implementations for the message queue, event bus, and logger. +- Write more extensive tests for the application logic. +- Implement retry logic for failed SMS deliveries. +- Improve error handling to handle edge cases and ensure graceful degradation. From fb66a154215cfe91849a3ec1da201a4887803c21 Mon Sep 17 00:00:00 2001 From: rohitkrsoni Date: Sat, 4 May 2024 04:47:06 +0930 Subject: [PATCH 6/7] Added tests for eventBus --- SmsMicroservice.Tests/EventBusTests.cs | 52 ++++++++++++++++++++++++ SmsMicroservice.Tests/SmsServiceTests.cs | 32 ++++++++------- 2 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 SmsMicroservice.Tests/EventBusTests.cs diff --git a/SmsMicroservice.Tests/EventBusTests.cs b/SmsMicroservice.Tests/EventBusTests.cs new file mode 100644 index 0000000..fc3167b --- /dev/null +++ b/SmsMicroservice.Tests/EventBusTests.cs @@ -0,0 +1,52 @@ +using SMSMicroService; +using SMSMicroService.Implementations; + +namespace SmsMicroservice.Tests +{ + public class EventBusTests + { + private readonly EventBus _eventBus; + public EventBusTests() { + _eventBus = new EventBus(); + } + + [Fact] + public async Task PublishEventAsync_AddsSuccessEventToList() + { + // Arrange + var testEvent = new SmsSentEvent() + { + SmsSent = true, + PhoneNumber = "7006789876", + SmsText = "Hello from test", + Timestamp = DateTime.Now + }; + + // Act + await _eventBus.PublishEventAsync(testEvent); + + // Assert + Assert.Contains(testEvent, _eventBus.GetPublishedEvents()); + } + + [Fact] + public async Task PublishEventAsync_AddsFailureEventToList() + { + // Arrange + var testEvent = new SmsSentEvent() + { + SmsSent = false, + PhoneNumber = "7006789876", + SmsText = "Hello from test", + Timestamp = DateTime.Now + }; + + // Act + await _eventBus.PublishEventAsync(testEvent); + + // Assert + Assert.Contains(testEvent, _eventBus.GetPublishedEvents()); + } + + } +} diff --git a/SmsMicroservice.Tests/SmsServiceTests.cs b/SmsMicroservice.Tests/SmsServiceTests.cs index a5aa253..02f8386 100644 --- a/SmsMicroservice.Tests/SmsServiceTests.cs +++ b/SmsMicroservice.Tests/SmsServiceTests.cs @@ -41,22 +41,24 @@ public async Task SendSmsAsync_ValidCommand_ReturnsSmsSentEvent() Assert.Equal(command.SmsText, result.SmsText); } - [Fact] - public async Task PublishEventAsync_AddsEventToList() - { - // Arrange - var testEvent = new SmsSentEvent() { - SmsSent=true, - PhoneNumber="7006789876", - SmsText="Hello from test", - Timestamp=DateTime.Now - }; + [Fact] + public async Task SendSmsAsync_InValidCommand_ReturnsSmsSentEvent() + { + // Arrange + var command = new SendSmsCommand + { + PhoneNumber = "1234567890", // Invalid PhoneNumber + SmsText = "Hello from ABC!" // Invalid TextMessage + }; - // Act - await _eventBus.PublishEventAsync(testEvent); + // Act + var result = await InvokeSendSmsAsync(command); - // Assert - Assert.Contains(testEvent, _eventBus.GetPublishedEvents()); - } + // Assert + Assert.NotNull(result); + Assert.False(result.SmsSent); + Assert.Equal(command.PhoneNumber, result.PhoneNumber); + Assert.Equal(command.SmsText, result.SmsText); + } } } From f87b68e1a2b7a1898a72d53a2484ae32fc082efe Mon Sep 17 00:00:00 2001 From: rohitkrsoni Date: Wed, 10 Jul 2024 22:18:15 +0930 Subject: [PATCH 7/7] fix for dotnet 7.0 and removed warning --- SmsMicroservice.Tests/SmsServiceTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SmsMicroservice.Tests/SmsServiceTests.cs b/SmsMicroservice.Tests/SmsServiceTests.cs index 02f8386..0ea0d60 100644 --- a/SmsMicroservice.Tests/SmsServiceTests.cs +++ b/SmsMicroservice.Tests/SmsServiceTests.cs @@ -18,10 +18,11 @@ public SmsMicroserviceTests() private async Task InvokeSendSmsAsync(SendSmsCommand command) { var methodInfo = typeof(SMSMicroService.SmsMicroservice).GetMethod("SendSmsAsync", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - return await (Task)methodInfo.Invoke(_smsMicroservice, [command]); - } + var task = methodInfo != null ? methodInfo.Invoke(_smsMicroservice, new object[] { command }) as Task : throw new MethodAccessException("Method not found"); + return task == null ? throw new InvalidOperationException("Command should not be NULL") : await task; + } - [Fact] + [Fact] public async Task SendSmsAsync_ValidCommand_ReturnsSmsSentEvent() { // Arrange