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);
        }
示例#2
0
        /// <summary>
        /// Sets the filesystem used by the MediaFileManager
        /// </summary>
        /// <param name="builder">A builder.</param>
        /// <param name="filesystemFactory">Factory method to create an IFileSystem implementation used in the MediaFileManager</param>
        public static IUmbracoBuilder SetMediaFileSystem(this IUmbracoBuilder builder,
                                                         Func <IServiceProvider, IFileSystem> filesystemFactory)
        {
            builder.Services.AddUnique(
                provider =>
            {
                IFileSystem filesystem = filesystemFactory(provider);
                // We need to use the Filesystems to create a shadow wrapper,
                // because shadow wrapper requires the IsScoped delegate from the FileSystems.
                // This is used by the scope provider when taking control of the filesystems.
                FileSystems fileSystems = provider.GetRequiredService <FileSystems>();
                IFileSystem shadow      = fileSystems.CreateShadowWrapper(filesystem, "media");

                return(provider.CreateInstance <MediaFileManager>(shadow));
            });
            return(builder);
        }
    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"));
    }
    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)));
    }