public void Test_WorkflowReply() { // Ensures that we can serialize and deserialize workflow reply messages. WorkflowReply message; using (var stream = new MemoryStream()) { // Empty message. message = new WorkflowReply(); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <WorkflowReply>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(0, message.RequestId); Assert.Null(message.Error); Assert.Equal(0, message.ContextId); Assert.Equal(InternalReplayStatus.Unspecified, message.ReplayStatus); // Round-trip message.ClientId = 444; message.RequestId = 555; message.Error = new CadenceError("MyError"); message.ContextId = 666; message.ReplayStatus = InternalReplayStatus.Replaying; Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.Equal("MyError", message.Error.String); Assert.Equal(666, message.ContextId); Assert.Equal(InternalReplayStatus.Replaying, message.ReplayStatus); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <WorkflowReply>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.Equal("MyError", message.Error.String); Assert.Equal(666, message.ContextId); Assert.Equal(InternalReplayStatus.Replaying, message.ReplayStatus); // Clone() message = (WorkflowReply)message.Clone(); Assert.NotNull(message); Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.Equal("MyError", message.Error.String); Assert.Equal(666, message.ContextId); Assert.Equal(InternalReplayStatus.Replaying, message.ReplayStatus); } }
/// <summary> /// Transmits a message to the local <b>cadence-client</b> web server and then /// verifies that the response matches. /// </summary> /// <typeparam name="TMessage">The message type.</typeparam> /// <param name="message">The message to be checked.</param> /// <returns>The received echo message.</returns> private TMessage EchoToClient <TMessage>(TMessage message) where TMessage : ProxyMessage, new() { #if DEBUG var bytes = message.SerializeAsBytes(); var content = new ByteArrayContent(bytes); content.Headers.ContentType = new MediaTypeHeaderValue(ProxyMessage.ContentType); var request = new HttpRequestMessage(HttpMethod.Put, "/echo") { Content = content }; var response = fixture.ConnectionClient.SendAsync(request).Result; response.EnsureSuccessStatusCode(); bytes = response.Content.ReadAsByteArrayAsync().Result; return(ProxyMessage.Deserialize <TMessage>(response.Content.ReadAsStreamAsync().Result)); #else // The RELEASE client doesn't support the "/echo" endpoint so we'll // simply return the input message so the unit tests will pass. return(message); #endif }
public void Test_ActivityReply() { // Ensures that we can serialize and deserialize activity reply messages. ActivityReply message; using (var stream = new MemoryStream()) { // Empty message. message = new ActivityReply(); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ActivityReply>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(0, message.RequestId); Assert.Null(message.Error); Assert.Equal(0, message.ActivityContextId); // Round-trip message.ClientId = 444; message.RequestId = 555; message.Error = new CadenceError("MyError"); message.ActivityContextId = 666; Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.Equal("MyError", message.Error.String); Assert.Equal(666, message.ActivityContextId); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ActivityReply>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.Equal("MyError", message.Error.String); Assert.Equal(666, message.ActivityContextId); // Clone() message = (ActivityReply)message.Clone(); Assert.NotNull(message); Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.Equal("MyError", message.Error.String); Assert.Equal(666, message.ActivityContextId); } }
public void Test_WorkflowRequest() { // Ensures that we can serialize and deserialize workflow request messages. WorkflowRequest message; using (var stream = new MemoryStream()) { // Empty message. message = new WorkflowRequest(); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <WorkflowRequest>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(0, message.ClientId); Assert.Equal(0, message.RequestId); Assert.Equal(0, message.ContextId); // Round-trip message.ClientId = 444; message.RequestId = 555; message.ContextId = 666; Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.Equal(666, message.ContextId); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <WorkflowRequest>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.Equal(666, message.ContextId); // Clone() message = (WorkflowRequest)message.Clone(); Assert.NotNull(message); Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.Equal(666, message.ContextId); } }
public void Test_ProxyRequest() { // Ensures that we can serialize and deserialize request messages. ProxyRequest message; using (var stream = new MemoryStream()) { // Empty message. message = new ProxyRequest(); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ProxyRequest>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(0, message.ClientId); Assert.Equal(0, message.RequestId); Assert.False(message.IsCancellable); // Round-trip message.ClientId = 444; message.RequestId = 555; Assert.Equal(555, message.RequestId); message.IsCancellable = true; stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ProxyRequest>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.True(message.IsCancellable); // Clone() message = (ProxyRequest)message.Clone(); Assert.NotNull(message); Assert.Equal(444, message.ClientId); Assert.Equal(555, message.RequestId); Assert.True(message.IsCancellable); } }
/// <summary> /// Handles requests to the test <b>"/echo"</b> endpoint path. /// </summary> /// <param name="context">The request context.</param> /// <returns>The tracking <see cref="Task"/>.</returns> private async Task OnEchoRequestAsync(HttpContext context) { var request = context.Request; var response = context.Response; var requestMessage = ProxyMessage.Deserialize <ProxyMessage>(request.Body); var clonedMessage = requestMessage.Clone(); response.ContentType = ProxyMessage.ContentType; var stream = clonedMessage.SerializeAsStream(); try { await stream.CopyToAsync(response.Body); } finally { MemoryStreamPool.Free(stream); } }
/// <summary> /// Transmits a message to the connection's associated <b>temporal-proxy</b> /// and then verifies that the response matches. /// </summary> /// <typeparam name="TMessage">The message type.</typeparam> /// <param name="message">The message to be checked.</param> /// <returns>The received echo message.</returns> private TMessage EchoToProxy <TMessage>(TMessage message) where TMessage : ProxyMessage, new() { var bytes = message.SerializeAsBytes(); var content = new ByteArrayContent(bytes); content.Headers.ContentType = new MediaTypeHeaderValue(ProxyMessage.ContentType); var request = new HttpRequestMessage(HttpMethod.Put, "/echo") { Content = content }; var response = proxyClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result; response.EnsureSuccessStatusCode(); bytes = response.Content.ReadAsByteArrayAsync().Result; return(ProxyMessage.Deserialize <TMessage>(response.Content.ReadAsStreamAsync().Result)); }
public void Test_ProxyReply() { // Ensures that we can serialize and deserialize reply messages. ProxyReply message; using (var stream = new MemoryStream()) { // Empty message. message = new ProxyReply(); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ProxyReply>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(0, message.RequestId); Assert.Null(message.Error); // Round-trip message.RequestId = 555; message.Error = new CadenceError("MyError"); Assert.Equal(555, message.RequestId); Assert.Equal("MyError", message.Error.String); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ProxyReply>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(555, message.RequestId); Assert.Equal("MyError", message.Error.String); } }
public void Test_ActivityRequest() { // Ensures that we can serialize and deserialize activity request messages. ActivityRequest message; using (var stream = new MemoryStream()) { // Empty message. message = new ActivityRequest(); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ActivityRequest>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(0, message.RequestId); Assert.Equal(0, message.ContextId); // Round-trip message.RequestId = 555; Assert.Equal(555, message.RequestId); message.ContextId = 666; Assert.Equal(666, message.ContextId); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ActivityRequest>(stream, ignoreTypeCode: true); Assert.NotNull(message); Assert.Equal(555, message.RequestId); Assert.Equal(666, message.ContextId); } }
public void Test_ProxyMessage() { // Ensures that we can serialize and deserialize base messages. ProxyMessage message; using (var stream = new MemoryStream()) { // Empty message. message = new ProxyMessage(); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ProxyMessage>(stream, ignoreTypeCode: true); Assert.Equal(InternalMessageTypes.Unspecified, message.Type); Assert.Empty(message.Properties); Assert.Empty(message.Attachments); // Message with args and attachments. message = new ProxyMessage(); message.Properties.Add(PropertyNames.TestOne, "1"); message.Properties.Add(PropertyNames.TestTwo, "2"); message.Properties.Add(PropertyNames.TestEmpty, string.Empty); message.Properties.Add(PropertyNames.TestNull, null); message.SetJsonProperty(PropertyNames.TestComplex, new ComplexType() { Name = "foo", Value = "bar" }); message.SetJsonProperty(PropertyNames.TestPerson, new Person() { Name = "Jack", Age = 10 }); message.Attachments.Add(new byte[] { 0, 1, 2, 3, 4 }); message.Attachments.Add(new byte[0]); message.Attachments.Add(null); stream.SetLength(0); stream.Write(message.SerializeAsBytes(ignoreTypeCode: true)); stream.Seek(0, SeekOrigin.Begin); message = ProxyMessage.Deserialize <ProxyMessage>(stream, ignoreTypeCode: true); Assert.Equal(InternalMessageTypes.Unspecified, message.Type); Assert.Equal(6, message.Properties.Count); Assert.Equal("1", message.Properties[PropertyNames.TestOne]); Assert.Equal("2", message.Properties[PropertyNames.TestTwo]); Assert.Empty(message.Properties[PropertyNames.TestEmpty]); Assert.Null(message.Properties[PropertyNames.TestNull]); var complex = message.GetJsonProperty <ComplexType>(PropertyNames.TestComplex); Assert.Equal("foo", complex.Name); Assert.Equal("bar", complex.Value); var person = message.GetJsonProperty <Person>(PropertyNames.TestPerson); Assert.Equal("Jack", person.Name); Assert.Equal(10, person.Age); Assert.Equal(3, message.Attachments.Count); Assert.Equal(new byte[] { 0, 1, 2, 3, 4 }, message.Attachments[0]); Assert.Empty(message.Attachments[1]); Assert.Null(message.Attachments[2]); } }
/// <summary> /// Handles requests to the emulated <b>cadence-proxy</b> root <b>"/"</b> endpoint path. /// </summary> /// <param name="context">The request context.</param> /// <returns>The tracking <see cref="Task"/>.</returns> private async Task OnEmulatedRootRequestAsync(HttpContext context) { var request = context.Request; var response = context.Response; var proxyMessage = ProxyMessage.Deserialize <ProxyMessage>(request.Body); if (EmulatedLibraryClient == null && proxyMessage.Type != InternalMessageTypes.InitializeRequest) { response.StatusCode = StatusCodes.Status400BadRequest; await response.WriteAsync($"Unexpected Message: Waiting for an [{nameof(InitializeRequest)}] message to specify the [cadence-client] network endpoint."); return; } // Handle proxy reply messages by completing any pending [CallClientAsync()] operation. var reply = proxyMessage as ProxyReply; if (reply != null) { Operation operation; using (await emulationMutex.AcquireAsync()) { emulatedOperations.TryGetValue(reply.RequestId, out operation); } if (operation != null) { if (reply.Type != operation.Request.ReplyType) { response.StatusCode = StatusCodes.Status400BadRequest; await response.WriteAsync($"[cadence-emulation] has a request [type={operation.Request.Type}, requestId={operation.RequestId}] pending but reply [type={reply.Type}] is not valid and will be ignored."); } else { operation.SetReply(reply); response.StatusCode = StatusCodes.Status200OK; } } else { log.LogWarn(() => $"[cadence-emulation] reply [type={reply.Type}, requestId={reply.RequestId}] does not map to a pending operation and will be ignored."); response.StatusCode = StatusCodes.Status400BadRequest; await response.WriteAsync($"[cadence-emulation] does not have a pending operation with [requestId={reply.RequestId}]."); } return; } // Handle proxy request messages. switch (proxyMessage.Type) { //------------------------------------------------------------- // Client messages case InternalMessageTypes.CancelRequest: await OnEmulatedCancelRequestAsync((CancelRequest)proxyMessage); break; case InternalMessageTypes.DomainDescribeRequest: await OnEmulatedDomainDescribeRequestAsync((DomainDescribeRequest)proxyMessage); break; case InternalMessageTypes.DomainRegisterRequest: await OnEmulatedDomainRegisterRequestAsync((DomainRegisterRequest)proxyMessage); break; case InternalMessageTypes.DomainUpdateRequest: await OnEmulatedDomainUpdateRequestAsync((DomainUpdateRequest)proxyMessage); break; case InternalMessageTypes.HeartbeatRequest: await OnEmulatedHeartbeatRequestAsync((HeartbeatRequest)proxyMessage); break; case InternalMessageTypes.InitializeRequest: await OnEmulatedInitializeRequestAsync((InitializeRequest)proxyMessage); break; case InternalMessageTypes.ConnectRequest: await OnEmulatedConnectRequestAsync((ConnectRequest)proxyMessage); break; case InternalMessageTypes.TerminateRequest: await OnEmulatedTerminateRequestAsync((TerminateRequest)proxyMessage); break; case InternalMessageTypes.NewWorkerRequest: await OnEmulatedNewWorkerRequestAsync((NewWorkerRequest)proxyMessage); break; case InternalMessageTypes.StopWorkerRequest: await OnEmulatedStopWorkerRequestAsync((StopWorkerRequest)proxyMessage); break; case InternalMessageTypes.PingRequest: await OnEmulatedPingRequestAsync((PingRequest)proxyMessage); break; //------------------------------------------------------------- // Workflow messages case InternalMessageTypes.WorkflowExecuteRequest: await OnEmulatedWorkflowExecuteRequestAsync((WorkflowExecuteRequest)proxyMessage); break; case InternalMessageTypes.WorkflowRegisterRequest: await OnEmulatedWorkflowRegisterRequestAsync((WorkflowRegisterRequest)proxyMessage); break; case InternalMessageTypes.WorkflowSetCacheSizeRequest: await OnEmulatedWorkflowSetCacheSizeRequestAsync((WorkflowSetCacheSizeRequest)proxyMessage); break; case InternalMessageTypes.WorkflowGetResultRequest: await OnEmulatedWorkflowGetResultRequestAsync((WorkflowGetResultRequest)proxyMessage); break; //------------------------------------------------------------- default: response.StatusCode = StatusCodes.Status400BadRequest; await response.WriteAsync($"EMULATION: Message [{proxyMessage.Type}] is not supported."); break; } await Task.CompletedTask; }