Commit 1e3247ea authored by beaudoin@chromium.org's avatar beaudoin@chromium.org

- Most visited iframe now uses postMessage() to signal the iframing page that...

- Most visited iframe now uses postMessage() to signal the iframing page that the link has been displayed.
- Refactor most_visited_thumbnail.js to eliminate client-side secondary thumbnail fallback.
- Refactor UMA logging of NTP suggestions events.

The new postMessage() signal is sent whenever the iframe has failed loading the thumbnails, or when the thumbnail has been successfully loaded. This way it's impossible for the iframing page to learn whether the user has a given URL in its TopSites. The iframing page can use that signal to know when it's possible to display a fallback visual under the iframe.

The refactor significantly simplifies the iframe javascript by dropping support for multiple thumbnails, which can now be handled by the iframing page. UMA logging of NTP suggestions related statistics have also been both simplified and augmented. The patch also includes better unit tests for the UMA logging.

BUG=None

Review URL: https://codereview.chromium.org/102433009

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245579 0039d316-1c4b-4281-b951-d872f2087c98
parent 7dd8f2b5
......@@ -17,86 +17,64 @@ window.addEventListener('DOMContentLoaded', function() {
function logImpression(tileIndex, provider) {
chrome.embeddedSearch.newTabPage.logImpression(tileIndex, provider);
}
function displayLink(link) {
document.body.appendChild(link);
window.parent.postMessage('linkDisplayed', '{{ORIGIN}}');
}
function showDomainElement() {
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_THUMBNAIL_ERROR);
var link = createMostVisitedLink(
params, data.url, data.title, undefined, data.ping, data.provider);
var domain = document.createElement('div');
domain.textContent = data.domain;
link.appendChild(domain);
document.body.appendChild(link);
displayLink(link);
}
// Called on intentionally empty tiles for which the visuals are handled
// externally by the page itself.
function showEmptyTile() {
var link = createMostVisitedLink(
params, data.url, data.title, undefined, data.ping, data.provider);
document.body.appendChild(link);
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_EXTERNAL_TILE);
displayLink(createMostVisitedLink(
params, data.url, data.title, undefined, data.ping, data.provider));
}
function createAndAppendThumbnail(isVisible) {
// Creates and adds an image.
function createThumbnail(src) {
var image = new Image();
image.onload = function() {
var shadow = document.createElement('span');
shadow.classList.add('shadow');
var link = createMostVisitedLink(
params, data.url, data.title, undefined, data.ping, data.provider);
params, data.url, data.title, undefined, data.ping,
data.provider);
link.appendChild(shadow);
link.appendChild(image);
// We add 'position: absolute' in anticipation that there could be more
// than one thumbnail. This will superpose the elements.
link.style.position = 'absolute';
document.body.appendChild(link);
displayLink(link);
};
image.onerror = function() {
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_THUMBNAIL_ERROR);
if (data.domain) {
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_GRAY_TILE_FALLBACK);
showDomainElement();
} else {
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_EXTERNAL_TILE_FALLBACK);
showEmptyTile();
}
};
if (!isVisible) {
image.style.visibility = 'hidden';
}
return image;
image.src = src;
}
// Log an impression if we know the position of the tile.
if (isFinite(params.pos) && data.provider) {
logImpression(parseInt(params.pos, 10), data.provider);
}
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_TILE);
if (data.thumbnailUrl) {
var image = createAndAppendThumbnail(true);
// If a backup thumbnail URL was provided, preload it in case the first
// thumbnail errors. The backup thumbnail is always preloaded so that the
// server can't gain knowledge on the local thumbnail DB by specifying a
// second URL that is only sometimes fetched.
if (data.thumbnailUrl2) {
var image2 = createAndAppendThumbnail(false);
var imageFailed = false;
var image2Failed = false;
image2.onerror = function() {
image2Failed = true;
image2.style.visibility = 'hidden';
if (imageFailed) {
showDomainElement();
}
};
image2.src = data.thumbnailUrl2;
// The first thumbnail's onerror function will swap the visibility of
// the two thumbnails.
image.onerror = function() {
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_FALLBACK_THUMBNAIL_USED);
imageFailed = true;
image.style.visibility = 'hidden';
if (image2Failed) {
showDomainElement();
} else {
image2.style.visibility = 'visible';
}
};
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_FALLBACK_THUMBNAIL_REQUESTED);
} else {
image.onerror = showDomainElement;
}
image.src = data.thumbnailUrl;
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_THUMBNAIL_ATTEMPT);
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_THUMBNAIL_TILE);
createThumbnail(data.thumbnailUrl);
} else if (data.domain) {
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_GRAY_TILE);
showDomainElement();
} else {
logEvent(NTP_LOGGING_EVENT_TYPE.NTP_EXTERNAL_TILE);
showEmptyTile();
}
});
......
......@@ -10,30 +10,37 @@
<include src="instant_iframe_validation.js">
/**
* Enum for the different types of events that are logged from the NTP.
* The different types of events that are logged from the NTP. This enum is
* used to transfer information from the NTP javascript to the renderer and is
* not used as a UMA enum histogram's logged value.
* Note: Keep in sync with common/ntp_logging_events.h
* @enum {number}
* @const
*/
var NTP_LOGGING_EVENT_TYPE = {
// The user moused over an NTP tile or title.
NTP_MOUSEOVER: 0,
// The page attempted to load a thumbnail image.
NTP_THUMBNAIL_ATTEMPT: 1,
// There was an error in loading both the thumbnail image and the fallback
// (if it was provided), resulting in a grey tile.
NTP_THUMBNAIL_ERROR: 2,
// The page attempted to load a thumbnail URL while a fallback thumbnail was
// provided.
NTP_FALLBACK_THUMBNAIL_REQUESTED: 3,
// The primary thumbnail image failed to load and caused us to use the
// secondary thumbnail as a fallback.
NTP_FALLBACK_THUMBNAIL_USED: 4,
// The suggestion is coming from the server.
NTP_SERVER_SIDE_SUGGESTION: 5,
NTP_SERVER_SIDE_SUGGESTION: 0,
// The suggestion is coming from the client.
NTP_CLIENT_SIDE_SUGGESTION: 6,
NTP_CLIENT_SIDE_SUGGESTION: 1,
// Indicates a tile was rendered, no matter if it's a thumbnail, a gray tile
// or an external tile.
NTP_TILE: 2,
// The tile uses a local thumbnail image.
NTP_THUMBNAIL_TILE: 3,
// Used when no thumbnail is specified and a gray tile with the domain is used
// as the main tile.
NTP_GRAY_TILE: 4,
// The visuals of that tile are handled externally by the page itself.
NTP_EXTERNAL_TILE: 7
NTP_EXTERNAL_TILE: 5,
// There was an error in loading both the thumbnail image and the fallback
// (if it was provided), resulting in a grey tile.
NTP_THUMBNAIL_ERROR: 6,
// Used a gray tile with the domain as the fallback for a failed thumbnail.
NTP_GRAY_TILE_FALLBACK: 7,
// The visuals of that tile's fallback are handled externally.
NTP_EXTERNAL_TILE_FALLBACK: 8,
// The user moused over an NTP tile or title.
NTP_MOUSEOVER: 9
};
/**
......@@ -176,7 +183,6 @@ function fillMostVisited(location, fill) {
// Means that the suggestion data comes from the server. Create data object.
data.url = params.url;
data.thumbnailUrl = params.tu || '';
data.thumbnailUrl2 = params.tu2 || '';
data.title = params.ti || '';
data.direction = params.di || '';
data.domain = params.dom || '';
......@@ -196,7 +202,6 @@ function fillMostVisited(location, fill) {
}
if (/^javascript:/i.test(data.url) ||
/^javascript:/i.test(data.thumbnailUrl) ||
/^javascript:/i.test(data.thumbnailUrl2) ||
!/^[a-z0-9]{0,8}$/i.test(data.provider))
return;
if (data.direction)
......
......@@ -9,7 +9,8 @@
#include "base/strings/string_util.h"
#include "chrome/browser/search/instant_io_context.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "grit/browser_resources.h"
#include "net/url_request/url_request.h"
......@@ -51,17 +52,22 @@ bool IframeSource::ShouldDenyXFrameOptions() const {
bool IframeSource::GetOrigin(
int render_process_id,
int render_view_id,
int render_frame_id,
std::string* origin) const {
content::RenderViewHost* rvh =
content::RenderViewHost::FromID(render_process_id, render_view_id);
if (rvh == NULL)
content::RenderFrameHost* rfh =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
if (rfh == NULL)
return false;
content::WebContents* contents =
content::WebContents::FromRenderViewHost(rvh);
content::WebContents::FromRenderFrameHost(rfh);
if (contents == NULL)
return false;
*origin = contents->GetURL().GetOrigin().spec();
const content::NavigationEntry* entry =
contents->GetController().GetVisibleEntry();
if (entry == NULL)
return false;
*origin = entry->GetURL().GetOrigin().spec();
// Origin should not include a trailing slash. That is part of the path.
base::TrimString(*origin, "/", origin);
return true;
......@@ -78,10 +84,10 @@ void IframeSource::SendResource(
void IframeSource::SendJSWithOrigin(
int resource_id,
int render_process_id,
int render_view_id,
int render_frame_id,
const content::URLDataSource::GotDataCallback& callback) {
std::string origin;
if (!GetOrigin(render_process_id, render_view_id, &origin)) {
if (!GetOrigin(render_process_id, render_frame_id, &origin)) {
callback.Run(NULL);
return;
}
......
......@@ -35,16 +35,16 @@ class IframeSource : public content::URLDataSource {
void SendJSWithOrigin(
int resource_id,
int render_process_id,
int render_view_id,
int render_frame_id,
const content::URLDataSource::GotDataCallback& callback);
// This is exposed for testing and should not be overridden.
// Sets |origin| to the URL of the render view identified by |process_id| and
// |render_view_id|. Returns true if successful and false if not, for example
// if the render view does not exist.
// Sets |origin| to the URL of the render frame identified by |process_id| and
// |render_frame_id|. Returns true if successful and false if not, for example
// if the render frame does not exist.
virtual bool GetOrigin(
int process_id,
int render_view_id,
int render_frame_id,
std::string* origin) const;
DISALLOW_COPY_AND_ASSIGN(IframeSource);
......
......@@ -51,11 +51,11 @@ class TestIframeSource : public IframeSource {
const content::URLDataSource::GotDataCallback& callback) OVERRIDE {
}
// RenderViewHost is hard to mock in concert with everything else, so stub
// RenderFrameHost is hard to mock in concert with everything else, so stub
// this method out for testing.
virtual bool GetOrigin(
int process_id,
int render_view_id,
int render_frame_id,
std::string* origin) const OVERRIDE {
if (process_id == kInstantRendererPID) {
*origin = kInstantOrigin;
......@@ -96,7 +96,7 @@ class IframeSourceTest : public testing::Test {
const std::string& url,
bool allocate_info,
int render_process_id,
int render_view_id) {
int render_frame_id) {
net::URLRequest* request =
new net::URLRequest(GURL(url),
net::DEFAULT_PRIORITY,
......@@ -107,7 +107,7 @@ class IframeSourceTest : public testing::Test {
ResourceType::SUB_FRAME,
&resource_context_,
render_process_id,
render_view_id,
render_frame_id,
MSG_ROUTING_NONE,
false);
}
......@@ -121,8 +121,8 @@ class IframeSourceTest : public testing::Test {
void SendJSWithOrigin(
int resource_id,
int render_process_id,
int render_view_id) {
source()->SendJSWithOrigin(resource_id, render_process_id, render_view_id,
int render_frame_id) {
source()->SendJSWithOrigin(resource_id, render_process_id, render_frame_id,
callback_);
}
......
......@@ -60,7 +60,8 @@ void MostVisitedIframeSource::StartDataRequest(
} else if (path == kThumbnailCSSPath) {
SendResource(IDR_MOST_VISITED_THUMBNAIL_CSS, callback);
} else if (path == kThumbnailJSPath) {
SendResource(IDR_MOST_VISITED_THUMBNAIL_JS, callback);
SendJSWithOrigin(IDR_MOST_VISITED_THUMBNAIL_JS, render_process_id,
render_frame_id, callback);
} else if (path == kUtilJSPath) {
SendResource(IDR_MOST_VISITED_UTIL_JS, callback);
} else if (path == kCommonCSSPath) {
......
......@@ -15,6 +15,10 @@
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
// Macro to log UMA statistics related to the 8 tiles shown on the NTP.
#define UMA_HISTOGRAM_NTP_TILES(name, sample) \
UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 0, 8, 9)
namespace {
// Used to track if suggestions were issued by the client or the server.
......@@ -54,70 +58,79 @@ NTPUserDataLogger* NTPUserDataLogger::GetOrCreateFromWebContents(
return logger;
}
void NTPUserDataLogger::EmitThumbnailErrorRate() {
DCHECK_LE(number_of_thumbnail_errors_, number_of_thumbnail_attempts_);
if (number_of_thumbnail_attempts_ != 0) {
UMA_HISTOGRAM_PERCENTAGE(
"NewTabPage.ThumbnailErrorRate",
GetPercentError(number_of_thumbnail_errors_,
number_of_thumbnail_attempts_));
}
DCHECK_LE(number_of_fallback_thumbnails_used_,
number_of_fallback_thumbnails_requested_);
if (number_of_fallback_thumbnails_requested_ != 0) {
UMA_HISTOGRAM_PERCENTAGE(
"NewTabPage.ThumbnailFallbackRate",
GetPercentError(number_of_fallback_thumbnails_used_,
number_of_fallback_thumbnails_requested_));
}
number_of_thumbnail_attempts_ = 0;
number_of_thumbnail_errors_ = 0;
number_of_fallback_thumbnails_requested_ = 0;
number_of_fallback_thumbnails_used_ = 0;
}
void NTPUserDataLogger::EmitNtpStatistics() {
UMA_HISTOGRAM_COUNTS("NewTabPage.NumberOfMouseOvers", number_of_mouseovers_);
number_of_mouseovers_ = 0;
UMA_HISTOGRAM_COUNTS("NewTabPage.NumberOfExternalTiles",
number_of_external_tiles_);
number_of_external_tiles_ = 0;
UMA_HISTOGRAM_ENUMERATION(
"NewTabPage.SuggestionsType",
server_side_suggestions_ ? SERVER_SIDE : CLIENT_SIDE,
SUGGESTIONS_TYPE_COUNT);
server_side_suggestions_ = false;
// Only log the following statistics if at least one tile is recorded. This
// check is required because the statistics are emitted whenever the user
// changes tab away from the NTP. However, if the user comes back to that NTP
// later the statistics are not regenerated (i.e. they are all 0). If we log
// them again we get a strong bias.
if (number_of_tiles_ > 0) {
UMA_HISTOGRAM_ENUMERATION(
"NewTabPage.SuggestionsType",
has_server_side_suggestions_ ? SERVER_SIDE : CLIENT_SIDE,
SUGGESTIONS_TYPE_COUNT);
has_server_side_suggestions_ = false;
UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfTiles", number_of_tiles_);
number_of_tiles_ = 0;
UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailTiles",
number_of_thumbnail_tiles_);
number_of_thumbnail_tiles_ = 0;
UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTiles",
number_of_gray_tiles_);
number_of_gray_tiles_ = 0;
UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTiles",
number_of_external_tiles_);
number_of_external_tiles_ = 0;
UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailErrors",
number_of_thumbnail_errors_);
number_of_thumbnail_errors_ = 0;
UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTileFallbacks",
number_of_gray_tile_fallbacks_);
number_of_gray_tile_fallbacks_ = 0;
UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTileFallbacks",
number_of_external_tile_fallbacks_);
number_of_external_tile_fallbacks_ = 0;
}
}
void NTPUserDataLogger::LogEvent(NTPLoggingEventType event) {
switch (event) {
case NTP_MOUSEOVER:
number_of_mouseovers_++;
break;
case NTP_THUMBNAIL_ATTEMPT:
number_of_thumbnail_attempts_++;
break;
case NTP_THUMBNAIL_ERROR:
number_of_thumbnail_errors_++;
break;
case NTP_FALLBACK_THUMBNAIL_REQUESTED:
number_of_fallback_thumbnails_requested_++;
break;
case NTP_FALLBACK_THUMBNAIL_USED:
number_of_fallback_thumbnails_used_++;
break;
case NTP_SERVER_SIDE_SUGGESTION:
server_side_suggestions_ = true;
has_server_side_suggestions_ = true;
break;
case NTP_CLIENT_SIDE_SUGGESTION:
// We should never get a mix of server and client side suggestions,
// otherwise there could be a race condition depending on the order in
// which the iframes call this method.
DCHECK(!server_side_suggestions_);
break;
DCHECK(!has_server_side_suggestions_);
break;
case NTP_TILE:
number_of_tiles_++;
break;
case NTP_THUMBNAIL_TILE:
number_of_thumbnail_tiles_++;
break;
case NTP_GRAY_TILE:
number_of_gray_tiles_++;
break;
case NTP_EXTERNAL_TILE:
number_of_external_tiles_++;
break;
case NTP_THUMBNAIL_ERROR:
number_of_thumbnail_errors_++;
break;
case NTP_GRAY_TILE_FALLBACK:
number_of_gray_tile_fallbacks_++;
break;
case NTP_EXTERNAL_TILE_FALLBACK:
number_of_external_tile_fallbacks_++;
break;
case NTP_MOUSEOVER:
number_of_mouseovers_++;
break;
default:
NOTREACHED();
}
......@@ -144,24 +157,18 @@ void NTPUserDataLogger::NavigationEntryCommitted(
if (search::MatchesOriginAndPath(ntp_url_, load_details.previous_url)) {
EmitNtpStatistics();
// Only log thumbnail error rates for Instant NTP pages, as we do not have
// this data for non-Instant NTPs.
if (ntp_url_ != GURL(chrome::kChromeUINewTabURL))
EmitThumbnailErrorRate();
}
}
NTPUserDataLogger::NTPUserDataLogger(content::WebContents* contents)
: content::WebContentsObserver(contents),
number_of_mouseovers_(0),
number_of_thumbnail_attempts_(0),
number_of_thumbnail_errors_(0),
number_of_fallback_thumbnails_requested_(0),
number_of_fallback_thumbnails_used_(0),
has_server_side_suggestions_(false),
number_of_tiles_(0),
number_of_thumbnail_tiles_(0),
number_of_gray_tiles_(0),
number_of_external_tiles_(0),
server_side_suggestions_(false) {
}
size_t NTPUserDataLogger::GetPercentError(size_t errors, size_t events) const {
return (100 * errors) / events;
number_of_thumbnail_errors_(0),
number_of_gray_tile_fallbacks_(0),
number_of_external_tile_fallbacks_(0),
number_of_mouseovers_(0) {
}
......@@ -23,11 +23,6 @@ class NTPUserDataLogger
static NTPUserDataLogger* GetOrCreateFromWebContents(
content::WebContents* content);
// Logs the error percentage rate when loading thumbnail images for this NTP
// session to UMA histogram. Called when the user navigates to a URL. Only
// called for the instant NTP.
void EmitThumbnailErrorRate();
// Logs a number of statistics regarding the NTP. Called when an NTP tab is
// about to be deactivated (be it by switching tabs, losing focus or closing
// the tab/shutting down Chrome), or when the user navigates to a URL.
......@@ -47,39 +42,43 @@ class NTPUserDataLogger
protected:
explicit NTPUserDataLogger(content::WebContents* contents);
// Returns the percent error given |events| occurrences and |errors| errors.
virtual size_t GetPercentError(size_t errors, size_t events) const;
private:
friend class content::WebContentsUserData<NTPUserDataLogger>;
// Total number of mouseovers for this NTP session.
size_t number_of_mouseovers_;
// True if at least one iframe came from a server-side suggestion. In
// practice, either all the iframes are server-side suggestions or none are.
bool has_server_side_suggestions_;
// Total number of tiles rendered, no matter if it's a thumbnail, a gray tile
// or an external tile.
size_t number_of_tiles_;
// Total number of tiles using a local thumbnail image for this NTP session.
size_t number_of_thumbnail_tiles_;
// Total number of attempts made to load thumbnail images for this NTP
// session.
size_t number_of_thumbnail_attempts_;
// Total number of tiles for which no thumbnail is specified and a gray tile
// with the domain is used as the main tile.
size_t number_of_gray_tiles_;
// Total number of tiles for which the visual appearance is handled externally
// by the page itself.
size_t number_of_external_tiles_;
// Total number of errors that occurred when trying to load thumbnail images
// for this NTP session. When these errors occur a grey tile is shown instead
// of a thumbnail image.
size_t number_of_thumbnail_errors_;
// Total number of attempts made to load thumbnail images while providing a
// fallback thumbnail for this NTP session.
size_t number_of_fallback_thumbnails_requested_;
// Total number of errors that occurred while trying to load the primary
// thumbnail image and that caused a fallback to the secondary thumbnail.
size_t number_of_fallback_thumbnails_used_;
// The number of times a gray tile with the domain was used as the fallback
// for a failed thumbnail.
size_t number_of_gray_tile_fallbacks_;
// Total number of tiles for which the visual appearance is handled externally
// by the page itself.
size_t number_of_external_tiles_;
// The number of times an external tile, for which the visual appearance is
// handled by the page itself, was the fallback for a failed thumbnail.
size_t number_of_external_tile_fallbacks_;
// True if at least one iframe came from a server-side suggestion. In
// practice, either all the iframes are server-side suggestions or none are.
bool server_side_suggestions_;
// Total number of mouseovers for this NTP session.
size_t number_of_mouseovers_;
// The URL of this New Tab Page - varies based on NTP version.
GURL ntp_url_;
......
......@@ -5,26 +5,96 @@
#include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
#include "base/basictypes.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "base/metrics/histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "chrome/common/ntp_logging_events.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class MockNTPUserDataLogger : public NTPUserDataLogger {
class TestNTPUserDataLogger : public NTPUserDataLogger {
public:
MockNTPUserDataLogger() : NTPUserDataLogger(NULL) {}
virtual ~MockNTPUserDataLogger() {}
TestNTPUserDataLogger() : NTPUserDataLogger(NULL) {}
virtual ~TestNTPUserDataLogger() {}
};
MOCK_CONST_METHOD2(GetPercentError, size_t(size_t errors, size_t events));
base::HistogramBase::Count GetTotalCount(const std::string& histogram_name) {
base::HistogramBase* histogram = base::StatisticsRecorder::FindHistogram(
histogram_name);
return histogram->SnapshotSamples()->TotalCount();
}
private:
DISALLOW_COPY_AND_ASSIGN(MockNTPUserDataLogger);
};
base::HistogramBase::Count GetBinCount(const std::string& histogram_name,
base::HistogramBase::Sample value) {
base::HistogramBase* histogram = base::StatisticsRecorder::FindHistogram(
histogram_name);
return histogram->SnapshotSamples()->GetCount(value);
}
} // namespace
TEST(NTPUserDataLoggerTest, ThumbnailErrorRateDoesNotDivideByZero) {
MockNTPUserDataLogger logger;
EXPECT_CALL(logger, GetPercentError(testing::_, testing::_)).Times(0);
logger.EmitThumbnailErrorRate();
TEST(NTPUserDataLoggerTest, TestLogging) {
base::StatisticsRecorder::Initialize();
TestNTPUserDataLogger logger;
// Ensure it works when the statistics are all empty. Only the mouseover
// should be logged in this case. The other histograms are not created yet so
// we can't query them.
logger.EmitNtpStatistics();
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfMouseOvers"));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfMouseOvers", 0));
// Ensure it works with some non-zero statistics. All statistics should now
// be logged.
for (int i = 0; i < 20; ++i)
logger.LogEvent(NTP_MOUSEOVER);
for (int i = 0; i < 8; ++i)
logger.LogEvent(NTP_TILE);
for (int i = 0; i < 4; ++i)
logger.LogEvent(NTP_THUMBNAIL_TILE);
for (int i = 0; i < 2; ++i)
logger.LogEvent(NTP_THUMBNAIL_ERROR);
logger.LogEvent(NTP_GRAY_TILE_FALLBACK);
logger.LogEvent(NTP_EXTERNAL_TILE_FALLBACK);
for (int i = 0; i < 2; ++i)
logger.LogEvent(NTP_EXTERNAL_TILE);
for (int i = 0; i < 2; ++i)
logger.LogEvent(NTP_GRAY_TILE);
logger.LogEvent(NTP_SERVER_SIDE_SUGGESTION);
logger.EmitNtpStatistics();
EXPECT_EQ(2, GetTotalCount("NewTabPage.NumberOfMouseOvers"));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfMouseOvers", 0));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfMouseOvers", 20));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfTiles"));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfTiles", 8));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfThumbnailTiles"));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfThumbnailTiles", 4));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfThumbnailErrors"));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfThumbnailErrors", 2));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfGrayTileFallbacks"));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfGrayTileFallbacks", 1));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfExternalTileFallbacks"));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfExternalTileFallbacks", 1));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfExternalTiles"));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfExternalTiles", 2));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfGrayTiles"));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfGrayTiles", 2));
EXPECT_EQ(1, GetTotalCount("NewTabPage.SuggestionsType"));
EXPECT_EQ(1, GetBinCount("NewTabPage.SuggestionsType", 1));
// Statistics should be reset to 0, so we should not log anything else.
logger.EmitNtpStatistics();
EXPECT_EQ(3, GetTotalCount("NewTabPage.NumberOfMouseOvers"));
EXPECT_EQ(2, GetBinCount("NewTabPage.NumberOfMouseOvers", 0));
EXPECT_EQ(1, GetBinCount("NewTabPage.NumberOfMouseOvers", 20));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfTiles"));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfThumbnailTiles"));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfThumbnailErrors"));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfGrayTileFallbacks"));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfExternalTileFallbacks"));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfExternalTiles"));
EXPECT_EQ(1, GetTotalCount("NewTabPage.NumberOfGrayTiles"));
EXPECT_EQ(1, GetTotalCount("NewTabPage.SuggestionsType"));
}
......@@ -5,34 +5,43 @@
#ifndef CHROME_COMMON_NTP_LOGGING_EVENTS_H_
#define CHROME_COMMON_NTP_LOGGING_EVENTS_H_
// The different types of events that are logged from the NTP.
// The different types of events that are logged from the NTP. This enum is used
// to transfer information from the NTP javascript to the renderer and is not
// used as a UMA enum histogram's logged value.
// Note: Keep in sync with browser/resources/local_ntp/most_visited_utils.js
enum NTPLoggingEventType {
// The user moused over an NTP tile or title.
NTP_MOUSEOVER = 0,
// The suggestion is coming from the server.
NTP_SERVER_SIDE_SUGGESTION = 0,
// The page attempted to load a thumbnail image.
NTP_THUMBNAIL_ATTEMPT = 1,
// The suggestion is coming from the client.
NTP_CLIENT_SIDE_SUGGESTION = 1,
// There was an error in loading both the thumbnail image and the fallback
// (if it was provided), resulting in a grey tile.
NTP_THUMBNAIL_ERROR = 2,
// Indicates a tile was rendered, no matter if it's a thumbnail, a gray tile
// or an external tile.
NTP_TILE = 2,
// The page attempted to load a thumbnail URL while a fallback thumbnail was
// provided.
NTP_FALLBACK_THUMBNAIL_REQUESTED = 3,
// The tile uses a local thumbnail image.
NTP_THUMBNAIL_TILE = 3,
// The primary thumbnail image failed to load and caused us to use the
// secondary thumbnail as a fallback.
NTP_FALLBACK_THUMBNAIL_USED = 4,
// Used when no thumbnail is specified and a gray tile with the domain is used
// as the main tile.
NTP_GRAY_TILE = 4,
// The suggestion is coming from the server.
NTP_SERVER_SIDE_SUGGESTION = 5,
// The visuals of that tile are handled externally by the page itself.
NTP_EXTERNAL_TILE = 5,
// The suggestion is coming from the client.
NTP_CLIENT_SIDE_SUGGESTION = 6,
// There was an error in loading both the thumbnail image and the fallback
// (if it was provided), resulting in a grey tile.
NTP_THUMBNAIL_ERROR = 6,
// The visuals of that tile are handled externally by the page itself.
NTP_EXTERNAL_TILE = 7,
// Used a gray tile with the domain as the fallback for a failed thumbnail.
NTP_GRAY_TILE_FALLBACK = 7,
// The visuals of that tile's fallback are handled externally.
NTP_EXTERNAL_TILE_FALLBACK = 8,
// The user moused over an NTP tile or title.
NTP_MOUSEOVER = 9,
NTP_NUM_EVENT_TYPES
};
......
......@@ -12010,6 +12010,17 @@ other types of suffix sets.
</summary>
</histogram>
<histogram name="NewTabPage.NumberOfExternalTileFallbacks">
<summary>
The number of tiles for which we relied on external tiles as a fallback
because a local screenshot was not available to be used as a thumbnail.
External tiles are those for which the visuals are handled by the page
itself, not by the iframe. Recorded before changing focus away from the NTP,
be it bynavigating to a URL, switching tabs, changing the active window or
closing the tab/shutting down Chrome.
</summary>
</histogram>
<histogram name="NewTabPage.NumberOfExternalTiles">
<summary>
The number of external tiles that are displayed on the NTP. External tiles
......@@ -12020,6 +12031,25 @@ other types of suffix sets.
</summary>
</histogram>
<histogram name="NewTabPage.NumberOfGrayTileFallbacks">
<summary>
The number of tiles for which we displayed a gray tile with the domain name
as a fallback because a local screenshot was not available to be used as a
thumbnail. Recorded before changing focus away from the NTP, be it by
navigating to a URL, switching tabs, changing the active window or closing
the tab/shutting down Chrome.
</summary>
</histogram>
<histogram name="NewTabPage.NumberOfGrayTiles">
<summary>
The number of tiles for which no thumbnail was specified, but a domain was
so we displayed a gray tile with the domain name in it. Recorded before
changing focus away from the NTP, be it by navigating to a URL, switching
tabs, changing the active window or closing the tab/shutting down Chrome.
</summary>
</histogram>
<histogram name="NewTabPage.NumberOfMouseOvers">
<summary>
The total number of times the user hovered the mouse over Most Visited tile
......@@ -12029,6 +12059,46 @@ other types of suffix sets.
</summary>
</histogram>
<histogram name="NewTabPage.NumberOfThumbnailAttempts">
<obsolete>
Deprecated 01/2014. Replaced by NewTabPage.NumberOfThumbnailTiles.
</obsolete>
<summary>
The number of tiles for which we attempted to use a local screenshot as a
thumbnail. Recorded before changing focus away from the NTP, be it by
navigating to a URL, switching tabs, changing the active window or closing
the tab/shutting down Chrome.
</summary>
</histogram>
<histogram name="NewTabPage.NumberOfThumbnailErrors">
<summary>
The number of thumbnails for which a local screenshot was not available so
we were not able to display them on the Most Visited section of the NTP.
Recorded before changing focus away from the NTP, be it by navigating to a
URL, switching tabs, changing the active window or closing the tab/shutting
down Chrome.
</summary>
</histogram>
<histogram name="NewTabPage.NumberOfThumbnailTiles">
<summary>
The number of tiles for which we attempted to use a local screenshot as a
thumbnail. Recorded before changing focus away from the NTP, be it by
navigating to a URL, switching tabs, changing the active window or closing
the tab/shutting down Chrome.
</summary>
</histogram>
<histogram name="NewTabPage.NumberOfTiles">
<summary>
The number of tiles that are displayed on the NTP, no matter if they are
thumbnails, gray tiles, or external tiles. Recorded before changing focus
away from the NTP, be it by navigating to a URL, switching tabs, changing
the active window or closing the tab/shutting down Chrome.
</summary>
</histogram>
<histogram name="NewTabPage.OtherSessionsMenu" enum="NtpOtherSessionsType">
<summary>
Histogram for usage of the menu on the NTP that allows the user to access
......@@ -12109,6 +12179,10 @@ other types of suffix sets.
</histogram>
<histogram name="NewTabPage.ThumbnailErrorRate">
<obsolete>
Deprecated 01/2014. Replaced by NewTabPage.NumberOfThumbnailAttempts and
NewTabPage.NumberOfThumbnailErrors.
</obsolete>
<summary>
The percentage of errors per attempts to load image thumbnails on the New
Tab Page. When an error occurs, a grey tile is shown instead of a thumbnail
......@@ -12120,6 +12194,10 @@ other types of suffix sets.
</histogram>
<histogram name="NewTabPage.ThumbnailFallbackRate" units="%">
<obsolete>
Deprecated 01/2014. Replaced by NewTabPage.NumberOfGrayTileFallbacks and
NewTabPage.NumberOfExternalFallbacks.
</obsolete>
<summary>
The percentage of times most visited tiles use the fallback thumbnail. Only
requests that actually specify a fallback thumbnail are considered here. We
......@@ -33529,6 +33607,7 @@ other types of suffix sets.
<fieldtrial name="NewTabPageProviders" separator=".">
<group name="client" label="Suggestions coming from the client."/>
<group name="server" label="Suggestions coming from the server."/>
<group name="server0" label="Suggestions coming from server source 0."/>
<group name="server1" label="Suggestions coming from server source 1."/>
<group name="server2" label="Suggestions coming from server source 2."/>
<group name="server3" label="Suggestions coming from server source 3."/>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment