public async Task GetNext_HandlesUnserializableMessageBody() { var messageClass = typeof(TestSagaMessage1).FullName + ", " + typeof(TestSagaMessage1).Assembly.GetName().Name; var expectedMessage = new SubscribedMessage { Headers = "{ \"MessageClass\":\"" + messageClass + "\"}" }; var expectedHeaders = new Headers { MessageClass = messageClass, ExceptionDetails = null }; var expectedUserMessage = new TestSagaMessage1(); var subscriberId = Guid.NewGuid(); dataAccess.Setup(d => d.GetPendingSubscribed(subscriberId)) .Returns(Task.FromResult(expectedMessage)); serializer.Setup(s => s.DeserializeHeaders(It.IsAny <string>())) .Returns(expectedHeaders); serializer.Setup(s => s.DeserializeMessage(It.IsAny <string>(), typeof(TestSagaMessage1))) .Throws(new JsonException()); var message = await reader.GetNext(subscriberId); Assert.IsTrue(ReferenceEquals(expectedMessage, message.MessageData)); Assert.IsTrue(ReferenceEquals(expectedHeaders, message.Headers)); Assert.IsNull(message.Message); }
public async Task GetNext_HandlesUnrecognizedMessageClass() { var messageClass = "Peachtreebus.Tests.Sagas.TestSagaNotARealMessage, " + typeof(TestSagaMessage1).Assembly.GetName().Name; var expectedMessage = new SubscribedMessage { Headers = "{ \"MessageClass\":\"" + messageClass + "\"}" }; var expectedHeaders = new Headers { MessageClass = messageClass, ExceptionDetails = null }; var expectedUserMessage = new TestSagaMessage1(); Guid subscriberId = Guid.NewGuid(); dataAccess.Setup(d => d.GetPendingSubscribed(subscriberId)) .Returns(Task.FromResult(expectedMessage)); serializer.Setup(s => s.DeserializeHeaders(It.IsAny <string>())) .Returns(expectedHeaders); var message = await reader.GetNext(subscriberId); serializer.Verify(s => s.DeserializeMessage(It.IsAny <string>(), It.IsAny <Type>()), Times.Never); Assert.IsTrue(ReferenceEquals(expectedMessage, message.MessageData)); Assert.IsNotNull(message.Headers); Assert.IsNull(message.Message); }
public static bool Equals(StockInfoMessage?left, StockInfoMessage?right) { bool result = SubscribedMessage.Equals(left, right); result &= (result ? (left?.Articles.SequenceEqual(right?.Articles)).GetValueOrDefault() : false); return(result); }
public static bool Equals(ShoppingCartUpdateMessage?left, ShoppingCartUpdateMessage?right) { bool result = SubscribedMessage.Equals(left, right); result &= (result ? ShoppingCartContent.Equals(left?.ShoppingCart, right?.ShoppingCart) : false); return(result); }
public static bool Equals(ArticleSelectedMessage?left, ArticleSelectedMessage?right) { bool result = SubscribedMessage.Equals(left, right); result &= (result ? ArticleSelectedArticle.Equals(left?.Article, right?.Article) : false); return(result); }
public static bool Equals(InitiateInputMessage?left, InitiateInputMessage?right) { bool result = SubscribedMessage.Equals(left, right); result &= (result ? InitiateInputMessageDetails.Equals(left?.Details, right?.Details) : false); result &= (result ? (left?.Articles.SequenceEqual(right?.Articles)).GetValueOrDefault() : false); return(result); }
public static bool Equals(InputMessage?left, InputMessage?right) { bool result = SubscribedMessage.Equals(left, right); result &= (result ? EqualityComparer <bool?> .Default.Equals(left?.IsNewDelivery, right?.IsNewDelivery) : false); result &= (result ? (left?.Articles.SequenceEqual(right?.Articles)).GetValueOrDefault() : false); return(result); }
public static bool Equals(UnprocessedMessage?left, UnprocessedMessage?right) { bool result = SubscribedMessage.Equals(left, right); result &= (result ? EqualityComparer <String?> .Default.Equals(left?.Message, right?.Message) : false); result &= (result ? EqualityComparer <String?> .Default.Equals(left?.Text, right?.Text) : false); result &= (result ? EqualityComparer <UnprocessedReason?> .Default.Equals(left?.Reason, right?.Reason) : false); return(result); }
/// <summary> /// Moves a subscribed message from the pending table to the compelted table. /// </summary> /// <param name="message"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentNullException"></exception> public Task CompleteMessage(SubscribedMessage message) { const string completeStatement = "DECLARE " + " @MessageId UNIQUEIDENTIFIER," + " @SubscriberId UNIQUEIDENTIFIER," + " @ValidUntil DATETIME2, " + " @Enqueued DATETIME2, " + " @Body NVARCHAR(MAX), " + " @Retries TINYINT, " + " @NotBefore DATETIME2; " + "SELECT " + " @MessageId = [MessageId]," + " @SubscriberId = [SubscriberId]," + " @ValidUntil = [ValidUntil]," + " @Enqueued = [Enqueued]," + " @Body = [Body]," + " @Retries = [Retries]," + " @NotBefore = [NotBefore] " + "FROM [{0}].[Subscribed_Pending]" + "WHERE [Id] = @Id; " + "INSERT INTO [{0}].[Subscribed_Completed]" + " ([Id], [MessageId], [SubscriberId], [ValidUntil], [NotBefore], [Enqueued], [Completed], [Failed], [Retries], [Headers], [Body])" + "VALUES " + " (@Id, @MessageId, @SubscriberId, @ValidUntil, @NotBefore, @Enqueued, SYSUTCDATETIME(), NULL, @Retries, @Headers, @Body); " + "DELETE FROM[{0}].[Subscribed_Pending]" + " WHERE[Id] = @Id; "; if (IsUnsafe(_schemaConfig.Schema)) { throw new ArgumentException(SchemaUnsafe); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (string.IsNullOrEmpty(message.Headers)) { throw new ArgumentException($"{nameof(message)}.{nameof(message.Headers)} must be not null and not empty."); } string statement = string.Format(completeStatement, _schemaConfig.Schema); var p = new DynamicParameters(); p.Add("@Id", message.Id); p.Add("@Headers", message.Headers); return(_database.Connection.ExecuteAsync(statement, p, _database.Transaction)); }
/// <inheritdoc /> public void OnChannelSubscribed(SubscribedMessage subscribedMessage) { var subscribe = GetSubscriptionMessage() as SubscribeMessage; if ((subscribe?.ChannelName == subscribedMessage.ChannelName) || (subscribe?.Frequency == subscribedMessage.Frequency) || (subscribe?.Key == subscribedMessage.Key) || (subscribe?.Length == subscribedMessage.Length) || (subscribe?.Precision == subscribedMessage.Precision) || (subscribe?.Symbol == subscribedMessage.Symbol)) { throw new ArgumentException("Invalid subscribedMessage message.", nameof(subscribe)); } ChannelId = subscribedMessage.ChannelId; }
/// <summary> /// Updates a subscribed message in the pending table /// </summary> /// <param name="message"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentNullException"></exception> public Task Update(SubscribedMessage message) { const string UpdateMessageStatement = "UPDATE[{0}].[Subscribed_Pending] SET " + "[NotBefore] = @NotBefore, " + "[Retries] = @Retries, " + "[Headers] = @Headers " + "WHERE [Id] = @Id"; if (IsUnsafe(_schemaConfig.Schema)) { throw new ArgumentException(SchemaUnsafe); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (message.NotBefore == null) { throw new ArgumentNullException($"{nameof(message)}.{nameof(message.NotBefore)}"); } if (message.NotBefore.Kind == DateTimeKind.Unspecified) { throw new ArgumentException($"{nameof(message)}.{nameof(message.NotBefore)}.{nameof(message.NotBefore.Kind)} cannot be unspecified."); } if (string.IsNullOrEmpty(message.Headers)) { throw new ArgumentException($"{nameof(message)}.{nameof(message.Headers)} must be not null and not empty."); } var statement = string.Format(UpdateMessageStatement, _schemaConfig.Schema); var p = new DynamicParameters(); p.Add("@Id", message.Id); p.Add("@NotBefore", message.NotBefore.ToUniversalTime()); p.Add("@Retries", message.Retries); p.Add("@Headers", message.Headers); return(_database.Connection.ExecuteAsync(statement, p, _database.Transaction)); }
public void TestInitialize() { dataAccess = new Mock <IBusDataAccess>(); log = new Mock <ILog <SubscribedReader> >(); counters = new Mock <IPerfCounters>(); serializer = new Mock <ISerializer>(); clock = new Mock <ISystemClock>(); clock.SetupGet(x => x.UtcNow) .Returns(new DateTime(2022, 2, 22, 14, 22, 22, 222, DateTimeKind.Utc)); dataAccess.Setup(d => d.Update(It.IsAny <SubscribedMessage>())) .Callback <SubscribedMessage>((m) => { UpdatedMessage = m; }) .Returns(Task.CompletedTask); dataAccess.Setup(d => d.FailMessage(It.IsAny <SubscribedMessage>())) .Callback <SubscribedMessage>((d) => { FailedMessage = d; }) .Returns(Task.CompletedTask); dataAccess.Setup(d => d.CompleteMessage(It.IsAny <SubscribedMessage>())) .Callback <SubscribedMessage>((d) => { CompletedMessage = d; }) .Returns(Task.CompletedTask); reader = new SubscribedReader( dataAccess.Object, serializer.Object, log.Object, counters.Object, clock.Object); }
private void MessageReceived(dynamic message) { int messageTypeId = message[0]; switch (messageTypeId) { case MessageTypes.Welcome: var welcome = new WelcomeMessage(message); SessionId = welcome.SessionId; if (Welcome != null) { Welcome(this, welcome); } break; case MessageTypes.Subscribed: var subscribed = new SubscribedMessage(message); var topic = SubscribingTopics[subscribed.RequestId]; SubscribingTopics.Remove(subscribed.RequestId); SubscribedTopics.Add(subscribed.SubscriptionId, topic); if (Subscribed != null) { Subscribed(this, subscribed); } break; case MessageTypes.Event: if (Event != null) { Event(this, new EventMessage(message)); } break; default: throw new Exception("Unsupported message type: " + messageTypeId); } }
/// <summary> /// Stores a subscribed message in the pending table. /// </summary> /// <param name="message"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentNullException"></exception> public Task <long> AddMessage(SubscribedMessage message) { const string EnqueueMessageStatement = "INSERT INTO [{0}].[Subscribed_Pending] " + " ([MessageId], [SubscriberId], [ValidUntil], [NotBefore], [Enqueued], [Completed], [Failed], [Retries], [Headers], [Body]) " + "VALUES" + " ( @MessageId, @SubscriberId, @ValidUntil, @NotBefore, SYSUTCDATETIME(), NULL, NULL, 0, @Headers, @Body); " + "SELECT SCOPE_IDENTITY()"; if (IsUnsafe(_schemaConfig.Schema)) { throw new ArgumentException(SchemaUnsafe); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (message.MessageId == null) { throw new ArgumentNullException($"{nameof(message)}.{nameof(message.MessageId)}"); } if (message.NotBefore == null) { throw new ArgumentNullException($"{nameof(message)}.{nameof(message.NotBefore)}"); } if (message.NotBefore.Kind == DateTimeKind.Unspecified) { throw new ArgumentException($"{nameof(message)}.{nameof(message.NotBefore)}.{nameof(message.NotBefore.Kind)} cannot be unspecified."); } if (message.ValidUntil == null) { throw new ArgumentNullException($"{nameof(message)}.{nameof(message.ValidUntil)}"); } if (message.SubscriberId == Guid.Empty) { throw new ArgumentException($"{nameof(message)}.{nameof(message.SubscriberId)} must not be Guid.Empty"); } if (message.ValidUntil.Kind == DateTimeKind.Unspecified) { throw new ArgumentException($"{nameof(message)}.{nameof(message.ValidUntil)}.{nameof(message.ValidUntil.Kind)} cannot be unspecified."); } if (string.IsNullOrEmpty(message.Headers)) { throw new ArgumentException($"{nameof(message)}.{nameof(message.Headers)} must be not null and not empty."); } if (string.IsNullOrEmpty(message.Body)) { throw new ArgumentException($"{nameof(message)}.{nameof(message.Body)} must be not null and not empty."); } string statement = string.Format(EnqueueMessageStatement, _schemaConfig.Schema); var p = new DynamicParameters(); p.Add("@MessageId", message.MessageId); p.Add("@SubscriberId", message.SubscriberId); p.Add("@ValidUntil", message.ValidUntil.ToUniversalTime()); p.Add("@NotBefore", message.NotBefore.ToUniversalTime()); p.Add("@Headers", message.Headers); p.Add("@Body", message.Body); return(_database.Connection.QueryFirstAsync <long>(statement, p, _database.Transaction)); }