Implementing the Warmup module

- Global.asax.cs looks for static pages in ~\App_Data\Warmup
- Orchard.Warmup module contains methods to generate those pages based on
scheduled times, and content publishing

--HG--
branch : dev
This commit is contained in:
Sebastien Ros
2011-03-17 11:06:23 -07:00
parent c4a2de09b6
commit 15dbaaf355
48 changed files with 1518 additions and 44 deletions

View File

@@ -169,6 +169,8 @@
<Compile Include="Users\ShellSettingsUtility.cs" />
<Compile Include="Values.cs" />
<Compile Include="Users\Services\MembershipServiceTests.cs" />
<Compile Include="Warmup\WebDownloaderTests.cs" />
<Compile Include="Warmup\WarmupUpdaterTests.cs" />
<Compile Include="Widgets\RuleEngine\UrlRuleProviderTest.cs" />
<Compile Include="Widgets\Services\WidgetsServiceTest.cs" />
<Compile Include="Widgets\WidgetsTests.cs" />
@@ -254,6 +256,10 @@
<Project>{79AED36E-ABD0-4747-93D3-8722B042454B}</Project>
<Name>Orchard.Users</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.WarmUp\Orchard.Warmup.csproj">
<Project>{9CD5C81F-5828-4384-8474-2E2BE71D5EDD}</Project>
<Name>Orchard.Warmup</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.Web\Modules\Orchard.Widgets\Orchard.Widgets.csproj">
<Project>{194D3CCC-1153-474D-8176-FDE8D7D0D0BD}</Project>
<Name>Orchard.Widgets</Name>

View File

@@ -0,0 +1,281 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Xml;
using Autofac;
using Moq;
using NUnit.Framework;
using Orchard.Environment.Warmup;
using Orchard.FileSystems.AppData;
using Orchard.FileSystems.LockFile;
using Orchard.Services;
using Orchard.Tests.FileSystems.AppData;
using Orchard.Tests.Stubs;
using Orchard.Tests.UI.Navigation;
using Orchard.Warmup.Models;
using Orchard.Warmup.Services;
namespace Orchard.Tests.Modules.Warmup {
public class WarmupUpdaterTests {
protected IContainer _container;
private IWarmupUpdater _warmupUpdater;
private IAppDataFolder _appDataFolder;
private ILockFileManager _lockFileManager;
private StubClock _clock;
private Mock<IWebDownloader> _webDownloader;
private IOrchardServices _orchardServices;
private WarmupSettingsPart _settings;
private readonly string _basePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
private string _warmupFilename, _lockFilename;
private const string WarmupFolder = "Warmup";
[TestFixtureTearDown]
public void Clean() {
if (Directory.Exists(_basePath)) {
Directory.Delete(_basePath, true);
}
}
[SetUp]
public void Init() {
if (Directory.Exists(_basePath)) {
Directory.Delete(_basePath, true);
}
Directory.CreateDirectory(_basePath);
_appDataFolder = AppDataFolderTests.CreateAppDataFolder(_basePath);
_webDownloader = new Mock<IWebDownloader>();
_orchardServices = new StubOrchardServices();
((StubWorkContextAccessor.WorkContextImpl.StubSite) _orchardServices.WorkContext.CurrentSite).BaseUrl = "http://orchardproject.net";
_settings = new WarmupSettingsPart { Record = new WarmupSettingsPartRecord() };
_orchardServices.WorkContext.CurrentSite.ContentItem.Weld(_settings);
var builder = new ContainerBuilder();
builder.RegisterInstance(_appDataFolder).As<IAppDataFolder>();
builder.RegisterInstance(_orchardServices).As<IOrchardServices>();
builder.RegisterType<DefaultLockFileManager>().As<ILockFileManager>();
builder.RegisterType<WarmupUpdater>().As<IWarmupUpdater>();
builder.RegisterType<StubClock>().As<IClock>();
builder.RegisterInstance(_clock = new StubClock()).As<IClock>();
builder.RegisterInstance(_webDownloader.Object).As<IWebDownloader>();
_container = builder.Build();
_lockFileManager = _container.Resolve<ILockFileManager>();
_warmupUpdater = _container.Resolve<IWarmupUpdater>();
_warmupFilename = _appDataFolder.Combine(WarmupFolder, "warmup.txt");
_lockFilename = _appDataFolder.Combine(WarmupFolder, "warmup.txt.lock");
}
[Test]
public void ShouldDoNothingWhenNoUrlsAreSpecified() {
_warmupUpdater.EnsureGenerate();
Assert.That(_appDataFolder.ListFiles(WarmupFolder).Count(), Is.EqualTo(0));
}
[Test]
public void StampFileShouldBeDeletedToForceAnUpdate() {
_appDataFolder.CreateFile(_warmupFilename, "");
_warmupUpdater.Generate();
Assert.That(_appDataFolder.ListFiles(WarmupFolder).Count(), Is.EqualTo(0));
}
[Test]
public void GenerateShouldNotRunIfLocked() {
_appDataFolder.CreateFile(_warmupFilename, "");
ILockFile lockFile = null;
_lockFileManager.TryAcquireLock(_lockFilename, ref lockFile);
using(lockFile) {
_warmupUpdater.Generate();
// warmup file + lock file
Assert.That(_appDataFolder.ListFiles(WarmupFolder).Count(), Is.EqualTo(2));
}
_warmupUpdater.Generate();
Assert.That(_appDataFolder.ListFiles(WarmupFolder).Count(), Is.EqualTo(0));
}
[Test]
public void ShouldDownloadConfiguredUrls() {
_settings.Urls = @" /
/About";
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/"))
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/About"))
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.OK });
_warmupUpdater.Generate();
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
// warmup + content files
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, "warmup.txt")));
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/"))));
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
var homepageContent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/")));
var aboutcontent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About")));
Assert.That(homepageContent, Is.EqualTo("Foo"));
Assert.That(aboutcontent, Is.EqualTo("Bar"));
}
[Test]
public void ShouldCreateFilesForOkStatusOnly() {
_settings.Urls = @" /
/About";
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/"))
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/About"))
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.NotFound });
_warmupUpdater.Generate();
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
// warmup + content file
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, "warmup.txt")));
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/"))));
Assert.That(files, Has.None.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
}
[Test]
public void ShouldProcessValidRequestsOnly() {
_settings.Urls = @" /
<>@\\";
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/"))
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
_warmupUpdater.Generate();
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
// warmup + content file
Assert.That(files.Count, Is.EqualTo(2));
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, "warmup.txt")));
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/"))));
}
[Test]
public void WarmupFileShouldContainUtcNow() {
_settings.Urls = @"/";
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/"))
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
_warmupUpdater.Generate();
var warmupContent = _appDataFolder.ReadFile(_warmupFilename);
Assert.That(warmupContent, Is.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
}
[Test]
public void ShouldNotProcessIfDelayHasNotExpired() {
_settings.Urls = @"/";
_settings.Delay = 90;
_settings.Scheduled = true;
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/"))
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/About"))
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.OK });
_warmupUpdater.Generate();
var warmupContent = _appDataFolder.ReadFile(_warmupFilename);
Assert.That(warmupContent, Is.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
_settings.Urls = @" /
/About";
_clock.Advance(TimeSpan.FromMinutes(89));
_warmupUpdater.EnsureGenerate();
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
Assert.That(files, Has.None.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
warmupContent = _appDataFolder.ReadFile(_warmupFilename);
Assert.That(warmupContent, Is.Not.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
}
[Test]
public void ShouldProcessIfDelayHasExpired() {
_settings.Urls = @"/";
_settings.Delay = 90;
_settings.Scheduled = true;
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/"))
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
_webDownloader
.Setup(w => w.Download("http://orchardproject.net/About"))
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.OK });
_warmupUpdater.Generate();
var warmupContent = _appDataFolder.ReadFile(_warmupFilename);
Assert.That(warmupContent, Is.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
_settings.Urls = @" /
/About";
_clock.Advance(TimeSpan.FromMinutes(91));
_warmupUpdater.EnsureGenerate();
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
warmupContent = _appDataFolder.ReadFile(_warmupFilename);
Assert.That(warmupContent, Is.EqualTo(XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)));
}
[Test]
public void ShouldGenerateNonWwwVersions() {
_settings.Urls = @" /
/About";
((StubWorkContextAccessor.WorkContextImpl.StubSite)_orchardServices.WorkContext.CurrentSite).BaseUrl = "http://www.orchardproject.net";
_webDownloader
.Setup(w => w.Download("http://www.orchardproject.net/"))
.Returns(new DownloadResult { Content = "Foo", StatusCode = HttpStatusCode.OK });
_webDownloader
.Setup(w => w.Download("http://www.orchardproject.net/About"))
.Returns(new DownloadResult { Content = "Bar", StatusCode = HttpStatusCode.OK });
_warmupUpdater.Generate();
var files = _appDataFolder.ListFiles(WarmupFolder).ToList();
// warmup + content files
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, "warmup.txt")));
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://www.orchardproject.net/"))));
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://www.orchardproject.net/About"))));
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/"))));
Assert.That(files, Has.Some.Matches<string>(x => x == _appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About"))));
var homepageContent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/")));
var aboutcontent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://orchardproject.net/About")));
var wwwhomepageContent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://www.orchardproject.net/")));
var wwwaboutcontent = _appDataFolder.ReadFile(_appDataFolder.Combine(WarmupFolder, WarmupUtility.EncodeUrl("http://www.orchardproject.net/About")));
Assert.That(homepageContent, Is.EqualTo("Foo"));
Assert.That(wwwhomepageContent, Is.EqualTo("Foo"));
Assert.That(aboutcontent, Is.EqualTo("Bar"));
Assert.That(wwwaboutcontent, Is.EqualTo("Bar"));
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Net;
using NUnit.Framework;
using Orchard.Warmup.Services;
namespace Orchard.Tests.Modules.Warmup {
public class WebDownloaderTests {
private readonly IWebDownloader _webDownloader = new WebDownloader();
[Test]
public void ShouldReturnNullWhenUrlIsEmpty() {
Assert.That(_webDownloader.Download(null), Is.Null);
Assert.That(_webDownloader.Download(""), Is.Null);
Assert.That(_webDownloader.Download(" "), Is.Null);
}
[Test]
public void ShouldReturnNullWhenUrlIsInvalid() {
Assert.That(_webDownloader.Download("froutfrout|yepyep"), Is.Null);
}
[Test]
public void StatusCodeShouldBe404ForUnexistingResources() {
var download = _webDownloader.Download("http://www.microsoft.com/yepyep");
Assert.That(download, Is.Not.Null);
Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
Assert.That(download.Content, Is.Null);
}
[Test]
public void StatusCodeShouldBe200ForValidRequests() {
var download = _webDownloader.Download("http://www.microsoft.com/");
Assert.That(download, Is.Not.Null);
Assert.That(download.StatusCode, Is.EqualTo(HttpStatusCode.OK));
Assert.That(download.Content, Is.Not.Empty);
}
}
}