private async Task <bool> Validate( IStreamStore from, IStreamStore to, string branchId, bool failOnNoStream = false) { await _messageQueue.UncompletedMessagesOnBranch(branchId).FirstAsync(s => s == 0) .Timeout(Configuration.Timeout); var page = await from.ListStreams(); while (page.StreamIds.Length > 0) { foreach (var s in page.StreamIds.Where(x => !x.StartsWith("$"))) { var source = await from.GetStream(s, _serializer); if (source.Timeline != branchId) { continue; } var target = await to.GetStream(s, _serializer); if (target == null) // stream exists but some of the ancestors do not { return(false); } if (failOnNoStream && target.Version == ExpectedVersion.NoStream) { _log.Warn($"Stream {s} does not exist on target, probably due to missing ancestors", this); return(false); } if (source.Version <= target.Version && source.Version > ExpectedVersion.EmptyStream) { var fromMessage = (await from.ReadStreamBackwards(s, StreamVersion.End, 1)).Messages.SingleOrDefault(); var toMessage = (await to.ReadStreamForwards(s, source.ReadPosition(source.Version), 1)).Messages.SingleOrDefault(); if (fromMessage.MessageId == toMessage.MessageId) { return(true); } _log.Warn( $"Message doesn't match with remote for stream {s}@{source.Version} : " + $"{fromMessage.MessageId} != {toMessage.MessageId}", this); return(false); } var parent = source.Parent; while (parent != null && parent.Version > ExpectedVersion.EmptyStream) { if (!await Validate(from, to, parent.Timeline, true)) { return(false); } parent = parent.Parent; } } page = await page.Next(); } return(true); }