I need to verify in a unit test that the AggregateAsync
method received a specific aggregation command that is represented via a PipelineDefinition<BsonDocument, BsonDocument>
instance.
The command is $collStats
with the additional field/option storageStats
.
How can I check that the pipeline contains exactly this command, including the additional field?
I can get the individual stages of the pipeline with Stages
, so I can verify that there is only a single stage (containing the command above) and then get this stage:
PipelineDefinition<BsonDocument, BsonDocument> pipeline = ...; // obtained from some callback
IPipelineStageDefinition stage = pipeline.Stages.Single();
Now, I can easily check if this stage contains the $collStats
command with OperatorName
:
if (stage.OperatorName == "$collStats")
{
// check for additional "storageStats" field
}
But how can I check whether this command also contains the field storageStats
?
Unfortunately, there does not seem to be a similar property like OperatorFields
.
The only solution I currently found is to serialize the stage, and then check whether this serialized representation contains the specific field:
using MongoDB.Bson.Serialization;
BsonDocument command = stage.Render(
BsonSerializer.SerializerRegistry.GetSerializer<BsonDocument>(),
BsonSerializer.SerializerRegistry).Document;
BsonDocument fields = command.GetValue("$collStats").ToBsonDocument();
if (fields.Contains("storageStats"))
{
// finally ...
}
This feels way too complex and like the wrong way to do. Is there a simpler solution which I am missing?
To validate a MQL query, you have to render it. The reason for this is that a pipeline can be created in different ways and not always it's based on already rendered BsonDocument. So it might be rendering a stage as in your code above or Render the whole pipeline (which basically the same):
var registry = BsonSerializer.SerializerRegistry;
var serializer = registry.GetSerializer<BsonDocument>();
var renderedStages = pipeline.Render(serializer, registry).Documents
You may also configure event subscriber on CommandStartedEvent
(see here), but I doubt a server call is what you need here