public void WrapsIOExceptionsDuringWrite()
        {
            MockFileSystem      fs  = new MockFileSystem();
            FileSystemTaskQueue dut = CreateFileBasedQueue(fs, Item1EntryText);

            dut.IsEmpty.ShouldBeFalse();

            fs.File.TruncateWrites = true;

            Assert.Throws <FileBasedCollectionException>(() => dut.EnqueueAndFlush(Item2Payload));

            fs.File.TruncateWrites = false;
            fs.File.ReadAt(fs.File.Length - 2, 2).ShouldNotEqual("\r\n", "Bad Test: The file is supposed to be corrupt.");

            string error;

            FileSystemTaskQueue.TryCreate(null, MockEntryFileName, fs, out dut, out error).ShouldEqual(true);
            dut.IsEmpty.ShouldBeFalse();
            using (dut)
            {
                FileSystemTask output;
                dut.TryPeek(out output).ShouldEqual(true);
                output.ShouldEqual(Item1Payload);
                dut.DequeueAndFlush(output);
            }

            dut.IsEmpty.ShouldBeTrue();
        }
        public void StoresDeleteRecord()
        {
            const string DeleteRecord = "D 1\r\n";

            MockFileSystem      fs  = new MockFileSystem();
            FileSystemTaskQueue dut = CreateFileBasedQueue(fs, Item1EntryText);

            dut.IsEmpty.ShouldBeFalse();

            // Add a second entry to keep FileBasedQueue from setting the stream length to 0
            dut.EnqueueAndFlush(Item2Payload);
            dut.IsEmpty.ShouldBeFalse();

            fs.File.ReadAsString().ShouldEqual(Item1EntryText + Item2EntryText);
            fs.File.ReadAt(fs.File.Length - 2, 2).ShouldEqual("\r\n");

            dut.DequeueAndFlush(Item1Payload);
            dut.IsEmpty.ShouldBeFalse();
            dut.Count.ShouldEqual(1);

            FileSystemTask item;

            dut.TryPeek(out item).ShouldEqual(true);
            item.ShouldEqual(Item2Payload);
            dut.IsEmpty.ShouldBeFalse();
            dut.Count.ShouldEqual(1);

            fs.File.Length.ShouldEqual(Encoding.UTF8.GetByteCount(Item1EntryText) + Item2EntryText.Length + DeleteRecord.Length);
            fs.File.ReadAt(Encoding.UTF8.GetByteCount(Item1EntryText) + Item2EntryText.Length, DeleteRecord.Length).ShouldEqual(DeleteRecord);
        }
        public void RecoversWhenCorrupt()
        {
            MockFileSystem      fs  = new MockFileSystem();
            FileSystemTaskQueue dut = CreateFileBasedQueue(fs, CorruptEntryText);

            fs.File.ReadAsString().ShouldEqual(Item1EntryText);
            dut.Count.ShouldEqual(1);
        }
        public void TruncatesWhenEmpty()
        {
            MockFileSystem      fs  = new MockFileSystem();
            FileSystemTaskQueue dut = CreateFileBasedQueue(fs, Item1EntryText);

            dut.DequeueAndFlush(Item1Payload);

            fs.File.Length.ShouldEqual(0);
        }
        public void StoresAddRecord()
        {
            MockFileSystem      fs  = new MockFileSystem();
            FileSystemTaskQueue dut = CreateFileBasedQueue(fs, string.Empty);

            dut.EnqueueAndFlush(Item1Payload);

            fs.File.ReadAsString().ShouldEqual(Item1EntryText);
        }
        private static FileSystemTaskQueue CreateFileBasedQueue(MockFileSystem fs, string initialContents)
        {
            fs.File         = new ReusableMemoryStream(initialContents);
            fs.ExpectedPath = MockEntryFileName;

            string error;
            FileSystemTaskQueue dut;

            FileSystemTaskQueue.TryCreate(null, MockEntryFileName, fs, out dut, out error).ShouldEqual(true, error);
            dut.ShouldNotBeNull();
            return(dut);
        }
        public void TryPeekDoesNotDequeue()
        {
            MockFileSystem      fs  = new MockFileSystem();
            FileSystemTaskQueue dut = CreateFileBasedQueue(fs, Item1EntryText);

            for (int i = 0; i < 5; ++i)
            {
                FileSystemTask item;
                dut.TryPeek(out item).ShouldEqual(true);
                item.ShouldEqual(Item1Payload);
            }

            fs.File.ReadAsString().ShouldEqual(Item1EntryText);
        }
        public void ReturnsFalseWhenOpenFails()
        {
            MockFileSystem fs = new MockFileSystem();

            fs.File            = new ReusableMemoryStream(string.Empty);
            fs.ThrowDuringOpen = true;

            string error;
            FileSystemTaskQueue dut;

            FileSystemTaskQueue.TryCreate(null, MockEntryFileName, fs, out dut, out error).ShouldEqual(false);
            dut.ShouldBeNull();
            error.ShouldNotBeNull();
        }
        public override IssueType HasIssue(List <string> messages)
        {
            string error;
            FileSystemTaskQueue instance;

            if (!FileSystemTaskQueue.TryCreate(
                    this.Tracer,
                    this.dataPath,
                    new PhysicalFileSystem(),
                    out instance,
                    out error))
            {
                messages.Add("Failed to read background operations: " + error);
                return(IssueType.CantFix);
            }

            return(IssueType.None);
        }
        private bool UpdateBackgroundOperations(ITracer tracer, string dotGVFSRoot)
        {
            string esentBackgroundOpsFolder = Path.Combine(dotGVFSRoot, EsentBackgroundOpsFolder);

            if (Directory.Exists(esentBackgroundOpsFolder))
            {
                string newBackgroundOpsFolder = Path.Combine(dotGVFSRoot, GVFSConstants.DotGVFS.Databases.BackgroundFileSystemTasks);
                try
                {
                    using (PersistentDictionary <long, GVFltCallbacks.BackgroundGitUpdate> oldBackgroundOps =
                               new PersistentDictionary <long, GVFltCallbacks.BackgroundGitUpdate>(esentBackgroundOpsFolder))
                    {
                        string error;
                        FileSystemTaskQueue newBackgroundOps;
                        if (!FileSystemTaskQueue.TryCreate(
                                tracer,
                                newBackgroundOpsFolder,
                                new PhysicalFileSystem(),
                                out newBackgroundOps,
                                out error))
                        {
                            tracer.RelatedError("Failed to create new background operations folder: " + error);
                            return(false);
                        }

                        using (newBackgroundOps)
                        {
                            foreach (KeyValuePair <long, GVFltCallbacks.BackgroundGitUpdate> kvp in oldBackgroundOps)
                            {
                                tracer.RelatedInfo("Copying ESENT entry: {0} = {1}", kvp.Key, kvp.Value);
                                newBackgroundOps.EnqueueAndFlush(
                                    new FileSystemTask(
                                        (FileSystemTask.OperationType)kvp.Value.Operation,
                                        kvp.Value.VirtualPath,
                                        kvp.Value.OldVirtualPath));
                            }
                        }
                    }
                }
                catch (IOException ex)
                {
                    tracer.RelatedError("Could not write to new background operations: " + ex.Message);
                    return(false);
                }
                catch (EsentException ex)
                {
                    tracer.RelatedError("BackgroundOperations appears to be from an older version of GVFS and corrupted: " + ex.Message);
                    return(false);
                }

                string backupName;
                if (this.TryRenameFolderForDelete(tracer, esentBackgroundOpsFolder, out backupName))
                {
                    // If this fails, we leave behind cruft, but there's no harm because we renamed.
                    this.TryDeleteFolder(tracer, backupName);
                    return(true);
                }
                else
                {
                    // To avoid double upgrading, we should rollback if we can't rename the old data
                    this.TryDeleteFile(tracer, RepoMetadata.Instance.DataFilePath);
                    return(false);
                }
            }

            return(true);
        }