#region License
/*
* Copyright 2002-2005 the original author or authors.
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.IO;
using System.Security.Policy;
using System.Collections;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Web;
using AopAlliance.Aop;
using AopAlliance.Intercept;
using NUnit.Framework;
using Rhino.Mocks;
using Spring.Aop.Advice;
using Spring.Aop.Framework.Adapter;
using Spring.Aop.Interceptor;
using Spring.Aop.Support;
using Spring.Aop.Target;
using Spring.Context;
using Spring.Core.IO;
using Spring.Objects;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Support;
using Spring.Objects.Factory.Xml;
using Spring.Proxy;
using Spring.Threading;
#endregion
namespace Spring.Aop.Framework{
/// <summary>
/// Integration test cases for the ProxyFactoryObject, using an XML object factory.
/// </summary>
/// <author>Rod Johnson</author>
/// <author>Federico Spinazzi (.NET)</author>
/// <author>Choy Rim (.NET)</author>
/// <author>Aleksandar Seovic (.NET)</author>
[TestFixture]
public sealed class ProxyFactoryObjectTests
{
private MockRepository mocks;
private IObjectFactory factory;
[SetUp]
public void SetUp()
{
mocks = new MockRepository();
factory = new XmlObjectFactory(new ReadOnlyXmlTestResource("proxyFactoryTests.xml", GetType()));
}
[Test]
public void TargetThrowsInvalidCastException()
{
Exception expectedException = new InvalidCastException();
ITestObject test1 = (ITestObject)factory.GetObject("test1");
try
{
test1.Exceptional(expectedException);
Assert.Fail("Should have thrown exception raised by target");
}
catch (Exception ex)
{
Assert.AreEqual(expectedException, ex, "exception matches");
Assert.AreEqual(1, test1.ExceptionMethodCallCount);
}
}
[Test]
public void IsCompositionProxy()
{
ITestObject test1 = (ITestObject)factory.GetObject("test1");
Assert.IsTrue(AopUtils.IsCompositionAopProxy(test1), "test1 is a composition proxy");
}
[Test]
public void GetObjectTypeWithDirectTarget()
{
IObjectFactory bf = new XmlObjectFactory(
new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml",
GetType()));
// We have a counting before advice here
CountingBeforeAdvice cba = (CountingBeforeAdvice)bf.GetObject("countingBeforeAdvice");
Assert.AreEqual(0, cba.GetCalls());
ITestObject tb = (ITestObject)bf.GetObject("directTarget");
Assert.IsTrue(tb.Name.Equals("Adam"));
Assert.AreEqual(1, cba.GetCalls());
ProxyFactoryObject pfb = (ProxyFactoryObject)bf.GetObject("&directTarget");
Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type");
}
[Test]
public void GetObjectTypeWithTargetViaTargetSource()
{
IObjectFactory bf = new XmlObjectFactory(
new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml",
GetType()));
ITestObject tb = (ITestObject)bf.GetObject("viaTargetSource");
Assert.IsTrue(tb.Name.Equals("Adam"));
ProxyFactoryObject pfb = (ProxyFactoryObject)bf.GetObject("&viaTargetSource");
Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type");
}
[Test]
public void GetObjectTypeWithNoTargetOrTargetSource()
{
IObjectFactory bf =
new XmlObjectFactory(new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml", GetType()));
bf.GetObject("noTarget");
IFactoryObject pfb = (ProxyFactoryObject)bf.GetObject("&noTarget");
Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type");
}
/// <summary>
/// The instances are equal, but do not have object identity.
/// Interceptors and interfaces and the target are the same.
/// </summary>
[Test]
public void SingletonInstancesAreEqual()
{
ITestObject test1 = (ITestObject)factory.GetObject("test1");
ITestObject test1_1 = (ITestObject)factory.GetObject("test1");
Assert.AreEqual(test1, test1_1, "Singleton instances ==");
test1.Age = 25;
Assert.AreEqual(test1.Age, test1_1.Age);
test1.Age = 250;
Assert.AreEqual(test1.Age, test1_1.Age);
IAdvised pc1 = (IAdvised)test1;
IAdvised pc2 = (IAdvised)test1_1;
Assert.AreEqual(pc1.Advisors, pc2.Advisors);
int oldLength = pc1.Advisors.Length;
NopInterceptor di = new NopInterceptor();
pc1.AddAdvice(1, di);
Assert.AreEqual(pc1.Advisors, pc2.Advisors);
Assert.AreEqual(oldLength + 1, pc2.Advisors.Length, "Now have one more advisor");
Assert.AreEqual(di.Count, 0);
test1.Age = (5);
Assert.AreEqual(test1_1.Age, test1.Age);
Assert.AreEqual(3, di.Count);
}
[Test]
public void PrototypeInstancesAreNotEqual()
{
ITestObject test2 = (ITestObject)factory.GetObject("prototype");
ITestObject test2_1 = (ITestObject)factory.GetObject("prototype");
Assert.IsTrue(test2 != test2_1, "Prototype instances !=");
Assert.IsTrue(TestObject.Equals(test2, test2_1), "Prototype instances equal");
}
[Test]
public void PrototypeInstancesAreIndependent()
{
IObjectFactory objectFactory = new XmlObjectFactory(new ReadOnlyXmlTestResource("prototypeTests.xml", GetType()));
// Initial count value set in object factory XML
int INITIAL_COUNT = 10;
// Check it works without AOP
ISideEffectObject raw = (ISideEffectObject)objectFactory.GetObject("prototypeTarget");
Assert.AreEqual(INITIAL_COUNT, raw.Count);
raw.doWork();
Assert.AreEqual(INITIAL_COUNT + 1, raw.Count);
raw = (ISideEffectObject)objectFactory.GetObject("prototypeTarget");
Assert.AreEqual(INITIAL_COUNT, raw.Count);
// Now try with advised instances
ISideEffectObject prototype2FirstInstance = (ISideEffectObject)objectFactory.GetObject("prototype");
Assert.AreEqual(INITIAL_COUNT, prototype2FirstInstance.Count);
prototype2FirstInstance.doWork();
Assert.AreEqual(INITIAL_COUNT + 1, prototype2FirstInstance.Count);
ISideEffectObject prototype2SecondInstance = (ISideEffectObject)objectFactory.GetObject("prototype");
Assert.IsFalse(prototype2FirstInstance == prototype2SecondInstance, "Prototypes are not ==");
Assert.AreEqual(INITIAL_COUNT, prototype2SecondInstance.Count);
Assert.AreEqual(INITIAL_COUNT + 1, prototype2FirstInstance.Count);
}
/// <summary> Test invoker is automatically added to manipulate target</summary>
[Test]
public void AutoInvoker()
{
String name = "Hieronymous";
TestObject target = (TestObject)factory.GetObject("test");
target.Name = name;
ITestObject autoInvoker = (ITestObject)factory.GetObject("autoInvoker");
Assert.IsTrue(autoInvoker.Name.Equals(name));
}
[Test]
public void CanGetFactoryReferenceAndManipulate()
{
ITestObject to = (ITestObject)factory.GetObject("test1");
// no exception
string dummy = to.Name;
IAdvised config = (IAdvised)to;
Assert.AreEqual(1, config.Advisors.Length, "Object should have only one advisors");
Exception ex = new NotSupportedException("Invoke");
// Add evil interceptor to head of list
config.AddAdvice(0, new EvilMethodInterceptor(ex));
Assert.AreEqual(2, config.Advisors.Length, "The advisor count is wrong after adding an advisor programmatically.");
try
{
// evil interceptor should throw exception
dummy = to.Name;
Assert.Fail("Evil interceptor added programmatically should fail all method calls, but it didn't");
}
catch (Exception thrown)
{
Assert.AreEqual(thrown, ex, "The thrown exception is not the one we were looking for.");
}
}
/// <summary>
/// Must see effect immediately on behaviour.
/// TODO (EE): Note that we can't add or remove interfaces without reconfiguring the singleton.
/// </summary>
[Test, Ignore("change according to ProxyFactoryBeanTests.canAddAndRemoveAdvicesOnSingleton")]
public void CanAddAndRemoveIntroductionsOnSingleton()
{
try
{
ITimeStamped ts = (ITimeStamped)factory.GetObject("test1");
Assert.Fail("Shouldn't implement ITimeStamped before manipulation");
}
catch (InvalidCastException)
{
}
ProxyFactoryObject config = (ProxyFactoryObject)factory.GetObject("&test1");
long time = 666L;
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor();
ti.TimeStamp = new DateTime(time);
IIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped));
// add to front of introduction chain
int oldCount = config.Introductions.Length;
config.AddIntroduction(0, advisor);
Assert.IsTrue(config.Introductions.Length == oldCount + 1);
ITimeStamped ts2 = (ITimeStamped)factory.GetObject("test1");
Assert.IsTrue(ts2.TimeStamp == new DateTime(time));
// Can remove
config.RemoveIntroduction(advisor);
Assert.IsTrue(config.Introductions.Length == oldCount);
// Existing reference will still work
object o = ts2.TimeStamp;
// But new proxies should not implement ITimeStamped
try
{
ts2 = (ITimeStamped)factory.GetObject("test1");
Assert.Fail("Should no longer implement ITimeStamped");
}
catch (InvalidCastException)
{
// expected...
}
// Now check non-effect of removing interceptor that isn't there
oldCount = config.Advisors.Length;
config.RemoveAdvice(new DebugAdvice());
Assert.IsTrue(config.Advisors.Length == oldCount);
ITestObject it = (ITestObject)ts2;
DebugAdvice debugInterceptor = new DebugAdvice();
config.AddAdvice(0, debugInterceptor);
object foo = it.Spouse;
Assert.AreEqual(1, debugInterceptor.Count);
config.RemoveAdvice(debugInterceptor);
foo = it.Spouse;
// not invoked again
Assert.IsTrue(debugInterceptor.Count == 1);
}
/// <summary> Try adding and removing interfaces and interceptors on prototype.
/// Changes will only affect future references obtained from the factory.
/// Each instance will be independent.
/// </summary>
[Test]
public void CanAddAndRemoveAspectInterfacesOnPrototype()
{
try
{
ITimeStamped ts = (ITimeStamped)factory.GetObject("test2");
Assert.Fail("Shouldn't implement ITimeStamped before manipulation");
}
catch (InvalidCastException)
{
}
IAdvised config = (IAdvised)factory.GetObject("&test2");
long time = 666L;
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor();
ti.TimeStamp = new DateTime(time);
IIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(ti, typeof(ITimeStamped));
// add to front of introduction chain
int oldCount = config.Introductions.Length;
config.AddIntroduction(0, advisor);
Assert.IsTrue(config.Introductions.Length == oldCount + 1);
ITimeStamped ts2 = (ITimeStamped)factory.GetObject("test2");
Assert.IsTrue(ts2.TimeStamp == new DateTime(time));
// Can remove
config.RemoveIntroduction(advisor);
Assert.IsTrue(config.Introductions.Length == oldCount);
// Existing reference will still work
object o = ts2.TimeStamp;
// But new proxies should not implement ITimeStamped
try
{
ts2 = (ITimeStamped)factory.GetObject("test2");
Assert.Fail("Should no longer implement ITimeStamped");
}
catch (InvalidCastException)
{
}
// Now check non-effect of removing interceptor that isn't there
ITestObject it = (ITestObject)factory.GetObject("test2");
config = (IAdvised)it;
oldCount = config.Advisors.Length;
config.RemoveAdvice(new DebugAdvice());
Assert.IsTrue(config.Advisors.Length == oldCount);
DebugAdvice debugInterceptor = new DebugAdvice();
config.AddAdvice(0, debugInterceptor);
object foo = it.Spouse;
Assert.AreEqual(1, debugInterceptor.Count);
config.RemoveAdvice(debugInterceptor);
foo = it.Spouse;
// not invoked again
Assert.IsTrue(debugInterceptor.Count == 1);
}
/// <summary>
/// Note that we can't add or remove interfaces without reconfiguring the
/// singleton.
/// </summary>
[Test]
public void CanAddAndRemoveAspectInterfacesOnSingletonByCasting()
{
ITestObject it = (ITestObject)factory.GetObject("test1");
IAdvised pc = (IAdvised)it;
object name = it.Age;
NopInterceptor di = new NopInterceptor();
pc.AddAdvice(0, di);
Assert.AreEqual(0, di.Count);
it.Age = 25;
Assert.AreEqual(25, it.Age);
Assert.AreEqual(2, di.Count);
}
[Test]
public void MethodPointcuts()
{
ITestObject tb = (ITestObject)factory.GetObject("pointcuts");
PointcutForVoid.Reset();
Assert.IsTrue((PointcutForVoid.methodNames.Count == 0), "No methods intercepted");
object o = tb.Age;
Assert.IsTrue((PointcutForVoid.methodNames.Count == 0), "Not void: shouldn't have intercepted");
tb.Age = 1;
o = tb.Age;
tb.Name = "Tristan";
tb.ToString();
Assert.AreEqual(2, PointcutForVoid.methodNames.Count, "Recorded wrong number of invocations");
Assert.AreEqual("set_Age", PointcutForVoid.methodNames[0]);
Assert.AreEqual("set_Name", PointcutForVoid.methodNames[1]);
}
[Test]
public void CanAddThrowsAdviceWithoutAdvisor()
{
IObjectFactory f = new XmlObjectFactory(new ReadOnlyXmlTestResource("throwsAdvice.xml", GetType()));
ThrowsAdviceInterceptorTests.MyThrowsHandler th =
(ThrowsAdviceInterceptorTests.MyThrowsHandler)f.GetObject("throwsAdvice");
CountingBeforeAdvice cba = (CountingBeforeAdvice)f.GetObject("countingBeforeAdvice");
Assert.AreEqual(0, cba.GetCalls());
Assert.AreEqual(0, th.GetCalls());
ThrowsAdviceInterceptorTests.IEcho echo = (ThrowsAdviceInterceptorTests.IEcho)f.GetObject("throwsAdvised");
echo.A = 12;
Assert.AreEqual(1, cba.GetCalls());
Assert.AreEqual(0, th.GetCalls());
Exception expected = new Exception();
try
{
echo.EchoException(1, expected);
Assert.Fail();
}
catch (Exception ex)
{
Assert.AreEqual(expected, ex);
}
// No throws handler method: count should still be 0
Assert.AreEqual(0, th.GetCalls());
// Handler knows how to handle this exception
expected = new HttpException();
try
{
echo.EchoException(1, expected);
Assert.Fail();
}
catch (HttpException ex)
{
Assert.AreEqual(expected, ex);
}
// One match
Assert.AreEqual(1, th.GetCalls("HttpException"));
}
/// <summary> Checks that globals get invoked,
/// and that they can add aspect interfaces unavailable
/// to other objects. These interfaces don't need
/// to be included in proxiedInterface [].
/// </summary>
[Test]
[ExpectedException(typeof(InvalidCastException))]
public void GlobalsCanAddAspectInterfaces()
{
IAddedGlobalInterface agi = (IAddedGlobalInterface)factory.GetObject("autoInvoker");
Assert.IsTrue(agi.GlobalsAdded == -1);
ProxyFactoryObject pfb = (ProxyFactoryObject)factory.GetObject("&validGlobals");
pfb.GetObject(); // for creation
Assert.AreEqual(2, pfb.Advisors.Length, "Proxy should have 1 global and 1 explicit advisor");
Assert.AreEqual(1, pfb.Introductions.Length, "Proxy should have 1 global introduction");
agi.GlobalsAdded = ((IAdvised)agi).Introductions.Length;
Assert.IsTrue(agi.GlobalsAdded == 1);
IApplicationEventListener l = (IApplicationEventListener)factory.GetObject("validGlobals");
agi = (IAddedGlobalInterface)l;
Assert.IsTrue(agi.GlobalsAdded == -1);
agi = (IAddedGlobalInterface)factory.GetObject("test1");
}
[Test]
public void IsSingletonFalseReturnsNew_ProxyInstance_NotNewProxyTargetSource()
{
GoodCommand target = new GoodCommand();
IObjectFactory mock = (IObjectFactory) mocks.CreateMock(typeof(IObjectFactory));
Expect.Call(mock.GetObject("singleton")).Return(target).Repeat.Twice();
mocks.ReplayAll();
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName };
fac.IsSingleton = false;
fac.TargetName = "singleton";
fac.ObjectFactory = mock;
fac.AddAdvice(new NopInterceptor());
ICommand one = (ICommand)fac.GetObject();
ICommand two = (ICommand)fac.GetObject();
Assert.IsFalse(ReferenceEquals(one, two));
mocks.VerifyAll();
}
[Test]
public void IsSingletonTrueReturnsNew_ProxyInstance_NotNewProxyTargetSource()
{
GoodCommand target = new GoodCommand();
IObjectFactory mock = (IObjectFactory)mocks.CreateMock(typeof(IObjectFactory));
Expect.Call(mock.GetObject("singleton")).Return(target);
mocks.ReplayAll();
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName };
fac.IsSingleton = true; // default, just being explicit...
fac.TargetName = "singleton";
fac.ObjectFactory = mock;
fac.AddAdvice(new NopInterceptor());
ICommand one = (ICommand)fac.GetObject();
ICommand two = (ICommand)fac.GetObject();
Assert.IsTrue(ReferenceEquals(one, two));
mocks.VerifyAll();
}
private ProxyFactoryObject CreateFrozenProxyFactory()
{
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.AddInterface(typeof(ITestObject));
fac.IsFrozen = true;
fac.AddAdvisor(new PointcutForVoid()); // this is ok, no proxy created yet
fac.GetObject();
return fac;
}
[Test]
public void AddAdvisorWhenConfigIsFrozen()
{
ProxyFactoryObject fac = CreateFrozenProxyFactory();
try
{
fac.AddAdvisor(new PointcutForVoid()); // not ok
Assert.Fail("changing a frozen config must throw AopConfigException");
}
catch (AopConfigException)
{}
}
[Test]
[ExpectedException(typeof(AopConfigException))]
public void RemoveAdvisorWhenConfigIsFrozen()
{
ProxyFactoryObject fac = CreateFrozenProxyFactory();
fac.IsFrozen = true;
fac.RemoveAdvisor(new PointcutForVoid());
}
[Test]
[ExpectedException(typeof(AopConfigException))]
public void ReplaceAdvisorWhenConfigIsFrozen()
{
ProxyFactoryObject fac = CreateFrozenProxyFactory();
fac.IsFrozen = true;
fac.ReplaceAdvisor(new PointcutForVoid(), new PointcutForVoid());
}
[Test]
public void TargetAtEndOfInterceptorList()
{
GoodCommand target = new GoodCommand();
NopInterceptor advice = new NopInterceptor();
IObjectFactory mock = (IObjectFactory) mocks.CreateMock(typeof(IObjectFactory));
Expect.Call(mock.GetObject("advice")).Return(advice);
Expect.Call(mock.GetObject("singleton")).Return(target);
Expect.Call(mock.GetType("singleton")).Return(typeof(GoodCommand));
mocks.ReplayAll();
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName };
fac.IsSingleton = true; // default, just being explicit...
fac.InterceptorNames = new string[] { "advice", "singleton" };
fac.ObjectFactory = mock;
ICommand one = (ICommand)fac.GetObject();
ICommand two = (ICommand)fac.GetObject();
Assert.IsTrue(ReferenceEquals(one, two));
one.Execute();
Assert.AreEqual(1, advice.Count);
two.Execute();
Assert.AreEqual(2, advice.Count);
mocks.VerifyAll();
}
[Test]
public void MakeSurePrototypeTargetIsNotNeedlesslyCreatedDuringInitialization_Unit()
{
GoodCommand target = new GoodCommand();
NopInterceptor advice = new NopInterceptor();
MockRepository mocks = new MockRepository();
IObjectFactory factory = (IObjectFactory) mocks.CreateMock(typeof(IObjectFactory));
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName };
fac.IsSingleton = false;
fac.InterceptorNames = new string[] { "advice", "prototype" };
fac.ObjectFactory = factory;
// using (mocks.Record())
{
using (mocks.Unordered())
{
Expect.Call(factory.IsSingleton("advice")).Return(true);
Expect.Call(factory.GetObject("advice")).Return(advice);
Expect.Call(factory.GetType("prototype")).Return(target.GetType());
Expect.Call(factory.GetObject("prototype")).Return(target);
}
}
mocks.ReplayAll();
// using(mocks.Playback())
{
fac.GetObject();
}
mocks.VerifyAll();
}
[Test]
public void MakeSurePrototypeTargetIsNotNeedlesslyCreatedDuringInitialization_Integration()
{
try
{
RootObjectDefinition advice = new RootObjectDefinition(typeof(NopInterceptor));
// prototype target...
RootObjectDefinition target = new RootObjectDefinition(typeof(InstantiationCountingCommand), false);
DefaultListableObjectFactory ctx = new DefaultListableObjectFactory();
ctx.RegisterObjectDefinition("advice", advice);
ctx.RegisterObjectDefinition("prototype", target);
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName };
fac.IsSingleton = false;
fac.InterceptorNames = new string[] { "advice", "prototype" };
fac.ObjectFactory = ctx;
Assert.AreEqual(0, InstantiationCountingCommand.NumberOfInstantiations,
"Prototype target instance is being (needlessly) created during PFO initialization.");
fac.GetObject();
Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Expected 1 inst");
fac.GetObject();
Assert.AreEqual(2, InstantiationCountingCommand.NumberOfInstantiations);
}
finally
{
InstantiationCountingCommand.NumberOfInstantiations = 0;
}
}
[Test]
public void SingletonProxyWithPrototypeTargetCreatesTargetOnlyOnce()
{
try
{
RootObjectDefinition advice = new RootObjectDefinition(typeof(NopInterceptor));
// prototype target...
RootObjectDefinition target = new RootObjectDefinition(typeof(InstantiationCountingCommand), false);
DefaultListableObjectFactory ctx = new DefaultListableObjectFactory();
ctx.RegisterObjectDefinition("advice", advice);
ctx.RegisterObjectDefinition("prototype", target);
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName };
fac.IsSingleton = true;
fac.InterceptorNames = new string[] { "advice", "prototype" };
fac.ObjectFactory = ctx;
Assert.AreEqual(0, InstantiationCountingCommand.NumberOfInstantiations, "First Call");
fac.GetObject();
Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Second Call");
fac.GetObject();
Assert.AreEqual(1, InstantiationCountingCommand.NumberOfInstantiations, "Third Call");
}
finally
{
InstantiationCountingCommand.NumberOfInstantiations = 0;
}
}
public class InstantiationCountingCommand : ICommand
{
private static int numberOfInstantiations = 0;
public InstantiationCountingCommand()
{
++numberOfInstantiations;
}
public static int NumberOfInstantiations
{
get { return numberOfInstantiations; }
set { numberOfInstantiations = value; }
}
public void Execute()
{
}
}
[Test]
public void NullNameInInterceptorNamesArrayThrowAopConfigException()
{
IObjectFactory factory = (IObjectFactory) mocks.CreateMock(typeof(IObjectFactory));
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { typeof(ICommand).FullName };
fac.IsSingleton = false;
fac.InterceptorNames = new string[] { null, null };
fac.ObjectFactory = factory;
try
{
fac.GetObject();
Assert.Fail();
}
catch (AopConfigException)
{}
}
[Test]
public void PassEmptyInterceptorNamesArray_WithTargetThatImplementsAnInterfaceCanBeCastToSaidInterface()
{
IObjectFactory factory = (IObjectFactory) mocks.CreateMock(typeof(IObjectFactory));
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { };
fac.Target = new GoodCommand();
fac.ObjectFactory = factory;
IAdvised advised = fac.GetObject() as IAdvised;
Assert.IsNotNull(advised);
ICommand cmd = fac.GetObject() as ICommand;
Assert.IsNotNull(cmd);
DoesntImplementAnyInterfaces obj = fac.GetObject() as DoesntImplementAnyInterfaces;
Assert.IsNull(obj);
}
[Test]
[ExpectedException(typeof(AopConfigException))]
public void PassNullToTheProxyInterfacesProperty()
{
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = null;
}
[Test]
[ExpectedException(typeof(AopConfigException))]
public void PassClassNotInterfaceNameToTheProxyInterfacesProperty()
{
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { typeof(GoodCommand).FullName };
}
[Test]
[ExpectedException(typeof(AopConfigException))]
public void PassRubbishNameToTheProxyInterfacesProperty()
{
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { "Hey" };
}
[Test]
[ExpectedException(typeof(AopConfigException))]
public void PassNullElementListToTheProxyInterfacesProperty()
{
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.ProxyInterfaces = new string[] { null };
}
[Test]
public void ProxiedObjectUnwrapsTargetInvocationException()
{
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.AddInterface(typeof(ICommand));
fac.AddAdvice(new NopInterceptor());
fac.Target = new BadCommand();
ICommand cmd = (ICommand)fac.GetObject();
try
{
cmd.Execute();
}
catch (NotImplementedException)
{
// this is good, we want this exception to bubble up...
}
catch (TargetInvocationException)
{
Assert.Fail("Must have unwrapped this.");
}
}
[Test]
public void FactoryWrapsObjectInSingletonTargetSource()
{
IObjectFactory bf = new XmlObjectFactory(
new ReadOnlyXmlTestResource("proxyFactoryTargetSourceTests.xml",
GetType()));
ITestObject tb = (ITestObject)bf.GetObject("viaTargetSource");
Assert.IsTrue(tb.Name.Equals("Adam"));
ProxyFactoryObject pfb = (ProxyFactoryObject)bf.GetObject("&viaTargetSource");
Assert.IsTrue(typeof(ITestObject).IsAssignableFrom(pfb.ObjectType), "Has correct object type");
Assert.AreEqual(typeof(SingletonTargetSource), pfb.TargetSource.GetType(), "Incorrect target source, expected singleton");
}
[Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-293")]
public void SupportsTransparentProxyAsTarget()
{
AppDomain domain = null;
try
{
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = Environment.CurrentDirectory;
domain = AppDomain.CreateDomain("Spring", new Evidence(AppDomain.CurrentDomain.Evidence), setup);
object command = domain.CreateInstanceAndUnwrap(GetType().Assembly.FullName, typeof(RemotableCommand).FullName);
ProxyFactoryObject fac = new ProxyFactoryObject();
fac.AddInterface(typeof(ICommand));
fac.AddAdvice(new NopInterceptor());
fac.Target = command;
IAdvised advised = fac.GetObject() as IAdvised;
Assert.IsNotNull(advised);
ICommand cmd = fac.GetObject() as ICommand;
Assert.IsNotNull(cmd);
cmd.Execute();
}
finally
{
AppDomain.Unload(domain);
}
}
[Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-500")]
public void NotAccessibleInterfaceProxying()
{
const string xml = @"<?xml version='1.0' encoding='UTF-8' ?>
<objects xmlns='http://www.springframework.net'>
<object id='MyProxy' type='Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop'>
<property name='ProxyInterfaces'>
<list>
<value>Spring.Aop.Framework.HelperInterface2, Spring.Aop.Tests</value>
</list>
</property>
<property name='TargetName' value='MyTarget' />
<property name='InterceptorNames'>
<list>
<value>MyInterceptor</value>
</list>
</property>
</object>
<object id='MyTarget' type='Spring.Aop.Framework.HelperClassForNotAccessibleInterfaceProxyingTest, Spring.Aop.Tests'/>
<object id='MyInterceptor' type='Spring.Aop.Interceptor.NopInterceptor'/>
</objects>";
MemoryStream stream = new MemoryStream(new UTF8Encoding().GetBytes(xml));
IResource resource = new InputStreamResource(stream, "Test ProxyFactoryObject");
XmlObjectFactory objectFactory = new XmlObjectFactory(resource, null);
HelperInterface2 hc = (HelperInterface2)objectFactory.GetObject("MyProxy");
Console.WriteLine(hc.SecondDoSomething());
}
[Test]
public void ProxyFactoryObjectIsThreadSafe()
{
const int WORKERS = 10;
AsyncTestMethod[] workers = new AsyncTestMethod[WORKERS];
for(int i=0;i<WORKERS;i++)
{
workers[i] = new AsyncTestMethod( 1, new ThreadStart( CallGetObject ) );
}
for(int i=0;i<WORKERS;i++)
{
workers[i].Start();
}
for(int i=0;i<WORKERS;i++)
{
workers[i].AssertNoException();
}
}
private void CallGetObject()
{
ProxyFactoryObject proxyFactory = (ProxyFactoryObject) this.factory.GetObject("&concurrentPrototype");
ITestObject prevTestObject = null;
for(int i=0;i<20;i++)
{
ITestObject o = proxyFactory.GetObject() as ITestObject;
Assert.IsNotNull(o);
Assert.AreNotSame( prevTestObject, o );
prevTestObject = o;
Thread.Sleep( 0 );
}
}
[Test]
public void ProxyTypeDoesntChangeIfSameConfig()
{
ProxyFactoryObject factoryObject = (ProxyFactoryObject) this.factory.GetObject( "&concurrentPrototype" );
Type testObjectType1 = factoryObject.GetObject().GetType();
Type testObjectType2 = factoryObject.GetObject().GetType();
Assert.AreSame(testObjectType1, testObjectType2);
}
[Test]
public void ProxyTypeChangesIfConfigChanges()
{
ProxyFactoryObject factoryObject = (ProxyFactoryObject) this.factory.GetObject( "&concurrentPrototype" );
Type testObjectType1 = factoryObject.GetObject().GetType();
factoryObject.Interfaces = new Type[] {};
Type testObjectType2 = factoryObject.GetObject().GetType();
Assert.AreNotSame( testObjectType1,testObjectType2 );
}
#region WorkerThread Class
public class WorkerThread
{
private Exception _exception;
private Thread _thread;
private WaitCallback _callback;
private object _arg;
public WorkerThread(string name, WaitCallback callback,object arg)
{
this._arg = arg;
this._callback = callback;
_thread = new Thread( new ThreadStart( Run ) );
_thread.IsBackground = true;
_thread.Name = name;
}
public void Start()
{
_thread.Start();
}
public void Join()
{
if (_thread.IsAlive)
{
_thread.Join();
}
}
public Exception Exception
{
get { return this._exception; }
}
private void Run()
{
try
{
_callback( _arg );
}
catch(Exception ex)
{
_exception = ex;
}
}
}
#endregion WorkerThread Class
#region Helper Classes
public interface ICommand
{
void Execute();
}
public sealed class BadCommand : ICommand
{
public void Execute()
{
throw new NotImplementedException();
}
}
public sealed class GoodCommand : ICommand
{
public void Execute()
{
}
}
public sealed class RemotableCommand : MarshalByRefObject, ICommand
{
public void Execute()
{
}
}
/// <summary>
/// Fires only on void methods. Saves list of methods intercepted.
/// </summary>
public class PointcutForVoid : DynamicMethodMatcherPointcutAdvisor
{
private class AnonymousClassMethodInterceptor1 : IMethodInterceptor
{
public Object Invoke(IMethodInvocation invocation)
{
methodNames.Add(invocation.Method.Name);
return invocation.Proceed();
}
}
public static IList methodNames;
public static void Reset()
{
methodNames.Clear();
}
public PointcutForVoid()
: base(new AnonymousClassMethodInterceptor1())
{
}
/// <summary>
/// Must fire only if it returns void.
/// </summary>
public override bool Matches(MethodInfo method, Type targetType, object[] args)
{
return method.ReturnType == typeof(void);
}
static PointcutForVoid()
{
methodNames = new ArrayList();
}
}
/// <summary> Aspect interface</summary>
public interface IAddedGlobalInterface
{
int GlobalsAdded { get; set; }
}
/// <summary> Use as a global interceptor. Checks that
/// global interceptors can add aspect interfaces.
/// NB: Add only via global interceptors in XML file.
/// </summary>
public class GlobalIntroduction : IAdvice, IAddedGlobalInterface
{
private int globalsAdded = -1;
public int GlobalsAdded
{
get { return globalsAdded; }
set { globalsAdded = value; }
}
}
private class EvilMethodInterceptor : IMethodInterceptor
{
private Exception ex;
public EvilMethodInterceptor(Exception ex)
{
this.ex = ex;
}
public object Invoke(IMethodInvocation invocation)
{
throw ex;
}
}
#endregion
}
#region HelpersForNotAccessibleInterfaceProxyingTest
public class HelperClassForNotAccessibleInterfaceProxyingTest : HelperInterface1, HelperInterface2
{
public string FirstDoSomething()
{
return "FirstDoSomething (internal interface implementation)";
}
public string SecondDoSomething()
{
return "SecondDoSomething (public interface implementation)";
}
}
internal interface HelperInterface1
{
string FirstDoSomething();
}
public interface HelperInterface2
{
string SecondDoSomething();
}
#endregion
}
|