Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Unified Diff: net/url_request/url_request_throttler_simulation_unittest.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/url_request/url_request_throttler_simulation_unittest.cc
diff --git a/net/url_request/url_request_throttler_simulation_unittest.cc b/net/url_request/url_request_throttler_simulation_unittest.cc
deleted file mode 100644
index cd186594eed62fc69ff7aadbc66ffa9230fc40f0..0000000000000000000000000000000000000000
--- a/net/url_request/url_request_throttler_simulation_unittest.cc
+++ /dev/null
@@ -1,758 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// The tests in this file attempt to verify the following through simulation:
-// a) That a server experiencing overload will actually benefit from the
-// anti-DDoS throttling logic, i.e. that its traffic spike will subside
-// and be distributed over a longer period of time;
-// b) That "well-behaved" clients of a server under DDoS attack actually
-// benefit from the anti-DDoS throttling logic; and
-// c) That the approximate increase in "perceived downtime" introduced by
-// anti-DDoS throttling for various different actual downtimes is what
-// we expect it to be.
-
-#include <cmath>
-#include <limits>
-#include <vector>
-
-#include "base/environment.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/rand_util.h"
-#include "base/time/time.h"
-#include "net/base/request_priority.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_test_util.h"
-#include "net/url_request/url_request_throttler_manager.h"
-#include "net/url_request/url_request_throttler_test_support.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::TimeDelta;
-using base::TimeTicks;
-
-namespace net {
-namespace {
-
-// Set this variable in your environment if you want to see verbose results
-// of the simulation tests.
-const char kShowSimulationVariableName[] = "SHOW_SIMULATION_RESULTS";
-
-// Prints output only if a given environment variable is set. We use this
-// to not print any output for human evaluation when the test is run without
-// supervision.
-void VerboseOut(const char* format, ...) {
- static bool have_checked_environment = false;
- static bool should_print = false;
- if (!have_checked_environment) {
- have_checked_environment = true;
- scoped_ptr<base::Environment> env(base::Environment::Create());
- if (env->HasVar(kShowSimulationVariableName))
- should_print = true;
- }
-
- if (should_print) {
- va_list arglist;
- va_start(arglist, format);
- vprintf(format, arglist);
- va_end(arglist);
- }
-}
-
-// A simple two-phase discrete time simulation. Actors are added in the order
-// they should take action at every tick of the clock. Ticks of the clock
-// are two-phase:
-// - Phase 1 advances every actor's time to a new absolute time.
-// - Phase 2 asks each actor to perform their action.
-class DiscreteTimeSimulation {
- public:
- class Actor {
- public:
- virtual ~Actor() {}
- virtual void AdvanceTime(const TimeTicks& absolute_time) = 0;
- virtual void PerformAction() = 0;
- };
-
- DiscreteTimeSimulation() {}
-
- // Adds an |actor| to the simulation. The client of the simulation maintains
- // ownership of |actor| and must ensure its lifetime exceeds that of the
- // simulation. Actors should be added in the order you wish for them to
- // act at each tick of the simulation.
- void AddActor(Actor* actor) {
- actors_.push_back(actor);
- }
-
- // Runs the simulation for, pretending |time_between_ticks| passes from one
- // tick to the next. The start time will be the current real time. The
- // simulation will stop when the simulated duration is equal to or greater
- // than |maximum_simulated_duration|.
- void RunSimulation(const TimeDelta& maximum_simulated_duration,
- const TimeDelta& time_between_ticks) {
- TimeTicks start_time = TimeTicks();
- TimeTicks now = start_time;
- while ((now - start_time) <= maximum_simulated_duration) {
- for (std::vector<Actor*>::iterator it = actors_.begin();
- it != actors_.end();
- ++it) {
- (*it)->AdvanceTime(now);
- }
-
- for (std::vector<Actor*>::iterator it = actors_.begin();
- it != actors_.end();
- ++it) {
- (*it)->PerformAction();
- }
-
- now += time_between_ticks;
- }
- }
-
- private:
- std::vector<Actor*> actors_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscreteTimeSimulation);
-};
-
-// Represents a web server in a simulation of a server under attack by
-// a lot of clients. Must be added to the simulation's list of actors
-// after all |Requester| objects.
-class Server : public DiscreteTimeSimulation::Actor {
- public:
- Server(int max_queries_per_tick, double request_drop_ratio)
- : max_queries_per_tick_(max_queries_per_tick),
- request_drop_ratio_(request_drop_ratio),
- num_overloaded_ticks_remaining_(0),
- num_current_tick_queries_(0),
- num_overloaded_ticks_(0),
- max_experienced_queries_per_tick_(0),
- mock_request_(context_.CreateRequest(
- GURL(), DEFAULT_PRIORITY, NULL, NULL)) {}
-
- void SetDowntime(const TimeTicks& start_time, const TimeDelta& duration) {
- start_downtime_ = start_time;
- end_downtime_ = start_time + duration;
- }
-
- void AdvanceTime(const TimeTicks& absolute_time) override {
- now_ = absolute_time;
- }
-
- void PerformAction() override {
- // We are inserted at the end of the actor's list, so all Requester
- // instances have already done their bit.
- if (num_current_tick_queries_ > max_experienced_queries_per_tick_)
- max_experienced_queries_per_tick_ = num_current_tick_queries_;
-
- if (num_current_tick_queries_ > max_queries_per_tick_) {
- // We pretend the server fails for the next several ticks after it
- // gets overloaded.
- num_overloaded_ticks_remaining_ = 5;
- ++num_overloaded_ticks_;
- } else if (num_overloaded_ticks_remaining_ > 0) {
- --num_overloaded_ticks_remaining_;
- }
-
- requests_per_tick_.push_back(num_current_tick_queries_);
- num_current_tick_queries_ = 0;
- }
-
- // This is called by Requester. It returns the response code from
- // the server.
- int HandleRequest() {
- ++num_current_tick_queries_;
- if (!start_downtime_.is_null() &&
- start_downtime_ < now_ && now_ < end_downtime_) {
- // For the simulation measuring the increase in perceived
- // downtime, it might be interesting to count separately the
- // queries seen by the server (assuming a front-end reverse proxy
- // is what actually serves up the 503s in this case) so that we could
- // visualize the traffic spike seen by the server when it comes up,
- // which would in many situations be ameliorated by the anti-DDoS
- // throttling.
- return 503;
- }
-
- if ((num_overloaded_ticks_remaining_ > 0 ||
- num_current_tick_queries_ > max_queries_per_tick_) &&
- base::RandDouble() < request_drop_ratio_) {
- return 503;
- }
-
- return 200;
- }
-
- int num_overloaded_ticks() const {
- return num_overloaded_ticks_;
- }
-
- int max_experienced_queries_per_tick() const {
- return max_experienced_queries_per_tick_;
- }
-
- const URLRequest& mock_request() const {
- return *mock_request_.get();
- }
-
- std::string VisualizeASCII(int terminal_width) {
- // Account for | characters we place at left of graph.
- terminal_width -= 1;
-
- VerboseOut("Overloaded for %d of %d ticks.\n",
- num_overloaded_ticks_, requests_per_tick_.size());
- VerboseOut("Got maximum of %d requests in a tick.\n\n",
- max_experienced_queries_per_tick_);
-
- VerboseOut("Traffic graph:\n\n");
-
- // Printing the graph like this is a bit overkill, but was very useful
- // while developing the various simulations to see if they were testing
- // the corner cases we want to simulate.
-
- // Find the smallest number of whole ticks we need to group into a
- // column that will let all ticks fit into the column width we have.
- int num_ticks = requests_per_tick_.size();
- double ticks_per_column_exact =
- static_cast<double>(num_ticks) / static_cast<double>(terminal_width);
- int ticks_per_column = std::ceil(ticks_per_column_exact);
- DCHECK_GE(ticks_per_column * terminal_width, num_ticks);
-
- // Sum up the column values.
- int num_columns = num_ticks / ticks_per_column;
- if (num_ticks % ticks_per_column)
- ++num_columns;
- DCHECK_LE(num_columns, terminal_width);
- scoped_ptr<int[]> columns(new int[num_columns]);
- for (int tx = 0; tx < num_ticks; ++tx) {
- int cx = tx / ticks_per_column;
- if (tx % ticks_per_column == 0)
- columns[cx] = 0;
- columns[cx] += requests_per_tick_[tx];
- }
-
- // Find the lowest integer divisor that will let the column values
- // be represented in a graph of maximum height 50.
- int max_value = 0;
- for (int cx = 0; cx < num_columns; ++cx)
- max_value = std::max(max_value, columns[cx]);
- const int kNumRows = 50;
- double row_divisor_exact = max_value / static_cast<double>(kNumRows);
- int row_divisor = std::ceil(row_divisor_exact);
- DCHECK_GE(row_divisor * kNumRows, max_value);
-
- // To show the overload line, we calculate the appropriate value.
- int overload_value = max_queries_per_tick_ * ticks_per_column;
-
- // When num_ticks is not a whole multiple of ticks_per_column, the last
- // column includes fewer ticks than the others. In this case, don't
- // print it so that we don't show an inconsistent value.
- int num_printed_columns = num_columns;
- if (num_ticks % ticks_per_column)
- --num_printed_columns;
-
- // This is a top-to-bottom traversal of rows, left-to-right per row.
- std::string output;
- for (int rx = 0; rx < kNumRows; ++rx) {
- int range_min = (kNumRows - rx) * row_divisor;
- int range_max = range_min + row_divisor;
- if (range_min == 0)
- range_min = -1; // Make 0 values fit in the bottom range.
- output.append("|");
- for (int cx = 0; cx < num_printed_columns; ++cx) {
- char block = ' ';
- // Show the overload line.
- if (range_min < overload_value && overload_value <= range_max)
- block = '-';
-
- // Preferentially, show the graph line.
- if (range_min < columns[cx] && columns[cx] <= range_max)
- block = '#';
-
- output.append(1, block);
- }
- output.append("\n");
- }
- output.append("|");
- output.append(num_printed_columns, '=');
-
- return output;
- }
-
- const URLRequestContext& context() const { return context_; }
-
- private:
- TimeTicks now_;
- TimeTicks start_downtime_; // Can be 0 to say "no downtime".
- TimeTicks end_downtime_;
- const int max_queries_per_tick_;
- const double request_drop_ratio_; // Ratio of requests to 503 when failing.
- int num_overloaded_ticks_remaining_;
- int num_current_tick_queries_;
- int num_overloaded_ticks_;
- int max_experienced_queries_per_tick_;
- std::vector<int> requests_per_tick_;
-
- TestURLRequestContext context_;
- scoped_ptr<URLRequest> mock_request_;
-
- DISALLOW_COPY_AND_ASSIGN(Server);
-};
-
-// Mock throttler entry used by Requester class.
-class MockURLRequestThrottlerEntry : public URLRequestThrottlerEntry {
- public:
- explicit MockURLRequestThrottlerEntry(URLRequestThrottlerManager* manager)
- : URLRequestThrottlerEntry(manager, std::string()),
- mock_backoff_entry_(&backoff_policy_) {}
-
- const BackoffEntry* GetBackoffEntry() const override {
- return &mock_backoff_entry_;
- }
-
- BackoffEntry* GetBackoffEntry() override { return &mock_backoff_entry_; }
-
- TimeTicks ImplGetTimeNow() const override { return fake_now_; }
-
- void SetFakeNow(const TimeTicks& fake_time) {
- fake_now_ = fake_time;
- mock_backoff_entry_.set_fake_now(fake_time);
- }
-
- TimeTicks fake_now() const {
- return fake_now_;
- }
-
- protected:
- ~MockURLRequestThrottlerEntry() override {}
-
- private:
- TimeTicks fake_now_;
- MockBackoffEntry mock_backoff_entry_;
-};
-
-// Registry of results for a class of |Requester| objects (e.g. attackers vs.
-// regular clients).
-class RequesterResults {
- public:
- RequesterResults()
- : num_attempts_(0), num_successful_(0), num_failed_(0), num_blocked_(0) {
- }
-
- void AddSuccess() {
- ++num_attempts_;
- ++num_successful_;
- }
-
- void AddFailure() {
- ++num_attempts_;
- ++num_failed_;
- }
-
- void AddBlocked() {
- ++num_attempts_;
- ++num_blocked_;
- }
-
- int num_attempts() const { return num_attempts_; }
- int num_successful() const { return num_successful_; }
- int num_failed() const { return num_failed_; }
- int num_blocked() const { return num_blocked_; }
-
- double GetBlockedRatio() {
- DCHECK(num_attempts_);
- return static_cast<double>(num_blocked_) /
- static_cast<double>(num_attempts_);
- }
-
- double GetSuccessRatio() {
- DCHECK(num_attempts_);
- return static_cast<double>(num_successful_) /
- static_cast<double>(num_attempts_);
- }
-
- void PrintResults(const char* class_description) {
- if (num_attempts_ == 0) {
- VerboseOut("No data for %s\n", class_description);
- return;
- }
-
- VerboseOut("Requester results for %s\n", class_description);
- VerboseOut(" %d attempts\n", num_attempts_);
- VerboseOut(" %d successes\n", num_successful_);
- VerboseOut(" %d 5xx responses\n", num_failed_);
- VerboseOut(" %d requests blocked\n", num_blocked_);
- VerboseOut(" %.2f success ratio\n", GetSuccessRatio());
- VerboseOut(" %.2f blocked ratio\n", GetBlockedRatio());
- VerboseOut("\n");
- }
-
- private:
- int num_attempts_;
- int num_successful_;
- int num_failed_;
- int num_blocked_;
-};
-
-// Represents an Requester in a simulated DDoS situation, that periodically
-// requests a specific resource.
-class Requester : public DiscreteTimeSimulation::Actor {
- public:
- Requester(MockURLRequestThrottlerEntry* throttler_entry,
- const TimeDelta& time_between_requests,
- Server* server,
- RequesterResults* results)
- : throttler_entry_(throttler_entry),
- time_between_requests_(time_between_requests),
- last_attempt_was_failure_(false),
- server_(server),
- results_(results) {
- DCHECK(server_);
- }
-
- void AdvanceTime(const TimeTicks& absolute_time) override {
- if (time_of_last_success_.is_null())
- time_of_last_success_ = absolute_time;
-
- throttler_entry_->SetFakeNow(absolute_time);
- }
-
- void PerformAction() override {
- TimeDelta effective_delay = time_between_requests_;
- TimeDelta current_jitter = TimeDelta::FromMilliseconds(
- request_jitter_.InMilliseconds() * base::RandDouble());
- if (base::RandInt(0, 1)) {
- effective_delay -= current_jitter;
- } else {
- effective_delay += current_jitter;
- }
-
- if (throttler_entry_->fake_now() - time_of_last_attempt_ >
- effective_delay) {
- if (!throttler_entry_->ShouldRejectRequest(
- server_->mock_request(),
- server_->context().network_delegate())) {
- int status_code = server_->HandleRequest();
- MockURLRequestThrottlerHeaderAdapter response_headers(status_code);
- throttler_entry_->UpdateWithResponse(std::string(), &response_headers);
-
- if (status_code == 200) {
- if (results_)
- results_->AddSuccess();
-
- if (last_attempt_was_failure_) {
- last_downtime_duration_ =
- throttler_entry_->fake_now() - time_of_last_success_;
- }
-
- time_of_last_success_ = throttler_entry_->fake_now();
- last_attempt_was_failure_ = false;
- } else {
- if (results_)
- results_->AddFailure();
- last_attempt_was_failure_ = true;
- }
- } else {
- if (results_)
- results_->AddBlocked();
- last_attempt_was_failure_ = true;
- }
-
- time_of_last_attempt_ = throttler_entry_->fake_now();
- }
- }
-
- // Adds a delay until the first request, equal to a uniformly distributed
- // value between now and now + max_delay.
- void SetStartupJitter(const TimeDelta& max_delay) {
- int delay_ms = base::RandInt(0, max_delay.InMilliseconds());
- time_of_last_attempt_ = TimeTicks() +
- TimeDelta::FromMilliseconds(delay_ms) - time_between_requests_;
- }
-
- void SetRequestJitter(const TimeDelta& request_jitter) {
- request_jitter_ = request_jitter;
- }
-
- TimeDelta last_downtime_duration() const { return last_downtime_duration_; }
-
- private:
- scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry_;
- const TimeDelta time_between_requests_;
- TimeDelta request_jitter_;
- TimeTicks time_of_last_attempt_;
- TimeTicks time_of_last_success_;
- bool last_attempt_was_failure_;
- TimeDelta last_downtime_duration_;
- Server* const server_;
- RequesterResults* const results_; // May be NULL.
-
- DISALLOW_COPY_AND_ASSIGN(Requester);
-};
-
-void SimulateAttack(Server* server,
- RequesterResults* attacker_results,
- RequesterResults* client_results,
- bool enable_throttling) {
- const size_t kNumAttackers = 50;
- const size_t kNumClients = 50;
- DiscreteTimeSimulation simulation;
- URLRequestThrottlerManager manager;
- ScopedVector<Requester> requesters;
- for (size_t i = 0; i < kNumAttackers; ++i) {
- // Use a tiny time_between_requests so the attackers will ping the
- // server at every tick of the simulation.
- scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry(
- new MockURLRequestThrottlerEntry(&manager));
- if (!enable_throttling)
- throttler_entry->DisableBackoffThrottling();
-
- Requester* attacker = new Requester(throttler_entry.get(),
- TimeDelta::FromMilliseconds(1),
- server,
- attacker_results);
- attacker->SetStartupJitter(TimeDelta::FromSeconds(120));
- requesters.push_back(attacker);
- simulation.AddActor(attacker);
- }
- for (size_t i = 0; i < kNumClients; ++i) {
- // Normal clients only make requests every 2 minutes, plus/minus 1 minute.
- scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry(
- new MockURLRequestThrottlerEntry(&manager));
- if (!enable_throttling)
- throttler_entry->DisableBackoffThrottling();
-
- Requester* client = new Requester(throttler_entry.get(),
- TimeDelta::FromMinutes(2),
- server,
- client_results);
- client->SetStartupJitter(TimeDelta::FromSeconds(120));
- client->SetRequestJitter(TimeDelta::FromMinutes(1));
- requesters.push_back(client);
- simulation.AddActor(client);
- }
- simulation.AddActor(server);
-
- simulation.RunSimulation(TimeDelta::FromMinutes(6),
- TimeDelta::FromSeconds(1));
-}
-
-TEST(URLRequestThrottlerSimulation, HelpsInAttack) {
- Server unprotected_server(30, 1.0);
- RequesterResults unprotected_attacker_results;
- RequesterResults unprotected_client_results;
- Server protected_server(30, 1.0);
- RequesterResults protected_attacker_results;
- RequesterResults protected_client_results;
- SimulateAttack(&unprotected_server,
- &unprotected_attacker_results,
- &unprotected_client_results,
- false);
- SimulateAttack(&protected_server,
- &protected_attacker_results,
- &protected_client_results,
- true);
-
- // These assert that the DDoS protection actually benefits the
- // server. Manual inspection of the traffic graphs will show this
- // even more clearly.
- EXPECT_GT(unprotected_server.num_overloaded_ticks(),
- protected_server.num_overloaded_ticks());
- EXPECT_GT(unprotected_server.max_experienced_queries_per_tick(),
- protected_server.max_experienced_queries_per_tick());
-
- // These assert that the DDoS protection actually benefits non-malicious
- // (and non-degenerate/accidentally DDoSing) users.
- EXPECT_LT(protected_client_results.GetBlockedRatio(),
- protected_attacker_results.GetBlockedRatio());
- EXPECT_GT(protected_client_results.GetSuccessRatio(),
- unprotected_client_results.GetSuccessRatio());
-
- // The rest is just for optional manual evaluation of the results;
- // in particular the traffic pattern is interesting.
-
- VerboseOut("\nUnprotected server's results:\n\n");
- VerboseOut(unprotected_server.VisualizeASCII(132).c_str());
- VerboseOut("\n\n");
- VerboseOut("Protected server's results:\n\n");
- VerboseOut(protected_server.VisualizeASCII(132).c_str());
- VerboseOut("\n\n");
-
- unprotected_attacker_results.PrintResults(
- "attackers attacking unprotected server.");
- unprotected_client_results.PrintResults(
- "normal clients making requests to unprotected server.");
- protected_attacker_results.PrintResults(
- "attackers attacking protected server.");
- protected_client_results.PrintResults(
- "normal clients making requests to protected server.");
-}
-
-// Returns the downtime perceived by the client, as a ratio of the
-// actual downtime.
-double SimulateDowntime(const TimeDelta& duration,
- const TimeDelta& average_client_interval,
- bool enable_throttling) {
- TimeDelta time_between_ticks = duration / 200;
- TimeTicks start_downtime = TimeTicks() + (duration / 2);
-
- // A server that never rejects requests, but will go down for maintenance.
- Server server(std::numeric_limits<int>::max(), 1.0);
- server.SetDowntime(start_downtime, duration);
-
- URLRequestThrottlerManager manager;
- scoped_refptr<MockURLRequestThrottlerEntry> throttler_entry(
- new MockURLRequestThrottlerEntry(&manager));
- if (!enable_throttling)
- throttler_entry->DisableBackoffThrottling();
-
- Requester requester(
- throttler_entry.get(), average_client_interval, &server, NULL);
- requester.SetStartupJitter(duration / 3);
- requester.SetRequestJitter(average_client_interval);
-
- DiscreteTimeSimulation simulation;
- simulation.AddActor(&requester);
- simulation.AddActor(&server);
-
- simulation.RunSimulation(duration * 2, time_between_ticks);
-
- return static_cast<double>(
- requester.last_downtime_duration().InMilliseconds()) /
- static_cast<double>(duration.InMilliseconds());
-}
-
-TEST(URLRequestThrottlerSimulation, PerceivedDowntimeRatio) {
- struct Stats {
- // Expected interval that we expect the ratio of downtime when anti-DDoS
- // is enabled and downtime when anti-DDoS is not enabled to fall within.
- //
- // The expected interval depends on two things: The exponential back-off
- // policy encoded in URLRequestThrottlerEntry, and the test or set of
- // tests that the Stats object is tracking (e.g. a test where the client
- // retries very rapidly on a very long downtime will tend to increase the
- // number).
- //
- // To determine an appropriate new interval when parameters have changed,
- // run the test a few times (you may have to Ctrl-C out of it after a few
- // seconds) and choose an interval that the test converges quickly and
- // reliably to. Then set the new interval, and run the test e.g. 20 times
- // in succession to make sure it never takes an obscenely long time to
- // converge to this interval.
- double expected_min_increase;
- double expected_max_increase;
-
- size_t num_runs;
- double total_ratio_unprotected;
- double total_ratio_protected;
-
- bool DidConverge(double* increase_ratio_out) {
- double unprotected_ratio = total_ratio_unprotected / num_runs;
- double protected_ratio = total_ratio_protected / num_runs;
- double increase_ratio = protected_ratio / unprotected_ratio;
- if (increase_ratio_out)
- *increase_ratio_out = increase_ratio;
- return expected_min_increase <= increase_ratio &&
- increase_ratio <= expected_max_increase;
- }
-
- void ReportTrialResult(double increase_ratio) {
- VerboseOut(
- " Perceived downtime with throttling is %.4f times without.\n",
- increase_ratio);
- VerboseOut(" Test result after %d trials.\n", num_runs);
- }
- };
-
- Stats global_stats = { 1.08, 1.15 };
-
- struct Trial {
- TimeDelta duration;
- TimeDelta average_client_interval;
- Stats stats;
-
- void PrintTrialDescription() {
- double duration_minutes =
- static_cast<double>(duration.InSeconds()) / 60.0;
- double interval_minutes =
- static_cast<double>(average_client_interval.InSeconds()) / 60.0;
- VerboseOut("Trial with %.2f min downtime, avg. interval %.2f min.\n",
- duration_minutes, interval_minutes);
- }
- };
-
- // We don't set or check expected ratio intervals on individual
- // experiments as this might make the test too fragile, but we
- // print them out at the end for manual evaluation (we want to be
- // able to make claims about the expected ratios depending on the
- // type of behavior of the client and the downtime, e.g. the difference
- // in behavior between a client making requests every few minutes vs.
- // one that makes a request every 15 seconds).
- Trial trials[] = {
- { TimeDelta::FromSeconds(10), TimeDelta::FromSeconds(3) },
- { TimeDelta::FromSeconds(30), TimeDelta::FromSeconds(7) },
- { TimeDelta::FromMinutes(5), TimeDelta::FromSeconds(30) },
- { TimeDelta::FromMinutes(10), TimeDelta::FromSeconds(20) },
- { TimeDelta::FromMinutes(20), TimeDelta::FromSeconds(15) },
- { TimeDelta::FromMinutes(20), TimeDelta::FromSeconds(50) },
- { TimeDelta::FromMinutes(30), TimeDelta::FromMinutes(2) },
- { TimeDelta::FromMinutes(30), TimeDelta::FromMinutes(5) },
- { TimeDelta::FromMinutes(40), TimeDelta::FromMinutes(7) },
- { TimeDelta::FromMinutes(40), TimeDelta::FromMinutes(2) },
- { TimeDelta::FromMinutes(40), TimeDelta::FromSeconds(15) },
- { TimeDelta::FromMinutes(60), TimeDelta::FromMinutes(7) },
- { TimeDelta::FromMinutes(60), TimeDelta::FromMinutes(2) },
- { TimeDelta::FromMinutes(60), TimeDelta::FromSeconds(15) },
- { TimeDelta::FromMinutes(80), TimeDelta::FromMinutes(20) },
- { TimeDelta::FromMinutes(80), TimeDelta::FromMinutes(3) },
- { TimeDelta::FromMinutes(80), TimeDelta::FromSeconds(15) },
-
- // Most brutal?
- { TimeDelta::FromMinutes(45), TimeDelta::FromMilliseconds(500) },
- };
-
- // If things don't converge by the time we've done 100K trials, then
- // clearly one or more of the expected intervals are wrong.
- while (global_stats.num_runs < 100000) {
- for (size_t i = 0; i < arraysize(trials); ++i) {
- ++global_stats.num_runs;
- ++trials[i].stats.num_runs;
- double ratio_unprotected = SimulateDowntime(
- trials[i].duration, trials[i].average_client_interval, false);
- double ratio_protected = SimulateDowntime(
- trials[i].duration, trials[i].average_client_interval, true);
- global_stats.total_ratio_unprotected += ratio_unprotected;
- global_stats.total_ratio_protected += ratio_protected;
- trials[i].stats.total_ratio_unprotected += ratio_unprotected;
- trials[i].stats.total_ratio_protected += ratio_protected;
- }
-
- double increase_ratio;
- if (global_stats.DidConverge(&increase_ratio))
- break;
-
- if (global_stats.num_runs > 200) {
- VerboseOut("Test has not yet converged on expected interval.\n");
- global_stats.ReportTrialResult(increase_ratio);
- }
- }
-
- double average_increase_ratio;
- EXPECT_TRUE(global_stats.DidConverge(&average_increase_ratio));
-
- // Print individual trial results for optional manual evaluation.
- double max_increase_ratio = 0.0;
- for (size_t i = 0; i < arraysize(trials); ++i) {
- double increase_ratio;
- trials[i].stats.DidConverge(&increase_ratio);
- max_increase_ratio = std::max(max_increase_ratio, increase_ratio);
- trials[i].PrintTrialDescription();
- trials[i].stats.ReportTrialResult(increase_ratio);
- }
-
- VerboseOut("Average increase ratio was %.4f\n", average_increase_ratio);
- VerboseOut("Maximum increase ratio was %.4f\n", max_increase_ratio);
-}
-
-} // namespace
-} // namespace net
« no previous file with comments | « net/url_request/url_request_throttler_manager.cc ('k') | net/url_request/url_request_throttler_test_support.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698