示例#1
0
        /// <summary>
        /// Verify that we can create an HTTP traffic manager rule for a
        /// site on the proxy port using a specific hostname and then
        /// verify that that the traffic manager actually works by spinning
        /// up a [vegomatic] based service to accept the traffic.
        /// </summary>
        /// <param name="testName">Simple name (without spaces) used to ensure that URIs cached for different tests won't conflict.</param>
        /// <param name="proxyPort">The inbound proxy port.</param>
        /// <param name="network">The proxy network.</param>
        /// <param name="trafficManager">The traffic manager.</param>
        /// <param name="useCache">Optionally enable caching and verify.</param>
        /// <param name="serviceName">Optionally specifies the backend service name (defaults to <b>vegomatic</b>).</param>
        /// <param name="useIPAddress">Optionally uses an IP addrress rather than a hostname for the rule frontend.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        private async Task TestHttpRule(string testName, int proxyPort, string network, TrafficManager trafficManager, bool useCache = false, string serviceName = "vegomatic", bool useIPAddress = false)
        {
            // Append a GUID to the test name to ensure that we won't
            // conflict with what any previous test runs may have loaded
            // into the cache.

            testName += "-" + Guid.NewGuid().ToString("D");

            // Verify that we can create an HTTP traffic manager rule for a
            // site on the proxy port using a specific hostname and then
            // verify that that the traffic manager actually works by spinning
            // up a [vegomatic] based service to accept the traffic.

            var queryCount = 100;
            var manager    = hive.GetReachableManager();
            var hostname   = useIPAddress ? manager.PrivateAddress.ToString() : testHostname;

            manager.Connect();

            using (var client = new TestHttpClient(disableConnectionReuse: true))
            {
                // Setup the client to query the [vegomatic] service through the
                // proxy without needing to configure a hive DNS entry.

                client.BaseAddress = new Uri($"http://{manager.PrivateAddress}:{proxyPort}/");
                client.DefaultRequestHeaders.Host = testHostname;

                // Configure the traffic manager rule.

                var rule = new TrafficHttpRule()
                {
                    Name         = "vegomatic",
                    CheckExpect  = "status 200",
                    CheckSeconds = 1,
                };

                if (useCache)
                {
                    rule.Cache = new TrafficHttpCache()
                    {
                        Enabled = true
                    };
                }

                rule.Frontends.Add(
                    new TrafficHttpFrontend()
                {
                    Host      = useIPAddress ? null : hostname,
                    ProxyPort = proxyPort
                });

                rule.Backends.Add(
                    new TrafficHttpBackend()
                {
                    Server = serviceName,
                    Port   = 80
                });

                trafficManager.SetRule(rule);

                // Spin up a single [vegomatic] service instance.

                manager.SudoCommand($"docker service create --name vegomatic --network {network} --replicas 1 {vegomaticImage} test-server").EnsureSuccess();
                await WaitUntilReadyAsync(client.BaseAddress, hostname);

                // Query the service several times to verify that we get a response and
                // also that all of the responses are the same (because we have only
                // a single [vegomatic] instance returning its UUID).
                //
                // We're going to use a different URL for each request so that we
                // won't see any cache hits.

                var uniqueResponses = new HashSet <string>();
                var viaVarnish      = false;
                var cacheHit        = false;

                for (int i = 0; i < queryCount; i++)
                {
                    var response = await client.GetAsync($"/{testName}/pass-1/{i}?body=server-id&expires=60");

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    if (ViaVarnish(response))
                    {
                        viaVarnish = true;
                    }

                    if (CacheHit(response))
                    {
                        cacheHit = true;
                    }

                    var body = await response.Content.ReadAsStringAsync();

                    if (!uniqueResponses.Contains(body))
                    {
                        uniqueResponses.Add(body);
                    }
                }

                Assert.Single(uniqueResponses);

                if (useCache)
                {
                    // [viaVarnish] should be TRUE because we're routing through the cache.

                    Assert.True(viaVarnish);

                    // [cacheHit] should be FALSE because we used a unique URI for each request.

                    Assert.False(cacheHit);
                }
                else
                {
                    // [viaVarnish] and [cacheHit] should both be FALSE because we're not caching.

                    Assert.False(viaVarnish);
                    Assert.False(cacheHit);
                }

                // Repeat the test if caching is enabled with the same URLs as last time and verify that
                // we see cache hits this time.

                if (useCache)
                {
                    viaVarnish = false;
                    cacheHit   = false;

                    for (int i = 0; i < queryCount; i++)
                    {
                        var response = await client.GetAsync($"/{testName}/pass-1/{i}?body=server-id&expires=60");

                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                        if (ViaVarnish(response))
                        {
                            viaVarnish = true;
                        }

                        if (CacheHit(response))
                        {
                            cacheHit = true;
                        }

                        var body = await response.Content.ReadAsStringAsync();

                        if (!uniqueResponses.Contains(body))
                        {
                            uniqueResponses.Add(body);
                        }
                    }

                    Assert.True(viaVarnish);
                    Assert.True(cacheHit);
                }

                // Spin up a second replica and repeat the query test to verify
                // that we see two unique responses.
                //
                // Note that we're going to pass a new set of URLs to avoid having
                // any responses cached so we'll end up seeing all of the IDs.
                //
                // Note also that we need to perform these requests in parallel
                // to try to force Varnish to establish more than one connection
                // to the [vegomatic] service.  If we don't do this, Varnish will
                // establish a single connection to one of the service instances
                // and keep sending traffic there resulting in us seeing only
                // one response UUID.

                manager.SudoCommand($"docker service update --replicas 2 vegomatic").EnsureSuccess();
                await WaitUntilReadyAsync(client.BaseAddress, hostname);

                // Reset the response info and do the requests.

                uniqueResponses.Clear();
                viaVarnish = false;
                cacheHit   = false;

                var tasks = new List <Task>();
                var uris  = new List <string>();

                for (int i = 0; i < queryCount; i++)
                {
                    uris.Add($"/{testName}/pass-2/{i}?body=server-id&expires=60&delay=0.250");
                }

                foreach (var uri in uris)
                {
                    tasks.Add(Task.Run(
                                  async() =>
                    {
                        var response = await client.GetAsync(uri);
                        var body     = await response.Content.ReadAsStringAsync();

                        Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                        if (ViaVarnish(response))
                        {
                            viaVarnish = true;
                        }

                        if (CacheHit(response))
                        {
                            cacheHit = true;
                        }

                        lock (uniqueResponses)
                        {
                            if (!uniqueResponses.Contains(body))
                            {
                                uniqueResponses.Add(body);
                            }
                        }
                    }));
                }

                await NeonHelper.WaitAllAsync(tasks, TimeSpan.FromSeconds(30));

                if (useCache)
                {
                    // [viaVarnish] should be TRUE because we're routing through the cache.

                    Assert.True(viaVarnish);

                    // [cacheHit] should be FALSE because we used a unique URI for each request.

                    Assert.False(cacheHit);
                }
                else
                {
                    // [viaVarnish] and [cacheHit] should both be FALSE because we're not caching.

                    Assert.False(viaVarnish);
                    Assert.False(cacheHit);
                }

                Assert.Equal(2, uniqueResponses.Count);
            }
        }
示例#2
0
 public CarTests(ApiApplicationFactory <Startup> factory, CarGenerator carGenerator)
 {
     client            = factory.CreateTestClient("cars/");
     this.carGenerator = carGenerator;
 }
 public LogLevelTests()
 {
     _client      = new TestHttpClient();
     _credentials = new BasicAuthCredentials("http://test:80", "Walter", "White");
 }
 public static ILineBot CreateBot(TestHttpClient httpClient)
 {
     return(new LineBot(new TestConfiguration(), httpClient, new EmptyLineBotLogger()));
 }
 public static ILineBot CreateBot(ILineBotLogger logger)
 {
     return(new LineBot(new TestConfiguration(), TestHttpClient.Create(), logger));
 }
示例#6
0
 public RequestUriTests()
 {
     _client = new TestHttpClient();
 }
 public PostContent()
 {
     _client = new TestHttpClient();
 }
        public void RedirectProcessorRedirectsOldUrlWithReplaceType()
        {
            var configuration =
                TestData.TestData.DefaultConfiguration;
            var urlParser      = new UrlParser();
            var urlFormatter   = new UrlFormatter();
            var redirectParser = new RedirectParser(
                configuration,
                urlParser,
                urlFormatter);

            // create redirect processor
            var testHttpClient =
                new TestHttpClient();
            var redirectProcessor = new RedirectProcessor(
                configuration,
                new UrlHelper(
                    configuration,
                    urlParser,
                    urlFormatter),
                testHttpClient,
                urlParser,
                urlFormatter,
                new RedirectHelper(
                    configuration,
                    urlParser,
                    urlFormatter));

            // parse redirect with old url replace type
            var parsedRedirects = TestData.TestData.GetParsedRedirects(
                configuration,
                new[]
            {
                new Redirect
                {
                    OldUrl       = "/url1",
                    NewUrl       = "/url2",
                    RedirectType = RedirectType.Replace
                }
            })
                                  .ToList();

            // parse redirects to verify replace redirect works
            var parsedRedirects2 = TestData.TestData.GetParsedRedirects(
                configuration,
                new[]
            {
                new Redirect
                {
                    OldUrl = "/url1/replace/redirect",
                    NewUrl = "/url2/replace/redirect"
                }
            })
                                   .ToList();

            // preload parsed redirects
            redirectProcessor.PreloadParsedRedirects(
                parsedRedirects);

            var processedRedirects = new []
            {
                new ProcessedRedirect
                {
                    ParsedRedirect = parsedRedirects[0]
                },
                new ProcessedRedirect
                {
                    ParsedRedirect = parsedRedirects2[0]
                }
            };

            // process redirects
            foreach (var processedRedirect in processedRedirects)
            {
                redirectProcessor.Process(
                    processedRedirect);
            }

            // verify
            var urlResponseResult = processedRedirects[1]
                                    .Results
                                    .FirstOrDefault(x => x.Type == ResultTypes.UrlResponse);

            Assert.IsNotNull(urlResponseResult);
            Assert.AreEqual(
                "http://www.test.local/url2/replace/redirect",
                urlResponseResult.Url);
        }
        public void RedirectProcessorHandlesLowercasedRedirects()
        {
            var configuration =
                TestData.TestData.DefaultConfiguration;
            var urlParser      = new UrlParser();
            var urlFormatter   = new UrlFormatter();
            var redirectParser = new RedirectParser(
                configuration,
                urlParser,
                urlFormatter);

            // create redirect processor
            var testHttpClient =
                new TestHttpClient();
            var redirectProcessor = new RedirectProcessor(
                configuration,
                new UrlHelper(
                    configuration,
                    urlParser,
                    urlFormatter),
                testHttpClient,
                urlParser,
                urlFormatter,
                new RedirectHelper(
                    configuration,
                    urlParser,
                    urlFormatter));

            // parse redirects with uppercased old url
            var parsedRedirects = TestData.TestData.GetParsedRedirects(
                configuration,
                new[]
            {
                new Redirect
                {
                    OldUrl = "/Url1",
                    NewUrl = "/url2"
                }
            })
                                  .ToList();

            // simulate uppercased url redirects to lowercased url
            testHttpClient.Responses[
                parsedRedirects[0].OldUrl.Formatted] =
                new HttpResponse
            {
                StatusCode = 301,
                Headers    = new Dictionary <string, string>
                {
                    { "Location", "/url1" }
                }
            };

            // preload parsed redirects
            redirectProcessor.PreloadParsedRedirects(
                parsedRedirects);

            // process redirects
            var processedRedirect = new ProcessedRedirect
            {
                ParsedRedirect = parsedRedirects[0]
            };

            redirectProcessor.Process(
                processedRedirect);

            // verify
            var urlResponseResult = processedRedirect
                                    .Results
                                    .FirstOrDefault(x => x.Type == ResultTypes.UrlResponse);

            Assert.IsNotNull(urlResponseResult);
            Assert.AreEqual(
                "http://www.test.local/url2",
                urlResponseResult.Url);
        }
        public void RedirectProcessorCachesResponse()
        {
            var configuration =
                TestData.TestData.DefaultConfiguration;
            var urlParser      = new UrlParser();
            var urlFormatter   = new UrlFormatter();
            var redirectParser = new RedirectParser(
                configuration,
                urlParser,
                urlFormatter);

            // create redirect processor
            var testHttpClient =
                new TestHttpClient();
            var redirectProcessor = new RedirectProcessor(
                configuration,
                new UrlHelper(
                    configuration,
                    urlParser,
                    urlFormatter),
                testHttpClient,
                urlParser,
                urlFormatter,
                new RedirectHelper(
                    configuration,
                    urlParser,
                    urlFormatter));

            // create and parse redirects
            var redirects = new List <IRedirect>
            {
                new Redirect
                {
                    OldUrl = "/url1",
                    NewUrl = "/url3"
                },
                new Redirect
                {
                    OldUrl = "/url2",
                    NewUrl = "/url3"
                }
            };
            var parsedRedirects = new List <IParsedRedirect>();

            foreach (var redirect in redirects)
            {
                parsedRedirects.Add(
                    redirectParser.ParseRedirect(
                        redirect));
            }

            // preload parsed redirects
            redirectProcessor.PreloadParsedRedirects(
                parsedRedirects);

            // verify controlled http client doesn't have any responses
            Assert.AreEqual(
                0,
                testHttpClient.Responses.Count);

            // process redirects and verify responses are cached by overriding responses
            UrlResponseResult urlResponseResult = null;
            var processedRedirects = new List <IProcessedRedirect>();

            foreach (var parsedRedirect in parsedRedirects)
            {
                var processedRedirect = new ProcessedRedirect
                {
                    ParsedRedirect = parsedRedirect
                };

                redirectProcessor.Process(
                    processedRedirect);

                // get url response result, if url response result is null and
                // controlled http client has a response for old url
                if (urlResponseResult == null &&
                    testHttpClient.Responses.ContainsKey(
                        parsedRedirect.NewUrl.Formatted))
                {
                    urlResponseResult = processedRedirect.Results
                                        .FirstOrDefault(r => r.Type.Equals(
                                                            ResultTypes.UrlResponse)) as UrlResponseResult;
                }
                else
                {
                    // override response with forbidden status code
                    testHttpClient.Responses[
                        parsedRedirect.NewUrl.Formatted] =
                        new HttpResponse
                    {
                        StatusCode = 401
                    };
                }
            }

            // verify url response result for /url3 has status code ok and not forbidden
            Assert.IsNotNull(
                urlResponseResult);
            Assert.AreEqual(
                "http://www.test.local/url3",
                urlResponseResult.Url);
            Assert.AreEqual(
                404,
                urlResponseResult.StatusCode
                );
        }
        public void DetectUrlResponse()
        {
            // create test http client
            var testHttpClient = new TestHttpClient();

            // parsed redirects
            var parsedRedirects =
                TestData.TestData.GetParsedRedirects();

            // add moved response for parsed redirects
            foreach (var redirect in parsedRedirects)
            {
                testHttpClient.Responses[
                    redirect.OldUrl.Formatted] = new HttpResponse
                {
                    StatusCode = 301,
                    Headers    = new Dictionary <string, string>
                    {
                        { "Location", redirect.NewUrl.Formatted }
                    }
                };
            }

            // override redirect old url with ok response
            testHttpClient.Responses[
                "http://www.test.local/new-url"] = new HttpResponse
            {
                StatusCode = 200
            };

            // create redirect processor
            var configuration = new Configuration
            {
                DefaultUrl            = TestData.TestData.DefaultHost,
                ForceHttpHostPatterns = new[]
                {
                    "www\\.test\\.local"
                }
            };
            var urlParser         = new UrlParser();
            var urlFormatter      = new UrlFormatter();
            var redirectProcessor = new RedirectProcessor(
                configuration,
                new UrlHelper(
                    configuration,
                    urlParser,
                    urlFormatter),
                testHttpClient,
                urlParser,
                urlFormatter,
                new RedirectHelper(
                    configuration,
                    urlParser,
                    urlFormatter));

            // preload redirects
            redirectProcessor.PreloadParsedRedirects(
                parsedRedirects);

            // process redirects
            var processedRedirects = TestData.TestData.GetProcessedRedirects(
                parsedRedirects,
                new[] { redirectProcessor });

            // verify redirect processor detects overridden url with response
            var urlResponse = redirectProcessor.Results
                              .FirstOrDefault(x => x.Type.Equals(ResultTypes.UrlResponse));

            Assert.IsNotNull(urlResponse);
            Assert.AreEqual(
                "http://www.test.local/new-url",
                urlResponse.Url);
        }
        public void HttpsRedirectDoesntReturnCyclicRedirect()
        {
            // create redirect processor
            var configuration = new Configuration
            {
                DefaultUrl            = TestData.TestData.DefaultHost,
                ForceHttpHostPatterns = new[]
                {
                    "www\\.test\\.local"
                }
            };

            // create url and redirect parser
            var urlFormatter = new UrlFormatter();
            var urlParser    = new UrlParser();
            var urlHelper    = new UrlHelper(
                configuration,
                urlParser,
                urlFormatter);
            var redirectParser = new RedirectParser(
                configuration,
                urlParser,
                urlFormatter);

            // create redirect processor
            var testHttpClient =
                new TestHttpClient();
            var redirectProcessor = new RedirectProcessor(
                configuration,
                urlHelper,
                testHttpClient,
                urlParser,
                urlFormatter,
                new RedirectHelper(
                    configuration,
                    urlParser,
                    urlFormatter));

            // parse redirects
            var redirects = new[] {
                new Redirect
                {
                    OldUrl = "http://www.test.local/url1",
                    NewUrl = "https://www.test.local/url1"
                },
                new Redirect
                {
                    OldUrl = "https://www.test.local/url1",
                    NewUrl = "https://www.test.local/url2"
                },
                new Redirect
                {
                    OldUrl = "https://www.test.local/url2",
                    NewUrl = "https://www.test.local/url3"
                }
            };

            // parse redirects
            var parsedRedirects = new List <IParsedRedirect>();

            foreach (var redirect in redirects)
            {
                parsedRedirects.Add(
                    redirectParser.ParseRedirect(
                        redirect));
            }

            // preload parsed redirects
            redirectProcessor.PreloadParsedRedirects(
                parsedRedirects);

            // process redirects using redirect processor
            var processedRedirects = TestData.TestData.GetProcessedRedirects(
                parsedRedirects,
                new[] { redirectProcessor });

            // verify cyclic redirect is not detected
            var cyclicRedirect = processedRedirects
                                 .FirstOrDefault(pr => pr.Results.Any(
                                                     r => r.Type.Equals(ResultTypes.CyclicRedirect)));

            Assert.IsNull(cyclicRedirect);

            // verify optimized redirect is detected
            var optimizedRedirect = processedRedirects
                                    .FirstOrDefault(pr => pr.Results.Any(
                                                        r => r.Type.Equals(ResultTypes.OptimizedRedirect)));

            Assert.IsNotNull(optimizedRedirect);
        }