Dryad/DryadLinqTests/TypesInQueryTests.cs

516 lines
19 KiB
C#

/*
Copyright (c) Microsoft Corporation
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License
at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions and
limitations under the License.
*/
using Microsoft.Research.DryadLinq;
using Microsoft.Research.Peloponnese.Storage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
namespace DryadLinqTests
{
public class TypesInQueryTests
{
public static void Run(DryadLinqContext context, string matchPattern)
{
TestLog.Message(" **********************");
TestLog.Message(" TypesInQueryTests ");
TestLog.Message(" **********************");
var tests = new Dictionary<string, Action>()
{
{"NonSealedTypeRecords", () => NonSealedTypeRecords(context) },
{"DerivedTypeRecords", () => DerivedTypeRecords(context) },
{"ObjectRecords", () => ObjectRecords(context) },
{"BadRecordsNotSerialized", () => BadRecordsNotSerialized(context) },
{"GroupByWithAnonymousTypes_Bug15675", () => GroupByWithAnonymousTypes_Bug15675(context) },
{"GroupByWithAnonymousTypes_Pipeline", () => GroupByWithAnonymousTypes_Pipeline(context) },
{"GroupByWithAnonymousTypes_MultipleAnonymousTypes", () => GroupByWithAnonymousTypes_MultipleAnonymousTypes(context) },
{"GroupByWithAnonymousTypes_GenericWithAnonTypeParam", () => GroupByWithAnonymousTypes_GenericWithAnonTypeParam(context) },
{"GroupByWithAnonymousTypes_ArrayOfAnon", () => GroupByWithAnonymousTypes_ArrayOfAnon(context) },
{"GroupByWithAnonymousTypes_NestedAnonTypes", () => GroupByWithAnonymousTypes_NestedAnonTypes(context) },
};
foreach (var test in tests)
{
if (Regex.IsMatch(test.Key, matchPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase))
{
test.Value.Invoke();
}
}
}
public static bool NonSealedTypeRecords(DryadLinqContext context)
{
string testName = "NonSealedTypeRecords";
TestLog.TestStart(testName);
bool passed = true;
try
{
IEnumerable<NonSealedClass>[] result = new IEnumerable<NonSealedClass>[2];
// cluster
{
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var output = pt1.Select(x => new NonSealedClass()).ToArray();
result[0] = output;
}
// local
{
context.LocalDebug = true;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var output = pt1.Select(x => new NonSealedClass()).ToArray();
result[1] = output;
}
// compare result
try
{
Validate.Check(result);
}
catch (Exception ex)
{
TestLog.Message("Error: " + ex.Message);
passed &= false;
}
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
public static bool DerivedTypeRecords(DryadLinqContext context)
{
string testName = "DerivedTypeRecords";
TestLog.TestStart(testName);
bool passed = true;
try
{
IEnumerable<ParentClass>[] result1 = new IEnumerable<ParentClass>[2];
IEnumerable<ChildClass>[] result2 = new IEnumerable<ChildClass>[2];
// cluster
{
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var output1 = pt1.Select(x => new ParentClass()).ToArray();
var output2 = pt1.Select(x => new ChildClass()).ToArray();
result1[0] = output1;
result2[0] = output2;
}
// local
{
context.LocalDebug = true;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var output1 = pt1.Select(x => new ParentClass()).ToArray();
var output2 = pt1.Select(x => new ChildClass()).ToArray();
result1[1] = output1;
result2[1] = output2;
}
// compare result
try
{
Validate.Check(result1);
Validate.Check(result2);
}
catch (Exception ex)
{
TestLog.Message("Error: " + ex.Message);
passed &= false;
}
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
public static bool ObjectRecords(DryadLinqContext context)
{
string testName = "ObjectRecords";
TestLog.TestStart(testName);
bool passed = true;
try
{
IEnumerable<object>[] result = new IEnumerable<object>[2];
// cluster
{
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var output = pt1.Select(x => new object()).ToArray();
result[0] = output;
}
// local
{
context.LocalDebug = true;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var output = pt1.Select(x => new object()).ToArray();
result[1] = output;
}
// compare result
try
{
Validate.Check(result);
}
catch (Exception ex)
{
TestLog.Message("Error: " + ex.Message);
passed &= false;
}
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
public static bool BadRecordsNotSerialized(DryadLinqContext context)
{
string testName = "BadRecordsNotSerialized";
TestLog.TestStart(testName);
bool passed = true;
try
{
IEnumerable<string>[] result = new IEnumerable<string>[2];
// cluster
{
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var output = pt1.Select(x => (x % 2 == 0 ? new ChildClass() : new ParentClass())).Select(x => x is ChildClass ? "child" : "parent").ToArray();
result[0] = output;
}
// local
{
context.LocalDebug = true;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var output = pt1.Select(x => (x % 2 == 0 ? new ChildClass() : new ParentClass())).Select(x => x is ChildClass ? "child" : "parent").ToArray();
result[1] = output;
}
// compare result
try
{
Validate.Check(result);
}
catch (Exception ex)
{
TestLog.Message("Error: " + ex.Message);
passed &= false;
}
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
//Bug 15675 -- GroupBy creates a DryadOrderByNode which is confused by the anonymous type.
// specifically, the call to DryadSort incorrectly referenced both the anonymous type and the code-gen proxy for the anonymous type.
// -- the fix was to clean up how & when we process the types involved in the query so that only the proxy would be referenced.
public static bool GroupByWithAnonymousTypes_Bug15675(DryadLinqContext context)
{
string testName = "GroupByWithAnonymousTypes_Bug15675";
TestLog.TestStart(testName);
bool passed = true;
try
{
// cluster
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var result1 = pt1.Select(i => new { Num = i % 10 })
.GroupBy(x => x.Num, x => x.Num)
.ToArray();
// local
context.LocalDebug = true;
IQueryable<int> pt2 = DataGenerator.GetSimpleFileSets(context);
var result2 = pt2.Select(i => new { Num = i % 10 })
.GroupBy(x => x.Num, x => x.Num)
.ToArray();
passed &= (result1.Count() == result2.Count());
passed &= (result1.Where(g => g.Key == 1).SelectMany(g => g).Count() == result2.Where(g => g.Key == 1).SelectMany(g => g).Count());
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
public static bool GroupByWithAnonymousTypes_Pipeline(DryadLinqContext context)
{
string testName = "GroupByWithAnonymousTypes_Pipeline";
TestLog.TestStart(testName);
bool passed = true;
try
{
// cluster
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var result1 = pt1.Select(i => new { Num = i % 10 })
.Where(x => true)
.GroupBy(x => x.Num, x => x.Num)
.ToArray();
// local
context.LocalDebug = true;
IQueryable<int> pt2 = DataGenerator.GetSimpleFileSets(context);
var result2 = pt2.Select(i => new { Num = i % 10 })
.Where(x => true)
.GroupBy(x => x.Num, x => x.Num)
.ToArray();
passed &= (result1.Count() == result2.Count());
passed &= (result1.Where(g => g.Key == 1).SelectMany(g => g).Count() == result2.Where(g => g.Key == 1).SelectMany(g => g).Count());
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
public static bool GroupByWithAnonymousTypes_MultipleAnonymousTypes(DryadLinqContext context)
{
string testName = "GroupByWithAnonymousTypes_MultipleAnonymousTypes";
TestLog.TestStart(testName);
bool passed = true;
try
{
// cluster
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var result1 = pt1.Select(i => new { Num = i % 10 })
.Where(x => true)
.Select(i => new { Num2 = i.Num })
.GroupBy(x => x.Num2, x => x.Num2)
.ToArray();
// local
context.LocalDebug = true;
IQueryable<int> pt2 = DataGenerator.GetSimpleFileSets(context);
var result2 = pt2.Select(i => new { Num = i % 10 })
.Where(x => true)
.Select(i => new { Num2 = i.Num })
.GroupBy(x => x.Num2, x => x.Num2)
.ToArray();
passed &= (result1.Count() == result2.Count());
passed &= (result1.Where(g => g.Key == 1).SelectMany(g => g).Count() == result2.Where(g => g.Key == 1).SelectMany(g => g).Count());
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
public static bool GroupByWithAnonymousTypes_GenericWithAnonTypeParam(DryadLinqContext context)
{
string testName = "GroupByWithAnonymousTypes_GenericWithAnonTypeParam";
TestLog.TestStart(testName);
bool passed = true;
try
{
// cluster
{
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var result1 = pt1.Select(i => MakeNewMyGenericType(new { Num = i % 10 }))
.GroupBy(x => x.Field.Num, x => x.Field.Num)
.ToArray();
// local
context.LocalDebug = true;
IQueryable<int> pt2 = DataGenerator.GetSimpleFileSets(context);
var result2 = pt2.Select(i => MakeNewMyGenericType(new { Num = i % 10 }))
.GroupBy(x => x.Field.Num, x => x.Field.Num)
.ToArray();
passed &= (result1.Count() == result2.Count());
passed &= (result1.Where(g => g.Key == 1).SelectMany(g => g).Count() == result2.Where(g => g.Key == 1).SelectMany(g => g).Count());
}
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
public static bool GroupByWithAnonymousTypes_ArrayOfAnon(DryadLinqContext context)
{
string testName = "GroupByWithAnonymousTypes_ArrayOfAnon";
TestLog.TestStart(testName);
bool passed = true;
try
{
// cluster
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var result1 = pt1.Select(i => new[] { new { Num = i % 10 } })
.GroupBy(x => x[0].Num, x => x[0].Num)
.ToArray();
// local
context.LocalDebug = true;
IQueryable<int> pt2 = DataGenerator.GetSimpleFileSets(context);
var result2 = pt2.Select(i => new[] { new { Num = i % 10 } })
.GroupBy(x => x[0].Num, x => x[0].Num)
.ToArray();
passed &= (result1.Count() == result2.Count());
passed &= (result1.Where(g => g.Key == 1).SelectMany(g => g).Count() == result2.Where(g => g.Key == 1).SelectMany(g => g).Count());
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
public static bool GroupByWithAnonymousTypes_NestedAnonTypes(DryadLinqContext context)
{
string testName = "GroupByWithAnonymousTypes_NestedAnonTypes";
TestLog.TestStart(testName);
bool passed = true;
try
{
// cluster
context.LocalDebug = false;
IQueryable<int> pt1 = DataGenerator.GetSimpleFileSets(context);
var result1 = pt1.Select(i => new { Num = new { NumInner = new int?(i % 10) } }) // nullable-fields present particular challenge.
.GroupBy(x => x.Num.NumInner, x => x.Num.NumInner)
.ToArray();
// local
context.LocalDebug = true;
IQueryable<int> pt2 = DataGenerator.GetSimpleFileSets(context);
var result2 = pt2.Select(i => new { Num = new { NumInner = new int?(i % 10) } }) // nullable-fields present particular challenge.
.GroupBy(x => x.Num.NumInner, x => x.Num.NumInner)
.ToArray();
passed &= (result1.Count() == result2.Count());
passed &= (result1.Where(g => g.Key == 1).SelectMany(g => g).Count() == result2.Where(g => g.Key == 1).SelectMany(g => g).Count());
}
catch (Exception Ex)
{
TestLog.Message("Error: " + Ex.Message);
passed &= false;
}
TestLog.LogResult(new TestResult(testName, context, passed));
return passed;
}
// This is a helper method to allow 'naming the anonymous type'
// -- there is no name to give 'anonymous' inline to the original query,
// but a generic-method only has to call it by pseudonym T, which is a useful workaround.
public static MyGenericType<T> MakeNewMyGenericType<T>(T item)
{
return new MyGenericType<T>(item);
}
}
[Serializable]
public class MyGenericType<T>
{
public T Field;
public MyGenericType(T data)
{
Field = data;
}
}
[Serializable]
public class NonSealedClass
{
public int X;
}
[Serializable]
public class ParentClass
{
public int X;
}
[Serializable]
public class ChildClass : ParentClass
{
public int Y;
}
}