diff --git a/src/ReactiveDomain.Foundation/StreamStore/ReadModelBase.cs b/src/ReactiveDomain.Foundation/StreamStore/ReadModelBase.cs
index 32461f48..a5e4d82e 100644
--- a/src/ReactiveDomain.Foundation/StreamStore/ReadModelBase.cs
+++ b/src/ReactiveDomain.Foundation/StreamStore/ReadModelBase.cs
@@ -182,9 +182,20 @@ protected virtual void Dispose(bool disposing)
}
_disposed = true;
}
+ ///
+ /// Applies a message synchronously to the read model while ensuring that the
+ /// is respected and bypasses both the queue and listeners. This is primarily useful in tests.
+ ///
+ /// The message to apply.
public void DirectApply(IMessage message) { DequeueMessage(message); }
public void Handle(Message message) { ((IHandle)_queue).Handle(message); }
public void Handle(IMessage message) { ((IHandle)_queue).Handle(message); }
+ ///
+ /// Publishes a message onto the read model's internal queue.
+ /// This bypasses the Listeners while ensuring that the
+ /// is respected. All messages will be processed in order from the queue thread.
+ ///
+ /// The message to publish.
public void Publish(IMessage message) { ((IPublisher)_queue).Publish(message); }
}
}
diff --git a/src/ReactiveDomain.Testing/Specifications/NullComfiguredConnection.cs b/src/ReactiveDomain.Testing/Specifications/NullComfiguredConnection.cs
index 50c1ff5d..fb814030 100644
--- a/src/ReactiveDomain.Testing/Specifications/NullComfiguredConnection.cs
+++ b/src/ReactiveDomain.Testing/Specifications/NullComfiguredConnection.cs
@@ -4,14 +4,34 @@
namespace ReactiveDomain.Testing
{
+ ///
+ /// An empty configured connection that produces null repositories, readers, etc.
+ /// Implements .
+ ///
public class NullConfiguredConnection : IConfiguredConnection
{
+ ///
+ /// Gets a .
+ ///
public IStreamStoreConnection Connection => new NullConnection();
+ ///
+ /// Gets a standard stream name builder
+ ///
public IStreamNameBuilder StreamNamer => new PrefixedCamelCaseStreamNameBuilder();
+ ///
+ /// Gets a default Json message serializer.
+ ///
public IEventSerializer Serializer => new JsonMessageSerializer();
+ ///
+ /// Gets a .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// A .
public ICorrelatedRepository GetCorrelatedRepository(
IRepository baseRepository = null,
bool caching = false,
@@ -20,21 +40,43 @@ public ICorrelatedRepository GetCorrelatedRepository(
return new NullRepository();
}
+ ///
+ /// Gets a .
+ ///
+ /// The name of the listener.
+ /// A
public IListener GetListener(string name)
{
return new NullListener(name);
}
+ ///
+ /// Gets a .
+ ///
+ /// The name of the listener.
+ /// A
public IListener GetQueuedListener(string name)
{
return new NullListener(name);
}
+ ///
+ /// Gets a .
+ ///
+ /// The name of the reader.
+ /// This parameter is ignored.
+ /// A
public IStreamReader GetReader(string name, Action handle)
{
return new NullReader(name);
}
+ ///
+ /// Gets a .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// A .
public IRepository GetRepository(bool caching = false, Func currentPolicyUserId = null)
{
return new NullRepository();
diff --git a/src/ReactiveDomain.Testing/Specifications/NullConnection.cs b/src/ReactiveDomain.Testing/Specifications/NullConnection.cs
index d7e6f21c..badd6b46 100644
--- a/src/ReactiveDomain.Testing/Specifications/NullConnection.cs
+++ b/src/ReactiveDomain.Testing/Specifications/NullConnection.cs
@@ -3,61 +3,148 @@
namespace ReactiveDomain.Testing
{
+ ///
+ /// An empty connection that implements .
+ ///
public class NullConnection : IStreamStoreConnection
{
-
+ ///
+ /// The name of the connection.
+ ///
public string ConnectionName => "NullConnection";
+ ///
+ /// Drops the events and returns a write result at the default version.
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// A at the default version.
public WriteResult AppendToStream(string stream, long expectedVersion, UserCredentials credentials = null, params EventData[] events)
{
return new WriteResult(0);
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
public void Close() { }
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
public void Connect() { }
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
public void DeleteStream(string stream, long expectedVersion, UserCredentials credentials = null)
{
}
+ ///
+ /// Cleans up resources.
+ ///
public void Dispose()
{
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
public void HardDeleteStream(string stream, long expectedVersion, UserCredentials credentials = null)
{
}
+ ///
+ /// Gets an empty stream slice.
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// An empty .
public StreamEventsSlice ReadStreamBackward(string stream, long start, long count, UserCredentials credentials = null)
{
return new StreamEventsSlice(stream, 0, ReadDirection.Backward, Array.Empty(), 0, 0, true);
}
+ ///
+ /// Gets an empty stream slice.
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// An empty .
public StreamEventsSlice ReadStreamForward(string stream, long start, long count, UserCredentials credentials = null)
{
return new StreamEventsSlice(stream, 0, ReadDirection.Forward, Array.Empty(), 0, 0, true);
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This connection.
public IDisposable SubscribeToAll(Action eventAppeared, Action subscriptionDropped = null, UserCredentials credentials = null, bool resolveLinkTos = true)
{
return this;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This connection.
public IDisposable SubscribeToAllFrom(Position from, Action eventAppeared, CatchUpSubscriptionSettings settings = null, Action liveProcessingStarted = null, Action subscriptionDropped = null, UserCredentials credentials = null, bool resolveLinkTos = true)
{
return this;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This connection.
public IDisposable SubscribeToStream(string stream, Action eventAppeared, Action subscriptionDropped = null, UserCredentials credentials = null)
{
return this;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ ///
+ /// This connection.
public IDisposable SubscribeToStreamFrom(string stream, long? lastCheckpoint, CatchUpSubscriptionSettings settings, Action eventAppeared, Action liveProcessingStarted = null, Action subscriptionDropped = null, UserCredentials credentials = null)
{
return this;
}
-
}
}
diff --git a/src/ReactiveDomain.Testing/Specifications/NullListener.cs b/src/ReactiveDomain.Testing/Specifications/NullListener.cs
index e515c1e8..772b6649 100644
--- a/src/ReactiveDomain.Testing/Specifications/NullListener.cs
+++ b/src/ReactiveDomain.Testing/Specifications/NullListener.cs
@@ -6,55 +6,121 @@
namespace ReactiveDomain.Testing
{
+ ///
+ /// An empty listener that implements .
+ ///
public class NullListener : IListener, ISubscriber
{
- private string _stream = "";
- public long _position = 0;
+ private string _stream;
+ private long _position;
+ ///
+ /// Gets a
+ ///
public ISubscriber EventStream => this;
+ ///
+ /// Gets the position of the stream.
+ ///
public long Position => _position;
+ ///
+ /// Gets the name of the stream.
+ ///
public string StreamName => _stream;
+
+ ///
+ /// Creates an empty lister.
+ ///
+ /// This parameter is ignored.
public NullListener(string name = "")
- {
- _stream = name;
+ {
}
+
+ ///
+ /// Cleans up resources.
+ ///
public void Dispose()
{
}
+ ///
+ /// Starts the listener at the requested checkpoint. Since the listener is not connected to anything,
+ /// this simply sets the listener's initial checkpoint.
+ ///
+ /// The name of the stream.
+ /// The position at which the listener should start.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
public void Start(string stream, long? checkpoint = null, bool blockUntilLive = false, CancellationToken cancelWaitToken = default)
{
_stream = stream;
_position = checkpoint ?? 0;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ ///
+ ///
public IDisposable SubscribeToAll(IHandle handler)
{
return this;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// false since the listener does not actually subscribe to anything.
bool ISubscriber.HasSubscriberFor(bool includeDerived)
{
return false;
}
+ ///
+ /// Does nothing other than set the stream name. Required for implementation of .
+ ///
+ /// The type of aggregate. Used for building the listener's stream name.
+ /// The ID of the aggregate whose stream to listen to.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
void IListener.Start(Guid id, long? checkpoint, bool blockUntilLive, CancellationToken cancelWaitToken)
{
_stream = new PrefixedCamelCaseStreamNameBuilder().GenerateForAggregate(typeof(TAggregate), id);
}
+ ///
+ /// Does nothing other than set the stream name. Required for implementation of .
+ ///
+ /// The type of aggregate. Used for building the listener's stream name.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
void IListener.Start(long? checkpoint, bool blockUntilLive, CancellationToken cancelWaitToken)
{
_stream = nameof(TAggregate);
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ ///
IDisposable ISubscriber.Subscribe(IHandle handler, bool includeDerived)
{
return this;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
void ISubscriber.Unsubscribe(IHandle handler)
{
}
diff --git a/src/ReactiveDomain.Testing/Specifications/NullReader.cs b/src/ReactiveDomain.Testing/Specifications/NullReader.cs
index 00ee93c8..2feac1ce 100644
--- a/src/ReactiveDomain.Testing/Specifications/NullReader.cs
+++ b/src/ReactiveDomain.Testing/Specifications/NullReader.cs
@@ -4,38 +4,100 @@
namespace ReactiveDomain.Testing
{
+ ///
+ /// An empty reader. Implements .
+ ///
public class NullReader : IStreamReader
{
- private string _name = "";
+ private readonly string _name;
+
+ ///
+ /// Creates an empty reader.
+ ///
+ /// The name of the reader.
public NullReader(string name)
{
_name = name;
}
+
+ ///
+ /// Gets the reader's position, which is always 0.
+ ///
public long? Position => 0;
+ ///
+ /// Gets the name of the stream.
+ ///
public string StreamName => _name;
private Action _handle = _ => { };
+
+ ///
+ /// Sets the reader's handler. The handler is not used since the Read methods are no-ops.
+ ///
public Action Handle { set => _handle = value; }
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
public void Cancel() { }
+ ///
+ /// Cleans up resources.
+ ///
public void Dispose() { }
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// true
public bool Read(string stream, Func completionCheck, long? checkpoint = null, long? count = null, bool readBackwards = false)
{
return true;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// true
public bool Read(Type tMessage, Func completionCheck, long? checkpoint = null, long? count = null, bool readBackwards = false)
{
return true;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// true
bool IStreamReader.Read(Guid id, Func completionCheck, long? checkpoint, long? count, bool readBackwards)
{
return true;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// true
bool IStreamReader.Read(Func completionCheck, long? checkpoint, long? count, bool readBackwards)
{
return true;
diff --git a/src/ReactiveDomain.Testing/Specifications/NullRepository.cs b/src/ReactiveDomain.Testing/Specifications/NullRepository.cs
index 7e6d4fa5..4abcc713 100644
--- a/src/ReactiveDomain.Testing/Specifications/NullRepository.cs
+++ b/src/ReactiveDomain.Testing/Specifications/NullRepository.cs
@@ -4,30 +4,77 @@
namespace ReactiveDomain.Testing
{
+ ///
+ /// An empty repository. Implements and .
+ ///
public class NullRepository : ICorrelatedRepository, IRepository
{
+ ///
+ /// Does nothing. Required for implementation of and .
+ ///
+ /// This parameter is ignored.
public void Delete(IEventSource aggregate) { }
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// null
public TAggregate GetById(Guid id, ICorrelatedMessage source) where TAggregate : AggregateRoot, IEventSource
{
return null;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// null
public TAggregate GetById(Guid id, int version, ICorrelatedMessage source) where TAggregate : AggregateRoot, IEventSource
{
return null;
}
+ ///
+ /// Does nothing. Required for implementation of and .
+ ///
+ /// This parameter is ignored.
public void HardDelete(IEventSource aggregate) { }
+ ///
+ /// Does nothing. Required for implementation of and .
+ ///
+ /// This parameter is ignored.
public void Save(IEventSource aggregate) { }
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// Output parameter for the retrieved aggregate.
+ /// This parameter is ignored.
+ /// false
public bool TryGetById(Guid id, out TAggregate aggregate, ICorrelatedMessage source) where TAggregate : AggregateRoot, IEventSource
{
aggregate = null;
return false;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// Output parameter for the retrieved aggregate.
+ /// This parameter is ignored.
+ /// false
public bool TryGetById(Guid id, int version, out TAggregate aggregate, ICorrelatedMessage source) where TAggregate : AggregateRoot, IEventSource
{
aggregate = null;
@@ -35,17 +82,38 @@ public bool TryGetById(Guid id, int version, out TAggregate aggregat
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
+ /// null
TAggregate IRepository.GetById(Guid id, int version)
{
return null;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// Output parameter for the retrieved aggregate.
+ /// This parameter is ignored.
+ /// false
bool IRepository.TryGetById(Guid id, out TAggregate aggregate, int version)
{
aggregate = null;
return false;
}
+ ///
+ /// Does nothing. Required for implementation of .
+ ///
+ /// This type parameter is ignored.
+ /// This parameter is ignored.
+ /// This parameter is ignored.
void IRepository.Update(ref TAggregate aggregate, int version)
{
}
diff --git a/src/ReactiveDomain.Testing/Specifications/ReadModelTestSpecification.cs b/src/ReactiveDomain.Testing/Specifications/ReadModelTestSpecification.cs
index 922b3d26..656583ad 100644
--- a/src/ReactiveDomain.Testing/Specifications/ReadModelTestSpecification.cs
+++ b/src/ReactiveDomain.Testing/Specifications/ReadModelTestSpecification.cs
@@ -3,13 +3,31 @@
using ReactiveDomain.Messaging.Bus;
using System.Collections.Generic;
-namespace ReactiveDomain.Testing {
- public abstract class ReadModelTestSpecification : IPublisher {
- void IPublisher.Publish(IMessage message) {
- PublishedMessages.Add(message);
- }
- protected List PublishedMessages = new List();
- protected IConfiguredConnection Connection = new NullConfiguredConnection();
-
- }
+namespace ReactiveDomain.Testing
+{
+ ///
+ /// A base test class for testing read models. Includes a
+ /// that can be used creating read models under test without needing additional infrastructure, and can be used itself as an
+ /// to collect published messages from read models. These messages are recorded in for use in tests.
+ ///
+ public abstract class ReadModelTestSpecification : IPublisher
+ {
+ ///
+ /// Adds the message onto the test class's list of published messages.
+ /// Required for implementation of .
+ ///
+ /// The message to add.
+ void IPublisher.Publish(IMessage message)
+ {
+ PublishedMessages.Add(message);
+ }
+ ///
+ /// The list of messages recorded from the test class's Publish method.
+ ///
+ protected List PublishedMessages = new List();
+ ///
+ /// A for use in creating read models under test without needing additional infrastructure.
+ ///
+ protected IConfiguredConnection Connection = new NullConfiguredConnection();
+ }
}