218 lines
7.6 KiB
C#
218 lines
7.6 KiB
C#
|
|
//
|
||
|
|
// Copyright (c) 2012-2021 Antmicro
|
||
|
|
//
|
||
|
|
// This file is licensed under the MIT License.
|
||
|
|
// Full license text is available in the LICENSE file.
|
||
|
|
|
||
|
|
using System;
|
||
|
|
using Antmicro.Migrant.Customization;
|
||
|
|
using System.IO;
|
||
|
|
using System.Reflection;
|
||
|
|
using Antmicro.Migrant.VersionTolerance;
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
namespace Antmicro.Migrant.Tests
|
||
|
|
{
|
||
|
|
public class TwoDomainsDriver
|
||
|
|
{
|
||
|
|
public TwoDomainsDriver(bool useGeneratedSerializer, bool useGeneratedDeserializer)
|
||
|
|
{
|
||
|
|
settings = new DriverSettings(useGeneratedSerializer, useGeneratedDeserializer, true);
|
||
|
|
|
||
|
|
// this is just a little hack that allows us to debug TwoDomainTests on one domain
|
||
|
|
// when `PrepareDomains` method is not called; when `PrepareDomains` is called
|
||
|
|
// then these fields are overwritten with proper values
|
||
|
|
testsOnDomain1 = new InnerDriver { Settings = settings };
|
||
|
|
testsOnDomain2 = testsOnDomain1;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void PrepareDomains()
|
||
|
|
{
|
||
|
|
var pathBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||
|
|
foreach (var domain in new[] { "domain1", "domain2" }.Select(x => Path.Combine(pathBase, x)))
|
||
|
|
{
|
||
|
|
Directory.CreateDirectory(domain);
|
||
|
|
foreach(var file in new[] { "Tests.dll", "Migrant.dll" })
|
||
|
|
{
|
||
|
|
File.Copy(Path.Combine(pathBase, file), Path.Combine(domain, file), true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
domain1 = AppDomain.CreateDomain("domain1", null, Path.Combine(pathBase, "domain1"), string.Empty, false);
|
||
|
|
domain2 = AppDomain.CreateDomain("domain2", null, Path.Combine(pathBase, "domain2"), string.Empty, false);
|
||
|
|
|
||
|
|
testsOnDomain1 = (InnerDriver)domain1.CreateInstanceAndUnwrap(typeof(InnerDriver).Assembly.FullName, typeof(InnerDriver).FullName);
|
||
|
|
testsOnDomain2 = (InnerDriver)domain2.CreateInstanceAndUnwrap(typeof(InnerDriver).Assembly.FullName, typeof(InnerDriver).FullName);
|
||
|
|
|
||
|
|
testsOnDomain1.Settings = settings;
|
||
|
|
testsOnDomain2.Settings = settings;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void DisposeDomains()
|
||
|
|
{
|
||
|
|
testsOnDomain1 = null;
|
||
|
|
testsOnDomain2 = null;
|
||
|
|
AppDomain.Unload(domain1);
|
||
|
|
AppDomain.Unload(domain2);
|
||
|
|
domain1 = null;
|
||
|
|
domain2 = null;
|
||
|
|
|
||
|
|
var pathBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||
|
|
|
||
|
|
Directory.Delete(Path.Combine(pathBase, "domain1"), true);
|
||
|
|
Directory.Delete(Path.Combine(pathBase, "domain2"), true);
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool SerializeAndDeserializeOnTwoAppDomains(DynamicType domainOneType, DynamicType domainTwoType, VersionToleranceLevel vtl, bool allowGuidChange = true)
|
||
|
|
{
|
||
|
|
testsOnDomain1.CreateInstanceOnAppDomain(domainOneType);
|
||
|
|
testsOnDomain2.CreateInstanceOnAppDomain(domainTwoType);
|
||
|
|
|
||
|
|
var bytes = testsOnDomain1.SerializeOnAppDomain();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
testsOnDomain2.DeserializeOnAppDomain(bytes, settings.GetSettings(allowGuidChange ? vtl | VersionToleranceLevel.AllowGuidChange : vtl));
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
catch (VersionToleranceException)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
protected DriverSettings settings;
|
||
|
|
|
||
|
|
protected InnerDriver testsOnDomain1;
|
||
|
|
protected InnerDriver testsOnDomain2;
|
||
|
|
|
||
|
|
private AppDomain domain1;
|
||
|
|
private AppDomain domain2;
|
||
|
|
}
|
||
|
|
|
||
|
|
public class DriverSettings : MarshalByRefObject
|
||
|
|
{
|
||
|
|
public DriverSettings(bool useGeneratedSerializer, bool useGeneratedDeserializer, bool useStamping)
|
||
|
|
{
|
||
|
|
this.useGeneratedDeserializer = useGeneratedDeserializer;
|
||
|
|
this.useGeneratedSerializer = useGeneratedSerializer;
|
||
|
|
this.useStamping = useStamping;
|
||
|
|
}
|
||
|
|
|
||
|
|
public Settings GetSettings(VersionToleranceLevel level = 0)
|
||
|
|
{
|
||
|
|
return new Settings(useGeneratedSerializer ? Method.Generated : Method.Reflection,
|
||
|
|
useGeneratedDeserializer ? Method.Generated : Method.Reflection,
|
||
|
|
level,
|
||
|
|
disableTypeStamping: !useStamping);
|
||
|
|
}
|
||
|
|
|
||
|
|
public Settings GetSettingsAllowingGuidChange(VersionToleranceLevel level = 0)
|
||
|
|
{
|
||
|
|
return GetSettings(level | VersionToleranceLevel.AllowGuidChange);
|
||
|
|
}
|
||
|
|
|
||
|
|
private bool useGeneratedSerializer;
|
||
|
|
private bool useGeneratedDeserializer;
|
||
|
|
private bool useStamping;
|
||
|
|
}
|
||
|
|
|
||
|
|
public class InnerDriver : MarshalByRefObject
|
||
|
|
{
|
||
|
|
public InnerDriver()
|
||
|
|
{
|
||
|
|
DynamicType.prefix = AppDomain.CurrentDomain.FriendlyName;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void CreateInstanceOnAppDomain(DynamicType type, Version version = null)
|
||
|
|
{
|
||
|
|
obj = type.Instantiate(version);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void DeserializeOnAppDomain(byte[] data, Settings settings)
|
||
|
|
{
|
||
|
|
var stream = new MemoryStream(data);
|
||
|
|
var deserializer = new Serializer(settings);
|
||
|
|
obj = deserializer.Deserialize<object>(stream);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void SetValueOnAppDomain(string className, string fieldName, object value)
|
||
|
|
{
|
||
|
|
var field = FindClass(className).GetField(fieldName);
|
||
|
|
field.SetValue(obj, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void SetValueOnAppDomain(string fieldName, object value)
|
||
|
|
{
|
||
|
|
SetValueOnAppDomainInner(obj, fieldName, value);
|
||
|
|
}
|
||
|
|
|
||
|
|
private object SetValueOnAppDomainInner(object o, string fieldName, object value)
|
||
|
|
{
|
||
|
|
var elements = fieldName.Split(new[] { '.' }, 2);
|
||
|
|
if (elements.Length == 1)
|
||
|
|
{
|
||
|
|
var field = o.GetType().GetField(fieldName);
|
||
|
|
field.SetValue(o, value);
|
||
|
|
return o;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var field = o.GetType().GetField(elements[0]);
|
||
|
|
var local = field.GetValue(o);
|
||
|
|
local = SetValueOnAppDomainInner(local, elements[1], value);
|
||
|
|
field.SetValue(o, local);
|
||
|
|
return o;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public object GetValueOnAppDomain(string className, string fieldName)
|
||
|
|
{
|
||
|
|
var field = FindClass(className).GetField(fieldName);
|
||
|
|
return field.GetValue(obj);
|
||
|
|
}
|
||
|
|
|
||
|
|
public object GetValueOnAppDomain(string fieldName)
|
||
|
|
{
|
||
|
|
var elements = fieldName.Split('.');
|
||
|
|
FieldInfo field = null;
|
||
|
|
object currentObject = null;
|
||
|
|
foreach (var element in elements)
|
||
|
|
{
|
||
|
|
currentObject = (currentObject == null) ? obj : field.GetValue(currentObject);
|
||
|
|
field = currentObject.GetType().GetField(element);
|
||
|
|
}
|
||
|
|
|
||
|
|
return field.GetValue(currentObject);
|
||
|
|
}
|
||
|
|
|
||
|
|
public byte[] SerializeOnAppDomain()
|
||
|
|
{
|
||
|
|
var stream = new MemoryStream();
|
||
|
|
var serializer = new Serializer(Settings.GetSettings());
|
||
|
|
serializer.Serialize(obj, stream);
|
||
|
|
return stream.ToArray();
|
||
|
|
}
|
||
|
|
|
||
|
|
private Type FindClass(string className)
|
||
|
|
{
|
||
|
|
var currentClass = obj.GetType();
|
||
|
|
while (currentClass != null && currentClass.Name != className)
|
||
|
|
{
|
||
|
|
currentClass = currentClass.BaseType;
|
||
|
|
}
|
||
|
|
if (currentClass == null)
|
||
|
|
{
|
||
|
|
throw new ArgumentException(className);
|
||
|
|
}
|
||
|
|
|
||
|
|
return currentClass;
|
||
|
|
}
|
||
|
|
|
||
|
|
public string Location { get; set; }
|
||
|
|
public DriverSettings Settings { get; set; }
|
||
|
|
|
||
|
|
protected object obj;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|