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

Mono tests failing due to methods that cannot be found #154

Closed
chwarr opened this issue Apr 14, 2016 · 1 comment
Closed

Mono tests failing due to methods that cannot be found #154

chwarr opened this issue Apr 14, 2016 · 1 comment
Assignees
Labels

Comments

@chwarr
Copy link
Member

chwarr commented Apr 14, 2016

Recent Travis CI runs for PRs #145 and #153 have failed with an odd error in the serialization unit tests. It appears that we can't find methods of tagged reader/untagged reader that we expect to via reflection under Mono. We don't have this issue with .NET on Windows (the AppVeyor builds are passing).

For example, here's a test failure stack from #153's Linux C# build:

Errors and Failures:
1) Test Error : UnitTest.Aliases.TypeAliasTests.AliasBlob
   System.ArgumentNullException : Value cannot be null.
Parameter name: method
  at System.Linq.Expressions.Expression.Call (System.Linq.Expressions.Expression instance, System.Reflection.MethodInfo method, IEnumerable`1 arguments) <0x41f91080 + 0x001c3> in <filename unknown>:0 
  at System.Linq.Expressions.Expression.Call (System.Linq.Expressions.Expression instance, System.Reflection.MethodInfo method) <0x41f91030 + 0x0002f> in <filename unknown>:0 
  at Bond.Expressions.UntaggedReader`1[R].ReadFieldOmitted () <0x4213bbf0 + 0x0006b> in <filename unknown>:0 
  at Bond.Expressions.UntaggedParser`1[R].Field (ITransform transform, Bond.FieldDef fieldDef, IField field) <0x4213b860 + 0x001bd> in <filename unknown>:0 
  at Bond.Expressions.UntaggedParser`1+<Apply>c__AnonStorey0[R].<>m__0 (<>__AnonType1`2 <>__TranspIdent1, IField knownField) <0x4213b780 + 0x00097> in <filename unknown>:0 
  at System.Linq.Enumerable+<SelectManyIterator>c__Iterator5`3[TSource,TCollection,TResult].MoveNext () <0x41fdad10 + 0x002da> in <filename unknown>:0 
  at System.Collections.Generic.List`1[T].InsertRange (Int32 index, IEnumerable`1 collection) <0x41f124c0 + 0x002a8> in <filename unknown>:0 
  at System.Collections.Generic.List`1[T].AddRange (IEnumerable`1 collection) <0x41f12480 + 0x00025> in <filename unknown>:0 
  at Bond.Expressions.UntaggedParser`1[R].Apply (ITransform transform) <0x4213aa30 + 0x00a8b> in <filename unknown>:0 
  at Bond.Expressions.DeserializerTransform`1[R].Struct (IParser parser, System.Linq.Expressions.Expression var, System.Type schemaType, Boolean initialize) <0x4208d000 + 0x00664> in <filename unknown>:0 
  at Bond.Expressions.DeserializerTransform`1[R].Deserialize (IParser parser, System.Linq.Expressions.Expression var, System.Type objectType, System.Type schemaType, Boolean initialize) <0x4207c250 + 0x004f5> in <filename unknown>:0 
  at Bond.Expressions.DeserializerTransform`1[R].Generate (IParser parser, System.Type type) <0x4208c950 + 0x000d5> in <filename unknown>:0 
  at Bond.Deserializer`1[R]..ctor (System.Type type, IParser parser, IFactory factory, Bond.Factory factory2, Boolean inlineNested) <0x4208b1e0 + 0x00bff> in <filename unknown>:0 
  at Bond.Deserializer`1[R]..ctor (System.Type type, RuntimeSchema schema) <0x42135cf0 + 0x0005f> in <filename unknown>:0 
  at UnitTest.Util.DeserializeUntagged[From,To] (IClonableUntaggedProtocolReader reader) <0x42135be0 + 0x000b4> in <filename unknown>:0 
  at UnitTest.Util.<AllSerializeDeserialize`2>m__6[From,To] (System.IO.Stream stream) <0x42135a90 + 0x0011a> in <filename unknown>:0 
  at UnitTest.Util+<AllSerializeDeserialize>c__AnonStorey2`2[From,To].<>m__3 (System.Action`2 serialize, System.Func`2 deserialize) <0x41f8f430 + 0x00087> in <filename unknown>:0 
  at UnitTest.Util.AllSerializeDeserialize[From,To] (UnitTest.From from, Boolean noTranscoding) <0x41f8adb0 + 0x03a18> in <filename unknown>:0 
  at UnitTest.Aliases.TypeAliasTests.TestTypeAliases[T,U] (UnitTest.Aliases.T from) <0x41f8ac40 + 0x00036> in <filename unknown>:0 
  at UnitTest.Aliases.TypeAliasTests.AliasBlob () <0x41f89ed0 + 0x0002a> in <filename unknown>:0 
  at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) <0x41f33da0 + 0x000b7> in <filename unknown>:0 
@chwarr
Copy link
Member Author

chwarr commented Apr 15, 2016

@lalo and I did some debugging here.

The unit tests failure was manifesting when creating deserializers for various types. The particual test case was attempting to deserialize from an IClonableTaggedProtocolReader. In the internal class TaggedReader, which is used to help build the deserializer, we couldn't find methods like ITaggedProtocolReader.ReadStructBegin.

The call stack in play here is

When initializing TaggedReader, we call GetMethod with an expression for the call to ITaggedProtocolReader.ReadStructBegin. GetMethod then calls FindMethod with arguments like (typeof(IClonableTaggedProtocolReader), "ReadStructBegin", ...). IClonableTaggedProtocolReader doesn't directly implement ReadStructBegin, so the GetDeclaredMethods call returns an empty collection. We then attempt to look up "ReadStructBegin" in the "base class".

Here's the implementation of Reflection.GetBaseType

static Type GetBaseType(this Type type)
{
    if (type.IsInterface())
    {
        return type.GetInterfaces().FirstOrDefault();
    }

    return type.GetTypeInfo().BaseType;
}

Here's the implementation of IClonableTaggedProtocolReader:

public interface IClonableTaggedProtocolReader
    : ITaggedProtocolReader, ICloneable<IClonableTaggedProtocolReader>
{ }

Before the recent PR changes, Type.GetInterfaces was returning ITaggedProtocolReader and then IClonable<>. However, the addition of some classes caused the other to be swapped. So, we ended up looking for "ReadStructBegin" in IClonable<>, which does not implement such a method.

From the documentation for Type.GetInterfaces:

The GetInterfaces method does not return interfaces in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which interfaces are returned, because that order varies.

The fix here is going to involve looking for the method in all the interfaces the type implements, not just the first.

chwarr added a commit to chwarr/bond that referenced this issue Apr 15, 2016
This is a potential fix for issue microsoft#154, "Mono tests failing due to
methods that cannot be found"
lalo pushed a commit to lalo/bond that referenced this issue Apr 15, 2016
This is a potential fix for issue microsoft#154, "Mono tests failing due to
methods that cannot be found"
lalo added a commit to lalo/bond that referenced this issue Apr 15, 2016
- Do not depend on ordering of interfaces when searching for a method
- Throw exception if more than one method is found
- Add corresponding tests

This change fixes microsoft#154
lalo added a commit that referenced this issue Apr 16, 2016
- Do not depend on ordering of interfaces when searching for a method
- Throw exception if more than one method is found
- Add corresponding tests

This change fixes #154
@lalo lalo closed this as completed in a9c4d78 Apr 16, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants