Commit f8eda312 authored by Rayan Kanso's avatar Rayan Kanso Committed by Commit Bot

[Background Fetch] Persistent storage for getting settled fetches

Boilerplate for getting settled background fetches that have been
persisted to disk.

TBR=avi@chromium.org

Bug: 826257
Change-Id: I8a49663df9841fc736af3edad3c946c84da8443c
Reviewed-on: https://chromium-review.googlesource.com/1057623
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#560304}
parent 86c3f0e1
......@@ -436,6 +436,8 @@ jumbo_source_set("browser") {
"background_fetch/storage/get_developer_ids_task.h",
"background_fetch/storage/get_metadata_task.cc",
"background_fetch/storage/get_metadata_task.h",
"background_fetch/storage/get_settled_fetches_task.cc",
"background_fetch/storage/get_settled_fetches_task.h",
"background_fetch/storage/mark_registration_for_deletion_task.cc",
"background_fetch/storage/mark_registration_for_deletion_task.h",
"background_fetch/storage/mark_request_complete_task.cc",
......
......@@ -19,6 +19,7 @@
#include "content/browser/background_fetch/storage/delete_registration_task.h"
#include "content/browser/background_fetch/storage/get_developer_ids_task.h"
#include "content/browser/background_fetch/storage/get_metadata_task.h"
#include "content/browser/background_fetch/storage/get_settled_fetches_task.h"
#include "content/browser/background_fetch/storage/mark_registration_for_deletion_task.h"
#include "content/browser/background_fetch/storage/mark_request_complete_task.h"
#include "content/browser/background_fetch/storage/start_next_pending_request_task.h"
......@@ -424,6 +425,13 @@ void BackgroundFetchDataManager::GetSettledFetchesForRegistration(
SettledFetchesCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableBackgroundFetchPersistence)) {
AddDatabaseTask(std::make_unique<background_fetch::GetSettledFetchesTask>(
this, registration_id, std::move(callback)));
return;
}
auto iter = registrations_.find(registration_id.unique_id());
DCHECK(iter != registrations_.end());
......
......@@ -22,6 +22,7 @@
#include "content/public/browser/background_fetch_response.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace content {
......@@ -275,6 +276,27 @@ class BackgroundFetchDataManagerTest
run_loop.Run();
}
// Synchronous version of
// BackgroundFetchDataManager::GetSettledFetchesForRegistration().
void GetSettledFetchesForRegistration(
const BackgroundFetchRegistrationId& registration_id,
blink::mojom::BackgroundFetchError* out_error,
bool* out_succeeded,
std::vector<BackgroundFetchSettledFetch>* out_settled_fetches) {
DCHECK(out_error);
DCHECK(out_succeeded);
DCHECK(out_settled_fetches);
base::RunLoop run_loop;
background_fetch_data_manager_->GetSettledFetchesForRegistration(
registration_id,
base::BindOnce(&BackgroundFetchDataManagerTest::
DidGetSettledFetchesForRegistration,
base::Unretained(this), run_loop.QuitClosure(),
out_error, out_succeeded, out_settled_fetches));
run_loop.Run();
}
// Synchronous version of
// ServiceWorkerContextWrapper::GetRegistrationUserDataByKeyPrefix.
std::vector<std::string> GetRegistrationUserDataByKeyPrefix(
......@@ -394,6 +416,22 @@ class BackgroundFetchDataManagerTest
std::move(quit_closure).Run();
}
void DidGetSettledFetchesForRegistration(
base::OnceClosure quit_closure,
blink::mojom::BackgroundFetchError* out_error,
bool* out_succeeded,
std::vector<BackgroundFetchSettledFetch>* out_settled_fetches,
blink::mojom::BackgroundFetchError error,
bool succeeded,
std::vector<BackgroundFetchSettledFetch> settled_fetches,
std::vector<std::unique_ptr<storage::BlobDataHandle>>) {
*out_error = error;
*out_succeeded = succeeded;
*out_settled_fetches = std::move(settled_fetches);
std::move(quit_closure).Run();
}
BackgroundFetchRegistrationStorage registration_storage_;
std::unique_ptr<BackgroundFetchDataManager> background_fetch_data_manager_;
};
......@@ -784,6 +822,61 @@ TEST_P(BackgroundFetchDataManagerTest, PopNextRequestAndMarkAsComplete) {
2 /* completed_requests */}));
}
TEST_P(BackgroundFetchDataManagerTest, GetSettledFetchesForRegistration) {
// This test only applies to persistent storage.
if (registration_storage_ ==
BackgroundFetchRegistrationStorage::kNonPersistent)
return;
int64_t sw_id = RegisterServiceWorker();
ASSERT_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, sw_id);
std::vector<ServiceWorkerFetchRequest> requests(2u);
BackgroundFetchOptions options;
blink::mojom::BackgroundFetchError error;
BackgroundFetchRegistrationId registration_id(
sw_id, origin(), kExampleDeveloperId, kExampleUniqueId);
CreateRegistration(registration_id, requests, options, &error);
ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_EQ(
GetRequestStats(sw_id),
(ResponseStateStats{2 /* pending_requests */, 0 /* active_requests */,
0 /* completed_requests */}));
// Nothing is downloaded yet.
bool succeeded = false;
std::vector<BackgroundFetchSettledFetch> settled_fetches;
GetSettledFetchesForRegistration(registration_id, &error, &succeeded,
&settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
EXPECT_TRUE(succeeded);
EXPECT_EQ(settled_fetches.size(), 0u);
for (size_t i = 0; i < requests.size(); i++) {
scoped_refptr<BackgroundFetchRequestInfo> request_info;
PopNextRequest(registration_id, &request_info);
ASSERT_TRUE(request_info);
AnnotateRequestInfoWithFakeDownloadManagerData(request_info.get());
MarkRequestAsComplete(registration_id, request_info.get());
}
RestartDataManagerFromPersistentStorage();
EXPECT_EQ(
GetRequestStats(sw_id),
(ResponseStateStats{0 /* pending_requests */, 0 /* active_requests */,
requests.size() /* completed_requests */}));
GetSettledFetchesForRegistration(registration_id, &error, &succeeded,
&settled_fetches);
EXPECT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
// We are marking the responses as failed in Download Manager.
EXPECT_FALSE(succeeded);
EXPECT_EQ(settled_fetches.size(), requests.size());
}
TEST_P(BackgroundFetchDataManagerTest, Cleanup) {
// Tests that the BackgroundFetchDataManager cleans up registrations
// marked for deletion.
......
// Copyright 2018 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 "content/browser/background_fetch/storage/get_settled_fetches_task.h"
#include "base/barrier_closure.h"
#include "content/browser/background_fetch/background_fetch.pb.h"
#include "content/browser/background_fetch/storage/database_helpers.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
namespace content {
namespace background_fetch {
GetSettledFetchesTask::GetSettledFetchesTask(
BackgroundFetchDataManager* data_manager,
BackgroundFetchRegistrationId registration_id,
SettledFetchesCallback callback)
: DatabaseTask(data_manager),
registration_id_(registration_id),
settled_fetches_callback_(std::move(callback)),
weak_factory_(this) {}
GetSettledFetchesTask::~GetSettledFetchesTask() = default;
void GetSettledFetchesTask::Start() {
service_worker_context()->GetRegistrationUserDataByKeyPrefix(
registration_id_.service_worker_registration_id(),
{CompletedRequestKeyPrefix(registration_id_.unique_id())},
base::BindOnce(&GetSettledFetchesTask::DidGetCompletedRequests,
weak_factory_.GetWeakPtr()));
}
void GetSettledFetchesTask::DidGetCompletedRequests(
const std::vector<std::string>& data,
ServiceWorkerStatusCode status) {
switch (ToDatabaseStatus(status)) {
case DatabaseStatus::kOk:
break;
// TODO(crbug.com/780025): Log failures to UMA.
case DatabaseStatus::kFailed:
FinishTaskWithErrorCode(
blink::mojom::BackgroundFetchError::STORAGE_ERROR);
return;
case DatabaseStatus::kNotFound:
background_fetch_succeeded_ = false;
FinishTaskWithErrorCode(blink::mojom::BackgroundFetchError::INVALID_ID);
return;
}
// Nothing failed yet so the default state is success.
if (data.empty()) {
FinishTaskWithErrorCode(blink::mojom::BackgroundFetchError::NONE);
return;
}
base::RepeatingClosure barrier_closure = base::BarrierClosure(
data.size(),
base::BindOnce(&GetSettledFetchesTask::FinishTaskWithErrorCode,
weak_factory_.GetWeakPtr(),
blink::mojom::BackgroundFetchError::NONE));
settled_fetches_.reserve(data.size());
for (const std::string& serialized_completed_request : data) {
proto::BackgroundFetchCompletedRequest completed_request;
if (!completed_request.ParseFromString(serialized_completed_request)) {
NOTREACHED()
<< "Database is corrupt"; // TODO(crbug.com/780027): Nuke it.
}
settled_fetches_.emplace_back(BackgroundFetchSettledFetch());
settled_fetches_.back().request =
std::move(ServiceWorkerFetchRequest::ParseFromString(
completed_request.serialized_request()));
if (!completed_request.succeeded()) {
FillFailedResponse(&settled_fetches_.back().response, barrier_closure);
continue;
}
FillSuccessfulResponse(&settled_fetches_.back().response, barrier_closure);
}
}
void GetSettledFetchesTask::FillFailedResponse(
ServiceWorkerResponse* response,
const base::RepeatingClosure& callback) {
DCHECK(response);
background_fetch_succeeded_ = false;
// TODO(rayankans): Fill failed response with error reports.
std::move(callback).Run();
}
void GetSettledFetchesTask::FillSuccessfulResponse(
ServiceWorkerResponse* response,
const base::RepeatingClosure& callback) {
DCHECK(response);
// TODO(rayankans): Get the response stored in Cache Storage.
std::move(callback).Run();
}
void GetSettledFetchesTask::FinishTaskWithErrorCode(
blink::mojom::BackgroundFetchError error) {
std::move(settled_fetches_callback_)
.Run(error, background_fetch_succeeded_, std::move(settled_fetches_),
{} /* blob_data_handles */);
Finished(); // Destroys |this|.
}
} // namespace background_fetch
} // namespace content
// Copyright 2018 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 CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_SETTLED_FETCHES_TASK_H_
#define CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_SETTLED_FETCHES_TASK_H_
#include "base/callback_forward.h"
#include "content/browser/background_fetch/storage/database_task.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "storage/browser/blob/blob_data_handle.h"
namespace content {
namespace background_fetch {
class GetSettledFetchesTask : public DatabaseTask {
public:
using SettledFetchesCallback = base::OnceCallback<void(
blink::mojom::BackgroundFetchError,
bool,
std::vector<BackgroundFetchSettledFetch>,
std::vector<std::unique_ptr<storage::BlobDataHandle>>)>;
GetSettledFetchesTask(BackgroundFetchDataManager* data_manager,
BackgroundFetchRegistrationId registration_id,
SettledFetchesCallback callback);
~GetSettledFetchesTask() override;
// DatabaseTask implementation:
void Start() override;
private:
void DidGetCompletedRequests(const std::vector<std::string>& data,
ServiceWorkerStatusCode status);
void FillFailedResponse(ServiceWorkerResponse* response,
const base::RepeatingClosure& callback);
void FillSuccessfulResponse(ServiceWorkerResponse* response,
const base::RepeatingClosure& callback);
void FinishTaskWithErrorCode(blink::mojom::BackgroundFetchError error);
BackgroundFetchRegistrationId registration_id_;
SettledFetchesCallback settled_fetches_callback_;
std::vector<BackgroundFetchSettledFetch> settled_fetches_;
bool background_fetch_succeeded_ = true;
base::WeakPtrFactory<GetSettledFetchesTask> weak_factory_; // Keep as last.
DISALLOW_COPY_AND_ASSIGN(GetSettledFetchesTask);
};
} // namespace background_fetch
} // namespace content
#endif // CONTENT_BROWSER_BACKGROUND_FETCH_STORAGE_GET_SETTLED_FETCHES_TASK_H_
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