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

Run template tests run in parallel to save 15min of run time #17672

Merged
merged 2 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,28 +58,29 @@ public void AndroidTemplateTearDown()
public void RunOnAndroid(string id, string framework, string config)
{
var projectDir = TestDirectory;
var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");
var projectName = DotnetInternal.GetProjectName(projectDir);
var projectFile = Path.Combine(projectDir, $"{projectName}.csproj");
Comment on lines +61 to +62
Copy link
Member Author

Choose a reason for hiding this comment

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

This change and other projectName stuff is repeated for nearly every test: it's what ensures that the lengthy project names used throughout the tests are not too long for WinUI AppX (see PR description for more info).


Assert.IsTrue(DotnetInternal.New(id, projectDir, framework),
Assert.IsTrue(DotnetInternal.New(id, projectDir, projectName, framework),
$"Unable to create template {id}. Check test output for errors.");

AddInstrumentation(projectDir);
AddInstrumentation(projectDir, projectName);

Assert.IsTrue(DotnetInternal.Build(projectFile, config, target: "Install", framework: $"{framework}-android", properties: BuildProps),
$"Project {Path.GetFileName(projectFile)} failed to install. Check test output/attachments for errors.");

testPackage = $"com.companyname.{Path.GetFileName(projectDir).ToLowerInvariant()}";
testPackage = $"com.companyname.{projectName.ToLowerInvariant()}";
Assert.IsTrue(XHarness.RunAndroid(testPackage, Path.Combine(projectDir, "xh-results"), -1),
$"Project {Path.GetFileName(projectFile)} failed to run. Check test output/attachments for errors.");
}

void AddInstrumentation(string projectDir)
void AddInstrumentation(string projectDir, string projectName)
{
var androidDir = Path.Combine(projectDir, "Platforms", "Android");
var instDestination = Path.Combine(androidDir, "Instrumentation.cs");
FileUtilities.CreateFileFromResource("TemplateLaunchInstrumentation.cs", instDestination);
Assert.True(File.Exists(instDestination), "Failed to create Instrumentation.cs");
FileUtilities.ReplaceInFile(instDestination, "namespace mauitemplate", $"namespace {Path.GetFileName(projectDir)}");
FileUtilities.ReplaceInFile(instDestination, "namespace mauitemplate", $"namespace {projectName}");

FileUtilities.ReplaceInFile(Path.Combine(androidDir, "MainActivity.cs"),
"MainLauncher = true",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,16 @@ public void AppleTemplateFxtTearDown()
public void RunOniOS(string id, string config, string framework)
{
var projectDir = TestDirectory;
var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");
var projectName = DotnetInternal.GetProjectName(projectDir);
var projectFile = Path.Combine(projectDir, $"{projectName}.csproj");

Assert.IsTrue(DotnetInternal.New(id, projectDir, framework),
Assert.IsTrue(DotnetInternal.New(id, projectDir, projectName, framework),
$"Unable to create template {id}. Check test output for errors.");

Assert.IsTrue(DotnetInternal.Build(projectFile, config, framework: $"{framework}-ios", properties: BuildProps),
$"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors.");

var appFile = Path.Combine(projectDir, "bin", config, $"{framework}-ios", "iossimulator-x64", $"{Path.GetFileName(projectDir)}.app");
var appFile = Path.Combine(projectDir, "bin", config, $"{framework}-ios", "iossimulator-x64", $"{projectName}.app");

Assert.IsTrue(XHarness.RunAppleForTimeout(appFile, Path.Combine(projectDir, "xh-results"), TestSimulator.XHarnessID),
$"Project {Path.GetFileName(projectFile)} failed to run. Check test output/attachments for errors.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public string TestName
{
get
{
var result = TestContext.CurrentContext.Test.Name;
var result = "id_" + TestContext.CurrentContext.Test.ID + "_" + TestContext.CurrentContext.Test.Name;
foreach (var c in invalidChars.Concat(Path.GetInvalidPathChars().Concat(Path.GetInvalidFileNameChars())))
{
result = result.Replace(c, '_');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
using Microsoft.Maui.IntegrationTests.Apple;

[assembly: LevelOfParallelism(2)]
Copy link
Member Author

Choose a reason for hiding this comment

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

This is the key part of the change. Can adjust in the future higher/lower.


namespace Microsoft.Maui.IntegrationTests
{
[Parallelizable(scope: ParallelScope.All)]
public class TemplateTests : BaseBuildTest
{
[SetUp]
public void TemplateTestsSetUp()
{
File.Copy(Path.Combine(TestEnvironment.GetMauiDirectory(), "src", "Templates", "tests", "Directory.Build.props"),
Path.Combine(TestDirectory, "Directory.Build.props"), true);
Path.Combine(TestDirectory, "Directory.Build.props"), overwrite: true);
File.Copy(Path.Combine(TestEnvironment.GetMauiDirectory(), "src", "Templates", "tests", "Directory.Build.targets"),
Path.Combine(TestDirectory, "Directory.Build.targets"), true);
Path.Combine(TestDirectory, "Directory.Build.targets"), overwrite: true);
}

[Test]
Expand All @@ -30,9 +33,10 @@ public void TemplateTestsSetUp()
public void Build(string id, string framework, string config, bool shouldPack)
{
var projectDir = TestDirectory;
var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");
var projectName = DotnetInternal.GetProjectName(projectDir);
var projectFile = Path.Combine(projectDir, $"{projectName}.csproj");

Assert.IsTrue(DotnetInternal.New(id, projectDir, framework),
Assert.IsTrue(DotnetInternal.New(id, projectDir, projectName, framework),
$"Unable to create template {id}. Check test output for errors.");

EnableTizen(projectFile);
Expand All @@ -59,9 +63,10 @@ public void Build(string id, string framework, string config, bool shouldPack)
public void BuildUnpackaged(string id, string framework, string config)
{
var projectDir = TestDirectory;
var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");
var projectName = DotnetInternal.GetProjectName(projectDir);
var projectFile = Path.Combine(projectDir, $"{projectName}.csproj");

Assert.IsTrue(DotnetInternal.New(id, projectDir, framework),
Assert.IsTrue(DotnetInternal.New(id, projectDir, projectName, framework),
$"Unable to create template {id}. Check test output for errors.");

EnableTizen(projectFile);
Expand All @@ -81,9 +86,10 @@ public void PublishUnpackaged(string id, string framework, string config)
Assert.Ignore("Running Windows templates is only supported on Windows.");

var projectDir = TestDirectory;
var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");
var projectName = DotnetInternal.GetProjectName(projectDir);
var projectFile = Path.Combine(projectDir, $"{projectName}.csproj");

Assert.IsTrue(DotnetInternal.New(id, projectDir, framework),
Assert.IsTrue(DotnetInternal.New(id, projectDir, projectName, framework),
$"Unable to create template {id}. Check test output for errors.");

BuildProps.Add("WindowsPackageType=None");
Expand Down Expand Up @@ -118,9 +124,10 @@ void AssetExists(string filename)
public void PackCoreLib(string id, string framework, string config)
{
var projectDir = TestDirectory;
var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");
var projectName = DotnetInternal.GetProjectName(projectDir);
var projectFile = Path.Combine(projectDir, $"{projectName}.csproj");

Assert.IsTrue(DotnetInternal.New(id, projectDir, framework),
Assert.IsTrue(DotnetInternal.New(id, projectDir, projectName, framework),
$"Unable to create template {id}. Check test output for errors.");

EnableTizen(projectFile);
Expand Down Expand Up @@ -151,9 +158,10 @@ public void PackCoreLib(string id, string framework, string config)
public void BuildWithoutPackageReference(string id, string framework, string config)
{
var projectDir = TestDirectory;
var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");
var projectName = DotnetInternal.GetProjectName(projectDir);
var projectFile = Path.Combine(projectDir, $"{projectName}.csproj");

Assert.IsTrue(DotnetInternal.New(id, projectDir, framework),
Assert.IsTrue(DotnetInternal.New(id, projectDir, projectName, framework),
$"Unable to create template {id}. Check test output for errors.");

EnableTizen(projectFile);
Expand All @@ -178,9 +186,10 @@ public void BuildWithoutPackageReference(string id, string framework, string con
public void BuildWithDifferentVersionNumber(string id, string config, string display, string version)
{
var projectDir = TestDirectory;
var projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");
var projectName = DotnetInternal.GetProjectName(projectDir);
var projectFile = Path.Combine(projectDir, $"{projectName}.csproj");

Assert.IsTrue(DotnetInternal.New(id, projectDir),
Assert.IsTrue(DotnetInternal.New(id, projectDir, projectName),
$"Unable to create template {id}. Check test output for errors.");

EnableTizen(projectFile);
Expand All @@ -204,19 +213,21 @@ public void CheckEntitlementsForMauiBlazorOnMacCatalyst(string id, string config
Assert.Ignore("Running MacCatalyst templates is only supported on Mac.");

string projectDir = TestDirectory;
string projectFile = Path.Combine(projectDir, $"{Path.GetFileName(projectDir)}.csproj");
var projectName = DotnetInternal.GetProjectName(projectDir);
var projectFile = Path.Combine(projectDir, $"{projectName}.csproj");

// Note: Debug app is stored in the maccatalyst-x64 folder, while the Release is in parent directory
string appLocation = config == "Release" ?
Path.Combine(projectDir, "bin", config, $"{framework}-maccatalyst", $"{Path.GetFileName(projectDir)}.app") :
Path.Combine(projectDir, "bin", config, $"{framework}-maccatalyst", "maccatalyst-x64", $"{Path.GetFileName(projectDir)}.app");
Path.Combine(projectDir, "bin", config, $"{framework}-maccatalyst", $"{projectName}.app") :
Path.Combine(projectDir, "bin", config, $"{framework}-maccatalyst", "maccatalyst-x64", $"{projectName}.app");
string entitlementsPath = Path.Combine(projectDir, "x.xml");

List<string> buildWithCodeSignProps = new List<string>(BuildProps)
{
"EnableCodeSigning=true"
};

Assert.IsTrue(DotnetInternal.New(id, projectDir, framework), $"Unable to create template {id}. Check test output for errors.");
Assert.IsTrue(DotnetInternal.New(id, projectDir, projectName, framework), $"Unable to create template {id}. Check test output for errors.");
Assert.IsTrue(DotnetInternal.Build(projectFile, config, framework: $"{framework}-maccatalyst", properties: buildWithCodeSignProps, msbuildWarningsAsErrors: true),
$"Project {Path.GetFileName(projectFile)} failed to build. Check test output/attachments for errors.");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ public static bool Publish(string projectFile, string config, string target = ""
return Run("publish", $"{buildArgs} -bl:\"{binlogPath}\"");
}

public static bool New(string shortName, string outputDirectory, string framework = "")
public static bool New(string shortName, string outputDirectory, string projectName, string framework = "")
{
var args = $"{shortName} -o \"{outputDirectory}\"";
var args = $"{shortName} -o \"{outputDirectory}\" -n \"{projectName}\"";

if (!string.IsNullOrEmpty(framework))
args += $" -f {framework}";
Expand Down Expand Up @@ -119,5 +119,33 @@ public static string RunForOutput(string command, string args, out int exitCode,
return ToolRunner.Run(pinfo, out exitCode, timeoutInSeconds: timeoutInSeconds);
}

/// <summary>
/// Takes the given <paramref name="projectDir"/> and creates a valid C# project file name that
/// is suitable for a cross-platform .NET MAUI project.
/// </summary>
/// <param name="projectDir"></param>
/// <returns></returns>
public static string GetProjectName(string projectDir)
{
// By default, the project name is the name of the folder the template is being created in.
// That project name is then used in the Windows AppX manifest, and that has a maximum
// length of 50 chars, including the default name prefix used in .NET MAUI. So, if it's too
// long, we chop off a bit and specify an explicit project name that is not too long.
// The error you'd otherwise get is:
// MakeAppx : error : Error info: error C00CE169: App manifest validation error: The app manifest must be valid
// as per schema: Line 10, Column 13, Reason: 'com.companyname.SomeUnfortunateNameThatIsTooLongToBeValid'
// violates maxLength constraint of '50'.
const string AppXNamePrefix = "com.companyname.";

var projectName = Path.GetFileName(projectDir);
if ((AppXNamePrefix + projectName).Length >= 50)
{
return projectName.Substring(0, 50 - AppXNamePrefix.Length);
}
else
{
return projectName;
}
}
}
}