| // 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 |