/// <summary> /// Initializes a new instance of the <see cref="InteractionHandshakeConductor"/> class. /// </summary> /// <param name="localEndpoint">The endpoint ID of the local endpoint.</param> /// <param name="endpointInformationStorage">The object that stores information about the known endpoints.</param> /// <param name="interactionSubjects">The collection that contains all the registered subjects and their commands and notifications.</param> /// <param name="commandProxyHub">The object that stores the command proxy objects.</param> /// <param name="notificationProxyHub">The object that stores the notification proxy objects.</param> /// <param name="sendMessage">The action that is used to send a message to a remote endpoint.</param> /// <param name="sendMessageAndWaitForResponse"> /// The function that sends out a message to the given endpoint and returns a task that will, eventually, hold the return message. /// </param> /// <param name="sendTimeout">The maximum amount of time the instance will wait for a response message to be returned.</param> /// <param name="diagnostics">The object that provides the diagnostics methods for the application.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="localEndpoint"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="endpointInformationStorage"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="interactionSubjects"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="commandProxyHub"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="notificationProxyHub"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="sendMessage"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="sendMessageAndWaitForResponse"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="diagnostics"/> is <see langword="null" />. /// </exception> public InteractionHandshakeConductor( EndpointId localEndpoint, IStoreInformationAboutEndpoints endpointInformationStorage, IStoreInteractionSubjects interactionSubjects, IStoreRemoteCommandProxies commandProxyHub, IStoreRemoteNotificationProxies notificationProxyHub, SendMessage sendMessage, SendMessageAndWaitForResponse sendMessageAndWaitForResponse, TimeSpan sendTimeout, SystemDiagnostics diagnostics) { { Lokad.Enforce.Argument(() => localEndpoint); Lokad.Enforce.Argument(() => endpointInformationStorage); Lokad.Enforce.Argument(() => interactionSubjects); Lokad.Enforce.Argument(() => commandProxyHub); Lokad.Enforce.Argument(() => notificationProxyHub); Lokad.Enforce.Argument(() => sendMessage); Lokad.Enforce.Argument(() => sendMessageAndWaitForResponse); Lokad.Enforce.Argument(() => diagnostics); } m_Current = localEndpoint; m_EndpointInformationStorage = endpointInformationStorage; m_EndpointInformationStorage.OnEndpointConnected += HandleEndpointSignIn; m_InteractionSubjects = interactionSubjects; m_CommandProxyHub = commandProxyHub; m_NotificationProxyHub = notificationProxyHub; m_SendMessage = sendMessage; m_SendMessageAndWaitForResponse = sendMessageAndWaitForResponse; m_Diagnostics = diagnostics; m_SendTimeout = sendTimeout; }
public void HandleEndpointSignOut() { var localEndpoint = new EndpointId("local"); var notifier = new Mock <IStoreInformationAboutEndpoints>(); var configuration = new Mock <IConfiguration>(); { configuration.Setup(c => c.HasValueFor(It.IsAny <ConfigurationKey>())) .Returns(false); } var systemDiagnostics = new SystemDiagnostics((p, s) => { }, null); SendMessageAndWaitForResponse sender = (e, m, r, t) => Task <ICommunicationMessage> .Factory.StartNew( () => new SuccessMessage(localEndpoint, new MessageId()), new CancellationToken(), TaskCreationOptions.None, new CurrentThreadTaskScheduler()); var hub = new RemoteCommandHub( notifier.Object, new CommandProxyBuilder( localEndpoint, sender, configuration.Object, systemDiagnostics), systemDiagnostics); var endpoint = new EndpointId("other"); var types = new List <OfflineTypeInformation> { new OfflineTypeInformation( typeof(InteractionExtensionsTest.IMockCommandSetWithTaskReturn).FullName, typeof(InteractionExtensionsTest.IMockCommandSetWithTaskReturn).Assembly.GetName()) }; var eventWasTriggered = false; hub.OnEndpointConnected += (s, e) => { eventWasTriggered = true; Assert.AreEqual(endpoint, e.Endpoint); Assert.IsTrue(hub.HasCommandFor(e.Endpoint, typeof(InteractionExtensionsTest.IMockCommandSetWithTaskReturn))); }; hub.OnEndpointDisconnected += (s, e) => { eventWasTriggered = true; Assert.AreEqual(endpoint, e.Endpoint); Assert.IsFalse(hub.HasCommandFor(e.Endpoint, typeof(InteractionExtensionsTest.IMockCommandSetWithTaskReturn))); }; hub.OnReceiptOfEndpointCommands(endpoint, types); Assert.IsTrue(eventWasTriggered); eventWasTriggered = false; notifier.Raise(l => l.OnEndpointDisconnected += null, new EndpointEventArgs(endpoint)); Assert.IsTrue(eventWasTriggered); }
public void ProxyConnectingToMethodWithRetryCount() { var remoteEndpoint = new EndpointId("other"); var local = new EndpointId("local"); var retryCount = -1; var timeout = TimeSpan.MinValue; CommandInvokedMessage intermediateMsg = null; SendMessageAndWaitForResponse sender = (e, m, r, t) => { retryCount = r; timeout = t; intermediateMsg = m as CommandInvokedMessage; return(Task <ICommunicationMessage> .Factory.StartNew( () => new SuccessMessage(remoteEndpoint, new MessageId()), new CancellationToken(), TaskCreationOptions.None, new CurrentThreadTaskScheduler())); }; var configuration = new Mock <IConfiguration>(); { configuration.Setup(c => c.HasValueFor(It.IsAny <ConfigurationKey>())) .Returns(false); } var systemDiagnostics = new SystemDiagnostics((p, s) => { }, null); var builder = new CommandProxyBuilder(local, sender, configuration.Object, systemDiagnostics); var proxy = builder.ProxyConnectingTo <InteractionExtensionsTest.IMockCommandSetWithTaskReturn>(remoteEndpoint); var result = proxy.MyRetryMethod(10); result.Wait(); Assert.IsTrue(result.IsCompleted); Assert.IsFalse(result.IsCanceled); Assert.IsFalse(result.IsFaulted); Assert.AreEqual( CommandId.Create(typeof(InteractionExtensionsTest.IMockCommandSetWithTaskReturn).GetMethod("MyRetryMethod")), intermediateMsg.Invocation.Command); Assert.AreEqual(0, intermediateMsg.Invocation.Parameters.Length); Assert.AreEqual(10, retryCount); Assert.AreEqual(TimeSpan.FromMilliseconds(CommunicationConstants.DefaultWaitForResponseTimeoutInMilliSeconds), timeout); }
/// <summary> /// Initializes a new instance of the <see cref="CommandProxyBuilder"/> class. /// </summary> /// <param name="localEndpoint">The ID number of the local endpoint.</param> /// <param name="sendWithResponse"> /// The function that sends out a message to the given endpoint and returns a task that will, eventually, hold the return message. /// </param> /// <param name="configuration">The object that stores the configuration for the application.</param> /// <param name="systemDiagnostics">The object that provides the diagnostics methods for the system.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="localEndpoint"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="sendWithResponse"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="configuration"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="systemDiagnostics"/> is <see langword="null" />. /// </exception> public CommandProxyBuilder( EndpointId localEndpoint, SendMessageAndWaitForResponse sendWithResponse, IConfiguration configuration, SystemDiagnostics systemDiagnostics) { { Lokad.Enforce.Argument(() => localEndpoint); Lokad.Enforce.Argument(() => sendWithResponse); Lokad.Enforce.Argument(() => configuration); Lokad.Enforce.Argument(() => systemDiagnostics); } m_Local = localEndpoint; m_SendWithResponse = sendWithResponse; m_Configuration = configuration; m_Diagnostics = systemDiagnostics; }
public void ProxyConnectingToMethodWithTypedTaskReturnWithFailedExecution() { var remoteEndpoint = new EndpointId("other"); var local = new EndpointId("local"); CommandInvokedMessage intermediateMsg = null; SendMessageAndWaitForResponse sender = (e, m, r, t) => { intermediateMsg = m as CommandInvokedMessage; return(Task <ICommunicationMessage> .Factory.StartNew( () => new FailureMessage(remoteEndpoint, new MessageId()), new CancellationToken(), TaskCreationOptions.None, new CurrentThreadTaskScheduler())); }; var configuration = new Mock <IConfiguration>(); { configuration.Setup(c => c.HasValueFor(It.IsAny <ConfigurationKey>())) .Returns(false); } var systemDiagnostics = new SystemDiagnostics((p, s) => { }, null); var builder = new CommandProxyBuilder(local, sender, configuration.Object, systemDiagnostics); var proxy = builder.ProxyConnectingTo <InteractionExtensionsTest.IMockCommandSetWithTypedTaskReturn>(remoteEndpoint); var result = proxy.MyMethod(10); Assert.Throws <AggregateException>(result.Wait); Assert.IsTrue(result.IsCompleted); Assert.IsFalse(result.IsCanceled); Assert.IsTrue(result.IsFaulted); Assert.IsAssignableFrom(typeof(CommandInvocationFailedException), result.Exception.InnerExceptions[0]); Assert.AreEqual( CommandId.Create(typeof(InteractionExtensionsTest.IMockCommandSetWithTypedTaskReturn).GetMethod("MyMethod")), intermediateMsg.Invocation.Command); Assert.AreEqual(1, intermediateMsg.Invocation.Parameters.Length); Assert.AreEqual(typeof(int), intermediateMsg.Invocation.Parameters[0].Parameter.Type); Assert.AreEqual("input", intermediateMsg.Invocation.Parameters[0].Parameter.Name); Assert.AreEqual(10, intermediateMsg.Invocation.Parameters[0].Value); }
private static void RegisterSendMessageFunctions(ContainerBuilder builder) { builder.Register( c => { var layer = c.Resolve <IProtocolLayer>(); SendMessage result = layer.SendMessageTo; return(result); }) .As <SendMessage>() .SingleInstance(); builder.Register( c => { var layer = c.Resolve <IProtocolLayer>(); SendMessageAndWaitForResponse result = layer.SendMessageAndWaitForResponse; return(result); }) .As <SendMessageAndWaitForResponse>() .SingleInstance(); }
public void HandshakeWithLocalRejection() { var id = new EndpointId("a:10"); var remoteEndpoint = new EndpointId("b:10"); var endpointStorage = new Mock <IStoreInformationAboutEndpoints>(); { endpointStorage.Setup(e => e.TryRemoveEndpoint(It.IsAny <EndpointId>())) .Returns(true) .Verifiable(); } var providedSubjects = new Dictionary <CommunicationSubject, CommunicationSubjectGroup> { { new CommunicationSubject("a"), new CommunicationSubjectGroup( new CommunicationSubject("a"), new[] { new VersionedTypeFallback( new Tuple <OfflineTypeInformation, Version>( new OfflineTypeInformation(typeof(int).FullName, typeof(int).Assembly.GetName()), new Version(1, 0))), }, new VersionedTypeFallback[0]) } }; var requiredSubjects = new Dictionary <CommunicationSubject, CommunicationSubjectGroup> { { new CommunicationSubject("b"), new CommunicationSubjectGroup( new CommunicationSubject("b"), new VersionedTypeFallback[0], new[] { new VersionedTypeFallback( new Tuple <OfflineTypeInformation, Version>( new OfflineTypeInformation(typeof(double).FullName, typeof(double).Assembly.GetName()), new Version(1, 0))), }) } }; var interactionSubjects = new Mock <IStoreInteractionSubjects>(); { interactionSubjects.Setup(i => i.ProvidedSubjects()) .Returns(providedSubjects.Keys); interactionSubjects.Setup(i => i.RequiredSubjects()) .Returns(requiredSubjects.Keys); interactionSubjects.Setup(i => i.ContainsGroupProvisionsForSubject(It.IsAny <CommunicationSubject>())) .Returns <CommunicationSubject>(providedSubjects.ContainsKey); interactionSubjects.Setup(i => i.GroupProvisionsFor(It.IsAny <CommunicationSubject>())) .Returns <CommunicationSubject>(c => providedSubjects[c]); interactionSubjects.Setup(i => i.ContainsGroupRequirementsForSubject(It.IsAny <CommunicationSubject>())) .Returns <CommunicationSubject>(requiredSubjects.ContainsKey); interactionSubjects.Setup(i => i.GroupRequirementsFor(It.IsAny <CommunicationSubject>())) .Returns <CommunicationSubject>(c => requiredSubjects[c]); } var commandProxies = new Mock <IStoreRemoteCommandProxies>(); { commandProxies.Setup( c => c.OnReceiptOfEndpointCommands(It.IsAny <EndpointId>(), It.IsAny <IEnumerable <OfflineTypeInformation> >())) .Verifiable(); } var notificationProxies = new Mock <IStoreRemoteNotificationProxies>(); { notificationProxies.Setup( n => n.OnReceiptOfEndpointNotifications(It.IsAny <EndpointId>(), It.IsAny <IEnumerable <OfflineTypeInformation> >())) .Verifiable(); } var wasMessageSend = false; SendMessage sendMessage = (endpoint, message, retries) => { wasMessageSend = true; var msg = message as EndpointInteractionInformationResponseMessage; Assert.IsNotNull(msg); Assert.AreEqual(InteractionConnectionState.Neutral, msg.State); }; var wasMessageSendAndWaitedForResponse = false; SendMessageAndWaitForResponse sendMessageAndWaitForResponse = (endpoint, message, retries, timeout) => { wasMessageSendAndWaitedForResponse = true; return(Task <ICommunicationMessage> .Factory.StartNew( () => new EndpointInteractionInformationResponseMessage(remoteEndpoint, new MessageId(), InteractionConnectionState.Neutral), new CancellationTokenSource().Token, TaskCreationOptions.None, new CurrentThreadTaskScheduler())); }; var configuration = new Mock <IConfiguration>(); { configuration.Setup(c => c.HasValueFor(It.IsAny <ConfigurationKey>())) .Returns(false); } var diagnostics = new SystemDiagnostics((l, m) => { }, null); var conductor = new InteractionHandshakeConductor( id, endpointStorage.Object, interactionSubjects.Object, commandProxies.Object, notificationProxies.Object, sendMessage, sendMessageAndWaitForResponse, TimeSpan.FromMinutes(1), diagnostics); endpointStorage.Raise(e => e.OnEndpointConnected += null, new EndpointEventArgs(remoteEndpoint)); Assert.IsTrue(wasMessageSendAndWaitedForResponse); Assert.IsFalse(wasMessageSend); commandProxies.Verify( c => c.OnReceiptOfEndpointCommands(It.IsAny <EndpointId>(), It.IsAny <IEnumerable <OfflineTypeInformation> >()), Times.Never()); notificationProxies.Verify( c => c.OnReceiptOfEndpointNotifications(It.IsAny <EndpointId>(), It.IsAny <IEnumerable <OfflineTypeInformation> >()), Times.Never()); conductor.ContinueHandshakeWith( remoteEndpoint, new[] { new CommunicationSubjectGroup(new CommunicationSubject("b"), new VersionedTypeFallback[0], new VersionedTypeFallback[0]), }, new MessageId()); Assert.IsTrue(wasMessageSend); commandProxies.Verify( c => c.OnReceiptOfEndpointCommands(It.IsAny <EndpointId>(), It.IsAny <IEnumerable <OfflineTypeInformation> >()), Times.Never()); notificationProxies.Verify( c => c.OnReceiptOfEndpointNotifications(It.IsAny <EndpointId>(), It.IsAny <IEnumerable <OfflineTypeInformation> >()), Times.Never()); endpointStorage.Verify(e => e.TryRemoveEndpoint(It.IsAny <EndpointId>()), Times.Once()); }