910e62b5创建于 1月15日历史提交
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/cronet/host_cache_persistence_manager.h"

#include "base/test/scoped_mock_time_message_loop_task_runner.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/network_isolation_key.h"
#include "net/dns/host_cache.h"
#include "net/dns/public/dns_query_type.h"
#include "net/dns/public/host_resolver_source.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cronet {

class HostCachePersistenceManagerTest : public testing::Test {
 protected:
  void SetUp() override {
    cache_ = std::make_unique<net::HostCache>(/*max_entries=*/1000);
    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
    pref_service_->registry()->RegisterListPref(kPrefName);
  }

  void MakePersistenceManager(base::TimeDelta delay) {
    persistence_manager_ = std::make_unique<HostCachePersistenceManager>(
        cache_.get(), pref_service_.get(), kPrefName, delay, nullptr);
  }

  // Sets an entry in the HostCache in order to trigger a pref write. The
  // caller is responsible for making sure this is a change that will trigger
  // a write, and the HostCache's interaction with its PersistenceDelegate is
  // assumed to work (it's tested in net/dns/host_cache_unittest.cc).
  void WriteToCache(const std::string& host) {
    net::HostCache::Key key(host, net::DnsQueryType::UNSPECIFIED, 0,
                            net::HostResolverSource::ANY,
                            net::NetworkAnonymizationKey());
    net::HostCache::Entry entry(net::OK, /*ip_endpoints=*/{}, /*aliases=*/{},
                                net::HostCache::Entry::SOURCE_UNKNOWN);
    cache_->Set(key, entry, base::TimeTicks::Now(), base::Seconds(1));
  }

  // Reads the current value of the pref from the TestingPrefServiceSimple
  // and deserializes it into a temporary new HostCache. Only checks the size,
  // not the full contents, since the tests in this file are only intended
  // to test that writes happen when they're supposed to, not serialization
  // correctness.
  void CheckPref(size_t expected_size) {
    const base::Value* value = pref_service_->GetUserPref(kPrefName);
    net::HostCache temp_cache(10);
    if (value)
      temp_cache.RestoreFromListValue(value->GetList());
    ASSERT_EQ(expected_size, temp_cache.size());
  }

  // Generates a temporary HostCache with a few entries and uses it to
  // initialize the value in prefs.
  void InitializePref() {
    net::HostCache temp_cache(10);

    net::HostCache::Key key1("1.test", net::DnsQueryType::UNSPECIFIED, 0,
                             net::HostResolverSource::ANY,
                             net::NetworkAnonymizationKey());
    net::HostCache::Key key2("2.test", net::DnsQueryType::UNSPECIFIED, 0,
                             net::HostResolverSource::ANY,
                             net::NetworkAnonymizationKey());
    net::HostCache::Key key3("3.test", net::DnsQueryType::UNSPECIFIED, 0,
                             net::HostResolverSource::ANY,
                             net::NetworkAnonymizationKey());
    net::HostCache::Entry entry(net::OK, /*ip_endpoints=*/{}, /*aliases=*/{},
                                net::HostCache::Entry::SOURCE_UNKNOWN);

    temp_cache.Set(key1, entry, base::TimeTicks::Now(), base::Seconds(1));
    temp_cache.Set(key2, entry, base::TimeTicks::Now(), base::Seconds(1));
    temp_cache.Set(key3, entry, base::TimeTicks::Now(), base::Seconds(1));

    base::Value::List list;
    temp_cache.GetList(list, false /* include_stale */,
                       net::HostCache::SerializationType::kRestorable);
    pref_service_->SetList(kPrefName, std::move(list));
  }

  static const char kPrefName[];

  base::test::TaskEnvironment task_environment_;
  base::ScopedMockTimeMessageLoopTaskRunner task_runner_;

  // The HostCache and PrefService have to outlive the
  // HostCachePersistenceManager.
  std::unique_ptr<net::HostCache> cache_;
  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
  std::unique_ptr<HostCachePersistenceManager> persistence_manager_;
};

const char HostCachePersistenceManagerTest::kPrefName[] = "net.test";

// Make a single change to the HostCache and make sure that it's written
// when the timer expires. Then repeat.
TEST_F(HostCachePersistenceManagerTest, SeparateWrites) {
  MakePersistenceManager(base::Seconds(60));

  WriteToCache("1.test");
  task_runner_->FastForwardBy(base::Seconds(59));
  CheckPref(0);
  task_runner_->FastForwardBy(base::Seconds(1));
  CheckPref(1);

  WriteToCache("2.test");
  task_runner_->FastForwardBy(base::Seconds(59));
  CheckPref(1);
  task_runner_->FastForwardBy(base::Seconds(1));
  CheckPref(2);
}

// Write to the HostCache multiple times and make sure that all changes
// are written to prefs at the appropriate times.
TEST_F(HostCachePersistenceManagerTest, MultipleWrites) {
  MakePersistenceManager(base::Seconds(300));

  WriteToCache("1.test");
  WriteToCache("2.test");
  task_runner_->FastForwardBy(base::Seconds(299));
  CheckPref(0);
  task_runner_->FastForwardBy(base::Seconds(1));
  CheckPref(2);

  WriteToCache("3.test");
  WriteToCache("4.test");
  task_runner_->FastForwardBy(base::Seconds(299));
  CheckPref(2);
  task_runner_->FastForwardBy(base::Seconds(1));
  CheckPref(4);
}

// Make changes to the HostCache at different times and ensure that the writes
// to prefs are batched as expected.
TEST_F(HostCachePersistenceManagerTest, BatchedWrites) {
  MakePersistenceManager(base::Milliseconds(100));

  WriteToCache("1.test");
  task_runner_->FastForwardBy(base::Milliseconds(30));
  WriteToCache("2.test");
  task_runner_->FastForwardBy(base::Milliseconds(30));
  WriteToCache("3.test");
  CheckPref(0);
  task_runner_->FastForwardBy(base::Milliseconds(40));
  CheckPref(3);

  // Add a delay in between batches.
  task_runner_->FastForwardBy(base::Milliseconds(50));

  WriteToCache("4.test");
  task_runner_->FastForwardBy(base::Milliseconds(30));
  WriteToCache("5.test");
  task_runner_->FastForwardBy(base::Milliseconds(30));
  WriteToCache("6.test");
  CheckPref(3);
  task_runner_->FastForwardBy(base::Milliseconds(40));
  CheckPref(6);
}

// Set the pref before the HostCachePersistenceManager is created, and make
// sure it gets picked up by the HostCache.
TEST_F(HostCachePersistenceManagerTest, InitAfterPrefs) {
  CheckPref(0);
  InitializePref();
  CheckPref(3);

  MakePersistenceManager(base::Seconds(1));
  task_runner_->RunUntilIdle();
  ASSERT_EQ(3u, cache_->size());
}

// Set the pref after the HostCachePersistenceManager is created, and make
// sure it gets picked up by the HostCache.
TEST_F(HostCachePersistenceManagerTest, InitBeforePrefs) {
  MakePersistenceManager(base::Seconds(1));
  ASSERT_EQ(0u, cache_->size());

  CheckPref(0);
  InitializePref();
  CheckPref(3);
  ASSERT_EQ(3u, cache_->size());
}

}  // namespace cronet