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