#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.Threading;
using AopAlliance.Aop;
using NUnit.Framework;
using Spring.Objects;
using AopAlliance.Intercept;
using Spring.Threading;
using Spring.Util;
#endregion
namespace Spring.Aop.Framework{
/// <summary>
/// Unit tests for the AopContext class.
/// </summary>
/// <author>Rick Evans</author>
[TestFixture]
public sealed class AopContextTests
{
[SetUp]
public void SetUp()
{
// makes sure the context is always empty before any unit test...
try
{
do
{
AopContext.PopProxy();
} while (true);
}
catch (AopConfigException)
{
}
}
[Test]
[ExpectedException(typeof(AopConfigException))]
public void CurrentProxyChokesIfNoAopProxyIsOnTheStack()
{
AopContext.CurrentProxy.ToString();
}
[Test]
public void CurrentProxyStackJustPeeksItDoesntPop()
{
string foo = "Foo";
AopContext.PushProxy(foo);
object fooref = AopContext.CurrentProxy;
Assert.IsTrue(ReferenceEquals(foo, fooref),
"Not the exact same instance (must be).");
// must not have been popped off the stack by looking at it...
object foorefref = AopContext.CurrentProxy;
Assert.IsTrue(ReferenceEquals(fooref, foorefref),
"Not the exact same instance (must be).");
}
[Test]
[ExpectedException(typeof(AopConfigException))]
public void PopProxyWithNothingOnStack()
{
AopContext.PopProxy();
}
[Test(Description = "SPRNET-1158")]
public void IsActiveMatchesStackState()
{
Assert.IsFalse(AopContext.IsActive);
AopContext.PushProxy("Foo");
Assert.IsTrue(AopContext.IsActive);
AopContext.PopProxy();
Assert.IsFalse(AopContext.IsActive);
}
#region CurrentProxyIsThreadSafe
[Test, Explicit]
public void ProxyPerformanceTests()
{
int runs = 5000000;
StopWatch watch = new StopWatch();
ITestObject testObject = new ChainableTestObject(null);
using (watch.Start("Naked Duration: {0}"))
{
for (int i = 0; i < runs; i++)
{
object result = testObject.DoSomething(this);
}
}
ITestObject hardcodedWrapper = new ChainableTestObject(testObject);
using (watch.Start("Hardcoded Wrapper Duration: {0}"))
{
for (int i = 0; i < runs; i++)
{
object result = hardcodedWrapper.DoSomething(this);
}
}
PeformanceTestAopContextInterceptor interceptor = new PeformanceTestAopContextInterceptor();
ITestObject proxy = CreateProxy(testObject, interceptor, false);
using(watch.Start("Proxy Duration ('ExposeProxy'==false): {0}"))
{
for(int i=0;i<runs;i++)
{
object result = proxy.DoSomething(this);
}
}
Assert.AreEqual(runs, interceptor.Calls);
interceptor = new PeformanceTestAopContextInterceptor();
proxy = CreateProxy(testObject, interceptor, true);
using(watch.Start("Proxy Duration ('ExposeProxy'==true): {0}"))
{
for(int i=0;i<runs;i++)
{
object result = proxy.DoSomething(this);
}
}
Assert.AreEqual(runs, interceptor.Calls);
}
private class PeformanceTestAopContextInterceptor : IMethodInterceptor
{
public int Calls = 0;
public object Invoke(IMethodInvocation invocation)
{
Calls++;
Object ret = invocation.Proceed();
return ret;
}
}
[Test(Description = "http://opensource.atlassian.com/projects/spring/browse/SPRNET-341")]
public void CurrentProxyIsThreadSafe()
{
ProxyTestObjectAndExposeProxy();
AsyncTestMethod t1 = new AsyncTestMethod(1000, new ThreadStart(ProxyTestObjectAndExposeProxy));
AsyncTestMethod t2 = new AsyncTestMethod(1000, new ThreadStart(ProxyTestObjectAndExposeProxy));
t1.Start();
t2.Start();
t1.AssertNoException();
t2.AssertNoException();
}
public interface ITestObject
{
object DoSomething(object arg);
}
private class ChainableTestObject : ITestObject
{
private readonly ITestObject next;
public ChainableTestObject(ITestObject next)
{
this.next = next;
}
public virtual object DoSomething(object arg)
{
if (next != null)
{
return next.DoSomething(arg);
}
// simulate some sensible work
string rep = string.Format("{0} {1}", this.GetType(), arg.GetHashCode());
return arg;
}
}
private void ProxyTestObjectAndExposeProxy()
{
TestAopContextInterceptor interceptor = new TestAopContextInterceptor();
ITestObject proxy = CreateProxyChain(interceptor, true);
Assert.IsFalse(AopContext.IsActive);
Assert.AreEqual(this, proxy.DoSomething(this), "Incorrect return value");
Assert.IsFalse(AopContext.IsActive);
Assert.AreEqual(2, interceptor.Calls); // 2 interceptions on the way
}
private ITestObject CreateProxyChain(IAdvice interceptor, bool exposeProxy)
{
ITestObject first = new ChainableTestObject(null);
ITestObject firstProxy = CreateProxy(first, interceptor, exposeProxy);
Assert.IsNotNull(firstProxy);
ITestObject second = new ChainableTestObject(firstProxy);
ITestObject secondProxy = CreateProxy(second, interceptor, exposeProxy);
Assert.IsNotNull(secondProxy);
return secondProxy;
}
private ITestObject CreateProxy(object target, IAdvice interceptor, bool exposeProxy)
{
ProxyFactory pf = new ProxyFactory(target);
pf.ExposeProxy = exposeProxy;
// pf.Target = target;
pf.AddAdvice(interceptor);
return pf.GetProxy() as ITestObject;
}
private class TestAopContextInterceptor : IMethodInterceptor
{
public int Calls = 0;
public object Invoke(IMethodInvocation invocation)
{
Calls++;
Assert.IsTrue(AopContext.IsActive);
Assert.IsNotNull(AopContext.CurrentProxy);
Assert.AreSame(invocation.Proxy, AopContext.CurrentProxy);
Object ret = invocation.Proceed();
Assert.IsNotNull(AopContext.CurrentProxy);
Assert.IsTrue(AopContext.IsActive);
return ret;
}
}
#endregion
}
}
|