Files
Umbraco-CMS/src/Umbraco.Tests/IO/ShadowFileSystemTests.cs

928 lines
38 KiB
C#
Raw Normal View History

using System;
2018-11-19 14:40:59 +01:00
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Moq;
using NUnit.Framework;
2016-09-22 08:33:11 +02:00
using Umbraco.Core;
2018-11-19 14:40:59 +01:00
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
2017-05-12 14:49:44 +02:00
using Umbraco.Core.Scoping;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.IO
{
[TestFixture]
public class ShadowFileSystemTests
{
2016-10-31 11:08:28 +01:00
// tested:
// only 1 instance of this class is created
// SetUp and TearDown run before/after each test
// SetUp does not start before the previous TearDown returns
[SetUp]
public void SetUp()
2016-09-22 08:33:11 +02:00
{
2016-09-22 22:18:05 +02:00
SafeCallContext.Clear();
2016-09-22 08:33:11 +02:00
ClearFiles();
2018-11-19 14:40:59 +01:00
FileSystems.ResetShadowId();
2016-09-22 08:33:11 +02:00
}
[TearDown]
public void TearDown()
{
2016-09-22 22:18:05 +02:00
SafeCallContext.Clear();
2016-09-22 08:33:11 +02:00
ClearFiles();
2018-11-19 14:40:59 +01:00
FileSystems.ResetShadowId();
2016-09-22 08:33:11 +02:00
}
private static void ClearFiles()
{
TestHelper.DeleteDirectory(IOHelper.MapPath("FileSysTests"));
TestHelper.DeleteDirectory(IOHelper.MapPath("App_Data/TEMP/ShadowFs"));
}
private static string NormPath(string path)
{
return path.ToLowerInvariant().Replace("\\", "/");
}
[Test]
public void ShadowDeleteDirectory()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
Directory.CreateDirectory(path + "/ShadowTests/d1");
Directory.CreateDirectory(path + "/ShadowTests/d2");
var files = fs.GetFiles("");
Assert.AreEqual(0, files.Count());
var dirs = fs.GetDirectories("");
Assert.AreEqual(2, dirs.Count());
Assert.IsTrue(dirs.Contains("d1"));
Assert.IsTrue(dirs.Contains("d2"));
ss.DeleteDirectory("d1");
Assert.IsTrue(Directory.Exists(path + "/ShadowTests/d1"));
Assert.IsTrue(fs.DirectoryExists("d1"));
Assert.IsFalse(ss.DirectoryExists("d1"));
dirs = ss.GetDirectories("");
Assert.AreEqual(1, dirs.Count());
Assert.IsTrue(dirs.Contains("d2"));
}
[Test]
public void ShadowDeleteDirectoryInDir()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
Directory.CreateDirectory(path + "/ShadowTests/sub");
Directory.CreateDirectory(path + "/ShadowTests/sub/d1");
Directory.CreateDirectory(path + "/ShadowTests/sub/d2");
var files = fs.GetFiles("");
Assert.AreEqual(0, files.Count());
var dirs = ss.GetDirectories("");
Assert.AreEqual(1, dirs.Count());
Assert.IsTrue(dirs.Contains("sub"));
dirs = fs.GetDirectories("sub");
Assert.AreEqual(2, dirs.Count());
Assert.IsTrue(dirs.Contains("sub/d1"));
Assert.IsTrue(dirs.Contains("sub/d2"));
dirs = ss.GetDirectories("sub");
Assert.AreEqual(2, dirs.Count());
Assert.IsTrue(dirs.Contains("sub/d1"));
Assert.IsTrue(dirs.Contains("sub/d2"));
ss.DeleteDirectory("sub/d1");
Assert.IsTrue(Directory.Exists(path + "/ShadowTests/sub/d1"));
Assert.IsTrue(fs.DirectoryExists("sub/d1"));
Assert.IsFalse(ss.DirectoryExists("sub/d1"));
dirs = fs.GetDirectories("sub");
Assert.AreEqual(2, dirs.Count());
Assert.IsTrue(dirs.Contains("sub/d1"));
Assert.IsTrue(dirs.Contains("sub/d2"));
dirs = ss.GetDirectories("sub");
Assert.AreEqual(1, dirs.Count());
Assert.IsTrue(dirs.Contains("sub/d2"));
}
[Test]
public void ShadowDeleteFile()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
var files = fs.GetFiles("");
Assert.AreEqual(2, files.Count());
Assert.IsTrue(files.Contains("f1.txt"));
Assert.IsTrue(files.Contains("f2.txt"));
files = ss.GetFiles("");
Assert.AreEqual(2, files.Count());
Assert.IsTrue(files.Contains("f1.txt"));
Assert.IsTrue(files.Contains("f2.txt"));
var dirs = ss.GetDirectories("");
Assert.AreEqual(0, dirs.Count());
ss.DeleteFile("f1.txt");
Assert.IsTrue(File.Exists(path + "/ShadowTests/f1.txt"));
Assert.IsTrue(fs.FileExists("f1.txt"));
Assert.IsFalse(ss.FileExists("f1.txt"));
files = ss.GetFiles("");
Assert.AreEqual(1, files.Count());
Assert.IsTrue(files.Contains("f2.txt"));
}
[Test]
public void ShadowDeleteFileInDir()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
Directory.CreateDirectory(path + "/ShadowTests/sub");
File.WriteAllText(path + "/ShadowTests/sub/f1.txt", "foo");
File.WriteAllText(path + "/ShadowTests/sub/f2.txt", "foo");
var files = fs.GetFiles("");
Assert.AreEqual(0, files.Count());
files = fs.GetFiles("sub");
Assert.AreEqual(2, files.Count());
Assert.IsTrue(files.Contains("sub/f1.txt"));
Assert.IsTrue(files.Contains("sub/f2.txt"));
files = ss.GetFiles("");
Assert.AreEqual(0, files.Count());
var dirs = ss.GetDirectories("");
Assert.AreEqual(1, dirs.Count());
Assert.IsTrue(dirs.Contains("sub"));
files = ss.GetFiles("sub");
Assert.AreEqual(2, files.Count());
Assert.IsTrue(files.Contains("sub/f1.txt"));
Assert.IsTrue(files.Contains("sub/f2.txt"));
dirs = ss.GetDirectories("sub");
Assert.AreEqual(0, dirs.Count());
ss.DeleteFile("sub/f1.txt");
Assert.IsTrue(File.Exists(path + "/ShadowTests/sub/f1.txt"));
Assert.IsTrue(fs.FileExists("sub/f1.txt"));
Assert.IsFalse(ss.FileExists("sub/f1.txt"));
files = fs.GetFiles("sub");
Assert.AreEqual(2, files.Count());
Assert.IsTrue(files.Contains("sub/f1.txt"));
Assert.IsTrue(files.Contains("sub/f2.txt"));
files = ss.GetFiles("sub");
Assert.AreEqual(1, files.Count());
Assert.IsTrue(files.Contains("sub/f2.txt"));
}
[Test]
public void ShadowCantCreateFile()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
Assert.Throws<FileSecurityException>(() =>
{
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("../../f1.txt", ms);
});
}
[Test]
public void ShadowCreateFile()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
Assert.IsTrue(File.Exists(path + "/ShadowTests/f2.txt"));
Assert.IsFalse(File.Exists(path + "/ShadowSystem/f2.txt"));
Assert.IsTrue(fs.FileExists("f2.txt"));
Assert.IsTrue(ss.FileExists("f2.txt"));
Assert.IsFalse(File.Exists(path + "/ShadowTests/f1.txt"));
Assert.IsTrue(File.Exists(path + "/ShadowSystem/f1.txt"));
Assert.IsFalse(fs.FileExists("f1.txt"));
Assert.IsTrue(ss.FileExists("f1.txt"));
var files = ss.GetFiles("");
Assert.AreEqual(2, files.Count());
Assert.IsTrue(files.Contains("f1.txt"));
Assert.IsTrue(files.Contains("f2.txt"));
string content;
using (var stream = ss.OpenFile("f1.txt"))
content = new StreamReader(stream).ReadToEnd();
Assert.AreEqual("foo", content);
}
[Test]
public void ShadowCreateFileInDir()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("sub/f1.txt", ms);
Assert.IsFalse(File.Exists(path + "/ShadowTests/sub/f1.txt"));
Assert.IsTrue(File.Exists(path + "/ShadowSystem/sub/f1.txt"));
Assert.IsFalse(fs.FileExists("sub/f1.txt"));
Assert.IsTrue(ss.FileExists("sub/f1.txt"));
Assert.IsFalse(fs.DirectoryExists("sub"));
Assert.IsTrue(ss.DirectoryExists("sub"));
var dirs = fs.GetDirectories("");
Assert.AreEqual(0, dirs.Count());
dirs = ss.GetDirectories("");
Assert.AreEqual(1, dirs.Count());
Assert.IsTrue(dirs.Contains("sub"));
var files = ss.GetFiles("sub");
Assert.AreEqual(1, files.Count());
string content;
using (var stream = ss.OpenFile("sub/f1.txt"))
content = new StreamReader(stream).ReadToEnd();
Assert.AreEqual("foo", content);
}
[Test]
public void ShadowAbort()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("path/to/some/dir/f1.txt", ms);
2017-05-12 14:49:44 +02:00
// file is only written to the shadow fs
Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt"));
2017-05-12 14:49:44 +02:00
Assert.IsFalse(File.Exists(path + "/ShadowTests/path/to/some/dir/f1.txt"));
// let the shadow fs die
}
[Test]
public void ShadowComplete()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
Directory.CreateDirectory(path + "/ShadowTests/sub/sub");
File.WriteAllText(path + "/ShadowTests/sub/sub/f2.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("path/to/some/dir/f1.txt", ms);
ss.DeleteFile("sub/sub/f2.txt");
Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt"));
ss.Complete();
2017-05-12 14:49:44 +02:00
// yes we are cleaning now
//Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt")); // *not* cleaning
Assert.IsTrue(File.Exists(path + "/ShadowTests/path/to/some/dir/f1.txt"));
Assert.IsFalse(File.Exists(path + "/ShadowTests/sub/sub/f2.txt"));
}
2018-11-19 14:40:59 +01:00
class FS : FileSystemWrapper
{
public FS(IFileSystem innerFileSystem)
: base(innerFileSystem)
{ }
}
2016-09-22 08:33:11 +02:00
[Test]
public void ShadowScopeComplete()
{
var logger = Mock.Of<ILogger>();
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs");
2016-09-22 08:33:11 +02:00
Directory.CreateDirectory(path);
Directory.CreateDirectory(shadowfs);
2017-05-12 14:49:44 +02:00
var scopedFileSystems = false;
2016-09-22 08:33:11 +02:00
2018-11-19 14:40:59 +01:00
var phy = new PhysicalFileSystem(path, "ignore");
2018-11-28 11:05:41 +01:00
var container = Mock.Of<IFactory>();
2018-11-19 14:40:59 +01:00
var fileSystems = new FileSystems(container, logger) { IsScoped = () => scopedFileSystems };
2018-11-24 15:38:00 +01:00
var fs = fileSystems.GetFileSystem<FS>(phy);
2018-11-19 14:40:59 +01:00
var sw = (ShadowWrapper) fs.InnerFileSystem;
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f1.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f1.txt"));
2016-09-22 08:33:11 +02:00
Guid id;
// explicit shadow without scope does not work
sw.Shadow(id = Guid.NewGuid());
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f2.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f2.txt"));
2016-09-22 08:33:11 +02:00
sw.UnShadow(true);
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f2.txt"));
Assert.IsFalse(Directory.Exists(shadowfs + "/" + id));
2016-09-22 08:33:11 +02:00
// shadow with scope but no complete does not complete
2017-05-12 14:49:44 +02:00
scopedFileSystems = true; // pretend we have a scope
2018-11-19 14:40:59 +01:00
var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f3.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsFalse(phy.FileExists("sub/f3.txt"));
var dirs = Directory.GetDirectories(shadowfs);
2018-11-19 14:40:59 +01:00
Assert.AreEqual(1, dirs.Length);
Assert.AreEqual((shadowfs + "/" + id).Replace('\\', '/'), dirs[0].Replace('\\', '/'));
2018-11-19 14:40:59 +01:00
dirs = Directory.GetDirectories(dirs[0]);
var typedDir = dirs.FirstOrDefault(x => x.Replace('\\', '/').EndsWith("/typed"));
Assert.IsNotNull(typedDir);
dirs = Directory.GetDirectories(typedDir);
var scopedDir = dirs.FirstOrDefault(x => x.Replace('\\', '/').EndsWith("/Umbraco.Tests.IO.ShadowFileSystemTests+FS")); // this is where files go
Assert.IsNotNull(scopedDir);
2016-09-22 08:33:11 +02:00
scope.Dispose();
2017-05-12 14:49:44 +02:00
scopedFileSystems = false;
2018-11-19 14:40:59 +01:00
Assert.IsFalse(phy.FileExists("sub/f3.txt"));
TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(shadowfs + "/" + id)));
2016-09-22 08:33:11 +02:00
// shadow with scope and complete does complete
2017-05-12 14:49:44 +02:00
scopedFileSystems = true; // pretend we have a scope
2018-11-19 14:40:59 +01:00
scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f4.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsFalse(phy.FileExists("sub/f4.txt"));
Assert.AreEqual(1, Directory.GetDirectories(shadowfs).Length);
2016-09-22 08:33:11 +02:00
scope.Complete();
scope.Dispose();
2017-05-12 14:49:44 +02:00
scopedFileSystems = false;
TestHelper.TryAssert(() => Assert.AreEqual(0, Directory.GetDirectories(shadowfs).Length));
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f4.txt"));
Assert.IsFalse(Directory.Exists(shadowfs + "/" + id));
2016-09-22 08:33:11 +02:00
// test scope for "another thread"
2017-05-12 14:49:44 +02:00
scopedFileSystems = true; // pretend we have a scope
2018-11-19 14:40:59 +01:00
scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f5.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsFalse(phy.FileExists("sub/f5.txt"));
2017-05-12 14:49:44 +02:00
// pretend we're another thread w/out scope
scopedFileSystems = false;
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f6.txt", ms);
scopedFileSystems = true; // pretend we have a scope
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f6.txt")); // other thread has written out to fs
2016-09-22 08:33:11 +02:00
scope.Complete();
scope.Dispose();
2017-05-12 14:49:44 +02:00
scopedFileSystems = false;
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f5.txt"));
Assert.IsFalse(Directory.Exists(shadowfs + "/" + id));
2016-09-22 08:33:11 +02:00
}
[Test]
public void ShadowScopeCompleteWithFileConflict()
{
2017-05-12 14:49:44 +02:00
var logger = Mock.Of<ILogger>();
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs");
2016-09-22 08:33:11 +02:00
Directory.CreateDirectory(path);
2017-05-12 14:49:44 +02:00
var scopedFileSystems = false;
2018-11-19 14:40:59 +01:00
var phy = new PhysicalFileSystem(path, "ignore");
2018-11-28 11:05:41 +01:00
var container = Mock.Of<IFactory>();
2018-11-19 14:40:59 +01:00
var fileSystems = new FileSystems(container, logger) { IsScoped = () => scopedFileSystems };
2018-11-24 15:38:00 +01:00
var fs = fileSystems.GetFileSystem<FS>( phy);
2018-11-19 14:40:59 +01:00
var sw = (ShadowWrapper) fs.InnerFileSystem;
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f1.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f1.txt"));
2016-09-22 08:33:11 +02:00
Guid id;
2017-05-12 14:49:44 +02:00
scopedFileSystems = true; // pretend we have a scope
2018-11-19 14:40:59 +01:00
var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f2.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsFalse(phy.FileExists("sub/f2.txt"));
2017-05-12 14:49:44 +02:00
// pretend we're another thread w/out scope
scopedFileSystems = false;
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("bar")))
sw.AddFile("sub/f2.txt", ms);
scopedFileSystems = true; // pretend we have a scope
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f2.txt")); // other thread has written out to fs
2016-09-22 08:33:11 +02:00
scope.Complete();
scope.Dispose();
2017-05-12 14:49:44 +02:00
scopedFileSystems = false;
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f2.txt"));
TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(shadowfs + "/" + id)));
2016-09-22 08:33:11 +02:00
string text;
2018-11-19 14:40:59 +01:00
using (var s = phy.OpenFile("sub/f2.txt"))
2016-09-22 08:33:11 +02:00
using (var r = new StreamReader(s))
text = r.ReadToEnd();
// the shadow filesystem will happily overwrite anything it can
Assert.AreEqual("foo", text);
}
[Test]
public void ShadowScopeCompleteWithDirectoryConflict()
{
2017-05-12 14:49:44 +02:00
var logger = Mock.Of<ILogger>();
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs");
2016-09-22 08:33:11 +02:00
Directory.CreateDirectory(path);
2017-05-12 14:49:44 +02:00
var scopedFileSystems = false;
2018-11-19 14:40:59 +01:00
var phy = new PhysicalFileSystem(path, "ignore");
2018-11-28 11:05:41 +01:00
var container = Mock.Of<IFactory>();
2018-11-19 14:40:59 +01:00
var fileSystems = new FileSystems(container, logger) { IsScoped = () => scopedFileSystems };
2018-11-24 15:38:00 +01:00
var fs = fileSystems.GetFileSystem<FS>( phy);
2018-11-19 14:40:59 +01:00
var sw = (ShadowWrapper)fs.InnerFileSystem;
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f1.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f1.txt"));
2016-09-22 08:33:11 +02:00
Guid id;
2017-05-12 14:49:44 +02:00
scopedFileSystems = true; // pretend we have a scope
2018-11-19 14:40:59 +01:00
var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f2.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsFalse(phy.FileExists("sub/f2.txt"));
2017-05-12 14:49:44 +02:00
// pretend we're another thread w/out scope
scopedFileSystems = false;
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("bar")))
sw.AddFile("sub/f2.txt/f2.txt", ms);
scopedFileSystems = true; // pretend we have a scope
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f2.txt/f2.txt")); // other thread has written out to fs
2016-09-22 08:33:11 +02:00
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
sw.AddFile("sub/f3.txt", ms);
2018-11-19 14:40:59 +01:00
Assert.IsFalse(phy.FileExists("sub/f3.txt"));
2016-09-22 08:33:11 +02:00
2017-05-12 14:49:44 +02:00
scope.Complete();
2016-09-22 08:33:11 +02:00
try
{
// no way this can work since we're trying to write a file
// but there's now a directory with the same name on the real fs
2017-05-12 14:49:44 +02:00
scope.Dispose();
2016-09-22 08:33:11 +02:00
Assert.Fail("Expected AggregateException.");
}
catch (AggregateException ae)
{
Assert.AreEqual(1, ae.InnerExceptions.Count);
var e = ae.InnerExceptions[0];
Assert.IsNotNull(e.InnerException);
Assert.IsInstanceOf<AggregateException>(e);
ae = (AggregateException) e;
Assert.AreEqual(1, ae.InnerExceptions.Count);
e = ae.InnerExceptions[0];
Assert.IsNotNull(e.InnerException);
2017-05-12 14:49:44 +02:00
Assert.IsInstanceOf<Exception>(e.InnerException);
2016-09-22 08:33:11 +02:00
}
// still, the rest of the changes has been applied ok
2018-11-19 14:40:59 +01:00
Assert.IsTrue(phy.FileExists("sub/f3.txt"));
2016-09-22 08:33:11 +02:00
}
[Test]
public void GetFilesReturnsChildrenOnly()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
File.WriteAllText(path + "/f1.txt", "foo");
Directory.CreateDirectory(path + "/test");
File.WriteAllText(path + "/test/f2.txt", "foo");
Directory.CreateDirectory(path + "/test/inner");
File.WriteAllText(path + "/test/inner/f3.txt", "foo");
path = NormPath(path);
var files = Directory.GetFiles(path);
Assert.AreEqual(1, files.Length);
files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
Assert.AreEqual(3, files.Length);
var efiles = Directory.EnumerateFiles(path);
Assert.AreEqual(1, efiles.Count());
efiles = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories);
Assert.AreEqual(3, efiles.Count());
}
[Test]
public void DeleteDirectoryAndFiles()
{
2016-09-22 08:33:11 +02:00
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
File.WriteAllText(path + "/f1.txt", "foo");
Directory.CreateDirectory(path + "/test");
File.WriteAllText(path + "/test/f2.txt", "foo");
Directory.CreateDirectory(path + "/test/inner");
File.WriteAllText(path + "/test/inner/f3.txt", "foo");
path = NormPath(path);
TestHelper.Try(() => Directory.Delete(path, true));
TestHelper.TryAssert(() => Assert.IsFalse(File.Exists(path + "/test/inner/f3.txt")));
}
2017-05-12 14:49:44 +02:00
/// <summary>
/// Check that GetFiles will return all files on the shadow, while returning
/// just one on each of the filesystems used by the shadow.
/// </summary>
[Test]
public void ShadowGetFiles()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
// Assert
// ensure we get 2 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(2, getFiles.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, sfsFiles.Length);
}
/// <summary>
/// Check that GetFiles using the filter function with empty string will return expected results
/// </summary>
[Test]
public void ShadowGetFilesUsingEmptyFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
// Assert
// ensure we get 2 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(2, getFiles.Count());
// ensure we get 0 files when using a empty filter
var getFilesWithEmptyFilter = ss.GetFiles(string.Empty, "");
Assert.AreEqual(0, getFilesWithEmptyFilter.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, sfsFiles.Length);
}
/// <summary>
/// Check that GetFiles using the filter function with null will return expected results
/// </summary>
[Test]
public void ShadowGetFilesUsingNullFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
// Assert
// ensure we get 2 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(2, getFiles.Count());
// ensure we get 2 files when using null in filter parameter
var getFilesWithNullFilter = ss.GetFiles(string.Empty, null);
Assert.AreEqual(2, getFilesWithNullFilter.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(1, sfsFiles.Length);
}
[Test]
public void ShadowGetFilesUsingWildcardFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.doc", ms);
// Assert
// ensure we get 4 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(4, getFiles.Count());
// ensure we get only 2 of 4 files from the shadow when using filter
var getFilesWithWildcardFilter = ss.GetFiles(string.Empty, "*.doc");
Assert.AreEqual(2, getFilesWithWildcardFilter.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(2, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(2, sfsFiles.Length);
}
[Test]
public void ShadowGetFilesUsingSingleCharacterFilter()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f2.txt", "foo");
File.WriteAllText(path + "/ShadowTests/f2.doc", "foo");
File.WriteAllText(path + "/ShadowTests/f2.docx", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.txt", ms);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.doc", ms);
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f1.docx", ms);
// Assert
// ensure we get 6 files from the shadow
var getFiles = ss.GetFiles(string.Empty);
Assert.AreEqual(6, getFiles.Count());
// ensure we get only 2 of 6 files from the shadow when using filter on shadow
var getFilesWithWildcardSinglecharFilter = ss.GetFiles(string.Empty, "f1.d?c");
Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter.Count());
// ensure we get only 2 of 6 files from the shadow when using filter on disk
var getFilesWithWildcardSinglecharFilter2 = ss.GetFiles(string.Empty, "f2.d?c");
Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter2.Count());
var fsFiles = fs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(3, fsFiles.Length);
var sfsFiles = sfs.GetFiles(string.Empty).ToArray();
Assert.AreEqual(3, sfsFiles.Length);
}
/// <summary>
/// Returns the full paths of the files on the disk.
/// Note that this will be the *actual* path of the file, meaning a file existing on the initialized FS
/// will be in one location, while a file written after initializing the shadow, will exist at the
/// shadow location directory.
/// </summary>
[Test]
public void ShadowGetFullPath()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f2.txt", ms);
// Assert
var f1FullPath = ss.GetFullPath("f1.txt");
var f2FullPath = ss.GetFullPath("f2.txt");
Assert.AreEqual(Path.Combine(path, "ShadowTests", "f1.txt"), f1FullPath);
Assert.AreEqual(Path.Combine(path, "ShadowSystem", "f2.txt"), f2FullPath);
}
/// <summary>
/// Returns the path relative to the filesystem root
/// </summary>
/// <remarks>
/// This file stuff in this test is kinda irrelevant with the current implementation.
/// We do tests that the files are written to the correct places and the relative path is returned correct,
/// but GetRelativePath is currently really just string manipulation so files are not actually hit by the code.
/// Leaving the file stuff in here for now in case the method becomes more clever at some point.
/// </remarks>
[Test]
public void ShadowGetRelativePath()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f2.txt", ms);
// Assert
var f1RelativePath = ss.GetRelativePath("f1.txt");
var f2RelativePath = ss.GetRelativePath("f2.txt");
Assert.AreEqual("f1.txt", f1RelativePath);
Assert.AreEqual("f2.txt", f2RelativePath);
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt")));
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt")));
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt")));
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt")));
}
/// <summary>
/// Ensure the url returned contains the path relative to the FS root,
/// but including the rootUrl the FS was initialized with.
/// </summary>
/// <remarks>
/// This file stuff in this test is kinda irrelevant with the current implementation.
/// We do tests that the files are written to the correct places and the url is returned correct,
/// but GetUrl is currently really just string manipulation so files are not actually hit by the code.
/// Leaving the file stuff in here for now in case the method becomes more clever at some point.
/// </remarks>
[Test]
public void ShadowGetUrl()
{
// Arrange
var path = IOHelper.MapPath("FileSysTests");
Directory.CreateDirectory(path);
Directory.CreateDirectory(path + "/ShadowTests");
Directory.CreateDirectory(path + "/ShadowSystem");
var fs = new PhysicalFileSystem(path + "/ShadowTests/", "rootUrl");
var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "rootUrl");
var ss = new ShadowFileSystem(fs, sfs);
// Act
File.WriteAllText(path + "/ShadowTests/f1.txt", "foo");
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
ss.AddFile("f2.txt", ms);
// Assert
var f1Url = ss.GetUrl("f1.txt");
var f2Url = ss.GetUrl("f2.txt");
Assert.AreEqual("rootUrl/f1.txt", f1Url);
Assert.AreEqual("rootUrl/f2.txt", f2Url);
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt")));
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt")));
Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt")));
Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt")));
}
}
}