root/chrome/browser/metrics/variations/variations_service_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. seed_stored_
  2. set_intercepts_fetch
  3. fetch_attempted
  4. seed_stored
  5. DoActualFetch
  6. StoreSeed
  7. CreateTestSeed
  8. SerializeSeed
  9. SimulateServerResponse
  10. TEST_F
  11. SetUp
  12. TearDown
  13. SetVariationsRestrictParameterPolicyValue
  14. TEST_F
  15. TEST_F
  16. TEST_F
  17. TEST_F
  18. TEST_F
  19. TEST_F
  20. TEST_F

// 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.

#include "chrome/browser/metrics/variations/variations_service.h"

#include <vector>

#include "base/base64.h"
#include "base/prefs/testing_pref_service.h"
#include "base/sha1.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "chrome/browser/web_resource/resource_request_allowed_notifier_test_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_pref_service_syncable.h"
#include "components/variations/proto/study.pb.h"
#include "components/variations/proto/variations_seed.pb.h"
#include "content/public/test/test_browser_thread.h"
#include "net/base/url_util.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "testing/gtest/include/gtest/gtest.h"

#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h"
#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
#endif

namespace chrome_variations {

namespace {

// A test class used to validate expected functionality in VariationsService.
class TestVariationsService : public VariationsService {
 public:
  TestVariationsService(TestRequestAllowedNotifier* test_notifier,
                        PrefService* local_state)
      : VariationsService(test_notifier, local_state),
        intercepts_fetch_(true),
        fetch_attempted_(false),
        seed_stored_(false) {
    // Set this so StartRepeatedVariationsSeedFetch can be called in tests.
    SetCreateTrialsFromSeedCalledForTesting(true);
  }

  virtual ~TestVariationsService() {
  }

  void set_intercepts_fetch(bool value) {
    intercepts_fetch_ = value;
  }

  bool fetch_attempted() const { return fetch_attempted_; }

  bool seed_stored() const { return seed_stored_; }

  virtual void DoActualFetch() OVERRIDE {
    if (intercepts_fetch_) {
      fetch_attempted_ = true;
      return;
    }

    VariationsService::DoActualFetch();
  }

 protected:
  virtual void StoreSeed(const std::string& seed_data,
                         const std::string& seed_signature,
                         const base::Time& date_fetched) OVERRIDE {
    seed_stored_ = true;
  }

 private:
  bool intercepts_fetch_;
  bool fetch_attempted_;
  bool seed_stored_;

  DISALLOW_COPY_AND_ASSIGN(TestVariationsService);
};

// Populates |seed| with simple test data. The resulting seed will contain one
// study called "test", which contains one experiment called "abc" with
// probability weight 100. |seed|'s study field will be cleared before adding
// the new study.
VariationsSeed CreateTestSeed() {
  VariationsSeed seed;
  Study* study = seed.add_study();
  study->set_name("test");
  study->set_default_experiment_name("abc");
  Study_Experiment* experiment = study->add_experiment();
  experiment->set_name("abc");
  experiment->set_probability_weight(100);
  seed.set_serial_number("123");
  return seed;
}

// Serializes |seed| to protobuf binary format.
std::string SerializeSeed(const VariationsSeed& seed) {
  std::string serialized_seed;
  seed.SerializeToString(&serialized_seed);
  return serialized_seed;
}

// Simulates a variations service response by setting a date header and the
// specified HTTP |response_code| on |fetcher|.
void SimulateServerResponse(int response_code, net::TestURLFetcher* fetcher) {
  ASSERT_TRUE(fetcher);
  scoped_refptr<net::HttpResponseHeaders> headers(
      new net::HttpResponseHeaders("date:Wed, 13 Feb 2013 00:25:24 GMT\0\0"));
  fetcher->set_response_headers(headers);
  fetcher->set_response_code(response_code);
}

}  // namespace

class VariationsServiceTest : public ::testing::Test {
 protected:
  VariationsServiceTest() {}

 private:
#if defined(OS_CHROMEOS)
  // Not used directly. Initializes CrosSettings for testing.
  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
  chromeos::ScopedTestCrosSettings test_cros_settings_;
#endif

  DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest);
};

#if !defined(OS_CHROMEOS)
TEST_F(VariationsServiceTest, VariationsURLIsValid) {
#if defined(OS_ANDROID)
  // Android uses profile prefs as the PrefService to generate the URL.
  TestingPrefServiceSyncable prefs;
  VariationsService::RegisterProfilePrefs(prefs.registry());
#else
  TestingPrefServiceSimple prefs;
  VariationsService::RegisterPrefs(prefs.registry());
#endif
  const std::string default_variations_url =
      VariationsService::GetDefaultVariationsServerURLForTesting();

  std::string value;
  GURL url = VariationsService::GetVariationsServerURL(&prefs);
  EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
  EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));

  prefs.SetString(prefs::kVariationsRestrictParameter, "restricted");
  url = VariationsService::GetVariationsServerURL(&prefs);
  EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
  EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
  EXPECT_EQ("restricted", value);
}
#else
class VariationsServiceTestChromeOS : public VariationsServiceTest {
 protected:
  VariationsServiceTestChromeOS() {}

  virtual void SetUp() OVERRIDE {
    cros_settings_ = chromeos::CrosSettings::Get();
    DCHECK(cros_settings_ != NULL);
    // Remove the real DeviceSettingsProvider and replace it with a stub that
    // allows modifications in a test.
    device_settings_provider_ = cros_settings_->GetProvider(
        chromeos::kReportDeviceVersionInfo);
    EXPECT_TRUE(device_settings_provider_ != NULL);
    EXPECT_TRUE(cros_settings_->RemoveSettingsProvider(
        device_settings_provider_));
    cros_settings_->AddSettingsProvider(&stub_settings_provider_);
  }

  virtual void TearDown() OVERRIDE {
    // Restore the real DeviceSettingsProvider.
    EXPECT_TRUE(
        cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
    cros_settings_->AddSettingsProvider(device_settings_provider_);
  }

  void SetVariationsRestrictParameterPolicyValue(std::string value) {
    cros_settings_->SetString(chromeos::kVariationsRestrictParameter, value);
  }

 private:
  chromeos::CrosSettings* cros_settings_;
  chromeos::StubCrosSettingsProvider stub_settings_provider_;
  chromeos::CrosSettingsProvider* device_settings_provider_;

  DISALLOW_COPY_AND_ASSIGN(VariationsServiceTestChromeOS);
};

TEST_F(VariationsServiceTestChromeOS, VariationsURLIsValid) {
  TestingPrefServiceSimple prefs;
  VariationsService::RegisterPrefs(prefs.registry());
  const std::string default_variations_url =
      VariationsService::GetDefaultVariationsServerURLForTesting();

  std::string value;
  GURL url = VariationsService::GetVariationsServerURL(&prefs);
  EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
  EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));

  SetVariationsRestrictParameterPolicyValue("restricted");
  url = VariationsService::GetVariationsServerURL(&prefs);
  EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
  EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
  EXPECT_EQ("restricted", value);
}
#endif

TEST_F(VariationsServiceTest, VariationsURLHasOSNameParam) {
  TestingPrefServiceSimple prefs;
  VariationsService::RegisterPrefs(prefs.registry());
  const GURL url = VariationsService::GetVariationsServerURL(&prefs);

  std::string value;
  EXPECT_TRUE(net::GetValueForKeyInQuery(url, "osname", &value));
  EXPECT_FALSE(value.empty());
}

TEST_F(VariationsServiceTest, RequestsInitiallyNotAllowed) {
  base::MessageLoopForUI message_loop;
  content::TestBrowserThread ui_thread(content::BrowserThread::UI,
                                       &message_loop);
  TestingPrefServiceSimple prefs;
  VariationsService::RegisterPrefs(prefs.registry());

  // Pass ownership to TestVariationsService, but keep a weak pointer to
  // manipulate it for this test.
  TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
  TestVariationsService test_service(test_notifier, &prefs);

  // Force the notifier to initially disallow requests.
  test_notifier->SetRequestsAllowedOverride(false);
  test_service.StartRepeatedVariationsSeedFetch();
  EXPECT_FALSE(test_service.fetch_attempted());

  test_notifier->NotifyObserver();
  EXPECT_TRUE(test_service.fetch_attempted());
}

TEST_F(VariationsServiceTest, RequestsInitiallyAllowed) {
  base::MessageLoopForUI message_loop;
  content::TestBrowserThread ui_thread(content::BrowserThread::UI,
                                       &message_loop);
  TestingPrefServiceSimple prefs;
  VariationsService::RegisterPrefs(prefs.registry());

  // Pass ownership to TestVariationsService, but keep a weak pointer to
  // manipulate it for this test.
  TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
  TestVariationsService test_service(test_notifier, &prefs);

  test_notifier->SetRequestsAllowedOverride(true);
  test_service.StartRepeatedVariationsSeedFetch();
  EXPECT_TRUE(test_service.fetch_attempted());
}

TEST_F(VariationsServiceTest, SeedStoredWhenOKStatus) {
  base::MessageLoop message_loop;
  content::TestBrowserThread io_thread(content::BrowserThread::IO,
                                       &message_loop);
  TestingPrefServiceSimple prefs;
  VariationsService::RegisterPrefs(prefs.registry());

  TestVariationsService service(new TestRequestAllowedNotifier, &prefs);
  service.set_intercepts_fetch(false);

  net::TestURLFetcherFactory factory;
  service.DoActualFetch();

  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
  SimulateServerResponse(net::HTTP_OK, fetcher);
  fetcher->SetResponseString(SerializeSeed(CreateTestSeed()));

  EXPECT_FALSE(service.seed_stored());
  service.OnURLFetchComplete(fetcher);
  EXPECT_TRUE(service.seed_stored());
}

TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) {
  const int non_ok_status_codes[] = {
    net::HTTP_NO_CONTENT,
    net::HTTP_NOT_MODIFIED,
    net::HTTP_NOT_FOUND,
    net::HTTP_INTERNAL_SERVER_ERROR,
    net::HTTP_SERVICE_UNAVAILABLE,
  };

  base::MessageLoop message_loop;
  content::TestBrowserThread io_thread(content::BrowserThread::IO,
                                       &message_loop);
  TestingPrefServiceSimple prefs;
  VariationsService::RegisterPrefs(prefs.registry());

  VariationsService variations_service(new TestRequestAllowedNotifier, &prefs);
  for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
    net::TestURLFetcherFactory factory;
    variations_service.DoActualFetch();
    EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());

    net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
    SimulateServerResponse(non_ok_status_codes[i], fetcher);
    variations_service.OnURLFetchComplete(fetcher);

    EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
  }
}

TEST_F(VariationsServiceTest, SeedDateUpdatedOn304Status) {
  base::MessageLoop message_loop;
  content::TestBrowserThread io_thread(content::BrowserThread::IO,
                                       &message_loop);
  TestingPrefServiceSimple prefs;
  VariationsService::RegisterPrefs(prefs.registry());

  VariationsService variations_service(new TestRequestAllowedNotifier, &prefs);
  net::TestURLFetcherFactory factory;
  variations_service.DoActualFetch();
  EXPECT_TRUE(
      prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());

  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
  SimulateServerResponse(net::HTTP_NOT_MODIFIED, fetcher);
  variations_service.OnURLFetchComplete(fetcher);
  EXPECT_FALSE(
      prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
}

}  // namespace chrome_variations

/* [<][>][^][v][top][bottom][index][help] */