Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
This commit is contained in:
Derrick Stolee 2021-06-15 15:09:48 -04:00
Родитель f513cd7799
Коммит db77f0d54a
77 изменённых файлов: 93 добавлений и 9332 удалений

Просмотреть файл

@ -21,9 +21,6 @@ steps:
- script: Scripts/Mac/BuildScalarForMac.sh $(configuration) $(majorAndMinorVersion).$(revision)
displayName: Build Scalar ($(configuration))
- script: Scripts/Mac/RunUnitTests.sh $(configuration) $(Common.TestResultsDirectory)
displayName: Run unit tests ($(configuration))
- task: PublishTestResults@2
displayName: Publish test results
inputs:

Просмотреть файл

@ -21,9 +21,6 @@ steps:
- script: $(Build.Repository.LocalPath)\Scripts\BuildScalarForWindows.bat $(configuration) $(majorAndMinorVersion).$(revision)
displayName: Build Scalar ($(configuration))
- script: $(Build.Repository.LocalPath)\Scripts\RunUnitTests.bat $(configuration) $(Common.TestResultsDirectory)
displayName: Run unit tests ($(configuration))
- task: PublishTestResults@2
displayName: Publish unit test results
inputs:

Просмотреть файл

@ -1,7 +0,0 @@
namespace Scalar.UnitTests.Category
{
public static class CategoryConstants
{
public const string ExceptionExpected = "ExceptionExpected";
}
}

Просмотреть файл

@ -1,35 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class NuGetUpgraderTests
{
[TestCase("https://pkgs.dev.azure.com/test-pat/_packaging/Test-Scalar-Installers-Custom/nuget/v3/index.json", "https://test-pat.visualstudio.com")]
[TestCase("https://PKGS.DEV.azure.com/test-pat/_packaging/Test-Scalar-Installers-Custom/nuget/v3/index.json", "https://test-pat.visualstudio.com")]
[TestCase("https://dev.azure.com/test-pat/_packaging/Test-Scalar-Installers-Custom/nuget/v3/index.json", null)]
[TestCase("http://pkgs.dev.azure.com/test-pat/_packaging/Test-Scalar-Installers-Custom/nuget/v3/index.json", null)]
public void CanConstructAzureDevOpsUrlFromPackageFeedUrl(string packageFeedUrl, string expectedAzureDevOpsUrl)
{
bool success = AzDevOpsOrgFromNuGetFeed.TryCreateCredentialQueryUrl(
packageFeedUrl,
out string azureDevOpsUrl,
out string error);
if (expectedAzureDevOpsUrl != null)
{
success.ShouldBeTrue();
azureDevOpsUrl.ShouldEqual(expectedAzureDevOpsUrl);
error.ShouldBeNull();
}
else
{
success.ShouldBeFalse();
azureDevOpsUrl.ShouldBeNull();
error.ShouldNotBeNull();
}
}
}
}

Просмотреть файл

@ -1,219 +0,0 @@
using Newtonsoft.Json;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.Git;
using Scalar.Common.Http;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.Git;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class CacheServerResolverTests
{
private const string CacheServerUrl = "https://cache/server";
private const string CacheServerName = "TestCacheServer";
[TestCase]
public void CanGetCacheServerFromNewConfig()
{
MockScalarEnlistment enlistment = this.CreateEnlistment(CacheServerUrl);
CacheServerInfo cacheServer = CacheServerResolver.GetCacheServerFromConfig(enlistment);
cacheServer.Url.ShouldEqual(CacheServerUrl);
CacheServerResolver.GetUrlFromConfig(enlistment).ShouldEqual(CacheServerUrl);
}
[TestCase]
public void CanGetCacheServerWithNoConfig()
{
MockScalarEnlistment enlistment = this.CreateEnlistment();
this.ValidateIsNone(enlistment, CacheServerResolver.GetCacheServerFromConfig(enlistment));
CacheServerResolver.GetUrlFromConfig(enlistment).ShouldEqual(enlistment.RepoUrl);
}
[TestCase]
public void CanResolveUrlForKnownName()
{
CacheServerResolver resolver = this.CreateResolver();
CacheServerInfo resolvedCacheServer;
string error;
resolver.TryResolveUrlFromRemote(CacheServerName, this.CreateScalarConfig(), out resolvedCacheServer, out error);
resolvedCacheServer.Url.ShouldEqual(CacheServerUrl);
resolvedCacheServer.Name.ShouldEqual(CacheServerName);
}
[TestCase]
public void CanResolveNameFromKnownUrl()
{
CacheServerResolver resolver = this.CreateResolver();
CacheServerInfo resolvedCacheServer = resolver.ResolveNameFromRemote(CacheServerUrl, this.CreateScalarConfig());
resolvedCacheServer.Url.ShouldEqual(CacheServerUrl);
resolvedCacheServer.Name.ShouldEqual(CacheServerName);
}
[TestCase]
public void CanResolveNameFromCustomUrl()
{
const string CustomUrl = "https://not/a/known/cache/server";
CacheServerResolver resolver = this.CreateResolver();
CacheServerInfo resolvedCacheServer = resolver.ResolveNameFromRemote(CustomUrl, this.CreateScalarConfig());
resolvedCacheServer.Url.ShouldEqual(CustomUrl);
resolvedCacheServer.Name.ShouldEqual(CacheServerInfo.ReservedNames.UserDefined);
}
[TestCase]
public void CanResolveUrlAsRepoUrl()
{
MockScalarEnlistment enlistment = this.CreateEnlistment();
CacheServerResolver resolver = this.CreateResolver(enlistment);
this.ValidateIsNone(enlistment, resolver.ResolveNameFromRemote(enlistment.RepoUrl, this.CreateScalarConfig()));
this.ValidateIsNone(enlistment, resolver.ResolveNameFromRemote(enlistment.RepoUrl + "/", this.CreateScalarConfig()));
this.ValidateIsNone(enlistment, resolver.ResolveNameFromRemote(enlistment.RepoUrl + "//", this.CreateScalarConfig()));
this.ValidateIsNone(enlistment, resolver.ResolveNameFromRemote(enlistment.RepoUrl.ToUpper(), this.CreateScalarConfig()));
this.ValidateIsNone(enlistment, resolver.ResolveNameFromRemote(enlistment.RepoUrl.ToUpper() + "/", this.CreateScalarConfig()));
this.ValidateIsNone(enlistment, resolver.ResolveNameFromRemote(enlistment.RepoUrl.ToLower(), this.CreateScalarConfig()));
this.ValidateIsNone(enlistment, resolver.ResolveNameFromRemote(enlistment.RepoUrl.ToLower() + "/", this.CreateScalarConfig()));
}
[TestCase]
public void CanParseUrl()
{
CacheServerResolver resolver = new CacheServerResolver(new MockTracer(), this.CreateEnlistment());
CacheServerInfo parsedCacheServer = resolver.ParseUrlOrFriendlyName(CacheServerUrl);
parsedCacheServer.Url.ShouldEqual(CacheServerUrl);
parsedCacheServer.Name.ShouldEqual(CacheServerInfo.ReservedNames.UserDefined);
}
[TestCase]
public void CanParseName()
{
CacheServerResolver resolver = new CacheServerResolver(new MockTracer(), this.CreateEnlistment());
CacheServerInfo parsedCacheServer = resolver.ParseUrlOrFriendlyName(CacheServerName);
parsedCacheServer.Url.ShouldEqual(null);
parsedCacheServer.Name.ShouldEqual(CacheServerName);
}
[TestCase]
public void CanParseAndResolveDefault()
{
CacheServerResolver resolver = this.CreateResolver();
CacheServerInfo parsedCacheServer = resolver.ParseUrlOrFriendlyName(null);
parsedCacheServer.Url.ShouldEqual(null);
parsedCacheServer.Name.ShouldEqual(CacheServerInfo.ReservedNames.Default);
CacheServerInfo resolvedCacheServer;
string error;
resolver.TryResolveUrlFromRemote(parsedCacheServer.Name, this.CreateScalarConfig(), out resolvedCacheServer, out error);
resolvedCacheServer.Url.ShouldEqual(CacheServerUrl);
resolvedCacheServer.Name.ShouldEqual(CacheServerName);
}
[TestCase]
public void CanParseAndResolveNoCacheServer()
{
MockScalarEnlistment enlistment = this.CreateEnlistment();
CacheServerResolver resolver = this.CreateResolver(enlistment);
this.ValidateIsNone(enlistment, resolver.ParseUrlOrFriendlyName(CacheServerInfo.ReservedNames.None));
this.ValidateIsNone(enlistment, resolver.ParseUrlOrFriendlyName(enlistment.RepoUrl));
this.ValidateIsNone(enlistment, resolver.ParseUrlOrFriendlyName(enlistment.RepoUrl));
this.ValidateIsNone(enlistment, resolver.ParseUrlOrFriendlyName(enlistment.RepoUrl + "/"));
this.ValidateIsNone(enlistment, resolver.ParseUrlOrFriendlyName(enlistment.RepoUrl + "//"));
this.ValidateIsNone(enlistment, resolver.ParseUrlOrFriendlyName(enlistment.RepoUrl.ToUpper()));
this.ValidateIsNone(enlistment, resolver.ParseUrlOrFriendlyName(enlistment.RepoUrl.ToUpper() + "/"));
this.ValidateIsNone(enlistment, resolver.ParseUrlOrFriendlyName(enlistment.RepoUrl.ToLower()));
this.ValidateIsNone(enlistment, resolver.ParseUrlOrFriendlyName(enlistment.RepoUrl.ToLower() + "/"));
CacheServerInfo resolvedCacheServer;
string error;
resolver.TryResolveUrlFromRemote(CacheServerInfo.ReservedNames.None, this.CreateScalarConfig(), out resolvedCacheServer, out error)
.ShouldEqual(false, "Should not succeed in resolving the name 'None'");
resolvedCacheServer.ShouldEqual(null);
error.ShouldNotBeNull();
}
[TestCase]
public void CanParseAndResolveDefaultWhenServerAdvertisesNullListOfCacheServers()
{
MockScalarEnlistment enlistment = this.CreateEnlistment();
CacheServerResolver resolver = this.CreateResolver(enlistment);
CacheServerInfo resolvedCacheServer;
string error;
resolver.TryResolveUrlFromRemote(CacheServerInfo.ReservedNames.Default, this.CreateDefaultDeserializedScalarConfig(), out resolvedCacheServer, out error)
.ShouldEqual(true);
this.ValidateIsNone(enlistment, resolvedCacheServer);
}
[TestCase]
public void CanParseAndResolveOtherWhenServerAdvertisesNullListOfCacheServers()
{
MockScalarEnlistment enlistment = this.CreateEnlistment();
CacheServerResolver resolver = this.CreateResolver(enlistment);
CacheServerInfo resolvedCacheServer;
string error;
resolver.TryResolveUrlFromRemote(CacheServerInfo.ReservedNames.None, this.CreateDefaultDeserializedScalarConfig(), out resolvedCacheServer, out error)
.ShouldEqual(false, "Should not succeed in resolving the name 'None'");
resolvedCacheServer.ShouldEqual(null);
error.ShouldNotBeNull();
}
private void ValidateIsNone(Enlistment enlistment, CacheServerInfo cacheServer)
{
cacheServer.Url.ShouldEqual(enlistment.RepoUrl);
cacheServer.Name.ShouldEqual(CacheServerInfo.ReservedNames.None);
}
private MockScalarEnlistment CreateEnlistment(string newConfigValue = null, string oldConfigValue = null)
{
MockGitProcess gitProcess = new MockGitProcess();
gitProcess.SetExpectedCommandResult(
"config --local gvfs.cache-server",
() => new GitProcess.Result(newConfigValue ?? string.Empty, string.Empty, newConfigValue != null ? GitProcess.Result.SuccessCode : GitProcess.Result.GenericFailureCode));
gitProcess.SetExpectedCommandResult(
"config scalar.mock:..repourl.cache-server-url",
() => new GitProcess.Result(oldConfigValue ?? string.Empty, string.Empty, oldConfigValue != null ? GitProcess.Result.SuccessCode : GitProcess.Result.GenericFailureCode));
return new MockScalarEnlistment(gitProcess);
}
private ServerScalarConfig CreateScalarConfig()
{
return new ServerScalarConfig
{
CacheServers = new[]
{
new CacheServerInfo(CacheServerUrl, CacheServerName, globalDefault: true),
}
};
}
private ServerScalarConfig CreateDefaultDeserializedScalarConfig()
{
return JsonConvert.DeserializeObject<ServerScalarConfig>("{}");
}
private CacheServerResolver CreateResolver(MockScalarEnlistment enlistment = null)
{
enlistment = enlistment ?? this.CreateEnlistment();
return new CacheServerResolver(new MockTracer(), enlistment);
}
}
}

Просмотреть файл

@ -1,55 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
using System;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class EpochConverterTests
{
[TestCase]
public void DateToEpochToDate()
{
DateTime time = new DateTime(2018, 12, 18, 8, 12, 13, DateTimeKind.Utc);
DateTime converted = EpochConverter.FromUnixEpochSeconds(EpochConverter.ToUnixEpochSeconds(time));
time.ShouldEqual(converted);
}
[TestCase]
public void EpochToDateToEpoch()
{
long time = 15237623489;
long converted = EpochConverter.ToUnixEpochSeconds(EpochConverter.FromUnixEpochSeconds(time));
time.ShouldEqual(converted);
}
[TestCase]
public void FixedDates()
{
DateTime[] times = new DateTime[]
{
new DateTime(2018, 12, 13, 20, 53, 30, DateTimeKind.Utc),
new DateTime(2035, 1, 3, 5, 0, 59, DateTimeKind.Utc),
new DateTime(1989, 12, 31, 23, 59, 59, DateTimeKind.Utc)
};
long[] epochs = new long[]
{
1544734410,
2051413259,
631151999
};
for (int i = 0; i < times.Length; i++)
{
long epoch = EpochConverter.ToUnixEpochSeconds(times[i]);
epoch.ShouldEqual(epochs[i]);
DateTime time = EpochConverter.FromUnixEpochSeconds(epochs[i]);
time.ShouldEqual(times[i]);
}
}
}
}

Просмотреть файл

@ -1,428 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
using Scalar.UnitTests.Category;
using Scalar.UnitTests.Mock;
using Scalar.UnitTests.Mock.FileSystem;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class FileBasedDictionaryTests
{
private const string MockEntryFileName = "mock:\\entries.dat";
private const string TestKey = "akey";
private const string TestValue = "avalue";
private const string UpdatedTestValue = "avalue2";
private const string TestEntry = "A {\"Key\":\"akey\",\"Value\":\"avalue\"}\r\n";
private const string UpdatedTestEntry = "A {\"Key\":\"akey\",\"Value\":\"avalue2\"}\r\n";
private const string TestKey2 = "bkey";
private const string TestValue2 = "bvalue";
private const string UpdatedTestValue2 = "bvalue2";
private const string TestEntry2 = "A {\"Key\":\"bkey\",\"Value\":\"bvalue\"}\r\n";
private const string UpdatedTestEntry2 = "A {\"Key\":\"bkey\",\"Value\":\"bvalue2\"}\r\n";
[TestCase]
public void ParsesExistingDataCorrectly()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem();
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, TestEntry);
string value;
dut.TryGetValue(TestKey, out value).ShouldEqual(true);
value.ShouldEqual(TestValue);
}
[TestCase]
public void SetValueAndFlushWritesEntryToDisk()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem();
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
dut.SetValueAndFlush(TestKey, TestValue);
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { TestEntry });
}
[TestCase]
public void SetValuesAndFlushWritesEntriesToDisk()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem();
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
dut.SetValuesAndFlush(
new[]
{
new KeyValuePair<string, string>(TestKey, TestValue),
new KeyValuePair<string, string>(TestKey2, TestValue2),
});
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { TestEntry, TestEntry2 });
}
[TestCase]
public void SetValuesAndFlushWritesNewEntryAndUpdatesExistingEntryOnDisk()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem();
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
// Add TestKey to disk
dut.SetValueAndFlush(TestKey, TestValue);
fs.ExpectedFiles[MockEntryFileName].ReadAsString().ShouldEqual(TestEntry);
// This call to SetValuesAndFlush should update TestKey and write TestKey2
dut.SetValuesAndFlush(
new[]
{
new KeyValuePair<string, string>(TestKey, UpdatedTestValue),
new KeyValuePair<string, string>(TestKey2, TestValue2),
});
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { UpdatedTestEntry, TestEntry2 });
}
[TestCase]
public void SetValuesAndFlushWritesUpdatesExistingEntriesOnDisk()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem();
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
dut.SetValuesAndFlush(
new[]
{
new KeyValuePair<string, string>(TestKey, TestValue),
new KeyValuePair<string, string>(TestKey2, TestValue2),
});
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { TestEntry, TestEntry2 });
dut.SetValuesAndFlush(
new[]
{
new KeyValuePair<string, string>(TestKey, UpdatedTestValue),
new KeyValuePair<string, string>(TestKey2, UpdatedTestValue2),
});
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { UpdatedTestEntry, UpdatedTestEntry2 });
}
[TestCase]
public void SetValuesAndFlushUsesLastValueWhenKeyDuplicated()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem();
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
dut.SetValuesAndFlush(
new[]
{
new KeyValuePair<string, string>(TestKey, TestValue),
new KeyValuePair<string, string>(TestKey, UpdatedTestValue),
});
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { UpdatedTestEntry });
}
[TestCase]
public void SetValueAndFlushUpdatedEntryOnDisk()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem();
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, TestEntry);
dut.SetValueAndFlush(TestKey, UpdatedTestValue);
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { UpdatedTestEntry });
}
[TestCase]
[NUnit.Framework.Category(CategoryConstants.ExceptionExpected)]
public void SetValueAndFlushRecoversFromFailedOpenFileStream()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem(
openFileStreamFailurePath: MockEntryFileName + ".tmp",
maxOpenFileStreamFailures: 5,
fileExistsFailurePath: null,
maxFileExistsFailures: 0,
maxMoveAndOverwriteFileFailures: 5);
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
dut.SetValueAndFlush(TestKey, TestValue);
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { TestEntry });
}
[TestCase]
public void SetValueAndFlushRecoversFromDeletedTmp()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem(
openFileStreamFailurePath: null,
maxOpenFileStreamFailures: 0,
fileExistsFailurePath: MockEntryFileName + ".tmp",
maxFileExistsFailures: 5,
maxMoveAndOverwriteFileFailures: 0);
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
dut.SetValueAndFlush(TestKey, TestValue);
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { TestEntry });
}
[TestCase]
[NUnit.Framework.Category(CategoryConstants.ExceptionExpected)]
public void SetValueAndFlushRecoversFromFailedOverwrite()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem(
openFileStreamFailurePath: null,
maxOpenFileStreamFailures: 0,
fileExistsFailurePath: null,
maxFileExistsFailures: 0,
maxMoveAndOverwriteFileFailures: 5);
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
dut.SetValueAndFlush(TestKey, TestValue);
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { TestEntry });
}
[TestCase]
[NUnit.Framework.Category(CategoryConstants.ExceptionExpected)]
public void SetValueAndFlushRecoversFromDeletedTempAndFailedOverwrite()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem(
openFileStreamFailurePath: null,
maxOpenFileStreamFailures: 0,
fileExistsFailurePath: MockEntryFileName + ".tmp",
maxFileExistsFailures: 5,
maxMoveAndOverwriteFileFailures: 5);
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
dut.SetValueAndFlush(TestKey, TestValue);
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { TestEntry });
}
[TestCase]
[NUnit.Framework.Category(CategoryConstants.ExceptionExpected)]
public void SetValueAndFlushRecoversFromMixOfFailures()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem(failuresAcrossOpenExistsAndOverwritePath: MockEntryFileName + ".tmp");
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, string.Empty);
dut.SetValueAndFlush(TestKey, TestValue);
this.FileBasedDictionaryFileSystemShouldContain(fs, new[] { TestEntry });
}
[TestCase]
public void DeleteFlushesToDisk()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem();
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, TestEntry);
dut.RemoveAndFlush(TestKey);
fs.ExpectedFiles[MockEntryFileName].ReadAsString().ShouldBeEmpty();
}
[TestCase]
public void DeleteUnusedKeyFlushesToDisk()
{
FileBasedDictionaryFileSystem fs = new FileBasedDictionaryFileSystem();
FileBasedDictionary<string, string> dut = CreateFileBasedDictionary(fs, TestEntry);
dut.RemoveAndFlush("UnusedKey");
fs.ExpectedFiles[MockEntryFileName].ReadAsString().ShouldEqual(TestEntry);
}
private static FileBasedDictionary<string, string> CreateFileBasedDictionary(FileBasedDictionaryFileSystem fs, string initialContents)
{
fs.ExpectedFiles.Add(MockEntryFileName, new ReusableMemoryStream(initialContents));
fs.ExpectedOpenFileStreams.Add(MockEntryFileName + ".tmp", new ReusableMemoryStream(string.Empty));
fs.ExpectedOpenFileStreams.Add(MockEntryFileName, fs.ExpectedFiles[MockEntryFileName]);
string error;
FileBasedDictionary<string, string> dut;
FileBasedDictionary<string, string>.TryCreate(null, MockEntryFileName, fs, out dut, out error).ShouldEqual(true, error);
dut.ShouldNotBeNull();
// FileBasedDictionary should only open a file stream to the non-tmp file when being created. At all other times it should
// write to a tmp file and overwrite the non-tmp file
fs.ExpectedOpenFileStreams.Remove(MockEntryFileName);
return dut;
}
private void FileBasedDictionaryFileSystemShouldContain(
FileBasedDictionaryFileSystem fs,
IList<string> expectedEntries)
{
string delimiter = "\r\n";
string fileContents = fs.ExpectedFiles[MockEntryFileName].ReadAsString();
fileContents.Substring(fileContents.Length - delimiter.Length).ShouldEqual(delimiter);
// Remove the trailing delimiter
fileContents = fileContents.Substring(0, fileContents.Length - delimiter.Length);
string[] fileLines = fileContents.Split(new[] { delimiter }, StringSplitOptions.None);
fileLines.Length.ShouldEqual(expectedEntries.Count);
foreach (string expectedEntry in expectedEntries)
{
fileLines.ShouldContain(line => line.Equals(expectedEntry.Substring(0, expectedEntry.Length - delimiter.Length)));
}
}
private class FileBasedDictionaryFileSystem : ConfigurableFileSystem
{
private int openFileStreamFailureCount;
private int maxOpenFileStreamFailures;
private string openFileStreamFailurePath;
private int fileExistsFailureCount;
private int maxFileExistsFailures;
private string fileExistsFailurePath;
private int moveAndOverwriteFileFailureCount;
private int maxMoveAndOverwriteFileFailures;
private string failuresAcrossOpenExistsAndOverwritePath;
private int failuresAcrossOpenExistsAndOverwriteCount;
public FileBasedDictionaryFileSystem()
{
this.ExpectedOpenFileStreams = new Dictionary<string, ReusableMemoryStream>();
}
public FileBasedDictionaryFileSystem(
string openFileStreamFailurePath,
int maxOpenFileStreamFailures,
string fileExistsFailurePath,
int maxFileExistsFailures,
int maxMoveAndOverwriteFileFailures)
{
this.maxOpenFileStreamFailures = maxOpenFileStreamFailures;
this.openFileStreamFailurePath = openFileStreamFailurePath;
this.fileExistsFailurePath = fileExistsFailurePath;
this.maxFileExistsFailures = maxFileExistsFailures;
this.maxMoveAndOverwriteFileFailures = maxMoveAndOverwriteFileFailures;
this.ExpectedOpenFileStreams = new Dictionary<string, ReusableMemoryStream>();
}
/// <summary>
/// Fail a mix of OpenFileStream, FileExists, and Overwrite.
/// </summary>
/// <remarks>
/// Order of failures will be:
/// 1. OpenFileStream
/// 2. FileExists
/// 3. Overwrite
/// </remarks>
public FileBasedDictionaryFileSystem(string failuresAcrossOpenExistsAndOverwritePath)
{
this.failuresAcrossOpenExistsAndOverwritePath = failuresAcrossOpenExistsAndOverwritePath;
this.ExpectedOpenFileStreams = new Dictionary<string, ReusableMemoryStream>();
}
public Dictionary<string, ReusableMemoryStream> ExpectedOpenFileStreams { get; }
public override bool FileExists(string path)
{
if (this.maxFileExistsFailures > 0)
{
if (this.fileExistsFailureCount < this.maxFileExistsFailures &&
string.Equals(path, this.fileExistsFailurePath, ScalarPlatform.Instance.Constants.PathComparison))
{
if (this.ExpectedFiles.ContainsKey(path))
{
this.ExpectedFiles.Remove(path);
}
++this.fileExistsFailureCount;
}
}
else if (this.failuresAcrossOpenExistsAndOverwritePath != null)
{
if (this.failuresAcrossOpenExistsAndOverwriteCount == 1 &&
string.Equals(path, this.failuresAcrossOpenExistsAndOverwritePath, ScalarPlatform.Instance.Constants.PathComparison))
{
if (this.ExpectedFiles.ContainsKey(path))
{
this.ExpectedFiles.Remove(path);
}
++this.failuresAcrossOpenExistsAndOverwriteCount;
}
}
return this.ExpectedFiles.ContainsKey(path);
}
public override void MoveAndOverwriteFile(string sourceFileName, string destinationFilename)
{
if (this.maxMoveAndOverwriteFileFailures > 0)
{
if (this.moveAndOverwriteFileFailureCount < this.maxMoveAndOverwriteFileFailures)
{
++this.moveAndOverwriteFileFailureCount;
throw new Win32Exception();
}
}
else if (this.failuresAcrossOpenExistsAndOverwritePath != null)
{
if (this.failuresAcrossOpenExistsAndOverwriteCount == 2)
{
++this.failuresAcrossOpenExistsAndOverwriteCount;
throw new Win32Exception();
}
}
ReusableMemoryStream source;
this.ExpectedFiles.TryGetValue(sourceFileName, out source).ShouldEqual(true, "Source file does not exist: " + sourceFileName);
this.ExpectedFiles.ContainsKey(destinationFilename).ShouldEqual(true, "MoveAndOverwriteFile expects the destination file to exist: " + destinationFilename);
this.ExpectedFiles.Remove(sourceFileName);
this.ExpectedFiles[destinationFilename] = source;
}
public override Stream OpenFileStream(string path, FileMode fileMode, FileAccess fileAccess, FileShare shareMode, FileOptions options, bool flushesToDisk)
{
ReusableMemoryStream stream;
this.ExpectedOpenFileStreams.TryGetValue(path, out stream).ShouldEqual(true, "Unexpected access of file: " + path);
if (this.maxOpenFileStreamFailures > 0)
{
if (this.openFileStreamFailureCount < this.maxOpenFileStreamFailures &&
string.Equals(path, this.openFileStreamFailurePath, ScalarPlatform.Instance.Constants.PathComparison))
{
++this.openFileStreamFailureCount;
if (this.openFileStreamFailureCount % 2 == 0)
{
throw new IOException();
}
else
{
throw new UnauthorizedAccessException();
}
}
}
else if (this.failuresAcrossOpenExistsAndOverwritePath != null)
{
if (this.failuresAcrossOpenExistsAndOverwriteCount == 0 &&
string.Equals(path, this.failuresAcrossOpenExistsAndOverwritePath, ScalarPlatform.Instance.Constants.PathComparison))
{
++this.failuresAcrossOpenExistsAndOverwriteCount;
throw new IOException();
}
}
if (fileMode == FileMode.Create)
{
this.ExpectedFiles[path] = new ReusableMemoryStream(string.Empty);
}
this.ExpectedFiles.TryGetValue(path, out stream).ShouldEqual(true, "Unexpected access of file: " + path);
return stream;
}
}
}
}

Просмотреть файл

@ -1,274 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.Git;
using Scalar.Common.X509Certificates;
using Scalar.Tests.Should;
using Scalar.UnitTests.Category;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using Scalar.UnitTests.Mock.Git;
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace Scalar.UnitTests.Common.Git
{
[TestFixture]
public class GitSslTests
{
public static object[] BoolGitSettings = new[]
{
new object[] { GitConfigSetting.HttpSslCertPasswordProtected },
new object[] { GitConfigSetting.HttpSslVerify }
};
private const string CertificateName = "TestCert";
private const string CertificatePassword = "SecurePassword";
private MockTracer tracer;
private MockGitProcess gitProcess;
private Mock<CertificateVerifier> certificateVerifierMock;
private Mock<SystemCertificateStore> certificateStoreMock;
private MockDirectory mockDirectory;
private MockFileSystem fileSystem;
[SetUp]
public void Setup()
{
this.tracer = new MockTracer();
this.gitProcess = new MockGitProcess();
this.mockDirectory = new MockDirectory("mock://root", null, null);
this.fileSystem = new MockFileSystem(this.mockDirectory);
this.certificateVerifierMock = new Mock<CertificateVerifier>();
this.certificateStoreMock = new Mock<SystemCertificateStore>();
}
[Category(CategoryConstants.ExceptionExpected)]
[TestCaseSource(typeof(GitSslTests), nameof(GitSslTests.BoolGitSettings))]
public void ConstructorShouldThrowWhenLastBoolSettingNotABool(string setting)
{
IDictionary<string, GitConfigSetting> gitConfig = new Dictionary<string, GitConfigSetting>();
gitConfig.Add(setting, new GitConfigSetting(setting, "true", "this is true"));
Assert.Throws<InvalidRepoException>(() => new GitSsl(string.Empty, gitConfig));
}
[TestCaseSource(typeof(GitSslTests), nameof(GitSslTests.BoolGitSettings))]
public void ConstructorShouldNotThrowWhenLastBoolSettingIsABool(string setting)
{
IDictionary<string, GitConfigSetting> gitConfig = new Dictionary<string, GitConfigSetting>();
gitConfig.Add(setting, new GitConfigSetting(setting, "this is true", "true"));
Assert.DoesNotThrow(() => new GitSsl(string.Empty, gitConfig));
}
[TestCase]
public void GetCertificateShouldReturnNullWhenCertificateCommonNameSettingIsEmpty()
{
GitSsl sut = new GitSsl(string.Empty, new Dictionary<string, GitConfigSetting>());
X509Certificate2 result = sut.GetCertificate(this.tracer, this.gitProcess);
result.ShouldBeNull();
}
[TestCase]
public void GetCertificateShouldReturnCertificateFromFileWhenFileExistsAndIsPasswordProtectedAndIsValid()
{
X509Certificate2 certificate = GenerateTestCertificate();
this.SetupCertificateFile(certificate, CertificatePassword);
this.SetupGitCertificatePassword();
this.MakeCertificateValid(certificate);
GitSsl gitSsl = new GitSsl(string.Empty, GetGitConfig(), () => this.certificateStoreMock.Object, this.certificateVerifierMock.Object, this.fileSystem);
X509Certificate2 result = gitSsl.GetCertificate(this.tracer, this.gitProcess);
result.ShouldNotBeNull();
result.ShouldEqual(certificate);
}
[TestCase]
public void GetCertificateShouldReturnCertificateFromFileWhenFileExistsAndIsNotPasswordProtectedAndIsValid()
{
X509Certificate2 certificate = GenerateTestCertificate();
this.SetupCertificateFile(certificate);
this.MakeCertificateValid(certificate);
GitSsl gitSsl = new GitSsl(
string.Empty,
GetGitConfig(
new GitConfigSetting(GitConfigSetting.HttpSslCertPasswordProtected, "false")),
() => this.certificateStoreMock.Object,
this.certificateVerifierMock.Object,
this.fileSystem);
X509Certificate2 result = gitSsl.GetCertificate(this.tracer, this.gitProcess);
result.ShouldNotBeNull();
result.ShouldEqual(certificate);
}
[TestCase]
public void GetCertificateShouldReturnNullWhenFileExistsAndIsNotPasswordProtectedAndIsInvalid()
{
X509Certificate2 certificate = GenerateTestCertificate();
this.SetupCertificateFile(certificate);
this.MakeCertificateValid(certificate, false);
GitSsl gitSsl = new GitSsl(
string.Empty,
GetGitConfig(
new GitConfigSetting(GitConfigSetting.HttpSslCertPasswordProtected, "false")),
() => this.certificateStoreMock.Object,
this.certificateVerifierMock.Object,
this.fileSystem);
X509Certificate2 result = gitSsl.GetCertificate(this.tracer, this.gitProcess);
result.ShouldBeNull();
}
[TestCase]
public void GetCertificateShouldReturnCertificateFromFileWhenFileExistsAndIsNotPasswordProtectedAndIsInvalidAndShouldVerifyIsFalse()
{
X509Certificate2 certificate = GenerateTestCertificate();
this.SetupCertificateFile(certificate);
this.MakeCertificateValid(certificate, false);
GitSsl gitSsl = new GitSsl(
string.Empty,
GetGitConfig(
new GitConfigSetting(GitConfigSetting.HttpSslCertPasswordProtected, "false"),
new GitConfigSetting(GitConfigSetting.HttpSslVerify, "false")),
() => this.certificateStoreMock.Object,
this.certificateVerifierMock.Object,
this.fileSystem);
X509Certificate2 result = gitSsl.GetCertificate(this.tracer, this.gitProcess);
result.ShouldNotBeNull();
result.ShouldEqual(certificate);
}
[TestCase]
public void GetCertificateShouldReturnCertificateFromStoreAccordingToRulesWhenFileDoesNotExist()
{
X509Certificate2 certificate = this.MakeCertificateValid(GenerateTestCertificate());
this.SetupGitCertificatePassword();
GitSsl gitSsl = new GitSsl(
string.Empty,
GetGitConfig(),
() => this.certificateStoreMock.Object,
this.certificateVerifierMock.Object,
this.fileSystem);
this.SetupCertificateStore(
true,
this.MakeCertificateValid(GenerateTestCertificate(CertificateName + "suphix")),
this.MakeCertificateValid(GenerateTestCertificate("prefix" + CertificateName)),
this.MakeCertificateValid(GenerateTestCertificate("not this certificate")),
this.MakeCertificateValid(GenerateTestCertificate(), false),
this.MakeCertificateValid(GenerateTestCertificate(validFrom: DateTimeOffset.Now.AddDays(-4))),
this.MakeCertificateValid(GenerateTestCertificate(validTo: DateTimeOffset.Now.AddDays(4))),
certificate);
X509Certificate2 result = gitSsl.GetCertificate(this.tracer, this.gitProcess);
result.ShouldNotBeNull();
result.ShouldEqual(certificate);
}
[TestCase]
public void GetCertificateShouldReturnNullWhenNoMatchingCertificatesExist()
{
this.SetupGitCertificatePassword();
GitSsl gitSsl = new GitSsl(
string.Empty,
GetGitConfig(),
() => this.certificateStoreMock.Object,
this.certificateVerifierMock.Object,
this.fileSystem);
this.SetupCertificateStore(
true,
this.MakeCertificateValid(GenerateTestCertificate(CertificateName + "suphix")),
this.MakeCertificateValid(GenerateTestCertificate("prefix" + CertificateName)),
this.MakeCertificateValid(GenerateTestCertificate("not this certificate")));
X509Certificate2 result = gitSsl.GetCertificate(this.tracer, this.gitProcess);
result.ShouldBeNull();
}
private static IDictionary<string, GitConfigSetting> GetGitConfig(params GitConfigSetting[] overrides)
{
IDictionary<string, GitConfigSetting> gitConfig = new Dictionary<string, GitConfigSetting>();
gitConfig.Add(GitConfigSetting.HttpSslCert, new GitConfigSetting(GitConfigSetting.HttpSslCert, CertificateName));
gitConfig.Add(GitConfigSetting.HttpSslCertPasswordProtected, new GitConfigSetting(GitConfigSetting.HttpSslCertPasswordProtected, "true"));
gitConfig.Add(GitConfigSetting.HttpSslVerify, new GitConfigSetting(GitConfigSetting.HttpSslVerify, "true"));
foreach (GitConfigSetting settingOverride in overrides)
{
gitConfig[settingOverride.Name] = settingOverride;
}
return gitConfig;
}
private static X509Certificate2 GenerateTestCertificate(
string subjectName = null,
DateTimeOffset? validFrom = null,
DateTimeOffset? validTo = null)
{
ECDsa ecdsa = ECDsa.Create();
CertificateRequest req = new CertificateRequest($"cn={subjectName ?? CertificateName}", ecdsa, HashAlgorithmName.SHA256);
X509Certificate2 cert = req.CreateSelfSigned(validFrom ?? DateTimeOffset.Now.AddDays(-5), validTo ?? DateTimeOffset.Now.AddDays(5));
return cert;
}
private X509Certificate2 MakeCertificateValid(X509Certificate2 certificate, bool isValid = true)
{
this.certificateVerifierMock.Setup(x => x.Verify(certificate)).Returns(isValid);
return certificate;
}
private void SetupGitCertificatePassword()
{
this.gitProcess.SetExpectedCommandResult("credential fill", () => new GitProcess.Result($"password={CertificatePassword}\n", null, 0));
}
private void SetupCertificateStore(bool onlyValid, params X509Certificate2[] results)
{
this.SetupCertificateStore(X509FindType.FindBySubjectName, CertificateName, onlyValid, results);
}
private void SetupCertificateStore(
X509FindType findType,
string certificateName,
bool onlyValid,
params X509Certificate2[] results)
{
X509Certificate2Collection result = new X509Certificate2Collection();
result.AddRange(results);
this.certificateStoreMock.Setup(x => x.Find(findType, certificateName, onlyValid)).Returns(result);
}
private void SetupCertificateFile(X509Certificate2 certificate, string password = null)
{
byte[] certificateContents;
if (password == null)
{
certificateContents = certificate.Export(X509ContentType.Pkcs12);
}
else
{
certificateContents = certificate.Export(X509ContentType.Pkcs12, password);
}
this.mockDirectory.AddFile(
new MockFile(CertificateName, certificateContents),
Path.Combine(this.mockDirectory.FullName, CertificateName));
}
}
}

Просмотреть файл

@ -1,77 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class GitCommandLineParserTests
{
[TestCase]
public void IsVerbTests()
{
new GitCommandLineParser("gits status --no-idea").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git status --no-idea").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(true);
new GitCommandLineParser("git status").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(true);
new GitCommandLineParser("git statuses --no-idea").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git statuses").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git add").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git checkout").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git clean").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git commit").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git mv").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git reset").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git stage").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git update-index").IsVerb(GitCommandLineParser.Verbs.Status).ShouldEqual(false);
new GitCommandLineParser("git add").IsVerb(GitCommandLineParser.Verbs.AddOrStage).ShouldEqual(true);
new GitCommandLineParser("git checkout").IsVerb(GitCommandLineParser.Verbs.Checkout).ShouldEqual(true);
new GitCommandLineParser("git commit").IsVerb(GitCommandLineParser.Verbs.Commit).ShouldEqual(true);
new GitCommandLineParser("git mv").IsVerb(GitCommandLineParser.Verbs.Move).ShouldEqual(true);
new GitCommandLineParser("git reset").IsVerb(GitCommandLineParser.Verbs.Reset).ShouldEqual(true);
new GitCommandLineParser("git stage").IsVerb(GitCommandLineParser.Verbs.AddOrStage).ShouldEqual(true);
new GitCommandLineParser("git update-index").IsVerb(GitCommandLineParser.Verbs.UpdateIndex).ShouldEqual(true);
new GitCommandLineParser("git updateindex").IsVerb(GitCommandLineParser.Verbs.UpdateIndex).ShouldEqual(false);
new GitCommandLineParser("git add some/file/to/add").IsVerb(GitCommandLineParser.Verbs.AddOrStage).ShouldEqual(true);
new GitCommandLineParser("git stage some/file/to/add").IsVerb(GitCommandLineParser.Verbs.AddOrStage).ShouldEqual(true);
new GitCommandLineParser("git adds some/file/to/add").IsVerb(GitCommandLineParser.Verbs.AddOrStage).ShouldEqual(false);
new GitCommandLineParser("git stages some/file/to/add").IsVerb(GitCommandLineParser.Verbs.AddOrStage).ShouldEqual(false);
new GitCommandLineParser("git adding add").IsVerb(GitCommandLineParser.Verbs.AddOrStage).ShouldEqual(false);
new GitCommandLineParser("git adding add").IsVerb(GitCommandLineParser.Verbs.AddOrStage).ShouldEqual(false);
new GitCommandLineParser("git adding add").IsVerb(GitCommandLineParser.Verbs.Other).ShouldEqual(true);
}
[TestCase]
public void IsResetSoftOrMixedTests()
{
new GitCommandLineParser("gits reset --soft").IsResetSoftOrMixed().ShouldEqual(false);
new GitCommandLineParser("git reset --soft").IsResetSoftOrMixed().ShouldEqual(true);
new GitCommandLineParser("git reset --mixed").IsResetSoftOrMixed().ShouldEqual(true);
new GitCommandLineParser("git reset").IsResetSoftOrMixed().ShouldEqual(true);
new GitCommandLineParser("git reset --hard").IsResetSoftOrMixed().ShouldEqual(false);
new GitCommandLineParser("git reset --keep").IsResetSoftOrMixed().ShouldEqual(false);
new GitCommandLineParser("git reset --merge").IsResetSoftOrMixed().ShouldEqual(false);
new GitCommandLineParser("git checkout").IsResetSoftOrMixed().ShouldEqual(false);
new GitCommandLineParser("git status").IsResetSoftOrMixed().ShouldEqual(false);
}
[TestCase]
public void IsSerializedStatusTests()
{
new GitCommandLineParser("git status --serialized=some/file").IsSerializedStatus().ShouldEqual(true);
new GitCommandLineParser("git status --serialized").IsSerializedStatus().ShouldEqual(true);
new GitCommandLineParser("git checkout branch -- file").IsSerializedStatus().ShouldEqual(false);
new GitCommandLineParser("git status").IsSerializedStatus().ShouldEqual(false);
new GitCommandLineParser("git checkout --serialized").IsSerializedStatus().ShouldEqual(false);
new GitCommandLineParser("git checkout --serialized=some/file").IsSerializedStatus().ShouldEqual(false);
new GitCommandLineParser("gits status --serialized=some/file").IsSerializedStatus().ShouldEqual(false);
}
}
}

Просмотреть файл

@ -1,173 +0,0 @@
using NUnit.Framework;
using Scalar.Common.Git;
using Scalar.Tests.Should;
using System.Collections.Generic;
using System.Linq;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class GitConfigHelperTests
{
[TestCase]
public void SanitizeEmptyString()
{
string outputString;
GitConfigHelper.TrySanitizeConfigFileLine(string.Empty, out outputString).ShouldEqual(false);
}
[TestCase]
public void SanitizePureWhiteSpace()
{
string outputString;
GitConfigHelper.TrySanitizeConfigFileLine(" ", out outputString).ShouldEqual(false);
GitConfigHelper.TrySanitizeConfigFileLine(" \t\t ", out outputString).ShouldEqual(false);
GitConfigHelper.TrySanitizeConfigFileLine(" \t\t\n\n ", out outputString).ShouldEqual(false);
}
[TestCase]
public void SanitizeComment()
{
string outputString;
GitConfigHelper.TrySanitizeConfigFileLine("# This is a comment ", out outputString).ShouldEqual(false);
GitConfigHelper.TrySanitizeConfigFileLine("# This is a comment #", out outputString).ShouldEqual(false);
GitConfigHelper.TrySanitizeConfigFileLine("## This is a comment ##", out outputString).ShouldEqual(false);
GitConfigHelper.TrySanitizeConfigFileLine(" ## This is a comment ## ", out outputString).ShouldEqual(false);
GitConfigHelper.TrySanitizeConfigFileLine("\t ## This is a comment ## \t ", out outputString).ShouldEqual(false);
}
[TestCase]
public void TrimWhitspace()
{
string outputString;
GitConfigHelper.TrySanitizeConfigFileLine(" // ", out outputString).ShouldEqual(true);
outputString.ShouldEqual("//");
GitConfigHelper.TrySanitizeConfigFileLine(" /* ", out outputString).ShouldEqual(true);
outputString.ShouldEqual("/*");
GitConfigHelper.TrySanitizeConfigFileLine(" /A ", out outputString).ShouldEqual(true);
outputString.ShouldEqual("/A");
GitConfigHelper.TrySanitizeConfigFileLine("\t /A \t", out outputString).ShouldEqual(true);
outputString.ShouldEqual("/A");
GitConfigHelper.TrySanitizeConfigFileLine(" \t /A \t", out outputString).ShouldEqual(true);
outputString.ShouldEqual("/A");
}
[TestCase]
public void TrimTrailingComment()
{
string outputString;
GitConfigHelper.TrySanitizeConfigFileLine(" // # Trailing comment!", out outputString).ShouldEqual(true);
outputString.ShouldEqual("//");
GitConfigHelper.TrySanitizeConfigFileLine(" /* # Trailing comment!", out outputString).ShouldEqual(true);
outputString.ShouldEqual("/*");
GitConfigHelper.TrySanitizeConfigFileLine(" /A # Trailing comment!", out outputString).ShouldEqual(true);
outputString.ShouldEqual("/A");
GitConfigHelper.TrySanitizeConfigFileLine("\t /A \t # Trailing comment! \t", out outputString).ShouldEqual(true);
outputString.ShouldEqual("/A");
GitConfigHelper.TrySanitizeConfigFileLine(" \t /A \t # Trailing comment!", out outputString).ShouldEqual(true);
outputString.ShouldEqual("/A");
}
[TestCase]
public void ParseKeyValuesTest()
{
string input = @"
core.scalar=true
gc.auto=0
section.key=value1
section.key= value2
section.key =value3
section.key = value4
section.KEY=value5
section.empty=
";
Dictionary<string, GitConfigSetting> result = GitConfigHelper.ParseKeyValues(input);
result.Count.ShouldEqual(4);
result["core.scalar"].Values.Single().ShouldEqual("true");
result["gc.auto"].Values.Single().ShouldEqual("0");
result["section.key"].Values.Count.ShouldEqual(5);
result["section.key"].Values.ShouldContain(v => v == "value1");
result["section.key"].Values.ShouldContain(v => v == "value2");
result["section.key"].Values.ShouldContain(v => v == "value3");
result["section.key"].Values.ShouldContain(v => v == "value4");
result["section.key"].Values.ShouldContain(v => v == "value5");
result["section.empty"].Values.Single().ShouldEqual(string.Empty);
}
[TestCase]
public void ParseSpaceSeparatedKeyValuesTest()
{
string input = @"
core.scalar true
gc.auto 0
section.key value1
section.key value2
section.key value3
section.key value4
section.KEY value5" +
"\nsection.empty ";
Dictionary<string, GitConfigSetting> result = GitConfigHelper.ParseKeyValues(input, ' ');
result.Count.ShouldEqual(4);
result["core.scalar"].Values.Single().ShouldEqual("true");
result["gc.auto"].Values.Single().ShouldEqual("0");
result["section.key"].Values.Count.ShouldEqual(5);
result["section.key"].Values.ShouldContain(v => v == "value1");
result["section.key"].Values.ShouldContain(v => v == "value2");
result["section.key"].Values.ShouldContain(v => v == "value3");
result["section.key"].Values.ShouldContain(v => v == "value4");
result["section.key"].Values.ShouldContain(v => v == "value5");
result["section.empty"].Values.Single().ShouldEqual(string.Empty);
}
[TestCase]
public void GetSettingsTest()
{
string fileContents = @"
[core]
scalar = true
[gc]
auto = 0
[section]
key1 = 1
key2 = 2
key3 = 3
[notsection]
keyN1 = N1
keyN2 = N2
keyN3 = N3
[section]
[section]
key4 = 4
key5 = 5
[section]
key6 = 6
key7 =
= emptyKey";
Dictionary<string, GitConfigSetting> result = GitConfigHelper.GetSettings(fileContents.Split('\r', '\n'), "Section");
int expectedCount = 7; // empty keys will not be included.
result.Count.ShouldEqual(expectedCount);
// Verify keyN = N
for (int i = 1; i <= expectedCount - 1; i++)
{
result["key" + i.ToString()].Values.ShouldContain(v => v == i.ToString());
}
// Verify empty value
result["key7"].Values.Single().ShouldEqual(string.Empty);
}
}
}

Просмотреть файл

@ -1,29 +0,0 @@
using NUnit.Framework;
using Scalar.Common.Git;
using Scalar.Tests.Should;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class GitObjectsTests
{
[TestCase]
public void IsLooseObjectsDirectory_ValidDirectories()
{
GitObjects.IsLooseObjectsDirectory("BB").ShouldBeTrue();
GitObjects.IsLooseObjectsDirectory("bb").ShouldBeTrue();
GitObjects.IsLooseObjectsDirectory("A7").ShouldBeTrue();
GitObjects.IsLooseObjectsDirectory("55").ShouldBeTrue();
}
[TestCase]
public void IsLooseObjectsDirectory_InvalidDirectories()
{
GitObjects.IsLooseObjectsDirectory("K7").ShouldBeFalse();
GitObjects.IsLooseObjectsDirectory("A-").ShouldBeFalse();
GitObjects.IsLooseObjectsDirectory("?B").ShouldBeFalse();
GitObjects.IsLooseObjectsDirectory("BBB").ShouldBeFalse();
GitObjects.IsLooseObjectsDirectory("B-B").ShouldBeFalse();
}
}
}

Просмотреть файл

@ -1,386 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.Git;
using Scalar.Tests.Should;
using System.Collections.Generic;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class GitVersionTests
{
[TestCase]
public void GetFeatureFlags_VfsGitVersion_ReturnsGvfsProtocolSupported()
{
var version = new GitVersion(2, 28, 0, "vfs", 1, 0);
GitFeatureFlags features = version.GetFeatures();
features.HasFlag(GitFeatureFlags.GvfsProtocol).ShouldBeTrue();
}
[TestCase]
public void GetFeatureFlags_NormalGitVersion_ReturnsGvfsProtocolNotSupported()
{
var gitGitVersion = new GitVersion(2, 28, 0);
GitFeatureFlags gitGitFeatures = gitGitVersion.GetFeatures();
gitGitFeatures.HasFlag(GitFeatureFlags.GvfsProtocol).ShouldBeFalse();
var winGitVersion = new GitVersion(2, 28, 0, "windows", 1, 1);
GitFeatureFlags winGitFeatures = winGitVersion.GetFeatures();
winGitFeatures.HasFlag(GitFeatureFlags.GvfsProtocol).ShouldBeFalse();
}
[TestCase]
public void GetFeatureFlags_MaintenanceBuiltin()
{
var notSupportedVerisons = new List<GitVersion>
{
new GitVersion(2, 27, 1),
new GitVersion(2, 28, 0),
new GitVersion(2, 28, 1),
new GitVersion(2, 29, 0),
new GitVersion(2, 27, 1, "windows"),
new GitVersion(2, 28, 0, "windows"),
new GitVersion(2, 28, 1, "windows"),
new GitVersion(2, 29, 0, "windows"),
new GitVersion(2, 30, 0),
new GitVersion(2, 27, 0, "vfs", 1, 1),
new GitVersion(2, 28, 0, "vfs", 0, 0),
new GitVersion(2, 28, 0, "vfs", 0, 1),
};
foreach (GitVersion version in notSupportedVerisons)
{
GitFeatureFlags gitGitFeatures = version.GetFeatures();
gitGitFeatures.HasFlag(GitFeatureFlags.MaintenanceBuiltin).ShouldBeFalse($"Incorrect for version {version}");
}
var supportedVerisons = new List<GitVersion>
{
new GitVersion(2, 28, 0, "vfs", 1, 0),
new GitVersion(2, 29, 0, "vfs", 0, 0),
new GitVersion(2, 30, 0, "vfs", 0, 0),
new GitVersion(2, 31, 0),
new GitVersion(2, 31, 1),
};
foreach (GitVersion version in supportedVerisons)
{
GitFeatureFlags gitGitFeatures = version.GetFeatures();
gitGitFeatures.HasFlag(GitFeatureFlags.MaintenanceBuiltin).ShouldBeTrue($"Incorrect for version {version}");
}
}
[TestCase]
public void GetFeatureFlags_BuiltinFSMonitor()
{
GitVersion version = new GitVersion(2, 30, 0, "vfs", 0, 0);
GitFeatureFlags gitFeatures = version.GetFeatures();
gitFeatures.HasFlag(GitFeatureFlags.BuiltinFSMonitor).ShouldBeFalse($"Incorrect for version {version}");
version.Features.Add("bogus");
gitFeatures = version.GetFeatures();
gitFeatures.HasFlag(GitFeatureFlags.BuiltinFSMonitor).ShouldBeFalse($"Incorrect for version {version}");
version.Features.Add("fsmonitor--daemon");
gitFeatures = version.GetFeatures();
gitFeatures.HasFlag(GitFeatureFlags.BuiltinFSMonitor).ShouldBeTrue($"Incorrect for version {version}");
}
[TestCase]
public void TryParseInstallerName()
{
this.ParseAndValidateInstallerVersion("Git-1.2.3.scalar.4.5.gb16030b-64-bit" + ScalarPlatform.Instance.Constants.InstallerExtension);
this.ParseAndValidateInstallerVersion("git-1.2.3.scalar.4.5.gb16030b-64-bit" + ScalarPlatform.Instance.Constants.InstallerExtension);
this.ParseAndValidateInstallerVersion("Git-1.2.3.scalar.4.5.gb16030b-64-bit" + ScalarPlatform.Instance.Constants.InstallerExtension);
}
[TestCase]
public void Version_Data_Null_Returns_False()
{
GitVersion version;
bool success = GitVersion.TryParseVersion(null, out version);
success.ShouldEqual(false);
}
[TestCase]
public void Version_Data_Empty_Returns_False()
{
GitVersion version;
bool success = GitVersion.TryParseVersion(string.Empty, out version);
success.ShouldEqual(false);
}
[TestCase]
public void Version_Data_Not_Enough_Numbers_Returns_False()
{
GitVersion version;
bool success = GitVersion.TryParseVersion("2.0", out version);
success.ShouldEqual(false);
}
[TestCase]
public void Version_Data_Too_Many_Numbers_Returns_True()
{
GitVersion version;
bool success = GitVersion.TryParseVersion("2.0.1.test.1.4.3.6", out version);
success.ShouldEqual(true);
}
[TestCase]
public void Version_Data_Valid_Returns_True()
{
GitVersion version;
bool success = GitVersion.TryParseVersion("2.0.1", out version);
success.ShouldEqual(true);
}
[TestCase]
public void Version_Data_Valid_With_RC_Returns_True()
{
GitVersion version;
bool success = GitVersion.TryParseVersion("2.0.1-rc3", out version);
success.ShouldEqual(true);
}
[TestCase]
public void Version_Data_Valid_With_Platform_Returns_True()
{
GitVersion version;
bool success = GitVersion.TryParseVersion("2.0.1.test.1.2", out version);
success.ShouldEqual(true);
}
[TestCase]
public void Version_Data_Valid_With_RC_And_Platform_Returns_True()
{
GitVersion version;
bool success = GitVersion.TryParseVersion("2.0.1-rc3.test.1.2", out version);
success.ShouldEqual(true);
}
[TestCase]
public void Compare_Different_Platforms_Returns_False()
{
GitVersion version1 = new GitVersion(1, 2, 3, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test1", 4, 1);
version1.IsLessThan(version2).ShouldEqual(false);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_Equal()
{
GitVersion version1 = new GitVersion(1, 2, 3, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(false);
version1.IsEqualTo(version2).ShouldEqual(true);
}
[TestCase]
public void Compare_Version_Major_Less()
{
GitVersion version1 = new GitVersion(0, 2, 3, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(true);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_Major_Greater()
{
GitVersion version1 = new GitVersion(2, 2, 3, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(false);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_Minor_Less()
{
GitVersion version1 = new GitVersion(1, 1, 3, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(true);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_Minor_Greater()
{
GitVersion version1 = new GitVersion(1, 3, 3, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(false);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_Build_Less()
{
GitVersion version1 = new GitVersion(1, 2, 2, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(true);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_Build_Greater()
{
GitVersion version1 = new GitVersion(1, 2, 4, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(false);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_Revision_Less()
{
GitVersion version1 = new GitVersion(1, 2, 3, "test", 3, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(true);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_Revision_Greater()
{
GitVersion version1 = new GitVersion(1, 2, 3, "test", 5, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(false);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_MinorRevision_Less()
{
GitVersion version1 = new GitVersion(1, 2, 3, "test", 4, 1);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 2);
version1.IsLessThan(version2).ShouldEqual(true);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Compare_Version_MinorRevision_Greater()
{
GitVersion version1 = new GitVersion(1, 2, 3, "test", 4, 2);
GitVersion version2 = new GitVersion(1, 2, 3, "test", 4, 1);
version1.IsLessThan(version2).ShouldEqual(false);
version1.IsEqualTo(version2).ShouldEqual(false);
}
[TestCase]
public void Allow_Blank_Minor_Revision()
{
GitVersion version;
GitVersion.TryParseVersion("1.2.3.test.4", out version).ShouldEqual(true);
version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.ReleaseCandidate.ShouldEqual(null);
version.Platform.ShouldEqual("test");
version.Revision.ShouldEqual(4);
version.MinorRevision.ShouldEqual(0);
}
[TestCase]
public void Allow_Invalid_Minor_Revision()
{
GitVersion version;
GitVersion.TryParseVersion("1.2.3.test.4.notint", out version).ShouldEqual(true);
version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.ReleaseCandidate.ShouldEqual(null);
version.Platform.ShouldEqual("test");
version.Revision.ShouldEqual(4);
version.MinorRevision.ShouldEqual(0);
}
[TestCase]
public void Allow_ReleaseCandidate()
{
GitVersion version;
GitVersion.TryParseVersion("1.2.3-rc4", out version).ShouldEqual(true);
version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.ReleaseCandidate.ShouldEqual(4);
version.Platform.ShouldBeNull();
version.Revision.ShouldEqual(0);
version.MinorRevision.ShouldEqual(0);
}
[TestCase]
public void Allow_ReleaseCandidate_Platform()
{
GitVersion version;
GitVersion.TryParseVersion("1.2.3-rc4.test", out version).ShouldEqual(true);
version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.ReleaseCandidate.ShouldEqual(4);
version.Platform.ShouldEqual("test");
version.Revision.ShouldEqual(0);
version.MinorRevision.ShouldEqual(0);
}
[TestCase]
public void Allow_LocalGitBuildVersion_ParseMajorMinorBuildOnly()
{
GitVersion version;
GitVersion.TryParseVersion("1.2.3.456.abcdefg.hijk", out version).ShouldEqual(true);
version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.ReleaseCandidate.ShouldEqual(null);
version.Platform.ShouldEqual("456");
version.Revision.ShouldEqual(0);
version.MinorRevision.ShouldEqual(0);
}
[TestCase]
public void Allow_GarbageBuildVersion_ParseMajorMinorBuildOnly()
{
GitVersion version;
GitVersion.TryParseVersion("1.2.3.test.4.5.6.7.g1234abcd.8.9.😀.10.11.dirty.MSVC", out version).ShouldEqual(true);
version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.ReleaseCandidate.ShouldEqual(null);
version.Platform.ShouldEqual("test");
version.Revision.ShouldEqual(4);
version.MinorRevision.ShouldEqual(5);
}
private void ParseAndValidateInstallerVersion(string installerName)
{
GitVersion version;
bool success = GitVersion.TryParseInstallerName(installerName, ScalarPlatform.Instance.Constants.InstallerExtension, out version);
success.ShouldBeTrue();
version.Major.ShouldEqual(1);
version.Minor.ShouldEqual(2);
version.Build.ShouldEqual(3);
version.ReleaseCandidate.ShouldEqual(null);
version.Platform.ShouldEqual("scalar");
version.Revision.ShouldEqual(4);
version.MinorRevision.ShouldEqual(5);
}
}
}

Просмотреть файл

@ -1,140 +0,0 @@
using Newtonsoft.Json;
using NUnit.Framework;
using Scalar.Common.NuGetUpgrade;
using Scalar.Tests.Should;
using System.Collections.Generic;
using System.IO;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class JsonInstallManifestTests
{
private static int manifestEntryCount = 0;
[TestCase]
public void CanReadExpectedJsonString()
{
string installManifestJsonString =
@"
{
""Version"" : ""1"",
""PlatformInstallManifests"" : {
""Windows"": {
""InstallActions"": [
{
""Name"" : ""Git"",
""Version"" : ""2.19.0.1.34"",
""InstallerRelativePath"" : ""Installers\\Windows\\G4W\\Git-2.19.0.scalar.1.34.gc7fb556-64-bit.exe"",
""Args"" : ""/VERYSILENT /CLOSEAPPLICATIONS""
},
{
""Name"" : ""PostGitInstall script"",
""InstallerRelativePath"" : ""Installers\\Windows\\GSD\\postinstall.ps1""
},
]
}
}
}
";
InstallManifest installManifest = InstallManifest.FromJsonString(installManifestJsonString);
installManifest.ShouldNotBeNull();
InstallManifestPlatform platformInstallManifest = installManifest.PlatformInstallManifests[InstallManifest.WindowsPlatformKey];
platformInstallManifest.ShouldNotBeNull();
platformInstallManifest.InstallActions.Count.ShouldEqual(2);
this.VerifyInstallActionInfo(
platformInstallManifest.InstallActions[0],
"Git",
"2.19.0.1.34",
"/VERYSILENT /CLOSEAPPLICATIONS",
"Installers\\Windows\\G4W\\Git-2.19.0.scalar.1.34.gc7fb556-64-bit.exe");
this.VerifyInstallActionInfo(
platformInstallManifest.InstallActions[1],
"PostGitInstall script",
null,
null,
"Installers\\Windows\\GSD\\postinstall.ps1");
}
[TestCase]
public void CanDeserializeAndSerializeInstallManifest()
{
List<InstallActionInfo> entries = new List<InstallActionInfo>()
{
this.CreateInstallActionInfo(),
this.CreateInstallActionInfo()
};
InstallManifest installManifest = new InstallManifest();
installManifest.AddPlatformInstallManifest(InstallManifest.WindowsPlatformKey, entries);
JsonSerializer serializer = new JsonSerializer();
using (MemoryStream ms = new MemoryStream())
using (StreamWriter streamWriter = new StreamWriter(ms))
using (JsonWriter jsWriter = new JsonTextWriter(streamWriter))
{
string output = JsonConvert.SerializeObject(installManifest);
serializer.Serialize(jsWriter, installManifest);
jsWriter.Flush();
ms.Seek(0, SeekOrigin.Begin);
StreamReader streamReader = new StreamReader(ms);
InstallManifest deserializedInstallManifest = InstallManifest.FromJson(streamReader);
this.VerifyInstallManifestsAreEqual(installManifest, deserializedInstallManifest);
}
}
private InstallActionInfo CreateInstallActionInfo()
{
int entrySuffix = manifestEntryCount++;
return new InstallActionInfo(
name: $"Installer{entrySuffix}",
version: $"1.{entrySuffix}.1.2",
args: $"/nodowngrade{entrySuffix}",
installerRelativePath: $"installers/installer1{entrySuffix}",
command: string.Empty);
}
private void VerifyInstallManifestsAreEqual(InstallManifest expected, InstallManifest actual)
{
actual.PlatformInstallManifests.Count.ShouldEqual(expected.PlatformInstallManifests.Count, $"The number of platforms ({actual.PlatformInstallManifests.Count}) do not match the expected number of platforms ({expected.PlatformInstallManifests.Count}).");
foreach (KeyValuePair<string, InstallManifestPlatform> kvp in expected.PlatformInstallManifests)
{
this.VerifyPlatformManifestsAreEqual(kvp.Value, actual.PlatformInstallManifests[kvp.Key]);
}
}
private void VerifyInstallActionInfo(
InstallActionInfo actualEntry,
string expectedName,
string expectedVersion,
string expectedArgs,
string expectedInstallerRelativePath)
{
actualEntry.Name.ShouldEqual(expectedName, "InstallActionInfo name does not match expected value");
actualEntry.Version.ShouldEqual(expectedVersion, "InstallActionInfo version does not match expected value");
actualEntry.Args.ShouldEqual(expectedArgs, "InstallActionInfo Args does not match expected value");
actualEntry.InstallerRelativePath.ShouldEqual(expectedInstallerRelativePath, "InstallActionInfo InstallerRelativePath does not match expected value");
}
private void VerifyPlatformManifestsAreEqual(InstallManifestPlatform expected, InstallManifestPlatform actual)
{
actual.InstallActions.Count.ShouldEqual(expected.InstallActions.Count, $"The number of platforms ({actual.InstallActions.Count}) do not match the expected number of platforms ({expected.InstallActions.Count}).");
for (int i = 0; i < actual.InstallActions.Count; i++)
{
actual.InstallActions[i].Version.ShouldEqual(expected.InstallActions[i].Version);
actual.InstallActions[i].Args.ShouldEqual(expected.InstallActions[i].Args);
actual.InstallActions[i].Name.ShouldEqual(expected.InstallActions[i].Name);
actual.InstallActions[i].InstallerRelativePath.ShouldEqual(expected.InstallActions[i].InstallerRelativePath);
}
}
}
}

Просмотреть файл

@ -1,133 +0,0 @@
using NUnit.Framework;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common.Tracing;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class JsonTracerTests
{
[TestCase]
public void EventsAreFilteredByVerbosity()
{
using (JsonTracer tracer = new JsonTracer("Microsoft-Scalar-Test", "EventsAreFilteredByVerbosity1", disableTelemetry: true))
using (MockListener listener = new MockListener(EventLevel.Informational, Keywords.Any))
{
tracer.AddEventListener(listener);
tracer.RelatedEvent(EventLevel.Informational, "ShouldReceive", metadata: null);
listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldReceive"));
tracer.RelatedEvent(EventLevel.Verbose, "ShouldNotReceive", metadata: null);
listener.EventNamesRead.ShouldNotContain(name => name.Equals("ShouldNotReceive"));
}
using (JsonTracer tracer = new JsonTracer("Microsoft-Scalar-Test", "EventsAreFilteredByVerbosity2", disableTelemetry: true))
using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.Any))
{
tracer.AddEventListener(listener);
tracer.RelatedEvent(EventLevel.Informational, "ShouldReceive", metadata: null);
listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldReceive"));
tracer.RelatedEvent(EventLevel.Verbose, "ShouldAlsoReceive", metadata: null);
listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldAlsoReceive"));
}
}
[TestCase]
public void EventsAreFilteredByKeyword()
{
// Network filters all but network out
using (JsonTracer tracer = new JsonTracer("Microsoft-Scalar-Test", "EventsAreFilteredByKeyword1", disableTelemetry: true))
using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.Network))
{
tracer.AddEventListener(listener);
tracer.RelatedEvent(EventLevel.Informational, "ShouldReceive", metadata: null, keyword: Keywords.Network);
listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldReceive"));
tracer.RelatedEvent(EventLevel.Verbose, "ShouldNotReceive", metadata: null);
listener.EventNamesRead.ShouldNotContain(name => name.Equals("ShouldNotReceive"));
}
// Any filters nothing out
using (JsonTracer tracer = new JsonTracer("Microsoft-Scalar-Test", "EventsAreFilteredByKeyword2", disableTelemetry: true))
using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.Any))
{
tracer.AddEventListener(listener);
tracer.RelatedEvent(EventLevel.Informational, "ShouldReceive", metadata: null, keyword: Keywords.Network);
listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldReceive"));
tracer.RelatedEvent(EventLevel.Verbose, "ShouldAlsoReceive", metadata: null);
listener.EventNamesRead.ShouldContain(name => name.Equals("ShouldAlsoReceive"));
}
// None filters everything out (including events marked as none)
using (JsonTracer tracer = new JsonTracer("Microsoft-Scalar-Test", "EventsAreFilteredByKeyword3", disableTelemetry: true))
using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.None))
{
tracer.AddEventListener(listener);
tracer.RelatedEvent(EventLevel.Informational, "ShouldNotReceive", metadata: null, keyword: Keywords.Network);
listener.EventNamesRead.ShouldBeEmpty();
tracer.RelatedEvent(EventLevel.Verbose, "ShouldAlsoNotReceive", metadata: null);
listener.EventNamesRead.ShouldBeEmpty();
}
}
[TestCase]
public void EventMetadataWithKeywordsIsOptional()
{
using (JsonTracer tracer = new JsonTracer("Microsoft-Scalar-Test", "EventMetadataWithKeywordsIsOptional", disableTelemetry: true))
using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.Any))
{
tracer.AddEventListener(listener);
tracer.RelatedWarning(metadata: null, message: string.Empty, keywords: Keywords.Telemetry);
listener.EventNamesRead.ShouldContain(x => x.Equals("Warning"));
tracer.RelatedError(metadata: null, message: string.Empty, keywords: Keywords.Telemetry);
listener.EventNamesRead.ShouldContain(x => x.Equals("Error"));
}
}
[TestCase]
public void StartEventDoesNotDispatchTelemetry()
{
using (JsonTracer tracer = new JsonTracer("Microsoft-Scalar-Test", "StartEventDoesNotDispatchTelemetry", disableTelemetry: true))
using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.Telemetry))
{
tracer.AddEventListener(listener);
using (ITracer activity = tracer.StartActivity("TestActivity", EventLevel.Informational, Keywords.Telemetry, null))
{
listener.EventNamesRead.ShouldBeEmpty();
activity.Stop(null);
listener.EventNamesRead.ShouldContain(x => x.Equals("TestActivity"));
}
}
}
[TestCase]
public void StopEventIsDispatchedOnDispose()
{
using (JsonTracer tracer = new JsonTracer("Microsoft-Scalar-Test", "StopEventIsDispatchedOnDispose", disableTelemetry: true))
using (MockListener listener = new MockListener(EventLevel.Verbose, Keywords.Telemetry))
{
tracer.AddEventListener(listener);
using (ITracer activity = tracer.StartActivity("TestActivity", EventLevel.Informational, Keywords.Telemetry, null))
{
listener.EventNamesRead.ShouldBeEmpty();
}
listener.EventNamesRead.ShouldContain(x => x.Equals("TestActivity"));
}
}
}
}

Просмотреть файл

@ -1,148 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class LocalCacheResolverTests
{
private const string UrlKeyPrefix = "url_";
private const string RepoIdKeyPrefix = "id_";
[TestCase]
public void CanGetLocalCacheKeyFromRepoInfo()
{
List<string> repoIds = new List<string>
{
"df3216c6-6d33-476e-8d89-e877a6d74c79",
"testId",
"826847f5da3ef78114b2a9d5253ada9d95265c76"
};
MockTracer tracer = new MockTracer();
MockScalarEnlistment enlistment = CreateEnlistment("mock://repoUrl");
LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment);
foreach (string repoId in repoIds)
{
VstsInfoData vstsInfo = new VstsInfoData();
vstsInfo.Repository = new VstsInfoData.RepositoryDetails();
vstsInfo.Repository.Id = repoId;
localCacheResolver.TryGetLocalCacheKeyFromRepoInfoOrURL(
tracer,
vstsInfo,
out string localCacheKey,
out string errorMessage).ShouldBeTrue();
errorMessage.ShouldBeEmpty();
localCacheKey.ShouldEqual($"{RepoIdKeyPrefix}{repoId}");
}
}
[TestCase]
public void FallBackToUsingURLWhenRepoInfoEmpty()
{
MockScalarEnlistment enlistment = CreateEnlistment("mock://repoUrl");
LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment);
VstsInfoData vstsInfo = new VstsInfoData();
LocalKeyShouldBeResolvedFromURL(localCacheResolver, vstsInfo);
vstsInfo.Repository = new VstsInfoData.RepositoryDetails();
LocalKeyShouldBeResolvedFromURL(localCacheResolver, vstsInfo);
vstsInfo.Repository.Id = string.Empty;
LocalKeyShouldBeResolvedFromURL(localCacheResolver, vstsInfo);
vstsInfo.Repository.Id = " ";
LocalKeyShouldBeResolvedFromURL(localCacheResolver, vstsInfo);
}
[TestCase]
public void CanGetLocalCacheKeyFromURL()
{
MockScalarEnlistment enlistment = CreateEnlistment("mock://repoUrl");
LocalCacheResolver localCacheResolver = new LocalCacheResolver(enlistment);
LocalKeyShouldBeResolvedFromURL(localCacheResolver, vstsInfo: null);
}
[TestCase]
public void LocalCacheKeyFromURLIsCaseInsensitiveAndStable()
{
MockTracer tracer = new MockTracer();
List<MockScalarEnlistment> enlistments = new List<MockScalarEnlistment>
{
CreateEnlistment("mock://repourl"),
CreateEnlistment("mock://repoUrl"),
CreateEnlistment("MOCK://repoUrl"),
CreateEnlistment("mock://RepoUrl")
};
IEnumerable<LocalCacheResolver> localCacheResolvers = enlistments.Select(x => new LocalCacheResolver(x));
foreach (LocalCacheResolver resolver in localCacheResolvers)
{
resolver.TryGetLocalCacheKeyFromRepoInfoOrURL(
tracer,
vstsInfo: null,
localCacheKey: out string localCacheKey,
errorMessage: out string ErrorMessage).ShouldBeTrue();
// Use an explicit result to ensure the hash function is stable
localCacheKey.ShouldEqual("url_0d95e2600bac6918e2073de5278eed6a6a06f79f");
}
}
[TestCase]
public void LocalCacheKeysFromDifferentURLsAreDifferent()
{
List<MockScalarEnlistment> enlistments = new List<MockScalarEnlistment>
{
CreateEnlistment("mock://repourl"),
CreateEnlistment("mock://repourl2"),
CreateEnlistment("MOCK://repoUrl3"),
CreateEnlistment("mock://RepoUrl4")
};
IEnumerable<LocalCacheResolver> localCacheResolvers = enlistments.Select(x => new LocalCacheResolver(x));
HashSet<string> localCacheKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (LocalCacheResolver resolver in localCacheResolvers)
{
LocalKeyShouldBeResolvedFromURL(resolver, vstsInfo: null, localCacheKey: out string localCacheKey);
localCacheKeys.Add(localCacheKey).ShouldBeTrue("Different URLs should have unique cache keys");
}
}
private static MockScalarEnlistment CreateEnlistment(string repoUrl)
{
return new MockScalarEnlistment(
Path.Combine("mock:", "path"),
repoUrl,
Path.Combine("mock:", "git"),
gitProcess: null);
}
private static void LocalKeyShouldBeResolvedFromURL(LocalCacheResolver localCacheResolver, VstsInfoData vstsInfo)
{
LocalKeyShouldBeResolvedFromURL(localCacheResolver, vstsInfo, out _);
}
private static void LocalKeyShouldBeResolvedFromURL(LocalCacheResolver localCacheResolver, VstsInfoData vstsInfo, out string localCacheKey)
{
localCacheResolver.TryGetLocalCacheKeyFromRepoInfoOrURL(
new MockTracer(),
vstsInfo,
out localCacheKey,
out string errorMessage).ShouldBeTrue();
errorMessage.ShouldBeEmpty();
localCacheKey.Substring(0, UrlKeyPrefix.Length).ShouldEqual(UrlKeyPrefix);
SHA1Util.IsValidShaFormat(localCacheKey.Substring(UrlKeyPrefix.Length)).ShouldBeTrue();
}
}
}

Просмотреть файл

@ -1,39 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Platform.Mac;
using Scalar.Tests.Should;
using System.Collections.Generic;
using System.Text;
namespace Scalar.UnitTests.Platform.Mac
{
[TestFixture]
public class MacServiceProcessTests
{
[TestCase]
public void CanGetServices()
{
Mock<IProcessRunner> processHelperMock = new Mock<IProcessRunner>(MockBehavior.Strict);
StringBuilder sb = new StringBuilder();
sb.AppendLine("PID\tStatus\tLabel");
sb.AppendLine("1\t0\tcom.apple.process1");
sb.AppendLine("2\t0\tcom.apple.process2");
sb.AppendLine("3\t0\tcom.apple.process3");
sb.AppendLine("-\t0\tcom.apple.process4");
ProcessResult processResult = new ProcessResult(sb.ToString(), string.Empty, 0);
processHelperMock.Setup(m => m.Run("/bin/launchctl", "asuser 521 /bin/launchctl list", true)).Returns(processResult);
MacDaemonController daemonController = new MacDaemonController(processHelperMock.Object);
bool success = daemonController.TryGetDaemons("521", out List<MacDaemonController.DaemonInfo> daemons, out string error);
success.ShouldBeTrue();
daemons.ShouldNotBeNull();
daemons.Count.ShouldEqual(4);
processHelperMock.VerifyAll();
}
}
}

Просмотреть файл

@ -1,111 +0,0 @@
using NUnit.Framework;
using Scalar.Common.NamedPipes;
using Scalar.Tests.Should;
using Scalar.UnitTests.Category;
using System.IO;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class NamedPipeStreamReaderWriterTests
{
private MemoryStream stream;
private NamedPipeStreamWriter streamWriter;
private NamedPipeStreamReader streamReader;
[SetUp]
public void Setup()
{
this.stream = new MemoryStream();
this.streamWriter = new NamedPipeStreamWriter(this.stream);
this.streamReader = new NamedPipeStreamReader(this.stream);
}
[Test]
public void CanWriteAndReadMessages()
{
string firstMessage = @"This is a new message";
this.TestTransmitMessage(firstMessage);
string secondMessage = @"This is another message";
this.TestTransmitMessage(secondMessage);
string thirdMessage = @"This is the third message in a series of messages";
this.TestTransmitMessage(thirdMessage);
string longMessage = new string('T', 1024 * 5);
this.TestTransmitMessage(longMessage);
}
[Test]
[Category(CategoryConstants.ExceptionExpected)]
public void ReadingPartialMessgeThrows()
{
byte[] bytes = System.Text.Encoding.ASCII.GetBytes("This is a partial message");
this.stream.Write(bytes, 0, bytes.Length);
this.stream.Seek(0, SeekOrigin.Begin);
Assert.Throws<IOException>(() => this.streamReader.ReadMessage());
}
[Test]
public void CanSendMessagesWithNewLines()
{
string messageWithNewLines = "This is a \nstringwith\nnewlines";
this.TestTransmitMessage(messageWithNewLines);
}
[Test]
public void CanSendMultipleMessagesSequentially()
{
string[] messages = new string[]
{
"This is a new message",
"This is another message",
"This is the third message in a series of messages"
};
this.TestTransmitMessages(messages);
}
private void TestTransmitMessage(string message)
{
long pos = this.ReadStreamPosition();
this.streamWriter.WriteMessage(message);
this.SetStreamPosition(pos);
string readMessage = this.streamReader.ReadMessage();
readMessage.ShouldEqual(message, "The message read from the stream reader is not the same as the message that was sent.");
}
private void TestTransmitMessages(string[] messages)
{
long pos = this.ReadStreamPosition();
foreach (string message in messages)
{
this.streamWriter.WriteMessage(message);
}
this.SetStreamPosition(pos);
foreach (string message in messages)
{
string readMessage = this.streamReader.ReadMessage();
readMessage.ShouldEqual(message, "The message read from the stream reader is not the same as the message that was sent.");
}
}
private long ReadStreamPosition()
{
return this.stream.Position;
}
private void SetStreamPosition(long position)
{
this.stream.Seek(position, SeekOrigin.Begin);
}
}
}

Просмотреть файл

@ -1,456 +0,0 @@
using Moq;
using NuGet.Packaging.Core;
using NuGet.Protocol.Core.Types;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.Git;
using Scalar.Common.NuGetUpgrade;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using Scalar.UnitTests.Category;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Scalar.UnitTests.Common.NuGetUpgrade
{
[TestFixture]
public class NuGetUpgraderTests
{
protected const string OlderVersion = "1.0.1185.0";
protected const string CurrentVersion = "1.5.1185.0";
protected const string NewerVersion = "1.6.1185.0";
protected const string NewerVersion2 = "1.7.1185.0";
protected const string NuGetFeedUrl = "https://pkgs.dev.azure.com/contoso/packages";
protected const string NuGetFeedName = "feedNameValue";
protected static Exception httpRequestAuthException = new System.Net.Http.HttpRequestException("Response status code does not indicate success: 401 (Unauthorized).");
protected static Exception fatalProtocolAuthException = new FatalProtocolException("Unable to load the service index for source.", httpRequestAuthException);
protected static Exception[] networkAuthFailures =
{
httpRequestAuthException,
fatalProtocolAuthException
};
protected NuGetUpgrader upgrader;
protected MockTracer tracer;
protected NuGetUpgrader.NuGetUpgraderConfig upgraderConfig;
protected Mock<NuGetFeed> mockNuGetFeed;
protected MockFileSystem mockFileSystem;
protected Mock<ICredentialStore> mockCredentialManager;
protected ProductUpgraderPlatformStrategy productUpgraderPlatformStrategy;
protected string downloadDirectoryPath = Path.Combine(
$"mock:{Path.DirectorySeparatorChar}",
ProductUpgraderInfo.UpgradeDirectoryName,
ProductUpgraderInfo.DownloadDirectory);
protected delegate void DownloadPackageAsyncCallback(PackageIdentity packageIdentity);
public virtual ProductUpgraderPlatformStrategy CreateProductUpgraderPlatformStrategy()
{
return new MockProductUpgraderPlatformStrategy(this.mockFileSystem, this.tracer);
}
[SetUp]
public void SetUp()
{
this.upgraderConfig = new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, NuGetFeedUrl, NuGetFeedName);
this.tracer = new MockTracer();
this.mockFileSystem = new MockFileSystem(
new MockDirectory(
Path.GetDirectoryName(this.downloadDirectoryPath),
new[] { new MockDirectory(this.downloadDirectoryPath, null, null) },
null));
this.mockNuGetFeed = new Mock<NuGetFeed>(
NuGetFeedUrl,
NuGetFeedName,
this.downloadDirectoryPath,
null,
ScalarPlatform.Instance.UnderConstruction.SupportsNuGetEncryption,
this.tracer,
this.mockFileSystem);
this.mockNuGetFeed.Setup(feed => feed.SetCredentials(It.IsAny<string>()));
this.mockCredentialManager = new Mock<ICredentialStore>();
string credentialManagerString = "value";
string emptyString = string.Empty;
this.mockCredentialManager.Setup(foo => foo.TryGetCredential(It.IsAny<ITracer>(), It.IsAny<string>(), out credentialManagerString, out credentialManagerString, out credentialManagerString)).Returns(true);
this.productUpgraderPlatformStrategy = this.CreateProductUpgraderPlatformStrategy();
this.upgrader = new NuGetUpgrader(
CurrentVersion,
this.tracer,
false,
false,
this.mockFileSystem,
this.upgraderConfig,
this.mockNuGetFeed.Object,
this.mockCredentialManager.Object,
this.productUpgraderPlatformStrategy);
}
[TearDown]
public void TearDown()
{
this.mockNuGetFeed.Object.Dispose();
this.tracer.Dispose();
}
[TestCase]
public void TryQueryNewestVersion_NewVersionAvailable()
{
Version newVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion)),
};
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny<string>())).ReturnsAsync(availablePackages);
bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message);
// Assert that we found the newer version
success.ShouldBeTrue();
newVersion.ShouldNotBeNull();
newVersion.ShouldEqual<Version>(new Version(NewerVersion));
message.ShouldNotBeNull();
}
[TestCase]
public void TryQueryNewestVersion_MultipleNewVersionsAvailable()
{
Version newVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion2)),
};
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny<string>())).ReturnsAsync(availablePackages);
bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message);
// Assert that we found the newest version
success.ShouldBeTrue();
newVersion.ShouldNotBeNull();
newVersion.ShouldEqual<Version>(new Version(NewerVersion2));
message.ShouldNotBeNull();
}
[TestCase]
public void TryQueryNewestVersion_NoNewerVersionsAvailable()
{
Version newVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(OlderVersion)),
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
};
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny<string>())).ReturnsAsync(availablePackages);
bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message);
// Assert that no new version was returned
success.ShouldBeTrue();
newVersion.ShouldBeNull();
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryQueryNewestVersion_Exception()
{
Version newVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(OlderVersion)),
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
};
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny<string>())).Throws(new Exception("Network Error"));
bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message);
// Assert that no new version was returned
success.ShouldBeFalse();
newVersion.ShouldBeNull();
message.ShouldNotBeNull();
message.Any().ShouldBeTrue();
}
[TestCase]
public void CanDownloadNewestVersion()
{
Version actualNewestVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion)),
};
string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip");
IPackageSearchMetadata newestAvailableVersion = availablePackages.Last();
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages);
this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is<PackageIdentity>(packageIdentity => packageIdentity == newestAvailableVersion.Identity))).ReturnsAsync(testDownloadPath);
this.mockNuGetFeed.Setup(foo => foo.VerifyPackage(It.IsAny<string>())).Returns(true);
bool success = this.upgrader.TryQueryNewestVersion(out actualNewestVersion, out message);
// Assert that no new version was returned
success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}");
actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version.");
bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message);
downloadSuccessful.ShouldBeTrue();
this.upgrader.DownloadedPackagePath.ShouldEqual(testDownloadPath);
this.mockNuGetFeed.Verify(nuGetFeed => nuGetFeed.VerifyPackage(It.IsAny<string>()), Times.Once());
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void DownloadNewestVersion_HandleException()
{
Version newVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion)),
};
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(It.IsAny<string>())).ReturnsAsync(availablePackages);
this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.IsAny<PackageIdentity>())).Throws(new Exception("Network Error"));
this.mockNuGetFeed.Setup(foo => foo.VerifyPackage(It.IsAny<string>())).Returns(true);
bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message);
success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}");
newVersion.ShouldNotBeNull();
bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message);
downloadSuccessful.ShouldBeFalse();
}
[TestCase]
public void AttemptingToDownloadBeforeQueryingFails()
{
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion)),
};
IPackageSearchMetadata newestAvailableVersion = availablePackages.Last();
string downloadPath = "c:\\test_download_path";
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages);
this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is<PackageIdentity>(packageIdentity => packageIdentity == newestAvailableVersion.Identity))).ReturnsAsync(downloadPath);
bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message);
downloadSuccessful.ShouldBeFalse();
}
[TestCase]
public void TestUpgradeAllowed()
{
// Properly Configured NuGet config
NuGetUpgrader.NuGetUpgraderConfig nuGetUpgraderConfig =
new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, NuGetFeedUrl, NuGetFeedName);
NuGetUpgrader nuGetUpgrader = new NuGetUpgrader(
CurrentVersion,
this.tracer,
false,
false,
this.mockFileSystem,
nuGetUpgraderConfig,
this.mockNuGetFeed.Object,
this.mockCredentialManager.Object,
this.productUpgraderPlatformStrategy);
nuGetUpgrader.UpgradeAllowed(out _).ShouldBeTrue("NuGetUpgrader config is complete: upgrade should be allowed.");
// Empty FeedURL
nuGetUpgraderConfig =
new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, string.Empty, NuGetFeedName);
nuGetUpgrader = new NuGetUpgrader(
CurrentVersion,
this.tracer,
false,
false,
this.mockFileSystem,
nuGetUpgraderConfig,
this.mockNuGetFeed.Object,
this.mockCredentialManager.Object,
this.productUpgraderPlatformStrategy);
nuGetUpgrader.UpgradeAllowed(out string _).ShouldBeFalse("Upgrade without FeedURL configured should not be allowed.");
// Empty packageFeedName
nuGetUpgraderConfig =
new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, NuGetFeedUrl, string.Empty);
// Empty packageFeedName
nuGetUpgrader = new NuGetUpgrader(
CurrentVersion,
this.tracer,
false,
false,
this.mockFileSystem,
nuGetUpgraderConfig,
this.mockNuGetFeed.Object,
this.mockCredentialManager.Object,
this.productUpgraderPlatformStrategy);
nuGetUpgrader.UpgradeAllowed(out string _).ShouldBeFalse("Upgrade without FeedName configured should not be allowed.");
}
[TestCaseSource("networkAuthFailures")]
public void QueryNewestVersionReacquiresCredentialsOnAuthFailure(Exception exception)
{
Version actualNewestVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion)),
};
string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip");
IPackageSearchMetadata newestAvailableVersion = availablePackages.Last();
this.mockNuGetFeed.SetupSequence(foo => foo.QueryFeedAsync(It.IsAny<string>()))
.Throws(exception)
.ReturnsAsync(availablePackages);
// Setup the credential manager
string emptyString = string.Empty;
this.mockCredentialManager.Setup(foo => foo.TryDeleteCredential(It.IsAny<ITracer>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), out emptyString)).Returns(true);
bool success = this.upgrader.TryQueryNewestVersion(out actualNewestVersion, out message);
// Verify expectations
success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}");
actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version.");
this.mockNuGetFeed.Verify(nuGetFeed => nuGetFeed.QueryFeedAsync(It.IsAny<string>()), Times.Exactly(2));
string outString = string.Empty;
this.mockCredentialManager.Verify(credentialManager => credentialManager.TryGetCredential(It.IsAny<ITracer>(), It.IsAny<string>(), out outString, out outString, out outString), Times.Exactly(2));
this.mockCredentialManager.Verify(credentialManager => credentialManager.TryDeleteCredential(It.IsAny<ITracer>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), out outString), Times.Exactly(1));
}
[TestCase]
public void WellKnownArgumentTokensReplaced()
{
string logDirectory = "mock:\\test_log_directory";
string noTokenSourceString = "/arg no_token log_directory installation_id";
NuGetUpgrader.ReplaceArgTokens(noTokenSourceString, "unique_id", logDirectory, "installerBase").ShouldEqual(noTokenSourceString, "String with no tokens should not be modifed");
string sourceStringWithTokens = "/arg /log {log_directory}_{installation_id}_{installer_base_path}";
string expectedProcessedString = "/arg /log " + logDirectory + "_unique_id_installerBase";
NuGetUpgrader.ReplaceArgTokens(sourceStringWithTokens, "unique_id", logDirectory, "installerBase").ShouldEqual(expectedProcessedString, "expected tokens have not been replaced");
}
[TestCase]
public void DownloadFailsOnNuGetPackageVerificationFailure()
{
Version actualNewestVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion)),
};
IPackageSearchMetadata newestAvailableVersion = availablePackages.Last();
string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip");
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages);
this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is<PackageIdentity>(packageIdentity => packageIdentity == newestAvailableVersion.Identity)))
.Callback(new DownloadPackageAsyncCallback(
(packageIdentity) => this.mockFileSystem.WriteAllText(testDownloadPath, "Package contents that will fail validation")))
.ReturnsAsync(testDownloadPath);
this.mockNuGetFeed.Setup(foo => foo.VerifyPackage(It.IsAny<string>())).Returns(false);
bool success = this.upgrader.TryQueryNewestVersion(out actualNewestVersion, out message);
success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}");
actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version.");
bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message);
this.mockNuGetFeed.Verify(nuGetFeed => nuGetFeed.VerifyPackage(this.upgrader.DownloadedPackagePath), Times.Once());
downloadSuccessful.ShouldBeFalse("Failure to verify NuGet package should cause download to fail.");
this.mockFileSystem.FileExists(testDownloadPath).ShouldBeFalse("VerifyPackage should delete invalid packages");
}
[TestCase]
public void DoNotVerifyNuGetPackageWhenNoVerifyIsSpecified()
{
NuGetUpgrader.NuGetUpgraderConfig nuGetUpgraderConfig =
new NuGetUpgrader.NuGetUpgraderConfig(this.tracer, null, NuGetFeedUrl, NuGetFeedName);
NuGetUpgrader nuGetUpgrader = new NuGetUpgrader(
CurrentVersion,
this.tracer,
false,
true,
this.mockFileSystem,
nuGetUpgraderConfig,
this.mockNuGetFeed.Object,
this.mockCredentialManager.Object,
this.productUpgraderPlatformStrategy);
Version actualNewestVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion)),
};
IPackageSearchMetadata newestAvailableVersion = availablePackages.Last();
string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip");
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages);
this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is<PackageIdentity>(packageIdentity => packageIdentity == newestAvailableVersion.Identity))).ReturnsAsync(testDownloadPath);
this.mockNuGetFeed.Setup(foo => foo.VerifyPackage(It.IsAny<string>())).Returns(false);
bool success = nuGetUpgrader.TryQueryNewestVersion(out actualNewestVersion, out message);
success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}");
actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version.");
bool downloadSuccessful = nuGetUpgrader.TryDownloadNewestVersion(out message);
this.mockNuGetFeed.Verify(nuGetFeed => nuGetFeed.VerifyPackage(It.IsAny<string>()), Times.Never());
downloadSuccessful.ShouldBeTrue("Should be able to download package with verification issues when noVerify is specified");
}
protected IPackageSearchMetadata GeneratePackageSeachMetadata(Version version)
{
Mock<IPackageSearchMetadata> mockPackageSearchMetaData = new Mock<IPackageSearchMetadata>();
NuGet.Versioning.NuGetVersion nuGetVersion = new NuGet.Versioning.NuGetVersion(version);
mockPackageSearchMetaData.Setup(foo => foo.Identity).Returns(new NuGet.Packaging.Core.PackageIdentity("generatedPackedId", nuGetVersion));
return mockPackageSearchMetaData.Object;
}
}
}

Просмотреть файл

@ -1,189 +0,0 @@
using Moq;
using Moq.Protected;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.Git;
using Scalar.Common.NuGetUpgrade;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Scalar.UnitTests.Common.NuGetUpgrade
{
[TestFixture]
public class OrgNuGetUpgraderTests
{
private const string CurrentVersion = "1.5.1185.0";
private const string NewerVersion = "1.6.1185.0";
private const string DefaultUpgradeFeedPackageName = "package";
private const string DefaultUpgradeFeedUrl = "https://pkgs.dev.azure.com/contoso/";
private const string DefaultOrgInfoServerUrl = "https://www.contoso.com";
private const string DefaultRing = "slow";
private OrgNuGetUpgrader upgrader;
private MockTracer tracer;
private OrgNuGetUpgrader.OrgNuGetUpgraderConfig upgraderConfig;
private Mock<NuGetFeed> mockNuGetFeed;
private MockFileSystem mockFileSystem;
private Mock<ICredentialStore> mockCredentialManager;
private Mock<HttpMessageHandler> httpMessageHandlerMock;
private string downloadDirectoryPath = Path.Combine(
$"mock:{Path.DirectorySeparatorChar}",
ProductUpgraderInfo.UpgradeDirectoryName,
ProductUpgraderInfo.DownloadDirectory);
private interface IHttpMessageHandlerProtectedMembers
{
Task<HttpResponseMessage> SendAsync(HttpRequestMessage message, CancellationToken token);
}
public static IEnumerable<Exception> NetworkFailureCases()
{
yield return new HttpRequestException("Response status code does not indicate success: 401: (Unauthorized)");
yield return new TaskCanceledException("Task canceled");
}
[SetUp]
public void SetUp()
{
MockLocalScalarConfig mockGvfsConfig = new MockLocalScalarConfigBuilder(
DefaultRing,
DefaultUpgradeFeedUrl,
DefaultUpgradeFeedPackageName,
DefaultOrgInfoServerUrl)
.WithUpgradeRing()
.WithUpgradeFeedPackageName()
.WithUpgradeFeedUrl()
.WithOrgInfoServerUrl()
.Build();
this.upgraderConfig = new OrgNuGetUpgrader.OrgNuGetUpgraderConfig(this.tracer, mockGvfsConfig);
this.upgraderConfig.TryLoad(out _);
this.tracer = new MockTracer();
this.mockNuGetFeed = new Mock<NuGetFeed>(
DefaultUpgradeFeedUrl,
DefaultUpgradeFeedPackageName,
this.downloadDirectoryPath,
null,
ScalarPlatform.Instance.UnderConstruction.SupportsNuGetEncryption,
this.tracer,
this.mockFileSystem);
this.mockFileSystem = new MockFileSystem(
new MockDirectory(
Path.GetDirectoryName(this.downloadDirectoryPath),
new[] { new MockDirectory(this.downloadDirectoryPath, null, null) },
null));
this.mockCredentialManager = new Mock<ICredentialStore>();
string credentialManagerString = "value";
string emptyString = string.Empty;
this.mockCredentialManager.Setup(foo => foo.TryGetCredential(It.IsAny<ITracer>(), It.IsAny<string>(), out credentialManagerString, out credentialManagerString, out credentialManagerString)).Returns(true);
this.httpMessageHandlerMock = new Mock<HttpMessageHandler>();
this.httpMessageHandlerMock.Protected().As<IHttpMessageHandlerProtectedMembers>()
.Setup(m => m.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(this.ConstructResponseContent(NewerVersion))
});
HttpClient httpClient = new HttpClient(this.httpMessageHandlerMock.Object);
this.upgrader = new OrgNuGetUpgrader(
CurrentVersion,
this.tracer,
this.mockFileSystem,
httpClient,
false,
false,
this.upgraderConfig,
"windows",
this.mockNuGetFeed.Object,
this.mockCredentialManager.Object);
}
[TestCase]
public void SupportsAnonymousQuery()
{
this.upgrader.SupportsAnonymousVersionQuery.ShouldBeTrue();
}
[TestCase]
public void TryQueryNewestVersion()
{
Version newVersion;
string message;
bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message);
success.ShouldBeTrue();
newVersion.ShouldNotBeNull();
newVersion.ShouldEqual<Version>(new Version(NewerVersion));
message.ShouldNotBeNull();
message.ShouldEqual($"New version {OrgNuGetUpgraderTests.NewerVersion} is available.");
}
[TestCaseSource("NetworkFailureCases")]
public void HandlesNetworkErrors(Exception ex)
{
Version newVersion;
string message;
this.httpMessageHandlerMock.Protected().As<IHttpMessageHandlerProtectedMembers>()
.Setup(m => m.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(ex);
bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message);
success.ShouldBeFalse();
newVersion.ShouldBeNull();
message.ShouldNotBeNull();
message.ShouldContain("Network error");
}
[TestCase]
public void HandlesEmptyVersion()
{
Version newVersion;
string message;
this.httpMessageHandlerMock.Protected().As<IHttpMessageHandlerProtectedMembers>()
.Setup(m => m.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(this.ConstructResponseContent(string.Empty))
});
bool success = this.upgrader.TryQueryNewestVersion(out newVersion, out message);
success.ShouldBeTrue();
newVersion.ShouldBeNull();
message.ShouldNotBeNull();
message.ShouldContain("No versions available");
}
private string ConstructResponseContent(string version)
{
return $"{{\"version\" : \"{version}\"}} ";
}
}
}

Просмотреть файл

@ -1,110 +0,0 @@
using Moq;
using Moq.Protected;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class OrgInfoServerTests
{
public static List<OrgInfo> TestOrgInfo = new List<OrgInfo>()
{
new OrgInfo() { OrgName = "org1", Platform = "windows", Ring = "fast", Version = "1.2.3.1" },
new OrgInfo() { OrgName = "org1", Platform = "windows", Ring = "slow", Version = "1.2.3.2" },
new OrgInfo() { OrgName = "org1", Platform = "macOS", Ring = "fast", Version = "1.2.3.3" },
new OrgInfo() { OrgName = "org1", Platform = "macOS", Ring = "slow", Version = "1.2.3.4" },
new OrgInfo() { OrgName = "org2", Platform = "windows", Ring = "fast", Version = "1.2.3.5" },
new OrgInfo() { OrgName = "org2", Platform = "windows", Ring = "slow", Version = "1.2.3.6" },
new OrgInfo() { OrgName = "org2", Platform = "macOS", Ring = "fast", Version = "1.2.3.7" },
new OrgInfo() { OrgName = "org2", Platform = "macOS", Ring = "slow", Version = "1.2.3.8" },
};
private string baseUrl = "https://www.contoso.com";
private interface IHttpMessageHandlerProtectedMembers
{
Task<HttpResponseMessage> SendAsync(HttpRequestMessage message, CancellationToken token);
}
[TestCaseSource("TestOrgInfo")]
public void QueryNewestVersionWithParams(OrgInfo orgInfo)
{
Mock<HttpMessageHandler> handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock.Protected().As<IHttpMessageHandlerProtectedMembers>()
.Setup(m => m.SendAsync(It.Is<HttpRequestMessage>(request => this.UriMatches(request.RequestUri, this.baseUrl, orgInfo.OrgName, $"{orgInfo.Platform}-scalar", orgInfo.Ring)), It.IsAny<CancellationToken>()))
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(this.ConstructResponseContent(orgInfo.Version))
});
HttpClient httpClient = new HttpClient(handlerMock.Object);
OrgInfoApiClient upgradeChecker = new OrgInfoApiClient(httpClient, this.baseUrl);
Version version = upgradeChecker.QueryNewestVersion(orgInfo.OrgName, orgInfo.Platform, orgInfo.Ring);
version.ShouldEqual(new Version(orgInfo.Version));
handlerMock.VerifyAll();
}
private bool UriMatches(Uri uri, string baseUrl, string expectedOrgName, string expectedPlatform, string expectedRing)
{
bool hostMatches = uri.Host.Equals(baseUrl);
Dictionary<string, string> queryParams = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (string param in uri.Query.Substring(1).Split('&'))
{
string[] fields = param.Split('=');
string key = fields[0];
string value = fields[1];
queryParams.Add(key, value);
}
if (queryParams.Count != 3)
{
return false;
}
if (!queryParams.TryGetValue("Organization", out string orgName) || !string.Equals(orgName, expectedOrgName, StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (!queryParams.TryGetValue("platform", out string platform) || !string.Equals(platform, expectedPlatform, StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (!queryParams.TryGetValue("ring", out string ring) || !string.Equals(ring, expectedRing, StringComparison.OrdinalIgnoreCase))
{
return false;
}
return true;
}
private string ConstructResponseContent(string version)
{
return $"{{\"version\" : \"{version}\"}} ";
}
public class OrgInfo
{
public string OrgName { get; set; }
public string Ring { get; set; }
public string Platform { get; set; }
public string Version { get; set; }
}
}
}

Просмотреть файл

@ -1,35 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
using System.Runtime.InteropServices;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class PathsTests
{
[TestCase]
public void CanConvertOSPathToGitFormat()
{
string systemPath;
string expectedGitPath;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
systemPath = @"C:\This\is\a\path";
expectedGitPath = @"C:/This/is/a/path";
}
else
{
systemPath = @"/This/is/a/path";
expectedGitPath = systemPath;
}
string actualTransformedPath = Paths.ConvertPathToGitFormat(systemPath);
actualTransformedPath.ShouldEqual(expectedGitPath);
string doubleTransformedPath = Paths.ConvertPathToGitFormat(actualTransformedPath);
doubleTransformedPath.ShouldEqual(expectedGitPath);
}
}
}

Просмотреть файл

@ -1,311 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using Scalar.UnitTests.Category;
using Scalar.UnitTests.Mock.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class PhysicalFileSystemDeleteTests
{
[TestCase]
public void TryDeleteFileDeletesFile()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) });
fileSystem.TryDeleteFile(path);
fileSystem.ExistingFiles.ContainsKey(path).ShouldBeFalse("DeleteUtils failed to delete file");
}
[TestCase]
public void TryDeleteFileSetsAttributesToNormalBeforeDeletingFile()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(
new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) },
allFilesExist: false,
noOpDelete: true);
fileSystem.TryDeleteFile(path);
fileSystem.ExistingFiles.ContainsKey(path).ShouldBeTrue("DeleteTestsFileSystem is configured as no-op delete, file should still be present");
fileSystem.ExistingFiles[path].ShouldEqual(FileAttributes.Normal, "TryDeleteFile should set attributes to Normal before deleting");
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryDeleteFileReturnsTrueWhenSetAttributesFailsToFindFile()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(
Enumerable.Empty<KeyValuePair<string, FileAttributes>>(),
allFilesExist: true,
noOpDelete: false);
fileSystem.TryDeleteFile(path).ShouldEqual(true, "TryDeleteFile should return true when SetAttributes throws FileNotFoundException");
}
[TestCase]
public void TryDeleteFileReturnsNullExceptionOnSuccess()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) });
Exception e = new Exception();
fileSystem.TryDeleteFile(path, out e);
fileSystem.ExistingFiles.ContainsKey(path).ShouldBeFalse("DeleteUtils failed to delete file");
e.ShouldBeNull("Exception should be null when TryDeleteFile succeeds");
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryDeleteFileReturnsThrownException()
{
string path = "mock:\\file.txt";
Exception deleteException = new IOException();
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) });
fileSystem.DeleteException = deleteException;
Exception e;
fileSystem.TryDeleteFile(path, out e).ShouldBeFalse("TryDeleteFile should fail on IOException");
ReferenceEquals(e, deleteException).ShouldBeTrue("TryDeleteFile should return the thrown exception");
deleteException = new UnauthorizedAccessException();
fileSystem.DeleteException = deleteException;
fileSystem.TryDeleteFile(path, out e).ShouldBeFalse("TryDeleteFile should fail on UnauthorizedAccessException");
ReferenceEquals(e, deleteException).ShouldBeTrue("TryDeleteFile should return the thrown exception");
}
[TestCase]
public void TryDeleteFileDoesNotUpdateMetadataOnSuccess()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) });
EventMetadata metadata = new EventMetadata();
fileSystem.TryDeleteFile(path, "metadataKey", metadata).ShouldBeTrue("TryDeleteFile should succeed");
metadata.ShouldBeEmpty("TryDeleteFile should not update metadata on success");
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryDeleteFileUpdatesMetadataOnFailure()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) });
fileSystem.DeleteException = new IOException();
EventMetadata metadata = new EventMetadata();
fileSystem.TryDeleteFile(path, "testKey", metadata).ShouldBeFalse("TryDeleteFile should fail when IOException is thrown");
metadata.ContainsKey("testKey_DeleteFailed").ShouldBeTrue();
metadata["testKey_DeleteFailed"].ShouldEqual("true");
metadata.ContainsKey("testKey_DeleteException").ShouldBeTrue();
metadata["testKey_DeleteException"].ShouldBeOfType<string>().ShouldContain("IOException");
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryWaitForDeleteSucceedsAfterFailures()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) });
fileSystem.DeleteException = new IOException();
fileSystem.MaxDeleteFileExceptions = 5;
fileSystem.TryWaitForDelete(null, path, retryDelayMs: 0, maxRetries: 10, retryLoggingThreshold: 1).ShouldBeTrue();
fileSystem.DeleteFileCallCount.ShouldEqual(fileSystem.MaxDeleteFileExceptions + 1);
fileSystem.ExistingFiles.Add(path, FileAttributes.ReadOnly);
fileSystem.DeleteFileCallCount = 0;
fileSystem.MaxDeleteFileExceptions = 9;
fileSystem.TryWaitForDelete(null, path, retryDelayMs: 0, maxRetries: 10, retryLoggingThreshold: 1).ShouldBeTrue();
fileSystem.DeleteFileCallCount.ShouldEqual(fileSystem.MaxDeleteFileExceptions + 1);
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryWaitForDeleteFailsAfterMaxRetries()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) });
fileSystem.DeleteException = new IOException();
int maxRetries = 10;
fileSystem.TryWaitForDelete(null, path, retryDelayMs: 0, maxRetries: maxRetries, retryLoggingThreshold: 1).ShouldBeFalse();
fileSystem.DeleteFileCallCount.ShouldEqual(maxRetries + 1);
fileSystem.DeleteFileCallCount = 0;
fileSystem.TryWaitForDelete(null, path, retryDelayMs: 1, maxRetries: maxRetries, retryLoggingThreshold: 1).ShouldBeFalse();
fileSystem.DeleteFileCallCount.ShouldEqual(maxRetries + 1);
fileSystem.DeleteFileCallCount = 0;
fileSystem.TryWaitForDelete(null, path, retryDelayMs: 1, maxRetries: 0, retryLoggingThreshold: 1).ShouldBeFalse();
fileSystem.DeleteFileCallCount.ShouldEqual(1);
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryWaitForDeleteAlwaysLogsFirstAndLastFailure()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) });
fileSystem.DeleteException = new IOException();
MockTracer mockTracer = new MockTracer();
int maxRetries = 10;
fileSystem.TryWaitForDelete(mockTracer, path, retryDelayMs: 0, maxRetries: maxRetries, retryLoggingThreshold: 1000).ShouldBeFalse();
fileSystem.DeleteFileCallCount.ShouldEqual(maxRetries + 1);
mockTracer.RelatedWarningEvents.Count.ShouldEqual(2, "There should be two warning events, the first and last");
mockTracer.RelatedWarningEvents[0].ShouldContain(
new[]
{
"Failed to delete file, retrying ...",
"\"failureCount\":1",
"IOException"
});
mockTracer.RelatedWarningEvents[1].ShouldContain(
new[]
{
"Failed to delete file.",
"\"failureCount\":11",
"IOException"
});
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryWaitForDeleteLogsAtSpecifiedInterval()
{
string path = "mock:\\file.txt";
DeleteTestsFileSystem fileSystem = new DeleteTestsFileSystem(new[] { new KeyValuePair<string, FileAttributes>(path, FileAttributes.ReadOnly) });
fileSystem.DeleteException = new IOException();
MockTracer mockTracer = new MockTracer();
int maxRetries = 10;
fileSystem.TryWaitForDelete(mockTracer, path, retryDelayMs: 0, maxRetries: maxRetries, retryLoggingThreshold: 3).ShouldBeFalse();
fileSystem.DeleteFileCallCount.ShouldEqual(maxRetries + 1);
mockTracer.RelatedWarningEvents.Count.ShouldEqual(5, "There should be five warning events, the first and last, and the 4th, 7th, and 10th");
mockTracer.RelatedWarningEvents[0].ShouldContain(
new[]
{
"Failed to delete file, retrying ...",
"\"failureCount\":1",
"IOException"
});
mockTracer.RelatedWarningEvents[1].ShouldContain(
new[]
{
"Failed to delete file, retrying ...",
"\"failureCount\":4",
"IOException"
});
mockTracer.RelatedWarningEvents[2].ShouldContain(
new[]
{
"Failed to delete file, retrying ...",
"\"failureCount\":7",
"IOException"
});
mockTracer.RelatedWarningEvents[3].ShouldContain(
new[]
{
"Failed to delete file, retrying ...",
"\"failureCount\":10",
"IOException"
});
mockTracer.RelatedWarningEvents[4].ShouldContain(
new[]
{
"Failed to delete file.",
"\"failureCount\":11",
"IOException"
});
}
private class DeleteTestsFileSystem : PhysicalFileSystem
{
private bool allFilesExist;
private bool noOpDelete;
public DeleteTestsFileSystem(
IEnumerable<KeyValuePair<string, FileAttributes>> existingFiles,
bool allFilesExist = false,
bool noOpDelete = false)
{
this.ExistingFiles = new Dictionary<string, FileAttributes>(ScalarPlatform.Instance.Constants.PathComparer);
foreach (KeyValuePair<string, FileAttributes> kvp in existingFiles)
{
this.ExistingFiles[kvp.Key] = kvp.Value;
}
this.allFilesExist = allFilesExist;
this.noOpDelete = noOpDelete;
this.DeleteFileCallCount = 0;
this.MaxDeleteFileExceptions = -1;
}
public Dictionary<string, FileAttributes> ExistingFiles { get; private set; }
public Exception DeleteException { get; set; }
public int MaxDeleteFileExceptions { get; set; }
public int DeleteFileCallCount { get; set; }
public override bool FileExists(string path)
{
if (this.allFilesExist)
{
return true;
}
return this.ExistingFiles.ContainsKey(path);
}
public override void SetAttributes(string path, FileAttributes fileAttributes)
{
if (this.ExistingFiles.ContainsKey(path))
{
this.ExistingFiles[path] = fileAttributes;
}
else
{
throw new FileNotFoundException();
}
}
public override void DeleteFile(string path)
{
this.DeleteFileCallCount++;
if (!this.noOpDelete)
{
if (this.DeleteException != null &&
(this.MaxDeleteFileExceptions == -1 || this.MaxDeleteFileExceptions >= this.DeleteFileCallCount))
{
throw this.DeleteException;
}
if (this.ExistingFiles.ContainsKey(path))
{
if ((this.ExistingFiles[path] & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
{
throw new UnauthorizedAccessException();
}
else
{
this.ExistingFiles.Remove(path);
}
}
}
}
}
}
}

Просмотреть файл

@ -1,76 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.UnitTests.Mock.Common;
using System;
using System.IO;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class ProductUpgraderInfoTests
{
private Mock<PhysicalFileSystem> mockFileSystem;
private ProductUpgraderInfo productUpgraderInfo;
private string upgradeDirectory;
private string expectedNewVersionExistsFileName = "HighestAvailableVersion";
private string expectedNewVersionExistsFilePath;
private MockTracer tracer;
[SetUp]
public void SetUp()
{
this.upgradeDirectory = ProductUpgraderInfo.GetHighestAvailableVersionDirectory();
this.expectedNewVersionExistsFilePath = Path.Combine(this.upgradeDirectory, this.expectedNewVersionExistsFileName);
this.mockFileSystem = new Mock<PhysicalFileSystem>();
this.mockFileSystem.Setup(fileSystem => fileSystem.WriteAllText(this.expectedNewVersionExistsFilePath, It.IsAny<string>()));
this.tracer = new MockTracer();
this.productUpgraderInfo = new ProductUpgraderInfo(
this.tracer,
this.mockFileSystem.Object);
}
[TearDown]
public void TearDown()
{
this.mockFileSystem = null;
this.productUpgraderInfo = null;
this.tracer = null;
}
[TestCase]
public void RecordHighestVersion()
{
this.productUpgraderInfo.RecordHighestAvailableVersion(new Version("1.0.0.0"));
this.mockFileSystem.Verify(fileSystem => fileSystem.WriteAllText(this.expectedNewVersionExistsFilePath, It.IsAny<string>()), Times.Once());
}
[TestCase]
public void RecordingEmptyVersionDeletesExistingHighestVersionFile()
{
this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.expectedNewVersionExistsFilePath)).Returns(true);
this.productUpgraderInfo.RecordHighestAvailableVersion(null);
this.mockFileSystem.Verify(fileSystem => fileSystem.FileExists(this.expectedNewVersionExistsFilePath), Times.Once());
this.mockFileSystem.Verify(fileSystem => fileSystem.DeleteFile(this.expectedNewVersionExistsFilePath), Times.Once());
}
[TestCase]
public void RecordingEmptyVersionDoesNotDeleteNonExistingHighestVersionFile()
{
this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.expectedNewVersionExistsFilePath)).Returns(false);
this.productUpgraderInfo.RecordHighestAvailableVersion(null);
this.mockFileSystem.Verify(fileSystem => fileSystem.FileExists(this.expectedNewVersionExistsFilePath), Times.Once());
this.mockFileSystem.Verify(fileSystem => fileSystem.DeleteFile(this.expectedNewVersionExistsFilePath), Times.Never());
}
}
}

Просмотреть файл

@ -1,253 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common.FileSystem;
using Scalar.Common.RepoRegistry;
using Scalar.Tests.Should;
using Scalar.UnitTests.Category;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Scalar.UnitTests.Common.RepoRegistry
{
[TestFixture]
public class ScalarRepoRegistryTests
{
private readonly string registryFolderPath = Path.Combine(MockFileSystem.GetMockRoot(), "Scalar", "UnitTests.RepoRegistry");
[TestCase]
public void TryRegisterRepo_CreatesMissingRegistryDirectory()
{
MockFileSystem fileSystem = new MockFileSystem(new MockDirectory(Path.GetDirectoryName(this.registryFolderPath), null, null));
ScalarRepoRegistry registry = new ScalarRepoRegistry(
new MockTracer(),
fileSystem,
this.registryFolderPath);
List<ScalarRepoRegistration> registrations = new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo1"), "testUser")
};
fileSystem.DirectoryExists(this.registryFolderPath).ShouldBeFalse();
this.RegisterRepos(registry, registrations);
fileSystem.DirectoryExists(this.registryFolderPath).ShouldBeTrue("Registering a repo should have created the missing registry directory");
this.RegistryShouldContainRegistrations(registry, registrations);
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryRegisterRepo_FailsIfMissingRegistryDirectoryCantBeCreated()
{
Mock<PhysicalFileSystem> mockFileSystem = new Mock<PhysicalFileSystem>(MockBehavior.Strict);
mockFileSystem.Setup(fileSystem => fileSystem.DirectoryExists(this.registryFolderPath)).Returns(false);
mockFileSystem.Setup(fileSystem => fileSystem.CreateDirectory(this.registryFolderPath)).Throws(new UnauthorizedAccessException());
ScalarRepoRegistry registry = new ScalarRepoRegistry(
new MockTracer(),
mockFileSystem.Object,
this.registryFolderPath);
string testRepoRoot = Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo1");
string testUserId = "testUser";
registry.TryRegisterRepo(testRepoRoot, testUserId, out string errorMessage).ShouldBeFalse();
errorMessage.ShouldNotBeNullOrEmpty();
mockFileSystem.VerifyAll();
}
[TestCase]
public void TryRegisterRepo_RegisterMultipleRepos()
{
MockFileSystem fileSystem = new MockFileSystem(new MockDirectory(Path.GetDirectoryName(this.registryFolderPath), null, null));
ScalarRepoRegistry registry = new ScalarRepoRegistry(
new MockTracer(),
fileSystem,
this.registryFolderPath);
List<ScalarRepoRegistration> repoRegistrations = new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo1"), "testUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo2"), "testUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "MoreRepos", "Repo1"), "user2"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "MoreRepos", "Repo2"), "user2"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos2", "Repo1"), "testUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos3", "Repo1"), "ThirdUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos3", "Repo2"), "ThirdUser")
};
this.RegisterRepos(registry, repoRegistrations);
this.RegistryShouldContainRegistrations(registry, repoRegistrations);
}
[TestCase]
public void TryRegisterRepo_UpdatesUsersForExistingRegistrations()
{
MockFileSystem fileSystem = new MockFileSystem(new MockDirectory(Path.GetDirectoryName(this.registryFolderPath), null, null));
ScalarRepoRegistry registry = new ScalarRepoRegistry(
new MockTracer(),
fileSystem,
this.registryFolderPath);
List<ScalarRepoRegistration> registrationsPart1 = new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo1"), "testUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "MoreRepos", "Repo1"), "user2"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos2", "Repo1"), "testUser")
};
List<ScalarRepoRegistration> registrationsPart2 = new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo2"), "testUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "MoreRepos", "Repo2"), "user2"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos3", "Repo1"), "ThirdUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos3", "Repo2"), "ThirdUser")
};
this.RegisterRepos(registry, registrationsPart1.Concat(registrationsPart2));
this.RegistryShouldContainRegistrations(registry, registrationsPart1.Concat(registrationsPart2));
// Update the users on some registrations
foreach (ScalarRepoRegistration registration in registrationsPart2)
{
registration.UserId = $"UPDATED_{registration.UserId}";
}
// Just register the updates
this.RegisterRepos(registry, registrationsPart2);
// The unchanged + updated entries should be present
this.RegistryShouldContainRegistrations(registry, registrationsPart1.Concat(registrationsPart2));
}
[TestCase]
public void TryUnregisterRepo_RemovesRegisteredRepos()
{
MockFileSystem fileSystem = new MockFileSystem(new MockDirectory(Path.GetDirectoryName(this.registryFolderPath), null, null));
ScalarRepoRegistry registry = new ScalarRepoRegistry(
new MockTracer(),
fileSystem,
this.registryFolderPath);
List<ScalarRepoRegistration> registrationsPart1 = new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo1"), "testUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "MoreRepos", "Repo1"), "user2"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos2", "Repo1"), "testUser")
};
List<ScalarRepoRegistration> registrationsPart2 = new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo2"), "testUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "MoreRepos", "Repo2"), "user2"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos3", "Repo1"), "ThirdUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos3", "Repo2"), "ThirdUser")
};
this.RegisterRepos(registry, registrationsPart1.Concat(registrationsPart2));
this.RegistryShouldContainRegistrations(registry, registrationsPart1.Concat(registrationsPart2));
this.UnregisterRepos(registry, registrationsPart2);
this.RegistryShouldContainRegistrations(registry, registrationsPart1);
}
[TestCase]
public void TryUnregisterRepo_FailsIfRegistryDirectoryMissing()
{
MockFileSystem fileSystem = new MockFileSystem(new MockDirectory(Path.GetDirectoryName(this.registryFolderPath), null, null));
ScalarRepoRegistry registry = new ScalarRepoRegistry(
new MockTracer(),
fileSystem,
this.registryFolderPath);
fileSystem.DirectoryExists(this.registryFolderPath).ShouldBeFalse();
registry.TryUnregisterRepo(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo1"), out string errorMessage).ShouldBeFalse();
errorMessage.ShouldNotBeNullOrEmpty();
fileSystem.DirectoryExists(this.registryFolderPath).ShouldBeFalse();
}
[TestCase]
public void TryUnregisterRepo_FailsForUnregisteredRepo()
{
MockFileSystem fileSystem = new MockFileSystem(new MockDirectory(Path.GetDirectoryName(this.registryFolderPath), null, null));
ScalarRepoRegistry registry = new ScalarRepoRegistry(
new MockTracer(),
fileSystem,
this.registryFolderPath);
List<ScalarRepoRegistration> registrations = new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo1"), "testUser")
};
this.RegisterRepos(registry, registrations);
registry.TryUnregisterRepo(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo2"), out string errorMessage).ShouldBeFalse();
errorMessage.ShouldNotBeNullOrEmpty();
this.RegistryShouldContainRegistrations(registry, registrations);
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void TryUnregisterRepo_FailsIfDeleteFails()
{
string repoPath = Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "Repo1");
string registrationFilePath = Path.Combine(this.registryFolderPath, ScalarRepoRegistry.GetRepoRootSha(repoPath) + ".repo");
Mock<PhysicalFileSystem> mockFileSystem = new Mock<PhysicalFileSystem>(MockBehavior.Strict);
mockFileSystem.Setup(fileSystem => fileSystem.FileExists(registrationFilePath)).Returns(true);
mockFileSystem.Setup(fileSystem => fileSystem.DeleteFile(registrationFilePath)).Throws(new UnauthorizedAccessException());
ScalarRepoRegistry registry = new ScalarRepoRegistry(
new MockTracer(),
mockFileSystem.Object,
this.registryFolderPath);
registry.TryUnregisterRepo(repoPath, out string errorMessage).ShouldBeFalse();
errorMessage.ShouldNotBeNullOrEmpty();
mockFileSystem.VerifyAll();
}
[TestCase]
public void GetRepoRootSha_IsStable()
{
// Don't use MockFileSystem.GetMockRoot() as the SHA is tied to the specific string
// passed to GetRepoRootSha
ScalarRepoRegistry.GetRepoRootSha(@"B:\Repos\Repo1").ShouldEqual("f42a90ef8218f011c5dbcb642bd8eb6c08add452");
ScalarRepoRegistry.GetRepoRootSha(@"B:\folder\repoRoot").ShouldEqual("5a3c2a461d342525a532b03479e6cdeb775fa497");
}
private static bool RepoRegistrationsEqual(ScalarRepoRegistration repo1, ScalarRepoRegistration repo2)
{
return
repo1.NormalizedRepoRoot.Equals(repo2.NormalizedRepoRoot, StringComparison.Ordinal) &&
repo1.UserId.Equals(repo2.UserId, StringComparison.Ordinal);
}
private void RegisterRepos(ScalarRepoRegistry registry, IEnumerable<ScalarRepoRegistration> registrations)
{
foreach (ScalarRepoRegistration registration in registrations)
{
registry.TryRegisterRepo(registration.NormalizedRepoRoot, registration.UserId, out string errorMessage).ShouldBeTrue();
errorMessage.ShouldBeNull();
}
}
private void UnregisterRepos(ScalarRepoRegistry registry, IEnumerable<ScalarRepoRegistration> registrations)
{
foreach (ScalarRepoRegistration registration in registrations)
{
registry.TryUnregisterRepo(registration.NormalizedRepoRoot, out string errorMessage).ShouldBeTrue();
errorMessage.ShouldBeNull();
}
}
private void RegistryShouldContainRegistrations(ScalarRepoRegistry registry, IEnumerable<ScalarRepoRegistration> registrations)
{
registry.GetRegisteredRepos().ShouldMatch(registrations, RepoRegistrationsEqual);
}
}
}

Просмотреть файл

@ -1,83 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
using System;
using System.Threading;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class RetryBackoffTests
{
[TestCase]
public void CalculateBackoffReturnsZeroForFirstAttempt()
{
int failedAttempt = 1;
int maxBackoff = 300;
RetryBackoff.CalculateBackoffSeconds(failedAttempt, maxBackoff).ShouldEqual(0);
}
[TestCase]
public void CalculateBackoff()
{
int failedAttempt = 2;
int maxBackoff = 300;
double backoff = RetryBackoff.CalculateBackoffSeconds(failedAttempt, maxBackoff);
this.ValidateBackoff(backoff, failedAttempt, maxBackoff, RetryBackoff.DefaultExponentialBackoffBase);
backoff = RetryBackoff.CalculateBackoffSeconds(failedAttempt, maxBackoff, RetryBackoff.DefaultExponentialBackoffBase + 1);
this.ValidateBackoff(backoff, failedAttempt, maxBackoff, RetryBackoff.DefaultExponentialBackoffBase + 1);
++failedAttempt;
backoff = RetryBackoff.CalculateBackoffSeconds(failedAttempt, maxBackoff);
this.ValidateBackoff(backoff, failedAttempt, maxBackoff, RetryBackoff.DefaultExponentialBackoffBase);
backoff = RetryBackoff.CalculateBackoffSeconds(failedAttempt, maxBackoff, RetryBackoff.DefaultExponentialBackoffBase + 1);
this.ValidateBackoff(backoff, failedAttempt, maxBackoff, RetryBackoff.DefaultExponentialBackoffBase + 1);
}
[TestCase]
public void CalculateBackoffThatWouldExceedMaxBackoff()
{
int failedAttempt = 30;
int maxBackoff = 300;
double backoff = RetryBackoff.CalculateBackoffSeconds(failedAttempt, maxBackoff);
this.ValidateBackoff(backoff, failedAttempt, maxBackoff, RetryBackoff.DefaultExponentialBackoffBase);
}
[TestCase]
public void CalculateBackoffAcrossMultipleThreads()
{
int failedAttempt = 2;
int maxBackoff = 300;
int numThreads = 10;
Thread[] calcThreads = new Thread[numThreads];
for (int i = 0; i < numThreads; i++)
{
calcThreads[i] = new Thread(
() =>
{
double backoff = RetryBackoff.CalculateBackoffSeconds(failedAttempt, maxBackoff);
this.ValidateBackoff(backoff, failedAttempt, maxBackoff, RetryBackoff.DefaultExponentialBackoffBase);
});
calcThreads[i].Start();
}
for (int i = 0; i < calcThreads.Length; i++)
{
calcThreads[i].Join();
}
}
private void ValidateBackoff(double backoff, int failedAttempt, double maxBackoff, double exponentialBackoffBase)
{
backoff.ShouldBeAtLeast(Math.Min(Math.Pow(exponentialBackoffBase, failedAttempt), maxBackoff) * .9);
backoff.ShouldBeAtMost(Math.Min(Math.Pow(exponentialBackoffBase, failedAttempt), maxBackoff) * 1.1);
}
}
}

Просмотреть файл

@ -1,111 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.Git;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.Git;
using System;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class RetryConfigTests
{
private const string ReadConfigFailureMessage = "Failed to read config";
[TestCase]
public void TryLoadConfigFailsWhenGitFailsToReadConfig()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = new MockGitProcess();
gitProcess.SetExpectedCommandResult("config scalar.max-retries", () => new GitProcess.Result(string.Empty, ReadConfigFailureMessage, GitProcess.Result.GenericFailureCode));
gitProcess.SetExpectedCommandResult("config scalar.timeout-seconds", () => new GitProcess.Result(string.Empty, ReadConfigFailureMessage, GitProcess.Result.GenericFailureCode));
RetryConfig config;
string error;
RetryConfig.TryLoadFromGitConfig(tracer, gitProcess, out config, out error).ShouldEqual(false);
error.ShouldContain(ReadConfigFailureMessage);
}
[TestCase]
public void TryLoadConfigUsesDefaultValuesWhenEntriesNotInConfig()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = new MockGitProcess();
gitProcess.SetExpectedCommandResult("config scalar.max-retries", () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.GenericFailureCode));
gitProcess.SetExpectedCommandResult("config scalar.timeout-seconds", () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.GenericFailureCode));
RetryConfig config;
string error;
RetryConfig.TryLoadFromGitConfig(tracer, gitProcess, out config, out error).ShouldEqual(true);
error.ShouldEqual(string.Empty);
config.MaxRetries.ShouldEqual(RetryConfig.DefaultMaxRetries);
config.MaxAttempts.ShouldEqual(config.MaxRetries + 1);
config.Timeout.ShouldEqual(TimeSpan.FromSeconds(RetryConfig.DefaultTimeoutSeconds));
}
[TestCase]
public void TryLoadConfigUsesDefaultValuesWhenEntriesAreBlank()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = new MockGitProcess();
gitProcess.SetExpectedCommandResult("config scalar.max-retries", () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
gitProcess.SetExpectedCommandResult("config scalar.timeout-seconds", () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
RetryConfig config;
string error;
RetryConfig.TryLoadFromGitConfig(tracer, gitProcess, out config, out error).ShouldEqual(true);
error.ShouldEqual(string.Empty);
config.MaxRetries.ShouldEqual(RetryConfig.DefaultMaxRetries);
config.MaxAttempts.ShouldEqual(config.MaxRetries + 1);
config.Timeout.ShouldEqual(TimeSpan.FromSeconds(RetryConfig.DefaultTimeoutSeconds));
}
[TestCase]
public void TryLoadConfigEnforcesMinimumValuesOnMaxRetries()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = new MockGitProcess();
gitProcess.SetExpectedCommandResult("config scalar.max-retries", () => new GitProcess.Result("-1", string.Empty, GitProcess.Result.SuccessCode));
gitProcess.SetExpectedCommandResult("config scalar.timeout-seconds", () => new GitProcess.Result("30", string.Empty, GitProcess.Result.SuccessCode));
RetryConfig config;
string error;
RetryConfig.TryLoadFromGitConfig(tracer, gitProcess, out config, out error).ShouldEqual(false);
error.ShouldContain("Invalid value -1 for setting scalar.max-retries, value must be greater than or equal to 0");
}
[TestCase]
public void TryLoadConfigEnforcesMinimumValuesOnTimeout()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = new MockGitProcess();
gitProcess.SetExpectedCommandResult("config scalar.max-retries", () => new GitProcess.Result("3", string.Empty, GitProcess.Result.SuccessCode));
gitProcess.SetExpectedCommandResult("config scalar.timeout-seconds", () => new GitProcess.Result("-1", string.Empty, GitProcess.Result.SuccessCode));
RetryConfig config;
string error;
RetryConfig.TryLoadFromGitConfig(tracer, gitProcess, out config, out error).ShouldEqual(false);
error.ShouldContain("Invalid value -1 for setting scalar.timeout-seconds, value must be greater than or equal to 0");
}
[TestCase]
public void TryLoadConfigUsesConfiguredValues()
{
int maxRetries = RetryConfig.DefaultMaxRetries + 1;
int timeoutSeconds = RetryConfig.DefaultTimeoutSeconds + 1;
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = new MockGitProcess();
gitProcess.SetExpectedCommandResult("config scalar.max-retries", () => new GitProcess.Result(maxRetries.ToString(), string.Empty, GitProcess.Result.SuccessCode));
gitProcess.SetExpectedCommandResult("config scalar.timeout-seconds", () => new GitProcess.Result(timeoutSeconds.ToString(), string.Empty, GitProcess.Result.SuccessCode));
RetryConfig config;
string error;
RetryConfig.TryLoadFromGitConfig(tracer, gitProcess, out config, out error).ShouldEqual(true);
error.ShouldEqual(string.Empty);
config.MaxRetries.ShouldEqual(maxRetries);
config.MaxAttempts.ShouldEqual(config.MaxRetries + 1);
config.Timeout.ShouldEqual(TimeSpan.FromSeconds(timeoutSeconds));
}
}
}

Просмотреть файл

@ -1,237 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
using Scalar.UnitTests.Category;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class RetryWrapperTests
{
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void WillRetryOnIOException()
{
const int ExpectedTries = 5;
RetryWrapper<bool> dut = new RetryWrapper<bool>(ExpectedTries, CancellationToken.None, exponentialBackoffBase: 0);
int actualTries = 0;
RetryWrapper<bool>.InvocationResult output = dut.Invoke(
tryCount =>
{
actualTries++;
throw new IOException();
});
output.Succeeded.ShouldEqual(false);
actualTries.ShouldEqual(ExpectedTries);
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void WillNotRetryForGenericExceptions()
{
const int MaxTries = 5;
RetryWrapper<bool> dut = new RetryWrapper<bool>(MaxTries, CancellationToken.None, exponentialBackoffBase: 0);
Assert.Throws<Exception>(
() =>
{
RetryWrapper<bool>.InvocationResult output = dut.Invoke(tryCount => { throw new Exception(); });
});
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void WillNotMakeAnyAttemptWhenInitiallyCanceled()
{
const int MaxTries = 5;
int actualTries = 0;
RetryWrapper<bool> dut = new RetryWrapper<bool>(MaxTries, new CancellationToken(canceled: true), exponentialBackoffBase: 0);
Assert.Throws<OperationCanceledException>(
() =>
{
RetryWrapper<bool>.InvocationResult output = dut.Invoke(tryCount =>
{
++actualTries;
return new RetryWrapper<bool>.CallbackResult(true);
});
});
actualTries.ShouldEqual(0);
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void WillNotRetryForWhenCanceledDuringAttempts()
{
const int MaxTries = 5;
int actualTries = 0;
int expectedTries = 3;
using (CancellationTokenSource tokenSource = new CancellationTokenSource())
{
RetryWrapper<bool> dut = new RetryWrapper<bool>(MaxTries, tokenSource.Token, exponentialBackoffBase: 0);
Assert.Throws<OperationCanceledException>(
() =>
{
RetryWrapper<bool>.InvocationResult output = dut.Invoke(tryCount =>
{
++actualTries;
if (actualTries == expectedTries)
{
tokenSource.Cancel();
}
return new RetryWrapper<bool>.CallbackResult(new Exception("Test"), shouldRetry: true);
});
});
actualTries.ShouldEqual(expectedTries);
}
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void WillNotRetryWhenCancelledDuringBackoff()
{
const int MaxTries = 5;
int actualTries = 0;
int expectedTries = 2; // 2 because RetryWrapper does not wait after the first failure
using (CancellationTokenSource tokenSource = new CancellationTokenSource())
{
RetryWrapper<bool> dut = new RetryWrapper<bool>(MaxTries, tokenSource.Token, exponentialBackoffBase: 300);
Task.Run(() =>
{
// Wait 3 seconds and cancel
Thread.Sleep(1000 * 3);
tokenSource.Cancel();
});
Assert.Throws<OperationCanceledException>(
() =>
{
RetryWrapper<bool>.InvocationResult output = dut.Invoke(tryCount =>
{
++actualTries;
return new RetryWrapper<bool>.CallbackResult(new Exception("Test"), shouldRetry: true);
});
});
actualTries.ShouldEqual(expectedTries);
}
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void OnFailureIsCalledWhenEventHandlerAttached()
{
const int MaxTries = 5;
const int ExpectedFailures = 5;
RetryWrapper<bool> dut = new RetryWrapper<bool>(MaxTries, CancellationToken.None, exponentialBackoffBase: 0);
int actualFailures = 0;
dut.OnFailure += errorArgs => actualFailures++;
RetryWrapper<bool>.InvocationResult output = dut.Invoke(
tryCount =>
{
throw new IOException();
});
output.Succeeded.ShouldEqual(false);
actualFailures.ShouldEqual(ExpectedFailures);
}
[TestCase]
public void OnSuccessIsOnlyCalledOnce()
{
const int MaxTries = 5;
const int ExpectedFailures = 0;
const int ExpectedTries = 1;
RetryWrapper<bool> dut = new RetryWrapper<bool>(MaxTries, CancellationToken.None, exponentialBackoffBase: 0);
int actualFailures = 0;
dut.OnFailure += errorArgs => actualFailures++;
int actualTries = 0;
RetryWrapper<bool>.InvocationResult output = dut.Invoke(
tryCount =>
{
actualTries++;
return new RetryWrapper<bool>.CallbackResult(true);
});
output.Succeeded.ShouldEqual(true);
output.Result.ShouldEqual(true);
actualTries.ShouldEqual(ExpectedTries);
actualFailures.ShouldEqual(ExpectedFailures);
}
[TestCase]
public void WillNotRetryWhenNotRequested()
{
const int MaxTries = 5;
const int ExpectedFailures = 1;
const int ExpectedTries = 1;
RetryWrapper<bool> dut = new RetryWrapper<bool>(MaxTries, CancellationToken.None, exponentialBackoffBase: 0);
int actualFailures = 0;
dut.OnFailure += errorArgs => actualFailures++;
int actualTries = 0;
RetryWrapper<bool>.InvocationResult output = dut.Invoke(
tryCount =>
{
actualTries++;
return new RetryWrapper<bool>.CallbackResult(new Exception("Test"), shouldRetry: false);
});
output.Succeeded.ShouldEqual(false);
output.Result.ShouldEqual(false);
actualTries.ShouldEqual(ExpectedTries);
actualFailures.ShouldEqual(ExpectedFailures);
}
[TestCase]
public void WillRetryWhenRequested()
{
const int MaxTries = 5;
const int ExpectedFailures = 5;
const int ExpectedTries = 5;
RetryWrapper<bool> dut = new RetryWrapper<bool>(MaxTries, CancellationToken.None, exponentialBackoffBase: 0);
int actualFailures = 0;
dut.OnFailure += errorArgs => actualFailures++;
int actualTries = 0;
RetryWrapper<bool>.InvocationResult output = dut.Invoke(
tryCount =>
{
actualTries++;
return new RetryWrapper<bool>.CallbackResult(new Exception("Test"), shouldRetry: true);
});
output.Succeeded.ShouldEqual(false);
output.Result.ShouldEqual(false);
actualTries.ShouldEqual(ExpectedTries);
actualFailures.ShouldEqual(ExpectedFailures);
}
}
}

Просмотреть файл

@ -1,78 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
using System.Text;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class SHA1UtilTests
{
private const string TestString = "c:\\Repos\\GVFS\\src\\.gittattributes";
private const string TestResultSha1 = "ced5ad9680c1a05e9100680c2b3432de23bb7d6d";
private const string TestResultHex = "633a5c5265706f735c475646535c7372635c2e6769747461747472696275746573";
[TestCase]
public void SHA1HashStringForUTF8String()
{
SHA1Util.SHA1HashStringForUTF8String(TestString).ShouldEqual(TestResultSha1);
}
[TestCase]
public void HexStringFromBytes()
{
byte[] bytes = Encoding.UTF8.GetBytes(TestString);
SHA1Util.HexStringFromBytes(bytes).ShouldEqual(TestResultHex);
}
[TestCase]
public void IsValidFullSHAIsFalseForEmptyString()
{
SHA1Util.IsValidShaFormat(string.Empty).ShouldEqual(false);
}
[TestCase]
public void IsValidFullSHAIsFalseForHexStringsNot40Chars()
{
SHA1Util.IsValidShaFormat("1").ShouldEqual(false);
SHA1Util.IsValidShaFormat("9").ShouldEqual(false);
SHA1Util.IsValidShaFormat("A").ShouldEqual(false);
SHA1Util.IsValidShaFormat("a").ShouldEqual(false);
SHA1Util.IsValidShaFormat("f").ShouldEqual(false);
SHA1Util.IsValidShaFormat("f").ShouldEqual(false);
SHA1Util.IsValidShaFormat("1234567890abcdefABCDEF").ShouldEqual(false);
SHA1Util.IsValidShaFormat("12345678901234567890123456789012345678901").ShouldEqual(false);
}
[TestCase]
public void IsValidFullSHAFalseForNonHexStrings()
{
SHA1Util.IsValidShaFormat("@").ShouldEqual(false);
SHA1Util.IsValidShaFormat("g").ShouldEqual(false);
SHA1Util.IsValidShaFormat("G").ShouldEqual(false);
SHA1Util.IsValidShaFormat("~").ShouldEqual(false);
SHA1Util.IsValidShaFormat("_").ShouldEqual(false);
SHA1Util.IsValidShaFormat(".").ShouldEqual(false);
SHA1Util.IsValidShaFormat("1234567890abcdefABCDEF.tmp").ShouldEqual(false);
SHA1Util.IsValidShaFormat("G1234567890abcdefABCDEF.tmp").ShouldEqual(false);
SHA1Util.IsValidShaFormat("_G1234567890abcdefABCDEF.tmp").ShouldEqual(false);
SHA1Util.IsValidShaFormat("@234567890123456789012345678901234567890").ShouldEqual(false);
SHA1Util.IsValidShaFormat("g234567890123456789012345678901234567890").ShouldEqual(false);
SHA1Util.IsValidShaFormat("G234567890123456789012345678901234567890").ShouldEqual(false);
SHA1Util.IsValidShaFormat("~234567890123456789012345678901234567890").ShouldEqual(false);
SHA1Util.IsValidShaFormat("_234567890123456789012345678901234567890").ShouldEqual(false);
SHA1Util.IsValidShaFormat(".234567890123456789012345678901234567890").ShouldEqual(false);
}
[TestCase]
public void IsValidFullSHATrueForLength40HexStrings()
{
SHA1Util.IsValidShaFormat("1234567890123456789012345678901234567890").ShouldEqual(true);
SHA1Util.IsValidShaFormat("abcdef7890123456789012345678901234567890").ShouldEqual(true);
SHA1Util.IsValidShaFormat("ABCDEF7890123456789012345678901234567890").ShouldEqual(true);
SHA1Util.IsValidShaFormat("1234567890123456789012345678901234ABCDEF").ShouldEqual(true);
SHA1Util.IsValidShaFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").ShouldEqual(true);
SHA1Util.IsValidShaFormat("ffffffffffffffffffffffffffffffffffffffff").ShouldEqual(true);
}
}
}

Просмотреть файл

@ -1,89 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Tests.Should;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace Scalar.UnitTests.Common
{
[TestFixture]
public class ScalarEnlistmentTests
{
[TestCase]
public void TryGetScalarEnlistmentRoot()
{
string root = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "M:" : "/usr";
string a = Path.Combine(root, "a");
string a_b = Path.Combine(a, "b");
string a_b_src = Path.Combine(a_b, "src");
string a_b_src_git = Path.Combine(a_b_src, ".git");
string a_b_src_d = Path.Combine(a_b_src, "d");
string a_b_src_d_e = Path.Combine(a_b_src_d, "e");
string a_b_src_d_git = Path.Combine(a_b_src_d, ".git");
string a_src = Path.Combine(a, "src");
string a_src_src = Path.Combine(a_src, "src");
string a_src_src_git = Path.Combine(a_src_src, ".git");
string a_srcy = Path.Combine(a, "srcy");
string a_srcy_git = Path.Combine(a_srcy, ".git");
string a_c = Path.Combine(a, "c");
string a_c_git = Path.Combine(a_c, ".git");
HashSet<string> paths = new HashSet<string>()
{
a,
a_b,
a_b_src,
a_b_src_git,
a_b_src_d,
a_b_src_d_git,
a_src,
a_src_src,
a_src_src_git,
a_srcy,
a_srcy_git,
a_c,
a_c_git,
};
TestGetRoot(paths, false, a, null, null);
TestGetRoot(paths, true, a_b, a_b, a_b_src);
TestGetRoot(paths, true, a_b_src, a_b, a_b_src);
// The deepest Git repo should be picked.
TestGetRoot(paths, true, a_b_src_d, a_b_src_d, a_b_src_d);
TestGetRoot(paths, true, a_b_src_d_e, a_b_src_d, a_b_src_d);
TestGetRoot(paths, true, a_src, a_src, a_src_src);
TestGetRoot(paths, true, a_src_src, a_src, a_src_src);
TestGetRoot(paths, true, a_src_src_git, a_src, a_src_src);
TestGetRoot(paths, true, a_srcy, a_srcy, a_srcy);
TestGetRoot(paths, true, a_srcy_git, a_srcy, a_srcy);
TestGetRoot(paths, true, a_c, a_c, a_c);
}
private void TestGetRoot(
HashSet<string> paths,
bool expectedResult,
string directory,
string expectedEnlistmentRoot,
string expectedWorkingDirectoryRoot)
{
bool actualResult = ScalarEnlistment.TryGetScalarEnlistmentRoot(
directory,
out string enlistmentRoot,
out string workingDirectoryRoot,
path => paths.Contains(path));
actualResult.ShouldEqual(expectedResult);
if (!expectedResult)
{
return;
}
enlistmentRoot.ShouldEqual(expectedEnlistmentRoot);
workingDirectoryRoot.ShouldEqual(expectedWorkingDirectoryRoot);
}
}
}

Просмотреть файл

@ -1,259 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Git;
using Scalar.Common.NuGetUpgrade;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
namespace Scalar.UnitTests.Common
{
public class TryCreateProductUpgradeTests
{
private static string defaultUpgradeFeedPackageName = "package";
private static string defaultUpgradeFeedUrl = "https://pkgs.dev.azure.com/contoso/";
private static string defaultOrgInfoServerUrl = "https://www.contoso.com";
private static string defaultRing = "slow";
private MockTracer tracer;
private Mock<PhysicalFileSystem> fileSystemMock;
private Mock<ICredentialStore> credentialStoreMock;
[SetUp]
public void Setup()
{
this.tracer = new MockTracer();
// It is important that creating a new Upgrader does not
// require credentials. We must be able to create an
// upgrader to query / check upgrade preconditions without
// requiring authorization. We create these mocks with
// strict behavior to validate methods on them are called
// unnecessarily.
this.credentialStoreMock = new Mock<ICredentialStore>(MockBehavior.Strict);
this.fileSystemMock = new Mock<PhysicalFileSystem>(MockBehavior.Strict);
}
[TearDown]
public void TearDown()
{
this.credentialStoreMock.VerifyAll();
this.fileSystemMock.VerifyAll();
}
[TestCase]
public void CreatesNuGetUpgraderWhenConfigured()
{
MockLocalScalarConfig scalarConfig = this.ConstructDefaultMockNuGetConfigBuilder()
.Build();
bool success = ProductUpgrader.TryCreateUpgrader(
this.tracer,
this.fileSystemMock.Object,
scalarConfig,
this.credentialStoreMock.Object,
false,
false,
out ProductUpgrader productUpgrader,
out string error);
success.ShouldBeTrue();
productUpgrader.ShouldNotBeNull();
productUpgrader.ShouldBeOfType<NuGetUpgrader>();
error.ShouldBeNull();
}
[TestCase]
public void CreatesNuGetUpgraderWhenConfiguredWithNoRing()
{
MockLocalScalarConfig scalarConfig = this.ConstructDefaultMockNuGetConfigBuilder()
.WithNoUpgradeRing()
.Build();
bool success = ProductUpgrader.TryCreateUpgrader(
this.tracer,
this.fileSystemMock.Object,
scalarConfig,
this.credentialStoreMock.Object,
false,
false,
out ProductUpgrader productUpgrader,
out string error);
success.ShouldBeTrue();
productUpgrader.ShouldNotBeNull();
productUpgrader.ShouldBeOfType<NuGetUpgrader>();
error.ShouldBeNull();
}
[TestCase]
public void FailsWithDefaultConfiguration()
{
MockLocalScalarConfig scalarConfig = this.ConstructDefaultConfigBuilder()
.Build();
bool success = ProductUpgrader.TryCreateUpgrader(
this.tracer,
this.fileSystemMock.Object,
scalarConfig,
this.credentialStoreMock.Object,
false,
false,
out ProductUpgrader productUpgrader,
out string error);
success.ShouldBeFalse();
productUpgrader.ShouldBeNull();
error.ShouldNotBeNull();
}
[TestCase]
public void CreatesOrgNuGetUpgrader()
{
MockLocalScalarConfig scalarConfig = this.ConstructDefaultMockOrgNuGetConfigBuilder()
.Build();
bool success = ProductUpgrader.TryCreateUpgrader(
this.tracer,
this.fileSystemMock.Object,
scalarConfig,
this.credentialStoreMock.Object,
false,
false,
out ProductUpgrader productUpgrader,
out string error);
success.ShouldBeTrue();
productUpgrader.ShouldNotBeNull();
productUpgrader.ShouldBeOfType<OrgNuGetUpgrader>();
error.ShouldBeNull();
}
[TestCase]
public void NoUpgraderWhenNuGetFeedMissing()
{
MockLocalScalarConfig scalarConfig = this.ConstructDefaultMockNuGetConfigBuilder()
.WithNoUpgradeFeedUrl()
.Build();
bool success = ProductUpgrader.TryCreateUpgrader(
this.tracer,
this.fileSystemMock.Object,
scalarConfig,
this.credentialStoreMock.Object,
false,
false,
out ProductUpgrader productUpgrader,
out string error);
success.ShouldBeFalse();
productUpgrader.ShouldBeNull();
error.ShouldNotBeNull();
}
[TestCase]
public void NoOrgUpgraderWhenNuGetPackNameMissing()
{
MockLocalScalarConfig scalarConfig = this.ConstructDefaultMockOrgNuGetConfigBuilder()
.WithNoUpgradeFeedPackageName()
.Build();
bool success = ProductUpgrader.TryCreateUpgrader(
this.tracer,
this.fileSystemMock.Object,
scalarConfig,
this.credentialStoreMock.Object,
false,
false,
out ProductUpgrader productUpgrader,
out string error);
success.ShouldBeFalse();
productUpgrader.ShouldBeNull();
error.ShouldNotBeNull();
}
[TestCase]
public void NoOrgUpgraderWhenNuGetFeedMissing()
{
MockLocalScalarConfig scalarConfig = this.ConstructDefaultMockOrgNuGetConfigBuilder()
.WithNoUpgradeFeedUrl()
.Build();
bool success = ProductUpgrader.TryCreateUpgrader(
this.tracer,
this.fileSystemMock.Object,
scalarConfig,
this.credentialStoreMock.Object,
false,
false,
out ProductUpgrader productUpgrader,
out string error);
success.ShouldBeFalse();
productUpgrader.ShouldBeNull();
error.ShouldNotBeNull();
}
[TestCase]
public void NoUpgraderWhenNuGetPackNameMissing()
{
MockLocalScalarConfig scalarConfig = this.ConstructDefaultMockNuGetConfigBuilder()
.WithNoUpgradeFeedPackageName()
.Build();
bool success = ProductUpgrader.TryCreateUpgrader(
this.tracer,
this.fileSystemMock.Object,
scalarConfig,
this.credentialStoreMock.Object,
false,
false,
out ProductUpgrader productUpgrader,
out string error);
success.ShouldBeFalse();
productUpgrader.ShouldBeNull();
error.ShouldNotBeNull();
}
private MockLocalScalarConfigBuilder ConstructDefaultMockNuGetConfigBuilder()
{
MockLocalScalarConfigBuilder configBuilder = this.ConstructMockLocalScalarConfigBuilder()
.WithUpgradeRing()
.WithUpgradeFeedPackageName()
.WithUpgradeFeedUrl();
return configBuilder;
}
private MockLocalScalarConfigBuilder ConstructDefaultMockOrgNuGetConfigBuilder()
{
MockLocalScalarConfigBuilder configBuilder = this.ConstructMockLocalScalarConfigBuilder()
.WithUpgradeRing()
.WithUpgradeFeedPackageName()
.WithUpgradeFeedUrl()
.WithOrgInfoServerUrl();
return configBuilder;
}
private MockLocalScalarConfigBuilder ConstructDefaultConfigBuilder()
{
MockLocalScalarConfigBuilder configBuilder = this.ConstructMockLocalScalarConfigBuilder()
.WithUpgradeRing();
return configBuilder;
}
private MockLocalScalarConfigBuilder ConstructMockLocalScalarConfigBuilder()
{
return new MockLocalScalarConfigBuilder(
defaultRing,
defaultUpgradeFeedUrl,
defaultUpgradeFeedPackageName,
defaultOrgInfoServerUrl);
}
}
}

Просмотреть файл

@ -1,26 +0,0 @@
:040000 000000 34df85f635cb0e04c6d4ecedefe2707951616059 0000000000000000000000000000000000000000 D New folder
:100644 000000 953905e07b8e3fb9f8c9e5b8bd0e6cd1a2b3fbae 0000000000000000000000000000000000000000 D New folder/newFile.txt
:000000 040000 0000000000000000000000000000000000000000 2c877e829ad58c051e5f1b30391e41341d4ff56c A deepfolderdelete
:000000 040000 0000000000000000000000000000000000000000 cd3eb0505948ac13b8b550891be81fdf4def0dae A deepfolderdelete/subfolder
:000000 100644 0000000000000000000000000000000000000000 e02f6e8a454811f5a613743d3e9133afd545e36b A deepfolderdelete/subfolder/necessary.txt
:000000 100644 0000000000000000000000000000000000000000 1e2db0ae91731f7862918bb50b2af43050719cbd A fileToBecomeFolder
:040000 000000 f826e58b21f78935976a9779b27773e55e3b6429 0000000000000000000000000000000000000000 D fileToBecomeFolder
:100644 000000 39d05dc47b628f461ef92a4531db129c5d7ea4fb 0000000000000000000000000000000000000000 D fileToBecomeFolder/newdoc.txt
:000000 100644 0000000000000000000000000000000000000000 05c2b79a2c84782364b0f27244454ea29187bde6 A fileToDelete.txt
:100644 100644 c97bc99f8894348d4a8e4b8146fbac3384ac8cac 3afc1ef879df949927c85b4c849a65e39aa472c7 M fileToEdit.txt
:000000 100644 0000000000000000000000000000000000000000 0fb01bbb41482aec747112b58f1a11cf41bb7a11 A fileToRename.txt
:000000 100644 0000000000000000000000000000000000000000 ff236b434e083db032f4ac0f452303f4eeb8f4be A fileToRenameEdit.txt
:100644 000000 382d0750aef7b7e47b08f12befb7274311c4a850 0000000000000000000000000000000000000000 D fileWasRename.txt
:100644 000000 0fb01bbb41482aec747112b58f1a11cf41bb7a11 0000000000000000000000000000000000000000 D fileWasRenamed.txt
:100644 000000 c419470b3e2ee3b43d9a13edb180a453b06c0fb5 0000000000000000000000000000000000000000 D folderToBeFile
:000000 040000 0000000000000000000000000000000000000000 184fd663a53e325add265346ddd024b5a8829301 A folderToBeFile
:000000 100644 0000000000000000000000000000000000000000 f51ba4dac00d291e491906a99698c01f802e652d A folderToBeFile/existence.txt
:000000 040000 0000000000000000000000000000000000000000 a5731b081f875263a428c126a3242587fdaea6c9 A folderToDelete
:000000 100644 0000000000000000000000000000000000000000 8724404da33605d27cfa5490d412f0dfea16a277 A folderToDelete/fileToEdit2.txt
:040000 040000 403c21d5d12f6e6a6659460b5cec7e4b66b6c0f2 9a894ca28a2a8d813f2bae305cd94faf366ad5e0 M folderToEdit
:100644 100644 45f57f3292952208ad72232bc2a64038a3d0987f 59b502537b91543cb8aa7e6a26ee235197fa154b M folderToEdit/fileToEdit2.txt
:000000 040000 0000000000000000000000000000000000000000 e30358a677e3a55aa838d0bbe0207f61ce40f401 A folderToRename
:000000 100644 0000000000000000000000000000000000000000 35151eac3bb089589836bfece4dfbb84fae502de A folderToRename/existence.txt
:040000 000000 e30358a677e3a55aa838d0bbe0207f61ce40f401 0000000000000000000000000000000000000000 D folderWasRenamed
:100644 000000 35151eac3bb089589836bfece4dfbb84fae502de 0000000000000000000000000000000000000000 D folderWasRenamed/existence.txt
:100644 000000 9ff3c67e2792e4c17672c6b04a8a6efe732cb07a 0000000000000000000000000000000000000000 D newFile.txt

Просмотреть файл

@ -1,10 +0,0 @@
:040000 000000 d813c8227132c3bf73c013f8913f207b4876b2bf 0000000000000000000000000000000000000000 D GVFLT_MultiThreadTest
:040000 000000 1260ecb71f2be8eb92ea904c6dffa3e40eaaf1bf 0000000000000000000000000000000000000000 D GVFLT_MultiThreadTest/OpenForReadsSameTime
:100644 000000 eabe8d5ec569cc7e199e77411ad935f101414032 0000000000000000000000000000000000000000 D GVFLT_MultiThreadTest/OpenForReadsSameTime/test
:040000 000000 1260ecb71f2be8eb92ea904c6dffa3e40eaaf1bf 0000000000000000000000000000000000000000 D GVFLT_MultiThreadTest/OpenForWritesSameTime
:100644 000000 eabe8d5ec569cc7e199e77411ad935f101414032 0000000000000000000000000000000000000000 D GVFLT_MultiThreadTest/OpenForWritesSameTime/test
:000000 040000 0000000000000000000000000000000000000000 d813c8227132c3bf73c013f8913f207b4876b2bf A GVFlt_MultiThreadTest
:000000 040000 0000000000000000000000000000000000000000 1260ecb71f2be8eb92ea904c6dffa3e40eaaf1bf A GVFlt_MultiThreadTest/OpenForReadsSameTime
:000000 100644 0000000000000000000000000000000000000000 eabe8d5ec569cc7e199e77411ad935f101414032 A GVFlt_MultiThreadTest/OpenForReadsSameTime/test
:000000 040000 0000000000000000000000000000000000000000 1260ecb71f2be8eb92ea904c6dffa3e40eaaf1bf A GVFlt_MultiThreadTest/OpenForWritesSameTime
:000000 100644 0000000000000000000000000000000000000000 eabe8d5ec569cc7e199e77411ad935f101414032 A GVFlt_MultiThreadTest/OpenForWritesSameTime/test

Просмотреть файл

@ -1,27 +0,0 @@
:000000 040000 0000000000000000000000000000000000000000 34df85f635cb0e04c6d4ecedefe2707951616059 A New folder
:000000 100644 0000000000000000000000000000000000000000 953905e07b8e3fb9f8c9e5b8bd0e6cd1a2b3fbae A New folder/newFile.txt
:040000 000000 2c877e829ad58c051e5f1b30391e41341d4ff56c 0000000000000000000000000000000000000000 D deepfolderdelete
:040000 000000 cd3eb0505948ac13b8b550891be81fdf4def0dae 0000000000000000000000000000000000000000 D deepfolderdelete/subfolder
:100644 000000 e02f6e8a454811f5a613743d3e9133afd545e36b 0000000000000000000000000000000000000000 D deepfolderdelete/subfolder/necessary.txt
:100644 000000 1e2db0ae91731f7862918bb50b2af43050719cbd 0000000000000000000000000000000000000000 D fileToBecomeFolder
:000000 040000 0000000000000000000000000000000000000000 f826e58b21f78935976a9779b27773e55e3b6429 A fileToBecomeFolder
:000000 100644 0000000000000000000000000000000000000000 39d05dc47b628f461ef92a4531db129c5d7ea4fb A fileToBecomeFolder/newdoc.txt
:100644 000000 05c2b79a2c84782364b0f27244454ea29187bde6 0000000000000000000000000000000000000000 D fileToDelete.txt
:100644 100644 3afc1ef879df949927c85b4c849a65e39aa472c7 c97bc99f8894348d4a8e4b8146fbac3384ac8cac M fileToEdit.txt
:100644 000000 0fb01bbb41482aec747112b58f1a11cf41bb7a11 0000000000000000000000000000000000000000 D fileToRename.txt
:100644 000000 ff236b434e083db032f4ac0f452303f4eeb8f4be 0000000000000000000000000000000000000000 D fileToRenameEdit.txt
:000000 100644 0000000000000000000000000000000000000000 382d0750aef7b7e47b08f12befb7274311c4a850 A fileWasRename.txt
:000000 100644 0000000000000000000000000000000000000000 0fb01bbb41482aec747112b58f1a11cf41bb7a11 A fileWasRenamed.txt
:000000 100644 0000000000000000000000000000000000000000 c419470b3e2ee3b43d9a13edb180a453b06c0fb5 A folderToBeFile
:040000 000000 184fd663a53e325add265346ddd024b5a8829301 0000000000000000000000000000000000000000 D folderToBeFile
:100644 000000 f51ba4dac00d291e491906a99698c01f802e652d 0000000000000000000000000000000000000000 D folderToBeFile/existence.txt
:040000 000000 a5731b081f875263a428c126a3242587fdaea6c9 0000000000000000000000000000000000000000 D folderToDelete
:100644 000000 8724404da33605d27cfa5490d412f0dfea16a277 0000000000000000000000000000000000000000 D folderToDelete/fileToEdit2.txt
:040000 040000 9a894ca28a2a8d813f2bae305cd94faf366ad5e0 403c21d5d12f6e6a6659460b5cec7e4b66b6c0f2 M folderToEdit
:100644 100644 59b502537b91543cb8aa7e6a26ee235197fa154b 45f57f3292952208ad72232bc2a64038a3d0987f M folderToEdit/fileToEdit2.txt
:040000 000000 e30358a677e3a55aa838d0bbe0207f61ce40f401 0000000000000000000000000000000000000000 D folderToRename
:100644 000000 35151eac3bb089589836bfece4dfbb84fae502de 0000000000000000000000000000000000000000 D folderToRename/existence.txt
:000000 040000 0000000000000000000000000000000000000000 e30358a677e3a55aa838d0bbe0207f61ce40f401 A folderWasRenamed
:000000 100644 0000000000000000000000000000000000000000 35151eac3bb089589836bfece4dfbb84fae502de A folderWasRenamed/existence.txt
:000000 100644 0000000000000000000000000000000000000000 9ff3c67e2792e4c17672c6b04a8a6efe732cb07a A newFile.txt
:000000 120000 0000000000000000000000000000000000000000 3bd509d373734a9f9685d6a73ba73324f72931e3 A symLinkToBeCreated.txt

Двоичные данные
Scalar.UnitTests/Data/index_v4

Двоичный файл не отображается.

Просмотреть файл

@ -1,287 +0,0 @@
using NUnit.Framework;
using Scalar.Common.Git;
using Scalar.Tests;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.Git;
using System.Linq;
namespace Scalar.UnitTests.Git
{
[TestFixtureSource(typeof(DataSources), nameof(DataSources.AllBools))]
public class GitAuthenticationTests
{
private const string CertificatePath = "certificatePath";
private const string AzureDevOpsUseHttpPathString = "-c credential.\"https://dev.azure.com\".useHttpPath=true";
private readonly bool sslSettingsPresent;
public GitAuthenticationTests(bool sslSettingsPresent)
{
this.sslSettingsPresent = sslSettingsPresent;
}
[TestCase]
public void AuthShouldBackoffAfterFirstRetryFailure()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = this.GetGitProcess();
GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl", "fake path");
dut.TryInitializeAndRequireAuth(tracer, out _);
string authString;
string error;
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get initial credential");
dut.RejectCredentials(tracer, authString);
dut.IsBackingOff.ShouldEqual(false, "Should not backoff after credentials initially rejected");
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1);
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to retry getting credential on iteration");
dut.IsBackingOff.ShouldEqual(false, "Should not backoff after successfully getting credentials");
dut.RejectCredentials(tracer, authString);
dut.IsBackingOff.ShouldEqual(true, "Should continue to backoff after rejecting credentials");
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "TryGetCredential should not succeed during backoff");
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(2);
}
[TestCase]
public void BackoffIsNotInEffectAfterSuccess()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = this.GetGitProcess();
GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl", "fake path");
dut.TryInitializeAndRequireAuth(tracer, out _);
string authString;
string error;
for (int i = 0; i < 5; ++i)
{
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get credential on iteration " + i + ": " + error);
dut.RejectCredentials(tracer, authString);
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to retry getting credential on iteration " + i + ": " + error);
dut.ApproveCredentials(tracer, authString);
dut.IsBackingOff.ShouldEqual(false, "Should reset backoff after successfully refreshing credentials");
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(i + 1, $"Should have {i + 1} credentials rejection");
gitProcess.CredentialApprovals["mock://repoUrl"].Count.ShouldEqual(i + 1, $"Should have {i + 1} credential approvals");
}
}
[TestCase]
public void ContinuesToBackoffIfTryGetCredentialsFails()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = this.GetGitProcess();
GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl", "fake path");
dut.TryInitializeAndRequireAuth(tracer, out _);
string authString;
string error;
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "Failed to get initial credential");
dut.RejectCredentials(tracer, authString);
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1);
gitProcess.ShouldFail = true;
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "Succeeded despite GitProcess returning failure");
dut.IsBackingOff.ShouldEqual(true, "Should continue to backoff if failed to get credentials");
dut.RejectCredentials(tracer, authString);
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(false, "TryGetCredential should not succeed during backoff");
dut.IsBackingOff.ShouldEqual(true, "Should continue to backoff if failed to get credentials");
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1);
}
[TestCase]
public void TwoThreadsFailAtOnceStillRetriesOnce()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = this.GetGitProcess();
GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl", "fake path");
dut.TryInitializeAndRequireAuth(tracer, out _);
string authString;
string error;
// Populate an initial PAT on two threads
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true);
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true);
// Simulate a 401 error on two threads
dut.RejectCredentials(tracer, authString);
dut.RejectCredentials(tracer, authString);
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1);
gitProcess.CredentialRejections["mock://repoUrl"][0].BasicAuthString.ShouldEqual(authString);
// Both threads should still be able to get a PAT for retry purposes
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true, "The second thread caused back off when it shouldn't");
dut.TryGetCredentials(tracer, out authString, out error).ShouldEqual(true);
}
[TestCase]
public void TwoThreadsInterleavingFailuresStillRetriesOnce()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = this.GetGitProcess();
GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl", "fake path");
dut.TryInitializeAndRequireAuth(tracer, out _);
string thread1Auth;
string thread1AuthRetry;
string thread2Auth;
string thread2AuthRetry;
string error;
// Populate an initial PAT on two threads
dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true);
dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true);
// Simulate a 401 error on one threads
dut.RejectCredentials(tracer, thread1Auth);
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1);
gitProcess.CredentialRejections["mock://repoUrl"][0].BasicAuthString.ShouldEqual(thread1Auth);
// That thread then retries
dut.TryGetCredentials(tracer, out thread1AuthRetry, out error).ShouldEqual(true);
// The second thread fails with the old PAT
dut.RejectCredentials(tracer, thread2Auth);
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1, "Should not have rejected a second time");
gitProcess.CredentialRejections["mock://repoUrl"][0].BasicAuthString.ShouldEqual(thread1Auth, "Should only have rejected thread1's initial credential");
// The second thread should be able to get a PAT
dut.TryGetCredentials(tracer, out thread2AuthRetry, out error).ShouldEqual(true, error);
}
[TestCase]
public void TwoThreadsInterleavingFailuresShouldntStompASuccess()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = this.GetGitProcess();
GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl", "fake path");
dut.TryInitializeAndRequireAuth(tracer, out _);
string thread1Auth;
string thread2Auth;
string error;
// Populate an initial PAT on two threads
dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true);
dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true);
// Simulate a 401 error on one threads
dut.RejectCredentials(tracer, thread1Auth);
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1);
gitProcess.CredentialRejections["mock://repoUrl"][0].BasicAuthString.ShouldEqual(thread1Auth);
// That thread then retries and succeeds
dut.TryGetCredentials(tracer, out thread1Auth, out error).ShouldEqual(true);
dut.ApproveCredentials(tracer, thread1Auth);
gitProcess.CredentialApprovals["mock://repoUrl"].Count.ShouldEqual(1);
gitProcess.CredentialApprovals["mock://repoUrl"][0].BasicAuthString.ShouldEqual(thread1Auth);
// If the second thread fails with the old PAT, it shouldn't stomp the new PAT
dut.RejectCredentials(tracer, thread2Auth);
gitProcess.CredentialRejections["mock://repoUrl"].Count.ShouldEqual(1);
// The second thread should be able to get a PAT
dut.TryGetCredentials(tracer, out thread2Auth, out error).ShouldEqual(true);
thread2Auth.ShouldEqual(thread1Auth, "The second thread stomp the first threads good auth string");
}
[TestCase]
public void DontDoubleStoreExistingCredential()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = this.GetGitProcess();
GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl", "fake path");
dut.TryInitializeAndRequireAuth(tracer, out _);
string authString;
dut.TryGetCredentials(tracer, out authString, out _).ShouldBeTrue();
dut.ApproveCredentials(tracer, authString);
dut.ApproveCredentials(tracer, authString);
dut.ApproveCredentials(tracer, authString);
dut.ApproveCredentials(tracer, authString);
dut.ApproveCredentials(tracer, authString);
gitProcess.CredentialApprovals["mock://repoUrl"].Count.ShouldEqual(1);
gitProcess.CredentialRejections.Count.ShouldEqual(0);
gitProcess.StoredCredentials.Count.ShouldEqual(1);
gitProcess.StoredCredentials.Single().Key.ShouldEqual("mock://repoUrl");
}
[TestCase]
public void DontStoreDifferentCredentialFromCachedValue()
{
MockTracer tracer = new MockTracer();
MockGitProcess gitProcess = this.GetGitProcess();
GitAuthentication dut = new GitAuthentication(gitProcess, "mock://repoUrl", "fake path");
dut.TryInitializeAndRequireAuth(tracer, out _);
// Get and store an initial value that will be cached
string authString;
dut.TryGetCredentials(tracer, out authString, out _).ShouldBeTrue();
dut.ApproveCredentials(tracer, authString);
// Try and store a different value from the one that is cached
dut.ApproveCredentials(tracer, "different value");
gitProcess.CredentialApprovals["mock://repoUrl"].Count.ShouldEqual(1);
gitProcess.CredentialRejections.Count.ShouldEqual(0);
gitProcess.StoredCredentials.Count.ShouldEqual(1);
gitProcess.StoredCredentials.Single().Key.ShouldEqual("mock://repoUrl");
}
private MockGitProcess GetGitProcess()
{
MockGitProcess gitProcess = new MockGitProcess();
gitProcess.SetExpectedCommandResult("config scalar.FunctionalTests.UserName", () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.GenericFailureCode));
gitProcess.SetExpectedCommandResult("config scalar.FunctionalTests.Password", () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.GenericFailureCode));
if (this.sslSettingsPresent)
{
gitProcess.SetExpectedCommandResult("config --get-urlmatch http mock://repoUrl", () => new GitProcess.Result($"http.sslCert {CertificatePath}\nhttp.sslCertPasswordProtected true\n\n", string.Empty, GitProcess.Result.SuccessCode));
}
else
{
gitProcess.SetExpectedCommandResult("config --get-urlmatch http mock://repoUrl", () => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
}
int approvals = 0;
int rejections = 0;
gitProcess.SetExpectedCommandResult(
$"{AzureDevOpsUseHttpPathString} credential fill",
() => new GitProcess.Result("username=username\r\npassword=password" + rejections + "\r\n", string.Empty, GitProcess.Result.SuccessCode));
gitProcess.SetExpectedCommandResult(
$"{AzureDevOpsUseHttpPathString} credential approve",
() =>
{
approvals++;
return new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode);
});
gitProcess.SetExpectedCommandResult(
$"{AzureDevOpsUseHttpPathString} credential reject",
() =>
{
rejections++;
return new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode);
});
return gitProcess;
}
}
}

Просмотреть файл

@ -1,257 +0,0 @@
using NUnit.Framework;
using Scalar.Common.Git;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
namespace Scalar.UnitTests.Git
{
[TestFixture]
public class GitProcessTests
{
[TestCase]
public void TryKillRunningProcess_NeverRan()
{
GitProcess process = new GitProcess(new MockScalarEnlistment());
process.TryKillRunningProcess(out string processName, out int exitCode, out string error).ShouldBeTrue();
processName.ShouldBeNull();
exitCode.ShouldEqual(-1);
error.ShouldBeNull();
}
[TestCase]
public void ResultHasNoErrors()
{
GitProcess.Result result = new GitProcess.Result(
string.Empty,
string.Empty,
0);
result.ExitCodeIsFailure.ShouldBeFalse();
result.StderrContainsErrors().ShouldBeFalse();
}
[TestCase]
public void ResultHasWarnings()
{
GitProcess.Result result = new GitProcess.Result(
string.Empty,
"Warning: this is fine.\n",
0);
result.ExitCodeIsFailure.ShouldBeFalse();
result.StderrContainsErrors().ShouldBeFalse();
}
[TestCase]
public void ResultHasNonWarningErrors_SingleLine_AllWarnings()
{
GitProcess.Result result = new GitProcess.Result(
string.Empty,
"warning: this line should not be considered an error",
1);
result.ExitCodeIsFailure.ShouldBeTrue();
result.StderrContainsErrors().ShouldBeFalse();
}
[TestCase]
public void ResultHasNonWarningErrors_Multiline_AllWarnings()
{
GitProcess.Result result = new GitProcess.Result(
string.Empty,
@"warning: this line should not be considered an error
WARNING: neither should this.",
1);
result.ExitCodeIsFailure.ShouldBeTrue();
result.StderrContainsErrors().ShouldBeFalse();
}
[TestCase]
public void ResultHasNonWarningErrors_Multiline_EmptyLines()
{
GitProcess.Result result = new GitProcess.Result(
string.Empty,
@"
warning: this is fine
warning: this is too
",
1);
result.ExitCodeIsFailure.ShouldBeTrue();
result.StderrContainsErrors().ShouldBeFalse();
}
[TestCase]
public void ResultHasNonWarningErrors_Singleline_AllErrors()
{
GitProcess.Result result = new GitProcess.Result(
string.Empty,
"this is an error",
1);
result.ExitCodeIsFailure.ShouldBeTrue();
result.StderrContainsErrors().ShouldBeTrue();
}
[TestCase]
public void ResultHasNonWarningErrors_Multiline_AllErrors()
{
GitProcess.Result result = new GitProcess.Result(
string.Empty,
@"error1
error2",
1);
result.ExitCodeIsFailure.ShouldBeTrue();
result.StderrContainsErrors().ShouldBeTrue();
}
[TestCase]
public void ResultHasNonWarningErrors_Multiline_ErrorsAndWarnings()
{
GitProcess.Result result = new GitProcess.Result(
string.Empty,
@"WARNING: this is fine
this is an error",
1);
result.ExitCodeIsFailure.ShouldBeTrue();
result.StderrContainsErrors().ShouldBeTrue();
}
[TestCase]
public void ResultHasNonWarningErrors_TrailingWhitespace_Warning()
{
GitProcess.Result result = new GitProcess.Result(
string.Empty,
"Warning: this is fine\n",
1);
result.ExitCodeIsFailure.ShouldBeTrue();
result.StderrContainsErrors().ShouldBeFalse();
}
[TestCase]
public void ConfigResult_TryParseAsString_DefaultIsNull()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result(string.Empty, string.Empty, 1),
"settingName");
result.TryParseAsString(out string expectedValue, out string _).ShouldBeTrue();
expectedValue.ShouldBeNull();
}
[TestCase]
public void ConfigResult_TryParseAsString_FailsWhenErrors()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result(string.Empty, "errors", 1),
"settingName");
result.TryParseAsString(out string expectedValue, out string _).ShouldBeFalse();
}
[TestCase]
public void ConfigResult_TryParseAsString_NullWhenUnsetAndWarnings()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result(string.Empty, "warning: ignored", 1),
"settingName");
result.TryParseAsString(out string expectedValue, out string _).ShouldBeTrue();
expectedValue.ShouldBeNull();
}
[TestCase]
public void ConfigResult_TryParseAsString_PassesThroughErrors()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result(string.Empty, "--local can only be used inside a git repository", 1),
"settingName");
result.TryParseAsString(out string expectedValue, out string error).ShouldBeFalse();
error.Contains("--local").ShouldBeTrue();
}
[TestCase]
public void ConfigResult_TryParseAsString_RespectsDefaultOnFailure()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result(string.Empty, string.Empty, 1),
"settingName");
result.TryParseAsString(out string expectedValue, out string _, "default").ShouldBeTrue();
expectedValue.ShouldEqual("default");
}
[TestCase]
public void ConfigResult_TryParseAsString_OverridesDefaultOnSuccess()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result("expected", string.Empty, 0),
"settingName");
result.TryParseAsString(out string expectedValue, out string _, "default").ShouldBeTrue();
expectedValue.ShouldEqual("expected");
}
[TestCase]
public void ConfigResult_TryParseAsInt_FailsWithErrors()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result(string.Empty, "errors", 1),
"settingName");
result.TryParseAsInt(0, -1, out int value, out string error).ShouldBeFalse();
}
[TestCase]
public void ConfigResult_TryParseAsInt_DefaultWhenUnset()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result(string.Empty, string.Empty, 1),
"settingName");
result.TryParseAsInt(1, -1, out int value, out string error).ShouldBeTrue();
value.ShouldEqual(1);
}
[TestCase]
public void ConfigResult_TryParseAsInt_ParsesWhenNoError()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result("32", string.Empty, 0),
"settingName");
result.TryParseAsInt(1, -1, out int value, out string error).ShouldBeTrue();
value.ShouldEqual(32);
}
[TestCase]
public void ConfigResult_TryParseAsInt_ParsesWhenWarnings()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result("32", "warning: ignored", 0),
"settingName");
result.TryParseAsInt(1, -1, out int value, out string error).ShouldBeTrue();
value.ShouldEqual(32);
}
[TestCase]
public void ConfigResult_TryParseAsInt_ParsesWhenOutputIncludesWhitespace()
{
GitProcess.ConfigResult result = new GitProcess.ConfigResult(
new GitProcess.Result("\n\t 32\t\r\n", "warning: ignored", 0),
"settingName");
result.TryParseAsInt(1, -1, out int value, out string error).ShouldBeTrue();
value.ShouldEqual(32);
}
}
}

Просмотреть файл

@ -1,88 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Git;
using Scalar.Common.Maintenance;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using Scalar.UnitTests.Mock.Git;
using System.Collections.Generic;
namespace Scalar.UnitTests.Maintenance
{
[TestFixture]
public class CommitGraphStepTests
{
private MockTracer tracer;
private MockGitProcess gitProcess;
private ScalarContext context;
private string CommitGraphWriteCommand => $"commit-graph write --reachable --split --size-multiple=4 --expire-time={GitProcess.ExpireTimeDateString} --object-dir \"{this.context.Enlistment.GitObjectsRoot}\"";
private string CommitGraphVerifyCommand => $"commit-graph verify --shallow --object-dir \"{this.context.Enlistment.GitObjectsRoot}\"";
[TestCase]
public void WriteGraphWithPacks()
{
this.TestSetup();
this.gitProcess.SetExpectedCommandResult(
this.CommitGraphWriteCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
this.gitProcess.SetExpectedCommandResult(
this.CommitGraphVerifyCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
CommitGraphStep step = new CommitGraphStep(this.context, requireObjectCacheLock: false);
step.Execute();
this.tracer.RelatedInfoEvents.Count.ShouldEqual(0);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(2);
commands[0].ShouldEqual(this.CommitGraphWriteCommand);
commands[1].ShouldEqual(this.CommitGraphVerifyCommand);
}
[TestCase]
public void RewriteCommitGraphOnBadVerify()
{
this.TestSetup();
this.gitProcess.SetExpectedCommandResult(
this.CommitGraphWriteCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
this.gitProcess.SetExpectedCommandResult(
this.CommitGraphVerifyCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.GenericFailureCode));
CommitGraphStep step = new CommitGraphStep(this.context, requireObjectCacheLock: false);
step.Execute();
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(1);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(3);
commands[0].ShouldEqual(this.CommitGraphWriteCommand);
commands[1].ShouldEqual(this.CommitGraphVerifyCommand);
commands[2].ShouldEqual(this.CommitGraphWriteCommand);
}
private void TestSetup()
{
this.gitProcess = new MockGitProcess();
// Create enlistment using git process
ScalarEnlistment enlistment = new MockScalarEnlistment(this.gitProcess);
PhysicalFileSystem fileSystem = new MockFileSystem(new MockDirectory(enlistment.EnlistmentRoot, null, null));
// Create and return Context
this.tracer = new MockTracer();
this.context = new ScalarContext(this.tracer, fileSystem, enlistment: enlistment);
}
}
}

Просмотреть файл

@ -1,130 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Maintenance;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using Scalar.UnitTests.Category;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
namespace Scalar.UnitTests.Maintenance
{
[TestFixture]
public class GitMaintenanceStepTests
{
private ScalarContext context;
public enum WhenToStop
{
Never,
BeforeGitCommand,
DuringGitCommand
}
[TestCase]
public void GitMaintenanceStepRunsGitAction()
{
this.TestSetup();
CheckMethodStep step = new CheckMethodStep(this.context, WhenToStop.Never);
step.Execute();
step.SawWorkInvoked.ShouldBeTrue();
step.SawEndOfMethod.ShouldBeTrue();
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void GitMaintenanceStepSkipsGitActionAfterStop()
{
this.TestSetup();
CheckMethodStep step = new CheckMethodStep(this.context, WhenToStop.Never);
step.Stop();
step.Execute();
step.SawWorkInvoked.ShouldBeFalse();
step.SawEndOfMethod.ShouldBeFalse();
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void GitMaintenanceStepSkipsRunGitCommandAfterStop()
{
this.TestSetup();
CheckMethodStep step = new CheckMethodStep(this.context, WhenToStop.BeforeGitCommand);
step.Execute();
step.SawWorkInvoked.ShouldBeFalse();
step.SawEndOfMethod.ShouldBeFalse();
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void GitMaintenanceStepThrowsIfStoppedDuringGitCommand()
{
this.TestSetup();
CheckMethodStep step = new CheckMethodStep(this.context, WhenToStop.DuringGitCommand);
step.Execute();
step.SawWorkInvoked.ShouldBeTrue();
step.SawEndOfMethod.ShouldBeFalse();
}
private void TestSetup()
{
ITracer tracer = new MockTracer();
ScalarEnlistment enlistment = new MockScalarEnlistment();
PhysicalFileSystem fileSystem = new MockFileSystem(new MockDirectory(enlistment.EnlistmentRoot, null, null));
this.context = new ScalarContext(tracer, fileSystem, enlistment);
}
public class CheckMethodStep : GitMaintenanceStep
{
private WhenToStop when;
public CheckMethodStep(ScalarContext context, WhenToStop when)
: base(context, requireObjectCacheLock: true)
{
this.when = when;
}
public bool SawWorkInvoked { get; set; }
public bool SawEndOfMethod { get; set; }
public override string Area => "CheckMethodStep";
public override string ProgressMessage => throw new System.NotImplementedException();
protected override void PerformMaintenance()
{
if (this.when == WhenToStop.BeforeGitCommand)
{
this.Stop();
}
this.RunGitCommand(
process =>
{
this.SawWorkInvoked = true;
if (this.when == WhenToStop.DuringGitCommand)
{
this.Stop();
}
return null;
},
nameof(this.SawWorkInvoked));
this.SawEndOfMethod = true;
}
}
}
}

Просмотреть файл

@ -1,258 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Git;
using Scalar.Common.Maintenance;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using Scalar.UnitTests.Mock.Git;
using System;
using System.Collections.Generic;
using System.IO;
namespace Scalar.UnitTests.Maintenance
{
[TestFixture]
public class LooseObjectStepTests
{
private const string PrunePackedCommand = "prune-packed -q";
private string packCommand;
private MockTracer tracer;
private MockGitProcess gitProcess;
private ScalarContext context;
[TestCase]
public void LooseObjectsIgnoreTimeRestriction()
{
this.TestSetup(DateTime.UtcNow);
LooseObjectsStep step = new LooseObjectsStep(this.context, requireCacheLock: false, forceRun: true);
step.Execute();
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(0);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(2);
commands[0].ShouldEqual(PrunePackedCommand);
commands[1].ShouldEqual(this.packCommand);
}
[TestCase]
public void LooseObjectsFailTimeRestriction()
{
this.TestSetup(DateTime.UtcNow);
LooseObjectsStep step = new LooseObjectsStep(this.context, requireCacheLock: false, forceRun: false);
step.Execute();
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(1);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(0);
}
[TestCase]
public void LooseObjectsPassTimeRestriction()
{
this.TestSetup(DateTime.UtcNow.AddDays(-7));
Mock<GitProcessChecker> mockChecker = new Mock<GitProcessChecker>();
mockChecker.Setup(checker => checker.GetRunningGitProcessIds())
.Returns(Array.Empty<int>());
LooseObjectsStep step = new LooseObjectsStep(
this.context,
requireCacheLock: false,
forceRun: false,
gitProcessChecker: mockChecker.Object);
step.Execute();
mockChecker.Verify(checker => checker.GetRunningGitProcessIds(), Times.Once());
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(0);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(2);
commands[0].ShouldEqual(PrunePackedCommand);
commands[1].ShouldEqual(this.packCommand);
}
[TestCase]
public void LooseObjectsFailGitProcessIds()
{
this.TestSetup(DateTime.UtcNow.AddDays(-7));
Mock<GitProcessChecker> mockChecker = new Mock<GitProcessChecker>();
mockChecker.Setup(checker => checker.GetRunningGitProcessIds())
.Returns(new int[] { 1 });
LooseObjectsStep step = new LooseObjectsStep(
this.context,
requireCacheLock: false,
forceRun: false,
gitProcessChecker: mockChecker.Object);
step.Execute();
mockChecker.Verify(checker => checker.GetRunningGitProcessIds(), Times.Once());
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(1);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(0);
}
[TestCase]
public void LooseObjectsLimitPackCount()
{
this.TestSetup(DateTime.UtcNow.AddDays(-7));
// Verify with default limit
LooseObjectsStep step = new LooseObjectsStep(this.context, requireCacheLock: false, forceRun: false);
step.WriteLooseObjectIds(new StreamWriter(new MemoryStream())).ShouldEqual(3);
// Verify with limit of 2
step.MaxLooseObjectsInPack = 2;
step.WriteLooseObjectIds(new StreamWriter(new MemoryStream())).ShouldEqual(2);
}
[TestCase]
public void SkipInvalidLooseObjects()
{
this.TestSetup(DateTime.UtcNow.AddDays(-7));
// Verify with valid Objects
LooseObjectsStep step = new LooseObjectsStep(this.context, requireCacheLock: false, forceRun: false);
step.WriteLooseObjectIds(new StreamWriter(new MemoryStream())).ShouldEqual(3);
this.tracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.RelatedWarningEvents.Count.ShouldEqual(0);
// Write an ObjectId file with an invalid name
this.context.FileSystem.WriteAllText(Path.Combine(this.context.Enlistment.GitObjectsRoot, "AA", "NOT_A_SHA"), string.Empty);
// Verify it wasn't added and a warning exists
step.WriteLooseObjectIds(new StreamWriter(new MemoryStream())).ShouldEqual(3);
this.tracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.RelatedWarningEvents.Count.ShouldEqual(1);
}
[TestCase]
public void LooseObjectsCount()
{
this.TestSetup(DateTime.UtcNow.AddDays(-7));
LooseObjectsStep step = new LooseObjectsStep(this.context, requireCacheLock: false, forceRun: false);
step.CountLooseObjects(out int count, out long size);
count.ShouldEqual(3);
size.ShouldEqual("one".Length + "two".Length + "three".Length);
}
[TestCase]
public void LooseObjectId()
{
this.TestSetup(DateTime.UtcNow.AddDays(-7));
LooseObjectsStep step = new LooseObjectsStep(this.context, requireCacheLock: false, forceRun: false);
string directoryName = "AB";
string fileName = "830bb79cd4fadb2e73e780e452dc71db909001";
step.TryGetLooseObjectId(
directoryName,
Path.Combine(this.context.Enlistment.GitObjectsRoot, directoryName, fileName),
out string objectId).ShouldBeTrue();
objectId.ShouldEqual(directoryName + fileName);
directoryName = "AB";
fileName = "BAD_FILE_NAME";
step.TryGetLooseObjectId(
directoryName,
Path.Combine(this.context.Enlistment.GitObjectsRoot, directoryName, fileName),
out objectId).ShouldBeFalse();
}
[TestCase]
public void LooseObjectFileName()
{
this.TestSetup(DateTime.UtcNow);
LooseObjectsStep step = new LooseObjectsStep(this.context, requireCacheLock: false, forceRun: false);
step.GetLooseObjectFileName("0123456789012345678901234567890123456789")
.ShouldEqual(Path.Combine(this.context.Enlistment.GitObjectsRoot, "01", "23456789012345678901234567890123456789"));
}
private void TestSetup(DateTime lastRun)
{
string lastRunTime = EpochConverter.ToUnixEpochSeconds(lastRun).ToString();
// Create GitProcess
this.gitProcess = new MockGitProcess();
this.gitProcess.SetExpectedCommandResult(
PrunePackedCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
// Create enlistment using git process
ScalarEnlistment enlistment = new MockScalarEnlistment(this.gitProcess);
string packPrefix = Path.Combine(enlistment.GitPackRoot, "from-loose");
this.packCommand = $"pack-objects {packPrefix} --non-empty --window=0 --depth=0 -q";
this.gitProcess.SetExpectedCommandResult(
this.packCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
// Create a last run time file
MockFile timeFile = new MockFile(Path.Combine(enlistment.GitObjectsRoot, "info", LooseObjectsStep.LooseObjectsLastRunFileName), lastRunTime);
// Create info directory to hold last run time file
MockDirectory infoRoot = new MockDirectory(Path.Combine(enlistment.GitObjectsRoot, "info"), null, new List<MockFile>() { timeFile });
// Create Hex Folder 1 with 1 File
MockDirectory hex1 = new MockDirectory(
Path.Combine(enlistment.GitObjectsRoot, "AA"),
null,
new List<MockFile>()
{
new MockFile(Path.Combine(enlistment.GitObjectsRoot, "AA", "1156f4f2b850673090c285289ea8475d629fe1"), "one")
});
// Create Hex Folder 2 with 2 Files
MockDirectory hex2 = new MockDirectory(
Path.Combine(enlistment.GitObjectsRoot, "F1"),
null,
new List<MockFile>()
{
new MockFile(Path.Combine(enlistment.GitObjectsRoot, "F1", "1156f4f2b850673090c285289ea8475d629fe2"), "two"),
new MockFile(Path.Combine(enlistment.GitObjectsRoot, "F1", "1156f4f2b850673090c285289ea8475d629fe3"), "three")
});
// Create NonHex Folder with 4 Files
MockDirectory nonhex = new MockDirectory(
Path.Combine(enlistment.GitObjectsRoot, "ZZ"),
null,
new List<MockFile>()
{
new MockFile(Path.Combine(enlistment.GitObjectsRoot, "ZZ", "1156f4f2b850673090c285289ea8475d629fe4"), "4"),
new MockFile(Path.Combine(enlistment.GitObjectsRoot, "ZZ", "1156f4f2b850673090c285289ea8475d629fe5"), "5"),
new MockFile(Path.Combine(enlistment.GitObjectsRoot, "ZZ", "1156f4f2b850673090c285289ea8475d629fe6"), "6"),
new MockFile(Path.Combine(enlistment.GitObjectsRoot, "ZZ", "1156f4f2b850673090c285289ea8475d629fe7"), "7")
});
MockDirectory pack = new MockDirectory(
enlistment.GitPackRoot,
null,
new List<MockFile>());
// Create git objects directory
MockDirectory gitObjectsRoot = new MockDirectory(enlistment.GitObjectsRoot, new List<MockDirectory>() { infoRoot, hex1, hex2, nonhex, pack }, null);
// Add object directory to file System
List<MockDirectory> directories = new List<MockDirectory>() { gitObjectsRoot };
PhysicalFileSystem fileSystem = new MockFileSystem(new MockDirectory(enlistment.EnlistmentRoot, directories, null));
// Create and return Context
this.tracer = new MockTracer();
this.context = new ScalarContext(this.tracer, fileSystem, enlistment: enlistment);
}
}
}

Просмотреть файл

@ -1,244 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Git;
using Scalar.Common.Maintenance;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using Scalar.UnitTests.Mock.Git;
using System;
using System.Collections.Generic;
using System.IO;
namespace Scalar.UnitTests.Maintenance
{
[TestFixture]
public class PackfileMaintenanceStepTests
{
private const string StaleIdxName = "pack-stale.idx";
private const string KeepName = "pack-3.keep";
private MockTracer tracer;
private MockGitProcess gitProcess;
private ScalarContext context;
private string ExpireCommand => $"multi-pack-index expire --object-dir=\"{this.context.Enlistment.GitObjectsRoot}\"";
private string VerifyCommand => $"-c core.multiPackIndex=true multi-pack-index verify --object-dir=\"{this.context.Enlistment.GitObjectsRoot}\"";
private string WriteCommand => $"-c core.multiPackIndex=true multi-pack-index write --object-dir=\"{this.context.Enlistment.GitObjectsRoot}\"";
private string RepackCommand => $"-c pack.threads=1 -c repack.packKeptObjects=true multi-pack-index repack --object-dir=\"{this.context.Enlistment.GitObjectsRoot}\" --batch-size=3";
[TestCase]
public void PackfileMaintenanceIgnoreTimeRestriction()
{
this.TestSetup(DateTime.UtcNow);
PackfileMaintenanceStep step = new PackfileMaintenanceStep(this.context, requireObjectCacheLock: false, forceRun: true);
step.Execute();
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(0);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(5);
commands[0].ShouldEqual(this.WriteCommand);
commands[1].ShouldEqual(this.ExpireCommand);
commands[2].ShouldEqual(this.VerifyCommand);
commands[3].ShouldEqual(this.RepackCommand);
commands[4].ShouldEqual(this.VerifyCommand);
}
[TestCase]
public void PackfileMaintenanceFailTimeRestriction()
{
this.TestSetup(DateTime.UtcNow);
PackfileMaintenanceStep step = new PackfileMaintenanceStep(this.context, requireObjectCacheLock: false, forceRun: false);
step.Execute();
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(1);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(0);
}
[TestCase]
public void PackfileMaintenancePassTimeRestriction()
{
this.TestSetup(DateTime.UtcNow.AddDays(-1));
Mock<GitProcessChecker> mockChecker = new Mock<GitProcessChecker>();
mockChecker.Setup(checker => checker.GetRunningGitProcessIds())
.Returns(Array.Empty<int>());
PackfileMaintenanceStep step = new PackfileMaintenanceStep(
this.context,
requireObjectCacheLock: false,
forceRun: false,
gitProcessChecker: mockChecker.Object);
step.Execute();
mockChecker.Verify(checker => checker.GetRunningGitProcessIds(), Times.Once());
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(0);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(5);
commands[0].ShouldEqual(this.WriteCommand);
commands[1].ShouldEqual(this.ExpireCommand);
commands[2].ShouldEqual(this.VerifyCommand);
commands[3].ShouldEqual(this.RepackCommand);
commands[4].ShouldEqual(this.VerifyCommand);
}
[TestCase]
public void PackfileMaintenanceFailGitProcessIds()
{
this.TestSetup(DateTime.UtcNow.AddDays(-1));
Mock<GitProcessChecker> mockChecker = new Mock<GitProcessChecker>();
mockChecker.Setup(checker => checker.GetRunningGitProcessIds())
.Returns(new int[] { 1 });
PackfileMaintenanceStep step = new PackfileMaintenanceStep(
this.context,
requireObjectCacheLock: false,
forceRun: false,
gitProcessChecker: mockChecker.Object);
step.Execute();
mockChecker.Verify(checker => checker.GetRunningGitProcessIds(), Times.Once());
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(1);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(0);
}
[TestCase]
public void PackfileMaintenanceRewriteOnBadVerify()
{
this.TestSetup(DateTime.UtcNow, failOnVerify: true);
this.gitProcess.SetExpectedCommandResult(
this.WriteCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
PackfileMaintenanceStep step = new PackfileMaintenanceStep(this.context, requireObjectCacheLock: false, forceRun: true);
step.Execute();
this.tracer.StartActivityTracer.RelatedErrorEvents.Count.ShouldEqual(0);
this.tracer.StartActivityTracer.RelatedWarningEvents.Count.ShouldEqual(2);
List<string> commands = this.gitProcess.CommandsRun;
commands.Count.ShouldEqual(7);
commands[0].ShouldEqual(this.WriteCommand);
commands[1].ShouldEqual(this.ExpireCommand);
commands[2].ShouldEqual(this.VerifyCommand);
commands[3].ShouldEqual(this.WriteCommand);
commands[4].ShouldEqual(this.RepackCommand);
commands[5].ShouldEqual(this.VerifyCommand);
commands[6].ShouldEqual(this.WriteCommand);
}
[TestCase]
public void CountPackFiles()
{
this.TestSetup(DateTime.UtcNow);
PackfileMaintenanceStep step = new PackfileMaintenanceStep(this.context, requireObjectCacheLock: false, forceRun: true);
step.GetPackFilesInfo(out int count, out long size, out long secondSmallestSize, out bool hasKeep);
count.ShouldEqual(3);
size.ShouldEqual(11);
secondSmallestSize.ShouldEqual(3);
hasKeep.ShouldEqual(true);
this.context.FileSystem.DeleteFile(Path.Combine(this.context.Enlistment.GitPackRoot, KeepName));
step.GetPackFilesInfo(out count, out size, out secondSmallestSize, out hasKeep);
count.ShouldEqual(3);
size.ShouldEqual(11);
secondSmallestSize.ShouldEqual(3);
hasKeep.ShouldEqual(false);
}
[TestCase]
public void CleanStaleIdxFiles()
{
this.TestSetup(DateTime.UtcNow);
PackfileMaintenanceStep step = new PackfileMaintenanceStep(this.context, requireObjectCacheLock: false, forceRun: true);
List<string> staleIdx = step.CleanStaleIdxFiles(out int numDeletionBlocked);
staleIdx.Count.ShouldEqual(1);
staleIdx[0].ShouldEqual(StaleIdxName);
this.context
.FileSystem
.FileExists(Path.Combine(this.context.Enlistment.GitPackRoot, StaleIdxName))
.ShouldBeFalse();
}
private void TestSetup(DateTime lastRun, bool failOnVerify = false)
{
string lastRunTime = EpochConverter.ToUnixEpochSeconds(lastRun).ToString();
this.gitProcess = new MockGitProcess();
// Create enlistment using git process
ScalarEnlistment enlistment = new MockScalarEnlistment(this.gitProcess);
// Create a last run time file
MockFile timeFile = new MockFile(Path.Combine(enlistment.GitObjectsRoot, "info", PackfileMaintenanceStep.PackfileLastRunFileName), lastRunTime);
// Create info directory to hold last run time file
MockDirectory info = new MockDirectory(
Path.Combine(enlistment.GitObjectsRoot, "info"),
null,
new List<MockFile>() { timeFile });
// Create pack info
MockDirectory pack = new MockDirectory(
enlistment.GitPackRoot,
null,
new List<MockFile>()
{
new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-1.pack"), "one"),
new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-1.idx"), "1"),
new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-2.pack"), "two"),
new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-2.idx"), "2"),
new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-3.pack"), "three"),
new MockFile(Path.Combine(enlistment.GitPackRoot, "pack-3.idx"), "3"),
new MockFile(Path.Combine(enlistment.GitPackRoot, KeepName), string.Empty),
new MockFile(Path.Combine(enlistment.GitPackRoot, StaleIdxName), "4"),
});
// Create git objects directory
MockDirectory gitObjectsRoot = new MockDirectory(enlistment.GitObjectsRoot, new List<MockDirectory>() { info, pack }, null);
// Add object directory to file System
List<MockDirectory> directories = new List<MockDirectory>() { gitObjectsRoot };
PhysicalFileSystem fileSystem = new MockFileSystem(new MockDirectory(enlistment.EnlistmentRoot, directories, null));
// Create and return Context
this.tracer = new MockTracer();
this.context = new ScalarContext(this.tracer, fileSystem, enlistment);
this.gitProcess.SetExpectedCommandResult(
this.WriteCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
this.gitProcess.SetExpectedCommandResult(
this.ExpireCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
this.gitProcess.SetExpectedCommandResult(
this.VerifyCommand,
() => new GitProcess.Result(string.Empty, string.Empty, failOnVerify ? GitProcess.Result.GenericFailureCode : GitProcess.Result.SuccessCode));
this.gitProcess.SetExpectedCommandResult(
this.RepackCommand,
() => new GitProcess.Result(string.Empty, string.Empty, GitProcess.Result.SuccessCode));
}
}
}

Просмотреть файл

@ -1,26 +0,0 @@
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Tracing;
namespace Scalar.UnitTests.Mock.Common
{
public class MockFileBasedLock : FileBasedLock
{
public MockFileBasedLock(
PhysicalFileSystem fileSystem,
ITracer tracer,
string lockPath)
: base(fileSystem, tracer, lockPath)
{
}
public override bool TryAcquireLock()
{
return true;
}
public override void Dispose()
{
}
}
}

Просмотреть файл

@ -1,53 +0,0 @@
using Scalar.Common;
using System.Collections.Generic;
namespace Scalar.UnitTests.Mock.Common
{
public class MockLocalScalarConfig : LocalScalarConfig
{
public MockLocalScalarConfig()
{
this.Settings = new Dictionary<string, string>();
}
private Dictionary<string, string> Settings { get; set; }
public override bool TryGetAllConfig(out Dictionary<string, string> allConfig, out string error)
{
allConfig = new Dictionary<string, string>(this.Settings);
error = null;
return true;
}
public override bool TryGetConfig(
string name,
out string value,
out string error)
{
error = null;
this.Settings.TryGetValue(name, out value);
return true;
}
public override bool TrySetConfig(
string name,
string value,
out string error)
{
error = null;
this.Settings[name] = value;
return true;
}
public override bool TryRemoveConfig(string name, out string error)
{
error = null;
this.Settings.Remove(name);
return true;
}
}
}

Просмотреть файл

@ -1,91 +0,0 @@
using Scalar.Common;
using System.Collections.Generic;
namespace Scalar.UnitTests.Mock.Common
{
public class MockLocalScalarConfigBuilder
{
private string defaultRing;
private string defaultUpgradeFeedUrl;
private string defaultUpgradeFeedPackageName;
private string defaultOrgServerUrl;
private Dictionary<string, string> entries;
public MockLocalScalarConfigBuilder(
string defaultRing,
string defaultUpgradeFeedUrl,
string defaultUpgradeFeedPackageName,
string defaultOrgServerUrl)
{
this.defaultRing = defaultRing;
this.defaultUpgradeFeedUrl = defaultUpgradeFeedUrl;
this.defaultUpgradeFeedPackageName = defaultUpgradeFeedPackageName;
this.defaultOrgServerUrl = defaultOrgServerUrl;
this.entries = new Dictionary<string, string>();
}
public MockLocalScalarConfigBuilder WithUpgradeRing(string value = null)
{
return this.With(ScalarConstants.LocalScalarConfig.UpgradeRing, value ?? this.defaultRing);
}
public MockLocalScalarConfigBuilder WithNoUpgradeRing()
{
return this.WithNo(ScalarConstants.LocalScalarConfig.UpgradeRing);
}
public MockLocalScalarConfigBuilder WithUpgradeFeedPackageName(string value = null)
{
return this.With(ScalarConstants.LocalScalarConfig.UpgradeFeedPackageName, value ?? this.defaultUpgradeFeedPackageName);
}
public MockLocalScalarConfigBuilder WithNoUpgradeFeedPackageName()
{
return this.WithNo(ScalarConstants.LocalScalarConfig.UpgradeFeedPackageName);
}
public MockLocalScalarConfigBuilder WithUpgradeFeedUrl(string value = null)
{
return this.With(ScalarConstants.LocalScalarConfig.UpgradeFeedUrl, value ?? this.defaultUpgradeFeedUrl);
}
public MockLocalScalarConfigBuilder WithNoUpgradeFeedUrl()
{
return this.WithNo(ScalarConstants.LocalScalarConfig.UpgradeFeedUrl);
}
public MockLocalScalarConfigBuilder WithOrgInfoServerUrl(string value = null)
{
return this.With(ScalarConstants.LocalScalarConfig.OrgInfoServerUrl, value ?? this.defaultUpgradeFeedUrl);
}
public MockLocalScalarConfigBuilder WithNoOrgInfoServerUrl()
{
return this.WithNo(ScalarConstants.LocalScalarConfig.OrgInfoServerUrl);
}
public MockLocalScalarConfig Build()
{
MockLocalScalarConfig scalarConfig = new MockLocalScalarConfig();
foreach (KeyValuePair<string, string> kvp in this.entries)
{
scalarConfig.TrySetConfig(kvp.Key, kvp.Value, out _);
}
return scalarConfig;
}
private MockLocalScalarConfigBuilder With(string key, string value)
{
this.entries.Add(key, value);
return this;
}
private MockLocalScalarConfigBuilder WithNo(string key)
{
this.entries.Remove(key);
return this;
}
}
}

Просмотреть файл

@ -1,199 +0,0 @@
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Git;
using Scalar.Common.Tracing;
using Scalar.UnitTests.Mock.FileSystem;
using Scalar.UnitTests.Mock.Git;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Runtime.InteropServices;
namespace Scalar.UnitTests.Mock.Common
{
public class MockPlatform : ScalarPlatform
{
public MockPlatform() : base(underConstruction: new UnderConstructionFlags())
{
}
public string MockCurrentUser { get; set; }
public override IGitInstallation GitInstallation { get; } = new MockGitInstallation();
public override IPlatformFileSystem FileSystem { get; } = new MockPlatformFileSystem();
public override string Name { get => "Mock"; }
public override string ScalarConfigPath { get => Path.Combine("mock:", LocalScalarConfig.FileName); }
public override ScalarPlatformConstants Constants { get; } = new MockPlatformConstants();
public override void ConfigureVisualStudio(string gitBinPath, ITracer tracer)
{
throw new NotSupportedException();
}
public override bool TryVerifyAuthenticodeSignature(string path, out string subject, out string issuer, out string error)
{
throw new NotImplementedException();
}
public override string GetScalarServiceNamedPipeName(string serviceName)
{
return Path.Combine("Scalar_Mock_ServicePipeName", serviceName);
}
public override NamedPipeServerStream CreatePipeByName(string pipeName)
{
throw new NotSupportedException();
}
public override string GetCurrentUser()
{
return this.MockCurrentUser;
}
public override string GetUserIdFromLoginSessionId(int sessionId, ITracer tracer)
{
return sessionId.ToString();
}
public override string GetOSVersionInformation()
{
throw new NotSupportedException();
}
public override string GetCommonAppDataRootForScalar()
{
// TODO: Update this method to return non existant file path.
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
"Scalar");
}
public override string GetSecureDataRootForScalar()
{
return this.GetCommonAppDataRootForScalar();
}
public override Dictionary<string, string> GetPhysicalDiskInfo(string path, bool sizeStatsOnly)
{
return new Dictionary<string, string>();
}
public override string GetUpgradeProtectedDataDirectory()
{
return this.GetCommonAppDataRootForScalarComponent(ProductUpgraderInfo.UpgradeDirectoryName);
}
public override string GetUpgradeLogDirectoryParentDirectory()
{
return this.GetUpgradeProtectedDataDirectory();
}
public override string GetUpgradeHighestAvailableVersionDirectory()
{
return this.GetUpgradeProtectedDataDirectory();
}
public override void InitializeEnlistmentACLs(string enlistmentPath)
{
throw new NotSupportedException();
}
public override bool IsElevated()
{
throw new NotSupportedException();
}
public override void IsServiceInstalledAndRunning(string name, out bool installed, out bool running)
{
throw new NotSupportedException();
}
public override bool TryGetDefaultLocalCacheRoot(string enlistmentRoot, out string localCacheRoot, out string localCacheRootError)
{
throw new NotImplementedException();
}
public override void StartBackgroundScalarProcess(ITracer tracer, string programName, string[] args)
{
throw new NotSupportedException();
}
public override void PrepareProcessToRunInBackground()
{
throw new NotSupportedException();
}
public override FileBasedLock CreateFileBasedLock(PhysicalFileSystem fileSystem, ITracer tracer, string lockPath)
{
return new MockFileBasedLock(fileSystem, tracer, lockPath);
}
public override ProductUpgraderPlatformStrategy CreateProductUpgraderPlatformInteractions(
PhysicalFileSystem fileSystem,
ITracer tracer)
{
return new MockProductUpgraderPlatformStrategy(fileSystem, tracer);
}
public override bool TryKillProcessTree(int processId, out int exitCode, out string error)
{
error = null;
exitCode = 0;
return true;
}
public override string GetTemplateHooksDirectory()
{
throw new NotSupportedException();
}
public class MockPlatformConstants : ScalarPlatformConstants
{
public override string ExecutableExtension
{
get { return ".mockexe"; }
}
public override string InstallerExtension
{
get { return ".mockexe"; }
}
public override string ScalarBinDirectoryPath
{
get { return Path.Combine("MockProgramFiles", this.ScalarBinDirectoryName); }
}
public override string ScalarBinDirectoryName
{
get { return "MockScalar"; }
}
public override string ScalarExecutableName
{
get { return "MockScalar" + this.ExecutableExtension; }
}
public override string ProgramLocaterCommand
{
get { return "MockWhere"; }
}
public override HashSet<string> UpgradeBlockingProcesses
{
get { return new HashSet<string>(this.PathComparer) { "Scalar", "git", "wish", "bash" }; }
}
public override bool SupportsUpgradeWhileRunning => false;
public override int MaxPipePathLength => 250;
public override bool CaseSensitiveFileSystem => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
}
}
}

Просмотреть файл

@ -1,32 +0,0 @@
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Tracing;
namespace Scalar.UnitTests.Mock.Common
{
public class MockProductUpgraderPlatformStrategy : ProductUpgraderPlatformStrategy
{
public MockProductUpgraderPlatformStrategy(PhysicalFileSystem fileSystem, ITracer tracer)
: base(fileSystem, tracer)
{
}
public override bool TryPrepareLogDirectory(out string error)
{
error = null;
return true;
}
public override bool TryPrepareApplicationDirectory(out string error)
{
error = null;
return true;
}
public override bool TryPrepareDownloadDirectory(out string error)
{
error = null;
return true;
}
}
}

Просмотреть файл

@ -1,43 +0,0 @@
using Scalar.Common;
using Scalar.Common.Git;
using Scalar.UnitTests.Mock.Git;
using System.IO;
namespace Scalar.UnitTests.Mock.Common
{
public class MockScalarEnlistment : ScalarEnlistment
{
private MockGitProcess gitProcess;
public MockScalarEnlistment()
: base(Path.Combine("mock:", "path"), Path.Combine("mock:", "path"), "mock://repoUrl", Path.Combine("mock:", "git"), authentication: null)
{
this.GitObjectsRoot = Path.Combine("mock:", "path", ".git", "objects");
this.LocalObjectsRoot = this.GitObjectsRoot;
this.GitPackRoot = Path.Combine("mock:", "path", ".git", "objects", "pack");
}
public MockScalarEnlistment(string enlistmentRoot, string repoUrl, string gitBinPath, MockGitProcess gitProcess)
: base(enlistmentRoot, enlistmentRoot, repoUrl, gitBinPath, authentication: null)
{
this.gitProcess = gitProcess;
}
public MockScalarEnlistment(MockGitProcess gitProcess)
: this()
{
this.gitProcess = gitProcess;
}
public override string GitObjectsRoot { get; protected set; }
public override string LocalObjectsRoot { get; protected set; }
public override string GitPackRoot { get; protected set; }
public override GitProcess CreateGitProcess()
{
return this.gitProcess ?? new MockGitProcess();
}
}
}

Просмотреть файл

@ -1,158 +0,0 @@
using Newtonsoft.Json;
using Scalar.Common.Tracing;
using System;
using System.Collections.Generic;
using System.Threading;
namespace Scalar.UnitTests.Mock.Common
{
public class MockTracer : ITracer
{
private AutoResetEvent waitEvent;
public MockTracer()
{
this.waitEvent = new AutoResetEvent(false);
this.RelatedEvents = new List<string>();
this.RelatedInfoEvents = new List<string>();
this.RelatedWarningEvents = new List<string>();
this.RelatedErrorEvents = new List<string>();
}
public MockTracer StartActivityTracer { get; private set; }
public string WaitRelatedEventName { get; set; }
public List<string> RelatedEvents { get; }
public List<string> RelatedInfoEvents { get; }
public List<string> RelatedWarningEvents { get; }
public List<string> RelatedErrorEvents { get; }
public void WaitForRelatedEvent()
{
this.waitEvent.WaitOne();
}
public void RelatedEvent(EventLevel error, string eventName, EventMetadata metadata)
{
this.RelatedEvent(error, eventName, metadata, Keywords.None);
}
public void RelatedEvent(EventLevel error, string eventName, EventMetadata metadata, Keywords keyword)
{
if (eventName == this.WaitRelatedEventName)
{
this.waitEvent.Set();
}
this.RelatedEvents.Add($"EventName:'{eventName}', metadata: {JsonConvert.SerializeObject(metadata)}");
}
public void RelatedInfo(string message)
{
this.RelatedInfoEvents.Add(message);
}
public void RelatedInfo(EventMetadata metadata, string message)
{
metadata[TracingConstants.MessageKey.InfoMessage] = message;
this.RelatedInfoEvents.Add(JsonConvert.SerializeObject(metadata));
}
public void RelatedInfo(string format, params object[] args)
{
this.RelatedInfo(string.Format(format, args));
}
public void RelatedWarning(EventMetadata metadata, string message)
{
if (metadata != null)
{
metadata[TracingConstants.MessageKey.WarningMessage] = message;
this.RelatedWarningEvents.Add(JsonConvert.SerializeObject(metadata));
}
else if (message != null)
{
this.RelatedWarning(message);
}
}
public void RelatedWarning(EventMetadata metadata, string message, Keywords keyword)
{
this.RelatedWarning(metadata, message);
}
public void RelatedWarning(string message)
{
this.RelatedWarningEvents.Add(message);
}
public void RelatedWarning(string format, params object[] args)
{
this.RelatedWarningEvents.Add(string.Format(format, args));
}
public void RelatedError(EventMetadata metadata, string message)
{
metadata[TracingConstants.MessageKey.ErrorMessage] = message;
this.RelatedErrorEvents.Add(JsonConvert.SerializeObject(metadata));
}
public void RelatedError(EventMetadata metadata, string message, Keywords keyword)
{
this.RelatedError(metadata, message);
}
public void RelatedError(string message)
{
this.RelatedErrorEvents.Add(message);
}
public void RelatedError(string format, params object[] args)
{
this.RelatedErrorEvents.Add(string.Format(format, args));
}
public ITracer StartActivity(string activityName, EventLevel level)
{
return this.StartActivity(activityName, level, metadata: null);
}
public ITracer StartActivity(string activityName, EventLevel level, EventMetadata metadata)
{
return this.StartActivity(activityName, level, Keywords.None, metadata);
}
public ITracer StartActivity(string activityName, EventLevel level, Keywords startStopKeywords, EventMetadata metadata)
{
this.StartActivityTracer = this.StartActivityTracer ?? new MockTracer();
return this.StartActivityTracer;
}
public TimeSpan Stop(EventMetadata metadata)
{
return TimeSpan.Zero;
}
public void SetGitCommandSessionId(string sessionId)
{
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
if (disposing)
{
if (this.waitEvent != null)
{
this.waitEvent.Dispose();
this.waitEvent = null;
}
}
}
}
}

Просмотреть файл

@ -1,20 +0,0 @@
using Scalar.Common.Tracing;
using System.Collections.Generic;
namespace Scalar.UnitTests.Mock.Common.Tracing
{
public class MockListener : EventListener
{
public MockListener(EventLevel maxVerbosity, Keywords keywordFilter)
: base(maxVerbosity, keywordFilter, null)
{
}
public List<string> EventNamesRead { get; set; } = new List<string>();
protected override void RecordMessageInternal(TraceEventMessage message)
{
this.EventNamesRead.Add(message.EventName);
}
}
}

Просмотреть файл

@ -1,50 +0,0 @@
using Scalar.Common.FileSystem;
using Scalar.Tests.Should;
using System.Collections.Generic;
using System.IO;
namespace Scalar.UnitTests.Mock.FileSystem
{
public class ConfigurableFileSystem : PhysicalFileSystem
{
public ConfigurableFileSystem()
{
this.ExpectedFiles = new Dictionary<string, ReusableMemoryStream>();
this.ExpectedDirectories = new HashSet<string>();
}
public Dictionary<string, ReusableMemoryStream> ExpectedFiles { get; }
public HashSet<string> ExpectedDirectories { get; }
public override void CreateDirectory(string path)
{
}
public override void MoveAndOverwriteFile(string sourceFileName, string destinationFilename)
{
ReusableMemoryStream source;
this.ExpectedFiles.TryGetValue(sourceFileName, out source).ShouldEqual(true, "Source file does not exist: " + sourceFileName);
this.ExpectedFiles.ContainsKey(destinationFilename).ShouldEqual(true, "MoveAndOverwriteFile expects the destination file to exist: " + destinationFilename);
this.ExpectedFiles.Remove(sourceFileName);
this.ExpectedFiles[destinationFilename] = source;
}
public override Stream OpenFileStream(string path, FileMode fileMode, FileAccess fileAccess, FileShare shareMode, FileOptions options, bool flushesToDisk)
{
ReusableMemoryStream stream;
this.ExpectedFiles.TryGetValue(path, out stream).ShouldEqual(true, "Unexpected access of file: " + path);
return stream;
}
public override bool FileExists(string path)
{
return this.ExpectedFiles.ContainsKey(path);
}
public override bool DirectoryExists(string path)
{
return this.ExpectedDirectories.Contains(path);
}
}
}

Просмотреть файл

@ -1,302 +0,0 @@
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Tests.Should;
using System;
using System.Collections.Generic;
using System.IO;
namespace Scalar.UnitTests.Mock.FileSystem
{
public class MockDirectory
{
public MockDirectory(string fullName, IEnumerable<MockDirectory> folders, IEnumerable<MockFile> files)
{
this.FullName = fullName;
this.Name = Path.GetFileName(this.FullName);
this.Directories = new Dictionary<string, MockDirectory>(StringComparer.InvariantCultureIgnoreCase);
this.Files = new Dictionary<string, MockFile>(StringComparer.InvariantCultureIgnoreCase);
if (folders != null)
{
foreach (MockDirectory folder in folders)
{
this.Directories[folder.FullName] = folder;
}
}
if (files != null)
{
foreach (MockFile file in files)
{
this.Files[file.FullName] = file;
}
}
this.FileProperties = FileProperties.DefaultDirectory;
}
public string FullName { get; private set; }
public string Name { get; private set; }
public Dictionary<string, MockDirectory> Directories { get; private set; }
public Dictionary<string, MockFile> Files { get; private set; }
public FileProperties FileProperties { get; set; }
public MockFile FindFile(string path)
{
MockFile file;
if (this.Files.TryGetValue(path, out file))
{
return file;
}
foreach (MockDirectory directory in this.Directories.Values)
{
file = directory.FindFile(path);
if (file != null)
{
return file;
}
}
return null;
}
public void AddOrOverwriteFile(MockFile file, string path)
{
string parentPath = path.Substring(0, path.LastIndexOf(Path.DirectorySeparatorChar));
MockDirectory parentDirectory = this.FindDirectory(parentPath);
if (parentDirectory == null)
{
throw new IOException();
}
MockFile existingFileAtPath = parentDirectory.FindFile(path);
if (existingFileAtPath != null)
{
parentDirectory.Files.Remove(path);
}
parentDirectory.Files.Add(file.FullName, file);
}
public void AddFile(MockFile file, string path)
{
string parentPath = path.Substring(0, path.LastIndexOf(Path.DirectorySeparatorChar));
MockDirectory parentDirectory = this.FindDirectory(parentPath);
if (parentDirectory == null)
{
throw new IOException();
}
MockFile existingFileAtPath = parentDirectory.FindFile(path);
existingFileAtPath.ShouldBeNull();
parentDirectory.Files.Add(file.FullName, file);
}
public void RemoveFile(string path)
{
MockFile file;
if (this.Files.TryGetValue(path, out file))
{
this.Files.Remove(path);
return;
}
foreach (MockDirectory directory in this.Directories.Values)
{
file = directory.FindFile(path);
if (file != null)
{
directory.RemoveFile(path);
return;
}
}
}
public MockDirectory FindDirectory(string path)
{
if (path.Equals(this.FullName, StringComparison.InvariantCultureIgnoreCase))
{
return this;
}
MockDirectory foundDirectory;
if (this.Directories.TryGetValue(path, out foundDirectory))
{
return foundDirectory;
}
foreach (MockDirectory subDirectory in this.Directories.Values)
{
foundDirectory = subDirectory.FindDirectory(path);
if (foundDirectory != null)
{
return foundDirectory;
}
}
return null;
}
public MockFile CreateFile(string path)
{
return this.CreateFile(path, string.Empty);
}
public MockFile CreateFile(string path, string contents, bool createDirectories = false)
{
string parentPath = path.Substring(0, path.LastIndexOf(Path.DirectorySeparatorChar));
MockDirectory parentDirectory = this.FindDirectory(parentPath);
if (createDirectories)
{
if (parentDirectory == null)
{
parentDirectory = this.CreateDirectory(parentPath);
}
}
else
{
parentDirectory.ShouldNotBeNull();
}
MockFile newFile = new MockFile(path, contents);
parentDirectory.Files.Add(newFile.FullName, newFile);
return newFile;
}
public MockDirectory CreateDirectory(string path)
{
int lastSlashIdx = path.LastIndexOf(Path.DirectorySeparatorChar);
if (lastSlashIdx <= 0)
{
return this;
}
string parentPath = path.Substring(0, lastSlashIdx);
MockDirectory parentDirectory = this.FindDirectory(parentPath);
if (parentDirectory == null)
{
parentDirectory = this.CreateDirectory(parentPath);
}
MockDirectory newDirectory;
if (!parentDirectory.Directories.TryGetValue(path, out newDirectory))
{
newDirectory = new MockDirectory(path, null, null);
parentDirectory.Directories.Add(newDirectory.FullName, newDirectory);
}
return newDirectory;
}
public void DeleteDirectory(string path)
{
if (path.Equals(this.FullName, StringComparison.InvariantCultureIgnoreCase))
{
throw new NotSupportedException();
}
MockDirectory foundDirectory;
if (this.Directories.TryGetValue(path, out foundDirectory))
{
this.Directories.Remove(path);
}
else
{
foreach (MockDirectory subDirectory in this.Directories.Values)
{
foundDirectory = subDirectory.FindDirectory(path);
if (foundDirectory != null)
{
subDirectory.DeleteDirectory(path);
return;
}
}
}
}
public void MoveDirectory(string sourcePath, string targetPath)
{
MockDirectory sourceDirectory;
MockDirectory sourceDirectoryParent;
this.TryGetDirectoryAndParent(sourcePath, out sourceDirectory, out sourceDirectoryParent).ShouldEqual(true);
int endPathIndex = targetPath.LastIndexOf(Path.DirectorySeparatorChar);
string targetDirectoryPath = targetPath.Substring(0, endPathIndex);
MockDirectory targetDirectory = this.FindDirectory(targetDirectoryPath);
targetDirectory.ShouldNotBeNull();
sourceDirectoryParent.RemoveDirectory(sourceDirectory);
sourceDirectory.FullName = targetPath;
targetDirectory.AddDirectory(sourceDirectory);
}
public void RemoveDirectory(MockDirectory directory)
{
this.Directories.ContainsKey(directory.FullName).ShouldEqual(true);
this.Directories.Remove(directory.FullName);
}
private void AddDirectory(MockDirectory directory)
{
if (this.Directories.ContainsKey(directory.FullName))
{
MockDirectory oldDirectory = this.Directories[directory.FullName];
foreach (MockFile newFile in directory.Files.Values)
{
newFile.FullName = Path.Combine(oldDirectory.FullName, newFile.Name);
oldDirectory.AddOrOverwriteFile(newFile, newFile.FullName);
}
foreach (MockDirectory newDirectory in directory.Directories.Values)
{
newDirectory.FullName = Path.Combine(oldDirectory.FullName, newDirectory.Name);
this.AddDirectory(newDirectory);
}
}
else
{
this.Directories.Add(directory.FullName, directory);
}
}
private bool TryGetDirectoryAndParent(string path, out MockDirectory directory, out MockDirectory parentDirectory)
{
if (this.Directories.TryGetValue(path, out directory))
{
parentDirectory = this;
return true;
}
else
{
string parentPath = path.Substring(0, path.LastIndexOf(Path.DirectorySeparatorChar));
parentDirectory = this.FindDirectory(parentPath);
if (parentDirectory != null)
{
foreach (MockDirectory subDirectory in this.Directories.Values)
{
directory = subDirectory.FindDirectory(path);
if (directory != null)
{
return true;
}
}
}
}
directory = null;
parentDirectory = null;
return false;
}
}
}

Просмотреть файл

@ -1,69 +0,0 @@
using Scalar.Common.FileSystem;
using System;
using System.IO;
namespace Scalar.UnitTests.Mock.FileSystem
{
public class MockFile
{
private ReusableMemoryStream contentStream;
private FileProperties fileProperties;
public MockFile(string fullName, string contents)
{
this.FullName = fullName;
this.Name = Path.GetFileName(this.FullName);
this.FileProperties = FileProperties.DefaultFile;
this.contentStream = new ReusableMemoryStream(contents);
}
public MockFile(string fullName, byte[] contents)
{
this.FullName = fullName;
this.Name = Path.GetFileName(this.FullName);
this.FileProperties = FileProperties.DefaultFile;
this.contentStream = new ReusableMemoryStream(contents);
}
public event Action Changed;
public string FullName { get; set; }
public string Name { get; set; }
public FileProperties FileProperties
{
get
{
// The underlying content stream is the correct/true source of the file length
// Create a new copy of the properties to make sure the length is set correctly.
FileProperties newProperties = new FileProperties(
this.fileProperties.FileAttributes,
this.fileProperties.CreationTimeUTC,
this.fileProperties.LastAccessTimeUTC,
this.fileProperties.LastWriteTimeUTC,
this.contentStream.Length);
this.fileProperties = newProperties;
return this.fileProperties;
}
set
{
this.fileProperties = value;
if (this.Changed != null)
{
this.Changed();
}
}
}
public Stream GetContentStream()
{
this.contentStream.Position = 0;
return this.contentStream;
}
}
}

Просмотреть файл

@ -1,382 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using System;
using System.Collections.Generic;
using System.IO;
namespace Scalar.UnitTests.Mock.FileSystem
{
public class MockFileSystem : PhysicalFileSystem
{
public MockFileSystem(MockDirectory rootDirectory)
{
this.RootDirectory = rootDirectory;
this.DeleteNonExistentFileThrowsException = true;
this.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed = true;
}
public MockDirectory RootDirectory { get; private set; }
public bool DeleteFileThrowsException { get; set; }
public Exception ExceptionThrownByCreateDirectory { get; set; }
public bool TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed { get; set; }
/// <summary>
/// Allow FileMoves without checking the input arguments.
/// This is to support tests that just want to allow arbitrary
/// MoveFile calls to succeed.
/// </summary>
public bool AllowMoveFile { get; set; }
/// <summary>
/// Normal behavior C# File.Delete(..) is to not throw if the file to
/// be deleted does not exist. However, existing behavior of this mock
/// is to throw. This flag allows consumers to control this behavior.
/// </summary>
public bool DeleteNonExistentFileThrowsException { get; set; }
/// <summary>
/// Returns the root of the mock filesystem
/// </summary>
/// <remarks>
/// The paths returned are highly unlikely to be used on a real machine,
/// making it easier to catch product code that is (incorrectly)
/// interacting directly with the file system via System.IO or PInvoke.
/// </remarks>
public static string GetMockRoot()
{
switch (Path.DirectorySeparatorChar)
{
case '/':
return "/scalar_ut";
case '\\':
// Use a single letter (rather than something like "mock:") so
// that helper methods like Path.GetPathRoot work correctly
return "B:"; // Second floppy drive
default:
Assert.Fail($"Unknown DirectorySeparatorChar '{Path.DirectorySeparatorChar}'");
return null;
}
}
public override void DeleteDirectory(string path, bool recursive = true)
{
if (!recursive)
{
throw new NotImplementedException();
}
this.RootDirectory.DeleteDirectory(path);
}
public override bool FileExists(string path)
{
return this.RootDirectory.FindFile(path) != null;
}
public override bool DirectoryExists(string path)
{
return this.RootDirectory.FindDirectory(path) != null;
}
public override void CopyFile(string sourcePath, string destinationPath, bool overwrite)
{
throw new NotImplementedException();
}
public override void DeleteFile(string path)
{
if (this.DeleteFileThrowsException)
{
throw new IOException("Exception when deleting file");
}
MockFile file = this.RootDirectory.FindFile(path);
if (file == null && !this.DeleteNonExistentFileThrowsException)
{
return;
}
file.ShouldNotBeNull();
this.RootDirectory.RemoveFile(path);
}
public override void MoveAndOverwriteFile(string sourcePath, string destinationPath)
{
if (sourcePath == null || destinationPath == null)
{
throw new ArgumentNullException();
}
if (this.AllowMoveFile)
{
return;
}
MockFile sourceFile = this.RootDirectory.FindFile(sourcePath);
MockFile destinationFile = this.RootDirectory.FindFile(destinationPath);
if (sourceFile == null)
{
throw new FileNotFoundException();
}
if (destinationFile != null)
{
this.RootDirectory.RemoveFile(destinationPath);
}
this.WriteAllText(destinationPath, this.ReadAllText(sourcePath));
this.RootDirectory.RemoveFile(sourcePath);
}
public override Stream OpenFileStream(string path, FileMode fileMode, FileAccess fileAccess, FileShare shareMode, FileOptions options, bool flushesToDisk)
{
MockFile file = this.RootDirectory.FindFile(path);
if (fileMode == FileMode.Create)
{
if (file != null)
{
this.RootDirectory.RemoveFile(path);
}
return this.CreateAndOpenFileStream(path);
}
if (fileMode == FileMode.OpenOrCreate)
{
if (file == null)
{
return this.CreateAndOpenFileStream(path);
}
}
else
{
file.ShouldNotBeNull();
}
return file.GetContentStream();
}
public override void WriteAllText(string path, string contents)
{
MockFile file = new MockFile(path, contents);
this.RootDirectory.AddOrOverwriteFile(file, path);
}
public override string ReadAllText(string path)
{
MockFile file = this.RootDirectory.FindFile(path);
using (StreamReader reader = new StreamReader(file.GetContentStream()))
{
return reader.ReadToEnd();
}
}
public override byte[] ReadAllBytes(string path)
{
MockFile file = this.RootDirectory.FindFile(path);
using (Stream s = file.GetContentStream())
{
int count = (int)s.Length;
int pos = 0;
byte[] result = new byte[count];
while (count > 0)
{
int n = s.Read(result, pos, count);
if (n == 0)
{
throw new IOException("Unexpected end of stream");
}
pos += n;
count -= n;
}
return result;
}
}
public override IEnumerable<string> ReadLines(string path)
{
MockFile file = this.RootDirectory.FindFile(path);
using (StreamReader reader = new StreamReader(file.GetContentStream()))
{
while (!reader.EndOfStream)
{
yield return reader.ReadLine();
}
}
}
public override void CreateDirectory(string path)
{
if (this.ExceptionThrownByCreateDirectory != null)
{
throw this.ExceptionThrownByCreateDirectory;
}
this.RootDirectory.CreateDirectory(path);
}
public override bool TryCreateDirectoryWithAdminAndUserModifyPermissions(string directoryPath, out string error)
{
throw new NotImplementedException();
}
public override bool TryCreateOrUpdateDirectoryToAdminModifyPermissions(ITracer tracer, string directoryPath, out string error)
{
error = null;
if (this.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed)
{
// TryCreateOrUpdateDirectoryToAdminModifyPermissions is typically called for paths in C:\ProgramData\Scalar,
// if it's called for one of those paths remap the paths to be inside the mock: root
string mockDirectoryPath = directoryPath;
string scalarProgramData = @"C:\ProgramData\Scalar";
if (directoryPath.StartsWith(scalarProgramData, ScalarPlatform.Instance.Constants.PathComparison))
{
mockDirectoryPath = mockDirectoryPath.Substring(scalarProgramData.Length);
mockDirectoryPath = "mock:" + mockDirectoryPath;
}
this.RootDirectory.CreateDirectory(mockDirectoryPath);
return true;
}
return false;
}
public override IEnumerable<DirectoryItemInfo> ItemsInDirectory(string path)
{
MockDirectory directory = this.RootDirectory.FindDirectory(path);
directory.ShouldNotBeNull();
foreach (MockDirectory subDirectory in directory.Directories.Values)
{
yield return new DirectoryItemInfo()
{
Name = subDirectory.Name,
FullName = subDirectory.FullName,
IsDirectory = true
};
}
foreach (MockFile file in directory.Files.Values)
{
yield return new DirectoryItemInfo()
{
FullName = file.FullName,
Name = file.Name,
IsDirectory = false,
Length = file.FileProperties.Length
};
}
}
public override IEnumerable<string> EnumerateDirectories(string path)
{
MockDirectory directory = this.RootDirectory.FindDirectory(path);
directory.ShouldNotBeNull();
if (directory != null)
{
foreach (MockDirectory subDirectory in directory.Directories.Values)
{
yield return subDirectory.FullName;
}
}
}
public override IEnumerable<string> EnumerateFiles(string path, string searchPattern)
{
string searchSuffix = null;
bool matchAll = string.IsNullOrEmpty(searchPattern) || searchPattern == "*";
if (!matchAll)
{
// Only support matching "*<pattern>"
if (!searchPattern.StartsWith("*", StringComparison.Ordinal))
{
throw new NotImplementedException("Unsupported search pattern");
}
if (searchPattern.IndexOf('*', startIndex: 1) != -1)
{
throw new NotImplementedException("Unsupported search pattern");
}
if (searchPattern.Contains("?"))
{
throw new NotImplementedException("Unsupported search pattern");
}
searchSuffix = searchPattern.Substring(1);
}
MockDirectory directory = this.RootDirectory.FindDirectory(path);
directory.ShouldNotBeNull();
if (directory != null)
{
foreach (MockFile file in directory.Files.Values)
{
if (matchAll)
{
yield return file.FullName;
}
else if (file.Name.EndsWith(searchSuffix, ScalarPlatform.Instance.Constants.PathComparison))
{
yield return file.FullName;
}
}
}
}
public override FileAttributes GetAttributes(string path)
{
return FileAttributes.Normal;
}
public override void SetAttributes(string path, FileAttributes fileAttributes)
{
}
public override string[] GetFiles(string directoryPath, string mask)
{
if (!mask.Equals("*"))
{
throw new NotImplementedException();
}
MockDirectory directory = this.RootDirectory.FindDirectory(directoryPath);
directory.ShouldNotBeNull();
List<string> files = new List<string>();
foreach (MockFile file in directory.Files.Values)
{
files.Add(file.FullName);
}
return files.ToArray();
}
private Stream CreateAndOpenFileStream(string path)
{
MockFile file = this.RootDirectory.CreateFile(path);
file.ShouldNotBeNull();
return this.OpenFileStream(path, FileMode.Open, (FileAccess)NativeMethods.FileAccess.FILE_GENERIC_READ, FileShare.Read, callFlushFileBuffers: false);
}
}
}

Просмотреть файл

@ -1,69 +0,0 @@
using Scalar.Common.FileSystem;
using System;
using System.IO;
namespace Scalar.UnitTests.Mock.FileSystem
{
public class MockFileSystemWithCallbacks : PhysicalFileSystem
{
public Func<bool> OnFileExists { get; set; }
public Func<string, FileMode, FileAccess, Stream> OnOpenFileStream { get; set; }
public override bool FileExists(string path)
{
if (this.OnFileExists == null)
{
throw new InvalidOperationException("OnFileExists should be set if it is expected to be called.");
}
return this.OnFileExists();
}
public override Stream OpenFileStream(string path, FileMode fileMode, FileAccess fileAccess, FileShare shareMode, FileOptions options, bool flushesToDisk)
{
if (this.OnOpenFileStream == null)
{
throw new InvalidOperationException("OnOpenFileStream should be set if it is expected to be called.");
}
return this.OnOpenFileStream(path, fileMode, fileAccess);
}
public override void WriteAllText(string path, string contents)
{
}
public override string ReadAllText(string path)
{
throw new InvalidOperationException("ReadAllText has not been implemented.");
}
public override void DeleteFile(string path)
{
}
public override void DeleteDirectory(string path, bool recursive = true)
{
throw new InvalidOperationException("DeleteDirectory has not been implemented.");
}
public override void CreateDirectory(string path)
{
}
public override FileAttributes GetAttributes(string path)
{
return FileAttributes.Normal;
}
public override void SetAttributes(string path, FileAttributes fileAttributes)
{
}
public override string[] GetFiles(string directoryPath, string mask)
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -1,56 +0,0 @@
using Scalar.Common.FileSystem;
using Scalar.Common.Tracing;
using System;
namespace Scalar.UnitTests.Mock.FileSystem
{
public class MockPlatformFileSystem : IPlatformFileSystem
{
public bool SupportsFileMode { get; } = true;
public bool SupportsUntrackedCache { get; } = true;
public void FlushFileBuffers(string path)
{
throw new NotSupportedException();
}
public void MoveAndOverwriteFile(string sourceFileName, string destinationFilename)
{
throw new NotSupportedException();
}
public bool TryGetNormalizedPath(string path, out string normalizedPath, out string errorMessage)
{
errorMessage = null;
normalizedPath = path;
return true;
}
public bool IsExecutable(string fileName)
{
throw new NotSupportedException();
}
public bool IsSocket(string fileName)
{
throw new NotSupportedException();
}
public bool TryCreateDirectoryWithAdminAndUserModifyPermissions(string directoryPath, out string error)
{
throw new NotSupportedException();
}
public bool TryCreateOrUpdateDirectoryToAdminModifyPermissions(ITracer tracer, string directoryPath, out string error)
{
throw new NotSupportedException();
}
public bool IsFileSystemSupported(string path, out string error)
{
error = null;
return true;
}
}
}

Просмотреть файл

@ -1,22 +0,0 @@
using Scalar.Common.Git;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Scalar.UnitTests.Mock.Git
{
public class MockGitInstallation : IGitInstallation
{
public bool GitExists(string gitBinPath)
{
return false;
}
public string GetInstalledGitBinPath()
{
return null;
}
}
}

Просмотреть файл

@ -1,147 +0,0 @@
using Scalar.Common.Git;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Scalar.UnitTests.Mock.Git
{
public class MockGitProcess : GitProcess
{
private List<CommandInfo> expectedCommandInfos = new List<CommandInfo>();
public MockGitProcess()
: base(new MockScalarEnlistment())
{
this.CommandsRun = new List<string>();
this.StoredCredentials = new Dictionary<string, Credential>(StringComparer.OrdinalIgnoreCase);
this.CredentialApprovals = new Dictionary<string, List<Credential>>();
this.CredentialRejections = new Dictionary<string, List<Credential>>();
}
public List<string> CommandsRun { get; }
public bool ShouldFail { get; set; }
public Dictionary<string, Credential> StoredCredentials { get; }
public Dictionary<string, List<Credential>> CredentialApprovals { get; }
public Dictionary<string, List<Credential>> CredentialRejections { get; }
public void SetExpectedCommandResult(string command, Func<Result> result, bool matchPrefix = false)
{
CommandInfo commandInfo = new CommandInfo(command, result, matchPrefix);
this.expectedCommandInfos.Add(commandInfo);
}
public override bool TryStoreCredential(ITracer tracer, string repoUrl, string username, string password, out string error)
{
Credential credential = new Credential(username, password);
// Record the approval request for this credential
List<Credential> acceptedCredentials;
if (!this.CredentialApprovals.TryGetValue(repoUrl, out acceptedCredentials))
{
acceptedCredentials = new List<Credential>();
this.CredentialApprovals[repoUrl] = acceptedCredentials;
}
acceptedCredentials.Add(credential);
// Store the credential
this.StoredCredentials[repoUrl] = credential;
return base.TryStoreCredential(tracer, repoUrl, username, password, out error);
}
public override bool TryDeleteCredential(ITracer tracer, string repoUrl, string username, string password, out string error)
{
Credential credential = new Credential(username, password);
// Record the rejection request for this credential
List<Credential> rejectedCredentials;
if (!this.CredentialRejections.TryGetValue(repoUrl, out rejectedCredentials))
{
rejectedCredentials = new List<Credential>();
this.CredentialRejections[repoUrl] = rejectedCredentials;
}
rejectedCredentials.Add(credential);
// Erase the credential
this.StoredCredentials.Remove(repoUrl);
return base.TryDeleteCredential(tracer, repoUrl, username, password, out error);
}
protected override Result InvokeGitImpl(
string command,
string workingDirectory,
string dotGitDirectory,
bool fetchMissingObjects,
Action<StreamWriter> writeStdIn,
Action<string> parseStdOutLine,
int timeoutMs,
string gitObjectsDirectory = null,
bool userInteractive = true)
{
this.CommandsRun.Add(command);
if (this.ShouldFail)
{
return new Result(string.Empty, string.Empty, Result.GenericFailureCode);
}
Predicate<CommandInfo> commandMatchFunction =
(CommandInfo commandInfo) =>
{
if (commandInfo.MatchPrefix)
{
return command.StartsWith(commandInfo.Command);
}
else
{
return string.Equals(command, commandInfo.Command, StringComparison.Ordinal);
}
};
CommandInfo matchedCommand = this.expectedCommandInfos.Find(commandMatchFunction);
matchedCommand.ShouldNotBeNull("Unexpected command: " + command);
return matchedCommand.Result();
}
public class Credential
{
public Credential(string username, string password)
{
this.Username = username;
this.Password = password;
}
public string Username { get; }
public string Password { get; }
public string BasicAuthString
{
get => Convert.ToBase64String(Encoding.ASCII.GetBytes(this.Username + ":" + this.Password));
}
}
private class CommandInfo
{
public CommandInfo(string command, Func<Result> result, bool matchPrefix)
{
this.Command = command;
this.Result = result;
this.MatchPrefix = matchPrefix;
}
public string Command { get; private set; }
public Func<Result> Result { get; private set; }
public bool MatchPrefix { get; private set; }
}
}
}

Просмотреть файл

@ -1,11 +0,0 @@
using Scalar.Common.Http;
namespace Scalar.UnitTests.Mock
{
public class MockCacheServerInfo : CacheServerInfo
{
public MockCacheServerInfo() : base("https://mock", "mock")
{
}
}
}

Просмотреть файл

@ -1,96 +0,0 @@
using Scalar.Common.Tracing;
using Scalar.Upgrader;
using System;
using System.Collections.Generic;
namespace Scalar.UnitTests.Mock.Upgrader
{
public class MockInstallerPrerunChecker : InstallerPreRunChecker
{
public const string GitUpgradeCheckError = "Unable to upgrade Git";
private FailOnCheckType failOnCheck;
public MockInstallerPrerunChecker(ITracer tracer) : base(tracer, string.Empty)
{
}
[Flags]
public enum FailOnCheckType
{
Invalid = 0,
IsElevated = 0x2,
BlockingProcessesRunning = 0x4,
UnattendedMode = 0x8,
IsServiceInstalledAndNotRunning = 0x40,
}
public void SetReturnFalseOnCheck(FailOnCheckType prerunCheck)
{
this.failOnCheck |= prerunCheck;
}
public void SetReturnTrueOnCheck(FailOnCheckType prerunCheck)
{
this.failOnCheck &= ~prerunCheck;
}
public void Reset()
{
this.failOnCheck = FailOnCheckType.Invalid;
this.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.UnattendedMode);
this.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.BlockingProcessesRunning);
this.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.IsServiceInstalledAndNotRunning);
}
public void SetCommandToRerun(string command)
{
this.CommandToRerun = command;
}
protected override bool IsServiceInstalledAndNotRunning()
{
return this.FakedResultOfCheck(FailOnCheckType.IsServiceInstalledAndNotRunning);
}
protected override bool IsElevated()
{
return this.FakedResultOfCheck(FailOnCheckType.IsElevated);
}
protected override bool IsScalarUpgradeSupported()
{
return true;
}
protected override bool IsUnattended()
{
return this.FakedResultOfCheck(FailOnCheckType.UnattendedMode);
}
protected override bool IsBlockingProcessRunning(out HashSet<string> processes)
{
processes = new HashSet<string>();
bool isRunning = this.FakedResultOfCheck(FailOnCheckType.BlockingProcessesRunning);
if (isRunning)
{
processes.Add("git");
}
return isRunning;
}
protected override bool TryRunScalarWithArgs(string args, out string error)
{
error = "Unknown Scalar command";
return false;
}
private bool FakedResultOfCheck(FailOnCheckType checkType)
{
return !this.failOnCheck.HasFlag(checkType);
}
}
}

Просмотреть файл

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Scalar.UnitTests.Mock.Upgrader
{
public class MockTextWriter : TextWriter
{
private StringBuilder stringBuilder;
public MockTextWriter() : base()
{
this.AllLines = new List<string>();
this.stringBuilder = new StringBuilder();
}
public List<string> AllLines { get; private set; }
public override Encoding Encoding
{
get { return Encoding.Default; }
}
public override void Write(char value)
{
if (value.Equals('\r'))
{
return;
}
if (value.Equals('\n'))
{
this.AllLines.Add(this.stringBuilder.ToString());
this.stringBuilder.Clear();
return;
}
this.stringBuilder.Append(value);
}
public bool ContainsLine(string line)
{
return this.AllLines.Exists(x => x.Equals(line, StringComparison.Ordinal));
}
}
}

Просмотреть файл

@ -1,159 +0,0 @@
using System;
using System.IO;
using System.Text;
namespace Scalar.UnitTests.Mock
{
public class ReusableMemoryStream : Stream
{
private byte[] contents;
private long length;
private long position;
public ReusableMemoryStream(string initialContents)
{
this.contents = Encoding.UTF8.GetBytes(initialContents);
this.length = this.contents.Length;
}
public ReusableMemoryStream(byte[] initialContents)
{
this.contents = initialContents;
this.length = initialContents.Length;
}
public bool TruncateWrites { get; set; }
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override long Length
{
get { return this.length; }
}
public override long Position
{
get { return this.position; }
set { this.position = value; }
}
public override void Flush()
{
// noop
}
public string ReadAsString()
{
return Encoding.UTF8.GetString(this.contents, 0, (int)this.length);
}
public string ReadAt(long position, long length)
{
long lastPosition = this.Position;
this.Position = position;
byte[] bytes = new byte[length];
this.Read(bytes, 0, (int)length);
this.Position = lastPosition;
return Encoding.UTF8.GetString(bytes);
}
public override int Read(byte[] buffer, int offset, int count)
{
int actualCount = Math.Min((int)(this.length - this.position), count);
Array.Copy(this.contents, this.Position, buffer, offset, actualCount);
this.Position += actualCount;
return actualCount;
}
public override long Seek(long offset, SeekOrigin origin)
{
if (origin == SeekOrigin.Begin)
{
this.position = offset;
}
else if (origin == SeekOrigin.End)
{
this.position = this.length - offset;
}
else
{
this.position += offset;
}
if (this.position > this.length)
{
this.position = this.length - 1;
}
return this.position;
}
public override void SetLength(long value)
{
while (value > this.contents.Length)
{
if (this.contents.Length == 0)
{
this.contents = new byte[1024];
}
else
{
Array.Resize(ref this.contents, this.contents.Length * 2);
}
}
this.length = value;
}
public override void Write(byte[] buffer, int offset, int count)
{
if (this.position + count > this.contents.Length)
{
this.SetLength(this.position + count);
}
if (this.TruncateWrites)
{
count /= 2;
}
Array.Copy(buffer, offset, this.contents, this.position, count);
this.position += count;
if (this.position > this.length)
{
this.length = this.position;
}
if (this.TruncateWrites)
{
throw new IOException("Could not complete write");
}
}
protected override void Dispose(bool disposing)
{
// This method is a noop besides resetting the position.
// The byte[] in this class is the source of truth for the contents that this
// stream is providing, so we can't dispose it here.
this.position = 0;
}
}
}

Просмотреть файл

@ -1,19 +0,0 @@
# Scalar Unit Tests
* Targets .NET Core
* Contains all unit tests that OS agnostic
* Conditionally includes the Windows\\** directory when running on Windows.
## Running Unit Tests
**Option 1: `dotnet test`**
`dotnet test` will run Scalar.UnitTests, and if on Windows also the Windows-only tests.
**Option 2: Run individual tests from Visual Studio**
Unit tests can both be run from Visual Studio. Simply open the Test Explorer (VS for Windows) or Unit Tests Pad (VS for Mac) and run or debug the tests you wish.
## Adding New Tests
Whenever possible new unit tests should be added to the root Scalar.UnitTests direcotry. If the new tests are specific to the Window OS then they will need to be added to the Scalar.UnitTests\\Windows directory.

Просмотреть файл

@ -1,36 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Scalar.Common\Scalar.Common.csproj" />
<ProjectReference Include="..\Scalar.Service\Scalar.Service.csproj" />
<ProjectReference Include="..\Scalar.Service.UI\Scalar.Service.UI.csproj" />
<ProjectReference Include="..\Scalar.TestInfrastructure\Scalar.TestInfrastructure.csproj" />
<ProjectReference Include="..\Scalar.Upgrader\Scalar.Upgrader.csproj" />
<ProjectReference Include="..\Scalar\Scalar.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="Moq" Version="4.13.0" />
<PackageReference Include="nunit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
</ItemGroup>
<ItemGroup>
<None Remove="Data\**" />
<Content Include="Data\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(OSPlatform)' != 'windows'">
<Compile Remove="Windows\**" />
<None Include="Windows\**" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,219 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common.FileSystem;
using Scalar.Common.Maintenance;
using Scalar.Common.RepoRegistry;
using Scalar.Service;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using System.Collections.Generic;
using System.IO;
namespace Scalar.UnitTests.Service
{
[TestFixture]
public class MaintenanceTaskSchedulerTests
{
private MockTracer mockTracer;
private Mock<PhysicalFileSystem> mockFileSystem;
private Mock<IScalarVerbRunner> mockVerbRunner;
private Mock<IScalarRepoRegistry> mockRepoRegistry;
private Mock<IRegisteredUserStore> mockRegisteredUserStore;
[SetUp]
public void Setup()
{
this.mockTracer = new MockTracer();
this.mockFileSystem = new Mock<PhysicalFileSystem>(MockBehavior.Strict);
this.mockVerbRunner = new Mock<IScalarVerbRunner>(MockBehavior.Strict);
this.mockRepoRegistry = new Mock<IScalarRepoRegistry>(MockBehavior.Strict);
this.mockRegisteredUserStore = new Mock<IRegisteredUserStore>(MockBehavior.Strict);
}
[TearDown]
public void TearDown()
{
this.mockFileSystem.VerifyAll();
this.mockVerbRunner.VerifyAll();
this.mockRepoRegistry.VerifyAll();
this.mockRegisteredUserStore.VerifyAll();
}
[TestCase]
public void RegisterUser()
{
using (MaintenanceTaskScheduler taskScheduler = new MaintenanceTaskScheduler(
this.mockTracer,
this.mockFileSystem.Object,
this.mockVerbRunner.Object,
this.mockRepoRegistry.Object))
{
taskScheduler.RegisteredUser.ShouldBeNull();
UserAndSession testUser1 = new UserAndSession("testUser1", sessionId: 1);
UserAndSession testUser2 = new UserAndSession("testUser2", sessionId: 2);
taskScheduler.RegisterUser(testUser1);
taskScheduler.RegisteredUser.UserId.ShouldEqual(testUser1.UserId);
taskScheduler.RegisteredUser.SessionId.ShouldEqual(testUser1.SessionId);
taskScheduler.RegisterUser(testUser2);
taskScheduler.RegisteredUser.UserId.ShouldEqual(testUser2.UserId);
taskScheduler.RegisteredUser.SessionId.ShouldEqual(testUser2.SessionId);
}
}
[TestCase]
public void MaintenanceTask_Execute_NoRegisteredUser()
{
MaintenanceTasks.Task task = MaintenanceTasks.Task.PackFiles;
this.mockRegisteredUserStore.SetupGet(mrus => mrus.RegisteredUser).Returns((UserAndSession)null);
MaintenanceTaskScheduler.MaintenanceTask maintenanceTask = new MaintenanceTaskScheduler.MaintenanceTask(
this.mockTracer,
this.mockFileSystem.Object,
this.mockVerbRunner.Object,
this.mockRepoRegistry.Object,
this.mockRegisteredUserStore.Object,
task);
maintenanceTask.Execute();
this.mockTracer.RelatedInfoEvents.ShouldContain(entry => entry.Contains($"Skipping '{task}', no registered user"));
}
[TestCase]
public void MaintenanceTask_Execute_SkipsReposThatDoNotMatchRegisteredUser()
{
MaintenanceTasks.Task task = MaintenanceTasks.Task.PackFiles;
UserAndSession testUser = new UserAndSession("testUserId", sessionId: 1);
this.mockRegisteredUserStore.SetupGet(mrus => mrus.RegisteredUser).Returns(testUser);
this.mockRepoRegistry.Setup(reg => reg.GetRegisteredRepos()).Returns(
new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "repoRoot"), "nonMatchingUser"),
new ScalarRepoRegistration(Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "repoRoot2"), "nonMatchingUser2")
});
MaintenanceTaskScheduler.MaintenanceTask maintenanceTask = new MaintenanceTaskScheduler.MaintenanceTask(
this.mockTracer,
this.mockFileSystem.Object,
this.mockVerbRunner.Object,
this.mockRepoRegistry.Object,
this.mockRegisteredUserStore.Object,
task);
maintenanceTask.Execute();
this.mockTracer.RelatedEvents.ShouldContain(entry => entry.Contains("\"reposInRegistryForUser\":0"));
}
[TestCase]
public void MaintenanceTask_Execute_SkipsRegisteredRepoIfVolumeDoesNotExist()
{
MaintenanceTasks.Task task = MaintenanceTasks.Task.PackFiles;
UserAndSession testUser = new UserAndSession("testUserId", sessionId: 1);
this.mockRegisteredUserStore.SetupGet(mrus => mrus.RegisteredUser).Returns(testUser);
string repoPath = Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "repoRoot");
this.mockRepoRegistry.Setup(reg => reg.GetRegisteredRepos()).Returns(
new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(repoPath, testUser.UserId)
});
this.mockFileSystem.Setup(fs => fs.DirectoryExists(Path.GetPathRoot(repoPath))).Returns(false);
MaintenanceTaskScheduler.MaintenanceTask maintenanceTask = new MaintenanceTaskScheduler.MaintenanceTask(
this.mockTracer,
this.mockFileSystem.Object,
this.mockVerbRunner.Object,
this.mockRepoRegistry.Object,
this.mockRegisteredUserStore.Object,
task);
maintenanceTask.Execute();
this.mockTracer.RelatedEvents.ShouldContain(entry => entry.Contains("SkippedRepoWithMissingVolume"));
}
[TestCase]
public void MaintenanceTask_Execute_UnregistersRepoIfMissing()
{
MaintenanceTasks.Task task = MaintenanceTasks.Task.PackFiles;
UserAndSession testUser = new UserAndSession("testUserId", sessionId: 1);
this.mockRegisteredUserStore.SetupGet(mrus => mrus.RegisteredUser).Returns(testUser);
string repoPath = Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "repoRoot");
this.mockRepoRegistry.Setup(reg => reg.GetRegisteredRepos()).Returns(
new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(repoPath, testUser.UserId)
});
// Validate that TryUnregisterRepo will be called for repoPath
string emptyString = string.Empty;
this.mockRepoRegistry.Setup(reg => reg.TryUnregisterRepo(repoPath, out emptyString)).Returns(true);
// The root volume should exist
this.mockFileSystem.Setup(fs => fs.DirectoryExists(Path.GetPathRoot(repoPath))).Returns(true);
// The repo itself does not exist
this.mockFileSystem.Setup(fs => fs.DirectoryExists(repoPath)).Returns(false);
MaintenanceTaskScheduler.MaintenanceTask maintenanceTask = new MaintenanceTaskScheduler.MaintenanceTask(
this.mockTracer,
this.mockFileSystem.Object,
this.mockVerbRunner.Object,
this.mockRepoRegistry.Object,
this.mockRegisteredUserStore.Object,
task);
maintenanceTask.Execute();
this.mockTracer.RelatedEvents.ShouldContain(entry => entry.Contains("RemovedMissingRepo"));
}
[TestCase]
public void MaintenanceTask_Execute_CallsRunVerbOnlyForRegisteredRepos()
{
MaintenanceTasks.Task task = MaintenanceTasks.Task.PackFiles;
UserAndSession testUser = new UserAndSession("testUserId", sessionId: 1);
UserAndSession secondUser = new UserAndSession("testUserId2", sessionId: 1);
string repoPath1 = Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "repoRoot");
string repoPath2 = Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "repoRoot2");
string secondUsersRepoPath = Path.Combine(MockFileSystem.GetMockRoot(), "Repos", "secondUsersRepo");
this.mockRegisteredUserStore.SetupGet(mrus => mrus.RegisteredUser).Returns(testUser);
this.mockRepoRegistry.Setup(reg => reg.GetRegisteredRepos()).Returns(
new List<ScalarRepoRegistration>
{
new ScalarRepoRegistration(repoPath1, testUser.UserId),
new ScalarRepoRegistration(secondUsersRepoPath, secondUser.UserId),
new ScalarRepoRegistration(repoPath2, testUser.UserId)
});
// The root volume and repos exist
this.mockFileSystem.Setup(fs => fs.DirectoryExists(Path.GetPathRoot(repoPath1))).Returns(true);
this.mockFileSystem.Setup(fs => fs.DirectoryExists(repoPath1)).Returns(true);
this.mockFileSystem.Setup(fs => fs.DirectoryExists(repoPath2)).Returns(true);
this.mockVerbRunner.Setup(vr => vr.CallMaintenance(task, repoPath1, testUser.SessionId)).Returns(true);
this.mockVerbRunner.Setup(vr => vr.CallMaintenance(task, repoPath2, testUser.SessionId)).Returns(true);
MaintenanceTaskScheduler.MaintenanceTask maintenanceTask = new MaintenanceTaskScheduler.MaintenanceTask(
this.mockTracer,
this.mockFileSystem.Object,
this.mockVerbRunner.Object,
this.mockRepoRegistry.Object,
this.mockRegisteredUserStore.Object,
task);
maintenanceTask.Execute();
}
}
}

Просмотреть файл

@ -1,118 +0,0 @@
using NUnit.Framework;
using Scalar.Service;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using System.Threading;
namespace Scalar.UnitTests.Service
{
[TestFixture]
public class ServiceTaskQueueTests
{
private int maxWaitTime = 500;
[TestCase]
public void ServiceTaskQueueHandlesTwoJobs()
{
TestServiceTask step1 = new TestServiceTask();
TestServiceTask step2 = new TestServiceTask();
using (ServiceTaskQueue queue = new ServiceTaskQueue(new MockTracer()))
{
queue.TryEnqueue(step1);
queue.TryEnqueue(step2);
step1.EventTriggered.WaitOne(this.maxWaitTime).ShouldBeTrue();
step2.EventTriggered.WaitOne(this.maxWaitTime).ShouldBeTrue();
queue.Stop();
step1.NumberOfExecutions.ShouldEqual(1);
step2.NumberOfExecutions.ShouldEqual(1);
}
}
[TestCase]
public void ServiceTaskQueueStopSuceedsWhenQueueIsEmpty()
{
using (ServiceTaskQueue queue = new ServiceTaskQueue(new MockTracer()))
{
queue.Stop();
TestServiceTask step = new TestServiceTask();
queue.TryEnqueue(step).ShouldEqual(false);
}
}
[TestCase]
public void ServiceTaskQueueStopsJob()
{
using (ServiceTaskQueue queue = new ServiceTaskQueue(new MockTracer()))
{
// This step stops the queue after the step is started,
// then checks if Stop() was called.
WatchForStopTask watchForStop = new WatchForStopTask(queue);
queue.TryEnqueue(watchForStop).ShouldBeTrue();
watchForStop.EventTriggered.WaitOne(this.maxWaitTime).ShouldBeTrue();
watchForStop.SawStopping.ShouldBeTrue();
// Ensure we don't start a job after the Stop() call
TestServiceTask watchForStart = new TestServiceTask();
queue.TryEnqueue(watchForStart).ShouldBeFalse();
// This only ensures the event didn't happen within maxWaitTime
watchForStart.EventTriggered.WaitOne(this.maxWaitTime).ShouldBeFalse();
queue.Stop();
}
}
public class TestServiceTask : IServiceTask
{
public TestServiceTask()
{
this.EventTriggered = new ManualResetEvent(initialState: false);
}
public ManualResetEvent EventTriggered { get; set; }
public int NumberOfExecutions { get; set; }
public void Execute()
{
this.NumberOfExecutions++;
this.EventTriggered.Set();
}
public void Stop()
{
}
}
private class WatchForStopTask : IServiceTask
{
public WatchForStopTask(ServiceTaskQueue queue)
{
this.Queue = queue;
this.EventTriggered = new ManualResetEvent(false);
}
public ServiceTaskQueue Queue { get; set; }
public bool SawStopping { get; private set; }
public ManualResetEvent EventTriggered { get; private set; }
public void Execute()
{
this.Queue.Stop();
this.EventTriggered.Set();
}
public void Stop()
{
this.SawStopping = true;
}
}
}
}

Просмотреть файл

@ -1,16 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.UnitTests.Mock.Common;
namespace Scalar.UnitTests
{
[SetUpFixture]
public class Setup
{
[OneTimeSetUp]
public void SetUp()
{
ScalarPlatform.Register(new MockPlatform());
}
}
}

Просмотреть файл

@ -1,46 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common.Tracing;
using System;
namespace Scalar.UnitTests.Tracing
{
[TestFixture]
public class EventListenerTests
{
[TestCase]
public void EventListener_RecordMessage_ExceptionThrownInternally_RaisesFailureEventWithErrorMessage()
{
string expectedErrorMessage = $"test error message unique={Guid.NewGuid():N}";
Mock<IEventListenerEventSink> eventSink = new Mock<IEventListenerEventSink>();
TraceEventMessage message = new TraceEventMessage { Level = EventLevel.Error, Keywords = Keywords.None };
TestEventListener listener = new TestEventListener(EventLevel.Informational, Keywords.Any, eventSink.Object)
{
RecordMessageInternalCallback = _ => throw new Exception(expectedErrorMessage)
};
listener.RecordMessage(message);
eventSink.Verify(
x => x.OnListenerFailure(listener, It.Is<string>(msg => msg.Contains(expectedErrorMessage))),
times: Times.Once);
}
private class TestEventListener : EventListener
{
public TestEventListener(EventLevel maxVerbosity, Keywords keywordFilter, IEventListenerEventSink eventSink)
: base(maxVerbosity, keywordFilter, eventSink)
{
}
public Action<TraceEventMessage> RecordMessageInternalCallback { get; set; }
protected override void RecordMessageInternal(TraceEventMessage message)
{
this.RecordMessageInternalCallback?.Invoke(message);
}
}
}
}

Просмотреть файл

@ -1,273 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using System;
using System.IO.Pipes;
using System.Threading;
namespace Scalar.UnitTests.Tracing
{
[TestFixture]
public class QueuedPipeStringWriterTests
{
[TestCase]
public void Stop_RaisesStateStopped()
{
// Capture event invocations
Mock<IQueuedPipeStringWriterEventSink> eventSink = new Mock<IQueuedPipeStringWriterEventSink>();
// createPipeFunc returns `null` since the test will never enqueue any messaged to write
QueuedPipeStringWriter writer = new QueuedPipeStringWriter(
() => null,
eventSink.Object);
// Try to write some dummy data
writer.Start();
writer.Stop();
eventSink.Verify(
x => x.OnStateChanged(writer, QueuedPipeStringWriterState.Stopped, null),
Times.Once);
}
[TestCase]
public void MissingPipe_RaisesStateFailing()
{
const string inputMessage = "FooBar";
// Capture event invocations
Mock<IQueuedPipeStringWriterEventSink> eventSink = new Mock<IQueuedPipeStringWriterEventSink>();
QueuedPipeStringWriter writer = new QueuedPipeStringWriter(
() => throw new Exception("Failing pipe connection"),
eventSink.Object);
// Try to write some dummy data
writer.Start();
bool queueOk = writer.TryEnqueue(inputMessage);
writer.Stop();
queueOk.ShouldBeTrue();
eventSink.Verify(
x => x.OnStateChanged(writer, QueuedPipeStringWriterState.Failing, It.IsAny<Exception>()),
Times.Once);
eventSink.Verify(
x => x.OnStateChanged(writer, QueuedPipeStringWriterState.Stopped, It.IsAny<Exception>()),
Times.Once);
}
[TestCase]
public void GoodPipe_WritesDataAndRaisesStateHealthy()
{
const string inputMessage = "FooBar";
byte[] expectedData =
{
0x46, 0x6F, 0x6F, 0x42, 0x61, 0x72, (byte)'\n', // "FooBar\n"
0x46, 0x6F, 0x6F, 0x42, 0x61, 0x72, (byte)'\n', // "FooBar\n"
0x46, 0x6F, 0x6F, 0x42, 0x61, 0x72, (byte)'\n', // "FooBar\n"
};
string pipeName = Guid.NewGuid().ToString("N");
// Capture event invocations
Mock<IQueuedPipeStringWriterEventSink> eventSink = new Mock<IQueuedPipeStringWriterEventSink>();
QueuedPipeStringWriter writer = new QueuedPipeStringWriter(
() => new NamedPipeClientStream(".", pipeName, PipeDirection.Out),
eventSink.Object);
using (TestPipeReaderWorker pipeWorker = new TestPipeReaderWorker(pipeName, PipeTransmissionMode.Byte))
{
// Start the pipe reader worker first and wait until the pipe server has been stood-up
// before starting the pipe writer/enqueuing messages because the writer does not wait
// for the pipe to be ready to accept (it returns and drops messages immediately).
pipeWorker.Start();
pipeWorker.WaitForReadyToAccept();
writer.Start();
// Try to write some dummy data
bool queueOk1 = writer.TryEnqueue(inputMessage);
bool queueOk2 = writer.TryEnqueue(inputMessage);
bool queueOk3 = writer.TryEnqueue(inputMessage);
// Wait until we've received all the sent messages before shuting down
// the pipe worker thread.
pipeWorker.WaitForRecievedBytes(count: expectedData.Length);
pipeWorker.Stop();
writer.Stop();
queueOk1.ShouldBeTrue();
queueOk2.ShouldBeTrue();
queueOk3.ShouldBeTrue();
byte[] actualData = pipeWorker.GetReceivedDataSnapshot();
CollectionAssert.AreEqual(expectedData, actualData);
// Should only receive one 'healthy' state change per successfully written message
eventSink.Verify(
x => x.OnStateChanged(writer, QueuedPipeStringWriterState.Healthy, It.IsAny<Exception>()),
Times.Once);
eventSink.Verify(
x => x.OnStateChanged(writer, QueuedPipeStringWriterState.Stopped, It.IsAny<Exception>()),
Times.Once);
}
}
private class TestPipeReaderWorker : IDisposable
{
private readonly string pipeName;
private readonly PipeTransmissionMode transmissionMode;
private readonly AutoResetEvent receivedData = new AutoResetEvent(initialState: false);
private readonly ManualResetEvent readyToAccept = new ManualResetEvent(initialState: false);
private readonly ManualResetEvent shutdownEvent = new ManualResetEvent(initialState: false);
private int bufferLength = 0;
private byte[] buffer = new byte[16 * 1024];
private object bufferLock = new object();
private Thread thread;
private bool isRunning;
private bool isDisposed;
public TestPipeReaderWorker(string pipeName, PipeTransmissionMode transmissionMode)
{
this.pipeName = pipeName;
this.transmissionMode = transmissionMode;
}
public void Start()
{
if (!this.isRunning)
{
this.isRunning = true;
this.thread = new Thread(this.ThreadProc)
{
Name = nameof(TestPipeReaderWorker),
IsBackground = true
};
this.thread.Start();
}
}
public void WaitForReadyToAccept()
{
this.readyToAccept.WaitOne();
}
public void WaitForRecievedBytes(int count)
{
if (!this.isRunning)
{
throw new InvalidOperationException("Worker has been stopped so will never receieve new data");
}
int length;
while (true)
{
// Since the buffer can only grow (and we only care about waiting for a minimum length), we
// don't care that the length could increase after we've released the lock.
lock (this.bufferLock)
{
length = this.bufferLength;
}
if (length >= count)
{
break;
}
// Wait for more data (the buffer will grow)
this.receivedData.WaitOne();
}
}
public byte[] GetReceivedDataSnapshot()
{
if (this.isRunning)
{
throw new InvalidOperationException("Should stop the test pipe worker first");
}
if (this.isDisposed)
{
throw new ObjectDisposedException($"{nameof(TestPipeReaderWorker)}");
}
byte[] snapshot;
lock (this.bufferLock)
{
snapshot = new byte[this.bufferLength];
Array.Copy(this.buffer, snapshot, snapshot.Length);
}
return snapshot;
}
public void Stop()
{
if (this.isRunning)
{
this.isRunning = false;
this.shutdownEvent.Set();
this.thread.Join();
}
}
public void Dispose()
{
if (this.isDisposed)
{
return;
}
this.Stop();
this.isDisposed = true;
}
private void ThreadProc()
{
using (NamedPipeServerStream pipe = new NamedPipeServerStream(this.pipeName, PipeDirection.In, -1, this.transmissionMode, PipeOptions.Asynchronous))
{
// Signal that the pipe has been created and we're ready to accept clients
this.readyToAccept.Set();
pipe.WaitForConnection();
while (this.isRunning)
{
byte[] readBuffer = new byte[1024];
IAsyncResult asyncResult = pipe.BeginRead(readBuffer, offset: 0, count: readBuffer.Length, callback: null, state: null);
// Wait for a read operation to complete, or until we're told to shutdown
WaitHandle.WaitAny(new[] { asyncResult.AsyncWaitHandle, this.shutdownEvent });
if (this.isRunning)
{
// Complete the read
int nr = pipe.EndRead(asyncResult);
if (nr > 0)
{
// We actually read some data so append this to the main buffer
lock (this.bufferLock)
{
Array.Copy(readBuffer, 0, this.buffer, this.bufferLength, nr);
this.bufferLength += nr;
}
this.receivedData.Set();
}
else
{
// We got here because the pipe has been closed.
// If we've been asked to shutdown we will break on the next while-loop evaluation.
}
}
}
}
}
}
}
}

Просмотреть файл

@ -1,73 +0,0 @@
using Newtonsoft.Json;
using NUnit.Framework;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using System.Collections.Generic;
namespace Scalar.UnitTests.Tracing
{
[TestFixture]
public class TelemetryDaemonEventListenerTests
{
[TestCase]
public void TraceMessageDataIsCorrectFormat()
{
const string vfsVersion = "test-vfsVersion";
const string providerName = "test-ProviderName";
const string eventName = "test-eventName";
const EventLevel level = EventLevel.Error;
const EventOpcode opcode = EventOpcode.Start;
const string enlistmentId = "test-enlistmentId";
const string gitCommandSessionId = "test_sessionId";
const string payload = "test-payload";
Dictionary<string, object> expectedDict = new Dictionary<string, object>
{
["version"] = vfsVersion,
["providerName"] = providerName,
["eventName"] = eventName,
["eventLevel"] = (int)level,
["eventOpcode"] = (int)opcode,
["payload"] = new Dictionary<string, string>
{
["enlistmentId"] = enlistmentId,
["gitCommandSessionId"] = gitCommandSessionId,
["json"] = payload,
},
};
TelemetryDaemonEventListener.PipeMessage message = new TelemetryDaemonEventListener.PipeMessage
{
Version = vfsVersion,
ProviderName = providerName,
EventName = eventName,
EventLevel = level,
EventOpcode = opcode,
Payload = new TelemetryDaemonEventListener.PipeMessage.PipeMessagePayload
{
EnlistmentId = enlistmentId,
GitCommandSessionId = gitCommandSessionId,
Json = payload
},
};
string messageJson = message.ToJson();
Dictionary<string, object> actualDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(messageJson);
actualDict.Count.ShouldEqual(expectedDict.Count);
actualDict["version"].ShouldEqual(expectedDict["version"]);
actualDict["providerName"].ShouldEqual(expectedDict["providerName"]);
actualDict["eventName"].ShouldEqual(expectedDict["eventName"]);
actualDict["eventLevel"].ShouldEqual(expectedDict["eventLevel"]);
actualDict["eventOpcode"].ShouldEqual(expectedDict["eventOpcode"]);
Dictionary<string, string> expectedPayloadDict = (Dictionary<string, string>)expectedDict["payload"];
Dictionary<string, string> actualPayloadDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(actualDict["payload"].ToString());
actualPayloadDict.Count.ShouldEqual(expectedPayloadDict.Count);
actualPayloadDict["enlistmentId"].ShouldEqual(expectedPayloadDict["enlistmentId"]);
actualPayloadDict["gitCommandSessionId"].ShouldEqual(expectedPayloadDict["gitCommandSessionId"]);
actualPayloadDict["json"].ShouldEqual(expectedPayloadDict["json"]);
}
}
}

Просмотреть файл

@ -1,249 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Common.Tracing;
using Scalar.Tests.Should;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using Scalar.UnitTests.Mock.Upgrader;
using Scalar.Upgrader;
using System;
using System.Collections.Generic;
namespace Scalar.UnitTests.Upgrader
{
[TestFixture]
public class UpgradeOrchestratorTests
{
private const string ScalarVersion = "1.1.18115.1";
private delegate void TryGetNewerVersionCallback(out System.Version version, out string message);
private delegate void UpgradeAllowedCallback(out string message);
private delegate void TryRunPreUpgradeChecksCallback(out string delegateMessage);
private delegate void TryDownloadNewestVersionCallback(out string message);
private delegate void TryCreateAndConfigureDownloadDirectoryCallback(ITracer tracer, out string message);
private delegate void TryRunInstallerCallback(InstallActionWrapper installActionWrapper, out string error);
private MockTracer Tracer { get; set; }
private MockFileSystem FileSystem { get; set; }
private MockTextWriter Output { get; set; }
private MockInstallerPrerunChecker PreRunChecker { get; set; }
private Mock<LocalScalarConfig> MoqLocalConfig { get; set; }
private Mock<ProductUpgrader> MoqUpgrader { get; set; }
private UpgradeOrchestrator orchestrator { get; set; }
[SetUp]
public void Setup()
{
this.Tracer = new MockTracer();
this.FileSystem = new MockFileSystem(new MockDirectory(@"mock:\Scalar.Upgrades\Download", null, null));
this.Output = new MockTextWriter();
this.PreRunChecker = new MockInstallerPrerunChecker(this.Tracer);
this.PreRunChecker.Reset();
this.MoqUpgrader = this.DefaultUpgrader();
this.orchestrator = new WindowsUpgradeOrchestrator(
this.MoqUpgrader.Object,
this.Tracer,
this.FileSystem,
this.PreRunChecker,
input: null,
output: this.Output);
this.SetUpgradeAvailable(new Version(ScalarVersion), error: null);
}
[TestCase]
public void ExecuteSucceedsWhenUpgradeAvailable()
{
this.orchestrator.Execute();
this.VerifyOrchestratorInvokes(
upgradeAllowed: true,
queryNewestVersion: true,
downloadNewestVersion: true,
installNewestVersion: true,
cleanup: true);
this.orchestrator.ExitCode.ShouldEqual(ReturnCode.Success);
}
[TestCase]
public void ExecuteSucceedsWhenOnLatestVersion()
{
this.SetUpgradeAvailable(newVersion: null, error: null);
this.orchestrator.Execute();
this.VerifyOrchestratorInvokes(
upgradeAllowed: true,
queryNewestVersion: true,
downloadNewestVersion: false,
installNewestVersion: false,
cleanup: true);
this.orchestrator.ExitCode.ShouldEqual(ReturnCode.Success);
}
[TestCase]
public void ExecuteFailsWhenGetNewVersionFails()
{
string errorMessage = "Authentication error.";
this.SetUpgradeAvailable(newVersion: null, error: errorMessage);
this.orchestrator.Execute();
this.VerifyOrchestratorInvokes(
upgradeAllowed: true,
queryNewestVersion: true,
downloadNewestVersion: false,
installNewestVersion: false,
cleanup: true);
this.VerifyOutput("ERROR: Authentication error.");
this.orchestrator.ExitCode.ShouldEqual(ReturnCode.GenericError);
}
[TestCase]
public void ExecuteFailsWhenPrecheckFails()
{
this.PreRunChecker.SetReturnFalseOnCheck(MockInstallerPrerunChecker.FailOnCheckType.IsElevated);
this.orchestrator.Execute();
this.VerifyOrchestratorInvokes(
upgradeAllowed: true,
queryNewestVersion: false,
downloadNewestVersion: false,
installNewestVersion: false,
cleanup: true);
this.orchestrator.ExitCode.ShouldEqual(ReturnCode.GenericError);
}
[TestCase]
public void ExecuteFailsWhenDownloadFails()
{
this.MoqUpgrader.Setup(upgrader => upgrader.TryDownloadNewestVersion(out It.Ref<string>.IsAny))
.Callback(new TryDownloadNewestVersionCallback(
(out string delegateMessage) =>
{
delegateMessage = "Download error.";
}))
.Returns(false);
this.orchestrator.Execute();
this.VerifyOrchestratorInvokes(
upgradeAllowed: true,
queryNewestVersion: true,
downloadNewestVersion: true,
installNewestVersion: false,
cleanup: true);
this.VerifyOutput("ERROR: Download error.");
this.orchestrator.ExitCode.ShouldEqual(ReturnCode.GenericError);
}
[TestCase]
public void ExecuteFailsWhenRunInstallerFails()
{
this.MoqUpgrader.Setup(upgrader => upgrader.TryRunInstaller(It.IsAny<InstallActionWrapper>(), out It.Ref<string>.IsAny))
.Callback(new TryRunInstallerCallback((InstallActionWrapper installActionWrapper, out string delegateMessage) =>
{
delegateMessage = "Installer error.";
}))
.Returns(false);
this.orchestrator.Execute();
this.VerifyOrchestratorInvokes(
upgradeAllowed: true,
queryNewestVersion: true,
downloadNewestVersion: true,
installNewestVersion: true,
cleanup: true);
this.VerifyOutput("ERROR: Installer error.");
this.orchestrator.ExitCode.ShouldEqual(ReturnCode.GenericError);
}
public Mock<ProductUpgrader> DefaultUpgrader()
{
Mock<ProductUpgrader> mockUpgrader = new Mock<ProductUpgrader>();
mockUpgrader.Setup(upgrader => upgrader.UpgradeAllowed(out It.Ref<string>.IsAny))
.Callback(new UpgradeAllowedCallback((out string delegateMessage) =>
{
delegateMessage = string.Empty;
}))
.Returns(true);
string message = string.Empty;
mockUpgrader.Setup(upgrader => upgrader.TryDownloadNewestVersion(out It.Ref<string>.IsAny)).Returns(true);
mockUpgrader.Setup(upgrader => upgrader.TryRunInstaller(It.IsAny<InstallActionWrapper>(), out message)).Returns(true);
mockUpgrader.Setup(upgrader => upgrader.TryCleanup(out It.Ref<string>.IsAny)).Returns(true);
return mockUpgrader;
}
public void SetUpgradeAvailable(Version newVersion, string error)
{
bool upgradeResult = string.IsNullOrEmpty(error);
this.MoqUpgrader.Setup(upgrader => upgrader.TryQueryNewestVersion(out It.Ref<System.Version>.IsAny, out It.Ref<string>.IsAny))
.Callback(new TryGetNewerVersionCallback((out System.Version delegateVersion, out string delegateMessage) =>
{
delegateVersion = newVersion;
delegateMessage = error;
}))
.Returns(upgradeResult);
}
public void VerifyOrchestratorInvokes(
bool upgradeAllowed,
bool queryNewestVersion,
bool downloadNewestVersion,
bool installNewestVersion,
bool cleanup)
{
this.MoqUpgrader.Verify(
upgrader => upgrader.UpgradeAllowed(
out It.Ref<string>.IsAny),
upgradeAllowed ? Times.Once() : Times.Never());
this.MoqUpgrader.Verify(
upgrader => upgrader.TryQueryNewestVersion(
out It.Ref<System.Version>.IsAny,
out It.Ref<string>.IsAny),
queryNewestVersion ? Times.Once() : Times.Never());
this.MoqUpgrader.Verify(
upgrader => upgrader.TryDownloadNewestVersion(
out It.Ref<string>.IsAny),
downloadNewestVersion ? Times.Once() : Times.Never());
this.MoqUpgrader.Verify(
upgrader => upgrader.TryRunInstaller(
It.IsAny<InstallActionWrapper>(),
out It.Ref<string>.IsAny),
installNewestVersion ? Times.Once() : Times.Never());
this.MoqUpgrader.Verify(
upgrader => upgrader.TryCleanup(
out It.Ref<string>.IsAny),
cleanup ? Times.Once() : Times.Never());
}
public void VerifyOutput(string expectedMessage)
{
this.Output.AllLines.ShouldContain(
new List<string>() { expectedMessage },
(line, expectedLine) => { return line.Contains(expectedLine); });
}
}
}

Просмотреть файл

@ -1,44 +0,0 @@
using System;
namespace Scalar.UnitTests.Windows.Upgrader
{
public class MockProcessLauncher : Scalar.CommandLine.UpgradeVerb.ProcessLauncher
{
private int exitCode;
private bool hasExited;
private bool startResult;
public MockProcessLauncher(
int exitCode,
bool hasExited,
bool startResult)
{
this.exitCode = exitCode;
this.hasExited = hasExited;
this.startResult = startResult;
}
public bool IsLaunched { get; private set; }
public string LaunchPath { get; private set; }
public override bool HasExited
{
get { return this.hasExited; }
}
public override int ExitCode
{
get { return this.exitCode; }
}
public override bool TryStart(string path, string args, bool useShellExecute, out Exception exception)
{
this.LaunchPath = path;
this.IsLaunched = true;
exception = null;
return this.startResult;
}
}
}

Просмотреть файл

@ -1,75 +0,0 @@
using Moq;
using NUnit.Framework;
using Scalar.Common.NamedPipes;
using Scalar.Service.UI;
using Scalar.UnitTests.Mock.Common;
using System;
namespace Scalar.UnitTests.Windows.ServiceUI
{
[TestFixture]
public class ScalarToastRequestHandlerTests
{
private NamedPipeMessages.Notification.Request request;
private ScalarToastRequestHandler toastHandler;
private Mock<IToastNotifier> mockToastNotifier;
private MockTracer tracer;
[SetUp]
public void Setup()
{
this.tracer = new MockTracer();
this.mockToastNotifier = new Mock<IToastNotifier>(MockBehavior.Strict);
this.mockToastNotifier.SetupSet(toastNotifier => toastNotifier.UserResponseCallback = It.IsAny<Action<string>>()).Verifiable();
this.toastHandler = new ScalarToastRequestHandler(this.mockToastNotifier.Object, this.tracer);
this.request = new NamedPipeMessages.Notification.Request();
}
[TestCase]
public void UpgradeToastIsActionableAndContainsVersionInfo()
{
const string version = "1.0.956749.2";
this.request.Id = NamedPipeMessages.Notification.Request.Identifier.UpgradeAvailable;
this.request.NewVersion = version;
this.VerifyToastMessage(
expectedTitle: "New version " + version + " is available",
expectedMessage: "click Upgrade button",
expectedButtonTitle: "Upgrade",
expectedScalarCmd: "scalar upgrade --confirm");
}
[TestCase]
public void UnknownToastRequestGetsIgnored()
{
this.request.Id = (NamedPipeMessages.Notification.Request.Identifier)10;
this.toastHandler.HandleToastRequest(this.tracer, this.request);
this.mockToastNotifier.Verify(
toastNotifier => toastNotifier.Notify(
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string>()),
Times.Never());
}
private void VerifyToastMessage(
string expectedTitle,
string expectedMessage,
string expectedButtonTitle,
string expectedScalarCmd)
{
this.mockToastNotifier.Setup(toastNotifier => toastNotifier.Notify(
expectedTitle,
It.Is<string>(message => message.Contains(expectedMessage)),
expectedButtonTitle,
expectedScalarCmd));
this.toastHandler.HandleToastRequest(this.tracer, this.request);
this.mockToastNotifier.VerifyAll();
}
}
}

Просмотреть файл

@ -1,60 +0,0 @@
using Moq;
using NuGet.Packaging.Core;
using NuGet.Protocol.Core.Types;
using NUnit.Framework;
using Scalar.Common;
using Scalar.Platform.Windows;
using Scalar.Tests.Should;
using Scalar.UnitTests.Common.NuGetUpgrade;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Scalar.UnitTests.Windows.Common.Upgrader
{
[TestFixture]
public class WindowsNuGetUpgraderTests : NuGetUpgraderTests
{
public override ProductUpgraderPlatformStrategy CreateProductUpgraderPlatformStrategy()
{
return new WindowsProductUpgraderPlatformStrategy(this.mockFileSystem, this.tracer);
}
[TestCase]
public void TrySetupUpgradeApplicationDirectoryFailsIfCreateToolsDirectoryFails()
{
this.mockFileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed = false;
this.upgrader.TrySetupUpgradeApplicationDirectory(out string _, out string _).ShouldBeFalse();
this.mockFileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed = true;
}
[TestCase]
public void CanDownloadNewestVersionFailsIfDownloadDirectoryCreationFails()
{
Version actualNewestVersion;
string message;
List<IPackageSearchMetadata> availablePackages = new List<IPackageSearchMetadata>()
{
this.GeneratePackageSeachMetadata(new Version(CurrentVersion)),
this.GeneratePackageSeachMetadata(new Version(NewerVersion)),
};
string testDownloadPath = Path.Combine(this.downloadDirectoryPath, "testNuget.zip");
IPackageSearchMetadata newestAvailableVersion = availablePackages.Last();
this.mockNuGetFeed.Setup(foo => foo.QueryFeedAsync(NuGetFeedName)).ReturnsAsync(availablePackages);
this.mockNuGetFeed.Setup(foo => foo.DownloadPackageAsync(It.Is<PackageIdentity>(packageIdentity => packageIdentity == newestAvailableVersion.Identity))).ReturnsAsync(testDownloadPath);
bool success = this.upgrader.TryQueryNewestVersion(out actualNewestVersion, out message);
// Assert that no new version was returned
success.ShouldBeTrue($"Expecting TryQueryNewestVersion to have completed sucessfully. Error: {message}");
actualNewestVersion.ShouldEqual(newestAvailableVersion.Identity.Version.Version, "Actual new version does not match expected new version.");
this.mockFileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed = false;
bool downloadSuccessful = this.upgrader.TryDownloadNewestVersion(out message);
this.mockFileSystem.TryCreateOrUpdateDirectoryToAdminModifyPermissionsShouldSucceed = true;
downloadSuccessful.ShouldBeFalse();
}
}
}

Просмотреть файл

@ -1,59 +0,0 @@
using NUnit.Framework;
using Scalar.Common;
using Scalar.Platform.Windows;
using Scalar.Tests.Should;
using Scalar.UnitTests.Category;
using Scalar.UnitTests.Mock.Common;
using Scalar.UnitTests.Mock.FileSystem;
using System;
using System.IO;
namespace Scalar.UnitTests.Windows
{
[TestFixture]
public class WindowsFileBasedLockTests
{
[TestCase]
public void CreateLockWhenDirectoryMissing()
{
string parentPath = Path.Combine("mock:", "path", "to");
string lockPath = Path.Combine(parentPath, "lock");
MockTracer tracer = new MockTracer();
FileBasedLockFileSystem fs = new FileBasedLockFileSystem();
FileBasedLock fileBasedLock = new WindowsFileBasedLock(fs, tracer, lockPath);
fileBasedLock.TryAcquireLock().ShouldBeTrue();
fs.CreateDirectoryPath.ShouldNotBeNull();
fs.CreateDirectoryPath.ShouldEqual(parentPath);
}
[TestCase]
[Category(CategoryConstants.ExceptionExpected)]
public void AttemptToAcquireLockWhenAlreadyLocked()
{
string parentPath = Path.Combine("mock:", "path", "to");
string lockPath = Path.Combine(parentPath, "lock");
MockTracer tracer = new MockTracer();
FileBasedLockFileSystem fs = new FileBasedLockFileSystem();
FileBasedLock fileBasedLock = new WindowsFileBasedLock(fs, tracer, lockPath);
fileBasedLock.TryAcquireLock().ShouldBeTrue();
Assert.Throws<InvalidOperationException>(() => fileBasedLock.TryAcquireLock());
}
private class FileBasedLockFileSystem : ConfigurableFileSystem
{
public string CreateDirectoryPath { get; set; }
public override void CreateDirectory(string path)
{
this.CreateDirectoryPath = path;
}
public override Stream OpenFileStream(string path, FileMode fileMode, FileAccess fileAccess, FileShare shareMode, FileOptions options, bool flushesToDisk)
{
return new MemoryStream();
}
}
}
}

Просмотреть файл

@ -1,98 +1,93 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30406.18
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar", "Scalar\Scalar.csproj", "{31208ED8-5B83-4BE6-802A-18EE67434537}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Common", "Scalar.Common\Scalar.Common.csproj", "{179EAE33-265B-4698-BBC7-130F28F6D768}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Service", "Scalar.Service\Scalar.Service.csproj", "{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Upgrader", "Scalar.Upgrader\Scalar.Upgrader.csproj", "{424D0102-50EE-4CA6-A937-C8A89CE10103}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.UnitTests", "Scalar.UnitTests\Scalar.UnitTests.csproj", "{B1D1E8BE-D633-4624-A821-B222EB1B8020}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EB9427BB-456A-4319-8916-E782E0F5F6D3}"
ProjectSection(SolutionItems) = preProject
Dependencies.props = Dependencies.props
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
global.json = global.json
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.FunctionalTests", "Scalar.FunctionalTests\Scalar.FunctionalTests.csproj", "{C7E08779-6F45-4025-89E1-31346C9B234F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.TestInfrastructure", "Scalar.TestInfrastructure\Scalar.TestInfrastructure.csproj", "{77FC445D-FD03-4EE0-8582-7BD1437D9842}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.MSBuild", "Scalar.MSBuild\Scalar.MSBuild.csproj", "{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Installer.Mac", "Scalar.Installer.Mac\Scalar.Installer.Mac.csproj", "{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Installer.Windows", "Scalar.Installer.Windows\Scalar.Installer.Windows.csproj", "{913C7CBD-876C-45D8-B59E-D0849CD219E4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Service.UI", "Scalar.Service.UI\Scalar.Service.UI.csproj", "{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scalar.Packaging.Linux", "Scalar.Packaging.Linux\Scalar.Packaging.Linux.csproj", "{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{31208ED8-5B83-4BE6-802A-18EE67434537}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31208ED8-5B83-4BE6-802A-18EE67434537}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31208ED8-5B83-4BE6-802A-18EE67434537}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31208ED8-5B83-4BE6-802A-18EE67434537}.Release|Any CPU.Build.0 = Release|Any CPU
{179EAE33-265B-4698-BBC7-130F28F6D768}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{179EAE33-265B-4698-BBC7-130F28F6D768}.Debug|Any CPU.Build.0 = Debug|Any CPU
{179EAE33-265B-4698-BBC7-130F28F6D768}.Release|Any CPU.ActiveCfg = Release|Any CPU
{179EAE33-265B-4698-BBC7-130F28F6D768}.Release|Any CPU.Build.0 = Release|Any CPU
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Release|Any CPU.Build.0 = Release|Any CPU
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Debug|Any CPU.Build.0 = Debug|Any CPU
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Release|Any CPU.ActiveCfg = Release|Any CPU
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Release|Any CPU.Build.0 = Release|Any CPU
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Release|Any CPU.Build.0 = Release|Any CPU
{C7E08779-6F45-4025-89E1-31346C9B234F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7E08779-6F45-4025-89E1-31346C9B234F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7E08779-6F45-4025-89E1-31346C9B234F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7E08779-6F45-4025-89E1-31346C9B234F}.Release|Any CPU.Build.0 = Release|Any CPU
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Release|Any CPU.Build.0 = Release|Any CPU
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Release|Any CPU.Build.0 = Release|Any CPU
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Release|Any CPU.Build.0 = Release|Any CPU
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Release|Any CPU.Build.0 = Release|Any CPU
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Release|Any CPU.Build.0 = Release|Any CPU
{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FDE61E04-DC84-437F-A176-40CD62CDE05F}
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30406.18
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar", "Scalar\Scalar.csproj", "{31208ED8-5B83-4BE6-802A-18EE67434537}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Common", "Scalar.Common\Scalar.Common.csproj", "{179EAE33-265B-4698-BBC7-130F28F6D768}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Service", "Scalar.Service\Scalar.Service.csproj", "{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Upgrader", "Scalar.Upgrader\Scalar.Upgrader.csproj", "{424D0102-50EE-4CA6-A937-C8A89CE10103}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EB9427BB-456A-4319-8916-E782E0F5F6D3}"
ProjectSection(SolutionItems) = preProject
Dependencies.props = Dependencies.props
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
global.json = global.json
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.FunctionalTests", "Scalar.FunctionalTests\Scalar.FunctionalTests.csproj", "{C7E08779-6F45-4025-89E1-31346C9B234F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.TestInfrastructure", "Scalar.TestInfrastructure\Scalar.TestInfrastructure.csproj", "{77FC445D-FD03-4EE0-8582-7BD1437D9842}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.MSBuild", "Scalar.MSBuild\Scalar.MSBuild.csproj", "{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Installer.Mac", "Scalar.Installer.Mac\Scalar.Installer.Mac.csproj", "{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Installer.Windows", "Scalar.Installer.Windows\Scalar.Installer.Windows.csproj", "{913C7CBD-876C-45D8-B59E-D0849CD219E4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Service.UI", "Scalar.Service.UI\Scalar.Service.UI.csproj", "{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Packaging.Linux", "Scalar.Packaging.Linux\Scalar.Packaging.Linux.csproj", "{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{31208ED8-5B83-4BE6-802A-18EE67434537}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31208ED8-5B83-4BE6-802A-18EE67434537}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31208ED8-5B83-4BE6-802A-18EE67434537}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31208ED8-5B83-4BE6-802A-18EE67434537}.Release|Any CPU.Build.0 = Release|Any CPU
{179EAE33-265B-4698-BBC7-130F28F6D768}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{179EAE33-265B-4698-BBC7-130F28F6D768}.Debug|Any CPU.Build.0 = Debug|Any CPU
{179EAE33-265B-4698-BBC7-130F28F6D768}.Release|Any CPU.ActiveCfg = Release|Any CPU
{179EAE33-265B-4698-BBC7-130F28F6D768}.Release|Any CPU.Build.0 = Release|Any CPU
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Release|Any CPU.Build.0 = Release|Any CPU
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Debug|Any CPU.Build.0 = Debug|Any CPU
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Release|Any CPU.ActiveCfg = Release|Any CPU
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Release|Any CPU.Build.0 = Release|Any CPU
{C7E08779-6F45-4025-89E1-31346C9B234F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7E08779-6F45-4025-89E1-31346C9B234F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7E08779-6F45-4025-89E1-31346C9B234F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7E08779-6F45-4025-89E1-31346C9B234F}.Release|Any CPU.Build.0 = Release|Any CPU
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Release|Any CPU.Build.0 = Release|Any CPU
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Release|Any CPU.Build.0 = Release|Any CPU
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Release|Any CPU.Build.0 = Release|Any CPU
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Release|Any CPU.Build.0 = Release|Any CPU
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Release|Any CPU.Build.0 = Release|Any CPU
{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AAD540B9-E65F-4C0B-916C-4CB50DA7A7DB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FDE61E04-DC84-437F-A176-40CD62CDE05F}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -1,15 +0,0 @@
#!/bin/bash
. "$(dirname ${BASH_SOURCE[0]})/InitializeEnvironment.sh"
CONFIGURATION=$1
if [ -z $CONFIGURATION ]; then
CONFIGURATION=Debug
fi
TESTRESULTSDIR=$2
if [ -z $TESTRESULTSDIR ]; then
TESTRESULTSDIR=$SCALAR_OUTPUTDIR/TestResults
fi
dotnet test $SCALAR_SRCDIR/Scalar.sln --configuration $CONFIGURATION --logger trx --results-directory $TESTRESULTSDIR || exit 1

Просмотреть файл

@ -1,15 +0,0 @@
#!/bin/bash
. "$(dirname ${BASH_SOURCE[0]})/InitializeEnvironment.sh"
CONFIGURATION=$1
if [ -z $CONFIGURATION ]; then
CONFIGURATION=Debug
fi
TESTRESULTSDIR=$2
if [ -z $TESTRESULTSDIR ]; then
TESTRESULTSDIR=$SCALAR_OUTPUTDIR/TestResults
fi
dotnet test $SCALAR_SRCDIR/Scalar.sln --configuration $CONFIGURATION --logger trx --results-directory $TESTRESULTSDIR || exit 1

Просмотреть файл

@ -1,11 +0,0 @@
@ECHO OFF
CALL %~dp0\InitializeEnvironment.bat || EXIT /b 10
IF "%1"=="" (SET "Configuration=Debug") ELSE (SET "Configuration=%1")
IF "%2"=="" (SET "TestResultsDir=%SCALAR_OUTPUTDIR%\TestResults") ELSE (SET "TestResultsDir=%2" )
set RESULT=0
dotnet test %SCALAR_SRCDIR%\Scalar.sln --configuration %Configuration% --logger trx --results-directory %TestResultsDir% || set RESULT=1
exit /b %RESULT%