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

Add installer tests project #46927

Merged
merged 9 commits into from
Feb 25, 2025

Conversation

NikolaMilosavljevic
Copy link
Member

Contributes to dotnet/runtime#109848

This PR introduces test project for installer tests. It does not hook it up to build infra. There will be another PR soon that will introduce a job/step in VMR Validation stage that will run installer tests for both x64 and arm64 installers.

Originally the plan was to run these tests as part of the mainline build job, but we are running that job as cross-build on x64 host, which precludes us from testing arm64 installers.

Some notes about the PR contents:

@Copilot Copilot bot review requested due to automatic review settings February 18, 2025 23:16
@NikolaMilosavljevic NikolaMilosavljevic requested review from a team as code owners February 18, 2025 23:16
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Infrastructure untriaged Request triage from a team member labels Feb 18, 2025
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • src/SourceBuild/content/test/Microsoft.DotNet.Installer.Tests/Microsoft.DotNet.Installer.Tests.csproj: Language not supported
Comments suppressed due to low confidence (3)

src/SourceBuild/content/test/Microsoft.DotNet.Installer.Tests/DockerHelper.cs:150

  • The outputHelper parameter is marked as non-nullable but is being passed as null in some cases, which could lead to a NullReferenceException.
Func<string, ITestOutputHelper, (Process Process, string StdOut, string StdErr)> executor)

src/SourceBuild/content/test/Microsoft.DotNet.Installer.Tests/LinuxInstallerTests.cs:101

  • Assert.Fail is not a valid method in xUnit. Use Assert.True(false, "Test failed for {image}: {ex}") instead.
Assert.Fail("Test failed for {image}: {ex}");

src/SourceBuild/content/test/Microsoft.DotNet.Installer.Tests/LinuxInstallerTests.cs:229

  • Assert.Fail is not a valid method in xUnit. Use Assert.True(false, "Build failed: {output}") instead.
Assert.Fail("Build failed: {output}");

string? scenarioTestsPackage = Directory.GetFiles(nugetPackagesDir, "Microsoft.DotNet.ScenarioTests.SdkTemplateTests*.nupkg", SearchOption.AllDirectories).FirstOrDefault();
if (scenarioTestsPackage == null)
{
Assert.Fail("Scenario tests package not found");
Copy link
Preview

Copilot AI Feb 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.Fail is not a valid method in xUnit. Use Assert.True(false, "Scenario tests package not found") instead.

Suggested change
Assert.Fail("Scenario tests package not found");
Assert.True(false, "Scenario tests package not found");

Copilot is powered by AI, so mistakes are possible. Review output carefully before use.

Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not true - Assert.Fail exists and is new in v2 2.5, see https://xunit.net/docs/comparisons

}
else
{
Assert.Fail("Test summary not found");
Copy link
Preview

Copilot AI Feb 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.Fail is not a valid method in xUnit. Use Assert.True(false, "Test summary not found") instead.

Suggested change
Assert.Fail("Test summary not found");
Assert.True(false, "Test summary not found");

Copilot is powered by AI, so mistakes are possible. Review output carefully before use.

Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not true - Assert.Fail exists and is new in v2 2.5, see https://xunit.net/docs/comparisons


private readonly string[] RpmDistroImages =
[
"mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-40"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't ship the Fedora packages any more (and I'm actually in the process of removing the runtime-deps package in another PR). Can we instead use Azure Linux 3.0 or OpenSuSE Leap 15.6 here? Those are both RPM distros where we currently ship the packages.

Also, could we use the shipping "runtime-deps" images as our baseline instead of the buildtools-prereqs images? The shipping images better represent our customer scenarios.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - will fix.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A deps image would likely be this one mcr.microsoft.com/dotnet/runtime-deps:9.0-azurelinux3.0 as we don't have 10.0 images yet. I don't think we want the OS base image like mcr.microsoft.com/azurelinux/base/core:3.0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have 10.0 images soon (when P1 comes out), but the 9.0 ones should be good for now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 054366b


private readonly string[] DebDistroImages =
[
"mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-24.04"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't ship the Ubuntu packages any more (and I'm actually in the process of removing the Ubuntu support from the runtime-deps package in another PR). Can we instead use Debian stable here? Debian is the only disto that we ship our Deb packages for now.

Also, could we use the shipping "runtime-deps" image as our baseline instead of the buildtools-prereqs image? The shipping images better represent our customer scenarios.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - yeah makes sense, I'll update this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deps image would likely be this one: mcr.microsoft.com/dotnet/runtime-deps:9.0-bookworm-slim

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 054366b

Comment on lines 330 to 343
string depsId = "fedora";
if (baseImage.Contains("fedora"))
{
depsId = "fedora";
}
else if (baseImage.Contains("centos"))
{
depsId = "centos";
}
else if (baseImage.Contains("rhel"))
{
depsId = "rhel";
}
else if (baseImage.Contains("opensuse"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm removing these deps packages, so we don't need these checks here.

Suggested change
string depsId = "fedora";
if (baseImage.Contains("fedora"))
{
depsId = "fedora";
}
else if (baseImage.Contains("centos"))
{
depsId = "centos";
}
else if (baseImage.Contains("rhel"))
{
depsId = "rhel";
}
else if (baseImage.Contains("opensuse"))
string? depsId = null;
if (baseImage.Contains("opensuse"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I'll incorporate this in an offline change, along other proposed changes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 054366b

sb.Append("RUN");

// TODO: remove --force-all when aspnet package versioning issue have been resolved - https://github.com/dotnet/source-build/issues/4895
string packageInstallationCommand = distroType == DistroType.Deb ? "dpkg -i --force-all" : "rpm -i";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we construct these tests to point to a fake local package feed and install the packages via apt/tdnf/zypper instead of dpkg/rpm directly?

Doing so would let us better test actual end user scenarios

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's something we could consider in the future. It's not as trivial to now add that to current tests, at least not as easy as adding a local NuGet store. It would be easy to reuse most of the code for those tests.

For now we're automating current manual testing of RPMs an DEBs, in the same way they are executed.

Utilizing correct installation order also verifies the expected package dependencies.

</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this is a new project, consider taking a dependency on STJ.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will take a look and update. We might not even need a dependency.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 08a4230


private readonly string[] RpmDistroImages =
[
"mcr.microsoft.com/dotnet/runtime-deps:9.0-azurelinux3.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version should be shared across RPM and Deb to ensure consistency and reduce maintenance.

I am afraid this is going to get stale quickly.

This should be using the 10-preview images out of nightly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense - will update.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 08a4230

private const string NetStandard21RpmPackage = @"https://dotnetcli.blob.core.windows.net/dotnet/Runtime/3.1.0/netstandard-targeting-pack-2.1.0-x64.rpm";
private const string NetStandard21DebPackage = @"https://dotnetcli.blob.core.windows.net/dotnet/Runtime/3.1.0/netstandard-targeting-pack-2.1.0-x64.deb";

private enum DistroType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private enum DistroType
private enum PackageType

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix - thanks!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 08a4230

[Fact]
public void RunScenarioTestsForAllDistros()
{
if (Config.TestRpmPackages)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally these would be separate testcases. One of the primary reasons for this is that if one fails you would still get a read on the other. Also having explicitly testcases helps make it more obvious what is being tested.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, totally agree. Will do that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 64fa1b8

private readonly string _tmpDir;
private readonly string _contextDir;

private readonly string[] RpmDistroImages =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an array? What is the thinking on how this would expand?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will likely add more images. Having it as array makes the future modification simpler.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm changing this to InlineData in a Theory.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 64fa1b8

{
output = e.Message;
}
Assert.Fail($"Build failed: {output}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you know this failed during the build vs run?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't - will refactor this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 64fa1b8

sb.AppendLine("");
sb.AppendLine($"ENTRYPOINT [ \"dotnet\", \"{scenarioTestsBinary}\", \"--dotnet-root\", \"/usr/share/dotnet\" ]");

string dockerfile = Path.Combine(_contextDir, Path.GetRandomFileName());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like debugging would be easier if the filename started with Dockerfile with a random suffix.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 08a4230

if (distroType == DistroType.Rpm)
{
string? depsId = null;
if (baseImage.Contains("opensuse"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this not hardcoded to azurelinux since it appears to be the only exercisable codepath?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will likely add more at later time. Having support for other distros is cheap.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not refactor at that time? I don't like the thought of adding code that is not certain to be used, it is a form of technical debt. We don't have runtime-deps images for these distros. What is the ROI of adding them?

private string GetContentPackage(string prefix, DistroType distroType)
{
string matchPattern = DistroType.Deb == distroType ? "*.deb" : "*.rpm";
string[] rpmFiles = Directory.GetFiles(_contextDir, prefix + matchPattern, SearchOption.AllDirectories)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't necessarily rpm packages right? They could be deb files as well? If so the variable and exception message should be updated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 08a4230

sb.AppendLine($"COPY packages packages");

sb.AppendLine("");
sb.AppendLine("# Copy RPM packages");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These aren't necessarily RPM packages. There are a few RPM references

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 08a4230

@NikolaMilosavljevic
Copy link
Member Author

With 64fa1b8, I've split the tests and switched to ConditionalTheory. I did have to use repo and tag as separate inline data, as xUnit prints only 50 characters of any inline data string. This can only be tweaked in xUnit v3.

I was getting the following, when using image as inline data:
Passed Microsoft.DotNet.Installer.Tests.LinuxInstallerTests.DebTest(image: "mcr.microsoft.com/dotnet/nightly/runtime-deps:10.0"···) [6 m 10 s]

Splitting into repo and tag produces a nicer output:
Passed Microsoft.DotNet.Installer.Tests.LinuxInstallerTests.DebTest(repo: "mcr.microsoft.com/dotnet/nightly/runtime-deps", tag: "10.0-preview-trixie-slim") [6 m 14 s]

string[] files = Directory.GetFiles(_contextDir, prefix + matchPattern, SearchOption.AllDirectories)
.Where(p => !Path.GetFileName(p).Contains("dotnet-runtime-deps-"))
.ToArray();
if (files.Length == 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious if multiple are expected?

if (distroType == DistroType.Rpm)
{
string? depsId = null;
if (baseImage.Contains("opensuse"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not refactor at that time? I don't like the thought of adding code that is not certain to be used, it is a form of technical debt. We don't have runtime-deps images for these distros. What is the ROI of adding them?

sb.AppendLine("# Install the installer packages and Microsoft.DotNet.ScenarioTests.SdkTemplateTests tool");
sb.Append("RUN");

// TODO: remove --force-all when aspnet package versioning issue have been resolved - https://github.com/dotnet/source-build/issues/4895
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this has been resolved. Can the workaround be removed now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this should be in VMR now - will confirm and update the code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need this workaround due to Debain DEPs package that requires libgssapi-krb5-2. The package is missing on mcr.microsoft.com/dotnet/nightly/runtime-deps:10.0-preview-trixie-slim

dotnet/dotnet-docker#6271


// Set entry point
sb.AppendLine("");
sb.AppendLine($"ENTRYPOINT [ \"dotnet\", \"{scenarioTestsBinary}\", \"--dotnet-root\", \"/usr/share/dotnet\" ]");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why the entrypoint approach was used versus specifying via Docker run?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No particular reason. Does docker run approach provide any additional benefits? I understand that entrypoint can be overridden when running this image, i.e. for debugging.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mainly asking from a readability perspective of the DistroTest method - it is not obvious what tests are actually being run.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Yeah, you're right. The way it is today, this command is hidden in dockerfile generation method. I'll update this in a follow up PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a fix for this and will push the change soon.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 004efb2

@NikolaMilosavljevic
Copy link
Member Author

I need help merging this - it is hitting the unrelated test issues that are being worked on atm. @MichaelSimons

@MichaelSimons MichaelSimons merged commit bc742b0 into dotnet:main Feb 25, 2025
34 of 40 checks passed

private const string NetStandard21RpmPackage = @"https://dotnetcli.blob.core.windows.net/dotnet/Runtime/3.1.0/netstandard-targeting-pack-2.1.0-x64.rpm";
private const string NetStandard21DebPackage = @"https://dotnetcli.blob.core.windows.net/dotnet/Runtime/3.1.0/netstandard-targeting-pack-2.1.0-x64.deb";
private const string RuntimeDepsRepo = "mcr.microsoft.com/dotnet/nightly/runtime-deps";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that Preview 1 was released - this should be switched to "mcr.microsoft.com/dotnet/runtime-deps". @NikolaMilosavljevic, can you include that change as part of hooking these tests up to a pipeline? TIA

Comment on lines +138 to +139
// Find the scenario-tests package and unpack it to the context dir, subfolder "scenario-tests"
string? scenarioTestsPackage = Directory.GetFiles(nugetPackagesDir, "Microsoft.DotNet.ScenarioTests.SdkTemplateTests*.nupkg", SearchOption.AllDirectories).FirstOrDefault();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm struggling to follow the execution flow here. Where is that package coming from?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this project have a dependency on the scenario-tests.proj build?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Microsoft.DotNet.ScenarioTests.SdkTemplateTests*.nupkg package is a product of the scenario-tests repo. I did mention this yesterday at the meeting as a need to have this repo built separately from testing it - as it is today.

However, the plan is for installer tests to run during VMR Validation stage, and download all packages produced during VMR build. Scenario-tests package should be built, if not, that should be changed.

I will be testing the second part of installer-tests work soon, the pipeline hook-up.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the abovementioned plan is not possible, I'd add a dependency on scenario-tests repo project and have it built as part of installer testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Infrastructure untriaged Request triage from a team member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants