blob: ad058f8967237cb2fba60672d05dbade7d08a5fe [file] [log] [blame]
// 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 "android_webview/browser/aw_permission_manager.h"
#include <list>
#include <memory>
#include "android_webview/browser/aw_browser_permission_request_delegate.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_type.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using blink::mojom::PermissionStatus;
using content::PermissionType;
namespace android_webview {
namespace {
int kNoPendingOperation = -1;
int kRenderProcessIDForTesting = 8;
int kRenderFrameIDForTesting = 19;
const char kEmbeddingOrigin[] = "https://www.google.com/";
const char kRequestingOrigin1[] = "https://www.google.com/";
const char kRequestingOrigin2[] = "https://www.chromium.org/";
class AwBrowserPermissionRequestDelegateForTesting final
: public AwBrowserPermissionRequestDelegate {
public:
void EnqueueResponse(const std::string& origin,
PermissionType type,
bool grant) {
for (auto it = request_.begin(); it != request_.end(); ++it) {
if ((*it)->type != type || (*it)->origin != origin)
continue;
base::OnceCallback<void(bool)> callback = std::move((*it)->callback);
request_.erase(it);
std::move(callback).Run(grant);
return;
}
response_.push_back(std::make_unique<Response>(origin, type, grant));
}
// AwBrowserPermissionRequestDelegate:
void RequestProtectedMediaIdentifierPermission(
const GURL& origin,
base::OnceCallback<void(bool)> callback) override {}
void CancelProtectedMediaIdentifierPermissionRequests(
const GURL& origin) override {}
void RequestGeolocationPermission(
const GURL& origin,
base::OnceCallback<void(bool)> callback) override {
RequestPermission(origin, PermissionType::GEOLOCATION, std::move(callback));
}
void CancelGeolocationPermissionRequests(const GURL& origin) override {
CancelPermission(origin, PermissionType::GEOLOCATION);
}
void RequestMIDISysexPermission(
const GURL& origin,
base::OnceCallback<void(bool)> callback) override {
RequestPermission(origin, PermissionType::MIDI_SYSEX, std::move(callback));
}
void CancelMIDISysexPermissionRequests(const GURL& origin) override {
CancelPermission(origin, PermissionType::MIDI_SYSEX);
}
private:
void RequestPermission(const GURL& origin,
PermissionType type,
base::OnceCallback<void(bool)> callback) {
for (auto it = response_.begin(); it != response_.end(); ++it) {
if ((*it)->type != type || (*it)->origin != origin)
continue;
bool grant = (*it)->grant;
response_.erase(it);
std::move(callback).Run(grant);
return;
}
request_.push_back(
std::make_unique<Request>(origin, type, std::move(callback)));
}
void CancelPermission(const GURL& origin, PermissionType type) {
for (auto it = request_.begin(); it != request_.end(); ++it) {
if ((*it)->type != type || (*it)->origin != origin)
continue;
request_.erase(it);
return;
}
NOTREACHED();
}
private:
struct Request {
GURL origin;
PermissionType type;
base::OnceCallback<void(bool)> callback;
Request(const GURL& origin,
PermissionType type,
base::OnceCallback<void(bool)> callback)
: origin(origin), type(type), callback(std::move(callback)) {}
};
struct Response {
GURL origin;
PermissionType type;
bool grant;
Response(const std::string& origin, PermissionType type, bool grant)
: origin(GURL(origin)), type(type), grant(grant) {}
};
std::list<std::unique_ptr<Response>> response_;
std::list<std::unique_ptr<Request>> request_;
};
class AwPermissionManagerForTesting : public AwPermissionManager {
public:
~AwPermissionManagerForTesting() override {
// Call CancelPermissionRequests() from here so that it calls virtual
// methods correctly.
CancelPermissionRequests();
}
void EnqueuePermissionResponse(const std::string& origin,
PermissionType type,
bool grant) {
delegate()->EnqueueResponse(origin, type, grant);
}
private:
AwBrowserPermissionRequestDelegateForTesting* delegate() {
if (!delegate_)
delegate_.reset(new AwBrowserPermissionRequestDelegateForTesting);
return delegate_.get();
}
// AwPermissionManager:
int GetRenderProcessID(content::RenderFrameHost* render_frame_host) override {
return kRenderProcessIDForTesting;
}
int GetRenderFrameID(content::RenderFrameHost* render_frame_host) override {
return kRenderFrameIDForTesting;
}
GURL LastCommittedOrigin(
content::RenderFrameHost* render_frame_host) override {
return GURL(kEmbeddingOrigin);
}
AwBrowserPermissionRequestDelegate* GetDelegate(
int render_process_id,
int render_frame_id) override {
CHECK_EQ(kRenderProcessIDForTesting, render_process_id);
CHECK_EQ(kRenderFrameIDForTesting, render_frame_id);
return delegate();
}
std::unique_ptr<AwBrowserPermissionRequestDelegateForTesting> delegate_;
};
class AwPermissionManagerTest : public testing::Test {
public:
AwPermissionManagerTest()
: render_frame_host(nullptr) {}
void PermissionRequestResponse(int id, const PermissionStatus status) {
resolved_permission_status.push_back(status);
resolved_permission_request_id.push_back(id);
}
void PermissionsRequestResponse(int id,
const std::vector<PermissionStatus>& status) {
resolved_permission_status.insert(resolved_permission_status.end(),
status.begin(), status.end());
for (size_t i = 0; i < status.size(); ++i)
resolved_permission_request_id.push_back(id);
}
protected:
void SetUp() override { manager.reset(new AwPermissionManagerForTesting); }
void TearDown() override { manager.reset(); }
void EnqueuePermissionResponse(const std::string& origin,
PermissionType type,
bool grant) {
CHECK(manager);
manager->EnqueuePermissionResponse(origin, type, grant);
}
std::unique_ptr<AwPermissionManagerForTesting> manager;
// Use nullptr for testing. AwPermissionManagerForTesting override all methods
// that touch RenderFrameHost to work with nullptr.
content::RenderFrameHost* render_frame_host;
std::vector<PermissionStatus> resolved_permission_status;
std::vector<int> resolved_permission_request_id;
};
// The most simple test, PermissionType::MIDI is hard-coded to be granted.
TEST_F(AwPermissionManagerTest, MIDIPermissionIsGrantedSynchronously) {
int request_id = manager->RequestPermission(
PermissionType::MIDI, render_frame_host, GURL(kRequestingOrigin1), true,
base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 0));
EXPECT_EQ(kNoPendingOperation, request_id);
ASSERT_EQ(1u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
}
// Test the case a delegate is called, and it resolves the permission
// synchronously.
TEST_F(AwPermissionManagerTest, SinglePermissionRequestIsGrantedSynchronously) {
// Permission should be granted in this scenario.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::GEOLOCATION, true);
int request_id = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 0));
EXPECT_EQ(kNoPendingOperation, request_id);
ASSERT_EQ(1u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
// Permission should not be granted in this scenario.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::GEOLOCATION, false);
request_id = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 0));
EXPECT_EQ(kNoPendingOperation, request_id);
ASSERT_EQ(2u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[1]);
}
// Test the case a delegate is called, and it resolves the permission
// asynchronously.
TEST_F(AwPermissionManagerTest,
SinglePermissionRequestIsGrantedAsynchronously) {
int request_id = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 0));
EXPECT_NE(kNoPendingOperation, request_id);
EXPECT_EQ(0u, resolved_permission_status.size());
// This will resolve the permission.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::GEOLOCATION, true);
ASSERT_EQ(1u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
}
// Test the case a delegate is called, and the manager is deleted before the
// delegate callback is invoked.
TEST_F(AwPermissionManagerTest, ManagerIsDeletedWhileDelegateProcesses) {
int request_id = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 0));
EXPECT_NE(kNoPendingOperation, request_id);
EXPECT_EQ(0u, resolved_permission_status.size());
// Delete the manager.
manager.reset();
// All requests are cancelled internally.
EXPECT_EQ(0u, resolved_permission_status.size());
}
// Test the case multiple permissions are requested for the same origin, and the
// second permission is also resolved when the first permission is resolved.
TEST_F(AwPermissionManagerTest,
MultiplePermissionRequestsAreGrantedTogether) {
int request_1 = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 1));
EXPECT_NE(kNoPendingOperation, request_1);
int request_2 = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 2));
EXPECT_NE(kNoPendingOperation, request_2);
EXPECT_NE(request_1, request_2);
EXPECT_EQ(0u, resolved_permission_status.size());
// This will resolve the permission.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::GEOLOCATION, true);
ASSERT_EQ(2u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]);
}
// Test the case multiple permissions are requested for different origins, and
// each permission is resolved respectively in the requested order.
TEST_F(AwPermissionManagerTest,
MultiplePermissionRequestsAreGrantedRespectively) {
int request_1 = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 1));
EXPECT_NE(kNoPendingOperation, request_1);
int request_2 = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin2),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 2));
EXPECT_NE(kNoPendingOperation, request_2);
EXPECT_NE(request_1, request_2);
EXPECT_EQ(0u, resolved_permission_status.size());
// This will resolve the first request.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::GEOLOCATION, true);
ASSERT_EQ(1u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
EXPECT_EQ(1, resolved_permission_request_id[0]);
// This will resolve the second request.
manager->EnqueuePermissionResponse(kRequestingOrigin2,
PermissionType::GEOLOCATION, false);
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[1]);
EXPECT_EQ(2, resolved_permission_request_id[1]);
}
// Test the case multiple permissions are requested through single
// RequestPermissions call, then resolved synchronously.
TEST_F(AwPermissionManagerTest,
SinglePermissionsRequestIsGrantedSynchronously) {
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, false);
std::vector<PermissionType> permissions = {PermissionType::MIDI,
PermissionType::MIDI_SYSEX};
int request_id = manager->RequestPermissions(
permissions,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 0));
EXPECT_EQ(kNoPendingOperation, request_id);
ASSERT_EQ(2u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[1]);
}
// Test the case multiple permissions are requested through single
// RequestPermissions call, then one is resolved synchronously, the other is
// resolved asynchronously.
TEST_F(AwPermissionManagerTest,
SinglePermissionsRequestIsGrantedAsynchronously) {
std::vector<PermissionType> permissions = {PermissionType::MIDI,
PermissionType::MIDI_SYSEX};
int request_id = manager->RequestPermissions(
permissions,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 0));
EXPECT_NE(kNoPendingOperation, request_id);
// PermissionType::MIDI is resolved synchronously, but all permissions result
// are notified together when all permissions are resolved.
EXPECT_EQ(0u, resolved_permission_status.size());
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, false);
ASSERT_EQ(2u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[1]);
}
// Test the case multiple permissions are requested multiple times as follow.
// 1. Permission A and B are requested.
// 2. Permission A is resolved.
// 3. Permission A is requested for the same origin before the B is resolved.
TEST_F(AwPermissionManagerTest, ComplicatedRequestScenario1) {
// In the first case, the permission A is a type that does not call an
// internal delegate method.
std::vector<PermissionType> permissions_1 = {PermissionType::MIDI,
PermissionType::MIDI_SYSEX};
int request_1 = manager->RequestPermissions(
permissions_1,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 1));
EXPECT_NE(kNoPendingOperation, request_1);
EXPECT_EQ(0u, resolved_permission_status.size());
int request_2 = manager->RequestPermission(
PermissionType::MIDI, render_frame_host, GURL(kRequestingOrigin1), true,
base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 2));
EXPECT_EQ(kNoPendingOperation, request_2);
ASSERT_EQ(1u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
EXPECT_EQ(2, resolved_permission_request_id[0]);
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, true);
ASSERT_EQ(3u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]);
EXPECT_EQ(1, resolved_permission_request_id[1]);
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[2]);
EXPECT_EQ(1, resolved_permission_request_id[2]);
// In the second case, the permission A is a type that calls an internal
// delegate method.
std::vector<PermissionType> permissions_2 = {PermissionType::GEOLOCATION,
PermissionType::MIDI_SYSEX};
int request_3 = manager->RequestPermissions(
permissions_2,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 3));
EXPECT_NE(kNoPendingOperation, request_3);
ASSERT_EQ(3u, resolved_permission_status.size());
// The permission A is resolved, but the first request isn't finished.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::GEOLOCATION, false);
ASSERT_EQ(3u, resolved_permission_status.size());
int request_4 = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 4));
// The second request is finished first by using the resolved result for the
// first request.
EXPECT_EQ(kNoPendingOperation, request_4);
ASSERT_EQ(4u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[3]);
EXPECT_EQ(4, resolved_permission_request_id[3]);
// Then the first request is finished.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, true);
ASSERT_EQ(6u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[4]);
EXPECT_EQ(3, resolved_permission_request_id[4]);
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[5]);
EXPECT_EQ(3, resolved_permission_request_id[5]);
}
// Test the case multiple permissions are requested multiple times as follow.
// 1. Permission A and B are requested.
// 2. Permission A is resolved.
// 3. Permission A is requested for a different origin before the B is
// resolved.
TEST_F(AwPermissionManagerTest, ComplicatedRequestScenario2) {
// In the first case, the permission A is a type that does not call an
// internal delegate method.
std::vector<PermissionType> permissions_1 = {PermissionType::MIDI,
PermissionType::MIDI_SYSEX};
int request_1 = manager->RequestPermissions(
permissions_1,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 1));
EXPECT_NE(kNoPendingOperation, request_1);
EXPECT_EQ(0u, resolved_permission_status.size());
int request_2 = manager->RequestPermission(
PermissionType::MIDI, render_frame_host, GURL(kRequestingOrigin2), true,
base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 2));
EXPECT_EQ(kNoPendingOperation, request_2);
ASSERT_EQ(1u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
EXPECT_EQ(2, resolved_permission_request_id[0]);
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, true);
ASSERT_EQ(3u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]);
EXPECT_EQ(1, resolved_permission_request_id[1]);
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[2]);
EXPECT_EQ(1, resolved_permission_request_id[2]);
// In the second case, the permission A is a type that calls an internal
// delegate method.
std::vector<PermissionType> permissions_2 = {PermissionType::GEOLOCATION,
PermissionType::MIDI_SYSEX};
int request_3 = manager->RequestPermissions(
permissions_2,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 3));
EXPECT_NE(kNoPendingOperation, request_3);
ASSERT_EQ(3u, resolved_permission_status.size());
// The permission A is resolved, but the first request isn't finished.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::GEOLOCATION, false);
ASSERT_EQ(3u, resolved_permission_status.size());
// The second request could be resolved synchronously even if the first
// request isn't finished.
manager->EnqueuePermissionResponse(kRequestingOrigin2,
PermissionType::GEOLOCATION, true);
int request_4 = manager->RequestPermission(
PermissionType::GEOLOCATION, render_frame_host, GURL(kRequestingOrigin2),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 4));
EXPECT_EQ(kNoPendingOperation, request_4);
ASSERT_EQ(4u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[3]);
EXPECT_EQ(4, resolved_permission_request_id[3]);
// The first request is finished.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, true);
ASSERT_EQ(6u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[4]);
EXPECT_EQ(3, resolved_permission_request_id[4]);
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[5]);
EXPECT_EQ(3, resolved_permission_request_id[5]);
}
// Test the case multiple permissions are requested multiple times as follow.
// 1. Permission A and B are requested.
// 2. Permission B is resolved.
// 3. Permission A is requested for the same origin before the A is resolved.
TEST_F(AwPermissionManagerTest, ComplicatedRequestScenario3) {
// In the first case, the permission A is a type that does not call an
// internal delegate method.
std::vector<PermissionType> permissions_1 = {PermissionType::MIDI,
PermissionType::MIDI_SYSEX};
int request_1 = manager->RequestPermissions(
permissions_1,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 1));
EXPECT_NE(kNoPendingOperation, request_1);
EXPECT_EQ(0u, resolved_permission_status.size());
int request_2 = manager->RequestPermission(
PermissionType::MIDI_SYSEX, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 2));
EXPECT_NE(kNoPendingOperation, request_2);
EXPECT_EQ(0u, resolved_permission_status.size());
// Resolving the first request results in both requests finished.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, false);
ASSERT_EQ(3u, resolved_permission_status.size());
// Note: The result order in the same requiest is ensured, but each results
// for a request can be swapped because the manager use IDMap to resolve
// matched requests.
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]);
EXPECT_EQ(1, resolved_permission_request_id[1]);
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[2]);
EXPECT_EQ(1, resolved_permission_request_id[2]);
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[0]);
EXPECT_EQ(2, resolved_permission_request_id[0]);
// In the second case, the permission A is a type that calls an internal
// delegate method.
std::vector<PermissionType> permissions_2 = {PermissionType::GEOLOCATION,
PermissionType::MIDI_SYSEX};
int request_3 = manager->RequestPermissions(
permissions_2,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 3));
EXPECT_NE(kNoPendingOperation, request_3);
ASSERT_EQ(3u, resolved_permission_status.size());
// The permission B is resolved, but the first request isn't finished.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::GEOLOCATION, false);
ASSERT_EQ(3u, resolved_permission_status.size());
int request_4 = manager->RequestPermission(
PermissionType::MIDI_SYSEX, render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 4));
EXPECT_NE(kNoPendingOperation, request_4);
ASSERT_EQ(3u, resolved_permission_status.size());
// Resolving the first request results in both requests finished.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, true);
ASSERT_EQ(6u, resolved_permission_status.size());
// Order can be swapped. See Note in ComplicatedRequestScenario1.
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[4]);
EXPECT_EQ(3, resolved_permission_request_id[4]);
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[5]);
EXPECT_EQ(3, resolved_permission_request_id[5]);
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[3]);
EXPECT_EQ(4, resolved_permission_request_id[3]);
}
// Test the case multiple permissions are requested multiple times as follow.
// 1. Permission A and B are requested.
// 2. Permission B is resolved.
// 3. Permission A is requested for a different origin before the A is
// resolved.
TEST_F(AwPermissionManagerTest, ComplicatedRequestScenario4) {
// In the first case, the permission A is a type that does not call an
// internal delegate method.
std::vector<PermissionType> permissions_1 = {PermissionType::MIDI,
PermissionType::MIDI_SYSEX};
int request_1 = manager->RequestPermissions(
permissions_1,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 1));
EXPECT_NE(kNoPendingOperation, request_1);
EXPECT_EQ(0u, resolved_permission_status.size());
int request_2 = manager->RequestPermission(
PermissionType::MIDI_SYSEX, render_frame_host, GURL(kRequestingOrigin2),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 2));
EXPECT_NE(kNoPendingOperation, request_2);
EXPECT_EQ(0u, resolved_permission_status.size());
// The second request could be resolved synchronously even if the first
// request isn't finished.
manager->EnqueuePermissionResponse(kRequestingOrigin2,
PermissionType::MIDI_SYSEX, true);
ASSERT_EQ(1u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[0]);
EXPECT_EQ(2, resolved_permission_request_id[0]);
// The first request is finished.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, false);
ASSERT_EQ(3u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::GRANTED, resolved_permission_status[1]);
EXPECT_EQ(1, resolved_permission_request_id[1]);
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[2]);
EXPECT_EQ(1, resolved_permission_request_id[2]);
// In the second case, the permission A is a type that calls an internal
// delegate method.
std::vector<PermissionType> permissions_2 = {PermissionType::GEOLOCATION,
PermissionType::MIDI_SYSEX};
int request_3 = manager->RequestPermissions(
permissions_2,
render_frame_host, GURL(kRequestingOrigin1),
true, base::Bind(&AwPermissionManagerTest::PermissionsRequestResponse,
base::Unretained(this), 3));
EXPECT_NE(kNoPendingOperation, request_3);
ASSERT_EQ(3u, resolved_permission_status.size());
// The permission B is resolved, but the first request isn't finished.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::GEOLOCATION, false);
ASSERT_EQ(3u, resolved_permission_status.size());
int request_4 = manager->RequestPermission(
PermissionType::MIDI_SYSEX, render_frame_host, GURL(kRequestingOrigin2),
true, base::Bind(&AwPermissionManagerTest::PermissionRequestResponse,
base::Unretained(this), 4));
EXPECT_NE(kNoPendingOperation, request_4);
ASSERT_EQ(3u, resolved_permission_status.size());
// The second request could be resolved synchronously even if the first
// request isn't finished.
manager->EnqueuePermissionResponse(kRequestingOrigin2,
PermissionType::MIDI_SYSEX, false);
ASSERT_EQ(4u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[3]);
EXPECT_EQ(4, resolved_permission_request_id[3]);
// Resolving the first request results in resuming the second request.
manager->EnqueuePermissionResponse(kRequestingOrigin1,
PermissionType::MIDI_SYSEX, false);
ASSERT_EQ(6u, resolved_permission_status.size());
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[4]);
EXPECT_EQ(3, resolved_permission_request_id[4]);
EXPECT_EQ(PermissionStatus::DENIED, resolved_permission_status[5]);
EXPECT_EQ(3, resolved_permission_request_id[5]);
}
} // namespace
} // namespace android_webview