Example #1
0
        public void DehydrateShouldFailIfLocalCacheNotInMetadata()
        {
            this.Enlistment.UnmountGVFS();

            string majorVersion;
            string minorVersion;

            GVFSHelpers.GetPersistedDiskLayoutVersion(this.Enlistment.DotGVFSRoot, out majorVersion, out minorVersion);
            string objectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(this.Enlistment.DotGVFSRoot).ShouldNotBeNull();

            string metadataPath       = Path.Combine(this.Enlistment.DotGVFSRoot, GVFSHelpers.RepoMetadataName);
            string metadataBackupPath = metadataPath + ".backup";

            this.fileSystem.MoveFile(metadataPath, metadataBackupPath);

            this.fileSystem.CreateEmptyFile(metadataPath);
            GVFSHelpers.SaveDiskLayoutVersion(this.Enlistment.DotGVFSRoot, majorVersion, minorVersion);
            GVFSHelpers.SaveGitObjectsRoot(this.Enlistment.DotGVFSRoot, objectsRoot);

            this.DehydrateShouldFail("Failed to determine local cache path from repo metadata", noStatus: true);

            this.fileSystem.DeleteFile(metadataPath);
            this.fileSystem.MoveFile(metadataBackupPath, metadataPath);

            this.Enlistment.MountGVFS();
        }
Example #2
0
        public void DeleteCacheDuringHydrations()
        {
            GVFSFunctionalTestEnlistment enlistment1 = this.CloneAndMountEnlistment();

            string objectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(enlistment1.DotGVFSRoot).ShouldNotBeNull();

            objectsRoot.ShouldBeADirectory(this.fileSystem);

            Task task1 = Task.Run(() =>
            {
                this.HydrateEntireRepo(enlistment1);
            });

            while (!task1.IsCompleted)
            {
                try
                {
                    // Delete objectsRoot rather than this.localCachePath as the blob sizes database cannot be deleted while GVFS is mounted
                    this.DeleteDirectoryWithUnlimitedRetries(objectsRoot);
                    Thread.Sleep(100);
                }
                catch (IOException)
                {
                    // Hydration may have handles into the cache, so failing this delete is expected.
                }
            }

            task1.Exception.ShouldBeNull();

            enlistment1.Status().ShouldContain("Mount status: Ready");
        }
Example #3
0
        private void AlternatesFileShouldHaveGitObjectsRoot(GVFSFunctionalTestEnlistment enlistment)
        {
            string objectsRoot            = GVFSHelpers.GetPersistedGitObjectsRoot(enlistment.DotGVFSRoot);
            string alternatesFileContents = Path.Combine(enlistment.RepoRoot, ".git", "objects", "info", "alternates").ShouldBeAFile(this.fileSystem).WithContents();

            alternatesFileContents.ShouldEqual(objectsRoot);
        }
Example #4
0
        public void MountReusesLocalCacheKeyWhenGitObjectsRootDeleted()
        {
            GVFSFunctionalTestEnlistment enlistment = this.CloneAndMountEnlistment();

            enlistment.UnmountGVFS();

            // Find the current git objects root and ensure it's on disk
            string objectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(enlistment.DotGVFSRoot).ShouldNotBeNull();

            objectsRoot.ShouldBeADirectory(this.fileSystem);

            string mappingFilePath     = Path.Combine(enlistment.LocalCacheRoot, "mapping.dat");
            string mappingFileContents = this.fileSystem.ReadAllText(mappingFilePath);

            mappingFileContents.Length.ShouldNotEqual(0, "mapping.dat should not be empty");

            // Delete the git objects root folder, mount should re-create it and the mapping.dat file should not change
            this.DeleteDirectoryWithUnlimitedRetries(objectsRoot);

            enlistment.MountGVFS();

            GVFSHelpers.GetPersistedGitObjectsRoot(enlistment.DotGVFSRoot).ShouldEqual(objectsRoot);
            objectsRoot.ShouldBeADirectory(this.fileSystem);
            mappingFilePath.ShouldBeAFile(this.fileSystem).WithContents(mappingFileContents);

            this.AlternatesFileShouldHaveGitObjectsRoot(enlistment);
        }
        public void MountSetsGitObjectsRootToLegacyDotGVFSCache()
        {
            this.Enlistment.UnmountGVFS();

            // Delete the existing repo metadata
            string versionJsonPath = Path.Combine(this.Enlistment.DotGVFSRoot, GVFSHelpers.RepoMetadataName);

            versionJsonPath.ShouldBeAFile(this.fileSystem);
            this.fileSystem.DeleteFile(versionJsonPath);

            // "11" was the last version before the introduction of a volume wide GVFS cache
            string metadataPath = Path.Combine(this.Enlistment.DotGVFSRoot, GVFSHelpers.RepoMetadataName);

            this.fileSystem.CreateEmptyFile(metadataPath);
            GVFSHelpers.SaveDiskLayoutVersion(this.Enlistment.DotGVFSRoot, "11", "0");

            // Create the legacy cache location: <root>\.gvfs\gitObjectCache
            string legacyGitObjectsCachePath = Path.Combine(this.Enlistment.DotGVFSRoot, "gitObjectCache");

            this.fileSystem.CreateDirectory(legacyGitObjectsCachePath);

            this.Enlistment.MountGVFS();

            this.ValidatePersistedVersionMatchesCurrentVersion();

            GVFSHelpers.GetPersistedLocalCacheRoot(this.Enlistment.DotGVFSRoot)
            .ShouldEqual(string.Empty, "LocalCacheRoot should be an empty string when upgrading from a version prior to 12");

            GVFSHelpers.GetPersistedGitObjectsRoot(this.Enlistment.DotGVFSRoot)
            .ShouldEqual(legacyGitObjectsCachePath);
        }
Example #6
0
        public void DeleteObjectsCacheAndCacheMappingBeforeMount()
        {
            GVFSFunctionalTestEnlistment enlistment1 = this.CloneAndMountEnlistment();
            GVFSFunctionalTestEnlistment enlistment2 = this.CloneAndMountEnlistment();

            enlistment1.UnmountGVFS();

            string objectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(enlistment1.DotGVFSRoot).ShouldNotBeNull();

            objectsRoot.ShouldBeADirectory(this.fileSystem);
            this.DeleteDirectoryWithUnlimitedRetries(objectsRoot);

            string metadataPath = Path.Combine(this.localCachePath, "mapping.dat");

            metadataPath.ShouldBeAFile(this.fileSystem);
            this.fileSystem.DeleteFile(metadataPath);

            enlistment1.MountGVFS();

            Task task1 = Task.Run(() => this.HydrateRootFolder(enlistment1));
            Task task2 = Task.Run(() => this.HydrateRootFolder(enlistment2));

            task1.Wait();
            task2.Wait();
            task1.Exception.ShouldBeNull();
            task2.Exception.ShouldBeNull();

            enlistment1.Status().ShouldContain("Mount status: Ready");
            enlistment2.Status().ShouldContain("Mount status: Ready");

            this.AlternatesFileShouldHaveGitObjectsRoot(enlistment1);
            this.AlternatesFileShouldHaveGitObjectsRoot(enlistment2);
        }
        private void RunEsentRepoMetadataUpgradeTest(string sourceVersion)
        {
            this.Enlistment.UnmountGVFS();

            // Delete the existing repo metadata
            string versionJsonPath = Path.Combine(this.Enlistment.DotGVFSRoot, GVFSHelpers.RepoMetadataName);

            versionJsonPath.ShouldBeAFile(this.fileSystem);
            this.fileSystem.DeleteFile(versionJsonPath);

            ESENTDatabase.SaveDiskLayoutVersionAsEsentDatabase(this.Enlistment.DotGVFSRoot, sourceVersion);
            string esentDatabasePath = Path.Combine(this.Enlistment.DotGVFSRoot, ESENTDatabase.EsentRepoMetadataFolder);

            esentDatabasePath.ShouldBeADirectory(this.fileSystem);

            // We should be able to mount, and there should no longer be any Esent Repo Metadata
            this.Enlistment.MountGVFS();
            esentDatabasePath.ShouldNotExistOnDisk(this.fileSystem);
            versionJsonPath.ShouldBeAFile(this.fileSystem);

            this.ValidatePersistedVersionMatchesCurrentVersion();

            GVFSHelpers.GetPersistedLocalCacheRoot(this.Enlistment.DotGVFSRoot)
            .ShouldEqual(string.Empty, "LocalCacheRoot should be an empty string when upgrading from a version prior to 12");

            // We're starting with fresh enlisments, and so the legacy cache location: <root>\.gvfs\gitObjectCache should not be on disk
            Path.Combine(this.Enlistment.DotGVFSRoot, @".gvfs\gitObjectCache").ShouldNotExistOnDisk(this.fileSystem);

            // The upgrader should set GitObjectsRoot to src\.git\objects (because the legacy cache location is not on disk)
            GVFSHelpers.GetPersistedGitObjectsRoot(this.Enlistment.DotGVFSRoot)
            .ShouldNotBeNull("GitObjectsRoot should not be null")
            .ShouldEqual(Path.Combine(this.Enlistment.RepoRoot, @".git\objects"));
        }
Example #8
0
        public void CloneWithDefaultLocalCacheLocation()
        {
            FileSystemRunner fileSystem    = FileSystemRunner.DefaultRunner;
            string           homeDirectory = Environment.GetEnvironmentVariable("HOME");

            homeDirectory.ShouldBeADirectory(fileSystem);

            string newEnlistmentRoot = GVFSFunctionalTestEnlistment.GetUniqueEnlistmentRoot();

            ProcessStartInfo processInfo = new ProcessStartInfo(GVFSTestConfig.PathToGVFS);

            processInfo.Arguments              = $"clone {Properties.Settings.Default.RepoToClone} {newEnlistmentRoot} --no-mount --no-prefetch";
            processInfo.WindowStyle            = ProcessWindowStyle.Hidden;
            processInfo.CreateNoWindow         = true;
            processInfo.UseShellExecute        = false;
            processInfo.RedirectStandardOutput = true;

            ProcessResult result = ProcessHelper.Run(processInfo);

            result.ExitCode.ShouldEqual(0, result.Errors);

            string dotGVFSRoot = Path.Combine(newEnlistmentRoot, GVFSTestConfig.DotGVFSRoot);

            dotGVFSRoot.ShouldBeADirectory(fileSystem);
            string localCacheRoot = GVFSHelpers.GetPersistedLocalCacheRoot(dotGVFSRoot);
            string gitObjectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(dotGVFSRoot);

            string defaultGVFSCacheRoot = Path.Combine(homeDirectory, ".gvfsCache");

            localCacheRoot.StartsWith(defaultGVFSCacheRoot, StringComparison.Ordinal).ShouldBeTrue($"Local cache root did not default to using {homeDirectory}");
            gitObjectsRoot.StartsWith(defaultGVFSCacheRoot, StringComparison.Ordinal).ShouldBeTrue($"Git objects root did not default to using {homeDirectory}");

            RepositoryHelpers.DeleteTestDirectory(newEnlistmentRoot);
        }
        public void MountUpgradesPreSharedCacheLocalSizes()
        {
            this.Enlistment.UnmountGVFS();

            // Delete the existing repo metadata
            string versionJsonPath = Path.Combine(this.Enlistment.DotGVFSRoot, GVFSHelpers.RepoMetadataName);

            versionJsonPath.ShouldBeAFile(this.fileSystem);
            this.fileSystem.DeleteFile(versionJsonPath);

            // "11" was the last version before the introduction of a volume wide GVFS cache
            string metadataPath = Path.Combine(this.Enlistment.DotGVFSRoot, GVFSHelpers.RepoMetadataName);

            this.fileSystem.CreateEmptyFile(metadataPath);
            GVFSHelpers.SaveDiskLayoutVersion(this.Enlistment.DotGVFSRoot, "11", "0");

            // Create the legacy cache location: <root>\.gvfs\gitObjectCache
            string legacyGitObjectsCachePath = Path.Combine(this.Enlistment.DotGVFSRoot, "gitObjectCache");

            this.fileSystem.CreateDirectory(legacyGitObjectsCachePath);

            // Create a legacy PersistedDictionary sizes database
            List <KeyValuePair <string, long> > entries = new List <KeyValuePair <string, long> >()
            {
                new KeyValuePair <string, long>(new string('0', 40), 1),
                new KeyValuePair <string, long>(new string('1', 40), 2),
                new KeyValuePair <string, long>(new string('2', 40), 4),
                new KeyValuePair <string, long>(new string('3', 40), 8),
            };

            ESENTDatabase.CreateEsentBlobSizesDatabase(this.Enlistment.DotGVFSRoot, entries);

            this.Enlistment.MountGVFS();

            this.ValidatePersistedVersionMatchesCurrentVersion();

            GVFSHelpers.GetPersistedLocalCacheRoot(this.Enlistment.DotGVFSRoot)
            .ShouldEqual(string.Empty, "LocalCacheRoot should be an empty string when upgrading from a version prior to 12");

            GVFSHelpers.GetPersistedGitObjectsRoot(this.Enlistment.DotGVFSRoot)
            .ShouldEqual(legacyGitObjectsCachePath);

            string newBlobSizesRoot = Path.Combine(this.Enlistment.DotGVFSRoot, DatabasesFolderName, BlobSizesCacheName);

            GVFSHelpers.GetPersistedBlobSizesRoot(this.Enlistment.DotGVFSRoot)
            .ShouldEqual(newBlobSizesRoot);

            string blobSizesDbPath = Path.Combine(newBlobSizesRoot, BlobSizesDBFileName);

            newBlobSizesRoot.ShouldBeADirectory(this.fileSystem);
            blobSizesDbPath.ShouldBeAFile(this.fileSystem);

            foreach (KeyValuePair <string, long> entry in entries)
            {
                GVFSHelpers.SQLiteBlobSizesDatabaseHasEntry(blobSizesDbPath, entry.Key, entry.Value);
            }
        }
Example #10
0
        public void MountRegeneratesAlternatesFileWhenMissingFromDisk()
        {
            this.Enlistment.UnmountGVFS();

            string objectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(this.Enlistment.DotGVFSRoot).ShouldNotBeNull();

            string alternatesFilePath = Path.Combine(this.Enlistment.RepoRoot, ".git", "objects", "info", "alternates");

            alternatesFilePath.ShouldBeAFile(this.fileSystem).WithContents(objectsRoot);
            this.fileSystem.DeleteFile(alternatesFilePath);

            this.Enlistment.MountGVFS();

            alternatesFilePath.ShouldBeAFile(this.fileSystem).WithContents(objectsRoot);
        }
Example #11
0
        public void MountRegeneratesAlternatesFileWhenMissingGitObjectsRoot()
        {
            this.Enlistment.UnmountGVFS();

            string objectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(this.Enlistment.DotGVFSRoot).ShouldNotBeNull();

            string alternatesFilePath = this.Enlistment.GetDotGitPath("objects", "info", "alternates");

            alternatesFilePath.ShouldBeAFile(this.fileSystem).WithContents(objectsRoot);
            this.fileSystem.WriteAllText(alternatesFilePath, "Z:\\invalidPath");

            this.Enlistment.MountGVFS();

            alternatesFilePath.ShouldBeAFile(this.fileSystem).WithContents(objectsRoot);
        }
Example #12
0
        public void MountUsesNewLocalCacheKeyWhenLocalCacheDeleted()
        {
            GVFSFunctionalTestEnlistment enlistment = this.CloneAndMountEnlistment();

            enlistment.UnmountGVFS();

            // Find the current git objects root and ensure it's on disk
            string objectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(enlistment.DotGVFSRoot).ShouldNotBeNull();

            objectsRoot.ShouldBeADirectory(this.fileSystem);

            string mappingFilePath     = Path.Combine(enlistment.LocalCacheRoot, "mapping.dat");
            string mappingFileContents = this.fileSystem.ReadAllText(mappingFilePath);

            mappingFileContents.Length.ShouldNotEqual(0, "mapping.dat should not be empty");

            // Delete the local cache folder, mount should re-create it and generate a new mapping file and local cache key
            this.DeleteDirectoryWithUnlimitedRetries(enlistment.LocalCacheRoot);

            enlistment.MountGVFS();

            // Mount should recreate the local cache root
            enlistment.LocalCacheRoot.ShouldBeADirectory(this.fileSystem);

            // Determine the new local cache key
            string    newMappingFileContents = mappingFilePath.ShouldBeAFile(this.fileSystem).WithContents();
            const int GuidStringLength       = 32;
            string    mappingFileKey         = "A {\"Key\":\"https://gvfs.visualstudio.com/ci/_git/fortests\",\"Value\":\"";
            int       localKeyIndex          = newMappingFileContents.IndexOf(mappingFileKey);
            string    newCacheKey            = newMappingFileContents.Substring(localKeyIndex + mappingFileKey.Length, GuidStringLength);

            // Validate the new objects root is on disk and uses the new key
            objectsRoot.ShouldNotExistOnDisk(this.fileSystem);
            string newObjectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(enlistment.DotGVFSRoot);

            newObjectsRoot.ShouldNotEqual(objectsRoot);
            newObjectsRoot.ShouldContain(newCacheKey);
            newObjectsRoot.ShouldBeADirectory(this.fileSystem);

            this.AlternatesFileShouldHaveGitObjectsRoot(enlistment);
        }
Example #13
0
        public void MountFailsWhenNoLocalCacheRootInRepoMetadata()
        {
            this.Enlistment.UnmountGVFS();

            string currentVersion = GVFSHelpers.GetPersistedDiskLayoutVersion(this.Enlistment.DotGVFSRoot).ShouldNotBeNull();
            string objectsRoot    = GVFSHelpers.GetPersistedGitObjectsRoot(this.Enlistment.DotGVFSRoot).ShouldNotBeNull();

            string metadataPath       = Path.Combine(this.Enlistment.DotGVFSRoot, GVFSHelpers.RepoMetadataName);
            string metadataBackupPath = metadataPath + ".backup";

            this.fileSystem.MoveFile(metadataPath, metadataBackupPath);

            this.fileSystem.CreateEmptyFile(metadataPath);
            GVFSHelpers.SaveDiskLayoutVersion(this.Enlistment.DotGVFSRoot, currentVersion);
            GVFSHelpers.SaveGitObjectsRoot(this.Enlistment.DotGVFSRoot, objectsRoot);

            this.MountShouldFail("Failed to determine local cache path from repo metadata");

            this.fileSystem.DeleteFile(metadataPath);
            this.fileSystem.MoveFile(metadataBackupPath, metadataPath);

            this.Enlistment.MountGVFS();
        }
Example #14
0
        public void MountUpgradesLocalSizesToSharedCache()
        {
            GVFSFunctionalTestEnlistment enlistment = this.CloneAndMountEnlistment();

            enlistment.UnmountGVFS();

            string localCacheRoot = GVFSHelpers.GetPersistedLocalCacheRoot(enlistment.DotGVFSRoot);
            string gitObjectsRoot = GVFSHelpers.GetPersistedGitObjectsRoot(enlistment.DotGVFSRoot);

            // Delete the existing repo metadata
            string versionJsonPath = Path.Combine(enlistment.DotGVFSRoot, GVFSHelpers.RepoMetadataName);

            versionJsonPath.ShouldBeAFile(this.fileSystem);
            this.fileSystem.DeleteFile(versionJsonPath);

            // "13.0" was the last version before blob sizes were moved out of Esent
            string metadataPath = Path.Combine(enlistment.DotGVFSRoot, GVFSHelpers.RepoMetadataName);

            this.fileSystem.CreateEmptyFile(metadataPath);
            GVFSHelpers.SaveDiskLayoutVersion(enlistment.DotGVFSRoot, "13", "0");
            GVFSHelpers.SaveLocalCacheRoot(enlistment.DotGVFSRoot, localCacheRoot);
            GVFSHelpers.SaveGitObjectsRoot(enlistment.DotGVFSRoot, gitObjectsRoot);

            // Create a legacy PersistedDictionary sizes database
            List <KeyValuePair <string, long> > entries = new List <KeyValuePair <string, long> >()
            {
                new KeyValuePair <string, long>(new string('0', 40), 1),
                new KeyValuePair <string, long>(new string('1', 40), 2),
                new KeyValuePair <string, long>(new string('2', 40), 4),
                new KeyValuePair <string, long>(new string('3', 40), 8),
            };

            GVFSHelpers.CreateEsentBlobSizesDatabase(enlistment.DotGVFSRoot, entries);

            enlistment.MountGVFS();

            string majorVersion;
            string minorVersion;

            GVFSHelpers.GetPersistedDiskLayoutVersion(enlistment.DotGVFSRoot, out majorVersion, out minorVersion);

            majorVersion
            .ShouldBeAnInt("Disk layout version should always be an int")
            .ShouldEqual(DiskLayoutUpgradeTests.CurrentDiskLayoutMajorVersion, "Disk layout version should be upgraded to the latest");

            minorVersion
            .ShouldBeAnInt("Disk layout version should always be an int")
            .ShouldEqual(DiskLayoutUpgradeTests.CurrentDiskLayoutMinorVersion, "Disk layout version should be upgraded to the latest");

            string newBlobSizesRoot = Path.Combine(Path.GetDirectoryName(gitObjectsRoot), DiskLayoutUpgradeTests.BlobSizesCacheName);

            GVFSHelpers.GetPersistedBlobSizesRoot(enlistment.DotGVFSRoot)
            .ShouldEqual(newBlobSizesRoot);

            string blobSizesDbPath = Path.Combine(newBlobSizesRoot, DiskLayoutUpgradeTests.BlobSizesDBFileName);

            newBlobSizesRoot.ShouldBeADirectory(this.fileSystem);
            blobSizesDbPath.ShouldBeAFile(this.fileSystem);

            foreach (KeyValuePair <string, long> entry in entries)
            {
                GVFSHelpers.SQLiteBlobSizesDatabaseHasEntry(blobSizesDbPath, entry.Key, entry.Value);
            }

            // Upgrade a second repo, and make sure all sizes from both upgrades are in the shared database

            GVFSFunctionalTestEnlistment enlistment2 = this.CloneAndMountEnlistment();

            enlistment2.UnmountGVFS();

            // Delete the existing repo metadata
            versionJsonPath = Path.Combine(enlistment2.DotGVFSRoot, GVFSHelpers.RepoMetadataName);
            versionJsonPath.ShouldBeAFile(this.fileSystem);
            this.fileSystem.DeleteFile(versionJsonPath);

            // "13.0" was the last version before blob sizes were moved out of Esent
            metadataPath = Path.Combine(enlistment2.DotGVFSRoot, GVFSHelpers.RepoMetadataName);
            this.fileSystem.CreateEmptyFile(metadataPath);
            GVFSHelpers.SaveDiskLayoutVersion(enlistment2.DotGVFSRoot, "13", "0");
            GVFSHelpers.SaveLocalCacheRoot(enlistment2.DotGVFSRoot, localCacheRoot);
            GVFSHelpers.SaveGitObjectsRoot(enlistment2.DotGVFSRoot, gitObjectsRoot);

            // Create a legacy PersistedDictionary sizes database
            List <KeyValuePair <string, long> > additionalEntries = new List <KeyValuePair <string, long> >()
            {
                new KeyValuePair <string, long>(new string('4', 40), 16),
                new KeyValuePair <string, long>(new string('5', 40), 32),
                new KeyValuePair <string, long>(new string('6', 40), 64),
            };

            GVFSHelpers.CreateEsentBlobSizesDatabase(enlistment2.DotGVFSRoot, additionalEntries);

            enlistment2.MountGVFS();

            foreach (KeyValuePair <string, long> entry in entries)
            {
                GVFSHelpers.SQLiteBlobSizesDatabaseHasEntry(blobSizesDbPath, entry.Key, entry.Value);
            }

            foreach (KeyValuePair <string, long> entry in additionalEntries)
            {
                GVFSHelpers.SQLiteBlobSizesDatabaseHasEntry(blobSizesDbPath, entry.Key, entry.Value);
            }
        }