Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: chrome/test/pyautolib/remote_inspector_client.py

Issue 10332289: Add RemoteInspectorClient.EvaluateJavascript to run javascript over the remote inspector protocl (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Chrome remote inspector utility for pyauto tests. 6 """Chrome remote inspector utility for pyauto tests.
7 7
8 This script provides a python interface that acts as a front-end for Chrome's 8 This script provides a python interface that acts as a front-end for Chrome's
9 remote inspector module, communicating via sockets to interact with Chrome in 9 remote inspector module, communicating via sockets to interact with Chrome in
10 the same way that the Developer Tools does. This -- in theory -- should allow 10 the same way that the Developer Tools does. This -- in theory -- should allow
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 Public Attributes: 63 Public Attributes:
64 method: The string method name associated with this request. 64 method: The string method name associated with this request.
65 id: A unique integer id associated with this request. 65 id: A unique integer id associated with this request.
66 params: A dictionary of input parameters associated with this request. 66 params: A dictionary of input parameters associated with this request.
67 results: A dictionary of relevant results obtained from the remote Chrome 67 results: A dictionary of relevant results obtained from the remote Chrome
68 instance that are associated with this request. 68 instance that are associated with this request.
69 is_fulfilled: A boolean indicating whether or not this request has been sent 69 is_fulfilled: A boolean indicating whether or not this request has been sent
70 and all relevant results for it have been obtained (i.e., this value is 70 and all relevant results for it have been obtained (i.e., this value is
71 True only if all results for this request are known). 71 True only if all results for this request are known).
72 """ 72 """
73 def __init__(self, method, message_id): 73 def __init__(self, method, params, message_id):
74 """Initialize. 74 """Initialize.
75 75
76 Args: 76 Args:
77 method: The string method name for this request. 77 method: The string method name for this request.
78 message_id: An integer id for this request, which is assumed to be unique 78 message_id: An integer id for this request, which is assumed to be unique
79 from among all requests. 79 from among all requests.
80 """ 80 """
81 self.method = method 81 self.method = method
82 self.id = message_id 82 self.id = message_id
83 self.params = {} 83 self.params = params
84 self.results = {} 84 self.results = {}
85 self.is_fulfilled = False 85 self.is_fulfilled = False
86 86
87 def __repr__(self): 87 def __repr__(self):
88 json_dict = {} 88 json_dict = {}
89 json_dict['method'] = self.method 89 json_dict['method'] = self.method
90 json_dict['id'] = self.id 90 json_dict['id'] = self.id
91 if self.params: 91 if self.params:
92 json_dict['params'] = self.params 92 json_dict['params'] = self.params
93 return simplejson.dumps(json_dict, separators=(',', ':')) 93 return simplejson.dumps(json_dict, separators=(',', ':'))
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 """Start this thread; overridden from threading.Thread.""" 326 """Start this thread; overridden from threading.Thread."""
327 while not self._killed: 327 while not self._killed:
328 if self._action_queue: 328 if self._action_queue:
329 # There's a request to the remote inspector that needs to be processed. 329 # There's a request to the remote inspector that needs to be processed.
330 messages, callback = self._action_queue.pop(0) 330 messages, callback = self._action_queue.pop(0)
331 self._action_specific_callback = callback 331 self._action_specific_callback = callback
332 332
333 # Prepare the request list. 333 # Prepare the request list.
334 for message_id, message in enumerate(messages): 334 for message_id, message in enumerate(messages):
335 self._requests.append( 335 self._requests.append(
336 _DevToolsSocketRequest(message, message_id)) 336 _DevToolsSocketRequest(message[0], message[1], message_id))
337 337
338 # Send out each request. Wait until each request is complete before 338 # Send out each request. Wait until each request is complete before
339 # sending the next request. 339 # sending the next request.
340 for request in self._requests: 340 for request in self._requests:
341 self._FillInParams(request) 341 self._FillInParams(request)
342 self._client.SendMessage(str(request)) 342 self._client.SendMessage(str(request))
343 while not request.is_fulfilled: 343 while not request.is_fulfilled:
344 if self._killed: 344 if self._killed:
345 self._client.close() 345 self._client.close()
346 return 346 return
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after
724 { 724 {
725 'url': string, # URL of the webpage that was snapshotted. 725 'url': string, # URL of the webpage that was snapshotted.
726 'raw_data': string, # The raw data as JSON string. 726 'raw_data': string, # The raw data as JSON string.
727 'total_v8_node_count': integer, # Total number of nodes in the v8 heap. 727 'total_v8_node_count': integer, # Total number of nodes in the v8 heap.
728 # Only if |include_summary| is True. 728 # Only if |include_summary| is True.
729 'total_heap_size': integer, # Total v8 heap size (number of bytes). 729 'total_heap_size': integer, # Total v8 heap size (number of bytes).
730 # Only if |include_summary| is True. 730 # Only if |include_summary| is True.
731 } 731 }
732 """ 732 """
733 HEAP_SNAPSHOT_MESSAGES = [ 733 HEAP_SNAPSHOT_MESSAGES = [
734 'Page.getResourceTree', 734 ('Page.getResourceTree', {}),
735 'Debugger.enable', 735 ('Debugger.enable', {}),
736 'Profiler.clearProfiles', 736 ('Profiler.clearProfiles', {}),
737 'Profiler.takeHeapSnapshot', 737 ('Profiler.takeHeapSnapshot', {}),
738 'Profiler.getProfile', 738 ('Profiler.getProfile', {}),
739 ] 739 ]
740 740
741 self._current_heap_snapshot = [] 741 self._current_heap_snapshot = []
742 self._url = '' 742 self._url = ''
743 self._collected_heap_snapshot_data = {} 743 self._collected_heap_snapshot_data = {}
744 744
745 def HandleReply(reply_dict): 745 def HandleReply(reply_dict):
746 """Processes a reply message received from the remote Chrome instance. 746 """Processes a reply message received from the remote Chrome instance.
747 747
748 Args: 748 Args:
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
790 self._collected_heap_snapshot_data['total_heap_size'] = total_size 790 self._collected_heap_snapshot_data['total_heap_size'] = total_size
791 791
792 # Tell the remote inspector to take a v8 heap snapshot, then wait until 792 # Tell the remote inspector to take a v8 heap snapshot, then wait until
793 # the snapshot information is available to return. 793 # the snapshot information is available to return.
794 self._remote_inspector_thread.PerformAction(HEAP_SNAPSHOT_MESSAGES, 794 self._remote_inspector_thread.PerformAction(HEAP_SNAPSHOT_MESSAGES,
795 HandleReply) 795 HandleReply)
796 while not self._collected_heap_snapshot_data: 796 while not self._collected_heap_snapshot_data:
797 time.sleep(0.1) 797 time.sleep(0.1)
798 return self._collected_heap_snapshot_data 798 return self._collected_heap_snapshot_data
799 799
800 def EvaluateJavaScript(self, expression):
801 """Evaluates a JavaScript expression and returns the result.
802
803 Sends a message containing the expression to the remote Chrome instance we
804 are connected to, and evaluates it in the context of the tab we are
805 connected to. Blocks until the result is available and returns it.
806
807 Returns:
808 A dictionary representing the result.
dennis_jeffrey 2012/05/22 17:14:05 Is there a standard format for the result dictiona
jochen (gone - plz use gerrit) 2012/05/23 08:20:48 not really. It depends on what the expression eval
809 """
810 EVALUATE_MESSAGES = [
811 ('Runtime.evaluate', { 'expression': expression,
812 'objectGroup': 'group',
813 'returnByValue': True }),
814 ('Runtime.releaseObjectGroup', { 'objectGroup': 'group' })
815 ]
816
817 self._result = None
818 self._got_result = False
819
820 def HandleReply(reply_dict):
821 """Processes a reply message received from the remote Chrome instance.
822
823 Args:
824 reply_dict: A dictionary object representing the reply message received
825 from the remote Chrome instance.
826 """
827 if 'result' in reply_dict and 'result' in reply_dict['result']:
828 self._result = reply_dict['result']['result']['value']
829 self._got_result = True
830
831 # Tell the remote inspector to evaluate the given expression, then wait
832 # until that information is available to return.
833 self._remote_inspector_thread.PerformAction(EVALUATE_MESSAGES,
834 HandleReply)
835 while not self._got_result:
836 time.sleep(0.1)
837 return self._result
838
800 def GetMemoryObjectCounts(self): 839 def GetMemoryObjectCounts(self):
801 """Retrieves memory object count information. 840 """Retrieves memory object count information.
802 841
803 Returns: 842 Returns:
804 A dictionary containing the memory object count information: 843 A dictionary containing the memory object count information:
805 { 844 {
806 'DOMNodeCount': integer, # Total number of DOM nodes. 845 'DOMNodeCount': integer, # Total number of DOM nodes.
807 'EventListenerCount': integer, # Total number of event listeners. 846 'EventListenerCount': integer, # Total number of event listeners.
808 } 847 }
809 """ 848 """
810 MEMORY_COUNT_MESSAGES = [ 849 MEMORY_COUNT_MESSAGES = [
811 'Memory.getDOMNodeCount', 850 ('Memory.getDOMNodeCount', {})
812 ] 851 ]
813 852
814 self._event_listener_count = None 853 self._event_listener_count = None
815 self._dom_node_count = None 854 self._dom_node_count = None
816 855
817 def HandleReply(reply_dict): 856 def HandleReply(reply_dict):
818 """Processes a reply message received from the remote Chrome instance. 857 """Processes a reply message received from the remote Chrome instance.
819 858
820 Args: 859 Args:
821 reply_dict: A dictionary object representing the reply message received 860 reply_dict: A dictionary object representing the reply message received
(...skipping 20 matching lines...) Expand all
842 while not self._event_listener_count or not self._dom_node_count: 881 while not self._event_listener_count or not self._dom_node_count:
843 time.sleep(0.1) 882 time.sleep(0.1)
844 return { 883 return {
845 'DOMNodeCount': self._dom_node_count, 884 'DOMNodeCount': self._dom_node_count,
846 'EventListenerCount': self._event_listener_count, 885 'EventListenerCount': self._event_listener_count,
847 } 886 }
848 887
849 def CollectGarbage(self): 888 def CollectGarbage(self):
850 """Forces a garbage collection.""" 889 """Forces a garbage collection."""
851 COLLECT_GARBAGE_MESSAGES = [ 890 COLLECT_GARBAGE_MESSAGES = [
852 'Profiler.collectGarbage', 891 ('Profiler.collectGarbage', {})
853 ] 892 ]
854 893
855 # Tell the remote inspector to do a garbage collect. We can return 894 # Tell the remote inspector to do a garbage collect. We can return
856 # immediately, since there is no result for which to wait. 895 # immediately, since there is no result for which to wait.
857 self._remote_inspector_thread.PerformAction(COLLECT_GARBAGE_MESSAGES, None) 896 self._remote_inspector_thread.PerformAction(COLLECT_GARBAGE_MESSAGES, None)
858 897
859 def StartTimelineEventMonitoring(self, event_callback): 898 def StartTimelineEventMonitoring(self, event_callback):
860 """Starts timeline event monitoring. 899 """Starts timeline event monitoring.
861 900
862 Args: 901 Args:
863 event_callback: A callable to invoke whenever a timeline event is observed 902 event_callback: A callable to invoke whenever a timeline event is observed
864 from the remote inspector. The callable should take a single input, 903 from the remote inspector. The callable should take a single input,
865 which is a dictionary containing the detailed information of a 904 which is a dictionary containing the detailed information of a
866 timeline event. 905 timeline event.
867 """ 906 """
868 if self._timeline_started: 907 if self._timeline_started:
869 self._logger.warning('Timeline monitoring already started.') 908 self._logger.warning('Timeline monitoring already started.')
870 return 909 return
871 TIMELINE_MESSAGES = [ 910 TIMELINE_MESSAGES = [
872 'Timeline.start', 911 ('Timeline.start', {})
873 ] 912 ]
874 913
875 self._event_callback = event_callback 914 self._event_callback = event_callback
876 915
877 def HandleReply(reply_dict): 916 def HandleReply(reply_dict):
878 """Processes a reply message received from the remote Chrome instance. 917 """Processes a reply message received from the remote Chrome instance.
879 918
880 Args: 919 Args:
881 reply_dict: A dictionary object representing the reply message received 920 reply_dict: A dictionary object representing the reply message received
882 from the remote Chrome instance. 921 from the remote Chrome instance.
883 """ 922 """
884 if reply_dict.get('method') == 'Timeline.eventRecorded': 923 if reply_dict.get('method') == 'Timeline.eventRecorded':
885 self._event_callback(reply_dict['params']['record']) 924 self._event_callback(reply_dict['params']['record'])
886 925
887 # Tell the remote inspector to start the timeline. We can return 926 # Tell the remote inspector to start the timeline. We can return
888 # immediately, since there is no result for which to wait. 927 # immediately, since there is no result for which to wait.
889 self._timeline_callback = HandleReply 928 self._timeline_callback = HandleReply
890 self._remote_inspector_thread.AddMessageCallback(self._timeline_callback) 929 self._remote_inspector_thread.AddMessageCallback(self._timeline_callback)
891 self._remote_inspector_thread.PerformAction(TIMELINE_MESSAGES, None) 930 self._remote_inspector_thread.PerformAction(TIMELINE_MESSAGES, None)
892 self._timeline_started = True 931 self._timeline_started = True
893 932
894 def StopTimelineEventMonitoring(self): 933 def StopTimelineEventMonitoring(self):
895 """Stops timeline event monitoring.""" 934 """Stops timeline event monitoring."""
896 if not self._timeline_started: 935 if not self._timeline_started:
897 self._logger.warning('Timeline monitoring already stopped.') 936 self._logger.warning('Timeline monitoring already stopped.')
898 return 937 return
899 TIMELINE_MESSAGES = [ 938 TIMELINE_MESSAGES = [
900 'Timeline.stop', 939 ('Timeline.stop', {})
901 ] 940 ]
902 941
903 # Tell the remote inspector to stop the timeline. We can return 942 # Tell the remote inspector to stop the timeline. We can return
904 # immediately, since there is no result for which to wait. 943 # immediately, since there is no result for which to wait.
905 self._remote_inspector_thread.RemoveMessageCallback(self._timeline_callback) 944 self._remote_inspector_thread.RemoveMessageCallback(self._timeline_callback)
906 self._remote_inspector_thread.PerformAction(TIMELINE_MESSAGES, None) 945 self._remote_inspector_thread.PerformAction(TIMELINE_MESSAGES, None)
907 self._timeline_started = False 946 self._timeline_started = False
908 947
909 def _ConvertByteCountToHumanReadableString(self, num_bytes): 948 def _ConvertByteCountToHumanReadableString(self, num_bytes):
910 """Converts an integer number of bytes into a human-readable string. 949 """Converts an integer number of bytes into a human-readable string.
911 950
912 Args: 951 Args:
913 num_bytes: An integer number of bytes. 952 num_bytes: An integer number of bytes.
914 953
915 Returns: 954 Returns:
916 A human-readable string representation of the given number of bytes. 955 A human-readable string representation of the given number of bytes.
917 """ 956 """
918 if num_bytes < 1024: 957 if num_bytes < 1024:
919 return '%d B' % num_bytes 958 return '%d B' % num_bytes
920 elif num_bytes < 1048576: 959 elif num_bytes < 1048576:
921 return '%.2f KB' % (num_bytes / 1024.0) 960 return '%.2f KB' % (num_bytes / 1024.0)
922 else: 961 else:
923 return '%.2f MB' % (num_bytes / 1048576.0) 962 return '%.2f MB' % (num_bytes / 1048576.0)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698