Added smoke tests to create and use package cache

This commit is contained in:
Kiran Challa 2017-05-01 15:13:03 -07:00
parent b854e200cd
commit d488a989a6
11 changed files with 467 additions and 32 deletions

View File

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26405.2
VisualStudioVersion = 15.0.26228.9
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7D749BDA-4638-4517-B66A-D40DEDEEB141}"
ProjectSection(SolutionItems) = preProject
@ -17,6 +17,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MusicStore.Test", "test\Mus
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MusicStore.E2ETests", "test\MusicStore.E2ETests\MusicStore.E2ETests.csproj", "{72A5F455-121F-4954-BF28-D712C6BE88EA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{88A30728-49E5-46C5-9CEC-9D8FD346A043}"
ProjectSection(SolutionItems) = preProject
build\dependencies.props = build\dependencies.props
build\repo.targets = build\repo.targets
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU

View File

@ -13,6 +13,7 @@
<CoreFxVersion>4.3.0</CoreFxVersion>
<NETStandardImplicitPackageVersion>$(BundledNETStandardPackageVersion)</NETStandardImplicitPackageVersion>
<NuGetPackagesVersion>4.0.0</NuGetPackagesVersion>
<TestSdkVersion>15.0.0</TestSdkVersion>
<XunitVersion>2.2.0</XunitVersion>
</PropertyGroup>

View File

@ -1,25 +1,50 @@
<Project>
<PropertyGroup>
<PrepareDependsOn Condition="'$(MUSICSTORE_ASPNETCORE_STORE_FEED)' != ''">$(PrepareDependsOn);UpdateNuGetConfig</PrepareDependsOn>
<MusicStoreE2ETestProject>$(RepositoryRoot)test\MusicStore.E2ETests\MusicStore.E2ETests.csproj</MusicStoreE2ETestProject>
</PropertyGroup>
<Target Name="_FilterTestProjects" BeforeTargets="TestProjects" Condition="'$(RUN_TESTS_ON_NANO)'=='true'">
<Target Name="UpdateNuGetConfig">
<UpdatePackageSource
NuGetConfigPath="$(RepositoryRoot)NuGet.config"
SourceName="AspNetCoreStore"
SourceUri="$(MUSICSTORE_ASPNETCORE_STORE_FEED)" />
<Message Text="Updated NuGet.Config with feed '$(MUSICSTORE_ASPNETCORE_STORE_FEED)'" Importance="High" />
</Target>
<Target Name="_RunNanoTestsOnly"
BeforeTargets="TestProjects"
DependsOnTargets="_FilterTestProjects"
Condition="'$(RUN_TESTS_ON_NANO)' == 'true' ">
<Warning Text="Updated test projects to run only the project '$(MusicStoreE2ETestProject)' as the variable 'RUN_TESTS_ON_NANO' is set to '$(RUN_TESTS_ON_NANO)'" />
<ItemGroup>
<ProjectsToTest Update="$(MusicStoreE2ETestProject)">
<AdditionalProperties>VSTestTestCaseFilter=E2ETests=NanoServer</AdditionalProperties>
</ProjectsToTest>
</ItemGroup>
</Target>
<Target Name="_RunPackageStoreTestsOnly"
BeforeTargets="TestProjects"
DependsOnTargets="_FilterTestProjects"
Condition="'$(MUSICSTORE_ASPNETCORE_STORE_FEED)' != '' ">
<Warning Text="Updated test projects to run only the project '$(MusicStoreE2ETestProject)' as the variable 'MUSICSTORE_ASPNETCORE_STORE_FEED' is set to non empty value. Package store tests require to not have RuntimeIdentifiers on MusicStore sample which would fail other standalone tests." />
<ItemGroup>
<ProjectsToTest Update="$(MusicStoreE2ETestProject)">
<AdditionalProperties>VSTestTestCaseFilter=smoketests=usestore</AdditionalProperties>
</ProjectsToTest>
</ItemGroup>
</Target>
<Target Name="_FilterTestProjects">
<ItemGroup>
<ProjectsToTest Remove="@(ProjectsToTest)" />
<ProjectsToTest Include="$(MusicStoreE2ETestProject)" />
</ItemGroup>
<Error Text="Could not find test projects to run" Condition="@(ProjectsToTest->Count()) == 0" />
<ItemGroup>
<ProjectsToTest Update="$(MusicStoreE2ETestProject)">
<AdditionalProperties>VSTestTestCaseFilter=E2ETests=NanoServer</AdditionalProperties>
</ProjectsToTest>
</ItemGroup>
</Target>
</Project>

View File

@ -7,32 +7,15 @@
<TargetFramework>netcoreapp2.0</TargetFramework>
<DefineConstants>$(DefineConstants);DEMO</DefineConstants>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<RuntimeIdentifiers>win7-x86;win7-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<RuntimeIdentifiers Condition="'$(MUSICSTORE_ASPNETCORE_STORE_FEED)' == ''">win7-x86;win7-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>
<Content Update="ForTesting\**\*" CopyToPublishDirectory="Never" Condition=" '$(PublishForTesting)' != 'true' "/>
<Content Update="ForTesting\**\*" CopyToPublishDirectory="Never" Condition=" '$(PublishForTesting)' != 'true' " />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.AspNetCoreModule" Version="$(AspNetCoreModuleVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Twitter" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.TagHelpers" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.HttpSys" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Session" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="$(AspNetCoreVersion)" />
</ItemGroup>
</Project>

View File

@ -50,11 +50,9 @@ namespace MusicStore
builder.ConfigureLogging(factory =>
{
factory.AddConsole();
var logLevel = string.Equals(environment, "Development", StringComparison.Ordinal) ? LogLevel.Information : LogLevel.Warning;
factory.AddFilter("Console", level => level >= logLevel);
factory.AddConsole((name, level) => level >= logLevel);
});
var host = builder.Build();

View File

@ -15,11 +15,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NuGet.Packaging" Version="$(NuGetPackagesVersion)" />
<PackageReference Include="NuGet.Protocol.Core.v3" Version="$(NuGetPackagesVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(AspNetIntegrationTestingVersion)" />
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.CommandLineUtils.Sources" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="$(AspNetCoreVersion)" />

View File

@ -0,0 +1,53 @@
using System;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
namespace E2ETests
{
public class BaseStoreSetupFixture : IDisposable
{
private readonly IDisposable _logToken;
private readonly ILogger<BaseStoreSetupFixture> _logger;
private readonly Store _store;
public BaseStoreSetupFixture(bool createInDefaultLocation, string loggerName)
{
if (!Store.IsEnabled())
{
return;
}
var testLog = AssemblyTestLog.ForAssembly(typeof(BaseStoreSetupFixture).Assembly);
ILoggerFactory loggerFactory;
_logToken = testLog.StartTestLog(null, loggerName, out loggerFactory, testName: loggerName);
_logger = loggerFactory.CreateLogger<BaseStoreSetupFixture>();
CreateStoreInDefaultLocation = createInDefaultLocation;
_logger.LogInformation(
"Setting up store in the location: {location}",
createInDefaultLocation ? "default" : "custom");
_store = new Store(loggerFactory);
StoreDirectory = _store.CreateStore(createInDefaultLocation);
}
public bool CreateStoreInDefaultLocation { get; }
public string StoreDirectory { get; }
public void Dispose()
{
if (_store != null)
{
_store.Dispose();
}
if (_logToken != null)
{
_logToken.Dispose();
}
}
}
}

View File

@ -0,0 +1,22 @@
namespace E2ETests
{
public class DefaultLocationSetupFixture : BaseStoreSetupFixture
{
public DefaultLocationSetupFixture() :
base(
createInDefaultLocation: true,
loggerName: nameof(DefaultLocationSetupFixture))
{
}
}
public class CustomLocationSetupFixture : BaseStoreSetupFixture
{
public CustomLocationSetupFixture() :
base(
createInDefaultLocation: false,
loggerName: nameof(CustomLocationSetupFixture))
{
}
}
}

View File

@ -0,0 +1,70 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
using Xunit.Abstractions;
namespace E2ETests
{
public class SmokeTestsUsingDefaultLocation : IClassFixture<DefaultLocationSetupFixture>
{
private readonly DefaultLocationSetupFixture _testFixture;
private readonly ITestOutputHelper _output;
public SmokeTestsUsingDefaultLocation(
DefaultLocationSetupFixture testFixure,
ITestOutputHelper output)
{
_testFixture = testFixure;
_output = output;
}
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
[EnvironmentVariableSkipCondition(Store.MusicStoreAspNetCoreStoreFeed, null, SkipOnMatch = false)]
[ConditionalTheory]
[Trait("smoketests", "usestore")]
[Trait("smoketests", "usestore-defaultlocation")]
[InlineData(ServerType.Kestrel)]
[InlineData(ServerType.WebListener)]
public async Task DefaultLocation(ServerType serverType)
{
var tests = new SmokeTestsUsingStoreHelper(_output);
await tests.SmokeTestSuite(
serverType,
_testFixture.CreateStoreInDefaultLocation,
_testFixture.StoreDirectory);
}
}
public class SmokeTestsUsingInCustomLocation : IClassFixture<CustomLocationSetupFixture>
{
private readonly CustomLocationSetupFixture _testFixture;
private readonly ITestOutputHelper _output;
public SmokeTestsUsingInCustomLocation(
CustomLocationSetupFixture testFixure,
ITestOutputHelper output)
{
_testFixture = testFixure;
_output = output;
}
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
[EnvironmentVariableSkipCondition(Store.MusicStoreAspNetCoreStoreFeed, null, SkipOnMatch = false)]
[ConditionalTheory]
[Trait("smoketests", "usestore")]
[Trait("smoketests", "usestore-customlocation")]
[InlineData(ServerType.Kestrel)]
[InlineData(ServerType.WebListener)]
public async Task CustomLocation(ServerType serverType)
{
var tests = new SmokeTestsUsingStoreHelper(_output);
await tests.SmokeTestSuite(
serverType,
_testFixture.CreateStoreInDefaultLocation,
_testFixture.StoreDirectory);
}
}
}

View File

@ -0,0 +1,69 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.Extensions.Logging.Testing;
using Xunit;
using Xunit.Abstractions;
namespace E2ETests
{
public class SmokeTestsUsingStoreHelper : LoggedTest
{
public SmokeTestsUsingStoreHelper(ITestOutputHelper output) : base(output)
{
}
public async Task SmokeTestSuite(ServerType serverType, bool isStoreInDefaultLocation, string storeDirectory)
{
var targetFramework = "netcoreapp2.0";
var testName = $"SmokeTestsUsingStore_{serverType}";
using (StartLog(out var loggerFactory, testName))
{
var logger = loggerFactory.CreateLogger(nameof(SmokeTestsUsingStoreHelper));
var musicStoreDbName = DbUtils.GetUniqueName();
var deploymentParameters = new DeploymentParameters(
Helpers.GetApplicationPath(ApplicationType.Portable), serverType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64)
{
EnvironmentName = "SocialTesting",
SiteName = "MusicStoreTestSiteUsingStore",
PublishApplicationBeforeDeployment = true,
PreservePublishedApplicationForDebugging = Helpers.PreservePublishedApplicationForDebugging,
TargetFramework = targetFramework,
Configuration = Helpers.GetCurrentBuildConfiguration(),
ApplicationType = ApplicationType.Portable,
UserAdditionalCleanup = parameters =>
{
DbUtils.DropDatabase(musicStoreDbName, logger);
}
};
// Override the connection strings using environment based configuration
deploymentParameters.EnvironmentVariables
.Add(new KeyValuePair<string, string>(
MusicStoreConfig.ConnectionStringKey,
DbUtils.CreateConnectionString(musicStoreDbName)));
if (!isStoreInDefaultLocation)
{
deploymentParameters.EnvironmentVariables.Add(
new KeyValuePair<string, string>("DOTNET_SHARED_STORE", storeDirectory));
}
using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
{
var deploymentResult = await deployer.DeployAsync();
var mvcCoreDllPath = Path.Combine(deploymentResult.ContentRoot, "Microsoft.AspNetCore.Mvc.Core.dll");
var fileInfo = new FileInfo(mvcCoreDllPath);
Assert.False(
File.Exists(mvcCoreDllPath),
$"The file '{fileInfo.Name}.{fileInfo.Extension}' was not expected to be present in the publish directory");
await SmokeTestHelper.RunTestsAsync(deploymentResult, logger);
}
}
}
}
}

View File

@ -0,0 +1,205 @@
using System;
using System.Linq;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
using NuGet.Configuration;
using NuGet.Packaging.Core;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;
using System.Threading;
namespace E2ETests
{
internal class Store : IDisposable
{
public const string MusicStoreAspNetCoreStoreFeed = "MUSICSTORE_ASPNETCORE_STORE_FEED";
private readonly ILogger _logger;
private string _storeDir;
private string _tempDir;
public Store(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Store>();
}
public string CreateStore(bool createInDefaultLocation)
{
var storeParentDir = GetStoreParentDirectory(createInDefaultLocation);
InstallStore(storeParentDir);
_storeDir = Path.Combine(storeParentDir, "store");
return _storeDir;
}
public void Dispose()
{
if (string.IsNullOrEmpty(_storeDir))
{
return;
}
if (Helpers.PreservePublishedApplicationForDebugging)
{
_logger.LogInformation("Skipping deleting the store as it has been disabled");
}
else
{
_logger.LogInformation("Deleting the store...");
RetryHelper.RetryOperation(
() => Directory.Delete(_storeDir, recursive: true),
e => _logger.LogError($"Failed to delete directory : {e.Message}"),
retryCount: 3,
retryDelayMilliseconds: 100);
RetryHelper.RetryOperation(
() => Directory.Delete(_tempDir, recursive: true),
e => _logger.LogError($"Failed to delete directory : {e.Message}"),
retryCount: 3,
retryDelayMilliseconds: 100);
}
}
public static bool IsEnabled()
{
var storeFeed = Environment.GetEnvironmentVariable(MusicStoreAspNetCoreStoreFeed);
return !string.IsNullOrEmpty(storeFeed);
}
private void InstallStore(string storeParentDir)
{
var packageId = "Build.RS";
var storeFeed = Environment.GetEnvironmentVariable(MusicStoreAspNetCoreStoreFeed);
if (string.IsNullOrEmpty(storeFeed))
{
_logger.LogError("The feed for the store package was not provided." +
$"Set the environment variable '{MusicStoreAspNetCoreStoreFeed}' and try again.");
throw new InvalidOperationException(
$"The environment variable '{MusicStoreAspNetCoreStoreFeed}' is not defined or is empty.");
}
else
{
_logger.LogInformation($"Using the feed {storeFeed} for the store package");
}
// Get the version information from the attribute which is typically the same as the nuget package version
// Example:
// [assembly: AssemblyInformationalVersion("2.0.0-preview1-24847")]
var aspnetCoreHttpAssembly = typeof(Microsoft.AspNetCore.Http.FormCollection).Assembly;
var obj = aspnetCoreHttpAssembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), inherit: false).FirstOrDefault();
var assemblyInformationVersionAttribute = obj as AssemblyInformationalVersionAttribute;
if (assemblyInformationVersionAttribute == null)
{
throw new InvalidOperationException($"Could not find {nameof(assemblyInformationVersionAttribute)} from the assembly {aspnetCoreHttpAssembly.FullName}");
}
_logger.LogInformation($"Downloading package with id {packageId} and version {assemblyInformationVersionAttribute.InformationalVersion} from feed {storeFeed}");
_tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
var sourceRepository = Repository.Factory.GetCoreV2(new PackageSource(storeFeed));
var downloadResource = sourceRepository.GetResource<DownloadResource>();
var result = downloadResource.GetDownloadResourceResultAsync(
new PackageIdentity(packageId, NuGetVersion.Parse(assemblyInformationVersionAttribute.InformationalVersion)),
new PackageDownloadContext(
new SourceCacheContext() { NoCache = true, DirectDownload = true },
_tempDir,
directDownload: true),
null,
NuGet.Common.NullLogger.Instance,
CancellationToken.None)
.Result;
if (result.Status != DownloadResourceResultStatus.Available)
{
_logger.LogError($"Failed to download the package. Status: {result.Status}");
throw new InvalidOperationException("Unable to download the store package");
}
var zipFile = Path.Combine(_tempDir, "Build.RS.zip");
using (var targetStream = File.Create(zipFile))
{
using (result.PackageStream)
{
result.PackageStream.CopyTo(targetStream);
}
}
_logger.LogInformation($"Package downloaded and saved as zip file at {zipFile}");
var zipFileExtracted = Path.Combine(_tempDir, "extracted");
ZipFile.ExtractToDirectory(zipFile, zipFileExtracted);
_logger.LogInformation($"Package extracted at {zipFileExtracted}");
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
string fileNameWithExtension = null;
foreach (var file in new DirectoryInfo(zipFileExtracted).GetFiles())
{
if (file.Name.StartsWith($"{packageId}.winx64"))
{
using (var zipArchive = ZipFile.Open(file.FullName, ZipArchiveMode.Read))
{
var mvcCoreDllEntry = zipArchive.Entries
.Where(entry => string.Equals(entry.Name, "Microsoft.AspNetCore.Mvc.Core.dll", StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
if (mvcCoreDllEntry != null && mvcCoreDllEntry.FullName.Contains(assemblyInformationVersionAttribute.InformationalVersion))
{
fileNameWithExtension = file.Name;
break;
}
}
}
}
if (string.IsNullOrEmpty(fileNameWithExtension))
{
throw new InvalidOperationException(
$"Could not find a store zip file with version {assemblyInformationVersionAttribute.InformationalVersion}");
}
var storeZipFile = Path.Combine(zipFileExtracted, fileNameWithExtension);
ZipFile.ExtractToDirectory(storeZipFile, storeParentDir);
_logger.LogInformation($"Extracted the store zip file '{storeZipFile}' to '{storeParentDir}'");
}
else
{
throw new NotImplementedException();
}
}
private string GetStoreParentDirectory(bool createInDefaultLocation)
{
string storeParentDir;
if (createInDefaultLocation)
{
// On Windows: ..\.dotnet\x64\dotnet.exe
// On Linux : ../.dotnet/dotnet
var dotnetDir = new FileInfo(DotNetMuxer.MuxerPath).Directory.FullName;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
storeParentDir = dotnetDir;
}
else
{
storeParentDir = Path.Combine(dotnetDir, "x64");
}
}
else
{
storeParentDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
}
return storeParentDir;
}
}
}