Index: chrome/browser/extensions/api/automation/automation_apitest.cc |
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc |
index e3c1affb4fc48a0b54286dbf300f303dcf2bff62..5f1adcf9b60ffe8636b58a2dd92e1b2686779157 100644 |
--- a/chrome/browser/extensions/api/automation/automation_apitest.cc |
+++ b/chrome/browser/extensions/api/automation/automation_apitest.cc |
@@ -8,13 +8,15 @@ |
#include "base/single_thread_task_runner.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/thread_task_runner_handle.h" |
-#include "chrome/browser/extensions/api/automation_internal/automation_util.h" |
+#include "chrome/browser/accessibility/ax_tree_id_registry.h" |
+#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h" |
#include "chrome/browser/extensions/chrome_extension_function.h" |
#include "chrome/browser/extensions/extension_apitest.h" |
#include "chrome/browser/ui/tabs/tab_strip_model.h" |
#include "chrome/common/chrome_paths.h" |
#include "chrome/common/chrome_switches.h" |
#include "chrome/common/extensions/api/automation_internal.h" |
+#include "chrome/common/extensions/chrome_extension_messages.h" |
#include "chrome/test/base/ui_test_utils.h" |
#include "content/public/browser/ax_event_notification_details.h" |
#include "content/public/browser/render_widget_host.h" |
@@ -99,11 +101,6 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, SanityCheck) { |
<< message_; |
} |
-IN_PROC_BROWSER_TEST_F(AutomationApiTest, Unit) { |
- ASSERT_TRUE(RunExtensionSubtest("automation/tests/unit", "unit.html")) |
- << message_; |
-} |
- |
IN_PROC_BROWSER_TEST_F(AutomationApiTest, GetTreeByTabId) { |
StartEmbeddedTestServer(); |
ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "tab_id.html")) |
@@ -203,10 +200,9 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, Find) { |
<< message_; |
} |
-// Flaky. http://crbug.com/467921 |
-IN_PROC_BROWSER_TEST_F(AutomationApiTest, DISABLED_Mixins) { |
+IN_PROC_BROWSER_TEST_F(AutomationApiTest, Attributes) { |
StartEmbeddedTestServer(); |
- ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "mixins.html")) |
+ ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "attributes.html")) |
<< message_; |
} |
@@ -216,327 +212,4 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, TreeChange) { |
<< message_; |
} |
- |
-static const int kPid = 1; |
-static const int kTab0Rid = 1; |
-static const int kTab1Rid = 2; |
- |
-using content::BrowserContext; |
- |
-typedef ui::AXTreeSerializer<const ui::AXNode*> TreeSerializer; |
-typedef ui::AXTreeSource<const ui::AXNode*> TreeSource; |
- |
-#define AX_EVENT_ASSERT_EQUAL ui::AX_EVENT_LOAD_COMPLETE |
-#define AX_EVENT_ASSERT_NOT_EQUAL ui::AX_EVENT_ACTIVEDESCENDANTCHANGED |
-#define AX_EVENT_IGNORE ui::AX_EVENT_CHILDREN_CHANGED |
-#define AX_EVENT_TEST_COMPLETE ui::AX_EVENT_BLUR |
- |
-// This test is based on ui/accessibility/ax_generated_tree_unittest.cc |
-// However, because the tree updates need to be sent to the extension, we can't |
-// use a straightforward set of nested loops as that test does, so this class |
-// keeps track of where we're up to in our imaginary loops, while the extension |
-// function classes below do the work of actually incrementing the state when |
-// appropriate. |
-// The actual deserialization and comparison happens in the API bindings and the |
-// test extension respectively: see |
-// c/t/data/extensions/api_test/automation/tests/generated/generated_trees.js |
-class TreeSerializationState { |
- public: |
- TreeSerializationState() |
-#ifdef NDEBUG |
- : tree_size(3), |
-#else |
- : tree_size(2), |
-#endif |
- generator(tree_size, true), |
- num_trees(generator.UniqueTreeCount()), |
- tree0_version(0), |
- tree1_version(0) { |
- } |
- |
- // Serializes tree and sends it as an accessibility event to the extension. |
- void SendDataForTree(const ui::AXTree* tree, |
- TreeSerializer* serializer, |
- int routing_id, |
- BrowserContext* browser_context) { |
- ui::AXTreeUpdate update; |
- serializer->SerializeChanges(tree->root(), &update); |
- SendUpdate(update, |
- ui::AX_EVENT_LAYOUT_COMPLETE, |
- tree->root()->id(), |
- routing_id, |
- browser_context); |
- } |
- |
- // Sends the given AXTreeUpdate to the extension as an accessibility event. |
- void SendUpdate(ui::AXTreeUpdate update, |
- ui::AXEvent event, |
- int node_id, |
- int routing_id, |
- BrowserContext* browser_context) { |
- content::AXEventNotificationDetails detail(update.node_id_to_clear, |
- update.nodes, |
- event, |
- node_id, |
- kPid, |
- routing_id); |
- std::vector<content::AXEventNotificationDetails> details; |
- details.push_back(detail); |
- automation_util::DispatchAccessibilityEventsToAutomation( |
- details, browser_context, gfx::Vector2d()); |
- } |
- |
- // Notify the extension bindings to destroy the tree for the given tab |
- // (identified by routing_id) |
- void SendTreeDestroyedEvent(int routing_id, BrowserContext* browser_context) { |
- automation_util::DispatchTreeDestroyedEventToAutomation( |
- kPid, routing_id, browser_context); |
- } |
- |
- // Reset tree0 to a new generated tree based on tree0_version, reset |
- // tree0_source accordingly. |
- void ResetTree0() { |
- tree0.reset(new ui::AXSerializableTree); |
- tree0_source.reset(tree0->CreateTreeSource()); |
- generator.BuildUniqueTree(tree0_version, tree0.get()); |
- if (!serializer0.get()) |
- serializer0.reset(new TreeSerializer(tree0_source.get())); |
- } |
- |
- // Reset tree0, set up serializer0, send down the initial tree data to create |
- // the tree in the extension |
- void InitializeTree0(BrowserContext* browser_context) { |
- ResetTree0(); |
- serializer0->ChangeTreeSourceForTesting(tree0_source.get()); |
- serializer0->Reset(); |
- SendDataForTree(tree0.get(), serializer0.get(), kTab0Rid, browser_context); |
- } |
- |
- // Reset tree1 to a new generated tree based on tree1_version, reset |
- // tree1_source accordingly. |
- void ResetTree1() { |
- tree1.reset(new ui::AXSerializableTree); |
- tree1_source.reset(tree1->CreateTreeSource()); |
- generator.BuildUniqueTree(tree1_version, tree1.get()); |
- if (!serializer1.get()) |
- serializer1.reset(new TreeSerializer(tree1_source.get())); |
- } |
- |
- // Reset tree1, set up serializer1, send down the initial tree data to create |
- // the tree in the extension |
- void InitializeTree1(BrowserContext* browser_context) { |
- ResetTree1(); |
- serializer1->ChangeTreeSourceForTesting(tree1_source.get()); |
- serializer1->Reset(); |
- SendDataForTree(tree1.get(), serializer1.get(), kTab1Rid, browser_context); |
- } |
- |
- const int tree_size; |
- const ui::TreeGenerator generator; |
- |
- // The loop variables: comments indicate which variables in |
- // ax_generated_tree_unittest they correspond to. |
- const int num_trees; // n |
- int tree0_version; // i |
- int tree1_version; // j |
- int starting_node; // k |
- |
- // Tree infrastructure; tree0 and tree1 need to be regenerated whenever |
- // tree0_version and tree1_version change, respectively; tree0_source and |
- // tree1_source need to be reset whenever that happens. |
- scoped_ptr<ui::AXSerializableTree> tree0, tree1; |
- scoped_ptr<TreeSource> tree0_source, tree1_source; |
- scoped_ptr<TreeSerializer> serializer0, serializer1; |
- |
- // Whether tree0 needs to be destroyed after the extension has performed its |
- // checks |
- bool destroy_tree0; |
-}; |
- |
-static TreeSerializationState state; |
- |
-// Override for chrome.automationInternal.enableTab |
-// This fakes out the process and routing IDs for two "tabs", which contain the |
-// source and target trees, respectively, and sends down the current tree for |
-// the requested tab - tab 1 always has tree1, and tab 0 starts with tree0 |
-// and then has a series of updates intended to translate tree0 to tree1. |
-// Once all the updates have been sent, the extension asserts that both trees |
-// are equivalent, and then one or both of the trees are reset to a new version. |
-class FakeAutomationInternalEnableTabFunction |
- : public UIThreadExtensionFunction { |
- public: |
- FakeAutomationInternalEnableTabFunction() {} |
- |
- ExtensionFunction::ResponseAction Run() override { |
- using api::automation_internal::EnableTab::Params; |
- scoped_ptr<Params> params(Params::Create(*args_)); |
- EXTENSION_FUNCTION_VALIDATE(params.get()); |
- if (!params->args.tab_id.get()) |
- return RespondNow(Error("tab_id not specified")); |
- int tab_id = *params->args.tab_id; |
- if (tab_id == 0) { |
- // tab 0 <--> tree0 |
- base::ThreadTaskRunnerHandle::Get()->PostTask( |
- FROM_HERE, base::Bind(&TreeSerializationState::InitializeTree0, |
- base::Unretained(&state), |
- base::Unretained(browser_context()))); |
- // TODO(aboxhall): Need to rewrite this test in terms of tree ids. |
- return RespondNow(ArgumentList( |
- api::automation_internal::EnableTab::Results::Create(0))); |
- } |
- if (tab_id == 1) { |
- // tab 1 <--> tree1 |
- base::ThreadTaskRunnerHandle::Get()->PostTask( |
- FROM_HERE, base::Bind(&TreeSerializationState::InitializeTree1, |
- base::Unretained(&state), |
- base::Unretained(browser_context()))); |
- return RespondNow(ArgumentList( |
- api::automation_internal::EnableTab::Results::Create(0))); |
- } |
- return RespondNow(Error("Unrecognised tab_id")); |
- } |
-}; |
- |
-// Factory method for use in OverrideFunction() |
-ExtensionFunction* FakeAutomationInternalEnableTabFunctionFactory() { |
- return new FakeAutomationInternalEnableTabFunction(); |
-} |
- |
-// Helper method to serialize a series of updates via source_serializer to |
-// transform the tree which source_serializer was initialized from into |
-// target_tree, and then trigger the test code to assert the two tabs contain |
-// the same tree. |
-void TransformTree(TreeSerializer* source_serializer, |
- ui::AXTree* target_tree, |
- TreeSource* target_tree_source, |
- content::BrowserContext* browser_context) { |
- source_serializer->ChangeTreeSourceForTesting(target_tree_source); |
- for (int node_delta = 0; node_delta < state.tree_size; ++node_delta) { |
- int id = 1 + (state.starting_node + node_delta) % state.tree_size; |
- ui::AXTreeUpdate update; |
- source_serializer->SerializeChanges(target_tree->GetFromId(id), &update); |
- bool is_last_update = node_delta == state.tree_size - 1; |
- ui::AXEvent event = |
- is_last_update ? AX_EVENT_ASSERT_EQUAL : AX_EVENT_IGNORE; |
- state.SendUpdate( |
- update, event, target_tree->root()->id(), kTab0Rid, browser_context); |
- } |
-} |
- |
-// Helper method to send a no-op tree update to tab 0 with the given event. |
-void SendEvent(ui::AXEvent event, content::BrowserContext* browser_context) { |
- ui::AXTreeUpdate update; |
- ui::AXNode* root = state.tree0->root(); |
- state.serializer0->SerializeChanges(root, &update); |
- state.SendUpdate(update, event, root->id(), kTab0Rid, browser_context); |
-} |
- |
-// Override for chrome.automationInternal.performAction |
-// This is used as a synchronization mechanism; the general flow is: |
-// 1. The extension requests tree0 and tree1 (on tab 0 and tab 1 respectively) |
-// 2. FakeAutomationInternalEnableTabFunction sends down the trees |
-// 3. When the callback for getTree(0) fires, the extension calls doDefault() on |
-// the root node of tree0, which calls into this class's Run() method. |
-// 4. In the normal case, we're in the "inner loop" (iterating over |
-// starting_node). For each value of starting_node, we do the following: |
-// a. Serialize a sequence of updates which should transform tree0 into |
-// tree1. Each of these updates is sent as a childrenChanged event, |
-// except for the last which is sent as a loadComplete event. |
-// b. state.destroy_tree0 is set to true |
-// c. state.starting_node gets incremented |
-// d. The loadComplete event triggers an assertion in the extension. |
-// e. The extension performs another doDefault() on the root node of the |
-// tree. |
-// f. This time, we send a destroy event to tab0, so that the tree can be |
-// reset. |
-// g. The extension is notified of the tree's destruction and requests the |
-// tree for tab 0 again, returning to step 2. |
-// 5. When starting_node exceeds state.tree_size, we increment tree0_version if |
-// it would not exceed state.num_trees, or increment tree1_version and reset |
-// tree0_version to 0 otherwise, and reset starting_node to 0. |
-// Then we reset one or both trees as appropriate, and send down destroyed |
-// events similarly, causing the extension to re-request the tree and going |
-// back to step 2 again. |
-// 6. When tree1_version has gone through all possible values, we send a blur |
-// event, signaling the extension to call chrome.test.succeed() and finish |
-// the test. |
-class FakeAutomationInternalPerformActionFunction |
- : public UIThreadExtensionFunction { |
- public: |
- FakeAutomationInternalPerformActionFunction() {} |
- |
- ExtensionFunction::ResponseAction Run() override { |
- if (state.destroy_tree0) { |
- // Step 4.f: tell the extension to destroy the tree and re-request it. |
- state.SendTreeDestroyedEvent(kTab0Rid, browser_context()); |
- state.destroy_tree0 = false; |
- return RespondNow(NoArguments()); |
- } |
- |
- TreeSerializer* serializer0 = state.serializer0.get(); |
- if (state.starting_node < state.tree_size) { |
- // As a sanity check, if the trees are not equal, assert that they are not |
- // equal before serializing changes. |
- if (state.tree0_version != state.tree1_version) |
- SendEvent(AX_EVENT_ASSERT_NOT_EQUAL, browser_context()); |
- |
- // Step 4.a: pretend that tree0 turned into tree1, and serialize |
- // a sequence of updates to tab 0 to match. |
- TransformTree(serializer0, |
- state.tree1.get(), |
- state.tree1_source.get(), |
- browser_context()); |
- |
- // Step 4.b: remember that we need to tell the extension to destroy and |
- // re-request the tree on the next action. |
- state.destroy_tree0 = true; |
- |
- // Step 4.c: increment starting_node. |
- state.starting_node++; |
- } else if (state.tree0_version < state.num_trees - 1) { |
- // Step 5: Increment tree0_version and reset starting_node |
- state.tree0_version++; |
- state.starting_node = 0; |
- |
- // Step 5: Reset tree0 and tell the extension to destroy and re-request it |
- state.SendTreeDestroyedEvent(kTab0Rid, browser_context()); |
- } else if (state.tree1_version < state.num_trees - 1) { |
- // Step 5: Increment tree1_version and reset tree0_version and |
- // starting_node |
- state.tree1_version++; |
- state.tree0_version = 0; |
- state.starting_node = 0; |
- |
- // Step 5: Reset tree0 and tell the extension to destroy and re-request it |
- state.SendTreeDestroyedEvent(kTab0Rid, browser_context()); |
- |
- // Step 5: Reset tree1 and tell the extension to destroy and re-request it |
- state.SendTreeDestroyedEvent(kTab1Rid, browser_context()); |
- } else { |
- // Step 6: Send a TEST_COMPLETE (blur) event to signal the extension to |
- // call chrome.test.succeed(). |
- SendEvent(AX_EVENT_TEST_COMPLETE, browser_context()); |
- } |
- |
- return RespondNow(NoArguments()); |
- } |
-}; |
- |
-// Factory method for use in OverrideFunction() |
-ExtensionFunction* FakeAutomationInternalPerformActionFunctionFactory() { |
- return new FakeAutomationInternalPerformActionFunction(); |
-} |
- |
-// http://crbug.com/396353 |
-IN_PROC_BROWSER_TEST_F(AutomationApiTest, DISABLED_GeneratedTree) { |
- ASSERT_TRUE(extensions::ExtensionFunctionDispatcher::OverrideFunction( |
- "automationInternal.enableTab", |
- FakeAutomationInternalEnableTabFunctionFactory)); |
- ASSERT_TRUE(extensions::ExtensionFunctionDispatcher::OverrideFunction( |
- "automationInternal.performAction", |
- FakeAutomationInternalPerformActionFunctionFactory)); |
- ASSERT_TRUE(RunExtensionSubtest("automation/tests/generated", |
- "generated_trees.html")) << message_; |
-} |
- |
} // namespace extensions |