Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 589704437f | |||
| a4077df5b7 | |||
| 46ef9146c4 | |||
| 3c75693e20 |
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.6.0
|
||||
alpha070
|
||||
alpha071
|
||||
|
||||
+1
-1
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.6.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha070")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha071")]
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "alpha070"; } }
|
||||
public static string CurrentComment { get { return "alpha071"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -270,12 +270,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
// once content has been set, "template on disk" are not "on disk" anymore
|
||||
template.Content = content;
|
||||
SetVirtualPath(template);
|
||||
|
||||
if (dto.Design == content) return;
|
||||
dto.Design = content;
|
||||
Database.Update(dto); // though... we don't care about the db value really??!!
|
||||
|
||||
SetVirtualPath(template);
|
||||
}
|
||||
|
||||
protected override void PersistDeletedItem(ITemplate entity)
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Tests.Logging;
|
||||
using Umbraco.Web.Scheduling;
|
||||
|
||||
namespace Umbraco.Tests.Scheduling
|
||||
{
|
||||
[TestFixture]
|
||||
[Timeout(60000)]
|
||||
public class BackgroundTaskRunnerTests2
|
||||
{
|
||||
// this tests was used to debug a background task runner issue that was unearthed by Deploy,
|
||||
// where work items would never complete under certain circumstances, due to threading issues.
|
||||
// (fixed now)
|
||||
//
|
||||
[Test]
|
||||
[Timeout(4000)]
|
||||
public async Task ThreadResumeIssue()
|
||||
{
|
||||
var logger = new ConsoleLogger();
|
||||
var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger);
|
||||
var work = new ThreadResumeIssueWorkItem();
|
||||
runner.Add(work);
|
||||
|
||||
Console.WriteLine("running");
|
||||
await Task.Delay(1000); // don't complete too soon
|
||||
|
||||
Console.WriteLine("completing");
|
||||
|
||||
// this never returned, never reached "completed" because the same thread
|
||||
// resumed executing the waiting on queue operation in the runner
|
||||
work.Complete();
|
||||
Console.WriteLine("completed");
|
||||
|
||||
Console.WriteLine("done");
|
||||
}
|
||||
|
||||
public class ThreadResumeIssueWorkItem : IBackgroundTask
|
||||
{
|
||||
private TaskCompletionSource<int> _completionSource;
|
||||
|
||||
public async Task RunAsync(CancellationToken token)
|
||||
{
|
||||
_completionSource = new TaskCompletionSource<int>();
|
||||
token.Register(() => _completionSource.TrySetCanceled()); // propagate
|
||||
Console.WriteLine("item running...");
|
||||
await _completionSource.Task.ConfigureAwait(false);
|
||||
Console.WriteLine("item returning");
|
||||
}
|
||||
|
||||
public bool Complete(bool success = true)
|
||||
{
|
||||
Console.WriteLine("item completing");
|
||||
// this never returned, see test
|
||||
_completionSource.SetResult(0);
|
||||
Console.WriteLine("item returning from completing");
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsAsync { get { return true; } }
|
||||
|
||||
public void Dispose()
|
||||
{}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("Only runs in the debugger.")]
|
||||
public async Task DebuggerInterferenceIssue()
|
||||
{
|
||||
var logger = new ConsoleLogger();
|
||||
var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger);
|
||||
var taskCompleted = false;
|
||||
runner.TaskCompleted += (sender, args) =>
|
||||
{
|
||||
Console.WriteLine("runner task completed");
|
||||
taskCompleted = true;
|
||||
};
|
||||
var work = new DebuggerInterferenceIssueWorkitem();
|
||||
|
||||
// add the workitem to the runner and wait until it is running
|
||||
runner.Add(work);
|
||||
work.Running.Wait();
|
||||
|
||||
// then wait a little bit more to ensure that the WhenAny has been entered
|
||||
await Task.Delay(500);
|
||||
|
||||
// then break
|
||||
// when the timeout triggers, we cannot handle it
|
||||
// taskCompleted value does *not* change & nothing happens
|
||||
Debugger.Break();
|
||||
|
||||
// release after 15s
|
||||
// WhenAny should return the timeout task
|
||||
// and then taskCompleted should turn to true
|
||||
// = debugging does not prevent task completion
|
||||
|
||||
Console.WriteLine("*");
|
||||
Assert.IsFalse(taskCompleted);
|
||||
await Task.Delay(1000);
|
||||
Console.WriteLine("*");
|
||||
Assert.IsTrue(taskCompleted);
|
||||
}
|
||||
|
||||
public class DebuggerInterferenceIssueWorkitem : IBackgroundTask
|
||||
{
|
||||
private readonly SemaphoreSlim _timeout = new SemaphoreSlim(0, 1);
|
||||
private readonly ManualResetEventSlim _running = new ManualResetEventSlim(false);
|
||||
|
||||
private Timer _timer;
|
||||
|
||||
public ManualResetEventSlim Running { get { return _running; } }
|
||||
|
||||
public async Task RunAsync(CancellationToken token)
|
||||
{
|
||||
// timeout timer
|
||||
_timer = new Timer(_ => { _timeout.Release(); });
|
||||
_timer.Change(1000, 0);
|
||||
|
||||
var timeout = _timeout.WaitAsync(token);
|
||||
var source = CancellationTokenSource.CreateLinkedTokenSource(token); // cancels when token cancels
|
||||
|
||||
_running.Set();
|
||||
var task = WorkExecuteAsync(source.Token);
|
||||
Console.WriteLine("execute");
|
||||
var anyTask = await Task.WhenAny(task, timeout).ConfigureAwait(false);
|
||||
|
||||
Console.Write("anyTask: ");
|
||||
Console.WriteLine(anyTask == timeout ? "timeout" : "task");
|
||||
|
||||
Console.WriteLine("return");
|
||||
}
|
||||
|
||||
private async Task WorkExecuteAsync(CancellationToken token)
|
||||
{
|
||||
await Task.Delay(30000);
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsAsync { get { return true; } }
|
||||
|
||||
public void Dispose()
|
||||
{ }
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("Only runs in the debugger.")]
|
||||
public void TimerDebuggerTest()
|
||||
{
|
||||
var triggered = false;
|
||||
var timer = new Timer(_ => { triggered = true; });
|
||||
timer.Change(1000, 0);
|
||||
Debugger.Break();
|
||||
|
||||
// pause in debugger for 10s
|
||||
// means the timer triggers while execution is suspended
|
||||
// 'triggered' remains false all along
|
||||
// then resume execution
|
||||
// and 'triggered' becomes true, so the trigger "catches up"
|
||||
// = debugging should not prevent triggered code from executing
|
||||
|
||||
Thread.Sleep(200);
|
||||
Assert.IsTrue(triggered);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Tests.Logging;
|
||||
using Umbraco.Web.Scheduling;
|
||||
|
||||
namespace Umbraco.Tests.Scheduling
|
||||
{
|
||||
// THIS REPRODUCES THE DEPLOY ISSUE IN CORE
|
||||
//
|
||||
// the exact same thing also reproduces in playground
|
||||
// so it's not a framework version issue - but something we're doing here
|
||||
|
||||
[TestFixture]
|
||||
[Timeout(4000)]
|
||||
public class Repro
|
||||
{
|
||||
[Test]
|
||||
public async Task ReproduceDeployIssue()
|
||||
{
|
||||
var logger = new ConsoleLogger();
|
||||
var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { KeepAlive = true, LongRunning = true }, logger);
|
||||
var work = new SimpleWorkItem();
|
||||
runner.Add(work);
|
||||
|
||||
Console.WriteLine("running");
|
||||
await Task.Delay(1000); // don't complete too soon
|
||||
|
||||
Console.WriteLine("completing");
|
||||
|
||||
// this never returns, never reached "completed" because the same thread
|
||||
// resumes executing the waiting on queue operation in the runner
|
||||
work.Complete();
|
||||
Console.WriteLine("completed");
|
||||
|
||||
Console.WriteLine("done");
|
||||
}
|
||||
|
||||
public class SimpleWorkItem : IBackgroundTask
|
||||
{
|
||||
private TaskCompletionSource<int> _completionSource;
|
||||
|
||||
public async Task RunAsync(CancellationToken token)
|
||||
{
|
||||
_completionSource = new TaskCompletionSource<int>();
|
||||
token.Register(() => _completionSource.TrySetCanceled()); // propagate
|
||||
Console.WriteLine("item running...");
|
||||
await _completionSource.Task.ConfigureAwait(false);
|
||||
Console.WriteLine("item returning");
|
||||
}
|
||||
|
||||
public bool Complete(bool success = true)
|
||||
{
|
||||
Console.WriteLine("item completing");
|
||||
// this never returns, see test
|
||||
_completionSource.SetResult(0);
|
||||
Console.WriteLine("item returning from completing");
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsAsync { get { return true; } }
|
||||
|
||||
public void Dispose()
|
||||
{}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,7 +169,7 @@
|
||||
<Compile Include="Persistence\PetaPocoExpressionsTests.cs" />
|
||||
<Compile Include="Persistence\Repositories\LockedRepositoryTests.cs" />
|
||||
<Compile Include="Persistence\Repositories\RedirectUrlRepositoryTests.cs" />
|
||||
<Compile Include="Scheduling\DeployTest.cs" />
|
||||
<Compile Include="Scheduling\BackgroundTaskRunnerTests2.cs" />
|
||||
<Compile Include="Routing\NiceUrlRoutesTests.cs" />
|
||||
<Compile Include="Scoping\EventNameExtractorTests.cs" />
|
||||
<Compile Include="Scoping\LeakTests.cs" />
|
||||
|
||||
Reference in New Issue
Block a user