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

simplify and align functional test CI and docs, and fix failing skipped test #424

Merged
merged 7 commits into from
Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .azure-pipelines/templates/osx/functional-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ steps:
- bash: watchman log-level debug
displayName: Set watchman log level to debug

- bash: $(Build.BinariesDirectory)/ft/src/Scripts/Mac/RunFunctionalTests.sh $(configuration) --test-scalar-on-path --trace2-output=$(Build.ArtifactStagingDirectory)/logs/trace2-event.log
- bash: $(Build.BinariesDirectory)/ft/src/Scripts/Mac/RunFunctionalTests.sh $(configuration) --full-suite --test-scalar-on-path --trace2-output=$(Build.ArtifactStagingDirectory)/logs/trace2-event.log
displayName: Run functional tests

- ${{ if eq(parameters.useWatchman, 'true') }}:
Expand Down
2 changes: 1 addition & 1 deletion .azure-pipelines/templates/win/functional-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ steps:
- script: git config --global credential.interactive never
displayName: Disable interactive auth

- script: $(Build.BinariesDirectory)\ft\src\Scripts\RunFunctionalTests.bat $(configuration) --test-scalar-on-path "--trace2-output=$(Build.ArtifactStagingDirectory)\logs\trace2-event.log"
- script: $(Build.BinariesDirectory)\ft\src\Scripts\RunFunctionalTests.bat $(configuration) --full-suite --test-scalar-on-path "--trace2-output=$(Build.ArtifactStagingDirectory)\logs\trace2-event.log"
displayName: Run functional tests

- ${{ if eq(parameters.useWatchman, 'true') }}:
Expand Down
41 changes: 10 additions & 31 deletions AuthoringTests.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,8 @@
#### Runnable functional test projects

- `Scalar.FunctionalTests`
- `Scalar.FunctionalTests.Windows`

`Scalar.FunctionalTests` is a .NET Core project and contains all cross-platform functional tests. `Scalar.FunctionalTests.Windows`, contains functional tests that require Windows. Additionally, `Scalar.FunctionalTests.Windows` includes all the `Scalar.FunctionalTests` allowing it to run both cross-platform and Windows-specific functional tests.

#### Other functional test projects

*Scalar.NativeTests*

`Scalar.NativeTests` contains tests written in C++ that use the Windows API directly. These tests are called from the managed tests (see above) using PInvoke.

*Scalar.FunctionalTests.LockHolder*

The `LockHolder` is a small program that allows the functional tests to request and release the `ScalarLock`. `LockHolder` is useful for simulating different timing/race conditions.
`Scalar.FunctionalTests` is a .NET Core project and contains all cross-platform functional tests.

## Running the Functional Tests

Expand All @@ -34,19 +23,13 @@ The functional tests are built on NUnit 3, which is available as a set of NuGet
2. Run the Scalar installer that was built in step 2. This will ensure that Scalar will be able to find the correct version of the pre/post-command hooks. The installer will be placed in `BuildOutput\Scalar.Installer.Windows\bin\x64\<Debug or Release>`
3. Run the tests **with elevation**. Elevation is required because the functional tests create and delete a test service.

**Option 1:** Run the `Scalar.FunctionalTests.Windows` project from inside Visual Studio launched as Administrator.
**Option 1:** Run the `Scalar.FunctionalTests` project from inside Visual Studio launched as Administrator.

**Option 2:** Run `Scripts\RunFunctionalTests.bat` from CMD launched as Administrator.

#### Selecting Which Tests are Run

By default, the functional tests run a subset of tests as a quick smoke test for developers. There are three mutually exclusive arguments that can be passed to the functional tests to change this behavior:

- `--full-suite`: Run all configurations of all functional tests
- `--extra-only`: Run only those tests marked as "ExtraCoverage" (i.e. the tests that are not run by default)
- `--windows-only`: Run only the tests marked as being Windows specific

**NOTE** `Scripts\RunFunctionalTests.bat` already uses some of these arguments. If you run the tests using `RunFunctionalTests.bat` consider locally modifying the script rather than passing these flags as arguments to the script.
By default, the functional tests run on a single configuration. Passing the `--full-suite` option runs all tests on all configurations.

### Mac

Expand Down Expand Up @@ -79,34 +62,30 @@ Note that the test name must include the class and namespace and that `Debug` or

Windows (Script):

`Scripts\RunFunctionalTests.bat Debug --test=Scalar.FunctionalTests.Tests.EnlistmentPerFixture.GitFilesTests.CreateFileTest`
`Scripts\RunFunctionalTests.bat Debug --test=Scalar.FunctionalTests.Tests.EnlistmentPerFixture.CloneTests.CloneToPathWithSpaces

Windows (Visual Studio):

1. Set `Scalar.FunctionalTests.Windows` as StartUp project
2. Project Properties->Debug->Start options->Command line arguments (all on a single line): `--test=Scalar.FunctionalTests.Tests.EnlistmentPerFixture.GitFilesTests.CreateFileTest`
1. Set `Scalar.FunctionalTests` as StartUp project
2. Project Properties->Debug->Start options->Command line arguments (all on a single line): `--test=Scalar.FunctionalTests.Tests.EnlistmentPerFixture.CloneTests.CloneToPathWithSpaces

Mac:

`Scripts/Mac/RunFunctionalTests.sh Debug --test=Scalar.FunctionalTests.Tests.EnlistmentPerFixture.GitFilesTests.CreateFileTest`
`Scripts/Mac/RunFunctionalTests.sh Debug --test=Scalar.FunctionalTests.Tests.EnlistmentPerFixture.CloneTests.CloneToPathWithSpaces`

## How to Write a Functional Test

Each piece of functionality that we add to Scalar should have corresponding functional tests that clone a repo and use existing tools and filesystem APIs to interact with the virtual repo.

Since these are functional tests that can potentially modify the state of files on disk, you need to be careful to make sure each test can run in a clean
environment. There are three base classes that you can derive from when writing your tests. It's also important to put your new class into the same namespace
environment. There are two base classes that you can derive from when writing your tests. It's also important to put your new class into the same namespace
as the base class, because NUnit treats namespaces like test suites, and we have logic that keys off that for deciding when to create enlistments.

1. `TestsWithLongRunningEnlistment`

Before any test in this namespace is executed, we create a single enlistment. We then run all tests in this namespace that derive from this base class. Only put tests in here that are purely readonly and will leave the repo in a good state for future tests.

2. `TestsWithEnlistmentPerFixture`
1. `TestsWithEnlistmentPerFixture`

For any test fixture (a fixture is the same as a class in NUnit) that derives from this class, we create an enlistment before running any of the tests in the fixture, and then we delete the enlistment after all tests are done (but before any other fixture runs). If you need to write a sequence of tests that manipulate the same repo, this is the right base class.

3. `TestsWithEnlistmentPerTestCase`
2. `TestsWithEnlistmentPerTestCase`

Derive from this class if you need a new enlistment created for each test case. This is the most reliable, but also most expensive option.

Expand Down
1 change: 0 additions & 1 deletion Scalar.FunctionalTests/Categories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ namespace Scalar.FunctionalTests
{
public static class Categories
{
public const string ExtraCoverage = "ExtraCoverage";
public const string GitCommands = "GitCommands";

public const string WindowsOnly = "WindowsOnly";
Expand Down
31 changes: 0 additions & 31 deletions Scalar.FunctionalTests/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,6 @@ public static void Main(string[] args)
}
else
{
if (runner.HasCustomArg("--extra-only"))
{
Console.WriteLine("Running only the tests marked as ExtraCoverage");
includeCategories.Add(Categories.ExtraCoverage);
}
else
{
excludeCategories.Add(Categories.ExtraCoverage);
}

ScalarTestConfig.FileSystemRunners = FileSystemRunners.FileSystemRunner.DefaultRunners;
}

Expand All @@ -89,15 +79,6 @@ public static void Main(string[] args)
}
else
{
if (runner.HasCustomArg("--windows-only"))
{
includeCategories.Add(Categories.WindowsOnly);

// RunTests unions all includeCategories. Remove ExtraCoverage to
// ensure that we only run tests flagged as WindowsOnly
includeCategories.Remove(Categories.ExtraCoverage);
}

excludeCategories.Add(Categories.MacOnly);
}

Expand Down Expand Up @@ -135,18 +116,6 @@ private static void RunBeforeAnyTests()
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
ScalarServiceProcess.InstallService();

string statusCacheVersionTokenPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles, Environment.SpecialFolderOption.Create),
"Scalar",
"ProgramData",
"Scalar.Service",
"EnableGitStatusCacheToken.dat");

if (!File.Exists(statusCacheVersionTokenPath))
{
File.WriteAllText(statusCacheVersionTokenPath, string.Empty);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Scalar.FunctionalTests.Tests.EnlistmentPerFixture
{
[TestFixture]
[Category(Categories.ExtraCoverage)]
public class CacheServerTests : TestsWithEnlistmentPerFixture
{
private const string CustomUrl = "https://myCache";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
namespace Scalar.FunctionalTests.Tests.EnlistmentPerFixture
{
[TestFixture]
[Category(Categories.ExtraCoverage)]
public class FetchStepWithoutSharedCacheTests : TestsWithEnlistmentPerFixture
{
private const string PrefetchPackPrefix = "prefetch";
Expand Down Expand Up @@ -101,8 +100,9 @@ public void FetchStepCleansUpBadPrefetchPack()
this.TempPackRoot.ShouldBeADirectory(this.fileSystem).WithNoItems();
}

// WindowsOnly because the test depends on Windows-specific file sharing behavior
[TestCase, Order(4)]
[Category(Categories.MacTODO.TestNeedsToLockFile)]
[Category(Categories.WindowsOnly)]
public void FetchStepFailsWhenItCannotRemoveABadPrefetchPack()
{
this.Enlistment.Unregister();
Expand All @@ -119,10 +119,11 @@ public void FetchStepFailsWhenItCannotRemoveABadPrefetchPack()
// Open a handle to the bad pack that will prevent fetch-commits-and-trees from being able to delete it
using (FileStream stream = new FileStream(badPackPath, FileMode.Open, FileAccess.Read, FileShare.None))
{
string output = this.Enlistment.RunVerb("fetch", failOnError: false);
output.ShouldContain($"Unable to delete {badPackPath}");
this.Enlistment.RunVerb("fetch", failOnError: false);
}

badPackPath.ShouldBeAFile(this.fileSystem).WithContents(badContents);

// After handle is closed fetching commits and trees should succeed
this.Enlistment.RunVerb("fetch");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ namespace Scalar.FunctionalTests.Tests.EnlistmentPerFixture
{
[TestFixture]
[NonParallelizable]
[Category(Categories.ExtraCoverage)]
[Category(Categories.WindowsOnly)]
[Category(Categories.NeedsUpdatesForNonVirtualizedMode)]
public class UpgradeReminderTests : TestsWithEnlistmentPerFixture
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
namespace Scalar.FunctionalTests.Tests.MultiEnlistmentTests
{
[TestFixture]
[Category(Categories.ExtraCoverage)]
[Category(Categories.NeedsUpdatesForNonVirtualizedMode)]
public class ConfigVerbTests : TestsWithMultiEnlistment
{
Expand Down
2 changes: 1 addition & 1 deletion Scripts/Mac/RunFunctionalTests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ shift
chmod +x $TESTS_EXEC

# Run the tests!
$TESTS_EXEC --full-suite "$@"
$TESTS_EXEC "$@"