Commit 7ed44a41 authored by Hoch Hochkeppel's avatar Hoch Hochkeppel Committed by Commit Bot

WebShare: FakeDataTransferManager Deferral and test interception support

Adding support for IDataRequestDeferral to the FakeDataTransferManager,
as well as adding a test-only PostDataRequested event for easily
intercepting the data shared by a DataRequested handler. Also expanding
the corresponding tests to validate this new behavior.

Bug: 1035527
Change-Id: I44589302272e432b3ea7201b50faa2d90d254194
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2500947Reviewed-by: default avatarEric Willigers <ericwilligers@chromium.org>
Commit-Queue: Hoch Hochkeppel <mhochk@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#821431}
parent 631aed2d
......@@ -9,16 +9,45 @@
#include <wrl/implements.h>
#include <vector>
#include "base/callback_forward.h"
#include "base/callback.h"
namespace webshare {
// Provides an implementation of IDataTransferManager for use in GTests.
class FakeDataTransferManager
class __declspec(uuid("53CA4C00-6F19-40C1-A740-F66510E2DB40"))
FakeDataTransferManager
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>,
ABI::Windows::ApplicationModel::DataTransfer::IDataTransferManager> {
public:
// Represents a file surfaced to a DataRequested event
struct DataRequestedFile {
DataRequestedFile();
DataRequestedFile(const DataRequestedFile&) = delete;
DataRequestedFile& operator=(const DataRequestedFile&) = delete;
DataRequestedFile(DataRequestedFile&&);
~DataRequestedFile();
std::string name;
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFile> file;
};
// Represents the content surfaced to a DataRequested event
struct DataRequestedContent {
DataRequestedContent();
DataRequestedContent(const DataRequestedContent&) = delete;
DataRequestedContent& operator=(const DataRequestedContent&) = delete;
~DataRequestedContent();
std::string text;
std::string title;
std::string uri;
std::vector<DataRequestedFile> files;
};
using PostDataRequestedCallback =
base::RepeatingCallback<void(const DataRequestedContent&)>;
static bool IsSupportedEnvironment();
FakeDataTransferManager();
......@@ -49,6 +78,11 @@ class FakeDataTransferManager
bool HasDataRequestedListener();
// Sets a callback that will be invoked after any DataRequested event is
// triggered and passed the content supplied by the DataRequested handler
void SetPostDataRequestedCallback(
PostDataRequestedCallback post_data_requested_callback);
private:
struct DataRequestedHandlerEntry {
DataRequestedHandlerEntry();
......@@ -63,6 +97,7 @@ class FakeDataTransferManager
std::vector<DataRequestedHandlerEntry> data_requested_event_handlers_;
int64_t latest_token_value_ = 0;
PostDataRequestedCallback post_data_requested_callback_;
};
} // namespace webshare
......
......@@ -4,22 +4,63 @@
#include "chrome/browser/webshare/win/fake_data_transfer_manager.h"
#include <windows.storage.h>
#include <wrl/event.h>
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "base/test/task_environment.h"
#include "base/win/core_winrt_util.h"
#include "base/win/vector.h"
#include "chrome/browser/webshare/win/fake_storage_file_statics.h"
#include "chrome/browser/webshare/win/fake_uri_runtime_class_factory.h"
#include "testing/gtest/include/gtest/gtest-spi.h"
#include "testing/gtest/include/gtest/gtest.h"
using ABI::Windows::ApplicationModel::DataTransfer::DataRequestedEventArgs;
using ABI::Windows::ApplicationModel::DataTransfer::DataTransferManager;
using ABI::Windows::ApplicationModel::DataTransfer::IDataPackage;
using ABI::Windows::ApplicationModel::DataTransfer::IDataPackagePropertySet;
using ABI::Windows::ApplicationModel::DataTransfer::IDataRequest;
using ABI::Windows::ApplicationModel::DataTransfer::IDataRequestDeferral;
using ABI::Windows::ApplicationModel::DataTransfer::IDataRequestedEventArgs;
using ABI::Windows::ApplicationModel::DataTransfer::IDataTransferManager;
using ABI::Windows::Foundation::IAsyncOperation;
using ABI::Windows::Foundation::IAsyncOperationCompletedHandler;
using ABI::Windows::Foundation::ITypedEventHandler;
using ABI::Windows::Foundation::IUriRuntimeClass;
using ABI::Windows::Storage::IStorageFile;
using ABI::Windows::Storage::IStorageItem;
using ABI::Windows::Storage::IStreamedFileDataRequestedHandler;
using ABI::Windows::Storage::StorageFile;
using ABI::Windows::Storage::Streams::IOutputStream;
using Microsoft::WRL::Callback;
using Microsoft::WRL::ComPtr;
using Microsoft::WRL::Make;
namespace ABI {
namespace Windows {
namespace Foundation {
namespace Collections {
// Define template specializations for the types used. These uuids were randomly
// generated.
template <>
struct __declspec(uuid("CBE31E85-DEC8-4227-987F-9C63D6AA1A2E"))
IObservableVector<IStorageItem*> : IObservableVector_impl<IStorageItem*> {};
template <>
struct __declspec(uuid("30BE4864-5EE5-4111-916E-15126649F3C9"))
VectorChangedEventHandler<IStorageItem*>
: VectorChangedEventHandler_impl<IStorageItem*> {};
} // namespace Collections
} // namespace Foundation
} // namespace Windows
} // namespace ABI
namespace webshare {
......@@ -215,4 +256,159 @@ TEST_F(FakeDataTransferManagerTest, OutOfOrderEventInvocation) {
ASSERT_EQ(callback_3.invocation_count_, 1);
}
TEST_F(FakeDataTransferManagerTest, PostDataRequestedCallback) {
if (!IsSupportedEnvironment())
return;
base::test::SingleThreadTaskEnvironment task_environment;
// Create a StorageFile/Item to provide to the DataRequested event
ComPtr<IStorageFile> storage_file;
{
base::RunLoop run_loop;
auto file_name = base::win::ScopedHString::Create("MyTestFile.abc");
ComPtr<IAsyncOperation<StorageFile*>> create_operation;
auto storage_file_statics = Make<FakeStorageFileStatics>();
storage_file_statics->CreateStreamedFileAsync(
file_name.get(),
Callback<IStreamedFileDataRequestedHandler>([](IOutputStream* stream) {
ADD_FAILURE() << "DataRequestedHandler called for streamed file that "
"should never have been opened";
return S_OK;
}).Get(),
/*thumbnail*/ nullptr, &create_operation);
ASSERT_HRESULT_SUCCEEDED(create_operation->put_Completed(
Callback<IAsyncOperationCompletedHandler<StorageFile*>>(
[&run_loop, &storage_file](
IAsyncOperation<StorageFile*>* async_operation,
AsyncStatus async_status) {
EXPECT_EQ(async_status, AsyncStatus::Completed);
EXPECT_HRESULT_SUCCEEDED(
async_operation->GetResults(&storage_file));
run_loop.Quit();
return S_OK;
})
.Get()));
run_loop.Run();
}
ComPtr<IStorageItem> storage_item;
ASSERT_HRESULT_SUCCEEDED(storage_file.As(&storage_item));
// Set up a handler for the DataRequested event that provides a collection of
// content
auto callback = Callback<
ITypedEventHandler<DataTransferManager*, DataRequestedEventArgs*>>(
[&storage_item](IDataTransferManager* data_transfer_manager,
IDataRequestedEventArgs* event_args) -> HRESULT {
ComPtr<IDataRequest> data_request;
EXPECT_HRESULT_SUCCEEDED(event_args->get_Request(&data_request));
ComPtr<IDataPackage> data_package;
EXPECT_HRESULT_SUCCEEDED(data_request->get_Data(&data_package));
ComPtr<IDataPackagePropertySet> data_prop_sets;
EXPECT_HRESULT_SUCCEEDED(data_package->get_Properties(&data_prop_sets));
auto title_h = base::win::ScopedHString::Create("my title");
EXPECT_HRESULT_SUCCEEDED(data_prop_sets->put_Title(title_h.get()));
auto text_h = base::win::ScopedHString::Create("my text");
EXPECT_HRESULT_SUCCEEDED(data_package->SetText(text_h.get()));
auto uri_factory = Make<FakeUriRuntimeClassFactory>();
auto url_h = base::win::ScopedHString::Create("https://my.url.com");
ComPtr<IUriRuntimeClass> uri;
EXPECT_HRESULT_SUCCEEDED(uri_factory->CreateUri(url_h.get(), &uri));
EXPECT_HRESULT_SUCCEEDED(data_package->SetUri(uri.Get()));
auto storage_items = Make<base::win::Vector<IStorageItem*>>();
storage_items->Append(storage_item.Get());
EXPECT_HRESULT_SUCCEEDED(data_package->SetStorageItems(
storage_items.Get(), true /*readonly*/));
return S_OK;
});
EventRegistrationToken token;
ASSERT_HRESULT_SUCCEEDED(
fake_data_transfer_manager_->add_DataRequested(callback.Get(), &token));
// Set up a handler for the PostDataRequested event that validates all the
// expected data
bool post_data_requested_callback_invoked = false;
fake_data_transfer_manager_->SetPostDataRequestedCallback(
base::BindLambdaForTesting(
[&post_data_requested_callback_invoked,
&storage_file](const FakeDataTransferManager::DataRequestedContent&
data_requested_content) {
ASSERT_FALSE(post_data_requested_callback_invoked);
post_data_requested_callback_invoked = true;
ASSERT_EQ(data_requested_content.title, "my title");
ASSERT_EQ(data_requested_content.text, "my text");
ASSERT_EQ(data_requested_content.uri, "https://my.url.com");
ASSERT_EQ(data_requested_content.files.size(), 1u);
ASSERT_EQ(data_requested_content.files[0].name, "MyTestFile.abc");
ASSERT_EQ(data_requested_content.files[0].file, storage_file);
}));
// Run the flow
auto callback_invoker =
fake_data_transfer_manager_->GetDataRequestedInvoker();
ASSERT_FALSE(post_data_requested_callback_invoked);
std::move(callback_invoker).Run();
ASSERT_TRUE(post_data_requested_callback_invoked);
// Cleanup
ASSERT_HRESULT_SUCCEEDED(
fake_data_transfer_manager_->remove_DataRequested(token));
}
TEST_F(FakeDataTransferManagerTest, PostDataRequestedCallback_Deferral) {
if (!IsSupportedEnvironment())
return;
// Set up a handler for the DataRequested event that requests a deferral
ComPtr<IDataRequestDeferral> data_request_deferral;
auto callback = Callback<
ITypedEventHandler<DataTransferManager*, DataRequestedEventArgs*>>(
[&data_request_deferral](IDataTransferManager* data_transfer_manager,
IDataRequestedEventArgs* event_args) -> HRESULT {
ComPtr<IDataRequest> data_request;
EXPECT_HRESULT_SUCCEEDED(event_args->get_Request(&data_request));
EXPECT_HRESULT_SUCCEEDED(
data_request->GetDeferral(&data_request_deferral));
return S_OK;
});
EventRegistrationToken token;
ASSERT_HRESULT_SUCCEEDED(
fake_data_transfer_manager_->add_DataRequested(callback.Get(), &token));
// Set up a handler for the PostDataRequested event that records the event
bool post_data_requested_callback_invoked = false;
fake_data_transfer_manager_->SetPostDataRequestedCallback(
base::BindLambdaForTesting(
[&post_data_requested_callback_invoked](
const FakeDataTransferManager::DataRequestedContent&
data_requested_content) {
ASSERT_FALSE(post_data_requested_callback_invoked);
post_data_requested_callback_invoked = true;
}));
// Run the flow
auto callback_invoker =
fake_data_transfer_manager_->GetDataRequestedInvoker();
ASSERT_FALSE(post_data_requested_callback_invoked);
ASSERT_FALSE(data_request_deferral);
std::move(callback_invoker).Run();
ASSERT_FALSE(post_data_requested_callback_invoked);
ASSERT_TRUE(data_request_deferral);
ASSERT_HRESULT_SUCCEEDED(data_request_deferral->Complete());
ASSERT_TRUE(post_data_requested_callback_invoked);
// Cleanup
ASSERT_HRESULT_SUCCEEDED(
fake_data_transfer_manager_->remove_DataRequested(token));
}
} // namespace webshare
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