public void BuildEndpoints_JustHostWithWildcard_Works() { // Arrange var builder = Create <RuntimeRouteBuilder>(); var parsedRoute = new ParsedRoute { RouteId = "route1", Host = "*.example.com", Priority = 12, }; var cluster = new ClusterInfo("cluster1", new DestinationManager(), new Mock <IProxyHttpClientFactory>().Object); var routeInfo = new RouteInfo("route1"); // Act var config = builder.Build(parsedRoute, cluster, routeInfo); // Assert Assert.Same(cluster, config.Cluster); Assert.Equal(12, config.Priority); Assert.Equal(parsedRoute.GetConfigHash(), config.ConfigHash); Assert.Single(config.Endpoints); var routeEndpoint = config.Endpoints[0] as AspNetCore.Routing.RouteEndpoint; Assert.Equal("route1", routeEndpoint.DisplayName); Assert.Same(config, routeEndpoint.Metadata.GetMetadata <RouteConfig>()); Assert.Equal("/{**catchall}", routeEndpoint.RoutePattern.RawText); var hostMetadata = routeEndpoint.Metadata.GetMetadata <AspNetCore.Routing.HostAttribute>(); Assert.NotNull(hostMetadata); Assert.Single(hostMetadata.Hosts); Assert.Equal("*.example.com", hostMetadata.Hosts[0]); }
// Default ordering goes through segments one by one and tries to apply an ordering private static int Compare(RouteEntry entry1, RouteEntry entry2) { ParsedRoute parsedRoute1 = entry1.ParsedRoute; ParsedRoute parsedRoute2 = entry2.ParsedRoute; IList <PathContentSegment> segments1 = parsedRoute1.PathSegments.OfType <PathContentSegment>().ToArray(); IList <PathContentSegment> segments2 = parsedRoute2.PathSegments.OfType <PathContentSegment>().ToArray(); for (int i = 0; i < segments1.Count && i < segments2.Count; i++) { PathContentSegment segment1 = segments1[i]; PathContentSegment segment2 = segments2[i]; int order1 = GetPrecedenceDigit(segment1, entry1.Route.Constraints); int order2 = GetPrecedenceDigit(segment2, entry2.Route.Constraints); if (order1 > order2) { return(1); } else if (order1 < order2) { return(-1); } } return(0); }
// Note this performs all validation steps without short circuiting in order to report all possible errors. public bool ValidateRoute(ParsedRoute route, IConfigErrorReporter errorReporter) { Contracts.CheckValue(route, nameof(route)); Contracts.CheckValue(errorReporter, nameof(errorReporter)); var success = true; if (string.IsNullOrEmpty(route.RouteId)) { errorReporter.ReportError(ConfigErrors.ParsedRouteMissingId, route.RouteId, $"Route has no {nameof(route.RouteId)}."); success = false; } if (string.IsNullOrEmpty(route.Host) && string.IsNullOrEmpty(route.Path)) { errorReporter.ReportError(ConfigErrors.ParsedRouteRuleHasNoMatchers, route.RouteId, $"Route requires {nameof(route.Host)} or {nameof(route.Path)} specified. Set the Path to `/{{**catchall}}` to match all requests."); success = false; } success &= ValidateHost(route.Host, route.RouteId, errorReporter); success &= ValidatePath(route.Path, route.RouteId, errorReporter); success &= ValidateMethods(route.Methods, route.RouteId, errorReporter); success &= _transformBuilder.Validate(route.Transforms, route.RouteId, errorReporter); return(success); }
public void BuildEndpoints_NullMatchers_Works() { // Arrange var builder = Create <RuntimeRouteBuilder>(); var parsedRoute = new ParsedRoute { RouteId = "route1", Priority = 12, }; var backend = new BackendInfo("backend1", new EndpointManager(), new Mock <IProxyHttpClientFactory>().Object); var routeInfo = new RouteInfo("route1"); // Act var config = builder.Build(parsedRoute, backend, routeInfo); // Assert Assert.Same(backend, config.BackendOrNull); Assert.Equal(12, config.Priority); Assert.Empty(config.MatcherSummary); Assert.Single(config.AspNetCoreEndpoints); var routeEndpoint = config.AspNetCoreEndpoints[0] as AspNetCore.Routing.RouteEndpoint; Assert.Equal("route1", routeEndpoint.DisplayName); Assert.Same(config, routeEndpoint.Metadata.GetMetadata <RouteConfig>()); Assert.Equal("/{**catchall}", routeEndpoint.RoutePattern.RawText); var hostMetadata = routeEndpoint.Metadata.GetMetadata <AspNetCore.Routing.HostAttribute>(); Assert.Null(hostMetadata); }
public void BuildEndpoints_JustHostWithWildcard_Works() { // Arrange var builder = Create <RuntimeRouteBuilder>(); var parsedRoute = new ParsedRoute { RouteId = "route1", Host = "*.example.com", Priority = 12, }; var backend = new BackendInfo("backend1", new EndpointManager(), new Mock <IProxyHttpClientFactory>().Object); var routeInfo = new RouteInfo("route1"); // Act var config = builder.Build(parsedRoute, backend, routeInfo); // Assert config.BackendOrNull.Should().BeSameAs(backend); config.Priority.Should().Be(12); config.MatcherSummary.Should().Be(parsedRoute.GetMatcherSummary()); config.AspNetCoreEndpoints.Should().HaveCount(1); var routeEndpoint = config.AspNetCoreEndpoints[0] as AspNetCore.Routing.RouteEndpoint; routeEndpoint.DisplayName.Should().Be("route1"); routeEndpoint.Metadata.GetMetadata <RouteConfig>().Should().BeSameAs(config); routeEndpoint.RoutePattern.RawText.Should().Be("/{**catchall}"); var hostMetadata = routeEndpoint.Metadata.GetMetadata <AspNetCore.Routing.HostAttribute>(); hostMetadata.Should().NotBeNull(); hostMetadata.Hosts.Should().BeEquivalentTo("*.example.com"); }
public async Task BuildConfigAsync_RouteValidationError_SkipsRoute() { // Arrange var errorReporter = new TestConfigErrorReporter(); Mock <IBackendsRepo>() .Setup(r => r.GetBackendsAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(new Dictionary <string, Backend>()); var route1 = new ProxyRoute { RouteId = "route1", Match = { Host = "example.com" }, Priority = 1, BackendId = "backend1" }; Mock <IRoutesRepo>() .Setup(r => r.GetRoutesAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(new[] { route1 }); var parsedRoute1 = new ParsedRoute(); Mock <IRouteValidator>() .Setup(r => r.ValidateRoute(parsedRoute1, errorReporter)) .Returns(false); // Act var configManager = Create <DynamicConfigBuilder>(); var result = await configManager.BuildConfigAsync(errorReporter, CancellationToken.None); // Assert result.IsSuccess.Should().BeTrue(); result.Value.Should().NotBeNull(); result.Value.Backends.Should().BeEmpty(); result.Value.Routes.Should().BeEmpty(); }
// Note this performs all validation steps without short circuiting in order to report all possible errors. public async Task <bool> ValidateRouteAsync(ParsedRoute route) { _ = route ?? throw new ArgumentNullException(nameof(route)); var success = true; if (string.IsNullOrEmpty(route.RouteId)) { Log.MissingRouteId(_logger); success = false; } if ((route.Hosts == null || route.Hosts.Count == 0 || route.Hosts.Any(host => string.IsNullOrEmpty(host))) && string.IsNullOrEmpty(route.Path)) { Log.MissingRouteMatchers(_logger, route.RouteId); success = false; } success &= ValidateHost(route.Hosts, route.RouteId); success &= ValidatePath(route.Path, route.RouteId); success &= ValidateMethods(route.Methods, route.RouteId); success &= _transformBuilder.Validate(route.Transforms, route.RouteId); success &= await ValidateAuthorizationPolicyAsync(route.AuthorizationPolicy, route.RouteId); success &= await ValidateCorsPolicyAsync(route.CorsPolicy, route.RouteId); return(success); }
/// <inheritdoc/> public RouteConfig Build(ParsedRoute source, ClusterInfo cluster, RouteInfo runtimeRoute) { _ = source ?? throw new ArgumentNullException(nameof(source)); _ = runtimeRoute ?? throw new ArgumentNullException(nameof(runtimeRoute)); var transforms = _transformBuilder.Build(source.Transforms); // NOTE: `new RouteConfig(...)` needs a reference to the list of ASP .NET Core endpoints, // but the ASP .NET Core endpoints cannot be created without a `RouteConfig` metadata item. // We solve this chicken-egg problem by creating an (empty) list first // and passing a read-only wrapper of it to `RouteConfig.ctor`. // Recall that `List<T>.AsReadOnly()` creates a wrapper over the original list, // and changes to the underlying list *are* reflected on the read-only view. var aspNetCoreEndpoints = new List <Endpoint>(1); var newRouteConfig = new RouteConfig( runtimeRoute, source.GetConfigHash(), source.Priority, cluster, aspNetCoreEndpoints.AsReadOnly(), transforms); // TODO: Handle arbitrary AST's properly // Catch-all pattern when no path was specified var pathPattern = string.IsNullOrEmpty(source.Path) ? "/{**catchall}" : source.Path; // TODO: Propagate route priority var endpointBuilder = new AspNetCore.Routing.RouteEndpointBuilder( requestDelegate: _pipeline ?? Invoke, routePattern: AspNetCore.Routing.Patterns.RoutePatternFactory.Parse(pathPattern), order: 0); endpointBuilder.DisplayName = source.RouteId; endpointBuilder.Metadata.Add(newRouteConfig); if (!string.IsNullOrEmpty(source.Host)) { endpointBuilder.Metadata.Add(new AspNetCore.Routing.HostAttribute(source.Host)); } if (source.Methods != null && source.Methods.Count > 0) { endpointBuilder.Metadata.Add(new AspNetCore.Routing.HttpMethodMetadata(source.Methods)); } if (string.Equals(AuthorizationConstants.Default, source.AuthorizationPolicy, StringComparison.OrdinalIgnoreCase)) { endpointBuilder.Metadata.Add(DefaultAuthorization); } else if (!string.IsNullOrEmpty(source.AuthorizationPolicy)) { endpointBuilder.Metadata.Add(new AuthorizeAttribute(source.AuthorizationPolicy)); } var endpoint = endpointBuilder.Build(); aspNetCoreEndpoints.Add(endpoint); return(newRouteConfig); }
// Note this performs all validation steps without short circuiting in order to report all possible errors. public async Task <bool> ValidateRouteAsync(ParsedRoute route, IConfigErrorReporter errorReporter) { _ = route ?? throw new ArgumentNullException(nameof(route)); _ = errorReporter ?? throw new ArgumentNullException(nameof(errorReporter)); var success = true; if (string.IsNullOrEmpty(route.RouteId)) { errorReporter.ReportError(ConfigErrors.ParsedRouteMissingId, route.RouteId, $"Route has no {nameof(route.RouteId)}."); success = false; } if (string.IsNullOrEmpty(route.Host) && string.IsNullOrEmpty(route.Path)) { errorReporter.ReportError(ConfigErrors.ParsedRouteRuleHasNoMatchers, route.RouteId, $"Route requires {nameof(route.Host)} or {nameof(route.Path)} specified. Set the Path to `/{{**catchall}}` to match all requests."); success = false; } success &= ValidateHost(route.Host, route.RouteId, errorReporter); success &= ValidatePath(route.Path, route.RouteId, errorReporter); success &= ValidateMethods(route.Methods, route.RouteId, errorReporter); success &= _transformBuilder.Validate(route.Transforms, route.RouteId, errorReporter); success &= await ValidateAuthorizationPolicyAsync(route.AuthorizationPolicy, route.RouteId, errorReporter); success &= await ValidateCorsPolicyAsync(route.CorsPolicy, route.RouteId, errorReporter); return(success); }
public void BuildEndpoints_HostAndPath_Works() { // Arrange var builder = Create <RuntimeRouteBuilder>(); var parsedRoute = new ParsedRoute { RouteId = "route1", Host = "example.com", Path = "/a", Priority = 12, }; var backend = new BackendInfo("backend1", new DestinationManager(), new Mock <IProxyHttpClientFactory>().Object); var routeInfo = new RouteInfo("route1"); // Act var config = builder.Build(parsedRoute, backend, routeInfo); // Assert Assert.Same(backend, config.BackendOrNull); Assert.Equal(12, config.Priority); Assert.Equal(parsedRoute.GetConfigHash(), config.ConfigHash); Assert.Single(config.Endpoints); var routeEndpoint = config.Endpoints[0] as AspNetCore.Routing.RouteEndpoint; Assert.Equal("route1", routeEndpoint.DisplayName); Assert.Same(config, routeEndpoint.Metadata.GetMetadata <RouteConfig>()); Assert.Equal("/a", routeEndpoint.RoutePattern.RawText); var hostMetadata = routeEndpoint.Metadata.GetMetadata <AspNetCore.Routing.HostAttribute>(); Assert.NotNull(hostMetadata); Assert.Single(hostMetadata.Hosts); Assert.Equal("example.com", hostMetadata.Hosts[0]); }
internal ParsedRoute ToParsedRoute() { if (parsedRoute == null) { parsedRoute = RouteParser.Parse(GetRouteUrl()); } return(parsedRoute); }
private async Task <IList <ParsedRoute> > GetRoutesAsync(IConfigErrorReporter errorReporter, CancellationToken cancellation) { var routes = await _routesRepo.GetRoutesAsync(cancellation); var seenRouteIds = new HashSet <string>(); var sortedRoutes = new SortedList <(int, string), ParsedRoute>(routes?.Count ?? 0); if (routes == null) { return(sortedRoutes.Values); } foreach (var route in routes) { if (seenRouteIds.Contains(route.RouteId)) { errorReporter.ReportError(ConfigErrors.RouteDuplicateId, route.RouteId, $"Duplicate route '{route.RouteId}'."); continue; } try { foreach (var filter in _filters) { await filter.ConfigureRouteAsync(route, cancellation); } } catch (Exception ex) { errorReporter.ReportError(ConfigErrors.ConfigBuilderClusterException, route.RouteId, "An exception was thrown from the configuration callbacks.", ex); continue; } var parsedRoute = new ParsedRoute { RouteId = route.RouteId, Methods = route.Match.Methods, Host = route.Match.Host, Path = route.Match.Path, Priority = route.Priority, ClusterId = route.ClusterId, AuthorizationPolicy = route.AuthorizationPolicy, CorsPolicy = route.CorsPolicy, Metadata = route.Metadata, Transforms = route.Transforms, }; if (!await _parsedRouteValidator.ValidateRouteAsync(parsedRoute, errorReporter)) { // parsedRouteValidator already reported error message continue; } sortedRoutes.Add((parsedRoute.Priority ?? 0, parsedRoute.RouteId), parsedRoute); } return(sortedRoutes.Values); }
private async Task <IList <ParsedRoute> > GetRoutesAsync(CancellationToken cancellation) { var routes = await _routesRepo.GetRoutesAsync(cancellation); var seenRouteIds = new HashSet <string>(); var sortedRoutes = new SortedList <(int, string), ParsedRoute>(routes?.Count ?? 0); if (routes == null) { return(sortedRoutes.Values); } foreach (var route in routes) { if (seenRouteIds.Contains(route.RouteId)) { Log.DuplicateRouteId(_logger, route.RouteId); continue; } try { foreach (var filter in _filters) { await filter.ConfigureRouteAsync(route, cancellation); } } catch (Exception ex) { Log.RouteConfigException(_logger, route.RouteId, ex); continue; } var parsedRoute = new ParsedRoute { RouteId = route.RouteId, Methods = route.Match.Methods, Hosts = route.Match.Hosts, Path = route.Match.Path, Priority = route.Priority, ClusterId = route.ClusterId, AuthorizationPolicy = route.AuthorizationPolicy, CorsPolicy = route.CorsPolicy, Metadata = route.Metadata, Transforms = route.Transforms, }; if (!await _parsedRouteValidator.ValidateRouteAsync(parsedRoute)) { // parsedRouteValidator already reported error message continue; } sortedRoutes.Add((parsedRoute.Priority ?? 0, parsedRoute.RouteId), parsedRoute); } return(sortedRoutes.Values); }
private (bool IsSuccess, TestConfigErrorReporter ErrorReporter) RunScenario(ParsedRoute parsedRoute) { var errorReporter = new TestConfigErrorReporter(); var validator = Create <RouteValidator>(); var isSuccess = validator.ValidateRoute(parsedRoute, errorReporter); return(isSuccess, errorReporter); }
private (bool IsSuccess, TestConfigErrorReporter ErrorReporter) RunScenario(ParsedRoute parsedRoute) { var errorReporter = new TestConfigErrorReporter(); Mock <ITransformBuilder>().Setup(builder => builder.Validate(It.IsAny <IList <IDictionary <string, string> > >(), It.IsAny <string>(), It.IsAny <IConfigErrorReporter>())).Returns(true); var validator = Create <RouteValidator>(); var isSuccess = validator.ValidateRoute(parsedRoute, errorReporter); return(isSuccess, errorReporter); }
public async Task ApplyConfigurationsAsync_OneClusterOneDestinationOneRoute_Works() { // Arrange const string TestAddress = "https://localhost:123/"; var cluster = new Cluster { Destinations = { { "d1", new Destination { Address = TestAddress } } } }; var route = new ParsedRoute { RouteId = "route1", ClusterId = "cluster1", }; var dynamicConfigRoot = new DynamicConfigRoot { Clusters = new Dictionary<string, Cluster> { { "cluster1", cluster } }, Routes = new[] { route }, }; Mock<IDynamicConfigBuilder>() .Setup(d => d.BuildConfigAsync(It.IsAny<CancellationToken>())) .ReturnsAsync(dynamicConfigRoot); var proxyManager = Create<ReverseProxyConfigManager>(); // Act await proxyManager.ApplyConfigurationsAsync(CancellationToken.None); // Assert var actualClusters = _clusterManager.GetItems(); Assert.Single(actualClusters); Assert.Equal("cluster1", actualClusters[0].ClusterId); Assert.NotNull(actualClusters[0].DestinationManager); Assert.NotNull(actualClusters[0].Config.Value); var actualDestinations = actualClusters[0].DestinationManager.GetItems(); Assert.Single(actualDestinations); Assert.Equal("d1", actualDestinations[0].DestinationId); Assert.NotNull(actualDestinations[0].Config); Assert.Equal(TestAddress, actualDestinations[0].Config.Address); var actualRoutes = _routeManager.GetItems(); Assert.Single(actualRoutes); Assert.Equal("route1", actualRoutes[0].RouteId); Assert.NotNull(actualRoutes[0].Config.Value); Assert.Same(actualClusters[0], actualRoutes[0].Config.Value.Cluster); }
public async Task Rejects_UnknownCorsPolicy() { var route = new ParsedRoute { RouteId = "route1", CorsPolicy = "unknown", ClusterId = "cluster1", }; var result = await RunScenarioAsync(route); Assert.False(result.IsSuccess); Assert.Contains(result.Logger.Errors, err => err.eventId == EventIds.CorsPolicyNotFound); }
public async Task Rejects_MissingRouteId(string routeId) { // Arrange var parsedRoute = new ParsedRoute { RouteId = routeId }; // Act var result = await RunScenarioAsync(parsedRoute); // Assert Assert.False(result.IsSuccess); Assert.Contains(result.Logger.Errors, err => err.eventId == EventIds.MissingRouteId); }
public async Task Rejects_UnknownAuthorizationPolicy() { var route = new ParsedRoute { RouteId = "route1", AuthorizationPolicy = "unknown", ClusterId = "cluster1", }; var result = await RunScenarioAsync(route); Assert.False(result.IsSuccess); Assert.Contains(result.ErrorReporter.Errors, err => err.ErrorCode == ConfigErrors.ParsedRouteRuleInvalidAuthorizationPolicy && err.Message.Contains("Authorization policy 'unknown' not found")); }
public async Task Accepts_ReservedAuthorizationPolicy(string policy) { var route = new ParsedRoute { RouteId = "route1", AuthorizationPolicy = policy, Host = "localhost", ClusterId = "cluster1", }; var result = await RunScenarioAsync(route); Assert.True(result.IsSuccess); Assert.Empty(result.ErrorReporter.Errors); }
public async Task Accepts_ReservedCorsPolicy(string policy) { var route = new ParsedRoute { RouteId = "route1", CorsPolicy = policy, Hosts = new[] { "localhost" }, ClusterId = "cluster1", }; var result = await RunScenarioAsync(route); Assert.True(result.IsSuccess); Assert.Empty(result.Logger.Errors); }
private async Task <(bool IsSuccess, TestLogger Logger)> RunScenarioAsync(ParsedRoute parsedRoute) { Mock <ITransformBuilder>().Setup(builder => builder.Validate(It.IsAny <IList <IDictionary <string, string> > >(), It.IsAny <string>())).Returns(true); var loggerFactory = new TestLoggerFactory(); var logger = loggerFactory.CreateLogger <RouteValidator>(); Provide(logger); var validator = Create <RouteValidator>(); var isSuccess = await validator.ValidateRouteAsync(parsedRoute); return(isSuccess, loggerFactory.Logger); }
/// <inheritdoc/> public RouteConfig Build(ParsedRoute source, BackendInfo backendOrNull, RouteInfo runtimeRoute) { Contracts.CheckValue(source, nameof(source)); Contracts.CheckValue(runtimeRoute, nameof(runtimeRoute)); // NOTE: `new RouteConfig(...)` needs a reference to the list of ASP .NET Core endpoints, // but the ASP .NET Core endpoints cannot be created without a `RouteConfig` metadata item. // We solve this chicken-egg problem by creating an (empty) list first // and passing a read-only wrapper of it to `RouteConfig.ctor`. // Recall that `List<T>.AsReadOnly()` creates a wrapper over the original list, // and changes to the underlying list *are* reflected on the read-only view. var aspNetCoreEndpoints = new List <Endpoint>(1); var newRouteConfig = new RouteConfig( route: runtimeRoute, matcherSummary: source.GetMatcherSummary(), priority: source.Priority, backendOrNull: backendOrNull, aspNetCoreEndpoints: aspNetCoreEndpoints.AsReadOnly()); // TODO: Handle arbitrary AST's properly // Catch-all pattern when no path was specified var pathPattern = string.IsNullOrEmpty(source.Path) ? "/{**catchall}" : source.Path; // TODO: Propagate route priority var endpointBuilder = new AspNetCore.Routing.RouteEndpointBuilder( requestDelegate: _pipeline ?? Invoke, routePattern: AspNetCore.Routing.Patterns.RoutePatternFactory.Parse(pathPattern), order: 0); endpointBuilder.DisplayName = source.RouteId; endpointBuilder.Metadata.Add(newRouteConfig); if (source.Host != null) { endpointBuilder.Metadata.Add(new AspNetCore.Routing.HostAttribute(source.Host)); } if (source.Methods != null && source.Methods.Count > 0) { endpointBuilder.Metadata.Add(new AspNetCore.Routing.HttpMethodMetadata(source.Methods)); } var endpoint = endpointBuilder.Build(); aspNetCoreEndpoints.Add(endpoint); return(newRouteConfig); }
/// <summary> /// Initializes a new instance of the <see cref="HttpDirectRoute" /> class. /// </summary> /// <param name="routeTemplate">The route template.</param> /// <param name="order">The subroute order.</param> /// <param name="defaults">The default values.</param> /// <param name="constraints">The route constraints.</param> /// <param name="actions">The actions that are reachable via this route.</param> public HttpDirectRoute( string routeTemplate, int order, HttpRouteValueDictionary defaults, HttpRouteValueDictionary constraints, IEnumerable <ReflectedHttpActionDescriptor> actions) : base(routeTemplate, defaults : defaults, constraints : constraints, dataTokens : null, handler : null) { if (actions != null) { Actions = actions.AsArray(); DataTokens[RouteKeys.OrderDataTokenKey] = order; DataTokens[RouteKeys.PrecedenceDataTokenKey] = ParsedRoute.GetPrecedence(constraints); DataTokens[RouteKeys.ActionsDataTokenKey] = Actions; } }
public void Rejects_MissingHostAndPath() { // Arrange var route = new ParsedRoute { RouteId = "route1", ClusterId = "be1", }; // Act var result = RunScenario(route); // Assert Assert.False(result.IsSuccess); Assert.Contains(result.ErrorReporter.Errors, err => err.ErrorCode == ConfigErrors.ParsedRouteRuleHasNoMatchers); }
public void Rejects_MissingRouteId(string routeId) { // Arrange var errorReporter = new TestConfigErrorReporter(); var parsedRoute = new ParsedRoute { RouteId = routeId }; var validator = Create <RouteValidator>(); // Act var isSuccess = validator.ValidateRoute(parsedRoute, errorReporter); // Assert Assert.False(isSuccess); Assert.Contains(errorReporter.Errors, err => err.ErrorCode == ConfigErrors.ParsedRouteMissingId); }
public async Task Rejects_MissingHostAndPath(string host) { // Arrange var route = new ParsedRoute { RouteId = "route1", ClusterId = "cluster1", Hosts = host?.Split(",") }; // Act var result = await RunScenarioAsync(route); // Assert Assert.False(result.IsSuccess); Assert.Contains(result.Logger.Errors, err => err.eventId == EventIds.MissingRouteMatchers); }
public void Rejects_InvalidMethod(string methods) { // Arrange var route = new ParsedRoute { RouteId = "route1", Methods = methods.Split(","), ClusterId = "be1", }; // Act var result = RunScenario(route); // Assert Assert.False(result.IsSuccess); Assert.Contains(result.ErrorReporter.Errors, err => err.ErrorCode == ConfigErrors.ParsedRouteRuleInvalidMatcher && err.Message.Contains("verb")); }
public void Rejects_InvalidPath(string path) { // Arrange var route = new ParsedRoute { RouteId = "route1", Path = path, ClusterId = "be1", }; // Act var result = RunScenario(route); // Assert Assert.False(result.IsSuccess); Assert.Contains(result.ErrorReporter.Errors, err => err.ErrorCode == ConfigErrors.ParsedRouteRuleInvalidMatcher && err.Message.Contains("Invalid path pattern")); }
public async Task Rejects_InvalidHost(string host) { // Arrange var route = new ParsedRoute { RouteId = "route1", Host = host, ClusterId = "cluster1", }; // Act var result = await RunScenarioAsync(route); // Assert Assert.False(result.IsSuccess); Assert.Contains(result.ErrorReporter.Errors, err => err.ErrorCode == ConfigErrors.ParsedRouteRuleInvalidMatcher && err.Message.Contains("Invalid host name")); }
/// <summary> /// Parses routes. /// </summary> /// <param name="content">Content.</param> /// <param name="currentPage">Current page.</param> /// <param name="startOrder">Start order.</param> /// <returns>Parsed routes.</returns> private IList<ParsedRoute> ParseRoutes(string content, int currentPage, int startOrder) { int end = -1; Match m = null; ParsedRoute r = null; MatchCollection matches = null; string subContent = string.Empty; string routeDetails = string.Empty; List<ParsedRoute> ret = new List<ParsedRoute>(); Func<Match, string> getSubContent = (ms) => { int st = -1, ed = -1; string result = string.Empty; st = ms.Index; ed = content.IndexOf("</td>", st, StringComparison.InvariantCultureIgnoreCase); if (ed > 0) result = content.Substring(st, ed - st); return result; }; m = Regex.Match(content, "<h3[^>]+>Routes</h3>", RegexOptions.IgnoreCase); if (m != null && m.Success) { content = content.Substring(m.Index + m.Length); m = Regex.Match(content, "<table[^>]+class=\"ftable\">", RegexOptions.IgnoreCase); if (m != null && m.Success) { content = content.Substring(m.Index); end = content.IndexOf("</table>", StringComparison.InvariantCultureIgnoreCase); if (end > 0) { content = content.Substring(0, end); matches = Regex.Matches(content, "<td", RegexOptions.IgnoreCase); if (matches != null && matches.Count > 0) { for (int i = 0; i < matches.Count; i += 5) { subContent = getSubContent(matches[i + 2]); m = Regex.Match(subContent, "<a\\s+href=\"([^\"]+)\">([^<]+)</a>", RegexOptions.IgnoreCase); if (m != null && m.Success) { r = new ParsedRoute(); r.Name = RockClimbingComWiki.NormalizeName(m.Groups[2].Value.Trim(), false); if (!string.IsNullOrEmpty(r.Name)) { r.Description = RockClimbingComWiki.FixPunctiation(m.Groups[1].Value.Trim()); subContent = getSubContent(matches[i + 3]); m = Regex.Match(subContent, ">([^<]+)", RegexOptions.IgnoreCase); if (m != null && m.Success) r.Grade = Models.RouteGrade.Parse(m.Groups[1].Value.Trim()); if (!string.IsNullOrEmpty(r.Description)) { routeDetails = Load(r.Description); r.Description = string.Empty; m = Regex.Match(routeDetails, "<span\\s+class=\"description\">([^<]+)</span>", RegexOptions.IgnoreCase); if (m != null && m.Success) r.Description = RockClimbingComWiki.FixPunctiation(m.Groups[1].Value.Trim()); } if (r.Grade != null) { r.Order = startOrder; r.Climbing = r.Grade.ParsedClimbing; ret.Add(r); startOrder += 1; } } } } } } } } m = Regex.Match(content, string.Format("href=\"([^\"]+more{0}.html)\"", currentPage + 1), RegexOptions.IgnoreCase); if (m != null && m.Success) ret.AddRange(ParseRoutes(Load(m.Groups[1].Value.Trim()), currentPage + 1, startOrder + 1)); return ret; }