using System;
using System.Collections.Generic;
using System.Text;
using OpenLiveWriter.Extensibility.BlogClient;
using BlogRunner.Core.Config;
using System.Xml;
using System.Threading;
using System.Net;
using System.Text.RegularExpressions;
namespace BlogRunner.Core
{
public abstract class Test
{
protected const string YES = "Yes";
protected const string NO = "No";
const string NAMESPACE_BLOGRUNNER = "http://writer.live.com/blogrunner/2007";
public abstract void DoTest(Blog blog, IBlogClient blogClient, ITestResults results);
public virtual void DoTest(Blog blog, IBlogClient blogClient, XmlElement providerEl)
{
TestResultImpl results = new TestResultImpl();
DoTest(blog, blogClient, results);
results.ForEach(delegate(string key, string value) {
XmlElement optionsEl = (XmlElement) providerEl.SelectSingleNode("options");
if (optionsEl == null)
{
optionsEl = providerEl.OwnerDocument.CreateElement("options");
providerEl.AppendChild(optionsEl);
}
XmlElement el = (XmlElement) optionsEl.SelectSingleNode(key);
if (el == null)
{
el = providerEl.OwnerDocument.CreateElement(key);
optionsEl.AppendChild(el);
}
if (!el.HasAttribute("readonly", NAMESPACE_BLOGRUNNER))
{
el.InnerText = value;
}
});
}
static Test()
{
CleanUpPosts = true;
}
///
/// Retries action until either it returns true or the timeout time elapses.
///
protected static void RetryUntilTimeout(TimeSpan timeout, TimeoutAction action)
{
DateTime due = DateTime.UtcNow + timeout;
do
{
if (action())
return;
}
while (DateTime.UtcNow < due);
throw new TimeoutException("The operation has timed out");
}
protected delegate bool TimeoutAction();
protected static bool CleanUpPosts { get; set; }
}
public abstract class PostTest : Test
{
protected internal abstract void PreparePost(BlogPost blogPost, ref bool? publish);
protected internal abstract void HandleResult(string homepageHtml, ITestResults results);
///
/// Return true if the timeout condition was handled. False means
/// the caller should deal with the timeout (by throwing TimeoutException).
///
protected internal virtual bool HandleTimeout(TimeoutException te, ITestResults results)
{
return false;
}
protected virtual TimeSpan TimeoutDuration
{
get { return TimeSpan.FromMinutes(2.0); }
}
public sealed override void DoTest(Blog blog, IBlogClient blogClient, ITestResults results)
{
BlogPost blogPost = new BlogPost();
bool? publish = null;
PreparePost(blogPost, ref publish);
string token = BlogUtil.ShortGuid;
blogPost.Title = token + ":" + blogPost.Title;
string etag;
XmlDocument remotePost;
string postId = blogClient.NewPost(blog.BlogId, blogPost, null, publish ?? true, out etag, out remotePost);
using (WebClient webClient = new WebClient())
{
try
{
RetryUntilTimeout(TimeoutDuration, delegate {
string html = Encoding.ASCII.GetString(webClient.DownloadData(blog.HomepageUrl));
if (html.Contains(token))
{
HandleResult(html, results);
return true;
}
Thread.Sleep(1000);
return false;
});
}
catch (TimeoutException te)
{
if (!HandleTimeout(te, results))
throw;
}
}
if (postId != null && CleanUpPosts)
blogClient.DeletePost(blog.BlogId, postId, false);
}
}
public abstract class BodyContentPostTest : PostTest
{
public abstract string BodyContentString { get; }
public abstract void HandleContentResult(string result, ITestResults results);
private string guid1, guid2;
protected internal sealed override void PreparePost(BlogPost blogPost, ref bool? publish)
{
guid1 = BlogUtil.ShortGuid;
guid2 = BlogUtil.ShortGuid;
blogPost.Contents += "\r\n
\r\n" + guid1 + BodyContentString + guid2;
}
protected internal sealed override void HandleResult(string homepageHtml, ITestResults results)
{
Regex regex = new Regex(Regex.Escape(guid1) + "(.*?)" + Regex.Escape(guid2));
Match m = regex.Match(homepageHtml);
string result;
if (!m.Success)
result = null;
else
result = m.Groups[1].Value;
HandleContentResult(result, results);
}
}
public abstract class RoundtripTest : Test
{
protected internal abstract void PreparePost(Blog blog, IBlogClient blogClient, BlogPost blogPost, ref bool? publish);
protected internal abstract void HandleResult(BlogPost blogPost, ITestResults results);
public sealed override void DoTest(Blog blog, IBlogClient blogClient, ITestResults results)
{
BlogPost blogPost = new BlogPost();
bool? publish = null;
PreparePost(blog, blogClient, blogPost, ref publish);
string token = BlogUtil.ShortGuid;
blogPost.Title = token + ":" + blogPost.Title;
string etag;
XmlDocument remotePost;
string postId = blogClient.NewPost(blog.BlogId, blogPost, null, publish ?? true, out etag, out remotePost);
BlogPost newPost = blogClient.GetPost(blog.BlogId, postId);
HandleResult(newPost, results);
if (postId != null && CleanUpPosts)
blogClient.DeletePost(blog.BlogId, postId, false);
}
}
}