Commit 640ab571 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Media Feeds] Add basic webui for debugging

Add a basic webui at chrome://media-feeds
for debugging Media Feeds internals.

BUG=1058187

Change-Id: Ia769f103bdd5abfd6ff00754c26117e684d2fb03
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2086331
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Reviewed-by: default avatarcalamity <calamity@chromium.org>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748778}
parent 689bfd73
......@@ -1986,6 +1986,7 @@ jumbo_static_library("browser") {
"//chrome/browser/image_decoder",
"//chrome/browser/media:media_engagement_preload_proto",
"//chrome/browser/media:mojo_bindings",
"//chrome/browser/media/feeds:mojo_bindings",
"//chrome/browser/media/router",
"//chrome/browser/metrics:expired_histograms_array",
"//chrome/browser/metrics/variations:chrome_ui_string_overrider_factory",
......@@ -5664,6 +5665,7 @@ grit("dev_ui_browser_resources") {
deps = [
"//chrome/browser/engagement:mojo_bindings_js",
"//chrome/browser/media:mojo_bindings_js",
"//chrome/browser/media/feeds:mojo_bindings_js",
"//chrome/browser/ui/webui/interventions_internals:mojo_bindings_js",
]
if (is_android) {
......
......@@ -14,6 +14,7 @@
#include "chrome/browser/dom_distiller/dom_distiller_service_factory.h"
#include "chrome/browser/engagement/site_engagement_details.mojom.h"
#include "chrome/browser/language/translate_frame_binder.h"
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "chrome/browser/media/history/media_history_store.mojom.h"
#include "chrome/browser/media/media_engagement_score_details.mojom.h"
#include "chrome/browser/navigation_predictor/navigation_predictor.h"
......@@ -30,6 +31,7 @@
#include "chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom.h"
#include "chrome/browser/ui/webui/interventions_internals/interventions_internals_ui.h"
#include "chrome/browser/ui/webui/media/media_engagement_ui.h"
#include "chrome/browser/ui/webui/media/media_feeds_ui.h"
#include "chrome/browser/ui/webui/media/media_history_ui.h"
#include "chrome/browser/ui/webui/omnibox/omnibox.mojom.h"
#include "chrome/browser/ui/webui/omnibox/omnibox_ui.h"
......@@ -430,6 +432,9 @@ void PopulateChromeWebUIFrameBinders(
media::mojom::MediaEngagementScoreDetailsProvider, MediaEngagementUI>(
map);
RegisterWebUIControllerInterfaceBinder<media_feeds::mojom::MediaFeedsStore,
MediaFeedsUI>(map);
RegisterWebUIControllerInterfaceBinder<
media_history::mojom::MediaHistoryStore, MediaHistoryUI>(map);
......
......@@ -43,6 +43,9 @@ This file specifies browser resources for developer-facing chrome:// pages
<include name="IDR_MEDIA_ENGAGEMENT_HTML" file="resources\media\media_engagement.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
<include name="IDR_MEDIA_ENGAGEMENT_JS" file="resources\media\media_engagement.js" flattenhtml="true" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_ENGAGEMENT_SCORE_DETAILS_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\media_engagement_score_details.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_FEEDS_HTML" file="resources\media\media_feeds.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
<include name="IDR_MEDIA_FEEDS_JS" file="resources\media\media_feeds.js" flattenhtml="true" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_FEEDS_STORE_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\feeds\media_feeds_store.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_HISTORY_HTML" file="resources\media\media_history.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
<include name="IDR_MEDIA_HISTORY_JS" file="resources\media\media_history.js" flattenhtml="true" type="BINDATA" compress="gzip" />
<include name="IDR_MEDIA_HISTORY_STORE_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\history\media_history_store.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
......
# Copyright 2020 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.
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojo_bindings") {
sources = [ "media_feeds_store.mojom" ]
public_deps = [ "//url/mojom:url_mojom_origin" ]
}
......@@ -4,3 +4,6 @@
beccahughes@chromium.org
sgbowen@google.com
steimel@chromium.org
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
// Copyright 2020 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.
module media_feeds.mojom;
import "url/mojom/url.mojom";
struct MediaFeed {
// The ID of the field in storage.
int64 id;
// The URL for the discovered feed.
url.mojom.Url url;
};
// MediaFeedStore allows the Media Feeds WebUI to access data from the Media
// Feeds backend in the browser process for diagnostic purposes.
interface MediaFeedsStore {
// Gets all the discovered media feeds.
GetMediaFeeds() => (array<MediaFeed> feeds);
};
......@@ -74,4 +74,29 @@ bool MediaHistoryFeedsTable::SaveFeed(const GURL& url) {
return statement.Run();
}
std::vector<media_feeds::mojom::MediaFeedPtr>
MediaHistoryFeedsTable::GetRows() {
std::vector<media_feeds::mojom::MediaFeedPtr> feeds;
if (!CanAccessDatabase())
return feeds;
sql::Statement statement(
DB()->GetUniqueStatement(base::StringPrintf("SELECT id, url "
"FROM %s",
kTableName)
.c_str()));
while (statement.Step()) {
media_feeds::mojom::MediaFeedPtr feed(media_feeds::mojom::MediaFeed::New());
feed->id = statement.ColumnInt64(0);
feed->url = GURL(statement.ColumnString(1));
feeds.push_back(std::move(feed));
}
DCHECK(statement.Succeeded());
return feeds;
}
} // namespace media_history
......@@ -5,6 +5,9 @@
#ifndef CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_FEEDS_TABLE_H_
#define CHROME_BROWSER_MEDIA_HISTORY_MEDIA_HISTORY_FEEDS_TABLE_H_
#include <vector>
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "chrome/browser/media/history/media_history_table_base.h"
#include "sql/init_status.h"
#include "url/gurl.h"
......@@ -33,6 +36,9 @@ class MediaHistoryFeedsTable : public MediaHistoryTableBase {
// Saves a newly discovered feed in the database.
bool SaveFeed(const GURL& url);
// Returns the feed rows in the database.
std::vector<media_feeds::mojom::MediaFeedPtr> GetRows();
};
} // namespace media_history
......
......@@ -185,4 +185,10 @@ void MediaHistoryKeyedService::PostTaskToDBForTest(base::OnceClosure callback) {
store_->GetForRead()->PostTaskToDBForTest(std::move(callback));
}
void MediaHistoryKeyedService::GetMediaFeedsForDebug(
base::OnceCallback<void(std::vector<media_feeds::mojom::MediaFeedPtr>)>
callback) {
store_->GetForRead()->GetMediaFeedsForDebug(std::move(callback));
}
} // namespace media_history
......@@ -91,6 +91,12 @@ class MediaHistoryKeyedService : public KeyedService,
// for waiting for database operations in tests.
void PostTaskToDBForTest(base::OnceClosure callback);
// Returns all the rows in the media feeds table. This is only used for
// debugging because it loads all rows in the table.
void GetMediaFeedsForDebug(
base::OnceCallback<void(std::vector<media_feeds::mojom::MediaFeedPtr>)>
callback);
private:
class StoreHolder;
......
......@@ -73,6 +73,8 @@ class MediaHistoryStoreInternal
std::vector<mojom::MediaHistoryPlaybackRowPtr>
GetMediaHistoryPlaybackRowsForDebug();
std::vector<media_feeds::mojom::MediaFeedPtr> GetMediaFeedsForDebug();
void SavePlaybackSession(
const GURL& url,
const media_session::MediaMetadata& metadata,
......@@ -313,6 +315,15 @@ MediaHistoryStoreInternal::GetMediaHistoryPlaybackRowsForDebug() {
return playback_table_->GetPlaybackRows();
}
std::vector<media_feeds::mojom::MediaFeedPtr>
MediaHistoryStoreInternal::GetMediaFeedsForDebug() {
DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!initialization_successful_ || !feeds_table_)
return std::vector<media_feeds::mojom::MediaFeedPtr>();
return feeds_table_->GetRows();
}
int MediaHistoryStoreInternal::GetTableRowCount(const std::string& table_name) {
DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
if (!initialization_successful_)
......@@ -542,6 +553,15 @@ void MediaHistoryStore::GetMediaHistoryPlaybackRowsForDebug(
std::move(callback));
}
void MediaHistoryStore::GetMediaFeedsForDebug(
base::OnceCallback<void(std::vector<media_feeds::mojom::MediaFeedPtr>)>
callback) {
base::PostTaskAndReplyWithResult(
db_->db_task_runner_.get(), FROM_HERE,
base::BindOnce(&MediaHistoryStoreInternal::GetMediaFeedsForDebug, db_),
std::move(callback));
}
void MediaHistoryStore::SavePlaybackSession(
const GURL& url,
const media_session::MediaMetadata& metadata,
......
......@@ -14,6 +14,7 @@
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/updateable_sequenced_task_runner.h"
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "chrome/browser/media/history/media_history_origin_table.h"
#include "chrome/browser/media/history/media_history_playback_table.h"
#include "chrome/browser/media/history/media_history_store.mojom.h"
......@@ -74,6 +75,12 @@ class MediaHistoryStore {
base::OnceCallback<void(std::vector<mojom::MediaHistoryPlaybackRowPtr>)>
callback);
// Returns all the rows in the media feeds table. This is only used for
// debugging because it loads all rows in the table.
void GetMediaFeedsForDebug(
base::OnceCallback<void(std::vector<media_feeds::mojom::MediaFeedPtr>)>
callback);
// Gets the playback sessions from the media history store. The results will
// be ordered by most recent first and be limited to the first |num_sessions|.
// For each session it calls |filter| and if that returns |true| then that
......
......@@ -15,6 +15,7 @@
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "chrome/browser/media/history/media_history_feeds_table.h"
#include "chrome/browser/media/history/media_history_images_table.h"
#include "chrome/browser/media/history/media_history_keyed_service.h"
......@@ -141,6 +142,21 @@ class MediaHistoryStoreUnitTest : public testing::Test,
return out;
}
std::vector<media_feeds::mojom::MediaFeedPtr> GetMediaFeedsSync(
MediaHistoryKeyedService* service) {
base::RunLoop run_loop;
std::vector<media_feeds::mojom::MediaFeedPtr> out;
service->GetMediaFeedsForDebug(base::BindLambdaForTesting(
[&](std::vector<media_feeds::mojom::MediaFeedPtr> rows) {
out = std::move(rows);
run_loop.Quit();
}));
run_loop.Run();
return out;
}
MediaHistoryKeyedService* service() const {
// If the param is true then we use the OTR service to simulate being in
// incognito.
......@@ -524,13 +540,22 @@ TEST_P(MediaHistoryStoreFeedsTest, SaveMediaFeed) {
{
// Check the feeds were recorded.
mojom::MediaHistoryStatsPtr stats = GetStatsSync(service());
std::vector<media_feeds::mojom::MediaFeedPtr> feeds =
GetMediaFeedsSync(service());
EXPECT_EQ(IsReadOnly() ? 0 : 2,
stats->table_row_counts[MediaHistoryFeedsTable::kTableName]);
if (IsReadOnly()) {
EXPECT_TRUE(feeds.empty());
} else {
EXPECT_EQ(2u, feeds.size());
EXPECT_EQ(1, feeds[0]->id);
EXPECT_EQ(url_a, feeds[0]->url);
EXPECT_EQ(2, feeds[1]->id);
EXPECT_EQ(url_b, feeds[1]->url);
}
// The OTR service should have the same data.
EXPECT_EQ(stats, GetStatsSync(otr_service()));
EXPECT_EQ(feeds, GetMediaFeedsSync(otr_service()));
}
service()->SaveMediaFeed(url_c);
......@@ -538,12 +563,22 @@ TEST_P(MediaHistoryStoreFeedsTest, SaveMediaFeed) {
{
// Check the feeds were recorded.
mojom::MediaHistoryStatsPtr stats = GetStatsSync(service());
EXPECT_EQ(IsReadOnly() ? 0 : 2,
stats->table_row_counts[MediaHistoryFeedsTable::kTableName]);
std::vector<media_feeds::mojom::MediaFeedPtr> feeds =
GetMediaFeedsSync(service());
if (IsReadOnly()) {
EXPECT_TRUE(feeds.empty());
} else {
EXPECT_EQ(2u, feeds.size());
EXPECT_EQ(2, feeds[0]->id);
EXPECT_EQ(url_b, feeds[0]->url);
EXPECT_EQ(3, feeds[1]->id);
EXPECT_EQ(url_c, feeds[1]->url);
}
// The OTR service should have the same data.
EXPECT_EQ(stats, GetStatsSync(otr_service()));
EXPECT_EQ(feeds, GetMediaFeedsSync(otr_service()));
}
}
......
......@@ -17,6 +17,7 @@ if (closure_compile) {
"components:closure_compile",
"engagement:closure_compile",
"interventions_internals:closure_compile",
"media:closure_compile",
"reset_password:closure_compile",
]
if (is_linux || is_win || is_mac) {
......
......@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
import("//tools/grit/grit_rule.gni")
grit("webrtc_logs_resources") {
......@@ -18,3 +19,15 @@ grit("webrtc_logs_resources") {
"root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
]
}
js_type_check("closure_compile") {
deps = [ ":media_feeds" ]
}
js_library("media_feeds") {
deps = [
"//chrome/browser/media/feeds:mojo_bindings_js_library_for_compile",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:util",
]
}
<!doctype html>
<html lang="en">
<head>
<title>Media Feeds</title>
<meta charset="utf-8">
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
<script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
<script src="chrome://resources/js/promise_resolver.js"></script>
<script src="chrome://resources/mojo/url/mojom/url.mojom-lite.js"></script>
<script src="chrome://resources/js/util.js"></script>
<script src="chrome/browser/media/feeds/media_feeds_store.mojom-lite.js">
</script>
<script src="chrome://media-feeds/media-feeds.js"></script>
<style>
body {
font-family: 'Roboto', 'Noto', sans-serif;
font-size: 14px;
}
button {
margin-bottom: 20px;
}
table {
border-collapse: collapse;
margin-bottom: 20px;
}
table td,
table th {
border: 1px solid #777;
padding-inline-end: 4px;
padding-inline-start: 4px;
}
table th {
background: rgb(224, 236, 255);
cursor: pointer;
padding-bottom: 4px;
padding-inline-end: 4px;
padding-top: 4px;
white-space: nowrap;
}
.url-cell {
background-color: rgba(230, 230, 230, 0.5);
}
.name-cell {
background-color: rgba(230, 230, 230, 0.5);
}
table tr:hover {
background: rgb(255, 255, 187);
}
th.sort-column {
padding-inline-end: 16px;
}
th.sort-column::after {
content: '▲';
position: absolute;
}
th[sort-reverse].sort-column::after {
content: '▼';
position: absolute;
}
</style>
</head>
<body>
<h1>Media Feeds</h1>
<button id="copy-all-to-clipboard">Copy all to clipboard</button>
<table>
<thead>
<tr id="feed-table-header">
<th sort-key="id" class="sort-column" sort-reverse>
ID
</th>
<th sort-key="url">
Url
</th>
</tr>
</thead>
<tbody id="feed-table-body">
</tbody>
</table>
<template id="datarow">
<tr>
<td class="id-cell"></td>
<td class="url-cell"></td>
</tr>
</template>
</body>
</html>
// Copyright 2020 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.
// TODO(https://crbug.com/1059352): Factor out the sortable table.
'use strict';
// Allow a function to be provided by tests, which will be called when
// the page has been populated with media feeds details.
const pageIsPopulatedResolver = new PromiseResolver();
function whenPageIsPopulatedForTest() {
return pageIsPopulatedResolver.promise;
}
(function() {
let detailsProvider = null;
let info = null;
let feedTableBody = null;
let sortReverse = true;
let sortKey = 'id';
/**
* Creates a single row in the feeds table.
* @param {!mediaFeeds.mojom.MediaFeed} rowInfo The info to create the row.
* @return {!Node}
*/
function createRow(rowInfo) {
const template = $('datarow');
const td = template.content.querySelectorAll('td');
td[0].textContent = rowInfo.id;
td[1].textContent = rowInfo.url.url;
return document.importNode(template.content, true);
}
/**
* Remove all rows from the feeds table.
*/
function clearTable() {
feedTableBody.innerHTML = '';
}
/**
* Sort the feed info based on |sortKey| and |sortReverse|.
*/
function sortInfo() {
info.sort((a, b) => {
return (sortReverse ? -1 : 1) * compareTableItem(sortKey, a, b);
});
}
/**
* Compares two MediaFeed objects based on |sortKey|.
* @param {string} sortKey The name of the property to sort by.
* @param {mediaFeeds.mojom.MediaFeed} a First object to compare.
* @param {mediaFeeds.mojom.MediaFeed} b Second object to compare.
* @return {number|boolean} A negative number if |a| should be ordered before
* |b|, a positive number otherwise.
*/
function compareTableItem(sortKey, a, b) {
if (sortKey == 'url') {
return a.url.url > b.url.url ? 1 : -1;
} else if (sortKey == 'id') {
return a.id > b.id;
}
assertNotReached('Unsupported sort key: ' + sortKey);
return 0;
}
/**
* Regenerates the feed table from |info|.
*/
function renderTable() {
clearTable();
sortInfo();
info.forEach(rowInfo => feedTableBody.appendChild(createRow(rowInfo)));
}
/**
* Retrieve feed info and render the feed table.
*/
function updateFeedTable() {
detailsProvider.getMediaFeeds().then(response => {
info = response.feeds;
renderTable();
pageIsPopulatedResolver.resolve();
});
}
document.addEventListener('DOMContentLoaded', () => {
detailsProvider = mediaFeeds.mojom.MediaFeedsStore.getRemote();
feedTableBody = $('feed-table-body');
updateFeedTable();
// Set table header sort handlers.
const feedTableHeader = $('feed-table-header');
const headers = feedTableHeader.children;
for (let i = 0; i < headers.length; i++) {
headers[i].addEventListener('click', (e) => {
const newSortKey = e.target.getAttribute('sort-key');
if (sortKey == newSortKey) {
sortReverse = !sortReverse;
} else {
sortKey = newSortKey;
sortReverse = false;
}
const oldSortColumn = document.querySelector('.sort-column');
oldSortColumn.classList.remove('sort-column');
e.target.classList.add('sort-column');
if (sortReverse) {
e.target.setAttribute('sort-reverse', '');
} else {
e.target.removeAttribute('sort-reverse');
}
renderTable();
});
}
// Add handler to 'copy all to clipboard' button
const copyAllToClipboardButton = $('copy-all-to-clipboard');
copyAllToClipboardButton.addEventListener('click', (e) => {
// Make sure nothing is selected
window.getSelection().removeAllRanges();
document.execCommand('selectAll');
document.execCommand('copy');
// And deselect everything at the end.
window.getSelection().removeAllRanges();
});
});
})();
......@@ -257,6 +257,8 @@ jumbo_static_library("ui") {
"webui/log_web_ui_url.h",
"webui/media/media_engagement_ui.cc",
"webui/media/media_engagement_ui.h",
"webui/media/media_feeds_ui.cc",
"webui/media/media_feeds_ui.h",
"webui/media/media_history_ui.cc",
"webui/media/media_history_ui.h",
"webui/media/webrtc_logs_ui.cc",
......@@ -399,6 +401,7 @@ jumbo_static_library("ui") {
"//chrome/browser/engagement:mojo_bindings",
"//chrome/browser/image_decoder",
"//chrome/browser/media:mojo_bindings",
"//chrome/browser/media/feeds:mojo_bindings",
"//chrome/browser/notifications/scheduler/public",
"//chrome/browser/profiling_host",
"//chrome/browser/resources/invalidations:invalidations_resources",
......
......@@ -18,6 +18,7 @@
#include "chrome/browser/buildflags.h"
#include "chrome/browser/devtools/devtools_ui_bindings.h"
#include "chrome/browser/engagement/site_engagement_service.h"
#include "chrome/browser/media/feeds/media_feeds_service.h"
#include "chrome/browser/media/history/media_history_keyed_service.h"
#include "chrome/browser/media/media_engagement_service.h"
#include "chrome/browser/profiles/profile.h"
......@@ -48,6 +49,7 @@
#include "chrome/browser/ui/webui/local_state/local_state_ui.h"
#include "chrome/browser/ui/webui/log_web_ui_url.h"
#include "chrome/browser/ui/webui/media/media_engagement_ui.h"
#include "chrome/browser/ui/webui/media/media_feeds_ui.h"
#include "chrome/browser/ui/webui/media/media_history_ui.h"
#include "chrome/browser/ui/webui/media/webrtc_logs_ui.h"
#include "chrome/browser/ui/webui/memory_internals_ui.h"
......@@ -776,6 +778,11 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
return &NewWebUI<MediaEngagementUI>;
}
if (media_feeds::MediaFeedsService::IsEnabled() &&
url.host_piece() == chrome::kChromeUIMediaFeedsHost) {
return &NewWebUI<MediaFeedsUI>;
}
if (media_history::MediaHistoryKeyedService::IsEnabled() &&
url.host_piece() == chrome::kChromeUIMediaHistoryHost) {
return &NewWebUI<MediaHistoryUI>;
......
// Copyright 2020 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/ui/webui/media/media_feeds_ui.h"
#include "base/bind.h"
#include "base/macros.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/media/history/media_history_keyed_service.h"
#include "chrome/browser/media/history/media_history_keyed_service_factory.h"
#include "chrome/browser/media/history/media_history_store.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/dev_ui_browser_resources.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_data_source.h"
MediaFeedsUI::MediaFeedsUI(content::WebUI* web_ui)
: ui::MojoWebUIController(web_ui) {
// Setup the data source behind chrome://media-feeds.
std::unique_ptr<content::WebUIDataSource> source(
content::WebUIDataSource::Create(chrome::kChromeUIMediaFeedsHost));
source->AddResourcePath("media-feeds.js", IDR_MEDIA_FEEDS_JS);
source->AddResourcePath(
"chrome/browser/media/feeds/media_feeds_store.mojom-lite.js",
IDR_MEDIA_FEEDS_STORE_MOJOM_LITE_JS);
source->SetDefaultResource(IDR_MEDIA_FEEDS_HTML);
content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source.release());
}
WEB_UI_CONTROLLER_TYPE_IMPL(MediaFeedsUI)
MediaFeedsUI::~MediaFeedsUI() = default;
void MediaFeedsUI::BindInterface(
mojo::PendingReceiver<media_feeds::mojom::MediaFeedsStore> pending) {
receiver_.Add(this, std::move(pending));
}
void MediaFeedsUI::GetMediaFeeds(GetMediaFeedsCallback callback) {
return GetMediaHistoryService()->GetMediaFeedsForDebug(std::move(callback));
}
media_history::MediaHistoryKeyedService*
MediaFeedsUI::GetMediaHistoryService() {
Profile* profile = Profile::FromWebUI(web_ui());
DCHECK(profile);
media_history::MediaHistoryKeyedService* service =
media_history::MediaHistoryKeyedServiceFactory::GetForProfile(profile);
DCHECK(service);
return service;
}
// Copyright 2020 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.
#ifndef CHROME_BROWSER_UI_WEBUI_MEDIA_MEDIA_FEEDS_UI_H_
#define CHROME_BROWSER_UI_WEBUI_MEDIA_MEDIA_FEEDS_UI_H_
#include "chrome/browser/media/feeds/media_feeds_store.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "ui/webui/mojo_web_ui_controller.h"
namespace media_history {
class MediaHistoryKeyedService;
} // namespace media_history
// The UI for chrome://media-feeds.
class MediaFeedsUI : public ui::MojoWebUIController,
public media_feeds::mojom::MediaFeedsStore {
public:
explicit MediaFeedsUI(content::WebUI* web_ui);
MediaFeedsUI(const MediaFeedsUI&) = delete;
MediaFeedsUI& operator=(const MediaFeedsUI&) = delete;
~MediaFeedsUI() override;
// Instantiates the implementor of the MediaFeedsStore mojo interface passing
// the pending receiver that will be internally bound.
void BindInterface(
mojo::PendingReceiver<media_feeds::mojom::MediaFeedsStore> pending);
// media_history::mojom::MediaHistoryStore:
void GetMediaFeeds(GetMediaFeedsCallback callback) override;
private:
media_history::MediaHistoryKeyedService* GetMediaHistoryService();
mojo::ReceiverSet<media_feeds::mojom::MediaFeedsStore> receiver_;
WEB_UI_CONTROLLER_TYPE_DECL();
};
#endif // CHROME_BROWSER_UI_WEBUI_MEDIA_MEDIA_FEEDS_UI_H_
......@@ -97,6 +97,7 @@ const char kChromeUIManagementURL[] = "chrome://management";
const char kChromeUIMdUserManagerHost[] = "md-user-manager";
const char kChromeUIMdUserManagerUrl[] = "chrome://md-user-manager/";
const char kChromeUIMediaEngagementHost[] = "media-engagement";
const char kChromeUIMediaFeedsHost[] = "media-feeds";
const char kChromeUIMediaHistoryHost[] = "media-history";
const char kChromeUIMediaRouterInternalsHost[] = "media-router-internals";
const char kChromeUIMemoryInternalsHost[] = "memory-internals";
......
......@@ -103,6 +103,7 @@ extern const char kChromeUIManagementURL[];
extern const char kChromeUIMdUserManagerHost[];
extern const char kChromeUIMdUserManagerUrl[];
extern const char kChromeUIMediaEngagementHost[];
extern const char kChromeUIMediaFeedsHost[];
extern const char kChromeUIMediaHistoryHost[];
extern const char kChromeUIMediaRouterInternalsHost[];
extern const char kChromeUIMemoryInternalsHost[];
......
......@@ -285,6 +285,7 @@ js2gtest("browser_tests_js_mojo_lite_webui") {
"engagement/site_engagement_browsertest.js",
"interventions_internals_browsertest.js",
"media/media_engagement_browsertest.js",
"media/media_feeds_webui_browsertest.js",
"media/media_history_webui_browsertest.js",
"new_tab_page/new_tab_page_browsertest.js",
"usb_internals_browsertest.js",
......
// Copyright 2020 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.
/**
* @fileoverview Test suite for the Media Feeds WebUI.
*/
GEN('#include "chrome/browser/ui/browser.h"');
GEN('#include "media/base/media_switches.h"');
function MediaFeedsWebUIBrowserTest() {}
MediaFeedsWebUIBrowserTest.prototype = {
__proto__: testing.Test.prototype,
browsePreload: 'chrome://media-feeds',
featureList: {enabled: ['media::kMediaFeeds']},
isAsync: true,
extraLibraries: [
'//third_party/mocha/mocha.js',
'//chrome/test/data/webui/mocha_adapter.js',
],
};
TEST_F('MediaFeedsWebUIBrowserTest', 'All', function() {
suiteSetup(function() {
return whenPageIsPopulatedForTest();
});
test('check feeds table is loaded', function() {
let feedHeaders =
Array.from(document.querySelector('#feed-table-header').children);
assertDeepEquals(['ID', 'Url'], feedHeaders.map(x => x.textContent.trim()));
});
mocha.run();
});
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