Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ci] Split MSBuildDeviceIntegration tests across multiple build agents. #6360

Merged
merged 1 commit into from
Oct 4, 2021

Conversation

jpobst
Copy link
Contributor

@jpobst jpobst commented Oct 1, 2021

Much like the MSBuild tests used to, the MSBuild with Emulator tests can take multiple hours.

image

Like we did for MSBuild tests, the solution is to parallelize them across multiple build agents. This PR splits each test suite across 3 nodes using the same [Category ("Node-X")] hack, bringing the total wall-time of running each suite under an hour.

image

@jpobst jpobst marked this pull request as ready for review October 4, 2021 14:55
@jonpryor jonpryor merged commit 80f5d8c into main Oct 4, 2021
@jonpryor jonpryor deleted the msbuild-integration-nodes branch October 4, 2021 21:03
jpobst added a commit that referenced this pull request Feb 27, 2023
[Previously](#6360), we split our `MSBuildIntegration` unit tests to run across multiple CI test agents.  While a huge improvement, there are a few downsides to the approach we went with at the time:

- The number of agents is hardcoded by copy/pasting steps in the CI YAML.
- The tests must be manually load-balanced across agents with `[Category ("Node-X")]` in code which is cumbersome and hard to keep updated.

As we are at the point where our tests have expanded well past the 1 hour target we are faced with needing to increase our parallelization.

First, we can remove the YAML duplication by using AZDO's built-in `parallel` strategy, allowing us to control the number of agents to use with a single number:

```yaml
  - job: 
    strategy:
      parallel: 4
```

This leaves us the issue of automatically splitting our tests among an unknown number of test agents.  A clever solution is [provided in the AZDO docs](https://learn.microsoft.com/en-us/azure/devops/pipelines/test/parallel-testing-any-test-runner?view=azure-devops): 
- Use `dotnet test --list-tests` to find all the tests
- Use a script to calculate which tests the agent should run, based on `$(System.JobPositionInPhase)` and `$(System.TotalJobsInPhase)`
- Pass those test names into `dotnet test` as a filter

Unfortunately there are issues with the provided approach:
- `dotnet test --list-tests` is not compatible with `--filter` so you have to run *all* tests in the test assembly which is not desirable for us. (dotnet/sdk#8643)
- Passing test names (including test parameters) on the command line hits limitations with escaping certain characters and argument limits.

So the approach is good, but we have to do all the work ourselves.  Enter [dotnet-test-slicer](https://github.com/jpobst/dotnet-test-slicer).

This dotnet global tool:
- Uses the `NUnit.Engine` NuGet package to find all tests in a test assembly using the desired filter query.
- Slices the test list for the current test agent.
- Outputs the desired tests into an NUnit-specific `.runsettings` file that can be passed to `dotnet test --settings foo.runsettings`, bypassing command line arguments.

Voila! Now we can automatically scale our test agents up or down as needed by changing a single variable in our YAML file.

Limitation: The tests are sliced in a round robin fashion.  This can produce uneven results if test durations are uneven.  A future optimization would be to store approximate test durations so tests can be load balanced more intelligently.
@github-actions github-actions bot locked and limited conversation to collaborators Jan 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants