У нас есть тесты с использованием WatiN, которые мы хотим запустить на нашем сервере CruiseControl.NET. У нас это работает с одной единственной сборкой. Когда мы включаем эти тесты в других сборках, они не выполняются одновременно. Мы не хотим помещать все сборки, выполняющие эти тесты, в одну и ту же очередь cc.net, потому что эти тесты - это лишь малая часть всего времени сборки. Мы также хотели бы избежать создания отдельных проектов сборки для этих тестов, потому что это буквально удвоило бы количество сборок в нашей настройке cc.net.
Какие у нас есть варианты?
- Есть ли способ поместить эти тесты в свою собственную задачу cc.net и поместить только эту задачу в очередь?
- Есть ли какая-либо задача msbuild / nant / ccnet или что-то еще, что обрабатывает очередь?
- Существует ли какой-либо инструмент командной строки, который мы можем запустить из нашего сценария msbuild, который обрабатывает очереди задач командной строки, чтобы мы могли запускать наши тесты с помощью вызовов командной строки nunit?
- Есть ли другие умные решения этой проблемы?
Если мы не найдем какого-либо существующего решения этой проблемы, мы, вероятно, что-то создадим сами, если да, какое решение будет рекомендовано?
EDIT :
Это была моя последняя реализация мьютекса:
public class SystemLevelLock : IDisposable
{
private readonly string _id;
private bool _isAquired;
private Mutex _mutex;
public SystemLevelLock(string id)
{
_id = id;
Aquire();
}
public SystemLevelLock() : this(GetApplicationId()) { }
private void Aquire()
{
try
{
var mutex = GetMutex();
_isAquired = mutex.WaitOne(TimeSpan.FromMinutes(1), false);
if (!_isAquired)
throw new Exception("System level mutex could not be aquired");
}
catch (AbandonedMutexException)
{
// Mutex was abandoned by another process (it probably crashed)
// Mutex was aquired by this process instead
}
}
private Mutex GetMutex() { return _mutex ?? (_mutex = MakeMutex()); }
private Mutex MakeMutex()
{
var mutexId = string.Format("Global\\{{{0}}}", _id);
var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
var mutex = new Mutex(false, mutexId);
mutex.SetAccessControl(securitySettings);
return mutex;
}
private void Release()
{
if (_isAquired)
_mutex.ReleaseMutex();
}
public void Dispose() { Release(); }
}
И это реализация класса Browser, использующая мьютекс. При этом также используется сценарий сценария SpecFlow для хранения экземпляра браузера и блокировки для этого сценария.
public static class Browser
{
public static IE Current
{
get
{
if (!IsStarted())
Start();
return ScenarioBrowser;
}
}
private static IE ScenarioBrowser
{
get
{
if (ScenarioContext.Current.ContainsKey("browser"))
return ScenarioContext.Current["browser"] as IE;
return null;
}
set
{
if (value == null)
{
if (ScenarioContext.Current.ContainsKey("browser"))
ScenarioContext.Current.Remove("browser");
}
else
ScenarioContext.Current["browser"] = value;
}
}
private static IDisposable BrowserLock
{
get
{
if (ScenarioContext.Current.ContainsKey("browserLock"))
return ScenarioContext.Current["browserLock"] as IDisposable;
return null;
}
set
{
if (value == null)
{
if (ScenarioContext.Current.ContainsKey("browserLock"))
ScenarioContext.Current.Remove("browserLock");
}
else
ScenarioContext.Current["browserLock"] = value;
}
}
private static void LockBrowser()
{
BrowserLock = MakeBrowserLock();
}
private static void ReleaseBrowser()
{
BrowserLock.Dispose();
BrowserLock = null;
}
private static SystemLevelLock MakeBrowserLock() { return new SystemLevelLock("WatiNBrowserLock"); }
private static void Start()
{
LockBrowser();
var browser = new IE();
ScenarioBrowser = browser;
}
public static bool IsStarted() { return ScenarioBrowser != null; }
public static void Close()
{
try
{
var browser = ScenarioBrowser;
ScenarioBrowser = null;
browser.Close();
browser.Dispose();
}
finally
{
ReleaseBrowser();
}
}
}