public void ExcludeProblematicPaths() { // A normal path that will be backed up. string normalFilePath = Path.Combine(this.DATAFOLDER, "normal"); File.WriteAllBytes(normalFilePath, new byte[] { 0, 1, 2 }); // A long path to exclude. string longFile = SystemIO.IO_OS.PathCombine(this.DATAFOLDER, new string('y', 255)); TestUtils.WriteFile(longFile, new byte[] { 0, 1 }); // A folder that ends with a dot to exclude. string folderWithDot = Path.Combine(this.DATAFOLDER, "folder_with_dot."); SystemIO.IO_OS.DirectoryCreate(folderWithDot); // A folder that ends with a space to exclude. string folderWithSpace = Path.Combine(this.DATAFOLDER, "folder_with_space "); SystemIO.IO_OS.DirectoryCreate(folderWithSpace); // A file that ends with a dot to exclude. string fileWithDot = Path.Combine(this.DATAFOLDER, "file_with_dot."); TestUtils.WriteFile(fileWithDot, new byte[] { 0, 1 }); // A file that ends with a space to exclude. string fileWithSpace = Path.Combine(this.DATAFOLDER, "file_with_space "); TestUtils.WriteFile(fileWithSpace, new byte[] { 0, 1 }); FilterExpression filter = new FilterExpression(longFile, false); filter = FilterExpression.Combine(filter, new FilterExpression(Util.AppendDirSeparator(folderWithDot), false)); filter = FilterExpression.Combine(filter, new FilterExpression(Util.AppendDirSeparator(folderWithSpace), false)); filter = FilterExpression.Combine(filter, new FilterExpression(fileWithDot, false)); filter = FilterExpression.Combine(filter, new FilterExpression(fileWithSpace, false)); Dictionary <string, string> options = new Dictionary <string, string>(this.TestOptions); using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null)) { IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER }, filter); Assert.AreEqual(0, backupResults.Errors.Count()); Assert.AreEqual(0, backupResults.Warnings.Count()); } using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null)) { IListResults listResults = c.List("*"); Assert.AreEqual(0, listResults.Errors.Count()); Assert.AreEqual(0, listResults.Warnings.Count()); string[] backedUpPaths = listResults.Files.Select(x => x.Path).ToArray(); Assert.AreEqual(2, backedUpPaths.Length); Assert.Contains(Util.AppendDirSeparator(this.DATAFOLDER), backedUpPaths); Assert.Contains(normalFilePath, backedUpPaths); } }
public void ProblematicSuffixes(string pathComponent, bool skipOnWindows) { if (Platform.IsClientWindows && skipOnWindows) { return; } string folderPath = SystemIO.IO_OS.PathCombine(this.DATAFOLDER, pathComponent); SystemIO.IO_OS.DirectoryCreate(folderPath); string filePath = SystemIO.IO_OS.PathCombine(folderPath, pathComponent); byte[] fileBytes = { 0, 1, 2 }; TestUtils.WriteFile(filePath, fileBytes); Dictionary <string, string> options = new Dictionary <string, string>(this.TestOptions); using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null)) { IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER }); Assert.AreEqual(0, backupResults.Errors.Count()); Assert.AreEqual(0, backupResults.Warnings.Count()); } Dictionary <string, string> restoreOptions = new Dictionary <string, string>(this.TestOptions) { ["restore-path"] = this.RESTOREFOLDER }; // Restore just the file. using (Controller c = new Controller("file://" + this.TARGETFOLDER, restoreOptions, null)) { IRestoreResults restoreResults = c.Restore(new[] { filePath }); Assert.AreEqual(0, restoreResults.Errors.Count()); Assert.AreEqual(0, restoreResults.Warnings.Count()); } string restoreFilePath = SystemIO.IO_OS.PathCombine(this.RESTOREFOLDER, pathComponent); TestUtils.AssertFilesAreEqual(filePath, restoreFilePath, true, pathComponent); SystemIO.IO_OS.FileDelete(restoreFilePath); // Restore the entire directory. string pathSpec = $"[{Regex.Escape(Util.AppendDirSeparator(this.DATAFOLDER))}.*]"; using (Controller c = new Controller("file://" + this.TARGETFOLDER, restoreOptions, null)) { IRestoreResults restoreResults = c.Restore(new[] { pathSpec }); Assert.AreEqual(0, restoreResults.Errors.Count()); Assert.AreEqual(0, restoreResults.Warnings.Count()); } TestUtils.AssertDirectoryTreesAreEquivalent(this.DATAFOLDER, this.RESTOREFOLDER, true, pathComponent); }
public void LongPath() { string folderPath = Path.Combine(this.DATAFOLDER, new string('x', 10)); SystemIO.IO_OS.DirectoryCreate(folderPath); string fileName = new string('y', 255); string filePath = SystemIO.IO_OS.PathCombine(folderPath, fileName); byte[] fileBytes = { 0, 1, 2 }; TestUtils.WriteFile(filePath, fileBytes); Dictionary <string, string> options = new Dictionary <string, string>(this.TestOptions); using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null)) { IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER }); Assert.AreEqual(0, backupResults.Errors.Count()); Assert.AreEqual(0, backupResults.Warnings.Count()); } Dictionary <string, string> restoreOptions = new Dictionary <string, string>(this.TestOptions) { ["restore-path"] = this.RESTOREFOLDER }; using (Controller c = new Controller("file://" + this.TARGETFOLDER, restoreOptions, null)) { IRestoreResults restoreResults = c.Restore(new[] { filePath }); Assert.AreEqual(0, restoreResults.Errors.Count()); Assert.AreEqual(0, restoreResults.Warnings.Count()); } string restoreFilePath = SystemIO.IO_OS.PathCombine(this.RESTOREFOLDER, fileName); Assert.IsTrue(SystemIO.IO_OS.FileExists(restoreFilePath)); MemoryStream restoredStream = new MemoryStream(); using (FileStream fileStream = SystemIO.IO_OS.FileOpenRead(restoreFilePath)) { Utility.CopyStream(fileStream, restoredStream); } Assert.AreEqual(fileBytes, restoredStream.ToArray()); }
public void DirectoriesWithWildcards() { const string file = "file"; List <string> directories = new List <string>(); // Keep expected match counts since they'll differ between // Linux and Windows. var questionMarkWildcardShouldMatchCount = 0; var verbatimAsteriskShouldMatchCount = 0; const string asterisk = "*"; string dirWithAsterisk = Path.Combine(this.DATAFOLDER, asterisk); // Windows does not support literal asterisks in paths. if (!Platform.IsClientWindows) { SystemIO.IO_OS.DirectoryCreate(dirWithAsterisk); TestUtils.WriteFile(SystemIO.IO_OS.PathCombine(dirWithAsterisk, file), new byte[] { 0 }); directories.Add(dirWithAsterisk); questionMarkWildcardShouldMatchCount++; verbatimAsteriskShouldMatchCount++; } const string questionMark = "?"; string dirWithQuestionMark = Path.Combine(this.DATAFOLDER, questionMark); // Windows does not support literal question marks in paths. if (!Platform.IsClientWindows) { SystemIO.IO_OS.DirectoryCreate(dirWithQuestionMark); TestUtils.WriteFile(SystemIO.IO_OS.PathCombine(dirWithQuestionMark, file), new byte[] { 1 }); directories.Add(dirWithQuestionMark); questionMarkWildcardShouldMatchCount++; } // Include at least one single character directory in Windows // for a '?' wildcard can match on const string singleCharacterDir = "X"; string dirWithSingleCharacter = Path.Combine(this.DATAFOLDER, singleCharacterDir); SystemIO.IO_OS.DirectoryCreate(dirWithSingleCharacter); TestUtils.WriteFile(SystemIO.IO_OS.PathCombine(dirWithSingleCharacter, file), new byte[] { 2 }); directories.Add(dirWithSingleCharacter); questionMarkWildcardShouldMatchCount++; const string dir = "dir"; string normalDir = Path.Combine(this.DATAFOLDER, dir); SystemIO.IO_OS.DirectoryCreate(normalDir); TestUtils.WriteFile(SystemIO.IO_OS.PathCombine(normalDir, file), new byte[] { 3 }); directories.Add(normalDir); // Backup all files. Dictionary <string, string> options = new Dictionary <string, string>(this.TestOptions); using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null)) { IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER }); Assert.AreEqual(0, backupResults.Errors.Count()); Assert.AreEqual(0, backupResults.Warnings.Count()); } // Restore all files. Dictionary <string, string> restoreOptions = new Dictionary <string, string>(options) { ["restore-path"] = this.RESTOREFOLDER }; using (Controller c = new Controller("file://" + this.TARGETFOLDER, restoreOptions, null)) { IRestoreResults restoreResults = c.Restore(null); Assert.AreEqual(0, restoreResults.Errors.Count()); Assert.AreEqual(0, restoreResults.Warnings.Count()); TestUtils.AssertDirectoryTreesAreEquivalent(this.DATAFOLDER, this.RESTOREFOLDER, true, "Restore"); // List results using * should return a match for each directory. IListResults listResults = c.List(SystemIO.IO_OS.PathCombine(dirWithAsterisk, file)); Assert.AreEqual(0, listResults.Errors.Count()); Assert.AreEqual(0, listResults.Warnings.Count()); Assert.AreEqual(directories.Count, listResults.Files.Count()); listResults = c.List(SystemIO.IO_OS.PathCombine(dirWithQuestionMark, file)); Assert.AreEqual(0, listResults.Errors.Count()); Assert.AreEqual(0, listResults.Warnings.Count()); // List results using ? should return 3 matches in Linux, // one for the directory with '*' and one for the directory // with '?', plus one for directory 'X'; but should return // 1 matches in Windows just for directory 'X'. Assert.AreEqual(questionMarkWildcardShouldMatchCount, listResults.Files.Count()); } SystemIO.IO_OS.DirectoryDelete(this.RESTOREFOLDER, true); // Restore one file at a time using the verbatim identifier. foreach (string directory in directories) { foreach (string expectedFilePath in SystemIO.IO_OS.EnumerateFiles(directory)) { using (Controller c = new Controller("file://" + this.TARGETFOLDER, restoreOptions, null)) { string verbatimFilePath = "@" + expectedFilePath; // Verify that list result using verbatim identifier contains only one file. IListResults listResults = c.List(verbatimFilePath); Assert.AreEqual(0, listResults.Errors.Count()); Assert.AreEqual(0, listResults.Warnings.Count()); Assert.AreEqual(1, listResults.Files.Count()); Assert.AreEqual(expectedFilePath, listResults.Files.Single().Path); IRestoreResults restoreResults = c.Restore(new[] { verbatimFilePath }); Assert.AreEqual(0, restoreResults.Errors.Count()); Assert.AreEqual(0, restoreResults.Warnings.Count()); string fileName = SystemIO.IO_OS.PathGetFileName(expectedFilePath); string restoredFilePath = SystemIO.IO_OS.PathCombine(this.RESTOREFOLDER, fileName); TestUtils.AssertFilesAreEqual(expectedFilePath, restoredFilePath, false, expectedFilePath); SystemIO.IO_OS.FileDelete(restoredFilePath); } } } // Backup with asterisk in include filter should include all directories. FilterExpression filter = new FilterExpression(dirWithAsterisk); using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null)) { IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER }, filter); Assert.AreEqual(0, backupResults.Errors.Count()); Assert.AreEqual(0, backupResults.Warnings.Count()); Assert.AreEqual(directories.Count, backupResults.ExaminedFiles); } // Backup with verbatim asterisk in include filter should include // one directory in Linux and zero directories in Windows. filter = new FilterExpression("@" + SystemIO.IO_OS.PathCombine(dirWithAsterisk, file)); using (Controller c = new Controller("file://" + this.TARGETFOLDER, options, null)) { IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER }, filter); Assert.AreEqual(0, backupResults.Errors.Count()); Assert.AreEqual(0, backupResults.Warnings.Count()); Assert.AreEqual(verbatimAsteriskShouldMatchCount, backupResults.ExaminedFiles); } }
public void SymLinkPolicy(Options.SymlinkStrategy symlinkPolicy) { // Create symlink target directory const string targetDirName = "target"; var targetDir = systemIO.PathCombine(this.DATAFOLDER, targetDirName); systemIO.DirectoryCreate(targetDir); // Create files in symlink target directory var fileNames = new[] { "a.txt", "b.txt", "c.txt" }; foreach (var file in fileNames) { var targetFile = systemIO.PathCombine(targetDir, file); TestUtils.WriteFile(targetFile, Encoding.Default.GetBytes(file)); } // Create actual symlink directory linking to the target directory const string symlinkDirName = "symlink"; var symlinkDir = systemIO.PathCombine(this.DATAFOLDER, symlinkDirName); try { systemIO.CreateSymlink(symlinkDir, targetDir, asDir: true); } catch (Exception e) { // If client cannot create symlinks, mark test as ignored Assert.Ignore($"Client could not create a symbolic link. Error reported: {e.Message}"); } // Backup all files with given symlink policy Dictionary <string, string> restoreOptions = new Dictionary <string, string>(this.TestOptions) { ["restore-path"] = this.RESTOREFOLDER }; Dictionary <string, string> backupOptions = new Dictionary <string, string>(this.TestOptions) { ["symlink-policy"] = symlinkPolicy.ToString() }; using (Controller c = new Controller("file://" + this.TARGETFOLDER, backupOptions, null)) { IBackupResults backupResults = c.Backup(new[] { this.DATAFOLDER }); Assert.AreEqual(0, backupResults.Errors.Count()); Assert.AreEqual(0, backupResults.Warnings.Count()); } // Restore all files using (Controller c = new Controller("file://" + this.TARGETFOLDER, restoreOptions, null)) { IRestoreResults restoreResults = c.Restore(null); Assert.AreEqual(0, restoreResults.Errors.Count()); Assert.AreEqual(0, restoreResults.Warnings.Count()); // Verify that symlink policy was followed var restoreSymlinkDir = systemIO.PathCombine(this.RESTOREFOLDER, symlinkDirName); switch (symlinkPolicy) { case Options.SymlinkStrategy.Store: // Restore should contain an actual symlink to the original target Assert.That(systemIO.IsSymlink(restoreSymlinkDir), Is.True); var restoredSymlinkFullPath = systemIO.PathGetFullPath(systemIO.GetSymlinkTarget(restoreSymlinkDir)); var symlinkTargetFullPath = systemIO.PathGetFullPath(targetDir); Assert.That(restoredSymlinkFullPath, Is.EqualTo(symlinkTargetFullPath)); break; case Options.SymlinkStrategy.Follow: // Restore should contain a regular directory with copies of the files in the symlink target Assert.That(systemIO.IsSymlink(restoreSymlinkDir), Is.False); TestUtils.AssertDirectoryTreesAreEquivalent(targetDir, restoreSymlinkDir, true, "Restore"); break; case Options.SymlinkStrategy.Ignore: // Restore should not contain the symlink or directory at all Assert.That(systemIO.DirectoryExists(restoreSymlinkDir), Is.False); Assert.That(systemIO.FileExists(restoreSymlinkDir), Is.False); break; default: Assert.Fail($"Unexpected symlink policy"); break; } } }