The cosmos DB Emulator is a custom action available on the Azure DevOps portal, however, that doesn’t exactly make it turnkey to use. The custom task will spin up a container running Cosmos DB, however it does so with a specific local DNS / port that you need to pipe into your test running.

Alt

There is documentation but it’s a bit dated.

Alt

It will output a pipeline variable called “$(CosmosDbEmulator.Endpoint)”. This isn’t exactly clear from the output variables GUI within the task editor. The trick is getting this into a variable that you future tasks can use. I prefer using Environment Variables over Test Runner configuration files as the dated documentation from Microsoft advises.

Those of you familiar with Azure DevOps will know that it’s a bit tricky working with Environment Variables. Some tasks support them, some don’t. Unfortunately the DotNetCoreCLI task type, you know the one that executes my .NET Core Xunit tests does not support environment variables. Therefore I have to ensure the environment variable is made available before that task is executed.

Alt

I do that in my “Setup Cosmos DB Endpoint” task. Which is simply there to grab the pipeline variable and set it up as an Environment Variable so that future steps can use it.

Alt

The data flow is like this:

$(CosmosDbEmulator.Endpoint) --> EMULATOR_ENDPOINT --> COSMOS_DB_ENDPOINT

I’m jamming in an Environment Variable using an Environment Variable? Weird, I know right? But that’s because how the Environment Variables work within Tasks. If I pipe in the pipeline variable $(CosmosDbEmulator.Endpoint) as an Environment Variable “EMULATOR_ENDPOINT” then it is only available within the scope of that task!

I have to use some special syntax to ensure I setup an Environment Variable that will be available across all tasks (going forward). That’s where this comes into play:

echo Task.setvariable

echo ##vso[task.setvariable variable=COSMOS_DB_ENDPOINT]%EMULATOR_ENDPOINT%

When we analyze the Azure DevOps pipeline execution we see what’s happening:

Notice that during the Setup of the CosmosDB Endpoint the values look like this:

Alt

Key Value
$(CosmosDbEmulator.Endpoint) https://6f99b2565caf:8081/
EMULATOR_ENDPOINT https://6f99b2565caf:8081/
COSMOS_DB_ENDPOINT NULL

Now we move onto the confirmation step…

Alt

Notice in the next step things have changed:

Alt

Key Value
$(CosmosDbEmulator.Endpoint) https://6f99b2565caf:8081/
EMULATOR_ENDPOINT NULL
COSMOS_DB_ENDPOINT https://6f99b2565caf:8081/

Notice that the change I requested to COSMOS_DB_ENDPOINT does NOT take into effect in the CURRENT task where the value is set. This can be very perplexing but it is available in all subsequent steps.

You might be asking, why not just use the pipeline variable. The answer is simple. This whole approach, is designed to make the Unit Tests and Unit Test configuration SIMPLER. Therefore, the unit tests should not have to worry about where or how the CosmosDB Endpoint URL gets into the “COSMOS_DB_ENDPOINT” Environment Variable it will work the same way. Developers can set the variable themselves on their environment if they want to use a different endpoint for testing, or you can do NULL checks in your Unit Test and use the local emulator settings when running the tests locally.

Now your test running will execute and connect to a REAL Cosmos DB server without issue. Isn’t that wonderful?! Yes and no.

Unfortunately, CosmosDB takes a hella long time to load.

Alt

Like 10 bloody minutes long.

The conspiracy theorist in me might suspect that this was an obnoxious attempt by Microsoft to increase the build minutes incurred on Azure DevOps to drive an increase in build minutes per month or parallel builds unit which of course are the main monetization strategy. But it’s a new Microsoft, right? Maybe they will fix the Cosmos DB emulator so it isn’t so ridiculously long to boot….a dev can dream, no?