SPRNET-1297

-introduced IDictionary convenience constructor overload for DictionaryVariableSource
-added unit tests for DictionaryVariableSource behaviors
-introduced guard exception if unbalanced strings are passed to constructor as key-value pairs (but aren't in fact properly 'paired')
This commit is contained in:
sbohlen
2010-07-23 21:28:48 +00:00
parent c9ef6b8372
commit 611bdbb107
9 changed files with 210 additions and 59 deletions

View File

@@ -36,7 +36,7 @@ namespace Spring.Objects.Factory.Config
/// Creates a new, empty variable source
/// </summary>
public DictionaryVariableSource()
:this(null, true)
: this(null, true)
{
}
@@ -44,7 +44,7 @@ namespace Spring.Objects.Factory.Config
/// Creates a new, empty and case-insensitive variable source
/// </summary>
public DictionaryVariableSource(bool ignoreCase)
:this(null, ignoreCase)
: this(null, ignoreCase)
{
}
@@ -61,17 +61,32 @@ namespace Spring.Objects.Factory.Config
/// </remarks>
/// <param name="args">the argument list containing pairs, or <c>null</c></param>
public DictionaryVariableSource(params string[] args)
:this(true)
: this(true)
{
if (args != null)
{
for (int i = 0; i < args.Length; i += 2)
if (args.Length % 2 != 0)
{
Add(args[i], args[i + 1]);
throw new ArgumentOutOfRangeException("Unbalanced Key-Value pairs of strings detected. Verify that args contains pairs of key strings and value strings.");
}
for (int i = 0; i < args.Length; i += 2)
{
Add(args[i], args[i + 1]);
}
}
}
/// <summary>
/// Initializes a new instance of the DictionaryVariableSource class.
/// </summary>
public DictionaryVariableSource(IDictionary dictionary)
: this(dictionary, true)
{
}
/// <summary>
/// Creates a new variable source, reading values from another dictionary
/// and converting them to strings if necessary

View File

@@ -0,0 +1,120 @@
using System;
using System.Collections;
using System.Text;
using NUnit.Framework;
namespace Spring.Objects.Factory.Config
{
[TestFixture]
public class DictionaryVariableSourceTests
{
[Test]
public void Initialize_WithCaseSensitiveFlag_AddsCaseSensitiveKeys()
{
DictionaryVariableSource dvs = new DictionaryVariableSource(false);
dvs.Add("key1", "lowercasevalue");
dvs.Add("KEY1", "uppercasevalue");
Assert.AreEqual("lowercasevalue", dvs.ResolveVariable("key1"));
Assert.AreEqual("uppercasevalue", dvs.ResolveVariable("KEY1"));
}
[Test]
public void Iniitialize_WithStringArray_FillsKeyValuesInPairs()
{
DictionaryVariableSource dvs = new DictionaryVariableSource(new string[] { "key1", "value1", "key2", "value2" });
Assert.AreEqual("value1", dvs.ResolveVariable("key1"));
Assert.AreEqual("value2", dvs.ResolveVariable("key2"));
}
[Test]
public void Iniitialize_WithStringArray_ThrowsException_WhenOddNumberOfStringsProvided()
{
Assert.Throws<ArgumentOutOfRangeException>(() => new DictionaryVariableSource(new string[] { "key1", "value1", "key2", "value2", "orphanedKey1" }));
}
[Test]
public void Initialize_WithDictionaryConstructor_AddsCaseInsensitiveKeys()
{
IDictionary dict = new Hashtable() { { "key1", "value1" }, { "KEY2", "value2" } };
DictionaryVariableSource dvs = new DictionaryVariableSource(dict);
Assert.AreEqual("value1", dvs.ResolveVariable("KEY1"));
Assert.AreEqual("value2", dvs.ResolveVariable("key2"));
}
[Test]
public void Initialize_WithDictionaryConstructor_AddsKeys()
{
IDictionary dict = new Hashtable() { { "key1", "value1" }, { "key2", "value2" } };
DictionaryVariableSource dvs = new DictionaryVariableSource(dict);
Assert.AreEqual("value1", dvs.ResolveVariable("key1"));
Assert.AreEqual("value2", dvs.ResolveVariable("key2"));
}
[Test]
public void Initialize_WithDictionaryConstructorAndCaseSensitiveFlag_AddsCaseSensitiveKeys()
{
IDictionary dict = new Hashtable() { { "key1", "lowecasevalue" }, { "KEY1", "uppercasevalue" } };
DictionaryVariableSource dvs = new DictionaryVariableSource(dict, false);
Assert.AreEqual("lowecasevalue", dvs.ResolveVariable("key1"));
Assert.AreEqual("uppercasevalue", dvs.ResolveVariable("KEY1"));
}
[Test]
public void Initialize_WithEmptyConstructor_AddsCaseInsensitiveKeys()
{
DictionaryVariableSource dvs = new DictionaryVariableSource();
dvs.Add("key1", "value1");
dvs.Add("KEY2", "value2");
Assert.AreEqual("value1", dvs.ResolveVariable("KEY1"));
Assert.AreEqual("value2", dvs.ResolveVariable("key2"));
}
[Test]
public void Test()
{
Hashtable hashtable = new Hashtable();
hashtable.Add("KEY1", "value1");
Assert.False(hashtable.ContainsKey("key1"));
}
[Test]
public void CanResolveVariable_RespectsCaseSensitivity()
{
DictionaryVariableSource caseSensitive = new DictionaryVariableSource(false);
caseSensitive.Add("KEY1", "value1");
Assert.False(caseSensitive.CanResolveVariable("key1"));
}
[Test]
public void CanResolveVariable_RespectsCaseInsensitivity()
{
DictionaryVariableSource caseInsensitive = new DictionaryVariableSource();
caseInsensitive.Add("key1", "value1");
Assert.True(caseInsensitive.CanResolveVariable("KEY1"));
}
[Test]
public void Requesting_KeyNotFound_ThrowsException()
{
DictionaryVariableSource dvs = new DictionaryVariableSource();
dvs.Add("key-found", "value-found");
Assert.Throws<ArgumentException>(() => dvs.ResolveVariable("key-not-found"));
}
}
}

View File

@@ -38,13 +38,8 @@ namespace Spring.Objects.Factory.Config
{
StaticApplicationContext ac = new StaticApplicationContext();
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer();
try
{
vphc.PostProcessObjectFactory(ac.ObjectFactory);
Assert.Fail();
}
catch (ArgumentException)
{}
Assert.Throws<ArgumentException>(() => vphc.PostProcessObjectFactory(ac.ObjectFactory));
}
[Test]
@@ -52,15 +47,9 @@ namespace Spring.Objects.Factory.Config
{
StaticApplicationContext ac = new StaticApplicationContext();
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer();
vphc.VariableSources = new ArrayList( new object[] { new object() } );
vphc.VariableSources = new ArrayList(new object[] { new object() });
try
{
vphc.PostProcessObjectFactory(ac.ObjectFactory);
Assert.Fail();
}
catch (ArgumentException)
{}
Assert.Throws<ArgumentException>(() => vphc.PostProcessObjectFactory(ac.ObjectFactory));
}
[Test]
@@ -85,7 +74,7 @@ namespace Spring.Objects.Factory.Config
pvs = new MutablePropertyValues();
pvs.Add("VariableSources", variableSources);
ac.RegisterSingleton("configurer", typeof(VariablePlaceholderConfigurer), pvs);
ac.Refresh();
@@ -106,7 +95,7 @@ namespace Spring.Objects.Factory.Config
ac.RegisterSingleton("tb1", typeof(TestObject), pvs);
IList variableSources = new ArrayList();
variableSources.Add( new DictionaryVariableSource( new string[] { "maxResults", "35", "name", "Erich" } ) );
variableSources.Add(new DictionaryVariableSource(new string[] { "maxResults", "35", "name", "Erich" }));
pvs = new MutablePropertyValues();
@@ -119,9 +108,9 @@ namespace Spring.Objects.Factory.Config
TestObject tb1 = (TestObject)ac.GetObject("tb1");
Assert.AreEqual(35, tb1.Age);
Assert.AreEqual("Erich", tb1.Name);
}
Assert.AreEqual("Erich", tb1.Name);
}
[Test]
public void MultiResolution()
{
@@ -132,11 +121,11 @@ namespace Spring.Objects.Factory.Config
IList variableSources = new ArrayList();
variableSources.Add(new DictionaryVariableSource(new string[] { "firstname", "FirstName" }));
variableSources.Add(new DictionaryVariableSource(new string[] { "lastname", "LastName"}));
variableSources.Add(new DictionaryVariableSource(new string[] { "lastname", "LastName" }));
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources);
vphc.PostProcessObjectFactory(of);
RootObjectDefinition rod = (RootObjectDefinition) of.GetObjectDefinition("tb1");
RootObjectDefinition rod = (RootObjectDefinition)of.GetObjectDefinition("tb1");
Assert.AreEqual("Hello FirstName LastName!", rod.PropertyValues.GetPropertyValue("Greeting").Value);
}
@@ -150,11 +139,11 @@ namespace Spring.Objects.Factory.Config
IList variableSources = new ArrayList();
variableSources.Add(new DictionaryVariableSource(new string[] { "name", "${nickname}" }));
variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value"}));
variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value" }));
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources);
vphc.PostProcessObjectFactory(of);
RootObjectDefinition rod = (RootObjectDefinition) of.GetObjectDefinition("tb1");
RootObjectDefinition rod = (RootObjectDefinition)of.GetObjectDefinition("tb1");
Assert.AreEqual("nickname-value", rod.PropertyValues.GetPropertyValue("NameProperty").Value);
}
@@ -170,7 +159,7 @@ namespace Spring.Objects.Factory.Config
IList variableSources = new ArrayList();
variableSources.Add(new DictionaryVariableSource(new string[] { "name", "name-value" }));
variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value"}));
variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value" }));
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources);
ac.AddObjectFactoryPostProcessor(vphc);
ac.Refresh();
@@ -192,11 +181,11 @@ namespace Spring.Objects.Factory.Config
IList variableSources = new ArrayList();
variableSources.Add(new DictionaryVariableSource(new string[] { "name", "name-value", "nickname", null }));
variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value"}));
variableSources.Add(new DictionaryVariableSource(new string[] { "nickname", "nickname-value" }));
VariablePlaceholderConfigurer vphc = new VariablePlaceholderConfigurer(variableSources);
vphc.PostProcessObjectFactory(of);
RootObjectDefinition rod = (RootObjectDefinition) of.GetObjectDefinition("tb1");
RootObjectDefinition rod = (RootObjectDefinition)of.GetObjectDefinition("tb1");
Assert.AreEqual("name-value", rod.PropertyValues.GetPropertyValue("NameProperty").Value);
Assert.AreEqual(null, rod.PropertyValues.GetPropertyValue("NickNameProperty").Value);
}
@@ -245,7 +234,7 @@ namespace Spring.Objects.Factory.Config
}
catch (ObjectDefinitionStoreException ex)
{
Assert.IsTrue( ex.Message.IndexOf("nickname") > -1 );
Assert.IsTrue(ex.Message.IndexOf("nickname") > -1);
}
}
@@ -261,12 +250,12 @@ namespace Spring.Objects.Factory.Config
VariablePlaceholderConfigurer vpc = new VariablePlaceholderConfigurer();
vpc.IgnoreUnresolvablePlaceholders = true;
vpc.VariableSource = new DictionaryVariableSource(new string[] {"name", "Erich"});
vpc.VariableSource = new DictionaryVariableSource(new string[] { "name", "Erich" });
ac.AddObjectFactoryPostProcessor(vpc);
ac.Refresh();
TestObject tb1 = (TestObject) ac.GetObject("tb1");
TestObject tb1 = (TestObject)ac.GetObject("tb1");
Assert.AreEqual("Erich", tb1.Name);
Assert.AreEqual("${nickname}", tb1.Nickname);
}

View File

@@ -324,6 +324,7 @@
<Compile Include="Objects\Factory\Config\ConfigSectionVariableSourceTests.cs" />
<Compile Include="Objects\Factory\Config\ConnectionStringsVariableSourceTests.cs" />
<Compile Include="Objects\Factory\Config\DelegateObjectFactoryConfigurerTests.cs" />
<Compile Include="Objects\Factory\Config\DictionaryVariableSourceTests.cs" />
<Compile Include="Objects\Factory\Config\ObjectDefinitionVisitorTests.cs" />
<Compile Include="Objects\Factory\Config\ResourceHandlerConfigurerTests.cs" />
<Compile Include="Objects\Factory\Config\PropertyFileVariableSourceTests.cs" />

View File

@@ -35,17 +35,27 @@ namespace Spring.Messaging.Core
MessageQueue.EnableConnectionCache = false;
if (MessageQueue.Exists(path))
{
MessageQueue queue;
// TODO (EE): delete/create doesn't work for some reason
// MessageQueue.Delete(path);
// queue = MessageQueue.Create(path, transactional);
queue = new MessageQueue(path);
queue.Purge();
queue.Dispose();
using (MessageQueue queue = new MessageQueue(path))
{
queue.Purge();
}
}
else
{
MessageQueue.Create(path, transactional).Dispose();
/*
* MSDN docs indicate that calls to the static .Create() method should include
* an explicit call to .Dispose() b/c unmanaged resources are involved
* Here this req'ment is handled implicitly with the using() statement
* even though the empty using() block seems odd at first glance b/c it
* encloses a static method call
*/
using (MessageQueue.Create(path, transactional))
{
}
}
MessageQueue.ClearConnectionCache();
MessageQueue.EnableConnectionCache = defaultCacheEnabled; // set to default

View File

@@ -25,6 +25,7 @@ using System.Threading;
using NUnit.Framework;
using Spring.Messaging.Core;
using Spring.Testing.NUnit;
using System;
#endregion
@@ -48,6 +49,11 @@ namespace Spring.Messaging.Listener
{
MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxqueue", true);
MessageQueueUtils.RecreateMessageQueue(@".\Private$\testtxretryqueue", true);
if (listener != null)
listener.MessageCount = 0; //reset the property between tests b/c the object lifecycle is singleton!
base.SetUp();
}
@@ -74,7 +80,7 @@ namespace Spring.Messaging.Listener
q.ConvertAndSend("Goodbye World 1");
Assert.AreEqual(0, listener.MessageCount);
Assert.AreEqual(0, listener.MessageCount, "PRECONDITION FAILURE: Unable to send the message!");
distributedTxMessageListenerContainer.Start();
Thread.Sleep(waitInMillis);
@@ -94,23 +100,28 @@ namespace Spring.Messaging.Listener
[Test]
public void SendAndAsyncReceive()
{
const int MESSAGE_COUNT = 5;
//must match the retry count in the object registration for test to pass!
const int EXCEPTION_QUEUE_RETRY_COUNT = 2;
MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate;
Assert.IsNotNull(q);
q.ConvertAndSend("Hello World 1");
q.ConvertAndSend("Hello World 2");
q.ConvertAndSend("Hello World 3");
q.ConvertAndSend("Hello World 4");
q.ConvertAndSend("Hello World 5");
for (int i = 0; i < MESSAGE_COUNT; i++)
{
q.ConvertAndSend(String.Format("Hello World {0}", (i + 1)));
}
Assert.AreEqual(0, listener.MessageCount);
distributedTxMessageListenerContainer.Start();
Thread.Sleep(waitInMillis);
Assert.AreEqual(15, listener.MessageCount);
//this test needs to wait somewhat longer than the others in order to consistently pass so
//artificially inflate the waiting period before attempting subsequent asserts:
Thread.Sleep((int)(waitInMillis * 1.5));
Assert.AreEqual(MESSAGE_COUNT + (MESSAGE_COUNT * EXCEPTION_QUEUE_RETRY_COUNT), listener.MessageCount);
distributedTxMessageListenerContainer.Stop();
distributedTxMessageListenerContainer.Shutdown();

View File

@@ -34,7 +34,7 @@
</object>
<object id='testremotequeue' type='Spring.Messaging.Support.MessageQueueFactoryObject, Spring.Messaging'>
<property name='Path' value='FormatName:Direct=OS:MARK6500\Private$\testqueue'/>
<property name='Path' value='FormatName:Direct=OS:CCORSELLO-PC\Private$\testqueue'/>
<property name='RemoteQueue' value="true"/>
</object>

View File

@@ -62,12 +62,14 @@ namespace Spring.Messaging.Listener
set { listener = value; }
}
[Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Property 'MessageQueueObjectName' is required")]
[Test]
public void EnsureMessageQueuePropertyIsSet()
{
TransactionalMessageListenerContainer container = new TransactionalMessageListenerContainer();
container.AfterPropertiesSet();
container.Start();
ArgumentException ex = Assert.Throws<ArgumentException>(() => container.AfterPropertiesSet());
Assert.AreEqual("Property 'MessageQueueObjectName' is required", ex.Message);
}
[Test]
@@ -75,12 +77,14 @@ namespace Spring.Messaging.Listener
{
TransactionalMessageListenerContainer container = applicationContext["transactionalMessageListenerContainer"] as TransactionalMessageListenerContainer;
Assert.IsNotNull(container);
Assert.AreEqual(true, container.UseContainerManagedMessageQueueTransaction);
Assert.AreEqual(true, container.UseContainerManagedMessageQueueTransaction);
}
[Test]
public void SendAndAsyncReceiveWithExceptionHandling()
{
listener.MessageCount = 0;
MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate;
Assert.IsNotNull(q);
@@ -110,28 +114,28 @@ namespace Spring.Messaging.Listener
[Test]
public void SendAndAsyncReceive()
{
listener.MessageCount = 0;
MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate;
Assert.IsNotNull(q);
q.ConvertAndSend("Hello World 1");
q.ConvertAndSend("Hello World 2");
q.ConvertAndSend("Hello World 3");
q.ConvertAndSend("Hello World 4");
q.ConvertAndSend("Hello World 5");
Assert.AreEqual(0, listener.MessageCount);
transactionalMessageListenerContainer.Start();
Thread.Sleep(waitInMillis);
Thread.Sleep(waitInMillis * 2);
Assert.AreEqual(5, listener.MessageCount);
transactionalMessageListenerContainer.Stop();
transactionalMessageListenerContainer.Shutdown();
Thread.Sleep(2500);
}

View File

@@ -5,7 +5,8 @@
<db:provider id="DbProvider"
provider="System.Data.SqlClient"
connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=Spring;Persist Security Info=True;User ID=springqa;Password=springqa"/>
connectionString="Data Source=.\SQLExpress;Initial Catalog=springqa;Persist Security Info=True;User ID=springqa;Password=springqa"/>
<object id="adoTransactionManager"
type="Spring.Data.Core.AdoPlatformTransactionManager, Spring.Data">