libweave: Move backoff_entry from libchromeos into libweave It's used by libweave only. BUG=brillo:1257 TEST=`FEATURES=test emerge-gizmo libchromeos libweave` Change-Id: I07aa30a9b758161bf29c8bce7a057550f565dc94 Reviewed-on: https://chromium-review.googlesource.com/293421 Reviewed-by: Alex Vakulenko <avakulenko@chromium.org> Commit-Queue: Vitaly Buka <vitalybuka@chromium.org> Tested-by: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/libweave/libweave.gyp b/libweave/libweave.gyp index 05fc5ca..e0287d7 100644 --- a/libweave/libweave.gyp +++ b/libweave/libweave.gyp
@@ -27,6 +27,7 @@ 'target_name': 'libweave_common', 'type': 'static_library', 'sources': [ + 'src/backoff_entry.cc', 'src/base_api_handler.cc', 'src/buffet_config.cc', 'src/commands/cloud_command_proxy.cc', @@ -119,6 +120,7 @@ 'external/crypto/p224_spake_unittest.cc', 'external/crypto/p224_unittest.cc', 'external/crypto/sha2_unittest.cc', + 'src/backoff_entry_unittest.cc', 'src/base_api_handler_unittest.cc', 'src/buffet_config_unittest.cc', 'src/commands/cloud_command_proxy_unittest.cc',
diff --git a/libweave/src/backoff_entry.cc b/libweave/src/backoff_entry.cc new file mode 100644 index 0000000..b9c5b8f --- /dev/null +++ b/libweave/src/backoff_entry.cc
@@ -0,0 +1,167 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "libweave/src/backoff_entry.h" + +#include <algorithm> +#include <cmath> +#include <limits> + +#include <base/logging.h> +#include <base/numerics/safe_math.h> +#include <base/rand_util.h> + +namespace weave { + +BackoffEntry::BackoffEntry(const BackoffEntry::Policy* const policy) + : policy_(policy) { + DCHECK(policy_); + Reset(); +} + +void BackoffEntry::InformOfRequest(bool succeeded) { + if (!succeeded) { + ++failure_count_; + exponential_backoff_release_time_ = CalculateReleaseTime(); + } else { + // We slowly decay the number of times delayed instead of + // resetting it to 0 in order to stay stable if we receive + // successes interleaved between lots of failures. Note that in + // the normal case, the calculated release time (in the next + // statement) will be in the past once the method returns. + if (failure_count_ > 0) + --failure_count_; + + // The reason why we are not just cutting the release time to + // ImplGetTimeNow() is on the one hand, it would unset a release + // time set by SetCustomReleaseTime and on the other we would like + // to push every request up to our "horizon" when dealing with + // multiple in-flight requests. Ex: If we send three requests and + // we receive 2 failures and 1 success. The success that follows + // those failures will not reset the release time, further + // requests will then need to wait the delay caused by the 2 + // failures. + base::TimeDelta delay; + if (policy_->always_use_initial_delay) + delay = base::TimeDelta::FromMilliseconds(policy_->initial_delay_ms); + exponential_backoff_release_time_ = + std::max(ImplGetTimeNow() + delay, exponential_backoff_release_time_); + } +} + +bool BackoffEntry::ShouldRejectRequest() const { + return exponential_backoff_release_time_ > ImplGetTimeNow(); +} + +base::TimeDelta BackoffEntry::GetTimeUntilRelease() const { + base::TimeTicks now = ImplGetTimeNow(); + if (exponential_backoff_release_time_ <= now) + return base::TimeDelta(); + return exponential_backoff_release_time_ - now; +} + +base::TimeTicks BackoffEntry::GetReleaseTime() const { + return exponential_backoff_release_time_; +} + +void BackoffEntry::SetCustomReleaseTime(const base::TimeTicks& release_time) { + exponential_backoff_release_time_ = release_time; +} + +bool BackoffEntry::CanDiscard() const { + if (policy_->entry_lifetime_ms == -1) + return false; + + base::TimeTicks now = ImplGetTimeNow(); + + int64 unused_since_ms = + (now - exponential_backoff_release_time_).InMilliseconds(); + + // Release time is further than now, we are managing it. + if (unused_since_ms < 0) + return false; + + if (failure_count_ > 0) { + // Need to keep track of failures until maximum back-off period + // has passed (since further failures can add to back-off). + return unused_since_ms >= + std::max(policy_->maximum_backoff_ms, policy_->entry_lifetime_ms); + } + + // Otherwise, consider the entry is outdated if it hasn't been used for the + // specified lifetime period. + return unused_since_ms >= policy_->entry_lifetime_ms; +} + +void BackoffEntry::Reset() { + failure_count_ = 0; + + // We leave exponential_backoff_release_time_ unset, meaning 0. We could + // initialize to ImplGetTimeNow() but because it's a virtual method it's + // not safe to call in the constructor (and the constructor calls Reset()). + // The effects are the same, i.e. ShouldRejectRequest() will return false + // right after Reset(). + exponential_backoff_release_time_ = base::TimeTicks(); +} + +base::TimeTicks BackoffEntry::ImplGetTimeNow() const { + return base::TimeTicks::Now(); +} + +base::TimeTicks BackoffEntry::CalculateReleaseTime() const { + int effective_failure_count = + std::max(0, failure_count_ - policy_->num_errors_to_ignore); + + // If always_use_initial_delay is true, it's equivalent to + // the effective_failure_count always being one greater than when it's false. + if (policy_->always_use_initial_delay) + ++effective_failure_count; + + if (effective_failure_count == 0) { + // Never reduce previously set release horizon, e.g. due to Retry-After + // header. + return std::max(ImplGetTimeNow(), exponential_backoff_release_time_); + } + + // The delay is calculated with this formula: + // delay = initial_backoff * multiply_factor^( + // effective_failure_count - 1) * Uniform(1 - jitter_factor, 1] + // Note: if the failure count is too high, |delay_ms| will become infinity + // after the exponential calculation, and then NaN after the jitter is + // accounted for. Both cases are handled by using CheckedNumeric<int64_t> to + // perform the conversion to integers. + double delay_ms = policy_->initial_delay_ms; + delay_ms *= pow(policy_->multiply_factor, effective_failure_count - 1); + delay_ms -= base::RandDouble() * policy_->jitter_factor * delay_ms; + + // Do overflow checking in microseconds, the internal unit of TimeTicks. + const int64_t kTimeTicksNowUs = + (ImplGetTimeNow() - base::TimeTicks()).InMicroseconds(); + base::internal::CheckedNumeric<int64_t> calculated_release_time_us = + delay_ms + 0.5; + calculated_release_time_us *= base::Time::kMicrosecondsPerMillisecond; + calculated_release_time_us += kTimeTicksNowUs; + + const int64_t kMaxTime = std::numeric_limits<int64_t>::max(); + base::internal::CheckedNumeric<int64_t> maximum_release_time_us = kMaxTime; + if (policy_->maximum_backoff_ms >= 0) { + maximum_release_time_us = policy_->maximum_backoff_ms; + maximum_release_time_us *= base::Time::kMicrosecondsPerMillisecond; + maximum_release_time_us += kTimeTicksNowUs; + } + + // Decide between maximum release time and calculated release time, accounting + // for overflow with both. + int64 release_time_us = + std::min(calculated_release_time_us.ValueOrDefault(kMaxTime), + maximum_release_time_us.ValueOrDefault(kMaxTime)); + + // Never reduce previously set release horizon, e.g. due to Retry-After + // header. + return std::max( + base::TimeTicks() + base::TimeDelta::FromMicroseconds(release_time_us), + exponential_backoff_release_time_); +} + +} // namespace weave
diff --git a/libweave/src/backoff_entry.h b/libweave/src/backoff_entry.h new file mode 100644 index 0000000..3e7a036 --- /dev/null +++ b/libweave/src/backoff_entry.h
@@ -0,0 +1,114 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIBWEAVE_SRC_BACKOFF_ENTRY_H_ +#define LIBWEAVE_SRC_BACKOFF_ENTRY_H_ + +#include <base/time/time.h> + +namespace weave { + +// Provides the core logic needed for randomized exponential back-off +// on requests to a given resource, given a back-off policy. +// +// This class is largely taken from net/base/backoff_entry.h from Chromium. +// TODO(avakulenko): Consider packaging portions of Chrome's //net functionality +// into the current libchrome library. +class BackoffEntry { + public: + // The set of parameters that define a back-off policy. + struct Policy { + // Number of initial errors (in sequence) to ignore before applying + // exponential back-off rules. + int num_errors_to_ignore; + + // Initial delay. The interpretation of this value depends on + // always_use_initial_delay. It's either how long we wait between + // requests before backoff starts, or how much we delay the first request + // after backoff starts. + int initial_delay_ms; + + // Factor by which the waiting time will be multiplied. + double multiply_factor; + + // Fuzzing percentage. ex: 10% will spread requests randomly + // between 90%-100% of the calculated time. + double jitter_factor; + + // Maximum amount of time we are willing to delay our request, -1 + // for no maximum. + int64 maximum_backoff_ms; + + // Time to keep an entry from being discarded even when it + // has no significant state, -1 to never discard. + int64 entry_lifetime_ms; + + // If true, we always use a delay of initial_delay_ms, even before + // we've seen num_errors_to_ignore errors. Otherwise, initial_delay_ms + // is the first delay once we start exponential backoff. + // + // So if we're ignoring 1 error, we'll see (N, N, Nm, Nm^2, ...) if true, + // and (0, 0, N, Nm, ...) when false, where N is initial_backoff_ms and + // m is multiply_factor, assuming we've already seen one success. + bool always_use_initial_delay; + }; + + // Lifetime of policy must enclose lifetime of BackoffEntry. The + // pointer must be valid but is not dereferenced during construction. + explicit BackoffEntry(const Policy* const policy); + virtual ~BackoffEntry() = default; + + // Inform this item that a request for the network resource it is + // tracking was made, and whether it failed or succeeded. + void InformOfRequest(bool succeeded); + + // Returns true if a request for the resource this item tracks should + // be rejected at the present time due to exponential back-off policy. + bool ShouldRejectRequest() const; + + // Returns the absolute time after which this entry (given its present + // state) will no longer reject requests. + base::TimeTicks GetReleaseTime() const; + + // Returns the time until a request can be sent. + base::TimeDelta GetTimeUntilRelease() const; + + // Causes this object reject requests until the specified absolute time. + // This can be used to e.g. implement support for a Retry-After header. + void SetCustomReleaseTime(const base::TimeTicks& release_time); + + // Returns true if this object has no significant state (i.e. you could + // just as well start with a fresh BackoffEntry object), and hasn't + // had for Policy::entry_lifetime_ms. + bool CanDiscard() const; + + // Resets this entry to a fresh (as if just constructed) state. + void Reset(); + + // Returns the failure count for this entry. + int failure_count() const { return failure_count_; } + + protected: + // Equivalent to TimeTicks::Now(), virtual so unit tests can override. + virtual base::TimeTicks ImplGetTimeNow() const; + + private: + // Calculates when requests should again be allowed through. + base::TimeTicks CalculateReleaseTime() const; + + // Timestamp calculated by the exponential back-off algorithm at which we are + // allowed to start sending requests again. + base::TimeTicks exponential_backoff_release_time_; + + // Counts request errors; decremented on success. + int failure_count_; + + const Policy* const policy_; + + DISALLOW_COPY_AND_ASSIGN(BackoffEntry); +}; + +} // namespace weave + +#endif // LIBWEAVE_SRC_BACKOFF_ENTRY_H_
diff --git a/libweave/src/backoff_entry_unittest.cc b/libweave/src/backoff_entry_unittest.cc new file mode 100644 index 0000000..5b198a0 --- /dev/null +++ b/libweave/src/backoff_entry_unittest.cc
@@ -0,0 +1,309 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "libweave/src/backoff_entry.h" + +#include <gtest/gtest.h> + +using base::TimeDelta; +using base::TimeTicks; + +namespace weave { + +BackoffEntry::Policy base_policy = {0, 1000, 2.0, 0.0, 20000, 2000, false}; + +class TestBackoffEntry : public BackoffEntry { + public: + explicit TestBackoffEntry(const Policy* const policy) + : BackoffEntry(policy), now_(TimeTicks()) { + // Work around initialization in constructor not picking up + // fake time. + SetCustomReleaseTime(TimeTicks()); + } + + ~TestBackoffEntry() override {} + + TimeTicks ImplGetTimeNow() const override { return now_; } + + void set_now(const TimeTicks& now) { now_ = now; } + + private: + TimeTicks now_; + + DISALLOW_COPY_AND_ASSIGN(TestBackoffEntry); +}; + +TEST(BackoffEntryTest, BaseTest) { + TestBackoffEntry entry(&base_policy); + EXPECT_FALSE(entry.ShouldRejectRequest()); + EXPECT_EQ(TimeDelta(), entry.GetTimeUntilRelease()); + + entry.InformOfRequest(false); + EXPECT_TRUE(entry.ShouldRejectRequest()); + EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease()); +} + +TEST(BackoffEntryTest, CanDiscardNeverExpires) { + BackoffEntry::Policy never_expires_policy = base_policy; + never_expires_policy.entry_lifetime_ms = -1; + TestBackoffEntry never_expires(&never_expires_policy); + EXPECT_FALSE(never_expires.CanDiscard()); + never_expires.set_now(TimeTicks() + TimeDelta::FromDays(100)); + EXPECT_FALSE(never_expires.CanDiscard()); +} + +TEST(BackoffEntryTest, CanDiscard) { + TestBackoffEntry entry(&base_policy); + // Because lifetime is non-zero, we shouldn't be able to discard yet. + EXPECT_FALSE(entry.CanDiscard()); + + // Test the "being used" case. + entry.InformOfRequest(false); + EXPECT_FALSE(entry.CanDiscard()); + + // Test the case where there are errors but we can time out. + entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(1)); + EXPECT_FALSE(entry.CanDiscard()); + entry.set_now( + entry.GetReleaseTime() + + TimeDelta::FromMilliseconds(base_policy.maximum_backoff_ms + 1)); + EXPECT_TRUE(entry.CanDiscard()); + + // Test the final case (no errors, dependent only on specified lifetime). + entry.set_now(entry.GetReleaseTime() + + TimeDelta::FromMilliseconds(base_policy.entry_lifetime_ms - 1)); + entry.InformOfRequest(true); + EXPECT_FALSE(entry.CanDiscard()); + entry.set_now(entry.GetReleaseTime() + + TimeDelta::FromMilliseconds(base_policy.entry_lifetime_ms)); + EXPECT_TRUE(entry.CanDiscard()); +} + +TEST(BackoffEntryTest, CanDiscardAlwaysDelay) { + BackoffEntry::Policy always_delay_policy = base_policy; + always_delay_policy.always_use_initial_delay = true; + always_delay_policy.entry_lifetime_ms = 0; + + TestBackoffEntry entry(&always_delay_policy); + + // Because lifetime is non-zero, we shouldn't be able to discard yet. + entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(2000)); + EXPECT_TRUE(entry.CanDiscard()); + + // Even with no failures, we wait until the delay before we allow discard. + entry.InformOfRequest(true); + EXPECT_FALSE(entry.CanDiscard()); + + // Wait until the delay expires, and we can discard the entry again. + entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(1000)); + EXPECT_TRUE(entry.CanDiscard()); +} + +TEST(BackoffEntryTest, CanDiscardNotStored) { + BackoffEntry::Policy no_store_policy = base_policy; + no_store_policy.entry_lifetime_ms = 0; + TestBackoffEntry not_stored(&no_store_policy); + EXPECT_TRUE(not_stored.CanDiscard()); +} + +TEST(BackoffEntryTest, ShouldIgnoreFirstTwo) { + BackoffEntry::Policy lenient_policy = base_policy; + lenient_policy.num_errors_to_ignore = 2; + + BackoffEntry entry(&lenient_policy); + + entry.InformOfRequest(false); + EXPECT_FALSE(entry.ShouldRejectRequest()); + + entry.InformOfRequest(false); + EXPECT_FALSE(entry.ShouldRejectRequest()); + + entry.InformOfRequest(false); + EXPECT_TRUE(entry.ShouldRejectRequest()); +} + +TEST(BackoffEntryTest, ReleaseTimeCalculation) { + TestBackoffEntry entry(&base_policy); + + // With zero errors, should return "now". + TimeTicks result = entry.GetReleaseTime(); + EXPECT_EQ(entry.ImplGetTimeNow(), result); + + // 1 error. + entry.InformOfRequest(false); + result = entry.GetReleaseTime(); + EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(1000), result); + EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease()); + + // 2 errors. + entry.InformOfRequest(false); + result = entry.GetReleaseTime(); + EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(2000), result); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease()); + + // 3 errors. + entry.InformOfRequest(false); + result = entry.GetReleaseTime(); + EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(4000), result); + EXPECT_EQ(TimeDelta::FromMilliseconds(4000), entry.GetTimeUntilRelease()); + + // 6 errors (to check it doesn't pass maximum). + entry.InformOfRequest(false); + entry.InformOfRequest(false); + entry.InformOfRequest(false); + result = entry.GetReleaseTime(); + EXPECT_EQ(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(20000), + result); +} + +TEST(BackoffEntryTest, ReleaseTimeCalculationAlwaysDelay) { + BackoffEntry::Policy always_delay_policy = base_policy; + always_delay_policy.always_use_initial_delay = true; + always_delay_policy.num_errors_to_ignore = 2; + + TestBackoffEntry entry(&always_delay_policy); + + // With previous requests, should return "now". + TimeTicks result = entry.GetReleaseTime(); + EXPECT_EQ(TimeDelta(), entry.GetTimeUntilRelease()); + + // 1 error. + entry.InformOfRequest(false); + EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease()); + + // 2 errors. + entry.InformOfRequest(false); + EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease()); + + // 3 errors, exponential backoff starts. + entry.InformOfRequest(false); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease()); + + // 4 errors. + entry.InformOfRequest(false); + EXPECT_EQ(TimeDelta::FromMilliseconds(4000), entry.GetTimeUntilRelease()); + + // 8 errors (to check it doesn't pass maximum). + entry.InformOfRequest(false); + entry.InformOfRequest(false); + entry.InformOfRequest(false); + entry.InformOfRequest(false); + result = entry.GetReleaseTime(); + EXPECT_EQ(TimeDelta::FromMilliseconds(20000), entry.GetTimeUntilRelease()); +} + +TEST(BackoffEntryTest, ReleaseTimeCalculationWithJitter) { + for (int i = 0; i < 10; ++i) { + BackoffEntry::Policy jittery_policy = base_policy; + jittery_policy.jitter_factor = 0.2; + + TestBackoffEntry entry(&jittery_policy); + + entry.InformOfRequest(false); + entry.InformOfRequest(false); + entry.InformOfRequest(false); + TimeTicks result = entry.GetReleaseTime(); + EXPECT_LE(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(3200), + result); + EXPECT_GE(entry.ImplGetTimeNow() + TimeDelta::FromMilliseconds(4000), + result); + } +} + +TEST(BackoffEntryTest, FailureThenSuccess) { + TestBackoffEntry entry(&base_policy); + + // Failure count 1, establishes horizon. + entry.InformOfRequest(false); + TimeTicks release_time = entry.GetReleaseTime(); + EXPECT_EQ(TimeTicks() + TimeDelta::FromMilliseconds(1000), release_time); + + // Success, failure count 0, should not advance past + // the horizon that was already set. + entry.set_now(release_time - TimeDelta::FromMilliseconds(200)); + entry.InformOfRequest(true); + EXPECT_EQ(release_time, entry.GetReleaseTime()); + + // Failure, failure count 1. + entry.InformOfRequest(false); + EXPECT_EQ(release_time + TimeDelta::FromMilliseconds(800), + entry.GetReleaseTime()); +} + +TEST(BackoffEntryTest, FailureThenSuccessAlwaysDelay) { + BackoffEntry::Policy always_delay_policy = base_policy; + always_delay_policy.always_use_initial_delay = true; + always_delay_policy.num_errors_to_ignore = 1; + + TestBackoffEntry entry(&always_delay_policy); + + // Failure count 1. + entry.InformOfRequest(false); + EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease()); + + // Failure count 2. + entry.InformOfRequest(false); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease()); + entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(2000)); + + // Success. We should go back to the original delay. + entry.InformOfRequest(true); + EXPECT_EQ(TimeDelta::FromMilliseconds(1000), entry.GetTimeUntilRelease()); + + // Failure count reaches 2 again. We should increase the delay once more. + entry.InformOfRequest(false); + EXPECT_EQ(TimeDelta::FromMilliseconds(2000), entry.GetTimeUntilRelease()); + entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(2000)); +} + +TEST(BackoffEntryTest, RetainCustomHorizon) { + TestBackoffEntry custom(&base_policy); + TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3); + custom.SetCustomReleaseTime(custom_horizon); + custom.InformOfRequest(false); + custom.InformOfRequest(true); + custom.set_now(TimeTicks() + TimeDelta::FromDays(2)); + custom.InformOfRequest(false); + custom.InformOfRequest(true); + EXPECT_EQ(custom_horizon, custom.GetReleaseTime()); + + // Now check that once we are at or past the custom horizon, + // we get normal behavior. + custom.set_now(TimeTicks() + TimeDelta::FromDays(3)); + custom.InformOfRequest(false); + EXPECT_EQ( + TimeTicks() + TimeDelta::FromDays(3) + TimeDelta::FromMilliseconds(1000), + custom.GetReleaseTime()); +} + +TEST(BackoffEntryTest, RetainCustomHorizonWhenInitialErrorsIgnored) { + // Regression test for a bug discovered during code review. + BackoffEntry::Policy lenient_policy = base_policy; + lenient_policy.num_errors_to_ignore = 1; + TestBackoffEntry custom(&lenient_policy); + TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3); + custom.SetCustomReleaseTime(custom_horizon); + custom.InformOfRequest(false); // This must not reset the horizon. + EXPECT_EQ(custom_horizon, custom.GetReleaseTime()); +} + +TEST(BackoffEntryTest, OverflowProtection) { + BackoffEntry::Policy large_multiply_policy = base_policy; + large_multiply_policy.multiply_factor = 256; + TestBackoffEntry custom(&large_multiply_policy); + + // Trigger enough failures such that more than 11 bits of exponent are used + // to represent the exponential backoff intermediate values. Given a multiply + // factor of 256 (2^8), 129 iterations is enough: 2^(8*(129-1)) = 2^1024. + for (int i = 0; i < 129; ++i) { + custom.set_now(custom.ImplGetTimeNow() + custom.GetTimeUntilRelease()); + custom.InformOfRequest(false); + ASSERT_TRUE(custom.ShouldRejectRequest()); + } + + // Max delay should still be respected. + EXPECT_EQ(20000, custom.GetTimeUntilRelease().InMilliseconds()); +} + +} // namespace weave
diff --git a/libweave/src/commands/cloud_command_proxy.cc b/libweave/src/commands/cloud_command_proxy.cc index 58da7d1..d38fa04 100644 --- a/libweave/src/commands/cloud_command_proxy.cc +++ b/libweave/src/commands/cloud_command_proxy.cc
@@ -19,7 +19,7 @@ CommandInstance* command_instance, CloudCommandUpdateInterface* cloud_command_updater, StateChangeQueueInterface* state_change_queue, - std::unique_ptr<chromeos::BackoffEntry> backoff_entry, + std::unique_ptr<BackoffEntry> backoff_entry, TaskRunner* task_runner) : command_instance_{command_instance}, cloud_command_updater_{cloud_command_updater},
diff --git a/libweave/src/commands/cloud_command_proxy.h b/libweave/src/commands/cloud_command_proxy.h index 838b1ff..98a7c6c 100644 --- a/libweave/src/commands/cloud_command_proxy.h +++ b/libweave/src/commands/cloud_command_proxy.h
@@ -13,10 +13,10 @@ #include <base/macros.h> #include <base/memory/weak_ptr.h> #include <base/scoped_observer.h> -#include <chromeos/backoff_entry.h> #include <weave/command.h> #include <weave/task_runner.h> +#include "libweave/src/backoff_entry.h" #include "libweave/src/commands/cloud_command_update_interface.h" #include "libweave/src/states/state_change_queue_interface.h" @@ -30,7 +30,7 @@ CloudCommandProxy(CommandInstance* command_instance, CloudCommandUpdateInterface* cloud_command_updater, StateChangeQueueInterface* state_change_queue, - std::unique_ptr<chromeos::BackoffEntry> backoff_entry, + std::unique_ptr<BackoffEntry> backoff_entry, TaskRunner* task_runner); ~CloudCommandProxy() override = default; @@ -73,7 +73,7 @@ TaskRunner* task_runner_{nullptr}; // Backoff for SendCommandUpdate() method. - std::unique_ptr<chromeos::BackoffEntry> cloud_backoff_entry_; + std::unique_ptr<BackoffEntry> cloud_backoff_entry_; // Set to true while a pending PATCH request is in flight to the server. bool command_update_in_progress_{false};
diff --git a/libweave/src/commands/cloud_command_proxy_unittest.cc b/libweave/src/commands/cloud_command_proxy_unittest.cc index 8bdbfd9..d98776a 100644 --- a/libweave/src/commands/cloud_command_proxy_unittest.cc +++ b/libweave/src/commands/cloud_command_proxy_unittest.cc
@@ -58,15 +58,15 @@ }; // Test back-off entry that uses the test clock. -class TestBackoffEntry : public chromeos::BackoffEntry { +class TestBackoffEntry : public BackoffEntry { public: TestBackoffEntry(const Policy* const policy, base::Clock* clock) - : chromeos::BackoffEntry{policy}, clock_{clock} { + : BackoffEntry{policy}, clock_{clock} { creation_time_ = clock->Now(); } private: - // Override from chromeos::BackoffEntry to use the custom test clock for + // Override from BackoffEntry to use the custom test clock for // the backoff calculations. base::TimeTicks ImplGetTimeNow() const override { return base::TimeTicks::FromInternalValue(clock_->Now().ToInternalValue()); @@ -143,8 +143,8 @@ CHECK(command_instance_.get()); // Backoff - start at 1s and double with each backoff attempt and no jitter. - static const chromeos::BackoffEntry::Policy policy{ - 0, 1000, 2.0, 0.0, 20000, -1, false}; + static const BackoffEntry::Policy policy{0, 1000, 2.0, 0.0, + 20000, -1, false}; std::unique_ptr<TestBackoffEntry> backoff{ new TestBackoffEntry{&policy, &clock_}};
diff --git a/libweave/src/device_registration_info.cc b/libweave/src/device_registration_info.cc index f648337..bc738f6 100644 --- a/libweave/src/device_registration_info.cc +++ b/libweave/src/device_registration_info.cc
@@ -222,7 +222,7 @@ config_{std::move(config)}, notifications_enabled_{notifications_enabled}, network_{network} { - cloud_backoff_policy_.reset(new chromeos::BackoffEntry::Policy{}); + cloud_backoff_policy_.reset(new BackoffEntry::Policy{}); cloud_backoff_policy_->num_errors_to_ignore = 0; cloud_backoff_policy_->initial_delay_ms = 1000; cloud_backoff_policy_->multiply_factor = 2.0; @@ -230,10 +230,8 @@ cloud_backoff_policy_->maximum_backoff_ms = 30000; cloud_backoff_policy_->entry_lifetime_ms = -1; cloud_backoff_policy_->always_use_initial_delay = false; - cloud_backoff_entry_.reset( - new chromeos::BackoffEntry{cloud_backoff_policy_.get()}); - oauth2_backoff_entry_.reset( - new chromeos::BackoffEntry{cloud_backoff_policy_.get()}); + cloud_backoff_entry_.reset(new BackoffEntry{cloud_backoff_policy_.get()}); + oauth2_backoff_entry_.reset(new BackoffEntry{cloud_backoff_policy_.get()}); command_manager_->AddOnCommandDefChanged( base::Bind(&DeviceRegistrationInfo::OnCommandDefsChanged, @@ -1102,8 +1100,8 @@ if (!command_manager_->FindCommand(command_instance->GetID())) { LOG(INFO) << "New command '" << command_instance->GetName() << "' arrived, ID: " << command_instance->GetID(); - std::unique_ptr<chromeos::BackoffEntry> backoff_entry{ - new chromeos::BackoffEntry{cloud_backoff_policy_.get()}}; + std::unique_ptr<BackoffEntry> backoff_entry{ + new BackoffEntry{cloud_backoff_policy_.get()}}; std::unique_ptr<CloudCommandProxy> cloud_proxy{new CloudCommandProxy{ command_instance.get(), this, state_manager_->GetStateChangeQueue(), std::move(backoff_entry), task_runner_}};
diff --git a/libweave/src/device_registration_info.h b/libweave/src/device_registration_info.h index 62f2b65..fefc27c 100644 --- a/libweave/src/device_registration_info.h +++ b/libweave/src/device_registration_info.h
@@ -18,7 +18,6 @@ #include <base/single_thread_task_runner.h> #include <base/time/time.h> #include <base/timer/timer.h> -#include <chromeos/backoff_entry.h> #include <chromeos/data_encoding.h> #include <chromeos/errors/error.h> #include <weave/cloud.h> @@ -26,6 +25,7 @@ #include <weave/http_client.h> #include <weave/task_runner.h> +#include "libweave/src/backoff_entry.h" #include "libweave/src/buffet_config.h" #include "libweave/src/commands/cloud_command_update_interface.h" #include "libweave/src/commands/command_manager.h" @@ -311,9 +311,9 @@ std::unique_ptr<BuffetConfig> config_; // Backoff manager for DoCloudRequest() method. - std::unique_ptr<chromeos::BackoffEntry::Policy> cloud_backoff_policy_; - std::unique_ptr<chromeos::BackoffEntry> cloud_backoff_entry_; - std::unique_ptr<chromeos::BackoffEntry> oauth2_backoff_entry_; + std::unique_ptr<BackoffEntry::Policy> cloud_backoff_policy_; + std::unique_ptr<BackoffEntry> cloud_backoff_entry_; + std::unique_ptr<BackoffEntry> oauth2_backoff_entry_; // Flag set to true while a device state update patch request is in flight // to the cloud server.
diff --git a/libweave/src/notification/xmpp_channel.cc b/libweave/src/notification/xmpp_channel.cc index b5aa425..7d0d5c6 100644 --- a/libweave/src/notification/xmpp_channel.cc +++ b/libweave/src/notification/xmpp_channel.cc
@@ -7,11 +7,11 @@ #include <string> #include <base/bind.h> -#include <chromeos/backoff_entry.h> #include <chromeos/data_encoding.h> #include <weave/network.h> #include <weave/task_runner.h> +#include "libweave/src/backoff_entry.h" #include "libweave/src/notification/notification_delegate.h" #include "libweave/src/notification/notification_parser.h" #include "libweave/src/notification/xml_node.h" @@ -47,7 +47,7 @@ // Backoff policy. // Note: In order to ensure a minimum of 20 seconds between server errors, // we have a 30s +- 10s (33%) jitter initial backoff. -const chromeos::BackoffEntry::Policy kDefaultBackoffPolicy = { +const BackoffEntry::Policy kDefaultBackoffPolicy = { // Number of initial errors (in sequence) to ignore before applying // exponential back-off rules. 0,
diff --git a/libweave/src/notification/xmpp_channel.h b/libweave/src/notification/xmpp_channel.h index 1e42c2c..d6ae529 100644 --- a/libweave/src/notification/xmpp_channel.h +++ b/libweave/src/notification/xmpp_channel.h
@@ -13,9 +13,9 @@ #include <base/callback_forward.h> #include <base/macros.h> #include <base/memory/weak_ptr.h> -#include <chromeos/backoff_entry.h> #include <weave/stream.h> +#include "libweave/src/backoff_entry.h" #include "libweave/src/notification/notification_channel.h" #include "libweave/src/notification/xmpp_iq_stanza_handler.h" #include "libweave/src/notification/xmpp_stream_parser.h" @@ -152,7 +152,7 @@ std::string host_; uint16_t port_{0}; - chromeos::BackoffEntry backoff_entry_; + BackoffEntry backoff_entry_; NotificationDelegate* delegate_{nullptr}; TaskRunner* task_runner_{nullptr}; XmppStreamParser stream_parser_{this};