Merge remote-tracking branch 'origin/develop' into feature/#128-cookie-proxying-and-auto-redirect-configuration

This commit is contained in:
Oleksandr Yershov 2017-10-09 14:44:16 +03:00
commit 8bc5819f90
9 changed files with 292 additions and 45 deletions

View File

@ -1,6 +1,7 @@
#tool "nuget:?package=GitVersion.CommandLine" #tool "nuget:?package=GitVersion.CommandLine"
#tool "nuget:?package=GitReleaseNotes" #tool "nuget:?package=GitReleaseNotes"
#addin "nuget:?package=Cake.Json" #addin nuget:?package=Cake.Json
#addin nuget:?package=Newtonsoft.Json&version=9.0.1
#tool "nuget:?package=OpenCover" #tool "nuget:?package=OpenCover"
#tool "nuget:?package=ReportGenerator" #tool "nuget:?package=ReportGenerator"
#tool coveralls.net #tool coveralls.net

117
build.ps1
View File

@ -21,34 +21,35 @@ The build script target to run.
The build configuration to use. The build configuration to use.
.PARAMETER Verbosity .PARAMETER Verbosity
Specifies the amount of information to be displayed. Specifies the amount of information to be displayed.
.PARAMETER ShowDescription
Shows description about tasks.
.PARAMETER DryRun
Performs a dry run.
.PARAMETER Experimental .PARAMETER Experimental
Tells Cake to use the latest Roslyn release. Uses the nightly builds of the Roslyn script engine.
.PARAMETER WhatIf
Performs a dry run of the build script.
No tasks will be executed.
.PARAMETER Mono .PARAMETER Mono
Tells Cake to use the Mono scripting engine. Uses the Mono Compiler rather than the Roslyn script engine.
.PARAMETER SkipToolPackageRestore .PARAMETER SkipToolPackageRestore
Skips restoring of packages. Skips restoring of packages.
.PARAMETER ScriptArgs .PARAMETER ScriptArgs
Remaining arguments are added here. Remaining arguments are added here.
.LINK .LINK
http://cakebuild.net https://cakebuild.net
#> #>
[CmdletBinding()] [CmdletBinding()]
Param( Param(
[string]$Script = "build.cake", [string]$Script = "build.cake",
[string]$Target = "Default", [string]$Target,
[ValidateSet("Release", "Debug")] [string]$Configuration,
[string]$Configuration = "Release",
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
[string]$Verbosity = "Verbose", [string]$Verbosity,
[switch]$ShowDescription,
[Alias("WhatIf", "Noop")]
[switch]$DryRun,
[switch]$Experimental, [switch]$Experimental,
[Alias("DryRun","Noop")]
[switch]$WhatIf,
[switch]$Mono, [switch]$Mono,
[switch]$SkipToolPackageRestore, [switch]$SkipToolPackageRestore,
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
@ -80,6 +81,15 @@ function MD5HashFile([string] $filePath)
} }
} }
function GetProxyEnabledWebClient
{
$wc = New-Object System.Net.WebClient
$proxy = [System.Net.WebRequest]::GetSystemWebProxy()
$proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials
$wc.Proxy = $proxy
return $wc
}
Write-Host "Preparing to run build script..." Write-Host "Preparing to run build script..."
if(!$PSScriptRoot){ if(!$PSScriptRoot){
@ -87,31 +97,15 @@ if(!$PSScriptRoot){
} }
$TOOLS_DIR = Join-Path $PSScriptRoot "tools" $TOOLS_DIR = Join-Path $PSScriptRoot "tools"
$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins"
$MODULES_DIR = Join-Path $TOOLS_DIR "Modules"
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" $NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" $PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" $PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
# Should we use mono? $MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
$UseMono = "";
if($Mono.IsPresent) {
Write-Verbose -Message "Using the Mono based scripting engine."
$UseMono = "-mono"
}
# Should we use the new Roslyn?
$UseExperimental = "";
if($Experimental.IsPresent -and !($Mono.IsPresent)) {
Write-Verbose -Message "Using experimental version of Roslyn."
$UseExperimental = "-experimental"
}
# Is this a dry run?
$UseDryRun = "";
if($WhatIf.IsPresent) {
$UseDryRun = "-dryrun"
}
# Make sure tools folder exists # Make sure tools folder exists
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
@ -122,7 +116,9 @@ if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
# Make sure that packages.config exist. # Make sure that packages.config exist.
if (!(Test-Path $PACKAGES_CONFIG)) { if (!(Test-Path $PACKAGES_CONFIG)) {
Write-Verbose -Message "Downloading packages.config..." Write-Verbose -Message "Downloading packages.config..."
try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { try {
$wc = GetProxyEnabledWebClient
$wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
Throw "Could not download packages.config." Throw "Could not download packages.config."
} }
} }
@ -130,7 +126,7 @@ if (!(Test-Path $PACKAGES_CONFIG)) {
# Try find NuGet.exe in path if not exists # Try find NuGet.exe in path if not exists
if (!(Test-Path $NUGET_EXE)) { if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Trying to find nuget.exe in PATH..." Write-Verbose -Message "Trying to find nuget.exe in PATH..."
$existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
$NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
@ -142,7 +138,8 @@ if (!(Test-Path $NUGET_EXE)) {
if (!(Test-Path $NUGET_EXE)) { if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Downloading NuGet.exe..." Write-Verbose -Message "Downloading NuGet.exe..."
try { try {
(New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) $wc = GetProxyEnabledWebClient
$wc.DownloadFile($NUGET_URL, $NUGET_EXE)
} catch { } catch {
Throw "Could not download NuGet.exe." Throw "Could not download NuGet.exe."
} }
@ -175,6 +172,41 @@ if(-Not $SkipToolPackageRestore.IsPresent) {
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
} }
Write-Verbose -Message ($NuGetOutput | out-string) Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore addins from NuGet
if (Test-Path $ADDINS_PACKAGES_CONFIG) {
Push-Location
Set-Location $ADDINS_DIR
Write-Verbose -Message "Restoring addins from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet addins."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Restore modules from NuGet
if (Test-Path $MODULES_PACKAGES_CONFIG) {
Push-Location
Set-Location $MODULES_DIR
Write-Verbose -Message "Restoring modules from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet modules."
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location Pop-Location
} }
@ -183,7 +215,20 @@ if (!(Test-Path $CAKE_EXE)) {
Throw "Could not find Cake.exe at $CAKE_EXE" Throw "Could not find Cake.exe at $CAKE_EXE"
} }
# Build Cake arguments
$cakeArguments = @("$Script");
if ($Target) { $cakeArguments += "-target=$Target" }
if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
if ($ShowDescription) { $cakeArguments += "-showdescription" }
if ($DryRun) { $cakeArguments += "-dryrun" }
if ($Experimental) { $cakeArguments += "-experimental" }
if ($Mono) { $cakeArguments += "-mono" }
$cakeArguments += $ScriptArgs
# Start Cake # Start Cake
Write-Host "Running build script..." Write-Host "Running build script..."
Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" &$CAKE_EXE $cakeArguments
exit $LASTEXITCODE exit $LASTEXITCODE

View File

@ -184,7 +184,7 @@ namespace Ocelot.Configuration.Creator
private string CreateReRouteKey(FileReRoute fileReRoute) private string CreateReRouteKey(FileReRoute fileReRoute)
{ {
//note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain //note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain
var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}{fileReRoute.UpstreamHttpMethod}"; var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
return loadBalancerKey; return loadBalancerKey;
} }

View File

@ -6,6 +6,7 @@ using Ocelot.Configuration.Provider;
using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Errors; using Ocelot.Errors;
using Ocelot.Responses; using Ocelot.Responses;
using Ocelot.Utilities;
namespace Ocelot.DownstreamRouteFinder.Finder namespace Ocelot.DownstreamRouteFinder.Finder
{ {
@ -24,6 +25,8 @@ namespace Ocelot.DownstreamRouteFinder.Finder
public async Task<Response<DownstreamRoute>> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod) public async Task<Response<DownstreamRoute>> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod)
{ {
upstreamUrlPath = upstreamUrlPath.SetLastCharacterAs('/');
var configuration = await _configProvider.Get(); var configuration = await _configProvider.Get();
var applicableReRoutes = configuration.Data.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower())); var applicableReRoutes = configuration.Data.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower()));

View File

@ -30,7 +30,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
var upstreamUrlPath = context.Request.Path.ToString().SetLastCharacterAs('/'); var upstreamUrlPath = context.Request.Path.ToString();
_logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath); _logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath);

View File

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.File; using Ocelot.Configuration.File;
using Shouldly;
using TestStack.BDDfy; using TestStack.BDDfy;
using Xunit; using Xunit;
@ -15,6 +16,7 @@ namespace Ocelot.AcceptanceTests
{ {
private IWebHost _builder; private IWebHost _builder;
private readonly Steps _steps; private readonly Steps _steps;
private string _downstreamPath;
public RoutingTests() public RoutingTests()
{ {
@ -232,6 +234,34 @@ namespace Ocelot.AcceptanceTests
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_not_add_trailing_slash_to_downstream_url()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/api/products/{productId}",
DownstreamScheme = "http",
DownstreamHost = "localhost",
DownstreamPort = 51879,
UpstreamPathTemplate = "/products/{productId}",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunning())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/1"))
.Then(x => ThenTheDownstreamUrlPathShouldBe("/api/products/1"))
.BDDfy();
}
[Fact] [Fact]
public void should_return_response_201_with_simple_url() public void should_return_response_201_with_simple_url()
{ {
@ -379,11 +409,11 @@ namespace Ocelot.AcceptanceTests
.UseKestrel() .UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration() .UseIISIntegration()
.UseUrls(url)
.Configure(app => .Configure(app =>
{ {
app.Run(async context => app.Run(async context =>
{ {
_downstreamPath = context.Request.PathBase.Value;
context.Response.StatusCode = statusCode; context.Response.StatusCode = statusCode;
await context.Response.WriteAsync(responseBody); await context.Response.WriteAsync(responseBody);
}); });
@ -393,6 +423,11 @@ namespace Ocelot.AcceptanceTests
_builder.Start(); _builder.Start();
} }
internal void ThenTheDownstreamUrlPathShouldBe(string expectedDownstreamPath)
{
_downstreamPath.ShouldBe(expectedDownstreamPath);
}
public void Dispose() public void Dispose()
{ {
_builder?.Dispose(); _builder?.Dispose();

View File

@ -36,7 +36,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void should_return_route() public void should_return_route()
{ {
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher/"))
.And(x =>x.GivenTheTemplateVariableAndNameFinderReturns( .And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
new OkResponse<List<UrlPathPlaceholderNameAndValue>>( new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
new List<UrlPathPlaceholderNameAndValue>()))) new List<UrlPathPlaceholderNameAndValue>())))
@ -65,6 +65,39 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_append_slash_to_upstream_url_path()
{
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("matchInUrlMatcher"))
.And(x =>x.GivenTheTemplateVariableAndNameFinderReturns(
new OkResponse<List<UrlPathPlaceholderNameAndValue>>(
new List<UrlPathPlaceholderNameAndValue>())))
.And(x => x.GivenTheConfigurationIs(new List<ReRoute>
{
new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamPathTemplate("someUpstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.WithUpstreamTemplatePattern("someUpstreamPath")
.Build()
}, string.Empty
))
.And(x => x.GivenTheUrlMatcherReturns(new OkResponse<UrlMatch>(new UrlMatch(true))))
.And(x => x.GivenTheUpstreamHttpMethodIs("Get"))
.When(x => x.WhenICallTheFinder())
.Then(
x => x.ThenTheFollowingIsReturned(new DownstreamRoute(
new List<UrlPathPlaceholderNameAndValue>(),
new ReRouteBuilder()
.WithDownstreamPathTemplate("someDownstreamPath")
.WithUpstreamHttpMethod(new List<string> { "Get" })
.Build()
)))
.And(x => x.ThenTheUrlMatcherIsCalledCorrectly("matchInUrlMatcher/"))
.BDDfy();
}
[Fact] [Fact]
public void should_return_route_if_upstream_path_and_upstream_template_are_the_same() public void should_return_route_if_upstream_path_and_upstream_template_are_the_same()
{ {
@ -137,7 +170,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
[Fact] [Fact]
public void should_not_return_route() public void should_not_return_route()
{ {
this.Given(x => x.GivenThereIsAnUpstreamUrlPath("dontMatchPath")) this.Given(x => x.GivenThereIsAnUpstreamUrlPath("dontMatchPath/"))
.And(x => x.GivenTheConfigurationIs(new List<ReRoute> .And(x => x.GivenTheConfigurationIs(new List<ReRoute>
{ {
new ReRouteBuilder() new ReRouteBuilder()
@ -269,6 +302,12 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
.Verify(x => x.Match(_upstreamUrlPath, _reRoutesConfig[0].UpstreamPathTemplate.Value), Times.Once); .Verify(x => x.Match(_upstreamUrlPath, _reRoutesConfig[0].UpstreamPathTemplate.Value), Times.Once);
} }
private void ThenTheUrlMatcherIsCalledCorrectly(string expectedUpstreamUrlPath)
{
_mockMatcher
.Verify(x => x.Match(expectedUpstreamUrlPath, _reRoutesConfig[0].UpstreamPathTemplate.Value), Times.Once);
}
private void ThenTheUrlMatcherIsNotCalled() private void ThenTheUrlMatcherIsNotCalled()
{ {
_mockMatcher _mockMatcher

View File

@ -0,0 +1,124 @@
using Xunit;
using Shouldly;
using Ocelot.Authorisation;
using Ocelot.Infrastructure.Claims.Parser;
using Moq;
using System.Collections.Generic;
using System.Security.Claims;
using Ocelot.Responses;
using TestStack.BDDfy;
using Ocelot.Errors;
namespace Ocelot.UnitTests.Infrastructure
{
public class ScopesAuthoriserTests
{
private ScopesAuthoriser _authoriser;
public Mock<IClaimsParser> _parser;
private ClaimsPrincipal _principal;
private List<string> _allowedScopes;
private Response<bool> _result;
public ScopesAuthoriserTests()
{
_parser = new Mock<IClaimsParser>();
_authoriser = new ScopesAuthoriser(_parser.Object);
}
[Fact]
public void should_return_ok_if_no_allowed_scopes()
{
this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
.And(_ => GivenTheFollowing(new List<string>()))
.When(_ => WhenIAuthorise())
.Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
.BDDfy();
}
[Fact]
public void should_return_ok_if_null_allowed_scopes()
{
this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
.And(_ => GivenTheFollowing((List<string>)null))
.When(_ => WhenIAuthorise())
.Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
.BDDfy();
}
[Fact]
public void should_return_error_if_claims_parser_returns_error()
{
var fakeError = new FakeError();
this.Given(_ => GivenTheFollowing(new ClaimsPrincipal()))
.And(_ => GivenTheParserReturns(new ErrorResponse<List<string>>(fakeError)))
.And(_ => GivenTheFollowing(new List<string>(){"doesntmatter"}))
.When(_ => WhenIAuthorise())
.Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
.BDDfy();
}
[Fact]
public void should_match_scopes_and_return_ok_result()
{
var claimsPrincipal = new ClaimsPrincipal();
var allowedScopes = new List<string>(){"someScope"};
this.Given(_ => GivenTheFollowing(claimsPrincipal))
.And(_ => GivenTheParserReturns(new OkResponse<List<string>>(allowedScopes)))
.And(_ => GivenTheFollowing(allowedScopes))
.When(_ => WhenIAuthorise())
.Then(_ => ThenTheFollowingIsReturned(new OkResponse<bool>(true)))
.BDDfy();
}
[Fact]
public void should_not_match_scopes_and_return_error_result()
{
var fakeError = new FakeError();
var claimsPrincipal = new ClaimsPrincipal();
var allowedScopes = new List<string>(){"someScope"};
var userScopes = new List<string>(){"anotherScope"};
this.Given(_ => GivenTheFollowing(claimsPrincipal))
.And(_ => GivenTheParserReturns(new OkResponse<List<string>>(userScopes)))
.And(_ => GivenTheFollowing(allowedScopes))
.When(_ => WhenIAuthorise())
.Then(_ => ThenTheFollowingIsReturned(new ErrorResponse<bool>(fakeError)))
.BDDfy();
}
private void GivenTheParserReturns(Response<List<string>> response)
{
_parser.Setup(x => x.GetValuesByClaimType(It.IsAny<IEnumerable<Claim>>(), It.IsAny<string>())).Returns(response);
}
private void GivenTheFollowing(ClaimsPrincipal principal)
{
_principal = principal;
}
private void GivenTheFollowing(List<string> allowedScopes)
{
_allowedScopes = allowedScopes;
}
private void WhenIAuthorise()
{
_result = _authoriser.Authorise(_principal, _allowedScopes);
}
private void ThenTheFollowingIsReturned(Response<bool> expected)
{
_result.Data.ShouldBe(expected.Data);
_result.IsError.ShouldBe(expected.IsError);
}
}
public class FakeError : Error
{
public FakeError() : base("fake error", OcelotErrorCode.CannotAddDataError)
{
}
}
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Cake" version="0.17.0" /> <package id="Cake" version="0.22.2" />
</packages> </packages>