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)