From d3b35f262e0e419302f60c0ff97b51dd65f54768 Mon Sep 17 00:00:00 2001 From: DecaTec Date: Thu, 13 Apr 2017 15:37:06 +0200 Subject: [PATCH] Changed version to 0.8.0.0; bugfixes; Translate header 'f' is defined as default request header (IIS issue); unit tests --- DecaTec.WebDav/AbsoluteUri.cs | 10 +- DecaTec.WebDav/CodedUrl.cs | 5 +- DecaTec.WebDav/DecaTec.WebDav.csproj | 4 +- DecaTec.WebDav/HttpHeaderNames.cs | 5 + DecaTec.WebDav/HttpTranslateHeaderValues.cs | 14 + DecaTec.WebDav/LockToken.cs | 6 +- DecaTec.WebDav/NoTagList.cs | 5 +- DecaTec.WebDav/WebDavClient.cs | 14 +- DecaTec.WebDav/WebDavSession.cs | 57 ++- .../{v0.7.1.0.aml => v0.8.0.0.aml} | 30 +- .../ContentLayout.content | 4 +- .../DecaTec.WebDav.Documentation.shfbproj | 2 +- .../DecaTec.WebDav.UnitIntegrationTest.csproj | 3 + .../TestFile1.01 | 1 + .../UnitIntegrationTestWebDavClient.cs | 119 +++-- .../UnitIntegrationTestWebDavSession.cs | 78 ++- .../UnitTestLockToken.cs | 26 +- .../UnitTestWebDavClient.cs | 264 +++++++---- .../UnitTestWebDavSession.cs | 446 ++++++++++++++++++ 19 files changed, 894 insertions(+), 199 deletions(-) create mode 100644 DecaTec.WebDav/HttpTranslateHeaderValues.cs rename Documentation/DecaTec.WebDav.Documentation/Content/VersionHistory/{v0.7.1.0.aml => v0.8.0.0.aml} (54%) create mode 100644 UnitTests/DecaTec.WebDav.UnitIntegrationTest/TestFile1.01 create mode 100644 UnitTests/DecaTec.WebDav.UnitTest/UnitTestWebDavSession.cs diff --git a/DecaTec.WebDav/AbsoluteUri.cs b/DecaTec.WebDav/AbsoluteUri.cs index 23f80c5..61e4ef8 100644 --- a/DecaTec.WebDav/AbsoluteUri.cs +++ b/DecaTec.WebDav/AbsoluteUri.cs @@ -16,7 +16,7 @@ public class AbsoluteUri /// Constructs an . /// /// The URL to use. - /// Thrown when is null. + /// Thrown when is null. public AbsoluteUri(string absoluteUrl) { if (!Uri.TryCreate(absoluteUrl, UriKind.Absolute, out Uri absoluteUri)) @@ -38,9 +38,11 @@ public AbsoluteUri(Uri absoluteUri) this.absoluteUri = absoluteUri; } - /// - public override string ToString() => - absoluteUri.ToString(); + /// + /// Gets the string representation of this AbsoluteUri. + /// + /// The string representation of this AbsoluteUri. + public override string ToString() => absoluteUri.ToString(); /// /// Tries to parse the given into an . diff --git a/DecaTec.WebDav/CodedUrl.cs b/DecaTec.WebDav/CodedUrl.cs index 90a5006..1b53868 100644 --- a/DecaTec.WebDav/CodedUrl.cs +++ b/DecaTec.WebDav/CodedUrl.cs @@ -46,7 +46,10 @@ public CodedUrl(AbsoluteUri absoluteUri) AbsoluteUri = absoluteUri ?? throw new ArgumentNullException(nameof(absoluteUri)); } - /// + /// + /// Gets the string representation of this CodedUrl. + /// + /// The string representation of this CodedUrl. public override string ToString() => $"{CodedUrlPrefix}{AbsoluteUri}{CodedUrlPostfix}"; /// diff --git a/DecaTec.WebDav/DecaTec.WebDav.csproj b/DecaTec.WebDav/DecaTec.WebDav.csproj index 4f25248..d225ebe 100644 --- a/DecaTec.WebDav/DecaTec.WebDav.csproj +++ b/DecaTec.WebDav/DecaTec.WebDav.csproj @@ -3,7 +3,7 @@ netstandard1.1 PortableWebDavLibrary - 0.7.1.0-beta3 + 0.8.0.0-beta1 DecaTec DecaTec PortableWebDavLibrary @@ -15,7 +15,7 @@ https://github.com/DecaTec/Portable-WebDAV-Library WebDAV, portable, NETStandard, NETCore, UWP, dotnet, portable-webdav-library, Xamarin, Mono, multiplatform True - + Full documentation is available at https://decatec.de/ext/PortableWebDAVLibrary/Doc diff --git a/DecaTec.WebDav/HttpHeaderNames.cs b/DecaTec.WebDav/HttpHeaderNames.cs index 2440dd9..d7cf477 100644 --- a/DecaTec.WebDav/HttpHeaderNames.cs +++ b/DecaTec.WebDav/HttpHeaderNames.cs @@ -15,5 +15,10 @@ public static class HttpHeaderNames /// Header name for 'Content-Length'. /// public const string ContentLength = "Content-Length"; + + /// + /// Header name for 'Translate'. + /// + public const string Translate = "Translate"; } } diff --git a/DecaTec.WebDav/HttpTranslateHeaderValues.cs b/DecaTec.WebDav/HttpTranslateHeaderValues.cs new file mode 100644 index 0000000..5544285 --- /dev/null +++ b/DecaTec.WebDav/HttpTranslateHeaderValues.cs @@ -0,0 +1,14 @@ + +namespace DecaTec.WebDav +{ + /// + /// Class defining the values for the HTTP Translate header. + /// + public static class HttpTranslateHeaderValues + { + /// + /// Constant for Translate header when the server should return a file uninterpreted ('f'). + /// + public const string TranslateF = "f"; + } +} diff --git a/DecaTec.WebDav/LockToken.cs b/DecaTec.WebDav/LockToken.cs index c1629fd..c9e248e 100644 --- a/DecaTec.WebDav/LockToken.cs +++ b/DecaTec.WebDav/LockToken.cs @@ -9,9 +9,9 @@ namespace DecaTec.WebDav public class LockToken { /// - /// Constructs a based on the . + /// Constructs a based on the . /// - /// The lock token in absolute-URI format as defined in https://tools.ietf.org/html/rfc3986#section-4.3. + /// The lock token as string. /// Use the strong-typed constructors to create a new . public LockToken(string lockToken) { @@ -37,7 +37,7 @@ public LockToken(string lockToken) /// /// Constructs a based on the . /// - /// The lock token in absolute-URI format as defined in https://tools.ietf.org/html/rfc3986#section-4.3. + /// The lock token in absolute-URI format as defined in https://tools.ietf.org/html/rfc3986#section-4.3. /// Use the strong-typed constructors to create a new . /// Thrown when is null. public LockToken(AbsoluteUri absoluteUri) diff --git a/DecaTec.WebDav/NoTagList.cs b/DecaTec.WebDav/NoTagList.cs index 30e3fec..5adaf75 100644 --- a/DecaTec.WebDav/NoTagList.cs +++ b/DecaTec.WebDav/NoTagList.cs @@ -47,7 +47,10 @@ public NoTagList(CodedUrl codedUrl) CodedUrl = codedUrl ?? throw new ArgumentNullException(nameof(codedUrl)); } - /// + /// + /// Gets the string representation of this NoTagList. + /// + /// The string representation of this NoTagList. public override string ToString() => $"{NoTagListPrefix}{CodedUrl}{NoTagListPostfix}"; /// diff --git a/DecaTec.WebDav/WebDavClient.cs b/DecaTec.WebDav/WebDavClient.cs index 959695d..1fe3f30 100644 --- a/DecaTec.WebDav/WebDavClient.cs +++ b/DecaTec.WebDav/WebDavClient.cs @@ -118,7 +118,7 @@ public class WebDavClient : HttpClient public WebDavClient() : base() { - + SetDefaultRequestHeaders(); } /// @@ -128,7 +128,7 @@ public WebDavClient() public WebDavClient(HttpMessageHandler httpMessageHandler) : base(httpMessageHandler) { - + SetDefaultRequestHeaders(); } /// @@ -139,7 +139,17 @@ public WebDavClient(HttpMessageHandler httpMessageHandler) public WebDavClient(HttpMessageHandler httpMessageHandler, bool disposeHandler) : base(httpMessageHandler, disposeHandler) { + SetDefaultRequestHeaders(); + } + private void SetDefaultRequestHeaders() + { + // This is a workaround when the lib is used for WebDAV/IIS: + // When there is a GET request for a file with unmapped extension on IIS (e.g. 'file.01'), the IIS returns 404 ('not found'). + // This is due to the server trying to interpret any requested files (which makes sense for ASP, etc.). + // In order that the IIS serves files with unmapped extensions, the "Translate" header has to be set to 'f'. + // See: https://msdn.microsoft.com/en-us/library/cc250063.aspx + this.DefaultRequestHeaders.Add(HttpHeaderNames.Translate, HttpTranslateHeaderValues.TranslateF); } #endregion Constructor diff --git a/DecaTec.WebDav/WebDavSession.cs b/DecaTec.WebDav/WebDavSession.cs index 883f545..029d928 100644 --- a/DecaTec.WebDav/WebDavSession.cs +++ b/DecaTec.WebDav/WebDavSession.cs @@ -145,6 +145,21 @@ public Uri BaseUri set; } + /// + /// Gets or sets the BaseUri of this WebDavSession by a URL string. + /// + public string BaseUrl + { + get + { + return this.BaseUri == null ? string.Empty : this.BaseUri.ToString(); + } + set + { + this.BaseUri = new Uri(value); + } + } + /// /// Gets or sets the to use with this WebDavSession. /// @@ -203,8 +218,8 @@ public async Task CopyAsync(string sourceUrl, string destinationUrl, bool /// The representing the asynchronous operation. public async Task CopyAsync(Uri sourceUri, Uri destinationUri, bool overwrite) { - sourceUri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, sourceUri, true, false); - destinationUri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, destinationUri, true, false); + sourceUri = UriHelper.CombineUri(this.BaseUri, sourceUri, true); + destinationUri = UriHelper.CombineUri(this.BaseUri, destinationUri, true); var lockToken = GetAffectedLockToken(destinationUri); var response = await this.webDavClient.CopyAsync(sourceUri, destinationUri, overwrite, WebDavDepthHeaderValue.Infinity, lockToken); return response.IsSuccessStatusCode; @@ -231,7 +246,7 @@ public async Task CreateDirectoryAsync(string url) /// The representing the asynchronous operation. public async Task CreateDirectoryAsync(Uri uri) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); var lockToken = GetAffectedLockToken(uri); var response = await this.webDavClient.MkcolAsync(uri, lockToken); return response.IsSuccessStatusCode; @@ -258,7 +273,7 @@ public async Task DeleteAsync(string url) /// The representing the asynchronous operation. public async Task DeleteAsync(Uri uri) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); var lockToken = GetAffectedLockToken(uri); var response = await this.webDavClient.DeleteAsync(uri, lockToken); return response.IsSuccessStatusCode; @@ -311,7 +326,7 @@ public async Task DownloadFileAsync(string url, Stream localStream, Cancel /// The representing the asynchronous operation. public async Task DownloadFileAsync(Uri uri, Stream localStream, CancellationToken ct) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); var response = await this.webDavClient.GetAsync(uri, ct); if (response.Content != null) @@ -378,7 +393,7 @@ public async Task DownloadFileWithProgressAsync(Uri uri, Stream localStrea /// The representing the asynchronous operation. public async Task DownloadFileWithProgressAsync(Uri uri, Stream localStream, IProgress progress, CancellationToken cancellationToken) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); var response = await this.webDavClient.DownloadFileWithProgressAsync(uri, localStream, cancellationToken, progress); return response.IsSuccessStatusCode; } @@ -404,7 +419,7 @@ public async Task ExistsAsync(string url) /// The representing the asynchronous operation. public async Task ExistsAsync(Uri uri) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); var response = await this.webDavClient.HeadAsync(uri); return response.IsSuccessStatusCode; } @@ -459,14 +474,14 @@ public async Task> ListAsync(Uri uri, PropFind prop if (propFind == null) throw new ArgumentException("Argument propFind must not be null."); - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); var response = await this.webDavClient.PropFindAsync(uri, WebDavDepthHeaderValue.One, propFind); // Remember the original port to include it in the hrefs later. var port = UriHelper.GetPort(uri); if (response.StatusCode != WebDavStatusCode.MultiStatus) - throw new WebDavException(string.Format("Error while executing ListAsync (wrong response status code). Expected status code: 207 (MultiStatus); actual status code: {0} ({1})", (int)response.StatusCode, response.StatusCode)); + throw new WebDavException($"Error while executing ListAsync (wrong response status code). Expected status code: 207 (MultiStatus); actual status code: {(int)response.StatusCode} ({response.StatusCode})"); var multistatus = await WebDavResponseContentParser.ParseMultistatusResponseContentAsync(response.Content); @@ -591,7 +606,7 @@ public async Task LockAsync(string url) /// The representing the asynchronous operation. public async Task LockAsync(Uri uri) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); if (this.permanentLocks.ContainsKey(uri)) return true; // Lock already set. @@ -607,21 +622,23 @@ public async Task LockAsync(Uri uri) if (!response.IsSuccessStatusCode) return false; // Lock already exists. + // Save the content stream as string as it will be consumed while getting the lock token. + var responseContentString = await response.Content.ReadAsStringAsync(); var lockToken = WebDavHelper.GetLockTokenFromWebDavResponseMessage(response); - var prop = await WebDavResponseContentParser.ParsePropResponseContentAsync(response.Content); + var prop = WebDavResponseContentParser.ParsePropResponseContentString(responseContentString); var lockDiscovery = prop.LockDiscovery; if (lockDiscovery == null) return false; var url = uri.ToString(); - var lockGranted = lockDiscovery.ActiveLock.FirstOrDefault(x => url.EndsWith(UriHelper.AddTrailingSlash(x.LockRoot.Href, false), StringComparison.OrdinalIgnoreCase)); + var lockGranted = lockDiscovery.ActiveLock.FirstOrDefault(x => UriHelper.AddTrailingSlash(url, false).EndsWith(UriHelper.AddTrailingSlash(x.LockRoot.Href, false), StringComparison.OrdinalIgnoreCase)); if (lockGranted == null) { // Try with file expected. - lockGranted = lockDiscovery.ActiveLock.FirstOrDefault(x => url.EndsWith(UriHelper.AddTrailingSlash(x.LockRoot.Href, true), StringComparison.OrdinalIgnoreCase)); + lockGranted = lockDiscovery.ActiveLock.FirstOrDefault(x => UriHelper.AddTrailingSlash(url, true).EndsWith(UriHelper.AddTrailingSlash(x.LockRoot.Href, true), StringComparison.OrdinalIgnoreCase)); } if (lockGranted == null) @@ -682,8 +699,8 @@ public async Task MoveAsync(string sourceUrl, string destinationUrl, bool /// The representing the asynchronous operation. public async Task MoveAsync(Uri sourceUri, Uri destinationUri, bool overwrite) { - sourceUri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, sourceUri, true, false); - destinationUri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, destinationUri, true, false); + sourceUri = UriHelper.CombineUri(this.BaseUri, sourceUri, true); + destinationUri = UriHelper.CombineUri(this.BaseUri, destinationUri, true); var lockTokenSource = GetAffectedLockToken(sourceUri); var lockTokenDestination = GetAffectedLockToken(destinationUri); var response = await this.webDavClient.MoveAsync(sourceUri, destinationUri, overwrite, lockTokenSource, lockTokenDestination); @@ -713,7 +730,7 @@ public async Task UploadFileAsync(string url, Stream localStream) /// The representing the asynchronous operation. public async Task UploadFileAsync(Uri uri, Stream localStream) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); var lockToken = GetAffectedLockToken(uri); var content = new StreamContent(localStream); var response = await this.webDavClient.PutAsync(uri, content, lockToken); @@ -744,7 +761,7 @@ public async Task UploadFileWithProgressAsync(string url, Stream stream, s /// The representing the asynchronous operation. public async Task UploadFileWithProgressAsync(string url, Stream stream, string contentType, IProgress progress, CancellationToken cancellationToken) { - return await UploadFileWithProgressAsync(url, stream, contentType, progress, cancellationToken); + return await UploadFileWithProgressAsync(UriHelper.CreateUriFromUrl(url), stream, contentType, progress, cancellationToken); } /// @@ -771,7 +788,7 @@ public async Task UploadFileWithProgressAsync(Uri uri, Stream stream, stri /// The representing the asynchronous operation. public async Task UploadFileWithProgressAsync(Uri uri, Stream stream, string contentType, IProgress progress, CancellationToken cancellationToken) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); var lockToken = GetAffectedLockToken(uri); var response = await this.webDavClient.UploadFileWithProgressAsync(uri, stream, contentType, progress, cancellationToken, lockToken); return response.IsSuccessStatusCode; @@ -798,7 +815,7 @@ public async Task UnlockAsync(string url) /// The representing the asynchronous operation. public async Task UnlockAsync(Uri uri) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); if (!this.permanentLocks.TryRemove(uri, out PermanentLock permanentLock)) return false; @@ -829,7 +846,7 @@ private static WebDavClient CreateWebDavClient(HttpMessageHandler messageHandler private LockToken GetAffectedLockToken(Uri uri) { - uri = UriHelper.GetCombinedUriWithTrailingSlash(this.BaseUri, uri, true, false); + uri = UriHelper.CombineUri(this.BaseUri, uri, true); foreach (var lockItem in this.permanentLocks) { diff --git a/Documentation/DecaTec.WebDav.Documentation/Content/VersionHistory/v0.7.1.0.aml b/Documentation/DecaTec.WebDav.Documentation/Content/VersionHistory/v0.8.0.0.aml similarity index 54% rename from Documentation/DecaTec.WebDav.Documentation/Content/VersionHistory/v0.7.1.0.aml rename to Documentation/DecaTec.WebDav.Documentation/Content/VersionHistory/v0.8.0.0.aml index 0ea324e..1142eff 100644 --- a/Documentation/DecaTec.WebDav.Documentation/Content/VersionHistory/v0.7.1.0.aml +++ b/Documentation/DecaTec.WebDav.Documentation/Content/VersionHistory/v0.8.0.0.aml @@ -6,7 +6,7 @@
- Changes in release v0.7.1.0 + Changes in release v0.8.0.0 @@ -16,7 +16,13 @@ When using WebDavClient.DownloadFileWithProgressAsync, the passed Stream does not get disposed automatically. Disposing of this Stream is up to the client calling this method. - + + + + Strongly typed versions of Lock-Token formats as defined in WebDAV specification. + + + When using the Portable WebDAV Library on Xamarin, there was a problem when relative URLs (strings) where used (e.g. webDavSession.ListAsync(@"/folder");) @@ -25,7 +31,25 @@ - Strongly typed versions of Lock-Token formats as defined in WebDAV specification. + When using WebDavSession, a base URL (string) can now be specified. + + + + + + The 'Translate' header is always set to 'f' for IIS WebDAV serving unmapped file types (see MSDNhttps://msdn.microsoft.com/en-us/library/cc250063.aspx). + + + + + + Bugfix: When using WebDavSession with BaseUri and calling methods passing only the relative Uri/URL to a file, these operations always failed. + + + + + + Bugfix: When using WebDavSession.UploadFileWithProgressAsync with a URL, there was a stack overflow exception because the method called itself and not the correct overload. diff --git a/Documentation/DecaTec.WebDav.Documentation/ContentLayout.content b/Documentation/DecaTec.WebDav.Documentation/ContentLayout.content index 7be314b..c982ee9 100644 --- a/Documentation/DecaTec.WebDav.Documentation/ContentLayout.content +++ b/Documentation/DecaTec.WebDav.Documentation/ContentLayout.content @@ -99,9 +99,9 @@ - + - + diff --git a/Documentation/DecaTec.WebDav.Documentation/DecaTec.WebDav.Documentation.shfbproj b/Documentation/DecaTec.WebDav.Documentation/DecaTec.WebDav.Documentation.shfbproj index c358ef2..da80f28 100644 --- a/Documentation/DecaTec.WebDav.Documentation/DecaTec.WebDav.Documentation.shfbproj +++ b/Documentation/DecaTec.WebDav.Documentation/DecaTec.WebDav.Documentation.shfbproj @@ -103,7 +103,7 @@ - + diff --git a/UnitTests/DecaTec.WebDav.UnitIntegrationTest/DecaTec.WebDav.UnitIntegrationTest.csproj b/UnitTests/DecaTec.WebDav.UnitIntegrationTest/DecaTec.WebDav.UnitIntegrationTest.csproj index 99646cc..2f429ba 100644 --- a/UnitTests/DecaTec.WebDav.UnitIntegrationTest/DecaTec.WebDav.UnitIntegrationTest.csproj +++ b/UnitTests/DecaTec.WebDav.UnitIntegrationTest/DecaTec.WebDav.UnitIntegrationTest.csproj @@ -20,6 +20,9 @@ + + PreserveNewest + PreserveNewest diff --git a/UnitTests/DecaTec.WebDav.UnitIntegrationTest/TestFile1.01 b/UnitTests/DecaTec.WebDav.UnitIntegrationTest/TestFile1.01 new file mode 100644 index 0000000..c1f6daa --- /dev/null +++ b/UnitTests/DecaTec.WebDav.UnitIntegrationTest/TestFile1.01 @@ -0,0 +1 @@ +This a a file with unknown extension. \ No newline at end of file diff --git a/UnitTests/DecaTec.WebDav.UnitIntegrationTest/UnitIntegrationTestWebDavClient.cs b/UnitTests/DecaTec.WebDav.UnitIntegrationTest/UnitIntegrationTestWebDavClient.cs index a3301d6..05ed70b 100644 --- a/UnitTests/DecaTec.WebDav.UnitIntegrationTest/UnitIntegrationTestWebDavClient.cs +++ b/UnitTests/DecaTec.WebDav.UnitIntegrationTest/UnitIntegrationTestWebDavClient.cs @@ -12,6 +12,11 @@ namespace DecaTec.WebDav.UnitIntegrationTest { /// /// Unit integration test class for WebDavClient. + /// + /// IMPORTANT: This is a playground when testing this library against a specific WebDAV server implementation. + /// Not all methods of WebDavCliebnt will be tested here. + /// For unit tests of WebDavClient (with a mocked HTTP handler), see the UnitTestWebDavClient class in the unit test project. + /// /// You'll need a file 'TestConfiguration.txt' in the test's output folder with the following content: /// Line 1: The user name to use for WebDAV connections /// Line 2: The password to use for WebDAV connections @@ -22,29 +27,36 @@ namespace DecaTec.WebDav.UnitIntegrationTest [TestClass] public class UnitIntegrationTestWebDavClient { - private string userName; - private string password; - private string webDavRootFolder; + private static string userName; + private static string password; + private static string webDavRootFolder; private const string ConfigurationFile = @"TestConfiguration.txt"; private const string TestFile = @"TextFile1.txt"; + private const string TestFileUnknownExtension = @"TestFile1.01"; private const string TestCollection = "TestCollection"; - [TestInitialize] - public void ReadTestConfiguration() + public TestContext TestContext + { + get; + set; + } + + [ClassInitialize] + public static void ClassSetup(TestContext ctx) { try { var configuration = File.ReadAllLines(ConfigurationFile); - this.userName = configuration[0]; - this.password = configuration[1]; - this.webDavRootFolder = configuration[2]; + userName = configuration[0]; + password = configuration[1]; + webDavRootFolder = configuration[2]; } catch (Exception ex) { throw new FileNotFoundException("The configuration file cannot be found. Make sure that there is a file 'TestConfiguration.txt' in the test's output folder containing data about the WebDAV server to test against.", ConfigurationFile, ex); } - } + } private void DebugWriteResponseContent(string contentString) { @@ -79,7 +91,7 @@ private void DebugWriteResponseContent(string contentString) private WebDavClient CreateWebDavClientWithDebugHttpMessageHandler() { - var credentials = new NetworkCredential(this.userName, this.password); + var credentials = new NetworkCredential(userName, password); var httpClientHandler = new HttpClientHandler() { @@ -98,8 +110,8 @@ private WebDavClient CreateWebDavClientWithDebugHttpMessageHandler() public void UIT_WebDavClient_Copy() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); - var testCollectionSource = UriHelper.CombineUrl(this.webDavRootFolder, TestCollection, true); - var testCollectionDestination = UriHelper.CombineUrl(this.webDavRootFolder, TestCollection + "2", true); + var testCollectionSource = UriHelper.CombineUrl(webDavRootFolder, TestCollection, true); + var testCollectionDestination = UriHelper.CombineUrl(webDavRootFolder, TestCollection + "2", true); var testFile = UriHelper.CombineUrl(testCollectionSource, TestFile, true); // Create source collection. @@ -166,7 +178,7 @@ public void UIT_WebDavClient_PropFind_AllPropDepthInfinity() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); PropFind pf = PropFind.CreatePropFindAllProp(); - var response = client.PropFindAsync(this.webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; + var response = client.PropFindAsync(webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; var responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var propFindResponseSuccess = response.IsSuccessStatusCode; @@ -181,7 +193,7 @@ public void UIT_WebDavClient_PropFind_AllPropDepthOne() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); PropFind pf = PropFind.CreatePropFindAllProp(); - var response = client.PropFindAsync(this.webDavRootFolder, WebDavDepthHeaderValue.One, pf).Result; + var response = client.PropFindAsync(webDavRootFolder, WebDavDepthHeaderValue.One, pf).Result; var responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var propFindResponseSuccess = response.IsSuccessStatusCode; @@ -196,7 +208,7 @@ public void UIT_WebDavClient_PropFind_AllPropDepthZero() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); PropFind pf = PropFind.CreatePropFindAllProp(); - var response = client.PropFindAsync(this.webDavRootFolder, WebDavDepthHeaderValue.Zero, pf).Result; + var response = client.PropFindAsync(webDavRootFolder, WebDavDepthHeaderValue.Zero, pf).Result; var responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var propFindResponseSuccess = response.IsSuccessStatusCode; @@ -211,7 +223,7 @@ public void UIT_WebDavClient_PropFind_NamedProperties() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); PropFind pf = PropFind.CreatePropFindWithEmptyProperties("name"); - var response = client.PropFindAsync(this.webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; + var response = client.PropFindAsync(webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; var responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var propFindResponseSuccess = response.IsSuccessStatusCode; @@ -226,7 +238,7 @@ public void UIT_WebDavClient_PropFind_PropName() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); PropFind pf = PropFind.CreatePropFindWithPropName(); - var response = client.PropFindAsync(this.webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; + var response = client.PropFindAsync(webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; var responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var propFindResponseSuccess = response.IsSuccessStatusCode; @@ -244,7 +256,7 @@ public void UIT_WebDavClient_PropFind_PropName() public void UIT_WebDavClient_PropPatch() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); - var testFile = UriHelper.CombineUrl(this.webDavRootFolder, TestFile, true); + var testFile = UriHelper.CombineUrl(webDavRootFolder, TestFile, true); // Put file. var content = new StreamContent(File.OpenRead(TestFile)); @@ -318,7 +330,7 @@ public void UIT_WebDavClient_PropPatch() public void UIT_WebDavClient_Mkcol() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); - var testCollection = UriHelper.CombineUrl(this.webDavRootFolder, TestCollection, true); + var testCollection = UriHelper.CombineUrl(webDavRootFolder, TestCollection, true); // Create collection. var response = client.MkcolAsync(testCollection).Result; @@ -328,7 +340,7 @@ public void UIT_WebDavClient_Mkcol() // PropFind. PropFind pf = PropFind.CreatePropFindAllProp(); - response = client.PropFindAsync(this.webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; + response = client.PropFindAsync(webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var propFindResponseSuccess = response.IsSuccessStatusCode; @@ -366,7 +378,7 @@ public void UIT_WebDavClient_Mkcol() public void UIT_WebDavClient_Get() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); - var testFile = UriHelper.CombineUrl(this.webDavRootFolder, TestFile, true); + var testFile = UriHelper.CombineUrl(webDavRootFolder, TestFile, true); // Put file. var content = new StreamContent(File.OpenRead(TestFile)); @@ -400,6 +412,45 @@ public void UIT_WebDavClient_Get() Assert.IsTrue(deleteResponseSuccess); } + + [TestMethod] + public void UIT_WebDavClient_Get_WithFileWithUnknownExtension() + { + var client = CreateWebDavClientWithDebugHttpMessageHandler(); + var testFile = UriHelper.CombineUrl(webDavRootFolder, TestFileUnknownExtension, true); + + // Put file. + var content = new StreamContent(File.OpenRead(TestFileUnknownExtension)); + var response = client.PutAsync(testFile, content).Result; + var responseContentString = response.Content.ReadAsStringAsync().Result; + DebugWriteResponseContent(responseContentString); + var putResponseSuccess = response.IsSuccessStatusCode; + + // Head + response = client.HeadAsync(testFile).Result; + responseContentString = response.Content.ReadAsStringAsync().Result; + DebugWriteResponseContent(responseContentString); + var headResponseSuccess = response.IsSuccessStatusCode; + + // Get file. + response = client.GetAsync(testFile).Result; + var responseContentStringGet = response.Content.ReadAsStringAsync().Result; + DebugWriteResponseContent(responseContentString); + var getResponseSuccess = response.IsSuccessStatusCode; + + // Delete file. + response = client.DeleteAsync(testFile).Result; + responseContentString = response.Content.ReadAsStringAsync().Result; + DebugWriteResponseContent(responseContentString); + var deleteResponseSuccess = response.IsSuccessStatusCode; + + Assert.IsTrue(putResponseSuccess); + Assert.IsTrue(headResponseSuccess); + Assert.IsTrue(getResponseSuccess); + Assert.AreEqual("This a a file with unknown extension.", responseContentStringGet); + Assert.IsTrue(deleteResponseSuccess); + } + #endregion Get / head #region Move @@ -408,8 +459,8 @@ public void UIT_WebDavClient_Get() public void UIT_WebDavClient_Move() { var client = CreateWebDavClientWithDebugHttpMessageHandler(); - var testCollectionSource = UriHelper.CombineUrl(this.webDavRootFolder, TestCollection, true); - var testCollectionDestination = UriHelper.CombineUrl(this.webDavRootFolder, TestCollection + "2", true); + var testCollectionSource = UriHelper.CombineUrl(webDavRootFolder, TestCollection, true); + var testCollectionDestination = UriHelper.CombineUrl(webDavRootFolder, TestCollection + "2", true); var testFile = UriHelper.CombineUrl(testCollectionSource, TestFile, true); // Create source collection. @@ -433,7 +484,7 @@ public void UIT_WebDavClient_Move() // PropFind. PropFind pf = PropFind.CreatePropFindAllProp(); - response = client.PropFindAsync(this.webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; + response = client.PropFindAsync(webDavRootFolder, WebDavDepthHeaderValue.Infinity, pf).Result; responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var propFindResponseSuccess = response.IsSuccessStatusCode; @@ -485,20 +536,20 @@ public void UIT_WebDavClient_LockRefreshLockUnlock() OwnerHref = "test@test.com" }; - var response = client.LockAsync(this.webDavRootFolder, WebDavTimeoutHeaderValue.CreateWebDavTimeout(TimeSpan.FromMinutes(1)), WebDavDepthHeaderValue.Infinity, lockInfo).Result; + var response = client.LockAsync(webDavRootFolder, WebDavTimeoutHeaderValue.CreateWebDavTimeout(TimeSpan.FromMinutes(1)), WebDavDepthHeaderValue.Infinity, lockInfo).Result; var responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var lockResponseSuccess = response.IsSuccessStatusCode; LockToken lockToken = WebDavHelper.GetLockTokenFromWebDavResponseMessage(response); // Refresh lock. - response = client.RefreshLockAsync(this.webDavRootFolder, WebDavTimeoutHeaderValue.CreateWebDavTimeout(TimeSpan.FromSeconds(10)), lockToken).Result; + response = client.RefreshLockAsync(webDavRootFolder, WebDavTimeoutHeaderValue.CreateWebDavTimeout(TimeSpan.FromSeconds(10)), lockToken).Result; responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var refreshLockResponseSuccess = response.IsSuccessStatusCode; // Unlock. - response = client.UnlockAsync(this.webDavRootFolder, lockToken).Result; + response = client.UnlockAsync(webDavRootFolder, lockToken).Result; responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var unlockResponseSuccess = response.IsSuccessStatusCode; @@ -522,7 +573,7 @@ public void UIT_WebDavClient_LockAndPutWithoutToken() OwnerHref = "test@test.com" }; - var response = client.LockAsync(this.webDavRootFolder, WebDavTimeoutHeaderValue.CreateWebDavTimeout(TimeSpan.FromSeconds(15)), WebDavDepthHeaderValue.Infinity, lockInfo).Result; + var response = client.LockAsync(webDavRootFolder, WebDavTimeoutHeaderValue.CreateWebDavTimeout(TimeSpan.FromSeconds(15)), WebDavDepthHeaderValue.Infinity, lockInfo).Result; var responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var lockResponseSuccess = response.IsSuccessStatusCode; @@ -531,14 +582,14 @@ public void UIT_WebDavClient_LockAndPutWithoutToken() // Put file (without lock token) -> this should fail. var content = new StreamContent(File.OpenRead(TestFile)); - var requestUrl = UriHelper.CombineUrl(this.webDavRootFolder, TestFile, true); + var requestUrl = UriHelper.CombineUrl(webDavRootFolder, TestFile, true); response = client.PutAsync(requestUrl, content).Result; responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var putResponseSuccess = response.IsSuccessStatusCode; // Unlock. - response = client.UnlockAsync(this.webDavRootFolder, lockToken).Result; + response = client.UnlockAsync(webDavRootFolder, lockToken).Result; var unlockResponseSuccess = response.IsSuccessStatusCode; Assert.IsTrue(lockResponseSuccess); @@ -560,7 +611,7 @@ public void UIT_WebDavClient_LockAndPutWithToken() OwnerHref = "test@test.com" }; - var response = client.LockAsync(this.webDavRootFolder, WebDavTimeoutHeaderValue.CreateWebDavTimeout(TimeSpan.FromSeconds(15)), WebDavDepthHeaderValue.Infinity, lockInfo).Result; + var response = client.LockAsync(webDavRootFolder, WebDavTimeoutHeaderValue.CreateWebDavTimeout(TimeSpan.FromSeconds(15)), WebDavDepthHeaderValue.Infinity, lockInfo).Result; var responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var lockResponseSuccess = response.IsSuccessStatusCode; @@ -568,7 +619,7 @@ public void UIT_WebDavClient_LockAndPutWithToken() // Put file. var content = new StreamContent(File.OpenRead(TestFile)); - var requestUrl = UriHelper.CombineUrl(this.webDavRootFolder, TestFile, true); + var requestUrl = UriHelper.CombineUrl(webDavRootFolder, TestFile, true); response = client.PutAsync(requestUrl, content, lockToken).Result; responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); @@ -581,7 +632,7 @@ public void UIT_WebDavClient_LockAndPutWithToken() var deleteResponseSuccess = response.IsSuccessStatusCode; // Unlock. - response = client.UnlockAsync(this.webDavRootFolder, lockToken).Result; + response = client.UnlockAsync(webDavRootFolder, lockToken).Result; responseContentString = response.Content.ReadAsStringAsync().Result; DebugWriteResponseContent(responseContentString); var unlockResponseSuccess = response.IsSuccessStatusCode; @@ -593,6 +644,6 @@ public void UIT_WebDavClient_LockAndPutWithToken() Assert.IsTrue(unlockResponseSuccess); } - #endregion Lock / unlock + #endregion Lock / unlock } } diff --git a/UnitTests/DecaTec.WebDav.UnitIntegrationTest/UnitIntegrationTestWebDavSession.cs b/UnitTests/DecaTec.WebDav.UnitIntegrationTest/UnitIntegrationTestWebDavSession.cs index 4432cb5..a536d05 100644 --- a/UnitTests/DecaTec.WebDav.UnitIntegrationTest/UnitIntegrationTestWebDavSession.cs +++ b/UnitTests/DecaTec.WebDav.UnitIntegrationTest/UnitIntegrationTestWebDavSession.cs @@ -9,6 +9,11 @@ namespace DecaTec.WebDav.UnitIntegrationTest { /// /// Unit integration test class for WebDavSession. + /// + /// IMPORTANT: This is a playground when testing this library against a specific WebDAV server implementation. + /// Not all methods of WebDavSession will be tested here. + /// For unit tests of WebDavSession (with a mocked HTTP handler), see the UnitTestWebDavSession class in the unit test project. + /// /// You'll need a file 'TestConfiguration.txt' in the test's output folder with the following content: /// Line 1: The user name to use for WebDAV connections /// Line 2: The password to use for WebDAV connections @@ -19,21 +24,31 @@ namespace DecaTec.WebDav.UnitIntegrationTest [TestClass] public class UnitIntegrationTestWebDavSession { - private string userName; - private string password; - private string webDavRootFolder; + private static string userName; + private static string password; + private static string webDavRootFolder; private const string ConfigurationFile = @"TestConfiguration.txt"; - [TestInitialize] - public void ReadTestConfiguration() + private const string TestFile = @"TextFile1.txt"; + private const string TestFileUnknownExtension = @"TestFile1.01"; + private const string TestFolder = "TestFolder"; + + public TestContext TestContext + { + get; + set; + } + + [ClassInitialize] + public static void ClassSetup(TestContext ctx) { try { var configuration = File.ReadAllLines(ConfigurationFile); - this.userName = configuration[0]; - this.password = configuration[1]; - this.webDavRootFolder = configuration[2]; + userName = configuration[0]; + password = configuration[1]; + webDavRootFolder = configuration[2]; } catch (Exception ex) { @@ -46,7 +61,7 @@ private WebDavSession CreateWebDavSession() var httpClientHandler = new HttpClientHandler() { PreAuthenticate = true, - Credentials = new NetworkCredential(this.userName, this.password) + Credentials = new NetworkCredential(userName, password) }; var debugHttpMessageHandler = new DebugHttpMessageHandler(httpClientHandler); @@ -58,7 +73,7 @@ private WebDavSession CreateWebDavSession() public void UIT_WebDavSession_List() { var session = CreateWebDavSession(); - var items = session.ListAsync(this.webDavRootFolder).Result; + var items = session.ListAsync(webDavRootFolder).Result; Assert.IsNotNull(items); } @@ -131,16 +146,53 @@ public void UIT_WebDavSession_List_WithSpaceInFolderAndSubfolder() public void UIT_WebDavSession_Lock() { var session = CreateWebDavSession(); - var locked = session.LockAsync(this.webDavRootFolder).Result; - var requestUrl = UriHelper.CombineUrl(this.webDavRootFolder, "Test", true); + var locked = session.LockAsync(webDavRootFolder).Result; + var requestUrl = UriHelper.CombineUrl(webDavRootFolder, "Test", true); var created = session.CreateDirectoryAsync(requestUrl).Result; var deleted = session.DeleteAsync(requestUrl).Result; - var unlocked = session.UnlockAsync(this.webDavRootFolder).Result; + var unlocked = session.UnlockAsync(webDavRootFolder).Result; Assert.IsTrue(locked); Assert.IsTrue(created); Assert.IsTrue(deleted); Assert.IsTrue(unlocked); } + + [TestMethod] + public void UIT_WebDavSession_DeleteFileFolder_WithBaseUri() + { + var session = CreateWebDavSession(); + session.BaseUrl = webDavRootFolder; + var testFile = TestFolder + "/" + TestFile; + var createdFolder = session.CreateDirectoryAsync(TestFolder).Result; + var stream = File.OpenRead(TestFile); + var createdFile = session.UploadFileAsync(testFile, stream).Result; + stream.Dispose(); + + var deletedFile = session.DeleteAsync(testFile).Result; + var deletedFolder= session.DeleteAsync(TestFolder).Result; + + Assert.IsTrue(createdFolder); + Assert.IsTrue(createdFile); + Assert.IsTrue(deletedFile); + Assert.IsTrue(deletedFolder); + } + + [TestMethod] + public void UIT_WebDavSession_CreateAndHead_WithFileUnknown() + { + var session = CreateWebDavSession(); + session.BaseUrl = webDavRootFolder; + var stream = File.OpenRead(TestFileUnknownExtension); + var createdFile = session.UploadFileAsync(TestFileUnknownExtension, stream).Result; + stream.Dispose(); + + var fileExists = session.ExistsAsync(TestFileUnknownExtension).Result; + var deletedFile = session.DeleteAsync(TestFileUnknownExtension).Result; + + Assert.IsTrue(createdFile); + Assert.IsTrue(fileExists); + Assert.IsTrue(deletedFile); + } } } diff --git a/UnitTests/DecaTec.WebDav.UnitTest/UnitTestLockToken.cs b/UnitTests/DecaTec.WebDav.UnitTest/UnitTestLockToken.cs index ceebfea..41133fb 100644 --- a/UnitTests/DecaTec.WebDav.UnitTest/UnitTestLockToken.cs +++ b/UnitTests/DecaTec.WebDav.UnitTest/UnitTestLockToken.cs @@ -18,7 +18,7 @@ public void UT_LockToken_IfHeaderNoTagListFormat_IfHeaderWithoutBrackets() } [TestMethod] - public void UT_LockToken_Construct_IfHeaderNoTagListFormat_IfHeaderWithoutBracketsWithString() + public void UT_LockToken_Construct_IfHeaderWithoutBracketsWithString() { var lockTokenString = "urn:uuid:my-lock-token"; @@ -45,7 +45,7 @@ public void UT_LockToken_IfHeaderNoTagListFormat_IfHeaderWithBrackets() } [TestMethod] - public void UT_LockToken_Construct_IfHeaderNoTagListFormat_IfHeaderWithBracketsWithString() + public void UT_LockToken_Construct_IfHeaderWithBracketsWithString() { var lockTokenString = ""; @@ -72,7 +72,7 @@ public void UT_LockToken_LockTokenHeaderFormat_LockTokenHeaderWithoutBrackets() } [TestMethod] - public void UT_LockToken_Construct_LockTokenHeaderFormat_LockTokenHeaderWithoutBracketsWithString() + public void UT_LockToken_Construct_LockTokenHeaderWithoutBracketsWithString() { var lockTokenString = "urn:uuid:my-lock-token"; @@ -99,7 +99,7 @@ public void UT_LockToken_LockTokenHeaderFormat_LockTokenHeaderWithBrackets() } [TestMethod] - public void UT_LockToken_Construct_LockTokenHeaderFormat_LockTokenHeaderWithBracketsWithString() + public void UT_LockToken_Construct_LockTokenHeaderWithBracketsWithString() { var lockTokenString = ""; @@ -114,14 +114,16 @@ public void UT_LockToken_Construct_LockTokenHeaderFormat_LockTokenHeaderWithBrac } [TestMethod] - public void UT_LockToken_LockTokenHeaderFormat_LockTokenHeaderWithBothBrackets() + public void UT_LockToken_LockTokenHeaderFormat_LockTokenHeaderWithBothBracketsWithString() { - var parseResult = CodedUrl.TryParse("()", out var codedUrl); + var lockTokenString = "()"; - var lockToken = new LockToken(codedUrl.AbsoluteUri); + var parseResult = NoTagList.TryParse(lockTokenString, out var noTagList); + + var lockToken = new LockToken(noTagList.CodedUrl.AbsoluteUri); var lockTokenHeaderFormat = lockToken.LockTokenHeaderFormat; - Assert.AreEqual("()", lockTokenHeaderFormat.ToString()); + Assert.AreEqual("", lockTokenHeaderFormat.ToString()); Assert.IsTrue(parseResult); } @@ -132,12 +134,12 @@ public void UT_LockToken_Construct_LockTokenHeaderFormat_LockTokenHeaderWithBoth var lockToken = new LockToken(lockTokenString); var absoluteUri = lockToken.AbsoluteUri; - var codedUrl = lockToken.LockTokenHeaderFormat; - var lockTokenHeaderFormat = lockToken.IfHeaderNoTagListFormat; + var lockTokenHeaderFormat = lockToken.LockTokenHeaderFormat; + var ifHeaderNoTagListFormat = lockToken.IfHeaderNoTagListFormat; Assert.IsNull(absoluteUri); - Assert.IsNull(codedUrl); - Assert.AreEqual("()", lockTokenHeaderFormat.ToString()); + Assert.IsNull(lockTokenHeaderFormat); + Assert.AreEqual(lockTokenString, ifHeaderNoTagListFormat.ToString()); } } } diff --git a/UnitTests/DecaTec.WebDav.UnitTest/UnitTestWebDavClient.cs b/UnitTests/DecaTec.WebDav.UnitTest/UnitTestWebDavClient.cs index 420fdb7..e3b480c 100644 --- a/UnitTests/DecaTec.WebDav.UnitTest/UnitTestWebDavClient.cs +++ b/UnitTests/DecaTec.WebDav.UnitTest/UnitTestWebDavClient.cs @@ -20,6 +20,18 @@ public class UnitTestWebDavClient private const string TestFile = @"TextFile1.txt"; private const string TestFolder = "TestFolder"; + public TestContext TestContext + { + get; + set; + } + + [ClassInitialize] + public static void ClassSetup(TestContext ctx) + { + + } + private WebDavClient CreateWebDavClient(MockHttpMessageHandler mockHandler) { var credentials = new NetworkCredential(UserName, Password); @@ -112,14 +124,14 @@ public void UT_WebDavClient_Copy() { var testFolderSource = UriHelper.CombineUrl(WebDavRootFolder, TestFolder, true); var testFolderDestination = UriHelper.CombineUrl(WebDavRootFolder, TestFolder + "2", true); - var testFile = UriHelper.CombineUrl(testFolderSource, TestFile, true); var mockHandler = new MockHttpMessageHandler(); var requestHeaders = new List> { new KeyValuePair(WebDavConstants.Depth, WebDavDepthHeaderValue.Infinity.ToString()), - new KeyValuePair(WebDavRequestHeader.Destination, testFolderDestination) + new KeyValuePair(WebDavRequestHeader.Destination, testFolderDestination), + new KeyValuePair(WebDavRequestHeader.Overwrite, WebDavOverwriteHeaderValue.NoOverwrite) }; mockHandler.When(WebDavMethod.Copy, testFolderSource).WithHeaders(requestHeaders).Respond(HttpStatusCode.Created); @@ -178,8 +190,8 @@ public void UT_WebDavClient_DownloadFileWithProgress() using (var stream = new MemoryStream()) { response = client.DownloadFileWithProgressAsync(testFile, stream, CancellationToken.None, progress).Result; - stream.Position = 0; + using (StreamReader sr = new StreamReader(stream)) { downloadedString = sr.ReadToEnd(); @@ -301,7 +313,7 @@ public void UT_WebDavClient_LockRootFolder() [ExpectedException(typeof(WebDavException))] public void UT_WebDavClient_LockWithDepthOneShouldThrowException_ShouldThrowWebDavException() { - var testFileToLock = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var testFileToLock = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); var oneMinuteTimeout = WebDavTimeoutHeaderValue.CreateWebDavTimeout(TimeSpan.FromMinutes(1)); var depth = WebDavDepthHeaderValue.One; @@ -318,7 +330,7 @@ public void UT_WebDavClient_LockWithDepthOneShouldThrowException_ShouldThrowWebD { var response = client.LockAsync(testFileToLock, oneMinuteTimeout, depth, lockInfo).Result; } - catch(AggregateException ex) + catch (AggregateException ex) { throw ex.InnerException; } @@ -417,34 +429,7 @@ public void UT_WebDavClient_Move_WithOverwrite() Assert.IsTrue(response.IsSuccessStatusCode); } - #endregion Move - - //#region Post - - //[TestMethod] - //public void UT_WebDavClient_Post() - //{ - // var testFolderSource = UriHelper.CombineUrl(WebDavRootFolder, TestFolder, true); - // var testFolderDestination = UriHelper.CombineUrl(WebDavRootFolder, TestFolder + "Dest", true); - - // var mockHandler = new MockHttpMessageHandler(); - - // var requestHeaders = new List> - // { - // new KeyValuePair(WebDavRequestHeader.Destination, testFolderDestination), - // new KeyValuePair(WebDavRequestHeader.Depth, WebDavDepthHeaderValue.Infinity.ToString()), - // new KeyValuePair(WebDavRequestHeader.Overwrite, WebDavOverwriteHeaderValue.Overwrite) - // }; - - // mockHandler.When(WebDavMethod.Move, testFolderSource).WithHeaders(requestHeaders).Respond(HttpStatusCode.Created); - - // var client = CreateWebDavClient(mockHandler); - // var response = client.MoveAsync(testFolderSource, testFolderDestination, true).Result; - - // Assert.IsTrue(response.IsSuccessStatusCode); - //} - - //#endregion Post + #endregion Move #region PropFind @@ -587,98 +572,175 @@ public void UT_WebDavClient_PropFind_PropName() #endregion PropFind - #region PropPatch / put / delete file + #region PropPatch [TestMethod] - public void UT_WebDavClient_PropPatch() + public void UT_WebDavClient_PropPatchSet() { var mockHandler = new MockHttpMessageHandler(); - // Put - var requestUrl = WebDavRootFolder + @"/TextFile1.txt"; + var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var requestContentProppatch = "TestFileDisplayName"; + var responseContentProppatch = "http://127.0.0.1/TextFile1.txtHTTP/1.1 200 OK"; + mockHandler.When(WebDavMethod.PropPatch, testFile).WithContent(requestContentProppatch).Respond(HttpStatusCode.OK, new StringContent(responseContentProppatch)); + + var propertyUpdate = new PropertyUpdate(); + var set = new Set(); + + var prop = new Prop() + { + DisplayName = "TestFileDisplayName" + }; + + set.Prop = prop; + propertyUpdate.Items = new object[] { set }; + + var client = CreateWebDavClient(mockHandler); + var response = client.PropPatchAsync(testFile, propertyUpdate).Result; + var multistatusPropPatch = WebDavResponseContentParser.ParseMultistatusResponseContentAsync(response.Content).Result; + + Assert.IsNotNull(multistatusPropPatch); + Assert.IsTrue(response.IsSuccessStatusCode); + } + + [TestMethod] + public void UT_WebDavClient_PropPatchRemove() + { + var mockHandler = new MockHttpMessageHandler(); + + var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var requestContentProppatch = ""; + var responseContentProppatch = "http://127.0.0.1/TextFile1.txtHTTP/1.1 204 No Content"; + mockHandler.When(WebDavMethod.PropPatch, testFile).WithContent(requestContentProppatch).Respond(HttpStatusCode.NoContent, new StringContent(responseContentProppatch)); + + var propertyUpdate = new PropertyUpdate(); + var remove = new Remove(); + var prop = Prop.CreatePropWithEmptyProperties(PropNameConstants.DisplayName); + remove.Prop = prop; + propertyUpdate.Items = new object[] { remove }; + + var client = new WebDavClient(mockHandler); + var response = client.PropPatchAsync(testFile, propertyUpdate).Result; + + Assert.IsTrue(response.IsSuccessStatusCode); + } + + #endregion PropPatch + + #region Put + + [TestMethod] + public void UT_WebDavClient_Put() + { + var mockHandler = new MockHttpMessageHandler(); + + var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); var requestContentPut = "This is a test file for WebDAV."; - mockHandler.When(HttpMethod.Put, requestUrl).WithContent(requestContentPut).Respond(HttpStatusCode.Created); + mockHandler.When(HttpMethod.Put, testFile).WithContent(requestContentPut).Respond(HttpStatusCode.Created); - // Proppatch (set) - var requestContentProppatchSet = "TestFileDisplayName"; - var responseContentProppatchSet = "http://127.0.0.1/TextFile1.txtHTTP/1.1 200 OK"; - mockHandler.When(WebDavMethod.PropPatch, requestUrl).WithContent(requestContentProppatchSet).Respond(HttpStatusCode.OK, new StringContent(responseContentProppatchSet)); + var client = CreateWebDavClient(mockHandler); + var response = client.PutAsync(testFile, new StringContent(requestContentPut)).Result; - // Propfind - var requestContentPropFind = ""; + Assert.IsTrue(response.IsSuccessStatusCode); + } - var requestHeadersPropFind = new List> + #endregion Put + + #region Send + + [TestMethod] + public void UT_WebDavClient_Send() + { + var mockHandler = new MockHttpMessageHandler(); + + var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var requestContentPut = "This is a test file for WebDAV."; + mockHandler.When(HttpMethod.Put, testFile).WithContent(requestContentPut).Respond(HttpStatusCode.Created); + + var client = new WebDavClient(mockHandler); + + var httpRequestMessage = new HttpRequestMessage(HttpMethod.Put, testFile) { - new KeyValuePair(WebDavConstants.Depth, WebDavDepthHeaderValue.Zero.ToString()) + Content = new StringContent(requestContentPut) }; - var responseContentPropfind = "http://127.0.0.1/TextFile1.txtTestFileDisplayNameHTTP/1.1 200 OK"; - mockHandler.When(WebDavMethod.PropFind, requestUrl).WithHeaders(requestHeadersPropFind).WithContent(requestContentPropFind).Respond(HttpStatusCode.OK, new StringContent(responseContentPropfind)); + var response = client.SendAsync(httpRequestMessage).Result; + + Assert.IsTrue(response.IsSuccessStatusCode); + } - // Proppatch (remove) - var requestContentProppatchRemove = ""; - var responseContentProppatchRemove = "http://127.0.0.1/TextFile1.txtHTTP/1.1 204 No Content"; - mockHandler.When(WebDavMethod.PropPatch, requestUrl).WithContent(requestContentProppatchRemove).Respond(HttpStatusCode.NoContent, new StringContent(responseContentProppatchRemove)); + #endregion Send - // Delete - mockHandler.When(HttpMethod.Delete, requestUrl).Respond(HttpStatusCode.NoContent); + #region Unlock + + [TestMethod] + public void UT_WebDavClient_Unlock() + { + var testFileToUnlock = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var lockTokenString = ""; + + var mockHandler = new MockHttpMessageHandler(); + + var requestHeaders = new List> + { + new KeyValuePair(WebDavRequestHeader.LockToken, lockTokenString) + }; + + mockHandler.When(WebDavMethod.Unlock, testFileToUnlock).WithHeaders(requestHeaders).Respond(HttpStatusCode.NoContent); var client = CreateWebDavClient(mockHandler); + var lockToken = new LockToken(lockTokenString); + var response = client.UnlockAsync(testFileToUnlock, lockToken).Result; + + Assert.IsTrue(response.IsSuccessStatusCode); + } + + #endregion Unlock + + #region Upload file + + [TestMethod] + public void UT_WebDavClient_UploadFileWithProgress() + { var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var uploadFileContent = "This is a file uploaded with progress"; + var contentType = "application/octet-stream"; + Progress progress = new Progress(); + var progressHandlerIndicator = false; - // Put file. - var content = new StringContent(requestContentPut); - var response = client.PutAsync(testFile, content).Result; - var putResponseSuccess = response.IsSuccessStatusCode; + EventHandler progressHandler = (sender, e) => + { + progressHandlerIndicator = true; + }; - // PropPatch (set). - var propertyUpdate = new PropertyUpdate(); - var set = new Set(); + progress.ProgressChanged += progressHandler; - var prop = new Prop() + var requestHeaders = new List> { - DisplayName = "TestFileDisplayName" + new KeyValuePair(HttpHeaderNames.ContentType, contentType) }; - set.Prop = prop; - propertyUpdate.Items = new object[] { set }; - response = client.PropPatchAsync(testFile, propertyUpdate).Result; - var multistatusPropPatchSet = WebDavResponseContentParser.ParseMultistatusResponseContentAsync(response.Content).Result; - var propPatchResponseSuccess = response.IsSuccessStatusCode; - - // PropFind. - PropFind pf = PropFind.CreatePropFindWithEmptyProperties(PropNameConstants.DisplayName); - response = client.PropFindAsync(testFile, WebDavDepthHeaderValue.Zero, pf).Result; - var propFindResponseSuccess = response.IsSuccessStatusCode; - var multistatusPropFind = WebDavResponseContentParser.ParseMultistatusResponseContentAsync(response.Content).Result; - var displayName = ((Propstat)multistatusPropFind.Response[0].Items[0]).Prop.DisplayName; - var displayNameResult = "TestFileDisplayName" == displayName; - - // PropPatch (remove). - propertyUpdate = new PropertyUpdate(); - var remove = new Remove(); - prop = Prop.CreatePropWithEmptyProperties(PropNameConstants.DisplayName); - remove.Prop = prop; - propertyUpdate.Items = new object[] { remove }; - response = client.PropPatchAsync(testFile, propertyUpdate).Result; - var propPatchRemoveResponseSuccess = response.IsSuccessStatusCode; - multistatusPropFind = WebDavResponseContentParser.ParseMultistatusResponseContentAsync(response.Content).Result; - var multistatusResult = ((Propstat)multistatusPropFind.Response[0].Items[0]).Prop.DisplayName; - - // Delete file. - response = client.DeleteAsync(testFile).Result; - var deleteResponseSuccess = response.IsSuccessStatusCode; - - Assert.IsTrue(putResponseSuccess); - Assert.IsNotNull(multistatusPropPatchSet); - Assert.IsTrue(propPatchResponseSuccess); - Assert.IsTrue(propFindResponseSuccess); - Assert.IsTrue(displayNameResult); - Assert.IsTrue(propPatchRemoveResponseSuccess); - Assert.AreEqual(string.Empty, multistatusResult); - Assert.IsTrue(deleteResponseSuccess); + var mockHandler = new MockHttpMessageHandler(); + mockHandler.When(HttpMethod.Put, testFile).WithHeaders(requestHeaders).Respond(HttpStatusCode.Created); + + var client = CreateWebDavClient(mockHandler); + WebDavResponseMessage response; + + using (var stream = new MemoryStream()) + { + using (StreamWriter wr = new StreamWriter(stream)) + { + wr.Write(uploadFileContent); + wr.Flush(); + stream.Position = 0; + response = client.UploadFileWithProgressAsync(testFile, stream, contentType, progress).Result; + } + } + + Assert.IsTrue(progressHandlerIndicator); + Assert.IsTrue(response.IsSuccessStatusCode); } - #endregion PropPatch / put / delete file + #endregion Upload file } } diff --git a/UnitTests/DecaTec.WebDav.UnitTest/UnitTestWebDavSession.cs b/UnitTests/DecaTec.WebDav.UnitTest/UnitTestWebDavSession.cs new file mode 100644 index 0000000..740fee7 --- /dev/null +++ b/UnitTests/DecaTec.WebDav.UnitTest/UnitTestWebDavSession.cs @@ -0,0 +1,446 @@ +using DecaTec.WebDav.WebDavArtifacts; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using RichardSzalay.MockHttp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Text; + +namespace DecaTec.WebDav.UnitTest +{ + [TestClass] + public class UnitTestWebDavSession + { + private const string UserName = "testuser"; + private const string Password = "testpassword"; + private const string WebDavRootFolder = @"http://127.0.0.1/webdav"; + + private const string TestFile = @"TextFile1.txt"; + private const string TestFolder = "TestFolder"; + + public TestContext TestContext + { + get; + set; + } + + [ClassInitialize] +        public static void ClassSetup(TestContext ctx) + { + + } + + private WebDavSession CreateWebDavSession(MockHttpMessageHandler mockHandler) + { + var credentials = new NetworkCredential(UserName, Password); + + var httpClientHandler = new HttpClientHandler() + { + Credentials = credentials, + PreAuthenticate = true + }; + + var debugHttpMessageHandler = new DebugHttpMessageHandler(httpClientHandler) + { + InnerHandler = mockHandler + }; + + var session = new WebDavSession(debugHttpMessageHandler) + { + BaseUri = new Uri(WebDavRootFolder, UriKind.Absolute) + }; + + return session; + } + + #region Copy + + [TestMethod] + public void UT_WebDavSession_Copy() + { + var testFolderSource = TestFolder; + var testFolderDestination = TestFolder + "2"; + var testFolderSourceExpected = UriHelper.CombineUrl(WebDavRootFolder, TestFolder, true); + var testFolderDestinationExpected = UriHelper.CombineUrl(WebDavRootFolder, TestFolder + "2", true); + + var mockHandler = new MockHttpMessageHandler(); + + var requestHeaders = new List> + { + new KeyValuePair(WebDavConstants.Depth, WebDavDepthHeaderValue.Infinity.ToString()), + new KeyValuePair(WebDavRequestHeader.Destination, testFolderDestinationExpected), + new KeyValuePair(WebDavRequestHeader.Overwrite, WebDavOverwriteHeaderValue.NoOverwrite) + }; + + mockHandler.When(WebDavMethod.Copy, testFolderSourceExpected).WithHeaders(requestHeaders).Respond(HttpStatusCode.Created); + + var sesion = CreateWebDavSession(mockHandler); + var success = sesion.CopyAsync(testFolderSource, testFolderDestination).Result; + + Assert.IsTrue(success); + } + + #endregion Copy + + #region Create directory + + [TestMethod] + public void UT_WebDavSesion_CreateDirectory() + { + var testFolder = UriHelper.CombineUrl(WebDavRootFolder, TestFolder, true); + + var mockHandler = new MockHttpMessageHandler(); + mockHandler.When(WebDavMethod.Mkcol, testFolder).Respond(HttpStatusCode.Created); + + var session = CreateWebDavSession(mockHandler); + var success = session.CreateDirectoryAsync(TestFolder).Result; + + Assert.IsTrue(success); + } + + #endregion Crfeate directory + + #region Delete + + [TestMethod] + public void UT_WebDavSession_DeleteFile() + { + var testFileUrl = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + + var mockHandler = new MockHttpMessageHandler(); + mockHandler.When(HttpMethod.Delete, testFileUrl).Respond(HttpStatusCode.NoContent); + + var session = CreateWebDavSession(mockHandler); + var successs = session.DeleteAsync(TestFile).Result; + + Assert.IsTrue(successs); + } + + [TestMethod] + public void UT_WebDavSession_DeleteFolder() + { + var testFolderUrl = UriHelper.CombineUrl(WebDavRootFolder, TestFolder, true); + + var mockHandler = new MockHttpMessageHandler(); + mockHandler.When(HttpMethod.Delete, testFolderUrl).Respond(HttpStatusCode.NoContent); + + var session = CreateWebDavSession(mockHandler); + var successs = session.DeleteAsync(TestFolder).Result; + + Assert.IsTrue(successs); + } + + #endregion Delete + + #region Download file + + [TestMethod] + public void UT_WebDavSession_DownloadFile() + { + var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var downloadFileContent = "This is a downloaded file"; + + var mockHandler = new MockHttpMessageHandler(); + mockHandler.When(HttpMethod.Get, testFile).Respond(HttpStatusCode.OK, new StringContent(downloadFileContent)); + + var session = CreateWebDavSession(mockHandler); + var success = false; + string downloadedString; + + using (var stream = new MemoryStream()) + { + success = session.DownloadFileAsync(TestFile, stream).Result; + stream.Position = 0; + + using (StreamReader sr = new StreamReader(stream)) + { + downloadedString = sr.ReadToEnd(); + } + } + + Assert.IsTrue(success); + Assert.AreEqual(downloadFileContent, downloadFileContent); + } + + [TestMethod] + public void UT_WebDavSession_DownloadFileWithProgress() + { + var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var downloadFileContent = "This is a file downloaded with progress"; + Progress progress = new Progress(); + var progressHandlerIndicator = false; + + EventHandler progressHandler = (sender, e) => + { + progressHandlerIndicator = true; + }; + + progress.ProgressChanged += progressHandler; + + var mockHandler = new MockHttpMessageHandler(); + mockHandler.When(HttpMethod.Get, testFile).Respond(HttpStatusCode.OK, new StringContent(downloadFileContent)); + + var session = CreateWebDavSession(mockHandler); + var success = false; + string downloadedString; + + using (var stream = new MemoryStream()) + { + success = session.DownloadFileWithProgressAsync(TestFile, stream, progress).Result; + stream.Position = 0; + + using (StreamReader sr = new StreamReader(stream)) + { + downloadedString = sr.ReadToEnd(); + } + } + + Assert.AreEqual(downloadFileContent, downloadedString); + Assert.IsTrue(progressHandlerIndicator); + Assert.IsTrue(success); + } + + #endregion DownloadFile + + #region Exists + + [TestMethod] + public void UT_WebDavSession_Exists() + { + var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + + var mockHandler = new MockHttpMessageHandler(); + mockHandler.When(HttpMethod.Head, testFile).Respond(HttpStatusCode.OK); + + var session = CreateWebDavSession(mockHandler); + var success = session.ExistsAsync(testFile).Result; + + Assert.IsTrue(success); + } + + #endregion Exists + + #region List + + [TestMethod] + public void UT_WebDavSession_List() + { + var mockHandler = new MockHttpMessageHandler(); + var requestContent = ""; + + var requestHeaders = new List> + { + new KeyValuePair(WebDavConstants.Depth, WebDavDepthHeaderValue.One.ToString()) + }; + + var responseContent = "http://127.0.0.1/webdavHTTP/1.1 200 OKSat, 08 Apr 2017 10:07:38 GMT0/012017-04-06T09:32:20.983Zhttp://127.0.0.1/webdav/test1/HTTP/1.1 200 OKSat, 08 Apr 2017 10:07:54 GMT0test1012017-04-08T10:07:32.205Zhttp://127.0.0.1/webdav/test2/HTTP/1.1 200 OKSat, 08 Apr 2017 10:07:35 GMT0test2012017-04-08T10:07:35.866Z"; + mockHandler.When(WebDavMethod.PropFind, WebDavRootFolder).WithContent(requestContent).WithHeaders(requestHeaders).Respond((HttpStatusCode)207, new StringContent(responseContent)); + + var session = CreateWebDavSession(mockHandler); + var list = session.ListAsync(WebDavRootFolder).Result; + + Assert.IsNotNull(list); + } + + #endregion List + + #region Lock + + [TestMethod] + public void UT_WebDavSession_LockSingleFile() + { + var testFileToLock = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var lockRequestContent = ""; + var lockResponseContent = "infinityInfiniteopaquelocktoken:d32688a4-478f-46eb-bcc4-cfe6129a207e.96bb01d2b440d8dbhttp://127.0.0.1/webdav/TextFile1.txt"; + var infiniteTimeout = WebDavTimeoutHeaderValue.CreateInfiniteWebDavTimeout(); + var depth = WebDavDepthHeaderValue.Infinity; + + var mockHandler = new MockHttpMessageHandler(); + + var requestHeaders = new List> + { + new KeyValuePair(WebDavConstants.Depth, depth.ToString()), + new KeyValuePair(WebDavRequestHeader.Timeout, infiniteTimeout.ToString()) + }; + + mockHandler.When(WebDavMethod.Lock, testFileToLock).WithHeaders(requestHeaders).WithContent(lockRequestContent).Respond(HttpStatusCode.OK, new StringContent(lockResponseContent)); + + var session = CreateWebDavSession(mockHandler); + var success = session.LockAsync(TestFile).Result; + + Assert.IsTrue(success); + } + + [TestMethod] + public void UT_WebDavSession_LockRootFolder() + { + var lockRequestContent = ""; + var lockResponseContent = "infinityInfiniteopaquelocktoken:d32688a4-478f-46eb-bcc4-cfe6129a207e.96bb01d2b440d8dbhttp://127.0.0.1/webdav/"; + var infiniteTimeout = WebDavTimeoutHeaderValue.CreateInfiniteWebDavTimeout(); + var depth = WebDavDepthHeaderValue.Infinity; + + var mockHandler = new MockHttpMessageHandler(); + + var requestHeaders = new List> + { + new KeyValuePair(WebDavConstants.Depth, depth.ToString()), + new KeyValuePair(WebDavRequestHeader.Timeout, infiniteTimeout.ToString()) + }; + + mockHandler.When(WebDavMethod.Lock, WebDavRootFolder).WithHeaders(requestHeaders).WithContent(lockRequestContent).Respond(HttpStatusCode.OK, new StringContent(lockResponseContent)); + + var session = CreateWebDavSession(mockHandler); + var success = session.LockAsync(WebDavRootFolder).Result; + + Assert.IsTrue(success); + } + + #endregion Lock + + #region Move + + [TestMethod] + public void UT_WebDavSession_Move() + { + var testFolderSource = TestFolder; + var testFolderDestination = TestFolder + "2"; + var testFolderSourceExpected = UriHelper.CombineUrl(WebDavRootFolder, TestFolder, true); + var testFolderDestinationExpected = UriHelper.CombineUrl(WebDavRootFolder, TestFolder + "2", true); + + var mockHandler = new MockHttpMessageHandler(); + + var requestHeaders = new List> + { + new KeyValuePair(WebDavRequestHeader.Destination, testFolderDestinationExpected), + new KeyValuePair(WebDavRequestHeader.Depth, WebDavDepthHeaderValue.Infinity.ToString()), + new KeyValuePair(WebDavRequestHeader.Overwrite, WebDavOverwriteHeaderValue.NoOverwrite) + }; + + mockHandler.When(WebDavMethod.Move, testFolderSourceExpected).WithHeaders(requestHeaders).Respond(HttpStatusCode.Created); + + var session = CreateWebDavSession(mockHandler); + var success = session.MoveAsync(testFolderSource, testFolderDestination).Result; + + Assert.IsTrue(success); + } + + #endregion Move + + #region Upload file + + [TestMethod] + public void UT_WebDavSession_UploadFile() + { + var mockHandler = new MockHttpMessageHandler(); + + var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var uploadFileContent = "This is a test file for WebDAV."; + mockHandler.When(HttpMethod.Put, testFile).WithContent(uploadFileContent).Respond(HttpStatusCode.Created); + + var session = CreateWebDavSession(mockHandler); + var success = false; + + using (var stream = new MemoryStream()) + { + using (StreamWriter wr = new StreamWriter(stream)) + { + wr.Write(uploadFileContent); + wr.Flush(); + stream.Position = 0; + success = session.UploadFileAsync(TestFile, stream).Result; + } + } + + Assert.IsTrue(success); + } + + [TestMethod] + public void UT_WebDavSession_UploadFileWithProgress() + { + var testFile = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var uploadFileContent = "This is a file uploaded with progress"; + var contentType = "application/octet-stream"; + Progress progress = new Progress(); + var progressHandlerIndicator = false; + + EventHandler progressHandler = (sender, e) => + { + progressHandlerIndicator = true; + }; + + progress.ProgressChanged += progressHandler; + + var requestHeaders = new List> + { + new KeyValuePair(HttpHeaderNames.ContentType, contentType) + }; + + var mockHandler = new MockHttpMessageHandler(); + mockHandler.When(HttpMethod.Put, testFile).WithHeaders(requestHeaders).Respond(HttpStatusCode.Created); + + var session = CreateWebDavSession(mockHandler); + var success = false; + + using (var stream = new MemoryStream()) + { + using (StreamWriter wr = new StreamWriter(stream)) + { + wr.Write(uploadFileContent); + wr.Flush(); + stream.Position = 0; + success = session.UploadFileWithProgressAsync(TestFile, stream, contentType, progress).Result; + } + } + + Assert.IsTrue(progressHandlerIndicator); + Assert.IsTrue(success); + } + + #endregion Upload file + + #region Unlock + + [TestMethod] + public void UT_WebDavSesion_Unlock() + { + // We have to lock before we can unlock because the lock token information + // is managed by the WebDavSession internally. + var testFileToLock = UriHelper.CombineUrl(WebDavRootFolder, TestFile, true); + var lockRequestContent = ""; + var lockResponseContent = "infinityInfiniteopaquelocktoken:d32688a4-478f-46eb-bcc4-cfe6129a207e.96bb01d2b440d8dbhttp://127.0.0.1/webdav/TextFile1.txt"; + var infiniteTimeout = WebDavTimeoutHeaderValue.CreateInfiniteWebDavTimeout(); + var depth = WebDavDepthHeaderValue.Infinity; + var lockTokenString = ""; + + var mockHandler = new MockHttpMessageHandler(); + + var requestHeadersLock = new List> + { + new KeyValuePair(WebDavConstants.Depth, depth.ToString()), + new KeyValuePair(WebDavRequestHeader.Timeout, infiniteTimeout.ToString()) + }; + + mockHandler.When(WebDavMethod.Lock, testFileToLock).WithHeaders(requestHeadersLock).WithContent(lockRequestContent).Respond(HttpStatusCode.OK, new StringContent(lockResponseContent)); + + var requestHeadersUnlock = new List> + { + new KeyValuePair(WebDavRequestHeader.LockToken, lockTokenString) + }; + + mockHandler.When(WebDavMethod.Unlock, testFileToLock).WithHeaders(requestHeadersUnlock).Respond(HttpStatusCode.NoContent); + + var session = CreateWebDavSession(mockHandler); + var success = session.LockAsync(TestFile).Result; + + Assert.IsTrue(success); + var lockToken = new LockToken(lockTokenString); + success = session.UnlockAsync(testFileToLock).Result; + + Assert.IsTrue(success); + } + + #endregion Unlock + } +}