From cb7332efb2b71262801583849063f98071f98786 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Mon, 12 Aug 2024 19:16:10 +0100 Subject: [PATCH] Run the Basic ContentBuilder Tests on CI We are currently not running ANY tests on CI. Lets correct this by running at least the content building and processor tests on CI. Certain content pipelines tests (Audio & Effects) have been disabled because they fail or hang on CI at this time. Current the tests run in x64 dotnet so that we can pass the TextureCompression tests. This PR #8456 should fix the texture compression issues so we do not need x64 dotnet. The Effect compilation for Linux /Mac needs to happen in wine. But dotnet 8 does not seem to run under wine on CI at this time. So that will need to be looked at. --- .github/workflows/main.yml | 55 +++++++++++++- .../Assets/Projects/BuildSimpleProject.csproj | 50 ++----------- .../MonoGame.Content.Builder.Task.targets | 7 +- .../MonoGame.Content.Builder/BuildContent.cs | 8 +- .../MonoGame.Tools.Tests/AudioContentTests.cs | 3 + .../BitmapContentTests.cs | 3 + .../BuilderTargetsTest.cs | 73 ++++++++++--------- .../EffectProcessorTests.cs | 3 + .../ModelProcessorTests.cs | 2 + .../MonoGame.Tools.Tests.csproj | 5 ++ .../MonoGame.Tools.Tests/Mp3ImporterTests.cs | 3 + .../MonoGame.Tools.Tests/OggImporterTests.cs | 3 + .../TextureImporterTests.cs | 3 + .../MonoGame.Tools.Tests/WavImporterTests.cs | 3 + .../MonoGame.Tools.Tests/WmaImporterTests.cs | 3 + .../BuildFrameworksTasks/BuildAndroidTask.cs | 15 +++- build/BuildToolsTasks/BuildToolTestsTask.cs | 12 +++ build/Tasks.cs | 6 ++ 18 files changed, 169 insertions(+), 88 deletions(-) create mode 100644 build/BuildToolsTasks/BuildToolTestsTask.cs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5f7dfb69f32..f132d120254 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,25 +25,73 @@ jobs: uses: actions/setup-java@v4 with: distribution: 'microsoft' - java-version: '11' + java-version: '17' - name: Disable annotations run: echo "::remove-matcher owner=csc::" + - name: install wine64 on linux + run: | + sudo apt install p7zip-full curl + sudo dpkg --add-architecture i386 + sudo mkdir -pm755 /etc/apt/keyrings + sudo wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key + sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources + sudo apt update && sudo apt install --install-recommends winehq-stable + if: runner.os == 'Linux' + + - name: Install Arial Font + run: | + echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true" | sudo debconf-set-selections + sudo apt install -y ttf-mscorefonts-installer + sudo fc-cache + fc-match Arial + if: runner.os == 'Linux' + + - name: install wine64 on macos + run: | + brew install wine-stable p7zip freeimage freetype + sudo mkdir -p /usr/local/lib + sudo ln -s /opt/homebrew/lib/libfreetype.dylib /usr/local/lib/libfreetype6.dylib + sudo ln -s /opt/homebrew/lib/libfreeimage.dylib /usr/local/lib/libfreeimage.dylib + if: runner.os == 'macOS' + + - name: Setup Wine + run: wget -qO- https://monogame.net/downloads/net8_mgfxc_wine_setup.sh | bash + if: runner.os != 'Windows' + - name: Install required workloads run: | if [ "$RUNNER_OS" == "Linux" ]; then - echo "MICROSOFT SUPPORT ANDROID WORKLOAD ON LINUX PLZZZ!" + dotnet workload install android elif [ "$RUNNER_OS" == "Windows" ]; then dotnet.exe workload install android ios macos else - dotnet workload install android ios macos + dotnet workload install android fi shell: bash - name: Build run: dotnet run --project build/Build.csproj -- --target=Default + - name: Test + run: dotnet test Tools/MonoGame.Tools.Tests/MonoGame.Tools.Tests.csproj --blame-hang-timeout 1m -c Release + env: + DOTNET_ROOT: ${{github.workspace}}/dotnet64 + MGFXC_WINE_PATH: /home/runner/.winemonogame + if: runner.os == 'Linux' + + - name: Test + run: dotnet test Tools/MonoGame.Tools.Tests/MonoGame.Tools.Tests.csproj --blame-hang-timeout 1m -c Release + env: + DOTNET_ROOT: ${{github.workspace}}/dotnet64 + MGFXC_WINE_PATH: /Users/runner/.winemonogame + if: runner.os == 'macOS' + + - name: Test + run: dotnet test Tools/MonoGame.Tools.Tests/MonoGame.Tools.Tests.csproj --blame-hang-timeout 1m -c Release + if: runner.os == 'Windows' + - name: Expose GitHub Runtime uses: crazy-max/ghaction-github-runtime@v3 @@ -88,3 +136,4 @@ jobs: removeArtifacts: true artifacts: "nugets/*.nupkg" token: ${{ secrets.GITHUB_TOKEN }} + diff --git a/Tests/Assets/Projects/BuildSimpleProject.csproj b/Tests/Assets/Projects/BuildSimpleProject.csproj index f01aead9d8d..ead23a2b9a1 100644 --- a/Tests/Assets/Projects/BuildSimpleProject.csproj +++ b/Tests/Assets/Projects/BuildSimpleProject.csproj @@ -1,50 +1,16 @@  - - + + - Debug - AnyCPU - 8.0.30703 - 2.0 - {1A3C19CC-557D-4009-82D6-92B511EA4172} - WinExe - Properties - BuildSimpleProject - BuildSimpleProject - 512 - DesktopGL - v4.5 - - - - true - bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\ - DEBUG;TRACE;LINUX - full - AnyCPU - prompt - false - 4 - - - - bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\ - TRACE;LINUX - true - pdbonly - AnyCPU - prompt - false - 4 + Exe + net8.0 + Major + false + DesktopGL - - - - - - + diff --git a/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.targets b/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.targets index b2df319d63b..4c2ab79c492 100644 --- a/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.targets +++ b/Tools/MonoGame.Content.Builder.Task/MonoGame.Content.Builder.Task.targets @@ -58,7 +58,8 @@ %(MonoGameContentReference.Link) %(MonoGameContentReference.RootDir)%(MonoGameContentReference.Directory) %(MonoGameContentReference.ContentFolder) - %(MonoGameContentReference.Filename) + %(MonoGameContentReference.OutputFolder) + %(MonoGameContentReference.Filename) - + diff --git a/Tools/MonoGame.Content.Builder/BuildContent.cs b/Tools/MonoGame.Content.Builder/BuildContent.cs index dc712a06154..3e19f9c7303 100644 --- a/Tools/MonoGame.Content.Builder/BuildContent.cs +++ b/Tools/MonoGame.Content.Builder/BuildContent.cs @@ -403,16 +403,12 @@ public void Build(out int successCount, out int errorCount) } catch (PipelineException ex) { - Console.Error.WriteLine("{0}: error: {1}", c.SourceFile, ex.Message); - if (ex.InnerException != null) - Console.Error.WriteLine(ex.InnerException.ToString()); + Console.Error.WriteLine("{0}: error: {1}. {2}", c.SourceFile, ex.Message, ex.InnerException != null ? ex.InnerException : string.Empty); ++errorCount; } catch (Exception ex) { - Console.Error.WriteLine("{0}: error: {1}", c.SourceFile, ex.Message); - if (ex.InnerException != null) - Console.Error.WriteLine(ex.InnerException.ToString()); + Console.Error.WriteLine("{0}: error: {1}. {2}", c.SourceFile, ex.Message, ex.InnerException != null ? ex.InnerException : string.Empty); ++errorCount; } } diff --git a/Tools/MonoGame.Tools.Tests/AudioContentTests.cs b/Tools/MonoGame.Tools.Tests/AudioContentTests.cs index b83284bb721..a9daf63cce1 100644 --- a/Tools/MonoGame.Tools.Tests/AudioContentTests.cs +++ b/Tools/MonoGame.Tools.Tests/AudioContentTests.cs @@ -11,6 +11,9 @@ namespace MonoGame.Tests.ContentPipeline { +#if MACOS + [Ignore("Hanging on Mac in CI?")] +#endif class AudioContentTests { [Test] diff --git a/Tools/MonoGame.Tools.Tests/BitmapContentTests.cs b/Tools/MonoGame.Tools.Tests/BitmapContentTests.cs index b4deab5bcb2..38e82c8d361 100644 --- a/Tools/MonoGame.Tools.Tests/BitmapContentTests.cs +++ b/Tools/MonoGame.Tools.Tests/BitmapContentTests.cs @@ -9,6 +9,9 @@ namespace MonoGame.Tests.ContentPipeline { +#if MACOS || LINUX + [Ignore("Does not work on Unix based systems. We need to get wine working on CI.")] +#endif class BitmapContentTests { // Needed to copy from an array of struct to a byte array diff --git a/Tools/MonoGame.Tools.Tests/BuilderTargetsTest.cs b/Tools/MonoGame.Tools.Tests/BuilderTargetsTest.cs index 99455e4be0a..990d3c9d61a 100644 --- a/Tools/MonoGame.Tools.Tests/BuilderTargetsTest.cs +++ b/Tools/MonoGame.Tools.Tests/BuilderTargetsTest.cs @@ -8,64 +8,71 @@ namespace MonoGame.Tests.ContentPipeline [TestFixture] public class BuilderTargetsTest { - string[] msBuildFolders = new string[] + string FindTool (string toolName) { - Path.Combine ("MSBuild", "15.0", "Bin", "MSBuild.exe"), - Path.Combine ("MSBuild", "14.0", "Bin", "MSBuild.exe"), - }; - string FindBuildTool(string buildTool) - { - if (Environment.OSVersion.Platform == PlatformID.Win32NT && buildTool == "msbuild") + var dotnetRoot = Environment.GetEnvironmentVariable ("DOTNET_ROOT"); + TestContext.WriteLine ("DOTNET_ROOT=" + dotnetRoot); + if (!string.IsNullOrEmpty (dotnetRoot)) { - var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); - foreach (var path in msBuildFolders) + var dotNetExe = Path.Combine (dotnetRoot, OperatingSystem.IsWindows() ? "dotnet.exe" : "dotnet"); + TestContext.WriteLine ("DOTNET_EXE=" + dotNetExe); + if (File.Exists (dotNetExe)) { - if (File.Exists(Path.Combine(programFiles, path))) - return Path.Combine(programFiles, path); + TestContext.WriteLine ("returning:" + dotNetExe); + return dotNetExe; } } - return buildTool; + TestContext.WriteLine ("returning:" + toolName); + return toolName; } bool RunBuild(string buildTool, string projectFile, params string[] parameters) { var root = Path.GetDirectoryName(typeof(BuilderTargetsTest).Assembly.Location); - var psi = new ProcessStartInfo(FindBuildTool(buildTool)) + var tool = FindTool(buildTool); + var psi = new ProcessStartInfo(tool) { - Arguments = projectFile + " /t:BuildContent " + string.Join(" ", parameters) + " /noconsolelogger \"/flp1:LogFile=build.log;Encoding=UTF-8;Verbosity=Diagnostic\"", + Arguments = $"build {projectFile} -t:IncludeContent {string.Join(" ", parameters)} -tl:off -bl -p:DotnetCommand=\"{tool}\"", WorkingDirectory = root, - UseShellExecute = true, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true }; + TestContext.WriteLine (psi.FileName + " " + psi.Arguments); using (var process = Process.Start(psi)) { - process.WaitForExit(); + process.OutputDataReceived += (sender, e) => { + if (!string.IsNullOrEmpty(e.Data)) + { + TestContext.WriteLine($"Output: {e.Data}"); + } + }; + + process.ErrorDataReceived += (sender, e) => { + if (!string.IsNullOrEmpty(e.Data)) + { + TestContext.WriteLine($"Error: {e.Data}"); + } + }; + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + if (!process.WaitForExit(60000)) {// wait for 60 seconds + process.Kill (); + } return process.ExitCode == 0; } } - static object[] BuilderTargetsBuildTools = new object[] { - "msbuild", - "xbuild", - }; - [Test] - [TestCaseSource("BuilderTargetsBuildTools")] -#if DESKTOPGL - [Ignore("Fails on Mac build server with xbuild for some reason.")] -#else - [Ignore("This test need to be rewritten to properly test Tools\\MonoGame.Content.Builder instead of the old builder targets.")] -#endif - public void BuildSimpleProject(string buildTool) + public void BuildSimpleProject() { - if (buildTool == "xbuild" && Environment.OSVersion.Platform == PlatformID.Win32NT) - Assert.Ignore("Skipping xbuild tests on windows"); - var root = Path.GetDirectoryName(typeof(BuilderTargetsTest).Assembly.Location); var outputPath = Path.Combine(root, "Assets", "Projects", "Content", "bin"); if (Directory.Exists(outputPath)) Directory.Delete(outputPath, recursive: true); - var result = RunBuild(buildTool, Path.Combine("Assets", "Projects", "BuildSimpleProject.csproj"), new string[] { - "/p:MonoGameContentBuilderExe=" + Path.Combine(root, "MGCB.exe") + var result = RunBuild("dotnet", Path.Combine(root, "Assets", "Projects", "BuildSimpleProject.csproj"), new string[] { + "-p:MGCBCommand=" + Path.Combine(root, "mgcb.dll") }); Assert.AreEqual(true, result, "Content Build should have succeeded."); var contentFont = Path.Combine(outputPath, "DesktopGL", "Content", "ContentFont.xnb"); diff --git a/Tools/MonoGame.Tools.Tests/EffectProcessorTests.cs b/Tools/MonoGame.Tools.Tests/EffectProcessorTests.cs index 7a4257981e6..bd4e4357caa 100644 --- a/Tools/MonoGame.Tools.Tests/EffectProcessorTests.cs +++ b/Tools/MonoGame.Tools.Tests/EffectProcessorTests.cs @@ -10,6 +10,9 @@ namespace MonoGame.Tests.ContentPipeline { +#if MACOS || LINUX + [Ignore("Does not work on CI yet. need to get wine working.")] +#endif class EffectProcessorTests { class ImporterContext : ContentImporterContext diff --git a/Tools/MonoGame.Tools.Tests/ModelProcessorTests.cs b/Tools/MonoGame.Tools.Tests/ModelProcessorTests.cs index 0df69481aaf..c219e85586f 100644 --- a/Tools/MonoGame.Tools.Tests/ModelProcessorTests.cs +++ b/Tools/MonoGame.Tools.Tests/ModelProcessorTests.cs @@ -282,6 +282,7 @@ public void DefaultEffectTest() } [Test] + [Ignore ("Not working yet")] /// /// Test to validate a model with missing normals does not throw an exception using the default ModelProcessor. /// @@ -305,6 +306,7 @@ public void MissingNormalsTestDefault() } [Test] + [Ignore ("Not working yet")] /// /// Test to validate a model with missing normals does not throw an exception using a custom ModelProcessor using MeshHelper.CalculateTangentFrames directly. /// diff --git a/Tools/MonoGame.Tools.Tests/MonoGame.Tools.Tests.csproj b/Tools/MonoGame.Tools.Tests/MonoGame.Tools.Tests.csproj index 23b50f97026..24bcd013c78 100644 --- a/Tools/MonoGame.Tools.Tests/MonoGame.Tools.Tests.csproj +++ b/Tools/MonoGame.Tools.Tests/MonoGame.Tools.Tests.csproj @@ -9,6 +9,9 @@ false false DESKTOPGL + $(DefineConstants);MACOS + $(DefineConstants);WINDOWS + $(DefineConstants);LINUX ..\..\Artifacts\Tests\Tools False true @@ -23,6 +26,8 @@ + + diff --git a/Tools/MonoGame.Tools.Tests/Mp3ImporterTests.cs b/Tools/MonoGame.Tools.Tests/Mp3ImporterTests.cs index 5f5ba7f2fe3..1139580ba92 100644 --- a/Tools/MonoGame.Tools.Tests/Mp3ImporterTests.cs +++ b/Tools/MonoGame.Tools.Tests/Mp3ImporterTests.cs @@ -9,6 +9,9 @@ namespace MonoGame.Tests.ContentPipeline { +#if MACOS + [Ignore("Hanging on Mac in CI?")] +#endif class Mp3ImporterTests { [Test] diff --git a/Tools/MonoGame.Tools.Tests/OggImporterTests.cs b/Tools/MonoGame.Tools.Tests/OggImporterTests.cs index ab0df895009..285f251c33d 100644 --- a/Tools/MonoGame.Tools.Tests/OggImporterTests.cs +++ b/Tools/MonoGame.Tools.Tests/OggImporterTests.cs @@ -9,6 +9,9 @@ namespace MonoGame.Tests.ContentPipeline { +#if MACOS + [Ignore("Hanging on Mac in CI?")] +#endif class OggImporterTests { [Test] diff --git a/Tools/MonoGame.Tools.Tests/TextureImporterTests.cs b/Tools/MonoGame.Tools.Tests/TextureImporterTests.cs index f3e49fb6f8d..c7e20d5e0da 100644 --- a/Tools/MonoGame.Tools.Tests/TextureImporterTests.cs +++ b/Tools/MonoGame.Tools.Tests/TextureImporterTests.cs @@ -105,6 +105,9 @@ public void ImportTif( ) /// Note that the image was created with Freeimage from a bitmap /// [Test] +#if MACOS || LINUX + [Ignore("Does not work on Unix based systems. We need to get wine working on CI.")] +#endif public void ImportImageWithBadContent( ) { Assert.Throws(typeof(InvalidContentException), ( ) => ImportStandard("Assets/Textures/rgbf.tif", SurfaceFormat.Vector4, 64)); diff --git a/Tools/MonoGame.Tools.Tests/WavImporterTests.cs b/Tools/MonoGame.Tools.Tests/WavImporterTests.cs index fd367c2e2d3..3dc54832c5e 100644 --- a/Tools/MonoGame.Tools.Tests/WavImporterTests.cs +++ b/Tools/MonoGame.Tools.Tests/WavImporterTests.cs @@ -9,6 +9,9 @@ namespace MonoGame.Tests.ContentPipeline { +#if MACOS + [Ignore("Hanging on Mac in CI?")] +#endif class WavImporterTests { [Test] diff --git a/Tools/MonoGame.Tools.Tests/WmaImporterTests.cs b/Tools/MonoGame.Tools.Tests/WmaImporterTests.cs index f04a9807af7..89d50df8c32 100644 --- a/Tools/MonoGame.Tools.Tests/WmaImporterTests.cs +++ b/Tools/MonoGame.Tools.Tests/WmaImporterTests.cs @@ -9,6 +9,9 @@ namespace MonoGame.Tests.ContentPipeline { +#if MACOS + [Ignore("Hanging on Mac in CI?")] +#endif class WmaImporterTests { [Test] diff --git a/build/BuildFrameworksTasks/BuildAndroidTask.cs b/build/BuildFrameworksTasks/BuildAndroidTask.cs index 70fa840712a..3a1e5784f10 100644 --- a/build/BuildFrameworksTasks/BuildAndroidTask.cs +++ b/build/BuildFrameworksTasks/BuildAndroidTask.cs @@ -7,5 +7,18 @@ public sealed class BuildAndroidTask : FrostingTask public override bool ShouldRun(BuildContext context) => context.IsWorkloadInstalled("android"); public override void Run(BuildContext context) - => context.DotNetPack(context.GetProjectPath(ProjectType.Framework, "Android"), context.DotNetPackSettings); + { + var arguments = new DotNetMSBuildSettings(); + arguments.WithProperty("AndroidSdkDirectory", System.Environment.GetEnvironmentVariable ("ANDROID_HOME")); + arguments.WithProperty("AcceptAndroidSDKLicenses", "true"); + arguments.WithTarget("InstallAndroidDependencies"); + var installSettings = new DotNetBuildSettings + { + MSBuildSettings = arguments, + Verbosity = DotNetVerbosity.Minimal, + Configuration = context.DotNetPackSettings.Configuration, + }; + context.DotNetBuild(context.GetProjectPath(ProjectType.Framework, "Android"), installSettings); + context.DotNetPack(context.GetProjectPath(ProjectType.Framework, "Android"), context.DotNetPackSettings); + } } diff --git a/build/BuildToolsTasks/BuildToolTestsTask.cs b/build/BuildToolsTasks/BuildToolTestsTask.cs new file mode 100644 index 00000000000..15f9c9f23e5 --- /dev/null +++ b/build/BuildToolsTasks/BuildToolTestsTask.cs @@ -0,0 +1,12 @@ + +namespace BuildScripts; + +[TaskName("Build ToolTests")] +[IsDependentOn(typeof(BuildContentPipelineTask))] +public sealed class BuildToolTestsTask : FrostingTask +{ + public override void Run(BuildContext context) + { + context.DotNetBuild(context.GetProjectPath(ProjectType.Tools, "MonoGame.Tools.Tests"), context.DotNetBuildSettings); + } +} \ No newline at end of file diff --git a/build/Tasks.cs b/build/Tasks.cs index fc74aa211a3..214275926c4 100644 --- a/build/Tasks.cs +++ b/build/Tasks.cs @@ -23,10 +23,16 @@ public sealed class BuildToolsTask : FrostingTask { } [IsDependentOn(typeof(BuildVSTemplatesTask))] public sealed class BuildTemplatesTask : FrostingTask { } +[TaskName("Build Tests")] +[IsDependentOn(typeof(BuildToolTestsTask))] +public sealed class BuildTestsTask : FrostingTask { } + + [TaskName("Build All")] [IsDependentOn(typeof(BuildFrameworksTask))] [IsDependentOn(typeof(BuildToolsTask))] [IsDependentOn(typeof(BuildTemplatesTask))] +[IsDependentOn(typeof(BuildTestsTask))] public sealed class BuildAllTask : FrostingTask { } [TaskName("Deploy")]