| Index: chrome/browser/browsing_data/browsing_data_media_license_helper_unittest.cc
|
| diff --git a/chrome/browser/browsing_data/browsing_data_media_license_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_media_license_helper_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8f4782e4eab69e6096efcd1f67e8c4fd8a11db54
|
| --- /dev/null
|
| +++ b/chrome/browser/browsing_data/browsing_data_media_license_helper_unittest.cc
|
| @@ -0,0 +1,348 @@
|
| +// Copyright 2016 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 <stddef.h>
|
| +#include <algorithm>
|
| +#include <memory>
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/files/file_util.h"
|
| +#include "base/macros.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/stl_util.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "chrome/browser/browsing_data/browsing_data_media_license_helper.h"
|
| +#include "chrome/test/base/testing_profile.h"
|
| +#include "content/public/browser/storage_partition.h"
|
| +#include "content/public/test/test_browser_thread.h"
|
| +#include "content/public/test/test_browser_thread_bundle.h"
|
| +#include "ppapi/shared_impl/ppapi_constants.h"
|
| +#include "storage/browser/fileapi/async_file_util.h"
|
| +#include "storage/browser/fileapi/file_system_context.h"
|
| +#include "storage/browser/fileapi/file_system_operation_context.h"
|
| +#include "storage/browser/fileapi/file_system_url.h"
|
| +#include "storage/browser/fileapi/isolated_context.h"
|
| +#include "storage/browser/quota/quota_manager.h"
|
| +#include "storage/common/fileapi/file_system_types.h"
|
| +#include "storage/common/fileapi/file_system_util.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using content::BrowserContext;
|
| +using content::BrowserThread;
|
| +
|
| +namespace {
|
| +
|
| +// We'll use these three distinct origins for testing, both as strings and as
|
| +// GURLs in appropriate contexts.
|
| +const char kTestOrigin1[] = "http://host1:1/";
|
| +const char kTestOrigin2[] = "http://host2:2/";
|
| +const char kTestOrigin3[] = "http://host3:1/";
|
| +
|
| +const GURL kOrigin1(kTestOrigin1);
|
| +const GURL kOrigin2(kTestOrigin2);
|
| +const GURL kOrigin3(kTestOrigin3);
|
| +
|
| +const char kWidevineCdmPluginId[] = "application_x-ppapi-widevine-cdm";
|
| +const char kClearKeyCdmPluginId[] = "application_x-ppapi-clearkey-cdm";
|
| +
|
| +class AwaitCompletionHelper {
|
| + public:
|
| + AwaitCompletionHelper() : start_(false), already_quit_(false) {}
|
| + virtual ~AwaitCompletionHelper() {}
|
| +
|
| + void BlockUntilNotified() {
|
| + if (!already_quit_) {
|
| + DCHECK(!start_);
|
| + start_ = true;
|
| + base::RunLoop().Run();
|
| + } else {
|
| + DCHECK(!start_);
|
| + already_quit_ = false;
|
| + }
|
| + }
|
| +
|
| + base::Closure NotifyClosure() {
|
| + return base::Bind(&AwaitCompletionHelper::Notify, base::Unretained(this));
|
| + }
|
| +
|
| + private:
|
| + void Notify() {
|
| + if (start_) {
|
| + DCHECK(!already_quit_);
|
| + base::MessageLoop::current()->QuitWhenIdle();
|
| + start_ = false;
|
| + } else {
|
| + DCHECK(!already_quit_);
|
| + already_quit_ = true;
|
| + }
|
| + }
|
| +
|
| + // Helps prevent from running message_loop, if the callback invoked
|
| + // immediately.
|
| + bool start_;
|
| + bool already_quit_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AwaitCompletionHelper);
|
| +};
|
| +
|
| +// The FileSystem APIs are all asynchronous; this testing class wraps up the
|
| +// boilerplate code necessary to deal with waiting for responses. In a nutshell,
|
| +// any async call whose response we want to test ought to be followed by a call
|
| +// to BlockUntilNotified(), which will block until Notify() is called.
|
| +class BrowsingDataMediaLicenseHelperTest : public testing::Test {
|
| + public:
|
| + BrowsingDataMediaLicenseHelperTest() {
|
| + now_ = base::Time::Now();
|
| + profile_.reset(new TestingProfile());
|
| + filesystem_context_ =
|
| + BrowserContext::GetDefaultStoragePartition(profile_.get())
|
| + ->GetFileSystemContext();
|
| + helper_ = BrowsingDataMediaLicenseHelper::Create(filesystem_context_);
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + ~BrowsingDataMediaLicenseHelperTest() override {
|
| + // Avoid memory leaks.
|
| + profile_.reset();
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + // Calls StartFetching() on the test's BrowsingDataMediaLicenseHelper
|
| + // object, then blocks until the callback is executed.
|
| + void FetchMediaLicenses() {
|
| + AwaitCompletionHelper await_completion;
|
| + helper_->StartFetching(
|
| + base::Bind(&BrowsingDataMediaLicenseHelperTest::OnFetchMediaLicenses,
|
| + base::Unretained(this), await_completion.NotifyClosure()));
|
| + await_completion.BlockUntilNotified();
|
| + }
|
| +
|
| + // Callback that should be executed in response to StartFetching(), and stores
|
| + // found file systems locally so that they are available via GetFileSystems().
|
| + void OnFetchMediaLicenses(
|
| + const base::Closure& done_cb,
|
| + const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>&
|
| + media_license_info_list) {
|
| + media_license_info_list_.reset(
|
| + new std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>(
|
| + media_license_info_list));
|
| + done_cb.Run();
|
| + }
|
| +
|
| + // Add some files to the PluginPrivateFileSystem. They are created as follows:
|
| + // kOrigin1 - ClearKey - 1 file - timestamp 10 days ago
|
| + // kOrigin2 - Widevine - 2 files - timestamps now and 60 days ago
|
| + // kOrigin3 - Widevine - 2 files - timestamps 20 and 30 days ago
|
| + virtual void PopulateTestMediaLicenseData() {
|
| + const base::Time ten_days_ago = now_ - base::TimeDelta::FromDays(10);
|
| + const base::Time twenty_days_ago = now_ - base::TimeDelta::FromDays(20);
|
| + const base::Time thirty_days_ago = now_ - base::TimeDelta::FromDays(30);
|
| + const base::Time sixty_days_ago = now_ - base::TimeDelta::FromDays(60);
|
| +
|
| + std::string clearkey_fsid =
|
| + CreateFileSystem(kClearKeyCdmPluginId, kOrigin1);
|
| + storage::FileSystemURL clearkey_file =
|
| + CreateFile(kOrigin1, clearkey_fsid, "foo");
|
| + SetFileTimestamp(clearkey_file, ten_days_ago);
|
| +
|
| + std::string widevine_fsid =
|
| + CreateFileSystem(kWidevineCdmPluginId, kOrigin2);
|
| + storage::FileSystemURL widevine_file1 =
|
| + CreateFile(kOrigin2, widevine_fsid, "bar1");
|
| + storage::FileSystemURL widevine_file2 =
|
| + CreateFile(kOrigin2, widevine_fsid, "bar2");
|
| + SetFileTimestamp(widevine_file1, now_);
|
| + SetFileTimestamp(widevine_file2, sixty_days_ago);
|
| +
|
| + std::string widevine_fsid2 =
|
| + CreateFileSystem(kWidevineCdmPluginId, kOrigin3);
|
| + storage::FileSystemURL widevine_file3 =
|
| + CreateFile(kOrigin3, widevine_fsid2, "test1");
|
| + storage::FileSystemURL widevine_file4 =
|
| + CreateFile(kOrigin3, widevine_fsid2, "test2");
|
| + SetFileTimestamp(widevine_file3, twenty_days_ago);
|
| + SetFileTimestamp(widevine_file4, thirty_days_ago);
|
| + }
|
| +
|
| + const base::Time Now() { return now_; }
|
| +
|
| + void DeleteMediaLicenseOrigin(const GURL& origin) {
|
| + helper_->DeleteMediaLicenseOrigin(origin);
|
| + }
|
| +
|
| + std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>*
|
| + ReturnedMediaLicenseInfo() const {
|
| + return media_license_info_list_.get();
|
| + }
|
| +
|
| + private:
|
| + // Creates a PluginPrivateFileSystem for the |plugin_name| and |origin|
|
| + // provided. Returns the file system ID for the created
|
| + // PluginPrivateFileSystem.
|
| + std::string CreateFileSystem(const std::string& plugin_name,
|
| + const GURL& origin) {
|
| + AwaitCompletionHelper await_completion;
|
| + std::string fsid = storage::IsolatedContext::GetInstance()
|
| + ->RegisterFileSystemForVirtualPath(
|
| + storage::kFileSystemTypePluginPrivate,
|
| + ppapi::kPluginPrivateRootName, base::FilePath());
|
| + EXPECT_TRUE(storage::ValidateIsolatedFileSystemId(fsid));
|
| + filesystem_context_->OpenPluginPrivateFileSystem(
|
| + origin, storage::kFileSystemTypePluginPrivate, fsid, plugin_name,
|
| + storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
|
| + base::Bind(&BrowsingDataMediaLicenseHelperTest::OnFileSystemOpened,
|
| + base::Unretained(this), await_completion.NotifyClosure()));
|
| + await_completion.BlockUntilNotified();
|
| + return fsid;
|
| + }
|
| +
|
| + void OnFileSystemOpened(const base::Closure& done_cb,
|
| + base::File::Error result) {
|
| + EXPECT_EQ(base::File::FILE_OK, result) << base::File::ErrorToString(result);
|
| + done_cb.Run();
|
| + }
|
| +
|
| + // Creates a file named |file_name| in the PluginPrivateFileSystem identified
|
| + // by |origin| and |fsid|. The file is empty (so size = 0). Returns the URL
|
| + // for the created file. The file must not already exist or the test will
|
| + // fail.
|
| + storage::FileSystemURL CreateFile(const GURL& origin,
|
| + const std::string& fsid,
|
| + const std::string& file_name) {
|
| + AwaitCompletionHelper await_completion;
|
| + std::string root = storage::GetIsolatedFileSystemRootURIString(
|
| + origin, fsid, ppapi::kPluginPrivateRootName);
|
| + storage::FileSystemURL file_url =
|
| + filesystem_context_->CrackURL(GURL(root + file_name));
|
| + storage::AsyncFileUtil* file_util = filesystem_context_->GetAsyncFileUtil(
|
| + storage::kFileSystemTypePluginPrivate);
|
| + std::unique_ptr<storage::FileSystemOperationContext> operation_context =
|
| + base::WrapUnique(
|
| + new storage::FileSystemOperationContext(filesystem_context_));
|
| + operation_context->set_allowed_bytes_growth(
|
| + storage::QuotaManager::kNoLimit);
|
| + file_util->EnsureFileExists(
|
| + std::move(operation_context), file_url,
|
| + base::Bind(&BrowsingDataMediaLicenseHelperTest::OnFileCreated,
|
| + base::Unretained(this), await_completion.NotifyClosure()));
|
| + await_completion.BlockUntilNotified();
|
| + return file_url;
|
| + }
|
| +
|
| + void OnFileCreated(const base::Closure& done_cb,
|
| + base::File::Error result,
|
| + bool created) {
|
| + EXPECT_EQ(base::File::FILE_OK, result) << base::File::ErrorToString(result);
|
| + EXPECT_TRUE(created);
|
| + done_cb.Run();
|
| + }
|
| +
|
| + // Sets the last_access_time and last_modified_time to |time_stamp| on the
|
| + // file specified by |file_url|. The file must already exist.
|
| + void SetFileTimestamp(const storage::FileSystemURL& file_url,
|
| + const base::Time& time_stamp) {
|
| + AwaitCompletionHelper await_completion;
|
| + storage::AsyncFileUtil* file_util = filesystem_context_->GetAsyncFileUtil(
|
| + storage::kFileSystemTypePluginPrivate);
|
| + std::unique_ptr<storage::FileSystemOperationContext> operation_context =
|
| + base::WrapUnique(
|
| + new storage::FileSystemOperationContext(filesystem_context_));
|
| + file_util->Touch(
|
| + std::move(operation_context), file_url, time_stamp, time_stamp,
|
| + base::Bind(&BrowsingDataMediaLicenseHelperTest::OnFileTouched,
|
| + base::Unretained(this), await_completion.NotifyClosure()));
|
| + await_completion.BlockUntilNotified();
|
| + }
|
| +
|
| + void OnFileTouched(const base::Closure& done_cb, base::File::Error result) {
|
| + EXPECT_EQ(base::File::FILE_OK, result) << base::File::ErrorToString(result);
|
| + done_cb.Run();
|
| + }
|
| +
|
| + content::TestBrowserThreadBundle thread_bundle_;
|
| + std::unique_ptr<TestingProfile> profile_;
|
| + scoped_refptr<BrowsingDataMediaLicenseHelper> helper_;
|
| +
|
| + // Keep a fixed "now" so that we can compare timestamps.
|
| + base::Time now_;
|
| +
|
| + // We don't own this pointer.
|
| + storage::FileSystemContext* filesystem_context_;
|
| +
|
| + // Storage to pass information back from callbacks.
|
| + std::unique_ptr<std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>>
|
| + media_license_info_list_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BrowsingDataMediaLicenseHelperTest);
|
| +};
|
| +
|
| +// Verifies that the BrowsingDataMediaLicenseHelper correctly handles an empty
|
| +// filesystem.
|
| +TEST_F(BrowsingDataMediaLicenseHelperTest, Empty) {
|
| + FetchMediaLicenses();
|
| + EXPECT_EQ(0u, ReturnedMediaLicenseInfo()->size());
|
| +}
|
| +
|
| +// Verifies that the BrowsingDataMediaLicenseHelper correctly finds the test
|
| +// data, and that each media license returned contains the expected data.
|
| +TEST_F(BrowsingDataMediaLicenseHelperTest, FetchData) {
|
| + PopulateTestMediaLicenseData();
|
| +
|
| + FetchMediaLicenses();
|
| + EXPECT_EQ(3u, ReturnedMediaLicenseInfo()->size());
|
| +
|
| + // Order is arbitrary, verify both origins.
|
| + bool test_hosts_found[] = {false, false, false};
|
| + for (const auto& info : *ReturnedMediaLicenseInfo()) {
|
| + if (info.origin == kOrigin1) {
|
| + EXPECT_FALSE(test_hosts_found[0]);
|
| + test_hosts_found[0] = true;
|
| + EXPECT_EQ(0u, info.size);
|
| + // Single file for origin1 should be 10 days ago.
|
| + EXPECT_EQ(10, (Now() - info.last_modified_time).InDays());
|
| + } else if (info.origin == kOrigin2) {
|
| + EXPECT_FALSE(test_hosts_found[1]);
|
| + test_hosts_found[1] = true;
|
| + EXPECT_EQ(0u, info.size);
|
| + // Files for origin2 are now and 60 days ago, so it should report now.
|
| + EXPECT_EQ(0, (Now() - info.last_modified_time).InDays());
|
| + } else if (info.origin == kOrigin3) {
|
| + EXPECT_FALSE(test_hosts_found[2]);
|
| + test_hosts_found[2] = true;
|
| + EXPECT_EQ(0u, info.size);
|
| + // Files for origin3 are 20 and 30 days ago, so it should report 20.
|
| + EXPECT_EQ(20, (Now() - info.last_modified_time).InDays());
|
| + } else {
|
| + ADD_FAILURE() << info.origin.spec() << " isn't an origin we added.";
|
| + }
|
| + }
|
| + for (size_t i = 0; i < arraysize(test_hosts_found); i++) {
|
| + EXPECT_TRUE(test_hosts_found[i]);
|
| + }
|
| +}
|
| +
|
| +// Verifies that the BrowsingDataMediaLicenseHelper correctly deletes media
|
| +// licenses via DeleteMediaLicenseOrigin().
|
| +TEST_F(BrowsingDataMediaLicenseHelperTest, DeleteData) {
|
| + PopulateTestMediaLicenseData();
|
| +
|
| + DeleteMediaLicenseOrigin(kOrigin1);
|
| + DeleteMediaLicenseOrigin(kOrigin2);
|
| +
|
| + FetchMediaLicenses();
|
| + EXPECT_EQ(1u, ReturnedMediaLicenseInfo()->size());
|
| +
|
| + BrowsingDataMediaLicenseHelper::MediaLicenseInfo info =
|
| + *(ReturnedMediaLicenseInfo()->begin());
|
| + EXPECT_EQ(kOrigin3, info.origin);
|
| + EXPECT_EQ(0u, info.size);
|
| + EXPECT_EQ(20, (Now() - info.last_modified_time).InDays());
|
| +}
|
| +
|
| +} // namespace
|
|
|