Skip to content

Conversation

SiyuGithub
Copy link
Contributor

@SiyuGithub SiyuGithub commented Jan 11, 2023

Add [CocoaFact] attribute to run unit tests on the Main UI threat. Before this PR, StaFact doesn't have a suitable test attribute to allow others to run their UI thread only unit tests on Mac.

What is included in this PR:
Implement new [CocoaFact] attribute. Add a MacOS app bundle which contains a Xunit built-in test runner to run new attribute unit tests on the UI Main thread.

@SiyuGithub SiyuGithub marked this pull request as draft January 11, 2023 18:57
@sandyarmstrong
Copy link
Contributor

This is a work-in-progress branch, we'll take it out of draft when it's ready for review.

<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<TargetingWindows Condition=" '$(TargetFramework)' == 'net472' or $(TargetFramework.EndsWith('-windows')) ">true</TargetingWindows>
<TargetingMacos Condition=" '$(TargetFramework)' == 'net6.0-macos10.15' or $(TargetFramework.EndsWith('-macos')) ">true</TargetingMacos>
Copy link
Owner

Choose a reason for hiding this comment

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

There is a contains syntax that may be better to use here if you're liable to use -macos10.15, so that the condition doesn't silently start failing when you later move to -macos12.
I think it's roughly this:
$(TargetFramework.Contains('macos'))

global.json Outdated
{
"sdk": {
"version": "7.0.101",
"version": "7.0.100",
Copy link
Owner

Choose a reason for hiding this comment

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

I presume this is just to allow you to build locally on your box and not because 7.0.101 is broken somehow. We'll need to revert this before merging. You could do it now and upgrade your SDK to solve the problem if you want.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yup, this whole branch was just us getting far enough locally to have something we could mess with in the Mac editor project. It's definitely not cleaned up or complete yet. 😄

@AArnott
Copy link
Owner

AArnott commented Jan 13, 2023

I don't know what the effect of .DS_Store files are on a mac, but I don't want them in the repo. Please remove them and add to the .gitignore file to ensure they don't come back.

Comment on lines 4 to 5
Xunit.Sdk.CocoaFactDiscoverer
Xunit.Sdk.CocoaFactDiscoverer.CocoaFactDiscoverer(Xunit.Abstractions.IMessageSink! diagnosticMessageSink) -> void
Copy link
Owner

@AArnott AArnott Jan 13, 2023

Choose a reason for hiding this comment

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

Should these cocoa attributes really be exposed to net472? I get that mono used to target this, but that's history right? Can we expose the new attribute exclusively to the macos target framework?
Actually, looking at your msbuild conditions, it doesn't look like they should be exposed to net472 after all, which makes me wonder if you're getting compilation warnings suggesting you remove them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right that we won't expose those to net472, I will clean them up.

Comment on lines 30 to 35
<ItemGroup>
<None Remove="Mac\" />
</ItemGroup>
<ItemGroup>
<Folder Include="Mac\" />
</ItemGroup>
Copy link
Owner

Choose a reason for hiding this comment

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

Can we remove these items, please?

<PropertyGroup>
<TargetFrameworks>net472;netstandard2.0;net6.0;net6.0-windows</TargetFrameworks>
<TargetFrameworks>net472;netstandard2.0;net6.0;net6.0-windows;net6.0-macos10.15</TargetFrameworks>
<SupportedOSPlatformVersion Condition="'$(TargetingMacos)'=='true'">10.15</SupportedOSPlatformVersion>
Copy link
Owner

Choose a reason for hiding this comment

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

I'm surprised this property isn't set by virtue of the TargetFramework mentioning the macos version. Are you sure this is necessary?

Copy link
Contributor

Choose a reason for hiding this comment

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

In theory, setting this is supposed to allow us to target net6.0-macos instead of net6.0-macos10.15, and still get net6.0-macos10.15 in the nupkg, but it wasn't working and we need to investigate. If we don't specify 10.15 somewhere, it uses the OS version of whoever does the build.

But yeah, it's not needed if we explicitly target net6.0-macos10.15.

Copy link
Owner

Choose a reason for hiding this comment

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

If we don't specify 10.15 somewhere, it uses the OS version of whoever does the build.

Are you sure? I can build net6.0-macos from Windows, and that has no basis for a macos version.
Also, when I target net6.0-windows, that targets Windows 7 -- not the version of Windows that I am using.

Copy link
Contributor

@sandyarmstrong sandyarmstrong Jan 13, 2023

Choose a reason for hiding this comment

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

It looks like each TFW can specify its own default OS version behavior: https://learn.microsoft.com/en-us/dotnet/standard/frameworks#os-version-in-tfms. So I would imagine the macOS workload targets are doing this. It could be that they pick macOS 13 by default not because that was the build host's OS version, but because that's the version associated with the Xcode SDK. Either way, we need to manually specify 10.15.

And I think I see my answer for SupportedOSPlatformVersion here: https://learn.microsoft.com/en-us/dotnet/standard/frameworks#support-older-os-versions. Seems that SupportedOSPlatformVersion indicates runtime version. So I should drop it anyway.

</ItemGroup>

<PropertyGroup Label="Globals">
<PartialTargetPath>$(RepoRootPath)\bin\Xunit.StaFact.Tests.Mac\$(Configuration)\$(TargetFramework)\osx-x64</PartialTargetPath>
Copy link
Contributor

Choose a reason for hiding this comment

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

The osx-x64 part here seems like it would fail on arm64.

If that's the case, you could do something like the following:

<HostArchitecture>$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)</HostArchitecture>
<HostArchitecture>$(HostArchitecture.ToLower())</HostArchitecture>
<PartialTargetPath>$(RepoRootPath)\bin\Xunit.StaFact.Tests.Mac\$(Configuration)\$(TargetFramework)\osx-$(HostArchitecture)</PartialTargetPath>

@SiyuGithub
Copy link
Contributor Author

Other than the Mac architecture problem described above, this PR is ready for review. Thanks!

P.S. Not sure if the problem I mentioned above has any influence, since the MacOS pipeline is using osx-x64 instead arm64, so all the tests are built and passed.

@SiyuGithub SiyuGithub marked this pull request as ready for review January 31, 2023 21:20
@SiyuGithub
Copy link
Contributor Author

Hi @AArnott, can I have a code review on this PR when you have time?
And since I don't have the Write Access to the StaFact repo, do you want me to apply one, or you prefer someone else who has the access to merge it after the review? Thanks!

@SiyuGithub SiyuGithub changed the title Dev/siyu/start to add cocoa fact Add cocoa fact attribute and related unit tests Feb 1, 2023
}
if ($IsMacOS) {
$frameworks += '-f','net6.0-macos'
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the changes to this file can be undone now, right?

@AArnott
Copy link
Owner

AArnott commented Feb 6, 2023

I can't build Xunit.StaFact.Tests.Mac on my Windows machine due to this error:

2>C:\Program Files\dotnet\sdk\7.0.102\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.targets(1226,3): error MSB4019: The imported project "C:\Program Files\dotnet\sdk\7.0.102\Sdks\Microsoft.NET.Sdk\13.1.1024\targets\Xamarin.Shared.Sdk.MultiTarget.targets" was not found. Confirm that the expression in the Import declaration ";..\13.1.1024\targets\Xamarin.Shared.Sdk.MultiTarget.targets" is correct, and that the file exists on disk.

What component do I need to install to get this?

@AArnott
Copy link
Owner

AArnott commented Feb 6, 2023

This works if I run init.ps1, restore, build works and even VS works if launched from that window. But VS launched from the start menu does not, nor does the command prompt until init.ps1 is run in that particular window. It seems that dotnet workload restore only works for a user-local unzipped copy of the .NET SDK. How can we get this to work in VS without having to spawn VS from an environment in which init.ps1 has just run?

@sandyarmstrong
Copy link
Contributor

How can we get this to work in VS without having to spawn VS from an environment in which init.ps1 has just run?

I don't know. On Mac, we have a property we can add to a solution to tell us where it should look for the .NET SDK. I'm not aware of any way to do this on Windows.

Should we add a solution filter that removes the Mac projects from the solution that would be used by default?

@AArnott
Copy link
Owner

AArnott commented Feb 6, 2023

It isn't just the mac project. It causes all the projects to fail. The error I quoted appears for both Xunit.StaFact and Xunit.StaFact.Tests.Mac. And the presence of that error apparently causes nuget restore to altogether fail, so 302 compile errors are reported in the Error List across all projects.

I've finished reviewing the PR and pushed a few changes so that I'm happy with the result, except for the fact that the solution is unusable in VS except when launched from a command prompt after running init. That's a very big loss from this PR, so I'm holding out hope that we can resolve that before merging this.

init.ps1 Outdated
# Install specific macOS workload version in order to support usage on older .NET and macOS
$rollbackFile = Join-Path ([System.IO.Path]::GetTempPath()) ([System.Guid]::NewGuid())
@{
"microsoft.net.sdk.macos" = "12.3.2372/7.0.100"
Copy link
Owner

Choose a reason for hiding this comment

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

Can you explain to me more about this requirement? Does this mean that dotnet workload restore is not enough?
I wonder too if this is somehow related to msbuild's failing import error.

Copy link
Contributor

Choose a reason for hiding this comment

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

The macOS workload is necessary in order to target net6.0-macos. That target framework is not available without the workload being installed.

The .NET SDK makes it difficult to specify a preferred version of a given workload. You have to use a rollback file to achieve this. Without specifying the version, the SDK will pull the latest for the SDK version specified in global.json (without taking target framework into account). So, even though this project is net6.0-macos, it would be referencing a newer Microsoft.macOS.dll that is not compatible with projects using the .NET 6 SDK and an older macos workload. To fix this, we specify an older workload version that is compatible with an older .NET/workload.

I wonder too if this is somehow related to msbuild's failing import error.

Yes. dotnet workload restore appears to be broken, at least with the macOS workload. It's like it tries to load targets before they have been installed. Tomas filed a bug about it recently: dotnet/sdk#30230. It would be great if the .NET SDK team fixed that. We can't depend on dotnet restore for CI, because it would pick up the wrong workload version as described earlier, but for local development it would be very convenient.

Copy link
Owner

Choose a reason for hiding this comment

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

Thanks. That's helpful, and I've upvoted that issue.
How do dotnet workloads work when the SDK to be installed into is in an elevated location like Program Files?
It's very odd to me that init.ps1 works, but running this command outside of init fails, where workloads.json refers to the json file your init.ps1 creates:

> dotnet workload install macos --from-rollback-file workloads.json

Downloading Microsoft.macOS.Sdk.Msi.x64 (13.1.1024)
Workload installation failed. Rolling back installed packs...
Workload installation failed: One or more errors occurred. (microsoft.macos.sdk.msi.x64::13.1.1024 is not found in NuGet feeds https://api.nuget.org/v3/index.json;https://pkgs.dev.azure.com/dnceng/public/_packaging/test-tools/nuget/v3/index.json".)

Copy link
Contributor

Choose a reason for hiding this comment

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

Notice it's picking 13.1.1024, which is a different version. It's newer, and I don't see it in nuget.

If you have multiple SDK versions installed, and you're running workload install from outside of a context where a global.json is specifying your SDK version, you can get different results based on whatever the default SDK is.

How do dotnet workloads work when the SDK to be installed into is in an elevated location like Program Files?

On Mac, when installing workloads to the machine-wide .NET SDK installation (/usr/local/share/dotnet), you have to use sudo to elevate. Presumably something similar is needed on Windows?

Copy link
Owner

@AArnott AArnott Feb 7, 2023

Choose a reason for hiding this comment

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

I do have the 7.0.200 installed, as of this morning when a VS update installed it. But all my dotnet workload install attempts were within the directory containing global.json, so evidently my repo's 7.0.101 constraint wasn't effective at retaining behavior from that SDK in this regard.

Windows doesn't need sudo to elevate. It prompts with interactive UI as needed.

The failures I'm seeing turn out to come from a collection of bugs in the SDK around this area. The do not show up when DOTNET_ROOT is set, which is why it works in non-elevated scenarios.

@sandyarmstrong
Copy link
Contributor

sandyarmstrong commented Feb 6, 2023

It isn't just the mac project. It causes all the projects to fail. The error I quoted appears for both Xunit.StaFact and Xunit.StaFact.Tests.Mac. And the presence of that error apparently causes nuget restore to altogether fail, so 302 compile errors are reported in the Error List across all projects.

I've finished reviewing the PR and pushed a few changes so that I'm happy with the result, except for the fact that the solution is unusable in VS except when launched from a command prompt after running init. That's a very big loss from this PR, so I'm holding out hope that we can resolve that before merging this.

Yeah, that's really unfortunate. If we're lucky, the .NET SDK team will fix workload restore for .NET 8, but I wouldn't count on a fix being backported.

Perhaps we should disable the net6.0-macos target framework unless building on Mac or in CI? And in the rare cases where you want to build locally on Windows, you could remove that condition and just make sure to launch VS correctly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants