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(); }
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"); }
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); }
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); }
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")); }
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); } }
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); }
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); }
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); }
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(); }
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); } }