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

BinaryFormatter tests should be skipped only on AOT, WASM and Mobile #106858

Merged
merged 4 commits into from
Sep 2, 2024

Conversation

adamsitnik
Copy link
Member

A follow up to the discussion we have started at #106737

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Aug 23, 2024
@adamsitnik adamsitnik added area-System.Runtime binaryformatter-migration Issues related to the removal of BinaryFormatter and migrations away from it and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Aug 23, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

@adamsitnik
Copy link
Member Author

The initial change I’ve sent with this PR has allowed me to discover that there were 19 projects where BF-related tests were skipped since #103255 was merged.

@ericstj I’ve re-enabled those tests by adding a project reference similar to what you did in #106737. We don’t want to run these tests on Mobile, WASM and NativeAOT (not supported by design). How adding such project reference is going to affect the build time for those configurations? Should we somehow make it conditional? If so, should we introduce an MSBuild property (or any other setting) and handle all that logic is some .targets file so we would not need to copy it everywhere and update all occurrences when changes are needed?

@bartonjs There are 5 System.Collections.Tests tests that fail due to a product change. I think you have mentioned it at some point, but I just want to make sure that we are aware of that change, it’s documented and expected.

    Starting:    System.Collections.Tests (parallel test collections = on [24 threads], stop on fail = off)
      System.Collections.Tests.HashSet_Generic_Tests_string.ComparerSerialization [FAIL]
        Assert.IsType() Failure: Value is not the exact type
        Expected: typeof(System.Collections.Generic.StringEqualityComparer)
        Actual:   typeof(System.Collections.Generic.GenericEqualityComparer<string>)
        Stack Trace:
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\HashSet\HashSet.Generic.Tests.cs(891,0): at System.Collections.Tests.HashSet_Generic_Tests`1.<ComparerSerialization>g__TestComparerSerialization|64_0[TCompare
  d](IEqualityComparer`1 equalityComparer, String internalTypeName)
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\HashSet\HashSet.Generic.Tests.cs(859,0): at System.Collections.Tests.HashSet_Generic_Tests`1.ComparerSerialization()
             at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
          D:\projects\runtime\src\libraries\System.Private.CoreLib\src\System\Reflection\MethodBaseInvoker.cs(57,0): at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
      System.Collections.Tests.Dictionary_Tests.ComparerSerialization [FAIL]
        Assert.IsType() Failure: Value is not the exact type
        Expected: typeof(System.Collections.Generic.StringEqualityComparer)
        Actual:   typeof(System.Collections.Generic.GenericEqualityComparer<string>)
        Stack Trace:
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\Dictionary\Dictionary.Tests.cs(457,0): at System.Collections.Tests.Dictionary_Tests.TestComparerSerialization[T](IEqualityComparer`1 equalityComparer, String
  internalTypeName)
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\Dictionary\Dictionary.Tests.cs(426,0): at System.Collections.Tests.Dictionary_Tests.ComparerSerialization()
             at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
          D:\projects\runtime\src\libraries\System.Private.CoreLib\src\System\Reflection\MethodBaseInvoker.cs(57,0): at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
      System.Collections.Tests.HashSet_Generic_Tests_int.ComparerSerialization [FAIL]
        Assert.IsType() Failure: Value is not the exact type
        Expected: typeof(System.Collections.Generic.StringEqualityComparer)
        Actual:   typeof(System.Collections.Generic.GenericEqualityComparer<string>)
        Stack Trace:
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\HashSet\HashSet.Generic.Tests.cs(891,0): at System.Collections.Tests.HashSet_Generic_Tests`1.<ComparerSerialization>g__TestComparerSerialization|64_0[TCompare
  d](IEqualityComparer`1 equalityComparer, String internalTypeName)
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\HashSet\HashSet.Generic.Tests.cs(859,0): at System.Collections.Tests.HashSet_Generic_Tests`1.ComparerSerialization()
             at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
          D:\projects\runtime\src\libraries\System.Private.CoreLib\src\System\Reflection\MethodBaseInvoker.cs(57,0): at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
      System.Collections.Tests.HashSet_Generic_Tests_int_With_Comparer_WrapStructural_SimpleInt.ComparerSerialization [FAIL]
        Assert.IsType() Failure: Value is not the exact type
        Expected: typeof(System.Collections.Generic.StringEqualityComparer)
        Actual:   typeof(System.Collections.Generic.GenericEqualityComparer<string>)
        Stack Trace:
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\HashSet\HashSet.Generic.Tests.cs(891,0): at System.Collections.Tests.HashSet_Generic_Tests`1.<ComparerSerialization>g__TestComparerSerialization|64_0[TCompare
  d](IEqualityComparer`1 equalityComparer, String internalTypeName)
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\HashSet\HashSet.Generic.Tests.cs(859,0): at System.Collections.Tests.HashSet_Generic_Tests`1.ComparerSerialization()
             at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
          D:\projects\runtime\src\libraries\System.Private.CoreLib\src\System\Reflection\MethodBaseInvoker.cs(57,0): at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
      System.Collections.Tests.HashSet_Generic_Tests_int_With_Comparer_WrapStructural_Int.ComparerSerialization [FAIL]
        Assert.IsType() Failure: Value is not the exact type
        Expected: typeof(System.Collections.Generic.StringEqualityComparer)
        Actual:   typeof(System.Collections.Generic.GenericEqualityComparer<string>)
        Stack Trace:
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\HashSet\HashSet.Generic.Tests.cs(891,0): at System.Collections.Tests.HashSet_Generic_Tests`1.<ComparerSerialization>g__TestComparerSerialization|64_0[TCompare
  d](IEqualityComparer`1 equalityComparer, String internalTypeName)
          D:\projects\runtime\src\libraries\System.Collections\tests\Generic\HashSet\HashSet.Generic.Tests.cs(859,0): at System.Collections.Tests.HashSet_Generic_Tests`1.ComparerSerialization()
             at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
          D:\projects\runtime\src\libraries\System.Private.CoreLib\src\System\Reflection\MethodBaseInvoker.cs(57,0): at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
    Finished:    System.Collections.Tests

@bartonjs
Copy link
Member

There are 5 System.Collections.Tests tests that fail due to a product change. I think you have mentioned it at some point, but I just want to make sure that we are aware of that change, it’s documented and expected.

If I did, I have no recollection of it. The BF compat package is just BF. Nothing should be different between using it in 9 and using BF in 8.

@ericstj
Copy link
Member

ericstj commented Aug 26, 2024

How adding such project reference is going to affect the build time for those configurations? Should we somehow make it conditional?

It shouldn't add any time to a root level build. This project already builds and it will continue to only build once - MSBuild will get the cached value. As for leaf builds of individual projects - it will increase the time, however if folks want to avoid that they can always pass --no-dependencies to skip project references.

I wonder if we really want to have all these binary-formatter tests spread across the repo. Maybe we should consolidate them to limit the number of tests that use the OOB?

// Assembly versions beyond 8.1 are the fully functional version from NuGet.
// Assembly versions before 8.1 probably won't be encountered, since that's the past.

if (assemblyVersion.Major == 8 && assemblyVersion.Minor == 1)
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand why you're taking the assembly version logic out.

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 don't understand why you're taking the assembly version logic out.

Because it has hidden the fact that 19 projects were using the "throwing" version of BF (the tests were always skipped so any test failures would go unnoticed). With this change such tests are going to throw if they reference the wrong version.

…t is mapped to StringEqualityComparer, but serialized as GenericEqualityComparer<string>
@adamsitnik
Copy link
Member Author

@bartonjs you were right, the failures were caused by changes from #104202. I've fixed them, the tests should now pass.

The best explanation can be found here:

// This type is added as an internal implementation detail in .NET 9. Even though as of .NET 9 BinaryFormatter has been
// deprecated, for back compat we still need to support serializing this type, especially when EqualityComparer<string>.Default
// is used as part of a collection, like Dictionary<string, TValue>.
//
// BinaryFormatter treats types in the core library as being special, in that it doesn't include the assembly as part of the
// serialized data, and then on deserialization it assumes the type is in mscorlib. We could make the type public and type forward
// it from the mscorlib shim, which would enable roundtripping on .NET 9+, but because this type doesn't exist downlevel, it would
// break serializing on .NET 9+ and deserializing downlevel. Therefore, we need to serialize as something that exists downlevel.
// We could serialize as OrdinalComparer, which does exist downlevel, and which has the nice property that it also implements
// IAlternateEqualityComparer<ReadOnlySpan<char>, string>, which means serializing an instance on .NET 9+ and deserializing it
// on .NET 9+ would continue to support span-based lookups. However, OrdinalComparer is not an EqualityComparer<string>, which
// means the type's public ancestry would not be retained, which could lead to strange casting-related errors, including downlevel.
// Instead, we can serialize as a GenericEqualityComparer<string>. This exists downlevel and also derives from EqualityComparer<string>,
// but doesn't implement IAlternateEqualityComparer<ReadOnlySpan<char>, string>. This means that upon deserializing on .NET 9+,
// the comparer loses its ability to handle span-based lookups. As BinaryFormatter is deprecated on .NET 9+, this is a readonable tradeoff.
info.SetType(typeof(GenericEqualityComparer<string>));

@adamsitnik
Copy link
Member Author

I wonder if we really want to have all these binary-formatter tests spread across the repo. Maybe we should consolidate them to limit the number of tests that use the OOB?

I like this idea, but due to time constraints I would prefer to do it after we ship 9. Is that acceptable?

@adamsitnik
Copy link
Member Author

@ericstj @bartonjs the PR is ready for review, PTAL

adamsitnik added a commit to adamsitnik/runtime that referenced this pull request Sep 9, 2024
…otnet#106858)

* respect AppContext switch (which is currently enabled for all projects in the root Directory.Build.props file)

* add project reference to all test projects that need working BF (and were being skipped for a while)

* adjust to changes from dotnet#104202: EqualityComparer<string>.Default is mapped to StringEqualityComparer, but serialized as GenericEqualityComparer<string>
github-actions bot pushed a commit that referenced this pull request Sep 17, 2024
…106858)

* respect AppContext switch (which is currently enabled for all projects in the root Directory.Build.props file)

* add project reference to all test projects that need working BF (and were being skipped for a while)

* adjust to changes from #104202: EqualityComparer<string>.Default is mapped to StringEqualityComparer, but serialized as GenericEqualityComparer<string>
carlossanlop pushed a commit that referenced this pull request Sep 17, 2024
* Remove package references from library tests (#106737)

* Remove package references from library tests

These tests should be referencing the product assemblies so that they
test latest and not old bits.

* Reference the OOB version of SRSF and make sure it's copied

* BinaryFormatter tests should be skipped only on AOT, WASM and Mobile (#106858)

* respect AppContext switch (which is currently enabled for all projects in the root Directory.Build.props file)

* add project reference to all test projects that need working BF (and were being skipped for a while)

* adjust to changes from #104202: EqualityComparer<string>.Default is mapped to StringEqualityComparer, but serialized as GenericEqualityComparer<string>

* Don't use WeakReferences in the round trip test, as the target may get freed in the meantime, fixes #104905 (#106967)

* Enable more BinaryFormatter tests (#107408)

* enable the BinaryFormatter tests in System.Runtime.Serialization.Formatters.Tests

* add new test project, where the flag is disabled and it runs only 3 tests in total that ensure that

* The SerializationGuard is no longer activated since BF was moved to the OOB package, the tests need to reflect that.

* Disable binary formatter tests when DotNetBuildSourceOnly. (#107549)

* [mono][tvos] Do not treat assembly.pdb/xml files as native files to bundle when AOTing on Helix (#107079)

* Do not treat assembly.pdb/xml files as native files to bundle

* Bundle satellite assemblies as well

* [mono][ci] Include PDBs from runtime pack when building on Helix if required (#107348)

---------

Co-authored-by: Eric StJohn <ericstj@microsoft.com>
Co-authored-by: Tom Deseyn <tom.deseyn@gmail.com>
Co-authored-by: Ivan Povazan <55002338+ivanpovazan@users.noreply.github.com>
carlossanlop pushed a commit that referenced this pull request Sep 17, 2024
…107903)

* Remove package references from library tests (#106737)

* Remove package references from library tests

These tests should be referencing the product assemblies so that they
test latest and not old bits.

* Reference the OOB version of SRSF and make sure it's copied

* BinaryFormatter tests should be skipped only on AOT, WASM and Mobile (#106858)

* respect AppContext switch (which is currently enabled for all projects in the root Directory.Build.props file)

* add project reference to all test projects that need working BF (and were being skipped for a while)

* adjust to changes from #104202: EqualityComparer<string>.Default is mapped to StringEqualityComparer, but serialized as GenericEqualityComparer<string>

* Don't use WeakReferences in the round trip test, as the target may get freed in the meantime, fixes #104905 (#106967)

* Enable more BinaryFormatter tests (#107408)

* enable the BinaryFormatter tests in System.Runtime.Serialization.Formatters.Tests

* add new test project, where the flag is disabled and it runs only 3 tests in total that ensure that

* The SerializationGuard is no longer activated since BF was moved to the OOB package, the tests need to reflect that.

* Disable binary formatter tests when DotNetBuildSourceOnly. (#107549)

* [mono][tvos] Do not treat assembly.pdb/xml files as native files to bundle when AOTing on Helix (#107079)

* Do not treat assembly.pdb/xml files as native files to bundle

* Bundle satellite assemblies as well

* [mono][ci] Include PDBs from runtime pack when building on Helix if required (#107348)

---------

Co-authored-by: Eric StJohn <ericstj@microsoft.com>
Co-authored-by: Adam Sitnik <adam.sitnik@gmail.com>
Co-authored-by: Tom Deseyn <tom.deseyn@gmail.com>
Co-authored-by: Ivan Povazan <55002338+ivanpovazan@users.noreply.github.com>
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Sep 17, 2024
…otnet#106858)

* respect AppContext switch (which is currently enabled for all projects in the root Directory.Build.props file)

* add project reference to all test projects that need working BF (and were being skipped for a while)

* adjust to changes from dotnet#104202: EqualityComparer<string>.Default is mapped to StringEqualityComparer, but serialized as GenericEqualityComparer<string>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Runtime binaryformatter-migration Issues related to the removal of BinaryFormatter and migrations away from it test-enhancement Improvements of test source code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants