Пример #1
0
        public void ShadowScopeCompleteWithFileConflict()
        {
            var logger = Mock.Of <ILogger>();

            var path     = IOHelper.MapPath("FileSysTests");
            var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs");

            Directory.CreateDirectory(path);

            var scopedFileSystems = false;

            var phy = new PhysicalFileSystem(path, "ignore");

            var container   = Mock.Of <IFactory>();
            var fileSystems = new FileSystems(container, logger)
            {
                IsScoped = () => scopedFileSystems
            };
            var fs = fileSystems.GetFileSystem <FS>(phy);
            var sw = (ShadowWrapper)fs.InnerFileSystem;

            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f1.txt", ms);
            Assert.IsTrue(phy.FileExists("sub/f1.txt"));

            Guid id;

            scopedFileSystems = true; // pretend we have a scope
            var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());

            Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f2.txt", ms);
            Assert.IsFalse(phy.FileExists("sub/f2.txt"));

            // 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

            Assert.IsTrue(phy.FileExists("sub/f2.txt")); // other thread has written out to fs
            scope.Complete();
            scope.Dispose();
            scopedFileSystems = false;
            Assert.IsTrue(phy.FileExists("sub/f2.txt"));
            TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(shadowfs + "/" + id)));

            string text;

            using (var s = phy.OpenFile("sub/f2.txt"))
                using (var r = new StreamReader(s))
                    text = r.ReadToEnd();

            // the shadow filesystem will happily overwrite anything it can
            Assert.AreEqual("foo", text);
        }
        public void ShadowScopeCompleteWithFileConflict()
        {
            var path     = HostingEnvironment.MapPathContentRoot("FileSysTests");
            var shadowfs = HostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempData.EnsureEndsWith('/') + "ShadowFs");

            Directory.CreateDirectory(path);

            var scopedFileSystems = false;

            var phy = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, path, "ignore");

            var globalSettings = Options.Create(new GlobalSettings());
            var fileSystems    = new FileSystems(NullLoggerFactory.Instance, IOHelper, globalSettings, HostingEnvironment)
            {
                IsScoped = () => scopedFileSystems
            };
            var shadowPath = $"x/{Guid.NewGuid().ToString("N").Substring(0, 6)}";
            var sw         = fileSystems.CreateShadowWrapper(phy, shadowPath);

            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f1.txt", ms);
            Assert.IsTrue(phy.FileExists("sub/f1.txt"));

            string id;

            scopedFileSystems = true; // pretend we have a scope
            var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(HostingEnvironment));

            Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f2.txt", ms);
            Assert.IsFalse(phy.FileExists("sub/f2.txt"));

            // 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

            Assert.IsTrue(phy.FileExists("sub/f2.txt")); // other thread has written out to fs
            scope.Complete();
            scope.Dispose();
            scopedFileSystems = false;
            Assert.IsTrue(phy.FileExists("sub/f2.txt"));
            TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(shadowfs + "/" + id)));

            string text;

            using (var s = phy.OpenFile("sub/f2.txt"))
                using (var r = new StreamReader(s))
                    text = r.ReadToEnd();

            // the shadow filesystem will happily overwrite anything it can
            Assert.AreEqual("foo", text);
        }
        public void ShadowScopeCompleteWithFileConflict()
        {
            var path    = IOHelper.MapPath("FileSysTests");
            var appdata = IOHelper.MapPath("App_Data");

            Directory.CreateDirectory(path);

            var scopedFileSystems = false;
            var scopeProvider     = MockScopeProvider(() => scopedFileSystems);

            var fs  = new PhysicalFileSystem(path, "ignore");
            var sw  = new ShadowWrapper(fs, "shadow", scopeProvider);
            var swa = new[] { sw };

            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f1.txt", ms);
            Assert.IsTrue(fs.FileExists("sub/f1.txt"));

            Guid id;

            scopedFileSystems = true; // pretend we have a scope
            var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa);

            Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f2.txt", ms);
            Assert.IsFalse(fs.FileExists("sub/f2.txt"));

            // 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

            Assert.IsTrue(fs.FileExists("sub/f2.txt")); // other thread has written out to fs
            scope.Complete();
            scope.Dispose();
            scopedFileSystems = false;
            Assert.IsTrue(fs.FileExists("sub/f2.txt"));
            TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)));

            string text;

            using (var s = fs.OpenFile("sub/f2.txt"))
                using (var r = new StreamReader(s))
                    text = r.ReadToEnd();

            // the shadow filesystem will happily overwrite anything it can
            Assert.AreEqual("foo", text);
        }
Пример #4
0
        public void ShadowScopeCompleteWithDirectoryConflict()
        {
            var logger = Mock.Of <ILogger>();

            var path     = IOHelper.MapPath("FileSysTests");
            var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs");

            Directory.CreateDirectory(path);

            var scopedFileSystems = false;

            var phy = new PhysicalFileSystem(path, "ignore");

            var container   = Mock.Of <IFactory>();
            var fileSystems = new FileSystems(container, logger)
            {
                IsScoped = () => scopedFileSystems
            };
            var fs = fileSystems.GetFileSystem <FS>(phy);
            var sw = (ShadowWrapper)fs.InnerFileSystem;

            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f1.txt", ms);
            Assert.IsTrue(phy.FileExists("sub/f1.txt"));

            Guid id;

            scopedFileSystems = true; // pretend we have a scope
            var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());

            Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f2.txt", ms);
            Assert.IsFalse(phy.FileExists("sub/f2.txt"));

            // 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

            Assert.IsTrue(phy.FileExists("sub/f2.txt/f2.txt")); // other thread has written out to fs

            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f3.txt", ms);
            Assert.IsFalse(phy.FileExists("sub/f3.txt"));

            scope.Complete();

            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
                scope.Dispose();
                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);
                Assert.IsInstanceOf <Exception>(e.InnerException);
            }

            // still, the rest of the changes has been applied ok
            Assert.IsTrue(phy.FileExists("sub/f3.txt"));
        }
Пример #5
0
        public void ShadowScopeComplete()
        {
            var logger = Mock.Of <ILogger>();

            var path     = IOHelper.MapPath("FileSysTests");
            var shadowfs = IOHelper.MapPath("App_Data/TEMP/ShadowFs");

            Directory.CreateDirectory(path);
            Directory.CreateDirectory(shadowfs);

            var scopedFileSystems = false;

            var phy = new PhysicalFileSystem(path, "ignore");

            var container   = Mock.Of <IFactory>();
            var fileSystems = new FileSystems(container, logger)
            {
                IsScoped = () => scopedFileSystems
            };
            var fs = fileSystems.GetFileSystem <FS>(phy);
            var sw = (ShadowWrapper)fs.InnerFileSystem;

            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f1.txt", ms);
            Assert.IsTrue(phy.FileExists("sub/f1.txt"));

            Guid id;

            // explicit shadow without scope does not work
            sw.Shadow(id = Guid.NewGuid());
            Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f2.txt", ms);
            Assert.IsTrue(phy.FileExists("sub/f2.txt"));
            sw.UnShadow(true);
            Assert.IsTrue(phy.FileExists("sub/f2.txt"));
            Assert.IsFalse(Directory.Exists(shadowfs + "/" + id));

            // shadow with scope but no complete does not complete
            scopedFileSystems = true; // pretend we have a scope
            var scope = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());

            Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f3.txt", ms);
            Assert.IsFalse(phy.FileExists("sub/f3.txt"));
            var dirs = Directory.GetDirectories(shadowfs);

            Assert.AreEqual(1, dirs.Length);
            Assert.AreEqual((shadowfs + "/" + id).Replace('\\', '/'), dirs[0].Replace('\\', '/'));
            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);
            scope.Dispose();
            scopedFileSystems = false;
            Assert.IsFalse(phy.FileExists("sub/f3.txt"));
            TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(shadowfs + "/" + id)));

            // shadow with scope and complete does complete
            scopedFileSystems = true; // pretend we have a scope
            scope             = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
            Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f4.txt", ms);
            Assert.IsFalse(phy.FileExists("sub/f4.txt"));
            Assert.AreEqual(1, Directory.GetDirectories(shadowfs).Length);
            scope.Complete();
            scope.Dispose();
            scopedFileSystems = false;
            TestHelper.TryAssert(() => Assert.AreEqual(0, Directory.GetDirectories(shadowfs).Length));
            Assert.IsTrue(phy.FileExists("sub/f4.txt"));
            Assert.IsFalse(Directory.Exists(shadowfs + "/" + id));

            // test scope for "another thread"

            scopedFileSystems = true; // pretend we have a scope
            scope             = new ShadowFileSystems(fileSystems, id = Guid.NewGuid());
            Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f5.txt", ms);
            Assert.IsFalse(phy.FileExists("sub/f5.txt"));

            // 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

            Assert.IsTrue(phy.FileExists("sub/f6.txt")); // other thread has written out to fs
            scope.Complete();
            scope.Dispose();
            scopedFileSystems = false;
            Assert.IsTrue(phy.FileExists("sub/f5.txt"));
            Assert.IsFalse(Directory.Exists(shadowfs + "/" + id));
        }
        public void ShadowScopeComplete()
        {
            var path    = IOHelper.MapPath("FileSysTests");
            var appdata = IOHelper.MapPath("App_Data");

            Directory.CreateDirectory(path);
            Directory.CreateDirectory(appdata);

            var scopedFileSystems = false;
            var scopeProvider     = MockScopeProvider(() => scopedFileSystems);

            var fs  = new PhysicalFileSystem(path, "ignore");
            var sw  = new ShadowWrapper(fs, "shadow", scopeProvider);
            var swa = new[] { sw };

            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f1.txt", ms);
            Assert.IsTrue(fs.FileExists("sub/f1.txt"));

            Guid id;

            // explicit shadow without scope does not work
            sw.Shadow(id = Guid.NewGuid());
            Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f2.txt", ms);
            Assert.IsTrue(fs.FileExists("sub/f2.txt"));
            sw.UnShadow(true);
            Assert.IsTrue(fs.FileExists("sub/f2.txt"));
            Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));

            // shadow with scope but no complete does not complete
            scopedFileSystems = true; // pretend we have a scope
            var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa);

            Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f3.txt", ms);
            Assert.IsFalse(fs.FileExists("sub/f3.txt"));
            Assert.AreEqual(1, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length);
            scope.Dispose();
            scopedFileSystems = false;
            Assert.IsFalse(fs.FileExists("sub/f3.txt"));
            Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));

            // shadow with scope and complete does complete
            scopedFileSystems = true; // pretend we have a scope
            scope             = new ShadowFileSystems(id = Guid.NewGuid(), swa);
            Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f4.txt", ms);
            Assert.IsFalse(fs.FileExists("sub/f4.txt"));
            Assert.AreEqual(1, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length);
            scope.Complete();
            scope.Dispose();
            scopedFileSystems = false;
            TestHelper.TryAssert(() => Assert.AreEqual(0, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length));
            Assert.IsTrue(fs.FileExists("sub/f4.txt"));
            Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));

            // test scope for "another thread"

            scopedFileSystems = true; // pretend we have a scope
            scope             = new ShadowFileSystems(id = Guid.NewGuid(), swa);
            Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
                sw.AddFile("sub/f5.txt", ms);
            Assert.IsFalse(fs.FileExists("sub/f5.txt"));

            // 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

            Assert.IsTrue(fs.FileExists("sub/f6.txt")); // other thread has written out to fs
            scope.Complete();
            scope.Dispose();
            scopedFileSystems = false;
            Assert.IsTrue(fs.FileExists("sub/f5.txt"));
            Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id));
        }
 public void TearDown()
 {
     SafeCallContext.Clear();
     ClearFiles();
     ShadowFileSystems.ResetId();
 }
Пример #8
0
    public void ShadowScopeCompleteWithDirectoryConflict()
    {
        var path     = HostingEnvironment.MapPathContentRoot("FileSysTests");
        var shadowfs =
            HostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempData.EnsureEndsWith('/') +
                                                  "ShadowFs");

        Directory.CreateDirectory(path);

        var scopedFileSystems = false;

        var phy = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, path, "ignore");

        var globalSettings = Options.Create(new GlobalSettings());
        var fileSystems    =
            new FileSystems(NullLoggerFactory.Instance, IOHelper, globalSettings, HostingEnvironment)
        {
            IsScoped = () => scopedFileSystems
        };
        var shadowPath = $"x/{Guid.NewGuid().ToString("N").Substring(0, 6)}";
        var sw         = fileSystems.CreateShadowWrapper(phy, shadowPath);

        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
        {
            sw.AddFile("sub/f1.txt", ms);
        }

        Assert.IsTrue(phy.FileExists("sub/f1.txt"));

        string id;

        scopedFileSystems = true; // pretend we have a scope
        var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(HostingEnvironment));

        Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
        {
            sw.AddFile("sub/f2.txt", ms);
        }

        Assert.IsFalse(phy.FileExists("sub/f2.txt"));

        // 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

        Assert.IsTrue(phy.FileExists("sub/f2.txt/f2.txt")); // other thread has written out to fs

        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
        {
            sw.AddFile("sub/f3.txt", ms);
        }

        Assert.IsFalse(phy.FileExists("sub/f3.txt"));

        scope.Complete();

        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
            scope.Dispose();
            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);
            Assert.IsInstanceOf <Exception>(e.InnerException);
        }

        // still, the rest of the changes has been applied ok
        Assert.IsTrue(phy.FileExists("sub/f3.txt"));
    }
Пример #9
0
    public void ShadowScopeComplete()
    {
        var loggerFactory = NullLoggerFactory.Instance;
        var path          = HostingEnvironment.MapPathContentRoot("FileSysTests");
        var shadowfs      =
            HostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempData.EnsureEndsWith('/') +
                                                  "ShadowFs");

        Directory.CreateDirectory(path);
        Directory.CreateDirectory(shadowfs);

        var scopedFileSystems = false;

        var phy = new PhysicalFileSystem(IOHelper, HostingEnvironment, Logger, path, "ignore");

        var globalSettings = Options.Create(new GlobalSettings());
        var fileSystems    =
            new FileSystems(loggerFactory, IOHelper, globalSettings, HostingEnvironment)
        {
            IsScoped = () => scopedFileSystems
        };
        var shadowPath = $"x/{Guid.NewGuid().ToString("N").Substring(0, 6)}";
        var sw         = (ShadowWrapper)fileSystems.CreateShadowWrapper(phy, shadowPath);

        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
        {
            sw.AddFile("sub/f1.txt", ms);
        }

        Assert.IsTrue(phy.FileExists("sub/f1.txt"));

        string id;

        // explicit shadow without scope does not work
        sw.Shadow(id = ShadowWrapper.CreateShadowId(HostingEnvironment));
        Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
        {
            sw.AddFile("sub/f2.txt", ms);
        }

        Assert.IsTrue(phy.FileExists("sub/f2.txt"));
        sw.UnShadow(true);
        Assert.IsTrue(phy.FileExists("sub/f2.txt"));
        Assert.IsFalse(Directory.Exists(shadowfs + "/" + id));

        // shadow with scope but no complete does not complete
        scopedFileSystems = true; // pretend we have a scope
        var scope = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(HostingEnvironment));

        Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
        {
            sw.AddFile("sub/f3.txt", ms);
        }

        Assert.IsFalse(phy.FileExists("sub/f3.txt"));
        var dirs = Directory.GetDirectories(shadowfs);

        Assert.AreEqual(1, dirs.Length);
        Assert.AreEqual((shadowfs + "/" + id).Replace('\\', '/'), dirs[0].Replace('\\', '/'));
        dirs = Directory.GetDirectories(dirs[0]);
        var typedDir = dirs.FirstOrDefault(x => x.Replace('\\', '/').EndsWith("/x"));

        Assert.IsNotNull(typedDir);
        dirs = Directory.GetDirectories(typedDir);
        var scopedDir =
            dirs.FirstOrDefault(x => x.Replace('\\', '/').EndsWith("/" + shadowPath)); // this is where files go

        Assert.IsNotNull(scopedDir);
        scope.Dispose();
        scopedFileSystems = false;
        Assert.IsFalse(phy.FileExists("sub/f3.txt"));
        TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(shadowfs + "/" + id)));

        // shadow with scope and complete does complete
        scopedFileSystems = true; // pretend we have a scope
        scope             = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(HostingEnvironment));
        Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
        {
            sw.AddFile("sub/f4.txt", ms);
        }

        Assert.IsFalse(phy.FileExists("sub/f4.txt"));
        Assert.AreEqual(1, Directory.GetDirectories(shadowfs).Length);
        scope.Complete();
        scope.Dispose();
        scopedFileSystems = false;
        TestHelper.TryAssert(() => Assert.AreEqual(0, Directory.GetDirectories(shadowfs).Length));
        Assert.IsTrue(phy.FileExists("sub/f4.txt"));
        Assert.IsFalse(Directory.Exists(shadowfs + "/" + id));

        // test scope for "another thread"

        scopedFileSystems = true; // pretend we have a scope
        scope             = new ShadowFileSystems(fileSystems, id = ShadowWrapper.CreateShadowId(HostingEnvironment));
        Assert.IsTrue(Directory.Exists(shadowfs + "/" + id));
        using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo")))
        {
            sw.AddFile("sub/f5.txt", ms);
        }

        Assert.IsFalse(phy.FileExists("sub/f5.txt"));

        // 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

        Assert.IsTrue(phy.FileExists("sub/f6.txt")); // other thread has written out to fs
        scope.Complete();
        scope.Dispose();
        scopedFileSystems = false;
        Assert.IsTrue(phy.FileExists("sub/f5.txt"));
        TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(shadowfs + "/" + id)));
    }