#region License
/*
* Copyright 2002-2004 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
using System;
using System.Reflection;
using System.Threading;
using log4net;
using NUnit.Framework;
using Spring.Threading;
namespace Spring.Services.WindowsService.Common{
class StoppingHelper
{
private readonly ServiceSupport serviceSupport;
private readonly ISync stopping;
private readonly ISync stopped;
public bool wasStopped = false;
public StoppingHelper (ServiceSupport serviceSupport, ISync stopping, ISync stopped)
{
this.stopping = stopping;
this.stopped = stopped;
this.serviceSupport = serviceSupport;
}
public void Stop ()
{
ServiceSupportTest.Log ("stopping ...");
stopping.Release();
ServiceSupportTest.Log ("stopping sync released ...");
serviceSupport.Stop(true);
wasStopped = true;
ServiceSupportTest.Log ("releasing stopped sync ...");
stopped.Release();
ServiceSupportTest.Log ("stopped ...");
}
}
class BlockWhileStartingExecutor : IExecutor
{
private readonly ISync started;
private readonly ISync starting;
MyServiceSupport serviceSupport;
public bool wasStarted = false;
public BlockWhileStartingExecutor (ISync starting, ISync started)
{
this.starting = starting;
this.started = started;
}
public MyServiceSupport ServiceSupport
{
get { return serviceSupport; }
set { serviceSupport = value; }
}
public void Start ()
{
serviceSupport.Start(true);
}
public void Execute (IRunnable runnable)
{
if (runnable == serviceSupport.StartedCommand)
{
ServiceSupportTest.Log ("waiting to start ...");
starting.Acquire();
ServiceSupportTest.Log ("starting ...");
runnable.Run();
wasStarted = true;
ServiceSupportTest.Log ("releasing started sync ...");
started.Release();
ServiceSupportTest.Log ("started ...");
}
else
{
ServiceSupportTest.Log ("unexpected runnable: " + runnable);
runnable.Run();
}
}
}
class MyServiceSupport : ServiceSupport
{
public MyServiceSupport(IExecutor executor, IServiceable serviceable) : base(executor, serviceable)
{
}
public IRunnable StartedCommand
{
get
{
return base.startedCommand;
}
}
}
class MyService : ServiceSupport.IServiceable
{
ISync _sync1;
ISync _sync2;
public MyService (ISync sync1, ISync sync2)
{
this._sync1 = sync1;
this._sync2 = sync2;
}
public void PerformStart ()
{
}
public void PerformStop ()
{
}
public void Dispose ()
{
lock (this)
{
_sync1.Release();
_sync2.Acquire();
}
}
}
[TestFixture]
public class ServiceSupportTest
{
MyService serviceable;
ServiceSupport serviceSupport;
ISync sync1;
ISync sync2;
static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
[SetUp]
public void SetUp ()
{
sync1 = new Semaphore(0);
sync2 = new Semaphore(0);
serviceable = new MyService(sync1, sync2);
serviceSupport = new ServiceSupport(serviceable);
}
[Test(Description="Bugfix")]
public void DoesNotLockTheServiceableWhenQueryingForStatus()
{
new Thread(new ThreadStart(serviceable.Dispose)).Start();
sync1.Acquire();
Assert.IsFalse(serviceSupport.StopRequested);
sync2.Release();
}
[Test]
public void WaitForStartedBeforeStopping()
{
MyService serviceable = new MyService(sync1, sync2);
ISync starting = new Latch();
ISync started = new Latch();
BlockWhileStartingExecutor executor =
new BlockWhileStartingExecutor(starting, started);
MyServiceSupport support = new MyServiceSupport(executor, serviceable);
executor.ServiceSupport = support;
Thread startThread = new Thread(new ThreadStart(executor.Start));
startThread.Name = "start";
startThread.Start();
Log ("start thread started");
Latch stopping = new Latch();
Latch stopped = new Latch();
StoppingHelper helper = new StoppingHelper(support, stopping, stopped);
Thread stopThread = new Thread(new ThreadStart(helper.Stop));
stopThread.Name = "stop";
stopThread.Start();
Log ("stop thread started: waiting for stopping ...");
stopping.Acquire();
Log ("stopping in progress ...");
Assert.IsFalse(executor.wasStarted);
Assert.IsFalse(helper.wasStopped, "helper could stop before expected");
Log ("allow to start ...");
starting.Release();
Log ("waiting for started ...");
started.Acquire();
Assert.IsTrue(executor.wasStarted);
stopped.Acquire();
Log ("waiting for stop ...");
Assert.IsTrue(helper.wasStopped);
Log ("stopped ...");
}
public static void Log (string msg)
{
Thread currentThread = Thread.CurrentThread;
string message = String.Format("thread [#{1}-{2}], msg = {0}", msg, currentThread.GetHashCode(), currentThread.Name);
log.Debug(message);
Console.Out.WriteLine (message);
}
}
}
|