From 097769d43b74ca2d03470617f711dd8c98cc84a5 Mon Sep 17 00:00:00 2001 From: "dennisjeffrey@chromium.org" Date: Thu, 14 Mar 2013 16:09:15 +0000 Subject: [Telemetry] Add tab property "dom_stats". Currently, the associated function reaches into the inspector_backend, which in turn now has a new module to communicate with the remote inspector's "Memory" domain. This allows us to query the remote inspector for the DOM node count, document count, and event listener count, for a tab. Making this change is a prerequisite to converting the Chrome Endure endurance tests over to Telemetry from their current pyauto-based implementation. BUG=chromium-os:39589 TEST=tools/telemetry/run_tests InspectorMemoryTest Review URL: https://chromiumcodereview.appspot.com/12800004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188092 0039d316-1c4b-4281-b951-d872f2087c98 --- .../telemetry/core/chrome/inspector_backend.py | 12 ++++++ .../telemetry/core/chrome/inspector_memory.py | 50 ++++++++++++++++++++++ .../core/chrome/inspector_memory_unittest.py | 21 +++++++++ tools/telemetry/telemetry/core/tab.py | 19 ++++++++ .../unittest_data/dom_counter_sample.html | 12 ++++++ 5 files changed, 114 insertions(+) create mode 100644 tools/telemetry/telemetry/core/chrome/inspector_memory.py create mode 100644 tools/telemetry/telemetry/core/chrome/inspector_memory_unittest.py create mode 100644 tools/telemetry/unittest_data/dom_counter_sample.html (limited to 'tools') diff --git a/tools/telemetry/telemetry/core/chrome/inspector_backend.py b/tools/telemetry/telemetry/core/chrome/inspector_backend.py index 8a5f8b1..ee5c06c 100644 --- a/tools/telemetry/telemetry/core/chrome/inspector_backend.py +++ b/tools/telemetry/telemetry/core/chrome/inspector_backend.py @@ -9,6 +9,7 @@ import sys from telemetry.core import util from telemetry.core import exceptions from telemetry.core.chrome import inspector_console +from telemetry.core.chrome import inspector_memory from telemetry.core.chrome import inspector_page from telemetry.core.chrome import inspector_runtime from telemetry.core.chrome import inspector_timeline @@ -30,6 +31,7 @@ class InspectorBackend(object): self._next_request_id = 0 self._console = inspector_console.InspectorConsole(self) + self._memory = inspector_memory.InspectorMemory(self) self._page = inspector_page.InspectorPage(self) self._runtime = inspector_runtime.InspectorRuntime(self) self._timeline = inspector_timeline.InspectorTimeline(self) @@ -152,6 +154,16 @@ class InspectorBackend(object): def message_output_stream(self, stream): # pylint: disable=E0202 self._console.message_output_stream = stream + # Memory public methods. + + def GetDOMStats(self, timeout): + dom_counters = self._memory.GetDOMCounters(timeout) + return { + 'document_count': dom_counters['documents'], + 'node_count': dom_counters['nodes'], + 'event_listener_count': dom_counters['jsEventListeners'] + } + # Page public methods. def PerformActionAndWaitForNavigate(self, action_function, timeout): diff --git a/tools/telemetry/telemetry/core/chrome/inspector_memory.py b/tools/telemetry/telemetry/core/chrome/inspector_memory.py new file mode 100644 index 0000000..931cb6e --- /dev/null +++ b/tools/telemetry/telemetry/core/chrome/inspector_memory.py @@ -0,0 +1,50 @@ +# Copyright (c) 2013 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. +import json + +class InspectorMemoryException(Exception): + pass + +class InspectorMemory(object): + """Communicates with the remote inspector's Memory domain.""" + + def __init__(self, inspector_backend): + self._inspector_backend = inspector_backend + self._inspector_backend.RegisterDomain( + 'Memory', + self._OnNotification, + self._OnClose) + + def _OnNotification(self, msg): + pass + + def _OnClose(self): + pass + + def GetDOMCounters(self, timeout): + """Retrieves DOM element counts. + + Args: + timeout: The number of seconds to wait for the inspector backend to + service the request before timing out. + + Returns: + A dictionary containing the counts associated with "nodes", "documents", + and "jsEventListeners". + """ + res = self._inspector_backend.SyncRequest({ + 'method': 'Memory.getDOMCounters' + }, timeout) + if ('result' not in res or + 'nodes' not in res['result'] or + 'documents' not in res['result'] or + 'jsEventListeners' not in res['result']): + raise InspectorMemoryException( + 'Inspector returned unexpected result for Memory.getDOMCounters:\n' + + json.dumps(res, indent=2)) + return { + 'nodes': res['result']['nodes'], + 'documents': res['result']['documents'], + 'jsEventListeners': res['result']['jsEventListeners'] + } diff --git a/tools/telemetry/telemetry/core/chrome/inspector_memory_unittest.py b/tools/telemetry/telemetry/core/chrome/inspector_memory_unittest.py new file mode 100644 index 0000000..a84be78 --- /dev/null +++ b/tools/telemetry/telemetry/core/chrome/inspector_memory_unittest.py @@ -0,0 +1,21 @@ +# Copyright (c) 2013 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. +import os + +from telemetry.test import tab_test_case + +class InspectorMemoryTest(tab_test_case.TabTestCase): + def testGetDOMStats(self): + unittest_data_dir = os.path.join(os.path.dirname(__file__), + '..', '..', '..', 'unittest_data') + self._browser.SetHTTPServerDirectory(unittest_data_dir) + + self._tab.Navigate( + self._browser.http_server.UrlOf('dom_counter_sample.html')) + self._tab.WaitForDocumentReadyStateToBeComplete() + + counts = self._tab.dom_stats + self.assertEqual(counts['document_count'], 1) + self.assertEqual(counts['node_count'], 14) + self.assertEqual(counts['event_listener_count'], 2) diff --git a/tools/telemetry/telemetry/core/tab.py b/tools/telemetry/telemetry/core/tab.py index 6e5c804..979b645 100644 --- a/tools/telemetry/telemetry/core/tab.py +++ b/tools/telemetry/telemetry/core/tab.py @@ -31,6 +31,25 @@ class Tab(web_contents.WebContents): def url(self): return self._inspector_backend.url + @property + def dom_stats(self): + """A dictionary populated with measured DOM statistics. + + Currently this dictionary contains: + { + 'document_count': integer, + 'node_count': integer, + 'event_listener_count': integer + } + """ + dom_counters = self._inspector_backend.GetDOMStats( + timeout=DEFAULT_TAB_TIMEOUT) + assert (len(dom_counters) == 3 and + all([x in dom_counters for x in ['document_count', 'node_count', + 'event_listener_count']])) + return dom_counters + + def Activate(self): """Brings this tab to the foreground asynchronously. diff --git a/tools/telemetry/unittest_data/dom_counter_sample.html b/tools/telemetry/unittest_data/dom_counter_sample.html new file mode 100644 index 0000000..483d1e0 --- /dev/null +++ b/tools/telemetry/unittest_data/dom_counter_sample.html @@ -0,0 +1,12 @@ + + DOM counter unit test page + +

Webpage to be used for DOM counter unit testing.

+

+ This webpage is meant to be used by a unit test that checks DOM element + counters. The test expects there to be exactly 1 document, 14 nodes, + and 2 event listeners. Beware, modifying the HTML of this page may + change the element count, causing the unit test to fail! +

+ + -- cgit v1.1