public void commands_should_not_deadlock() { var bus = new CommandBus("local"); long gotCmd1 = 0; long gotCmd2 = 0; bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>( cmd => { Interlocked.Exchange(ref gotCmd1, 1); bus.TryFire(new TestCommands.TestCommand2(Guid.NewGuid(), null)); return(true); })); bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand2>( cmd => { Interlocked.Exchange(ref gotCmd2, 1); return(true); })); CommandResponse result; bus.TryFire(new TestCommands.TestCommand(Guid.NewGuid(), null), out result); Assert.True(result is Success, $"Got Fail: {(result as Fail)?.Exception.Message}"); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd1) == 1, msg: "Expected Cmd1 handled"); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd2) == 1, msg: "Expected Cmd2 handled"); }
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 multiple_commands_can_register() { var bus = new CommandBus("local"); long gotCmd1 = 0; long gotCmd2 = 0; bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>( cmd => { Interlocked.Exchange(ref gotCmd1, 1); return(true); })); bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand2>( cmd => { Interlocked.Exchange(ref gotCmd2, 1); return(true); })); CommandResponse result; bus.TryFire(new TestCommands.TestCommand(Guid.NewGuid(), null), out result); Assert.True(result is Success); bus.TryFire(new TestCommands.TestCommand2(Guid.NewGuid(), null), out result); Assert.True(result is Success); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd1) == 1, msg: "Expected Cmd1 handled"); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd2) == 1, msg: "Expected Cmd2 handled"); }
public void tryfire_commands_should_not_call_other_commands() { var bus = new CommandBus("local"); long gotCmd = 0; bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>( cmd => { Interlocked.Increment(ref gotCmd); return(true); })); bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand2>( cmd => { Interlocked.Increment(ref gotCmd); return(true); })); CommandResponse response; var passed = bus.TryFire( new TestCommands.TestCommand(Guid.NewGuid(), null), out response, TimeSpan.FromMilliseconds(1500)); Assert.True(passed, "Expected false return"); Thread.Sleep(100); //let other threads complete Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd) == 1, msg: "Expected command received once, got " + gotCmd); Assert.IsType(typeof(Success), response); }
public void typed_failing_tryfire_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); } )); CommandResponse response; var command = new TestCommands.TypedTestCommand(Guid.NewGuid(), null); var passed = bus.TryFire(command, out response); Assert.False(passed, "Expected false return"); Assert.IsType(typeof(TestCommands.TestFailedCommandResponse), response); Assert.IsType(typeof(CommandException), ((Fail)response).Exception); Assert.Equal($"{command.GetType().Name}: {errText}", ((Fail)response).Exception.Message); Assert.Equal(data, ((TestCommands.TestFailedCommandResponse)response).Data); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotResponse) == 1, null, "Expected Fail"); Assert.IsOrBecomesTrue(() => data == responseData); }
public void typed_tryfire_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); } )); CommandResponse response; var pass = bus.TryFire(new TestCommands.TypedTestCommand(Guid.NewGuid(), null), out response); Assert.True(pass, "Expected true return value"); Assert.IsType(typeof(TestCommands.TestCommandResponse), response); Assert.Equal(data, ((TestCommands.TestCommandResponse)response).Data); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotResponse) == 1, null, "Expected Success"); Assert.IsOrBecomesTrue(() => data == responseData); }
public void tryfire_slow_commands_should_return_timeout() { var bus = new CommandBus("local"); long gotCmd1 = 0; long cancelRecieved = 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); })); CommandResponse response; var passed = bus.TryFire(new TestCommands.TestCommand(Guid.NewGuid(), null), out response); Assert.False(passed, "Expected false return"); Assert.IsType(typeof(Fail), response); Assert.IsType(typeof(CommandTimedOutException), ((Fail)response).Exception); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd1) == 1, msg: "Expected Cmd1 handled"); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref cancelRecieved) == 1, msg: "Expected cancel received"); }
public void tryfire_unsubscribed_commands_should_return_throw_commandNotHandledException() { var bus = new CommandBus("local"); CommandResponse response; var passed = bus.TryFire(new TestCommands.TestCommand(Guid.NewGuid(), null), out response); Assert.False(passed, "Expected false return"); Assert.IsType(typeof(Fail), response); Assert.IsType(typeof(CommandNotHandledException), ((Fail)response).Exception); }
public void tryfire_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))); CommandResponse response; var pass = bus.TryFire(new TestCommands.TestCommand(Guid.NewGuid(), null), out response); Assert.False(pass, "Expected false return value"); Assert.IsType(typeof(Fail), response); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotFail) == 1, null, "Expected Fail"); }
public void tryfire_passing_command_should_pass() { var bus = new CommandBus("local"); long gotSuccess = 0; bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>(cmd => true)); bus.Subscribe(new AdHocHandler <Success>(cmd => Interlocked.Exchange(ref gotSuccess, 1))); CommandResponse response; var pass = bus.TryFire(new TestCommands.TestCommand(Guid.NewGuid(), null), out response); Assert.True(pass, "Expected true return value"); Assert.IsType(typeof(Success), response); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotSuccess) == 1, null, "Expected Success"); }
public void tryfire_unsubscribed_commands_should_return_ack_timeout() { var bus = new CommandBus("local"); long cancelPublished = 0; bus.Subscribe(new AdHocHandler <CancelCommand>(c => Interlocked.Increment(ref cancelPublished))); CommandResponse response; var passed = bus.TryFire(new TestCommands.TestCommand(Guid.NewGuid(), null), out response); Assert.False(passed, "Expected false return"); Assert.IsType(typeof(Fail), response); Assert.IsType(typeof(CommandNotHandledException), ((Fail)response).Exception); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref cancelPublished) == 1, msg: "Expected cancel published"); }
public void handlers_that_wrap_exceptions_return_on_tryfire() { var bus = new CommandBus("local"); long gotCmd = 0; long gotResponse = 0; long gotAck = 0; long msgCount = 0; const string errText = @"I knew this would happen."; bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>( cmd => { Interlocked.Exchange(ref gotCmd, 1); throw new CommandException(errText, cmd); }, // ReSharper disable once RedundantArgumentDefaultValue wrapExceptions: 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))); CommandResponse response; var command = new TestCommands.TestCommand(Guid.NewGuid(), null); var passed = bus.TryFire(command, out response); Assert.False(passed, "Expected false return"); Assert.IsType(typeof(Fail), response); Assert.IsType(typeof(CommandException), ((Fail)response).Exception); Assert.True(string.Equals($"{command.GetType().Name}: {errText}", ((Fail)response).Exception.Message, StringComparison.Ordinal)); 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 tryfire_slow_commands_should_return_timeout() { var bus = new CommandBus("local"); long gotCmd1 = 0; bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>( cmd => { Interlocked.Exchange(ref gotCmd1, 1); Task.Delay(1000).Wait(); return(true); })); CommandResponse response; var passed = bus.TryFire(new TestCommands.TestCommand(Guid.NewGuid(), null), out response); Assert.False(passed, "Expected false return"); Assert.IsType(typeof(Fail), response);//,$"Expected 'Fail' got {response.GetType().Name}"); Assert.IsType(typeof(CommandTimedOutException), ((Fail)response).Exception); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd1) == 1, msg: "Expected Cmd1 handled"); }
public void passing_commands_on_connected_busses_should_pass() { var bus = new CommandBus("local"); var bus2 = new CommandBus("remote"); var conn = new BusConnector(bus, bus2); long gotCmd1 = 0; bus2.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>( cmd => { Interlocked.Exchange(ref gotCmd1, 1); return(true); })); CommandResponse result; bus.TryFire(new TestCommands.TestCommand(Guid.NewGuid(), null), out result); Assert.True(result is Success); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd1) == 1, msg: "Expected Cmd1 handled"); }
public void tryfire_oversubscribed_commands_should_return_false() { var bus = new CommandBus("local"); var bus2 = new CommandBus("remote"); var conn = new BusConnector(bus, bus2); long gotCmd = 0; long proccessedCmd = 0; long cancelPublished = 0; long cancelReturned = 0; bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>( cmd => { Interlocked.Increment(ref gotCmd); Task.Delay(250).Wait(); Interlocked.Increment(ref proccessedCmd); return(true); })); bus2.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand>( cmd => { Interlocked.Increment(ref gotCmd); Task.Delay(250).Wait(); Interlocked.Increment(ref proccessedCmd); return(true); })); bus.Subscribe(new AdHocCommandHandler <TestCommands.TestCommand2>( cmd => { Interlocked.Increment(ref gotCmd); Task.Delay(250).Wait(); Interlocked.Increment(ref proccessedCmd); return(true); })); bus2.Subscribe(new AdHocHandler <Canceled>(c => Interlocked.Increment(ref cancelPublished))); bus2.Subscribe(new AdHocHandler <Fail>( c => { if (c.Exception is CommandCanceledException) { Interlocked.Increment(ref cancelReturned); } })); CommandResponse response; var timer = Stopwatch.StartNew(); var passed = bus.TryFire( new TestCommands.TestCommand(Guid.NewGuid(), null), out response, TimeSpan.FromMilliseconds(1500)); timer.Stop(); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref gotCmd) <= 1, msg: "Expected command received no more than once, got " + gotCmd); Assert.True(timer.ElapsedMilliseconds < 1000, "Expected failure before task completion."); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref proccessedCmd) == 0, msg: "Expected command failed before handled; got " + proccessedCmd); Assert.False(passed, "Expected false return"); Assert.IsType(typeof(Fail), response); Assert.IsType(typeof(CommandOversubscribedException), ((Fail)response).Exception); Assert.IsOrBecomesTrue(() => Interlocked.Read(ref proccessedCmd) <= 1, 1500, msg: "Expected command handled no more than once, actual" + proccessedCmd); Assert.IsOrBecomesTrue( () => Interlocked.Read(ref cancelPublished) == 1, msg: "Expected cancel published once"); Assert.IsOrBecomesTrue( () => Interlocked.Read(ref cancelReturned) == 1, msg: "Expected cancel returned once, actual " + cancelReturned); }