Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mac: Add PreDelete Notification #181

Merged
1 change: 1 addition & 0 deletions GVFS/GVFS.FunctionalTests/Categories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public static class Mac
{
public const string M1 = "M1_CloneAndMount";
public const string M2 = "M2_StaticViewGitCommands";
public const string M2TODO = "M2_StaticViewGitCommandsStillTODO";
public const string M3 = "M3_AllGitCommands";
public const string M4 = "M4_All";
}
Expand Down
15 changes: 14 additions & 1 deletion GVFS/GVFS.FunctionalTests/FileSystemRunners/BashRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

namespace GVFS.FunctionalTests.FileSystemRunners
Expand Down Expand Up @@ -33,6 +34,11 @@ public class BashRunner : ShellRunner
"Permission denied"
};

private static string[] resourceUnavailableMessage = new string[]
{
"Resource temporarily unavailable",
};

private readonly string pathToBash;

public BashRunner()
Expand Down Expand Up @@ -233,7 +239,14 @@ public override void DeleteFile_FileShouldNotBeFound(string path)

public override void DeleteFile_AccessShouldBeDenied(string path)
{
this.DeleteFile(path).ShouldContain(permissionDeniedMessage);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we start getting more of these, we could create a WindowsBashRunner and a MacBashRunner. This seems fine for now though.

{
this.DeleteFile(path).ShouldContain(permissionDeniedMessage);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, don't bother checking the platform, and just make this ShouldContainOneOf(both messages)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not relax the check when we're running the tests on Windows. I like the idea of separate Windows\Mac BashRunners, but I also agree at this point we probably don't need both.

}
else
{
this.DeleteFile(path).ShouldContain(resourceUnavailableMessage);
}
}

public override void ReadAllText_FileShouldNotBeFound(string path)
Expand Down
1 change: 1 addition & 0 deletions GVFS/GVFS.FunctionalTests/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public static void Main(string[] args)
{
includeCategories.Add(Categories.Mac.M1);
includeCategories.Add(Categories.Mac.M2);
excludeCategories.Add(Categories.Mac.M2TODO);
excludeCategories.Add(Categories.Mac.M3);
excludeCategories.Add(Categories.Mac.M4);
excludeCategories.Add(Categories.Windows);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,6 @@ public void MoveDotGitFullFolderTreeToDotGitFullFolder(FileSystemRunner fileSyst
}

[TestCaseSource(typeof(FileSystemRunner), FileSystemRunner.TestRunners)]
[Category(Categories.Mac.M4)]
public void DeleteIndexFileFails(FileSystemRunner fileSystem)
{
string indexFilePath = this.Enlistment.GetVirtualPathTo(Path.Combine(".git", "index"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace GVFS.FunctionalTests.Tests.EnlistmentPerFixture
{
[TestFixtureSource(typeof(GitFilesTestsRunners), GitFilesTestsRunners.TestRunners)]
[Category(Categories.Mac.M2)]
public class GitFilesTests : TestsWithEnlistmentPerFixture
{
private FileSystemRunner fileSystem;
Expand All @@ -23,6 +24,7 @@ public GitFilesTests(FileSystemRunner fileSystem)
}

[TestCase, Order(1)]
[Category(Categories.Mac.M2TODO)]
public void CreateFileTest()
{
string fileName = "file1.txt";
Expand All @@ -36,6 +38,7 @@ public void CreateFileTest()
}

[TestCase, Order(2)]
[Category(Categories.Mac.M2TODO)]
public void CreateFileInFolderTest()
{
string folderName = "folder2";
Expand All @@ -51,11 +54,12 @@ public void CreateFileInFolderTest()

this.Enlistment.WaitForBackgroundOperations().ShouldEqual(true, "Background operations failed to complete.");

GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, folderName + "/" + Environment.NewLine);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming ModifiedPathsShouldContain to ModifiedPathsShouldContainLine, and move the newline inside the method. That way every caller doesn't have to know this detaill

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that idea, that will also allow for making ModifiedPathsNewLine private (as mentioned in a separate comment)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will move the newline inside the method but leave the method named ModifiedPathsShouldContain.

I found ModifiedPathsShouldContainLine looked a bit off as the caller is not passing in lines, it's passing in the paths that ``ModifiedPaths` should (or should not) have.

GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, folderName + "/" + fileName + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, folderName + "/" + GVFSHelpers.ModifiedPathsNewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, folderName + "/" + fileName + GVFSHelpers.ModifiedPathsNewLine);
}

[TestCase, Order(3)]
[Category(Categories.Mac.M2TODO)]
public void RenameEmptyFolderTest()
{
string folderName = "folder3a";
Expand All @@ -76,6 +80,7 @@ public void RenameEmptyFolderTest()
}

[TestCase, Order(4)]
[Category(Categories.Mac.M2TODO)]
public void RenameFolderTest()
{
string folderName = "folder4a";
Expand Down Expand Up @@ -108,6 +113,7 @@ public void RenameFolderTest()
}

[TestCase, Order(5)]
[Category(Categories.Mac.M2TODO)]
public void CaseOnlyRenameOfNewFolderKeepsExcludeEntries()
{
string[] expectedModifiedPathsEntries =
Expand All @@ -129,7 +135,6 @@ public void CaseOnlyRenameOfNewFolderKeepsExcludeEntries()
}

[TestCase, Order(6)]
[Category(Categories.Mac.M2)]
public void ReadingFileDoesNotUpdateIndexOrSparseCheckout()
{
string gitFileToCheck = "GVFS/GVFS.FunctionalTests/Category/CategoryConstants.cs";
Expand All @@ -153,11 +158,13 @@ public void ReadingFileDoesNotUpdateIndexOrSparseCheckout()
afterUpdateResult.Output.StartsWith("S ").ShouldEqual(true);
afterUpdateResult.Output.ShouldContain("ctime: 0:0", "mtime: 0:0", "size: 0\t");

GVFSHelpers.ModifiedPathsShouldNotContain(this.fileSystem, this.Enlistment.DotGVFSRoot, gitFileToCheck + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldNotContain(this.fileSystem, this.Enlistment.DotGVFSRoot, gitFileToCheck + GVFSHelpers.ModifiedPathsNewLine);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for ShouldNotContainLine

}

// TODO(Mac): Enable this test once the LockHolder is converted to .NET Core
[TestCase, Order(7)]
public void ModifiedFileWillGetSkipworktreeBitCleared()
[Category(Categories.Mac.M2TODO)]
public void ModifiedFileWillGetAddedToModifiedPathsFile()
{
string gitFileToTest = "GVFS/GVFS.Common/RetryWrapper.cs";
string fileToCreate = this.Enlistment.GetVirtualPathTo(gitFileToTest);
Expand All @@ -171,11 +178,12 @@ public void ModifiedFileWillGetSkipworktreeBitCleared()

this.Enlistment.WaitForBackgroundOperations().ShouldEqual(true, "Background operations did not complete.");

GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, gitFileToTest + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, gitFileToTest + GVFSHelpers.ModifiedPathsNewLine);
this.VerifyWorktreeBit(gitFileToTest, LsFilesStatus.Cached);
}

[TestCase, Order(8)]
[Category(Categories.Mac.M2TODO)]
public void RenamedFileAddedToSparseCheckoutAndSkipWorktreeBitCleared()
{
string fileToRenameEntry = "Test_EPF_MoveRenameFileTests/ChangeUnhydratedFileName/Program.cs";
Expand All @@ -189,14 +197,15 @@ public void RenamedFileAddedToSparseCheckoutAndSkipWorktreeBitCleared()
this.Enlistment.GetVirtualPathTo(fileToRenameTargetRelativePath));
this.Enlistment.WaitForBackgroundOperations().ShouldEqual(true, "Background operations failed to complete.");

GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameEntry + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameTargetEntry + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameEntry + GVFSHelpers.ModifiedPathsNewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameTargetEntry + GVFSHelpers.ModifiedPathsNewLine);

// Verify skip-worktree cleared
this.VerifyWorktreeBit(fileToRenameEntry, LsFilesStatus.Cached);
}

[TestCase, Order(9)]
[Category(Categories.Mac.M2TODO)]
public void RenamedFileAndOverwrittenTargetAddedToSparseCheckoutAndSkipWorktreeBitCleared()
{
string fileToRenameEntry = "Test_EPF_MoveRenameFileTests_2/MoveUnhydratedFileToOverwriteUnhydratedFileAndWrite/RunUnitTests.bat";
Expand All @@ -211,32 +220,31 @@ public void RenamedFileAndOverwrittenTargetAddedToSparseCheckoutAndSkipWorktreeB
this.Enlistment.GetVirtualPathTo(fileToRenameTargetRelativePath));
this.Enlistment.WaitForBackgroundOperations().ShouldEqual(true, "Background operations failed to complete.");

GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameEntry + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameTargetEntry + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameEntry + GVFSHelpers.ModifiedPathsNewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameTargetEntry + GVFSHelpers.ModifiedPathsNewLine);

// Verify skip-worktree cleared
this.VerifyWorktreeBit(fileToRenameEntry, LsFilesStatus.Cached);
this.VerifyWorktreeBit(fileToRenameTargetEntry, LsFilesStatus.Cached);
}

[TestCase, Order(10)]
public void DeletedFileAddedToSparseCheckoutAndSkipWorktreeBitCleared()
public void DeletedFileAddedToModifiedPathsFile()
{
string fileToDeleteEntry = "GVFlt_DeleteFileTest/GVFlt_DeleteFullFileWithoutFileContext_DeleteOnClose/a.txt";
string fileToDeleteRelativePath = "GVFlt_DeleteFileTest\\GVFlt_DeleteFullFileWithoutFileContext_DeleteOnClose\\a.txt";
this.VerifyWorktreeBit(fileToDeleteEntry, LsFilesStatus.SkipWorktree);

this.fileSystem.DeleteFile(this.Enlistment.GetVirtualPathTo(fileToDeleteRelativePath));
this.fileSystem.DeleteFile(this.Enlistment.GetVirtualPathTo(fileToDeleteEntry));
this.Enlistment.WaitForBackgroundOperations().ShouldEqual(true, "Background operations failed to complete.");

GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToDeleteEntry + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToDeleteEntry + GVFSHelpers.ModifiedPathsNewLine);

// Verify skip-worktree cleared
this.VerifyWorktreeBit(fileToDeleteEntry, LsFilesStatus.Cached);
}

[TestCase, Order(11)]
public void DeletedFolderAndChildrenAddedToSparseCheckoutAndSkipWorktreeBitCleared()
public void DeletedFolderAndChildrenAddedToToModifiedPathsFile()
{
string folderToDelete = "Scripts";
string[] filesToDelete = new string[]
Expand Down Expand Up @@ -268,25 +276,25 @@ public void DeletedFolderAndChildrenAddedToSparseCheckoutAndSkipWorktreeBitClear
}

[TestCase, Order(12)]
public void FileRenamedOutOfRepoAddedToSparseCheckoutAndSkipWorktreeBitCleared()
public void FileRenamedOutOfRepoAddedToModifiedPathsFile()
{
string fileToRenameEntry = "GVFlt_MoveFileTest/PartialToOutside/from/lessInFrom.txt";
string fileToRenameVirtualPath = this.Enlistment.GetVirtualPathTo("GVFlt_MoveFileTest\\PartialToOutside\\from\\lessInFrom.txt");
string fileToRenameVirtualPath = this.Enlistment.GetVirtualPathTo(fileToRenameEntry);
this.VerifyWorktreeBit(fileToRenameEntry, LsFilesStatus.SkipWorktree);

string fileOutsideRepoPath = Path.Combine(this.Enlistment.EnlistmentRoot, "FileRenamedOutOfRepoAddedToSparseCheckoutAndSkipWorktreeBitCleared.txt");
this.fileSystem.MoveFile(fileToRenameVirtualPath, fileOutsideRepoPath);
fileOutsideRepoPath.ShouldBeAFile(this.fileSystem).WithContents("lessData");

this.Enlistment.WaitForBackgroundOperations().ShouldEqual(true, "Background operations failed to complete.");

GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameEntry + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToRenameEntry + GVFSHelpers.ModifiedPathsNewLine);

// Verify skip-worktree cleared
this.VerifyWorktreeBit(fileToRenameEntry, LsFilesStatus.Cached);
}

[TestCase, Order(13)]
[Category(Categories.Mac.M2)]
public void OverwrittenFileAddedToSparseCheckoutAndSkipWorktreeBitCleared()
{
string fileToOverwriteEntry = "Test_EPF_WorkingDirectoryTests/1/2/3/4/ReadDeepProjectedFile.cpp";
Expand All @@ -300,13 +308,14 @@ public void OverwrittenFileAddedToSparseCheckoutAndSkipWorktreeBitCleared()

fileToOverwriteVirtualPath.ShouldBeAFile(this.fileSystem).WithContents(testContents);

GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToOverwriteEntry + "\r\n");
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToOverwriteEntry + GVFSHelpers.ModifiedPathsNewLine);

// Verify skip-worktree cleared
this.VerifyWorktreeBit(fileToOverwriteEntry, LsFilesStatus.Cached);
}

[TestCase, Order(14)]
[Category(Categories.Mac.M2TODO)]
public void SupersededFileAddedToSparseCheckoutAndSkipWorktreeBitCleared()
{
string fileToSupersedeEntry = "GVFlt_FileOperationTest/WriteAndVerify.txt";
Expand All @@ -318,7 +327,7 @@ public void SupersededFileAddedToSparseCheckoutAndSkipWorktreeBitCleared()
SupersedeFile(fileToSupersedePath, newContent).ShouldEqual(true);
this.Enlistment.WaitForBackgroundOperations().ShouldEqual(true, "Background operations failed to complete.");

GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToSupersedeEntry + Environment.NewLine);
GVFSHelpers.ModifiedPathsShouldContain(this.fileSystem, this.Enlistment.DotGVFSRoot, fileToSupersedeEntry + GVFSHelpers.ModifiedPathsNewLine);

// Verify skip-worktree cleared
this.VerifyWorktreeBit(fileToSupersedeEntry, LsFilesStatus.Cached);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace GVFS.FunctionalTests.Tests.EnlistmentPerFixture
{
[TestFixtureSource(typeof(FileSystemRunner), FileSystemRunner.TestRunners)]
[Category(Categories.GitCommands)]
[Category(Categories.Mac.M2)]
public class GitMoveRenameTests : TestsWithEnlistmentPerFixture
{
private string testFileContents = "0123456789";
Expand All @@ -31,6 +32,7 @@ public void GitStatus()
}

[TestCase, Order(2)]
[Category(Categories.Mac.M2TODO)]
public void GitStatusAfterNewFile()
{
string filename = "new.cs";
Expand All @@ -48,6 +50,7 @@ public void GitStatusAfterNewFile()
}

[TestCase, Order(3)]
[Category(Categories.Mac.M2TODO)]
public void GitStatusAfterFileNameCaseChange()
{
string oldFilename = "new.cs";
Expand All @@ -65,6 +68,7 @@ public void GitStatusAfterFileNameCaseChange()
}

[TestCase, Order(4)]
[Category(Categories.Mac.M2TODO)]
public void GitStatusAfterFileRename()
{
string oldFilename = "New.cs";
Expand All @@ -82,6 +86,7 @@ public void GitStatusAfterFileRename()
}

[TestCase, Order(5)]
[Category(Categories.Mac.M3)]
public void GitStatusAndObjectAfterGitAdd()
{
string existingFilename = "test.cs";
Expand Down Expand Up @@ -117,6 +122,7 @@ public void GitStatusAndObjectAfterGitAdd()
}

[TestCase, Order(6)]
[Category(Categories.Mac.M3)]
public void GitStatusAfterUnstage()
{
string existingFilename = "test.cs";
Expand All @@ -139,7 +145,7 @@ public void GitStatusAfterUnstage()
public void GitStatusAfterFileDelete()
{
string existingFilename = "test.cs";
this.Enlistment.GetVirtualPathTo(existingFilename).ShouldBeAFile(this.fileSystem);
this.EnsureTestFileExists(existingFilename);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you need to change the behavior here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately all of the tests in this class were written to be completely dependent on all of the tests running in order.

GitStatusAfterFileDelete was assuming that all prior tests ran, and one of those tests creates "test.cs". Because we can't run all of the tests just yet there is currently no "test.cs" at the point this test runs.

With this change you can run this individual test without having to run the tests listed above it.

this.fileSystem.DeleteFile(this.Enlistment.GetVirtualPathTo(existingFilename));
this.Enlistment.GetVirtualPathTo(existingFilename).ShouldNotExistOnDisk(this.fileSystem);

Expand Down Expand Up @@ -170,6 +176,7 @@ public void GitWithEnvironmentVariables()
}

[TestCase, Order(9)]
[Category(Categories.Mac.M2TODO)]
public void GitStatusAfterRenameFileIntoRepo()
{
string filename = "GitStatusAfterRenameFileIntoRepo.cs";
Expand All @@ -196,7 +203,7 @@ public void GitStatusAfterRenameFileIntoRepo()
[TestCase, Order(10)]
public void GitStatusAfterRenameFileOutOfRepo()
{
string existingFilename = "Test_EPF_MoveRenameFileTests\\ChangeUnhydratedFileName\\Program.cs";
string existingFilename = Path.Combine("Test_EPF_MoveRenameFileTests", "ChangeUnhydratedFileName", "Program.cs");

// Move the test file to this.Enlistment.EnlistmentRoot as it's outside of src
// and is cleaned up when the functional tests run
Expand All @@ -210,6 +217,7 @@ public void GitStatusAfterRenameFileOutOfRepo()
}

[TestCase, Order(11)]
[Category(Categories.Mac.M2TODO)]
public void GitStatusAfterRenameFolderIntoRepo()
{
string folderName = "GitStatusAfterRenameFolderIntoRepo";
Expand All @@ -235,5 +243,16 @@ public void GitStatusAfterRenameFolderIntoRepo()
folderName + "/",
folderName + "/" + fileName);
}

private void EnsureTestFileExists(string relativePath)
{
string filePath = this.Enlistment.GetVirtualPathTo(relativePath);
if (!this.fileSystem.FileExists(filePath))
{
this.fileSystem.WriteAllText(filePath, this.testFileContents);
}

this.Enlistment.GetVirtualPathTo(relativePath).ShouldBeAFile(this.fileSystem);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace GVFS.FunctionalTests.Tests.EnlistmentPerFixture
// TODO 452590 - Combine all of the MoveRenameTests into a single fixture, and have each use different
// well known files
[TestFixtureSource(typeof(FileSystemRunner), FileSystemRunner.TestRunners)]
[Category(Categories.Mac.M2TODO)]
public class MoveRenameFileTests : TestsWithEnlistmentPerFixture
{
public const string TestFileContents =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace GVFS.FunctionalTests.Tests.EnlistmentPerFixture
// TODO 452590 - Combine all of the MoveRenameTests into a single fixture, and have each use different
// well known files
[TestFixtureSource(typeof(FileSystemRunner), FileSystemRunner.TestRunners)]
[Category(Categories.Mac.M2TODO)]
public class MoveRenameFileTests_2 : TestsWithEnlistmentPerFixture
{
private const string TestFileFolder = "Test_EPF_MoveRenameFileTests_2";
Expand Down
Loading