[Extensions] Add user gesture tests for extension bindings

There's some churn going on with extension bindings (to native bindings)
and user gestures (to UAv2). Add two end-to-end bindings tests to expand
our coverage:
- Test that extension messages "pass" the user gesture to the receiver;
  that is, if a user gesture is active when a message is created, it
  should be active on the receiving end as well.
- Test that extension API callbacks are invoked with an active user
  gesture iff the API is invoked when a gesture is active.

Bug: None

Change-Id: I7d4036356bd20fd00c0774210b2019287413e30c
Reviewed-on: https://chromium-review.googlesource.com/1217166
Reviewed-by: Istiaque Ahmed <[email protected]>
Commit-Queue: Devlin <[email protected]>
Cr-Commit-Position: refs/heads/master@{#590162}
diff --git a/chrome/browser/extensions/extension_bindings_apitest.cc b/chrome/browser/extensions/extension_bindings_apitest.cc
index 0edc7f8..607a611 100644
--- a/chrome/browser/extensions/extension_bindings_apitest.cc
+++ b/chrome/browser/extensions/extension_bindings_apitest.cc
@@ -524,6 +524,119 @@
   EXPECT_EQ(SessionTabHelper::IdForTab(new_tab).id(), result_tab_id);
 }
 
+// Verifies that user gestures are carried through extension messages.
+IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
+                       UserGestureFromExtensionMessageTest) {
+  TestExtensionDir test_dir;
+  test_dir.WriteManifest(
+      R"({
+           "name": "User Gesture Content Script",
+           "manifest_version": 2,
+           "version": "0.1",
+           "background": { "scripts": ["background.js"] },
+           "content_scripts": [{
+             "matches": ["*://*.example.com:*/*"],
+             "js": ["content_script.js"],
+             "run_at": "document_end"
+           }]
+         })");
+  test_dir.WriteFile(FILE_PATH_LITERAL("content_script.js"),
+                     R"(const button = document.getElementById('go-button');
+                        button.addEventListener('click', () => {
+                          chrome.runtime.sendMessage('clicked');
+                        });)");
+  test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
+                     R"(chrome.runtime.onMessage.addListener((message) => {
+                        chrome.test.sendMessage(
+                            'Clicked: ' +
+                            chrome.test.isProcessingUserGesture());
+                        });)");
+
+  const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+  ASSERT_TRUE(extension);
+
+  const GURL url = embedded_test_server()->GetURL(
+      "example.com", "/extensions/page_with_button.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  content::WebContents* tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  {
+    // Passing a message without an active user gesture shouldn't result in a
+    // gesture being active on the receiving end.
+    ExtensionTestMessageListener listener(false);
+    content::EvalJsResult result =
+        content::EvalJs(tab, "document.getElementById('go-button').click()",
+                        content::EXECUTE_SCRIPT_NO_USER_GESTURE);
+    EXPECT_TRUE(result.value.is_none());
+
+    EXPECT_TRUE(listener.WaitUntilSatisfied());
+    EXPECT_EQ("Clicked: false", listener.message());
+  }
+
+  {
+    // If there is an active user gesture when the message is sent, we should
+    // synthesize a user gesture on the receiving end.
+    ExtensionTestMessageListener listener(false);
+    content::EvalJsResult result =
+        content::EvalJs(tab, "document.getElementById('go-button').click()");
+    EXPECT_TRUE(result.value.is_none());
+
+    EXPECT_TRUE(listener.WaitUntilSatisfied());
+    EXPECT_EQ("Clicked: true", listener.message());
+  }
+}
+
+// Verifies that user gestures from API calls are active when the callback is
+// triggered.
+IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
+                       UserGestureInExtensionAPICallback) {
+  TestExtensionDir test_dir;
+  test_dir.WriteManifest(
+      R"({
+           "name": "User Gesture Extension API Callback",
+           "manifest_version": 2,
+           "version": "0.1"
+         })");
+  test_dir.WriteFile(FILE_PATH_LITERAL("page.html"), "<html></html>");
+
+  const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+  ASSERT_TRUE(extension);
+
+  const GURL extension_page = extension->GetResourceURL("page.html");
+  ui_test_utils::NavigateToURL(browser(), extension_page);
+
+  content::WebContents* tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  constexpr char kScript[] =
+      R"(chrome.tabs.query({}, (tabs) => {
+           let message;
+           if (chrome.runtime.lastError)
+             message = 'Unexpected error: ' + chrome.runtime.lastError;
+           else
+             message = 'Has gesture: ' + chrome.test.isProcessingUserGesture();
+           domAutomationController.send(message);
+         });)";
+
+  {
+    // Triggering an API without an active gesture shouldn't result in a
+    // gesture in the callback.
+    std::string message;
+    EXPECT_TRUE(content::ExecuteScriptWithoutUserGestureAndExtractString(
+        tab, kScript, &message));
+    EXPECT_EQ("Has gesture: false", message);
+  }
+  {
+    // If there was an active gesture at the time of the API call, there should
+    // be an active gesture in the callback.
+    std::string message;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(tab, kScript, &message));
+    EXPECT_EQ("Has gesture: true", message);
+  }
+}
+
 // Run core bindings API tests with both native and JS-based bindings. This
 // ensures we have some minimum level of coverage while in the experimental
 // phase, when native bindings may be enabled on trunk but not at 100% stable.