public void cancel_should_not_cancel_others()
        {
            var bus     = new CommandBus("local");
            var handler = new CancelableTestCommandHandler();

            bus.Subscribe((IHandleCommand <TestCommands.TestCommand>)handler);
            bus.Subscribe((IHandleCommand <TestCommands.TestCommand2>)handler);
            var handler2 = new TestCommandHandler();

            bus.Subscribe((IHandleCommand <TestCommands.TestCommand3>)handler2);
            var cmd1 = new TestCommands.TestCommand(Guid.NewGuid(), null);
            var cmd2 = new TestCommands.TestCommand2(Guid.NewGuid(), null);
            var cmd3 = new TestCommands.TestCommand3(Guid.NewGuid(), null);

            Task.Delay(100).ContinueWith(t => bus.RequestCancel(cmd1));
            Task.Run(() => bus.Fire(cmd2));
            Task.Run(() => bus.Fire(cmd3));
            Assert.Throws <CommandCanceledException>(
                () =>
            {
                try
                {
                    bus.Fire(cmd1);
                }
                catch (Exception ex)
                {
                    throw ex.InnerException;
                }
            });
        }
        public void unsubscribe_should_not_remove_other_handlers()
        {
            var  bus           = new CommandBus("local");
            long proccessedCmd = 0;
            var  hndl          = new AdHocCommandHandler <TestCommands.TestCommand>(
                cmd =>
            {
                Interlocked.Increment(ref proccessedCmd);
                return(true);
            });

            bus.Subscribe(hndl);
            bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand2>(
                              cmd =>
            {
                Interlocked.Increment(ref proccessedCmd);
                return(true);
            }));
            bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null));
            bus.Unsubscribe(hndl);
            Assert.Throws <CommandNotHandledException>(
                () => bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null)));

            bus.Fire(new TestCommands.TestCommand2(Guid.NewGuid(), null));
            Assert.IsOrBecomesTrue(
                () => Interlocked.Read(ref proccessedCmd) == 2,
                msg: "Expected command handled twice, got" + proccessedCmd);
        }
        public void concurrent_commands_should_pass()
        {
            var  bus        = new CommandBus("local", slowCmdThreshold: TimeSpan.FromMilliseconds(50));
            long gotSuccess = 0;
            long gotFail    = 0;
            long gotTimeout = 0;
            Func <Command, bool> testAction        = cmd => { Interlocked.Increment(ref gotSuccess); return(true); };
            Func <Command, bool> testFailAction    = cmd => { Interlocked.Increment(ref gotFail); return(true); };
            Func <Command, bool> testTimeoutAction = cmd =>
            {
                Interlocked.Increment(ref gotTimeout);
                Thread.Sleep(55); //timeout == 50 ms
                return(true);
            };

            Parallel.Invoke(
                () => bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(testAction)),
                () => bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand2>(testTimeoutAction)),
                () => bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand3>(testFailAction))
                );
            Assert.True(gotSuccess == 0, $"gotSuccess should be 0, found { gotSuccess}");
            for (int i = 0; i < 50; i++)
            {
                Parallel.Invoke(
                    () => bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null)),
                    () => bus.TryFire(new TestCommands.TestCommand2(Guid.NewGuid(), null)),
                    () => bus.TryFire(new TestCommands.TestCommand3(Guid.NewGuid(), null)));
            }

            Assert.True(gotSuccess == 50, $"gotSuccess should be 50, found { gotSuccess}");
            Assert.True(gotFail == 50, $"gotFail should be 50, found { gotFail}");
            Assert.True(gotTimeout == 50, $"gotTimeout should be 50, found { gotTimeout}");
        }
        public void handlers_that_throw_exceptions_rethrow_on_fire()
        {
            var bus = new CommandBus("local");

            long gotCmd      = 0;
            long gotResponse = 0;
            long gotAck      = 0;
            long msgCount    = 0;

            bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(
                              cmd =>
            {
                Interlocked.Exchange(ref gotCmd, 1);
                throw new CommandException("I knew this would happen.", cmd);
            },
                              wrapExceptions: false));

            bus.Subscribe(new AdHocHandler <CommandResponse>(
                              cmd => Interlocked.Exchange(ref gotResponse, 1)));

            bus.Subscribe(new AdHocHandler <AckCommand>(
                              cmd => Interlocked.Exchange(ref gotAck, 1)));

            bus.Subscribe(new AdHocHandler <Message>(
                              cmd => Interlocked.Increment(ref msgCount)));

            Assert.Throws <CommandException>(() =>
                                             bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null)));

            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref msgCount) == 3, null, "Expected 3 Messages");
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotAck) == 1, null, "Expected Ack");
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd) == 1, null, "Expected Command was handled");
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotResponse) == 1, null, "Expected Response");
        }
        public void slow_commands_should_throw_timeout()
        {
            var  bus             = new CommandBus("local");
            long gotCmd1         = 0;
            long cancelRecieved  = 0;
            long cancelPublished = 0;

            bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(
                              cmd =>
            {
                Interlocked.Exchange(ref gotCmd1, 1);
                Task.Delay(1000).Wait();
                return(true);
            },
                              (cancel, currentCmdId) =>
            {
                if (cancel.CommandType == typeof(TestCommands.TestCommand) &&
                    (currentCmdId == cancel.CommandId))
                {
                    Interlocked.Increment(ref cancelRecieved);
                }
                return(Unit.Default);
            }));
            bus.Subscribe(new AdHocHandler <CancelCommand>(c => Interlocked.Increment(ref cancelPublished)));

            Assert.Throws <CommandTimedOutException>(() =>
                                                     bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null)));
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd1) == 1, msg: "Expected Cmd1 handled");
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref cancelPublished) == 1, msg: "Expected cancel published");
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref cancelRecieved) == 1, msg: "Expected cancel received");
        }
        public void command_handler_respondes_to_command_message()
        {
            var  bus         = new CommandBus("temp");
            long gotCmd      = 0;
            long gotResponse = 0;
            long gotAck      = 0;
            long msgCount    = 0;

            bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(
                              cmd =>
            {
                Interlocked.Exchange(ref gotCmd, 1);
                return(true);
            }));

            bus.Subscribe(new AdHocHandler <CommandResponse>(
                              cmd => Interlocked.Exchange(ref gotResponse, 1)));

            bus.Subscribe(new AdHocHandler <AckCommand>(
                              cmd => Interlocked.Exchange(ref gotAck, 1)));

            bus.Subscribe(new AdHocHandler <Message>(
                              cmd => Interlocked.Increment(ref msgCount)));

            bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null));

            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref msgCount) == 3, null, "Expected 3 Messages");
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotAck) == 1, null, "Expected Ack");
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd) == 1, null, "Expected Command was handled");
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotResponse) == 1, null, "Expected Response");
        }
        public void unsubscribed_commands_should_throw_ack_timeout()
        {
            var  bus             = new CommandBus("local");
            long cancelPublished = 0;

            bus.Subscribe(new AdHocHandler <CancelCommand>(c => Interlocked.Increment(ref cancelPublished)));
            Assert.Throws <CommandNotHandledException>(() =>
                                                       bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null)));
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref cancelPublished) == 1, msg: "Expected cancel published");
        }
        public void fire_failing_command_should_fail()
        {
            var  bus     = new CommandBus("local");
            long gotFail = 0;

            bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(cmd => false));
            bus.Subscribe(new AdHocHandler <Fail>(cmd => Interlocked.Exchange(ref gotFail, 1)));
            Assert.Throws <CommandException>(
                () => bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null)));
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotFail) == 1, null, "Expected Fail");
        }
        public void unsubscribed_commands_should_throw_ack_timeout()
        {
            var  bus = new CommandBus("local");
            long publishedMessageCount = 0;

            bus.Subscribe(new AdHocHandler <Message>(c => Interlocked.Increment(ref publishedMessageCount)));
            Assert.Throws <CommandNotHandledException>(() =>
                                                       bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null)));

            Assert.True(Interlocked.Read(ref publishedMessageCount) == 0, userMessage: "Expected no messages published");
        }
        public void noncancelable_commands_will_ignore_cancel()
        {
            var bus     = new CommandBus("local");
            var handler = new TestCommandHandler();

            bus.Subscribe((IHandleCommand <TestCommands.TestCommand3>)handler);
            var cmd = new TestCommands.TestCommand3(Guid.NewGuid(), null);

            Task.Delay(100).ContinueWith(t => bus.RequestCancel(cmd));

            bus.Fire(cmd);
        }
        public void fire_publishes_command_as_message()
        {
            var  bus   = new CommandBus("temp");
            long gotIt = 0;

            bus.Subscribe(new AdHocHandler <Command>(
                              cmd => { if (cmd is TestCommands.TestCommand)
                                       {
                                           Interlocked.Exchange(ref gotIt, 1);
                                       }
                              }));
            bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(cmd => true));
            bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null));
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotIt) == 1);
        }
        public void fire_passing_command_should_pass()
        {
            var bus = new CommandBus("local");

            long gotSuccess = 0;
            long gotFail    = 0;
            long gotCancel  = 0;

            bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(cmd => true));
            bus.Subscribe(new AdHocHandler <Success>(cmd => Interlocked.Exchange(ref gotSuccess, 1)));
            bus.Subscribe(new AdHocHandler <Fail>(cmd => Interlocked.Exchange(ref gotFail, 1)));
            bus.Subscribe(new AdHocHandler <Canceled>(cmd => Interlocked.Exchange(ref gotCancel, 1)));
            bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null));
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotSuccess) == 1, null, "Expected Success");
            Assert.True(gotFail == 0, "Unexpected fail received.");
            Assert.True(gotCancel == 0, "Unexpected Cancel received.");
        }
        public void command_handler_acks_command_message()
        {
            var  bus    = new CommandBus("temp");
            long gotCmd = 0;
            long gotAck = 0;
            var  hndl   =
                new AdHocCommandHandler <TestCommands.TestCommand>(
                    cmd => Interlocked.Exchange(ref gotCmd, 1) == 0);

            bus.Subscribe(hndl);
            var ackHndl =
                new AdHocHandler <AckCommand>(
                    cmd => Interlocked.Exchange(ref gotAck, 1));

            bus.Subscribe(ackHndl);
            bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null));
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotAck) == 1);
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd) == 1);
        }
        public void typed_fire_passing_command_should_pass()
        {
            var       bus  = new CommandBus("local");
            const int data = 12356;

            long gotResponse  = 0;
            long responseData = 0;

            bus.Subscribe(new AdHocTypedCommandHandler <TestCommands.TypedTestCommand, TestCommands.TestCommandResponse>(
                              cmd => new TestCommands.TestCommandResponse(cmd, data)));
            bus.Subscribe(new AdHocHandler <TestCommands.TestCommandResponse>(
                              cmd =>
            {
                Interlocked.Exchange(ref gotResponse, 1);
                Interlocked.Exchange(ref responseData, cmd.Data);
            }
                              ));

            bus.Fire(new TestCommands.TypedTestCommand(Guid.NewGuid(), null));
            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotResponse) == 1, null, "Expected Success");
            Assert.IsOrBecomesTrue(() => data == responseData);
        }
        public void cancelable_commands_can_be_canceled()
        {
            var bus     = new CommandBus("local");
            var handler = new CancelableTestCommandHandler();

            bus.Subscribe((IHandleCommand <TestCommands.TestCommand>)handler);
            var cmd = new TestCommands.TestCommand(Guid.NewGuid(), null);

            Task.Delay(100).ContinueWith(t => bus.RequestCancel(cmd));

            Assert.Throws <CommandCanceledException>(
                () =>
            {
                try
                {
                    bus.Fire(cmd);
                }
                catch (Exception ex)
                {
                    throw ex.InnerException;
                }
            });
        }
        public void fire_oversubscribed_commands_should_throw_oversubscribed()
        {
            var  bus           = new CommandBus("local");
            var  bus2          = new CommandBus("remote");
            var  conn          = new BusConnector(bus, bus2);
            long proccessedCmd = 0;
            long gotAck        = 0;

            bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(
                              cmd =>
            {
                Interlocked.Increment(ref proccessedCmd);
                Task.Delay(1000).Wait();
                return(true);
            }));
            bus2.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(
                               cmd =>
            {
                Interlocked.Increment(ref proccessedCmd);
                Task.Delay(100).Wait();
                return(true);
            }));
            bus.Subscribe(
                new AdHocHandler <AckCommand>(cmd => Interlocked.Increment(ref gotAck)));

            Assert.Throws <CommandOversubscribedException>(() =>
                                                           bus.Fire(new TestCommands.TestCommand(Guid.NewGuid(), null)));

            Assert.IsOrBecomesTrue(
                () => Interlocked.Read(ref gotAck) == 2,
                msg: "Expected command Acked twice, got " + gotAck);

            Assert.IsOrBecomesTrue(
                () => Interlocked.Read(ref proccessedCmd) <= 1,
                msg: "Expected command handled once or less, actual " + proccessedCmd);
        }
        public void typed_failing_fire_command_should_fail()
        {
            var          bus          = new CommandBus("local");
            const int    data         = 12356;
            const string errText      = @"I knew this would happen.";
            long         gotResponse  = 0;
            long         responseData = 0;

            bus.Subscribe(new AdHocTypedCommandHandler <TestCommands.TypedTestCommand, TestCommands.TestFailedCommandResponse>(
                              cmd => new TestCommands.TestFailedCommandResponse(cmd, new CommandException(errText, cmd), data)));
            bus.Subscribe(new AdHocHandler <TestCommands.TestFailedCommandResponse>(
                              cmd =>
            {
                Interlocked.Exchange(ref gotResponse, 1);
                Interlocked.Exchange(ref responseData, cmd.Data);
            }
                              ));

            Assert.Throws <CommandException>(() =>
                                             bus.Fire(new TestCommands.TypedTestCommand(Guid.NewGuid(), null)));

            Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotResponse) == 1, null, "Expected Fail");
            Assert.IsOrBecomesTrue(() => data == responseData);
        }