2

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?

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

3 Comments

Hmm, I guess I have to to that then. But why is there an OperatorName property? This is also part of the pipeline (which can be created in different ways as you said) and yet, I have direct access. Seems like the MongoDB .NET API is a bit inconsistent here: "Hey, you want the command name? Sure, here is a nice property. You also want its fields? Sorry, we can't do that!" Rather weird in my opinion, but it is what it is.
'why is there an OperatorName property' - it's used internally, in some cases you have to know what is the stage about without rendering it
Bless you for this! I have a complicated factory that takes dynamically generated search criteria in the form of hierarchies of POCOs and generates Atlas search pipelines. I'm trying to write unit tests to validate that the pipelines and stages are correct given various combinations of input, and this was the piece I was missing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.