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

WIP Communicate between framework mscorlib and core framework with Unit Tests #116

Merged
merged 16 commits into from
Oct 15, 2019

Conversation

Blind-Striker
Copy link
Contributor

@Blind-Striker Blind-Striker commented May 28, 2019

ref #108, #112

In addition to the work done at #112, and according to the suggestion in #112 (comment), I have done followings:

  • I created a class called CrossFrameworkClass that contains almost all fundamental .NET types (int, long, enum, struct, DateTime, Exception, etc.). Then I initialized this class with dummy values and serialize and save it as files for all frameworks (net461, netcoreapp2.0, netcoreapp2.1, netcoreapp2.2). I included those files to Hyperion.Tests project.
  • In order to re-generate files in case we need again, I've added a CLI command to Hyperion.Tests project.
  • I created a test that read test files, deserializes it and then compares it to the class that initialized with dummy values.

Right now tests are working. In order to be sure, I reverted all of @humhei's changes and ran the tests again and observed that tests are not passed.

There is only one case where the tests are failing. When you serialize and deserialize exceptions that have extra property such as ArgumentNullException, these properties are being ignored. So instead of full compare, I just compared exception messages. I think this problem related to ExceptionSerializerFactory which a subject of another issue.

Except that I'm pretty sure everything is working.

@Blind-Striker
Copy link
Contributor Author

@Aaronontheweb, @Horusiath We really need these changes, right now we are using our own package that forked from this project. We need not only for Akka projects but also for other projects where we use Hyperion as a serializer.

See:
https://github.com/armutcom/CacheManager.Serialization.Hyperion

If there are things you want me to change at this Pull Request, or if you think there are things that don't meet the standards of the project, I can make these changes quickly.

@akselarzuman the person who opened the PR #119 is my collage. We love Hyperion as a company 😄 and we use it extensively, and we want to make contributions whenever it's possible.

@@ -125,6 +125,14 @@ private static Type GetTypeFromManifestName(Stream stream, DeserializerSession s
return TypeNameLookup.GetOrAdd(byteArr, b =>
{
var shortName = StringEx.FromUtf8Bytes(b.Bytes, 0, b.Bytes.Length);
if (shortName.Contains("System.Private.CoreLib,%core%") && CoreAssemblyQualifiedName.Contains("mscorlib, Version="))
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this if/else statement something that could be replaced by compilation flags (iike #if NETCORE)? I'm not sure if this check is something that we need to call at runtime for potentially every single type when we know that CoreAssemblyQualifiedName will never change in the application lifetime.

Copy link
Contributor Author

@Blind-Striker Blind-Striker Oct 3, 2019

Choose a reason for hiding this comment

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

It isn't my commit but I'm not sure if we don't need runtime checks. Because the whole purpose of this PR is to provide interoperability between the .NET Framework and .NET Core, thus we might need runtime checks in case of serializing/deserializing between those two frameworks. As far as I understand Hyperion embeds the namespace into the serialized payload for types.

I'll check it and update the code if it's necessary. Thanks for pointing out.

@humhei fyi

Copy link
Contributor

@humhei humhei Oct 4, 2019

Choose a reason for hiding this comment

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

if (shortName.Contains("System.Private.CoreLib,%core%") && CoreAssemblyQualifiedName.Contains("mscorlib, Version="))

The second predication can be replaced by etc #if NET461
But i more like define a global variable
private static readonly bool IsFullNetFramework = CoreAssemblyQualifiedName.Contains("mscorlib, Version="))
Then you can check it like
if (shortName.Contains("System.Private.CoreLib,%core%") && IsFullNetFramework

Blind-Striker#1

Copy link
Contributor

Choose a reason for hiding this comment

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

The reason here is that we want to avoid unnecessary branches and operations. While it's quite possible that .NET Core 3.0 knows how to optimize static readonly checks, it's wasteful to defer checks, which result is known at compile time, back to the runtime for every type call. It's only a microoptimization, but it's also a sane practice to do.

A middle ground here is to make IsFullNetFramework a const defined in #if/else pragmas and put it as a first segment of && expression - since consts cannot be changed by reflection (unlike readonly values), they are always optimized on every .NET platform.

Copy link
Contributor

@humhei humhei Oct 4, 2019

Choose a reason for hiding this comment

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

Thanks for your explanation
Fixed In Blind-Striker#1
#if NETSTANDARD
#if NET45

Copy link
Contributor Author

@Blind-Striker Blind-Striker Oct 4, 2019

Choose a reason for hiding this comment

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

Ok, everything seems to be in order. I merged @humhei 's PR and pull the latest CI improvements from the dev branch (@Danthar fyi). All tests are passed.

After @akselarzuman's PR #119 merged I need to update test files (mentioned in #116 (comment)) for .NET Core 3.0 and run the tests again.

@Blind-Striker
Copy link
Contributor Author

@Danthar conflict resolved

@Blind-Striker
Copy link
Contributor Author

@Danthar I don't know why it failed, I have run build.ps1 on my local for all targets. The error message didn't specify anything :(

@Danthar
Copy link
Member

Danthar commented Oct 4, 2019

Because of this:
image

@Blind-Striker
Copy link
Contributor Author

Blind-Striker commented Oct 4, 2019

@Danthar Would it be a problem if I change vmImage: 'vs2017-win2016' to vmImage: windows-2019. 2.2.7 is the latest version .NET Core 2.2. Either I have to explicitly set projects .NET Core SDK version to the previous version (which is not compatible with VS 2019) or I have to change Windows image.

@Aaronontheweb
Copy link
Member

vmImage: windows-2019

@Danthar we should change this in our templates across all projects.

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

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

LGTM, looking at test output next to make sure what I've reviewed matches what is being tested...

@@ -2,7 +2,7 @@
# See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference

pool:
vmImage: vs2017-win2016
vmImage: windows-2019
Copy link
Member

Choose a reason for hiding this comment

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

LGTM

}

[Fact]
public void CanSerializeCrossFramework()
Copy link
Member

Choose a reason for hiding this comment

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

Nice, this the only way to do it - have to actually load the sucker and work the payloads on both ends.

}
}

private bool Equals(CrossFrameworkStruct other)
Copy link
Member

Choose a reason for hiding this comment

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

LGTM - validates that all of the primitives are covered.

<TargetFrameworks>net461;netcoreapp2.1;netcoreapp3.0</TargetFrameworks>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<LangVersion>latest</LangVersion>
<StartupObject>Hyperion.Tests.Generator.Program</StartupObject>
Copy link
Member

Choose a reason for hiding this comment

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

Fine with this - but I'll need to check the test output real fast to make sure everything is still there (pretty sure this PR would have exploded if it wasn't.)

@@ -118,11 +118,23 @@ private static Type GetTypeFromManifestName(Stream stream, DeserializerSession s
return TypeNameLookup.GetOrAdd(byteArr, b =>
{
var shortName = StringEx.FromUtf8Bytes(b.Bytes, 0, b.Bytes.Length);
#if NET45
Copy link
Member

Choose a reason for hiding this comment

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

And this is where all of the heavy-lifting for working between frameworks occurs I take it...

@Aaronontheweb
Copy link
Member

Tests look good. :shipit:

@Blind-Striker
Copy link
Contributor Author

Thanks @Aaronontheweb

I couldn't make the test project work with .NET Core 2.2. I think it's about Azure VM. I have got the error below.

The specified framework 'Microsoft.NETCore.App', version '2.2.7' was not found.

We can add the task below to install the latest .NET Core 2.2. But I didn't want to add that task without getting your opinion, and it also didn't feel like it was the right way to do this. Better wait for Microsoft to update their VM images.

  - task: UseDotNet@2
    displayName: 'Install .net core 2.2'
    inputs:
      packageType: sdk
      version: '2.2.402'
      installationPath: $(Agent.ToolsDirectory)/dotnet

But I'm pretty sure it's working because I have run the tests on my local and custom docker container with .NET Core 2.2.

@Blind-Striker Blind-Striker deleted the Communication branch October 15, 2019 20:17
@Aaronontheweb
Copy link
Member

@Blind-Striker go ahead and add it.... Can we do something similar for the Linux images as well so we could get the test suite to run on that too?

@Blind-Striker
Copy link
Contributor Author

@Aaronontheweb We can actually. I already did something similar in my projects before. We can use a matrix strategy

strategy:
  matrix:
    linux:
      imageName: 'ubuntu-latest'
    mac:
      imageName: 'macos-10.13'
    windows:
      imageName: 'windows-2019'

The only thing we need to do is add a condition to the task that checks the OS and run build.ps1 or build.sh according to that. Something like below

  - task: PowerShell@2
    displayName: "Compile & Tests"
    inputs:
      targetType: filePath
      filePath: ./build.ps1
    condition: eq( variables['Agent.OS'], 'Windows_NT' )

  - task: Bash@3
    displayName: 'Compile & Tests'
    inputs:
      targetType: filePath
      filePath: ./build.sh
    condition: or(eq( variables['Agent.OS'], 'Darwin' ), eq( variables['Agent.OS'], 'Linux' ))

The only drawback (it's not a drawback actually) of matrix strategy is you can't get separate build badges for each OS. So I always prefer to create separate YAML files per OS. But it's an aesthetic issue, not a technical one :)

I'll do the necessary changes and open a new PR.

@Aaronontheweb Aaronontheweb mentioned this pull request Oct 16, 2019
@Aaronontheweb
Copy link
Member

@Blind-Striker thank you! We would really appreciate that.

@@ -20,11 +20,7 @@
<Reference Include="Microsoft.CSharp" />
</ItemGroup>

Copy link
Contributor

Choose a reason for hiding this comment

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

#145

$(DefineConstants);NETSTANDARD

Maybe it is because The NETSTANDARD constrant is deleted here

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The tests should have failed on this case, I'll inform you after check it @DaniilSokolyuk @Aaronontheweb @humhei

Copy link
Member

Choose a reason for hiding this comment

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

Looks like the issue is specific to .NET Core 3+

Copy link
Member

Choose a reason for hiding this comment

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

Based on what I've found with #151 thus far

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.

5 participants