I get the impression that it's not. I have three integration tests that succeed when run individually, but when run in parallel, I get System.ArgumentException: An item with the same key has already been added.
I was sure hoping that ScenarioContext.Current always referred to the correct scenario, but it seems it's getting confused. Has anyone successfully added thread safety to this class? Or is there another approach I should be using for sharing values among step files?
ScenarioContext.Curent source:
public static ScenarioContext Current
{
get
{
if (current == null)
{
Debug.WriteLine("Accessing NULL ScenarioContext");
}
return current;
}
internal set { current = value; }
}
As you can see, it is not threadsafe
https://github.com/techtalk/SpecFlow/blob/master/Runtime/ScenarioContext.cs
This appears to be handled more nicely in SpecFlow V2: http://www.specflow.org/documentation/Parallel-Execution/
Extract (simpler of the options):
[Binding]
public class StepsWithScenarioContext : Steps
{
[Given(#"I put something into the context")]
public void GivenIPutSomethingIntoTheContext()
{
this.ScenarioContext.Set("test-value", "test-key");
}
}
I know this is a old post, but it's whell referenced, so this is my solution :
Just replace the ScenarioContext by a custom implementation like this :
public class ScenarioContextSafe
{
private static ScenarioContextSafe _current;
private static readonly object Locker = new object();
public static ScenarioContextSafe Current
{
get
{
lock (Locker) {
return _current ?? (_current = new ScenarioContextSafe());
}
}
}
public static void Reset()
{
lock (Locker) {
_current = null;
}
}
private readonly ConcurrentDictionary<string, object> _concurrentDictionary = new ConcurrentDictionary<string, object>();
public void Add(string key, object value)
{
_concurrentDictionary.TryAdd(key, value);
}
public void Set(object value, string key)
{
if (!_concurrentDictionary.ContainsKey(key))
_concurrentDictionary.TryAdd(key, value);
else
_concurrentDictionary[key] = value;
}
public void Remove(string key)
{
object result;
_concurrentDictionary.TryRemove(key, out result);
}
public T Get<T>(string key)
{
object result;
_concurrentDictionary.TryGetValue(key, out result);
return (T)result;
}
public bool ContainsKey(string key)
{
return _concurrentDictionary.ContainsKey(key);
}
public void Pending()
{
ScenarioContext.Current.Pending();
}
public ScenarioInfo ScenarioInfo{
get { return ScenarioContext.Current.ScenarioInfo; }
}
}
Then, create a hook for reset the context before each scenario
[BeforeScenario()]
public static void BeforeAllScenario()
{
ScenarioContextSafe.Reset();
}
I hope this help someone.
Related
I'm trying to pass the value from SceanrioContext to steps definitions in my tests with following way. I have Hooks class where _scenarioContext["lambda"] value is successfully retrieved and kept:
[Binding]
public class Hooks
{
private static IUnityContainer _container;
private static object locker = new object();
private static ThreadLocal<Lambda> _lambda = new ThreadLocal<Lambda>();
private static ScenarioContext _scenarioContext;
private static ScenarioContextSafe _scenarioContextSafe;
public Hooks(ScenarioContext scenarioContext, ScenarioContextSafe scenarioContextSafe)
{
_scenarioContext = scenarioContext;
_scenarioContextSafe = scenarioContextSafe;
}
[BeforeTestRun]
public static void ConfigurationSetUp()
{
Log.Info("Recreate S3 bucket");
AmazonS3Helper.RecreateBucketAsync().Wait();
Log.Info("Setup Configuration");
_container = new UnityContainer();
_objectContainer = new ObjectContainer();
_container.RegisterType<ISettings, TestSettings>(TypeLifetime.ContainerControlled);
_container.RegisterType<IAmazonServiceFactory, AmazonServiceFactory>(TypeLifetime.ContainerControlled);
_container.RegisterType<IPackageCollection, PackageCollection>(TypeLifetime.ContainerControlled);
_container.RegisterType<ILambdaCollection, LambdaCollection>(TypeLifetime.ContainerControlled);
_container.RegisterType<IStepFunctionCollection, StepFunctionCollection>(TypeLifetime.ContainerControlled);
_container.RegisterType<IS3BucketCollection, S3BucketCollection>(TypeLifetime.ContainerControlled);
_container.Resolve<ResoucesLoader>().Load();
}
[BeforeScenario]
public void DeployTransformStyleLambda()
{
var lambdasAll = _container.Resolve<ILambdaCollection>();
_scenarioContext["lambda"] = lambdasAll.FirstOrDefault(i => i.Name == TransformStyle);
lock (locker)
{
if (!((Lambda)_scenarioContext["lambda"]).Exists)
{
((Lambda) _scenarioContext["lambda"]).DeployAsync().Wait();
((Lambda) _scenarioContext["lambda"]).ReloadConfigurationAsync().Wait();
}
}
}
Then in MyTestsSteps1 class the value for ((Lambda) _scenarioContext["lambda"]) is successfully invoked but and in MyTestsSteps2 class I get the error message: The given key 'lambda' was not present in the dictionary when two tests are executed in parallel.
NOTE: Both tests are passing successfully running in single thread one by one though
[Binding]
public class MyTestsSteps1
{
private ScenarioContext _scenarioContext;
public MyTestsSteps1(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
}
[Given(#"test me")]
public void TestMe()
{
((Lambda) _scenarioContext["lambda"]).InvokeAsync(JsonSerializer.Serialize(request)).Wait();
}
And:
[Binding]
public class MyTestsSteps2
{
private ScenarioContext _scenarioContext;
public MyTestsSteps2(ScenarioContext scenarioContext)
{
_scenarioContext = scenarioContext;
}
[Given(#"again test me")]
public void TestMe()
{
((Lambda) _scenarioContext["lambda"]).InvokeAsync(JsonSerializer.Serialize(request)).Wait();
}
UPDATE: Added ScenarioContextSafe class with ConcurrentDictionary implementation
using System.Collections.Concurrent;
{
public class ScenarioContextSafe
{
private static ScenarioContextSafe _current;
private static readonly object Locker = new object();
public static ScenarioContextSafe Current
{
get
{
lock (Locker)
{
return _current ?? (_current = new ScenarioContextSafe());
}
}
}
public static void Reset()
{
lock (Locker)
{
_current = null;
}
}
private readonly ConcurrentDictionary<string, object> _concurrentDictionary =
new ConcurrentDictionary<string, object>();
public void Add(string key, object value)
{
_concurrentDictionary.TryAdd(key, value);
}
public void Set(object value, string key)
{
if (!_concurrentDictionary.ContainsKey(key))
_concurrentDictionary.TryAdd(key, value);
else
_concurrentDictionary[key] = value;
}
public void Remove(string key)
{
object result;
_concurrentDictionary.TryRemove(key, out result);
}
public T Get<T>(string key)
{
object result;
_concurrentDictionary.TryGetValue(key, out result);
return (T) result;
}
public bool ContainsKey(string key)
{
return _concurrentDictionary.ContainsKey(key);
}
}
}
Now BeforeScenario method in hooks looks like:
[BeforeScenario]
public void DeployTransformStyleLambda()
{
var lambdasAll = _container.Resolve<ILambdaCollection>();
_scenarioContextSafe.Add("lambda", lambdasAll.FirstOrDefault(i => i.Name == TransformStyle));
if (!_scenarioContextSafe.Get<Lambda>("lambda").Exists)
{
lock (locker)
{
_scenarioContextSafe.Get<Lambda>("lambda").DeployAsync().Wait();
_scenarioContextSafe.Get<Lambda>("lambda").ReloadConfigurationAsync().Wait();
}
}
}
Still while running tests in parallel and when I refer to _scenarioContextSafe.Get("lambda").InvokeAsync() in steps first test is passing but the second one fails with the error : System.NullReferenceException : Object reference not set to an instance of an object.
Finally I've got the reason why parallel test execution didn't work for me. That's so silly from my side...because of scenarioContext being STATIC!!!!! (line #4 and line #5 in Hooks class). It should not be static... that's it)) keep it as private readonly ScenarioContext _scenarioContext;
Example Code (I use Semaphore rather than lock to "lock" that bool member):
public class MsgSendHandler
{
private bool _isSocketSending = false;
private Semaphore _socketSendingSem = new Semaphore(1, 1);
public void Send(INetMsg msg)
{
// Add Msg To MsgQueue
TrySendNext();
}
private void SendCallback(IAsyncResult ar)
{
// Finish Send
_socketSendingSem.WaitOne();
_isSocketSending = false;
_socketSendingSem.Release();
TrySendNext();
}
private bool TrySendNext()
{
_socketSendingSem.WaitOne();
if (_isSocketSending)
return false;
_isSocketSending = true;
_socketSendingSem.Release();
// Socket Begin Send => SendCallback
return true;
}
}
Can I "lock" a value type like this? Is there any better solution?
Expanding on comment:
The way I created mutli-threaded functionality in Unity3D was to have a Dispatcher class that is called once per frame to run any Actions that have been added to a list.
Dispatcher.cs
A simple singleton class that holds the actions with an actual lock when looping through the actions.
public class Dispatcher
{
private static Dispatcher _instance;
public static Dispatcher Instance
{
get
{
if(_instance == null)
{
_instance = new Dispatcher();
}
return _instance;
}
}
private List<Action> _actions = new List<Action> ();
public void AddAction(Action action)
{
lock (_actions)
{
_actions.Add(action);
}
}
public void CompleteActions()
{
lock (_actions)
{
foreach (Action action in _actions)
{
action();
}
}
_actions.Clear();
}
public void ClearActions()
{
lock (_actions)
{
_actions.Clear();
}
}
}
DispatcherUpdate.cs
Another simple class that's added to a GameObject within the scene to call the Dispatcher to Complete the aquired Actions.
public class DispatcherUpdate : MonoBehaviour
{
private void Awake()
{
Dispatcher.Instance.ClearActions();
}
private void Update()
{
Dispatcher.Instance.CompleteActions();
}
}
Usage
Dispatcher.Instance.AddAction(() => TrySendNext());
This is the method I've used for Async multi-threading with SignalR
In my site, I call a third party API. To avoid hitting its rate limit, I need to define a global variable to enqueue requests. (I'm using RateLimiter any better solution?)
namespace MySite.App_Start
{
public static class Global
{
public static int MaxCount { get; set; } = 30;
public static TimeSpan Interval { get; set; } = TimeSpan.FromSeconds(1);
private static TimeLimiter rateLimiter;
public static TimeLimiter RateLimiter
{
get
{
if (rateLimiter == null)
rateLimiter = TimeLimiter.GetFromMaxCountByInterval(MaxCount, Interval);
return rateLimiter;
}
}
}
}
Then I'll use RateLimiter property. But I've read a lot that having a global variable is not a good idea. Considering my site has a lot of requests per second, is my code safe to use? Thanks.
Your code isn't 100% safe since it could create multiple instances of TimeLimiter in the beginning and depending on surrounding code, it could be a problem. I'm guessing it wouldn't be a big problem, but it's better to write the code properly to begin with.
This is something an IoC container handles nicely, but if you don't want to use one, you could use Lazy:
private static TimeLimiter rateLimiter = new Lazy(() =>
TimeLimiter.GetFromMaxCountByInterval(MaxCount, Interval));
public static TimeLimiter RateLimiter => rateLimiter.Value;
Maybe, you can make it thread-safe by using lock statement.
public static class Global
{
public static int MaxCount { get; set; } = 30;
public static TimeSpan Interval { get; set; } = TimeSpan.FromSeconds(1);
private static object _lockObject = new object();
private static TimeLimiter rateLimiter;
public static TimeLimiter RateLimiter
{
get
{
lock (_lockObject)
{
if (rateLimiter == null)
rateLimiter = TimeLimiter.GetFromMaxCountByInterval(MaxCount, Interval);
return rateLimiter;
}
}
}
}
Your code is not thread-safety.
Try this:
public class Singleton
{
protected Singleton() { }
private sealed class SingletonCreator
{
private static readonly Singleton instance = new Singleton();
public static Singleton Instance { get { return instance; } }
}
public static Singleton Instance
{
get { return SingletonCreator.Instance; }
}
}
Or use your favorite IoC-container with creating SingleInstance object
I have a list where it is entries can be updated, new data inserted or removed from 2 different threads.
Is it ok to use a public readonly object to lock when it is being used to interact to the other thread as to when it is locked or not or what would be the correct way to use this list across the 2 threads ?
You should always use a lock when accessing the list on different threads.
public class Sample
{
object synch = new object();
List<Something> list = new List<Something>();
void Add(Something something)
{
lock (synch) { list.Add(something); }
}
// Add the methods for update and delete.
}
You should wrap this in a class that handles the locking for you, or use a thread-safe collection, such as ConcurrentQueue<T> or one of the other collections in System.Collections.Concurrent.
Exposing the synchronization object to a public API is dangerous, and not a good practice.
First, read this article to understand why it's bad: http://blogs.msdn.com/b/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx
Then, do it anyway like I did:
public abstract class ConcurrentCollection<T> : ICollection<T>
{
private List<T> List { get; set; }
public ConcurrentCollection()
{
this.List = new List<T>();
}
public T this[int index]
{
get
{
return this.List[index];
}
}
protected virtual void AddUnsafe(T item)
{
this.List.Add(item);
}
protected virtual void RemoveUnsafe(T item)
{
this.List.Remove(item);
}
protected virtual void ClearUnsafe()
{
this.List.Clear();
}
public void Add(T item)
{
lock (this.List)
{
this.AddUnsafe(item);
}
}
public bool Remove(T item)
{
lock (this.List)
{
this.RemoveUnsafe(item);
return true;
}
}
public void Clear()
{
lock (this.List)
{
this.ClearUnsafe();
}
}
public int Count
{
get
{
lock (this.List)
{
return this.List.Count;
}
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public bool Contains(T item)
{
lock (this.List)
{
return this.List.Contains(item);
}
}
public void CopyTo(T[] array, int arrayIndex)
{
lock (this.List)
{
this.List.CopyTo(array, arrayIndex);
}
}
public IEnumerator<T> GetEnumerator()
{
return new ConcurrentEnumerator<T>(this.List, this.List);
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException("Abstract concurrent enumerators not implemented.");
}
}
public class ConcurrentEnumerator<T> : IEnumerator<T>
{
private int Position = -1;
private List<T> Duplicate;
private object Mutex;
private ICollection<T> NonConcurrentCollection;
internal ConcurrentEnumerator(ICollection<T> nonConcurrentCollection, object mutex)
{
this.NonConcurrentCollection = nonConcurrentCollection;
this.Mutex = mutex;
lock (this.Mutex)
{
this.Duplicate = new List<T>(this.NonConcurrentCollection);
}
}
public T Current
{
get
{
return this.Duplicate[this.Position];
}
}
object IEnumerator.Current
{
get
{
return this.Current;
}
}
public bool MoveNext()
{
this.Position++;
lock (this.Mutex)
{
while (this.Position < this.Duplicate.Count && !this.NonConcurrentCollection.Contains(this.Current))
{
this.Position++;
}
}
return this.Position < this.Duplicate.Count;
}
public void Reset()
{
this.Position = -1;
}
public void Dispose() { }
}
// Standards have List as derived Collection...
public class ConcurrentList<T> : ConcurrentCollection<T> { }
This code is still not fully safe, for instance the Count example may still crash, but it allows for iteration, adding and removing across threads. If you want to expose the mutex, do so, then lock around it for your other code constructs like count and contains.
But it's still a bad idea.
Edit: Example usage.
ConcurrentList<string> list = new ConcurrentList<string>();
list.Add("hello");
list.Add("world");
list.Add("foo");
list.Add("bar");
foreach (string word in list)
{
if (word == "world")
{
list.Remove("bar"); // Will not crash the foreach!
}
Console.WriteLine(word);
}
Output:
hello
world
foo
I am trying to get a custom enum class working which should enable me to create enums with user friendly identifiers and an arbitrary associated value. so far so good:
public class EnumBase<T, E>
where E : class
{
private static readonly List<E> list = new List<E>();
private string text;
private T value;
public string Text { get { return text; } }
public T Value { get { return value; } }
public EnumBase(string text, T value)
{
this.text = text;
this.value = value;
list.Add(this as E);
}
protected static IEnumerable<E> ItemList
{
get { return list; }
}
}
public class Zahlungsart : EnumBase<int, Zahlungsart>
{
public static readonly Zahlungsart Erlagsschein = new Zahlungsart("Erlagsschein", 0);
public static readonly Zahlungsart Lastschrift = new Zahlungsart("Lastschrift", 1);
private Zahlungsart(string text, int value) : base(text, value) { }
public static new IEnumerable<Zahlungsart> ItemList { get { return EnumBase<int, Zahlungsart>.ItemList; } }
}
And now my problem:
Console.WriteLine(Zahlungsart.ItemList.Count());
The following statement gives me 0, instead of 2. The problem is due to beforefieldinit, I think. I could work around this by calling some method of the specific enum directly which would force the static fields to load, but this is not the best solution, I think.
Hint: please do not propose some kind of [UserfriendlyName()]-attribute for enum here, I already know them.
EDIT
Thanks, hans. I had indeed a typo in my own code, calling the wrong generic specialisation.
Now my question is, can I get rid of the redefinition of ItemList in each subclass, but it seems this is necessary to to get the static fields initialized.
How about using "static constructor" ??
public class Zahlungsart : EnumBase<int, Zahlungsart>
{
public static readonly Zahlungsart Erlagsschein;
public static readonly Zahlungsart Lastschrift;
static Zahlungsart()
{
Erlagsschein = new Zahlungsart("Erlagsschein", 0);
Lastschrift = new Zahlungsart("Lastschrift", 1);
}
private Zahlungsart(string text, int value) : base(text, value) { }
public static new IEnumerable<Zahlungsart> ItemList { get { return EnumBase<int, Zahlungsart>.ItemList; } }
}
Your code doesn't repro the problem. But you will get a repro if you change the property like this:
public new static IEnumerable<Zahlungsart> ItemList {
get { return EnumBase<uint, Zahlungsart>.ItemList; } // Note: uint instead of int
}
Beware that every concrete class generated from a generic type will have its own static fields, they are not shared.