github.com/bazelbuild/rules_webtesting@v0.2.0/testing/web/debugger/debugger.py (about) 1 # Copyright 2017 Google Inc. 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 """Web Test Launcher Debugger Front-End.""" 15 16 import code 17 import getpass 18 import hashlib 19 import json 20 import socket 21 import sys 22 import urllib 23 24 25 class Debugger: 26 """Debugger connects to the WTL debugger and sends and receives messages.""" 27 28 def __init__(self, port, host="localhost"): 29 self._conn = socket.create_connection(address=(host, port)) 30 self._file = self._conn.makefile(mode="w") 31 self._decoder = json.JSONDecoder() 32 self._next_id = 1 33 self._buffer = "" 34 35 def _get_next_id(self): 36 id = self._next_id 37 self._next_id = self._next_id + 1 38 return id 39 40 def _read_next(self): 41 while True: 42 try: 43 self._buffer = self._buffer.strip() 44 obj, p = self._decoder.raw_decode(self._buffer) 45 self._buffer = self._buffer[p:] 46 return obj 47 except: 48 pass 49 s = self._conn.recv(4096).decode("utf-8") 50 if s == "": 51 quit() 52 self._buffer = self._buffer + s 53 54 def _read_until_waiting(self): 55 while True: 56 n = self._read_next() 57 print(n) 58 if n["status"] != "running": 59 return 60 61 def step(self): 62 """Execute the waiting WebDriver command and stop at the next one.""" 63 id = self._get_next_id() 64 json.dump(obj={"id": id, "command": "step"}, fp=self._file) 65 self._file.flush() 66 self._read_until_waiting() 67 68 def run(self): 69 """Execute WebDriver commands until a breakpoint is reached.""" 70 id = self._get_next_id() 71 json.dump(obj={"id": id, "command": "continue"}, fp=self._file) 72 self._file.flush() 73 self._read_until_waiting() 74 75 def stop(self): 76 """Quit WTL and the debugger.""" 77 id = self._get_next_id() 78 json.dump(obj={"id": id, "command": "stop"}, fp=self._file) 79 self._file.flush() 80 quit() 81 82 def set_breakpoint(self, path=None, methods=None, body=None): 83 """Set a WTL breakpoint. 84 85 Args: 86 path: string, Go regular expression to compare to WebDriver command 87 paths. 88 methods: list of strings, a list of HTTP methods ("POST", "GET", etc). 89 body: string, Go regular expression to compare to body of WebDriver 90 command. 91 Returns: 92 int, id of the breakpoint (can be used in delete_breakpoint command). 93 """ 94 id = self._get_next_id() 95 96 bp = {"id": id} 97 if path: 98 bp["path"] = path 99 if methods: 100 bp["methods"] = methods 101 if body: 102 bp["body"] = body 103 104 json.dump( 105 obj={ 106 "id": id, 107 "command": "set breakpoint", 108 "breakpoint": bp, 109 }, 110 fp=self._file) 111 self._file.flush() 112 self._read_until_waiting() 113 return id 114 115 def delete_breakpoint(self, breakpoint_id): 116 """Delete a previously set WTL breakpoint. 117 118 Args: 119 breakpoint_id: int, id of the breakpoint to delete. 120 """ 121 id = self._get_next_id() 122 123 json.dump( 124 obj={ 125 "id": id, 126 "command": "delete breakpoint", 127 "breakpoint": { 128 "id": breakpoint_id 129 }, 130 }, 131 fp=self._file) 132 self._file.flush() 133 self._read_until_waiting() 134 135 136 def collect_analytics(): 137 try: 138 urllib.urlopen( 139 "http://www.google-analytics.com/collect?v=1&aip=1&tid=UA-52159295-3" 140 "&t=screenview&cd=start&an=WTL+Debugger&uid=" + 141 hashlib.md5(getpass.getuser()).hexdigest()).close 142 except: 143 # Error collecting usage 144 pass 145 146 147 def main(args): 148 host = "localhost" 149 if len(args) == 2: 150 port = args[1] 151 elif len(args) == 3: 152 host = args[1] 153 port = args[2] 154 else: 155 print("Usage %s [host] port") 156 quit() 157 158 wtl = Debugger(host=host, port=port) 159 160 collect_analytics() 161 162 code.interact( 163 """ 164 \033[95m\033[1mPython Interactive Console\033[0m 165 166 Debugger Commands: 167 wtl.run(): Run test until next WTL breakpoint. 168 wtl.step(): Execute the current waiting command and break at the next one. 169 wtl.stop(): Quit WTL and the Debugger. 170 help(wtl): Additional debugger commands. 171 """, 172 local={"wtl": wtl}) 173 174 175 if __name__ == "__main__": 176 main(sys.argv)