Merge pull request #35 from Havret/ping_pong_benchmark

NO-JIRA: Pingpong benchmark
diff --git a/apache-nms-amqp.sln b/apache-nms-amqp.sln
index 4898062..8cc386e 100644
--- a/apache-nms-amqp.sln
+++ b/apache-nms-amqp.sln
@@ -19,6 +19,10 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache-NMS-AMQP-Interop-Test", "test\Apache-NMS-AMQP-Interop-Test\Apache-NMS-AMQP-Interop-Test.csproj", "{E5D009CB-7DDD-4C49-B7EB-361D42D0BF14}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmark", "benchmark", "{C0489CE7-BB93-48A6-A136-26FA942DB990}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PingPong", "src\PingPong\PingPong.csproj", "{CA6094FA-B615-47E6-A5D5-224BE62CDF70}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -101,6 +105,18 @@
 		{E5D009CB-7DDD-4C49-B7EB-361D42D0BF14}.Release|x64.Build.0 = Release|Any CPU
 		{E5D009CB-7DDD-4C49-B7EB-361D42D0BF14}.Release|x86.ActiveCfg = Release|Any CPU
 		{E5D009CB-7DDD-4C49-B7EB-361D42D0BF14}.Release|x86.Build.0 = Release|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Debug|x64.Build.0 = Debug|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Debug|x86.Build.0 = Debug|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Release|x64.ActiveCfg = Release|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Release|x64.Build.0 = Release|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Release|x86.ActiveCfg = Release|Any CPU
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -112,5 +128,6 @@
 		{A56349BE-ED66-4E18-B5FE-E3EA069D2ADD} = {19D7C0B5-0D2B-4459-BE75-6DD353857B28}
 		{08936343-AA11-4409-9599-06762070CF82} = {19D7C0B5-0D2B-4459-BE75-6DD353857B28}
 		{846D7B8A-49F5-408E-9189-402F4A90912D} = {19D7C0B5-0D2B-4459-BE75-6DD353857B28}
+		{CA6094FA-B615-47E6-A5D5-224BE62CDF70} = {C0489CE7-BB93-48A6-A136-26FA942DB990}
 	EndGlobalSection
 EndGlobal
diff --git a/src/PingPong/Ping.cs b/src/PingPong/Ping.cs
new file mode 100644
index 0000000..888f4a9
--- /dev/null
+++ b/src/PingPong/Ping.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using Apache.NMS;
+
+namespace PingPong
+{
+    public class Ping: IDisposable
+    {
+        private readonly IConnection connection;
+        private readonly ISession session;
+        private readonly IMessageProducer messageProducer;
+        private readonly IMessageConsumer messageConsumer;
+        private readonly Stopwatch stopwatch;
+        private readonly ITextMessage pingMessage;
+        private TaskCompletionSource<Stats> tsc;
+        private int numberOfMessages;
+        private int skipMessages;
+        private int counter;
+
+        public Ping(IConnectionFactory connectionFactory)
+        {
+            this.connection = connectionFactory.CreateConnection();
+            this.session = this.connection.CreateSession();
+            this.messageProducer = session.CreateProducer(session.GetTopic("ping"));
+            this.messageConsumer = session.CreateConsumer(session.GetTopic("pong"));
+            this.messageConsumer.Listener += OnMessage;
+            this.stopwatch = new Stopwatch();
+            this.pingMessage = session.CreateTextMessage("Ping");
+            this.connection.Start();
+        }
+
+        private void OnMessage(IMessage message)
+        {
+            if (skipMessages > 0)
+                skipMessages--;
+            else
+                counter++;
+
+            if (counter == numberOfMessages)
+            {
+                stopwatch.Stop();
+                this.tsc.SetResult(new Stats { MessagesCount = counter, Elapsed = stopwatch.Elapsed });                
+            }
+            else
+            {
+                messageProducer.Send(pingMessage);
+            }
+        }
+
+        public Task<Stats> Start(int numberOfMessages, int skipMessages)
+        {
+            this.numberOfMessages = numberOfMessages;
+            this.skipMessages = skipMessages;
+            this.tsc = new TaskCompletionSource<Stats>();
+            stopwatch.Start();
+            messageProducer.Send(pingMessage);
+            return this.tsc.Task;
+        }
+
+        public void Dispose()
+        {
+            connection?.Dispose();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/PingPong/PingPong.csproj b/src/PingPong/PingPong.csproj
new file mode 100644
index 0000000..f5ec638
--- /dev/null
+++ b/src/PingPong/PingPong.csproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\NMS.AMQP\Apache-NMS-AMQP.csproj" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/PingPong/Pong.cs b/src/PingPong/Pong.cs
new file mode 100644
index 0000000..55f955e
--- /dev/null
+++ b/src/PingPong/Pong.cs
@@ -0,0 +1,35 @@
+using System;
+using Apache.NMS;
+
+namespace PingPong
+{
+    public class Pong : IDisposable
+    {
+        private readonly IConnection connection;
+        private readonly ISession session;
+        private readonly IMessageProducer messageProducer;
+        private readonly IMessageConsumer messageConsumer;
+        private readonly ITextMessage pongMessage;
+
+        public Pong(IConnectionFactory connectionFactory)
+        {
+            this.connection = connectionFactory.CreateConnection();
+            this.session = this.connection.CreateSession();
+            this.messageProducer = session.CreateProducer(session.GetTopic("pong"));
+            this.messageConsumer = session.CreateConsumer(session.GetTopic("ping"));
+            this.messageConsumer.Listener += OnMessage;
+            this.pongMessage = session.CreateTextMessage("Pong");
+            this.connection.Start();
+        }
+
+        private void OnMessage(IMessage message)
+        {
+            this.messageProducer.Send(pongMessage);
+        }
+
+        public void Dispose()
+        {
+            connection?.Dispose();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/PingPong/Program.cs b/src/PingPong/Program.cs
new file mode 100644
index 0000000..0054f57
--- /dev/null
+++ b/src/PingPong/Program.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Threading.Tasks;
+using Apache.NMS.AMQP;
+
+namespace PingPong
+{
+    class Program
+    {
+        static async Task Main(string[] args)
+        {
+            var connectionFactory = new NmsConnectionFactory();
+            connectionFactory.UserName = "artemis";
+            connectionFactory.Password = "simetraehcapa";
+
+            using (var ping = new Ping(connectionFactory))
+            using (new Pong(connectionFactory))
+            {
+                var stats = await ping.Start(skipMessages: 100, numberOfMessages: 10000);
+                Console.WriteLine(stats);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/PingPong/Stats.cs b/src/PingPong/Stats.cs
new file mode 100644
index 0000000..5d5c201
--- /dev/null
+++ b/src/PingPong/Stats.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace PingPong
+{
+    public class Stats
+    {
+        public int MessagesCount { get; set; }
+        public TimeSpan Elapsed { get; set; }
+
+        public override string ToString()
+        {
+            return $"Sent {MessagesCount} msg in {Elapsed.TotalMilliseconds:F2}ms -- {MessagesCount / Elapsed.TotalSeconds:F2} msg/s";
+        }
+    }
+}
\ No newline at end of file