// Copyright 2014 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 "components/domain_reliability/context.h"
#include <map>
#include <string>
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "components/domain_reliability/beacon.h"
#include "components/domain_reliability/dispatcher.h"
#include "components/domain_reliability/scheduler.h"
#include "components/domain_reliability/test_util.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace domain_reliability {
namespace {
typedef std::vector<DomainReliabilityBeacon> BeaconVector;
DomainReliabilityBeacon MakeBeacon(MockableTime* time) {
DomainReliabilityBeacon beacon;
beacon.domain = "localhost";
beacon.status = "ok";
beacon.chrome_error = net::OK;
beacon.server_ip = "127.0.0.1";
beacon.protocol = "HTTP";
beacon.http_response_code = 200;
beacon.elapsed = base::TimeDelta::FromMilliseconds(250);
beacon.start_time = time->NowTicks() - beacon.elapsed;
return beacon;
}
class DomainReliabilityContextTest : public testing::Test {
protected:
DomainReliabilityContextTest()
: dispatcher_(&time_),
params_(MakeTestSchedulerParams()),
uploader_(base::Bind(&DomainReliabilityContextTest::OnUploadRequest,
base::Unretained(this))),
upload_reporter_string_("test-reporter"),
context_(&time_,
params_,
upload_reporter_string_,
&dispatcher_,
&uploader_,
MakeTestConfig().Pass()),
upload_pending_(false) {}
TimeDelta min_delay() const { return params_.minimum_upload_delay; }
TimeDelta max_delay() const { return params_.maximum_upload_delay; }
TimeDelta retry_interval() const { return params_.upload_retry_interval; }
TimeDelta zero_delta() const { return TimeDelta::FromMicroseconds(0); }
bool upload_pending() { return upload_pending_; }
const std::string& upload_report() {
DCHECK(upload_pending_);
return upload_report_;
}
const GURL& upload_url() {
DCHECK(upload_pending_);
return upload_url_;
}
void CallUploadCallback(bool success) {
DCHECK(upload_pending_);
upload_callback_.Run(success);
upload_pending_ = false;
}
bool CheckNoBeacons() {
BeaconVector beacons;
context_.GetQueuedBeaconsForTesting(&beacons);
return beacons.empty();
}
bool CheckCounts(size_t index,
unsigned expected_successful,
unsigned expected_failed) {
unsigned successful, failed;
context_.GetRequestCountsForTesting(index, &successful, &failed);
return successful == expected_successful && failed == expected_failed;
}
MockTime time_;
DomainReliabilityDispatcher dispatcher_;
DomainReliabilityScheduler::Params params_;
MockUploader uploader_;
std::string upload_reporter_string_;
DomainReliabilityContext context_;
private:
void OnUploadRequest(
const std::string& report_json,
const GURL& upload_url,
const DomainReliabilityUploader::UploadCallback& callback) {
DCHECK(!upload_pending_);
upload_report_ = report_json;
upload_url_ = upload_url;
upload_callback_ = callback;
upload_pending_ = true;
}
bool upload_pending_;
std::string upload_report_;
GURL upload_url_;
DomainReliabilityUploader::UploadCallback upload_callback_;
};
TEST_F(DomainReliabilityContextTest, Create) {
EXPECT_TRUE(CheckNoBeacons());
EXPECT_TRUE(CheckCounts(0, 0, 0));
EXPECT_TRUE(CheckCounts(1, 0, 0));
}
TEST_F(DomainReliabilityContextTest, NoResource) {
GURL url("http://example/no_resource");
DomainReliabilityBeacon beacon = MakeBeacon(&time_);
context_.OnBeacon(url, beacon);
EXPECT_TRUE(CheckNoBeacons());
EXPECT_TRUE(CheckCounts(0, 0, 0));
EXPECT_TRUE(CheckCounts(1, 0, 0));
}
TEST_F(DomainReliabilityContextTest, NeverReport) {
GURL url("http://example/never_report");
DomainReliabilityBeacon beacon = MakeBeacon(&time_);
context_.OnBeacon(url, beacon);
EXPECT_TRUE(CheckNoBeacons());
EXPECT_TRUE(CheckCounts(0, 0, 0));
EXPECT_TRUE(CheckCounts(1, 1, 0));
}
TEST_F(DomainReliabilityContextTest, AlwaysReport) {
GURL url("http://example/always_report");
DomainReliabilityBeacon beacon = MakeBeacon(&time_);
context_.OnBeacon(url, beacon);
BeaconVector beacons;
context_.GetQueuedBeaconsForTesting(&beacons);
EXPECT_EQ(1u, beacons.size());
EXPECT_TRUE(CheckCounts(0, 1, 0));
EXPECT_TRUE(CheckCounts(1, 0, 0));
}
TEST_F(DomainReliabilityContextTest, ReportUpload) {
GURL url("http://example/always_report");
DomainReliabilityBeacon beacon = MakeBeacon(&time_);
context_.OnBeacon(url, beacon);
BeaconVector beacons;
context_.GetQueuedBeaconsForTesting(&beacons);
EXPECT_EQ(1u, beacons.size());
EXPECT_TRUE(CheckCounts(0, 1, 0));
EXPECT_TRUE(CheckCounts(1, 0, 0));
// N.B.: Assumes max_delay is 5 minutes.
const char* kExpectedReport = "{"
"\"config_version\":\"1\","
"\"entries\":[{\"domain\":\"localhost\","
"\"http_response_code\":200,\"protocol\":\"HTTP\","
"\"request_age_ms\":300250,\"request_elapsed_ms\":250,"
"\"resource\":\"always_report\",\"server_ip\":\"127.0.0.1\","
"\"status\":\"ok\"}],"
"\"reporter\":\"test-reporter\","
"\"resources\":[{\"failed_requests\":0,\"name\":\"always_report\","
"\"successful_requests\":1}]}";
time_.Advance(max_delay());
EXPECT_TRUE(upload_pending());
EXPECT_EQ(kExpectedReport, upload_report());
EXPECT_EQ(GURL("https://exampleuploader/upload"), upload_url());
CallUploadCallback(true);
EXPECT_TRUE(CheckNoBeacons());
EXPECT_TRUE(CheckCounts(0, 0, 0));
EXPECT_TRUE(CheckCounts(1, 0, 0));
}
} // namespace
} // namespace domain_reliability