tools: Remove unused dev tools
This commit is contained in:
parent
413d539a7b
commit
4758a0ac12
@ -27,48 +27,6 @@ code. So, if you're out of work, the code coverage and flake8 data at the CI
|
|||||||
server should give you a place to start.
|
server should give you a place to start.
|
||||||
|
|
||||||
|
|
||||||
Protocol debugger
|
|
||||||
=================
|
|
||||||
|
|
||||||
Since the main interface provided to Mopidy is through the MPD protocol, it is
|
|
||||||
crucial that we try and stay in sync with protocol developments. In an attempt
|
|
||||||
to make it easier to debug differences Mopidy and MPD protocol handling we have
|
|
||||||
created ``tools/debug-proxy.py``.
|
|
||||||
|
|
||||||
This tool is proxy that sits in front of two MPD protocol aware servers and
|
|
||||||
sends all requests to both, returning the primary response to the client and
|
|
||||||
then printing any diff in the two responses.
|
|
||||||
|
|
||||||
Note that this tool depends on ``gevent`` unlike the rest of Mopidy at the time
|
|
||||||
of writing. See :option:`tools/debug-proxy.py --help` for available options.
|
|
||||||
Sample session::
|
|
||||||
|
|
||||||
[127.0.0.1]:59714
|
|
||||||
listallinfo
|
|
||||||
--- Reference response
|
|
||||||
+++ Actual response
|
|
||||||
@@ -1,16 +1,1 @@
|
|
||||||
-file: uri1
|
|
||||||
-Time: 4
|
|
||||||
-Artist: artist1
|
|
||||||
-Title: track1
|
|
||||||
-Album: album1
|
|
||||||
-file: uri2
|
|
||||||
-Time: 4
|
|
||||||
-Artist: artist2
|
|
||||||
-Title: track2
|
|
||||||
-Album: album2
|
|
||||||
-file: uri3
|
|
||||||
-Time: 4
|
|
||||||
-Artist: artist3
|
|
||||||
-Title: track3
|
|
||||||
-Album: album3
|
|
||||||
-OK
|
|
||||||
+ACK [2@0] {listallinfo} incorrect arguments
|
|
||||||
|
|
||||||
To ensure that Mopidy and MPD have comparable state it is suggested you scan
|
|
||||||
the same media directory with both servers.
|
|
||||||
|
|
||||||
Documentation writing
|
Documentation writing
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
|||||||
@ -1,195 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import difflib
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from gevent import select, server, socket
|
|
||||||
|
|
||||||
COLORS = ['\033[1;%dm' % (30 + i) for i in range(8)]
|
|
||||||
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = COLORS
|
|
||||||
RESET = "\033[0m"
|
|
||||||
BOLD = "\033[1m"
|
|
||||||
|
|
||||||
|
|
||||||
def proxy(client, address, reference_address, actual_address):
|
|
||||||
"""Main handler code that gets called for each connection."""
|
|
||||||
client.setblocking(False)
|
|
||||||
|
|
||||||
reference = connect(reference_address)
|
|
||||||
actual = connect(actual_address)
|
|
||||||
|
|
||||||
if reference and actual:
|
|
||||||
loop(client, address, reference, actual)
|
|
||||||
else:
|
|
||||||
print 'Could not connect to one of the backends.'
|
|
||||||
|
|
||||||
for sock in (client, reference, actual):
|
|
||||||
close(sock)
|
|
||||||
|
|
||||||
|
|
||||||
def connect(address):
|
|
||||||
"""Connect to given address and set socket non blocking."""
|
|
||||||
try:
|
|
||||||
sock = socket.socket()
|
|
||||||
sock.connect(address)
|
|
||||||
sock.setblocking(False)
|
|
||||||
except socket.error:
|
|
||||||
return None
|
|
||||||
return sock
|
|
||||||
|
|
||||||
|
|
||||||
def close(sock):
|
|
||||||
"""Shutdown and close our sockets."""
|
|
||||||
try:
|
|
||||||
sock.shutdown(socket.SHUT_WR)
|
|
||||||
sock.close()
|
|
||||||
except socket.error:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def loop(client, address, reference, actual):
|
|
||||||
"""Loop that handles one MPD reqeust/response pair per iteration."""
|
|
||||||
|
|
||||||
# Consume banners from backends
|
|
||||||
responses = dict()
|
|
||||||
disconnected = read(
|
|
||||||
[reference, actual], responses, find_response_end_token)
|
|
||||||
diff(address, '', responses[reference], responses[actual])
|
|
||||||
|
|
||||||
# We lost a backend, might as well give up.
|
|
||||||
if disconnected:
|
|
||||||
return
|
|
||||||
|
|
||||||
client.sendall(responses[reference])
|
|
||||||
|
|
||||||
while True:
|
|
||||||
responses = dict()
|
|
||||||
|
|
||||||
# Get the command from the client. Not sure how an if this will handle
|
|
||||||
# client sending multiple commands currently :/
|
|
||||||
disconnected = read([client], responses, find_request_end_token)
|
|
||||||
|
|
||||||
# We lost the client, might as well give up.
|
|
||||||
if disconnected:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Send the entire command to both backends.
|
|
||||||
reference.sendall(responses[client])
|
|
||||||
actual.sendall(responses[client])
|
|
||||||
|
|
||||||
# Get the entire resonse from both backends.
|
|
||||||
disconnected = read(
|
|
||||||
[reference, actual], responses, find_response_end_token)
|
|
||||||
|
|
||||||
# Send the client the complete reference response
|
|
||||||
client.sendall(responses[reference])
|
|
||||||
|
|
||||||
# Compare our responses
|
|
||||||
diff(address,
|
|
||||||
responses[client], responses[reference], responses[actual])
|
|
||||||
|
|
||||||
# Give up if we lost a backend.
|
|
||||||
if disconnected:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def read(sockets, responses, find_end_token):
|
|
||||||
"""Keep reading from sockets until they disconnet or we find our token."""
|
|
||||||
|
|
||||||
# This function doesn't go to well with idle when backends are out of sync.
|
|
||||||
disconnected = False
|
|
||||||
|
|
||||||
for sock in sockets:
|
|
||||||
responses.setdefault(sock, '')
|
|
||||||
|
|
||||||
while sockets:
|
|
||||||
for sock in select.select(sockets, [], [])[0]:
|
|
||||||
data = sock.recv(4096)
|
|
||||||
responses[sock] += data
|
|
||||||
|
|
||||||
if find_end_token(responses[sock]):
|
|
||||||
sockets.remove(sock)
|
|
||||||
|
|
||||||
if not data:
|
|
||||||
sockets.remove(sock)
|
|
||||||
disconnected = True
|
|
||||||
|
|
||||||
return disconnected
|
|
||||||
|
|
||||||
|
|
||||||
def find_response_end_token(data):
|
|
||||||
"""Find token that indicates the response is over."""
|
|
||||||
for line in data.splitlines(True):
|
|
||||||
if line.startswith(('OK', 'ACK')) and line.endswith('\n'):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def find_request_end_token(data):
|
|
||||||
"""Find token that indicates that request is over."""
|
|
||||||
lines = data.splitlines(True)
|
|
||||||
if not lines:
|
|
||||||
return False
|
|
||||||
elif 'command_list_ok_begin' == lines[0].strip():
|
|
||||||
return 'command_list_end' == lines[-1].strip()
|
|
||||||
else:
|
|
||||||
return lines[0].endswith('\n')
|
|
||||||
|
|
||||||
|
|
||||||
def diff(address, command, reference_response, actual_response):
|
|
||||||
"""Print command from client and a unified diff of the responses."""
|
|
||||||
sys.stdout.write('[%s]:%s\n%s' % (address[0], address[1], command))
|
|
||||||
for line in difflib.unified_diff(reference_response.splitlines(True),
|
|
||||||
actual_response.splitlines(True),
|
|
||||||
fromfile='Reference response',
|
|
||||||
tofile='Actual response'):
|
|
||||||
|
|
||||||
if line.startswith('+') and not line.startswith('+++'):
|
|
||||||
sys.stdout.write(GREEN)
|
|
||||||
elif line.startswith('-') and not line.startswith('---'):
|
|
||||||
sys.stdout.write(RED)
|
|
||||||
elif line.startswith('@@'):
|
|
||||||
sys.stdout.write(CYAN)
|
|
||||||
|
|
||||||
sys.stdout.write(line)
|
|
||||||
sys.stdout.write(RESET)
|
|
||||||
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
|
||||||
"""Handle flag parsing."""
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description='Proxy and compare MPD protocol interactions.')
|
|
||||||
parser.add_argument('--listen', default=':6600', type=parse_address,
|
|
||||||
help='address:port to listen on.')
|
|
||||||
parser.add_argument('--reference', default=':6601', type=parse_address,
|
|
||||||
help='address:port for the reference backend.')
|
|
||||||
parser.add_argument('--actual', default=':6602', type=parse_address,
|
|
||||||
help='address:port for the actual backend.')
|
|
||||||
|
|
||||||
return parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
def parse_address(address):
|
|
||||||
"""Convert host:port or port to address to pass to connect."""
|
|
||||||
if ':' not in address:
|
|
||||||
return ('', int(address))
|
|
||||||
host, port = address.rsplit(':', 1)
|
|
||||||
return (host, int(port))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
args = parse_args()
|
|
||||||
|
|
||||||
def handle(client, address):
|
|
||||||
"""Wrapper that adds reference and actual backends to proxy calls."""
|
|
||||||
return proxy(client, address, args.reference, args.actual)
|
|
||||||
|
|
||||||
try:
|
|
||||||
server.StreamServer(args.listen, handle).serve_forever()
|
|
||||||
except (KeyboardInterrupt, SystemExit):
|
|
||||||
pass
|
|
||||||
203
tools/idle.py
203
tools/idle.py
@ -1,203 +0,0 @@
|
|||||||
#! /usr/bin/env python
|
|
||||||
|
|
||||||
# This script is helper to systematicly test the behaviour of MPD's idle
|
|
||||||
# command. It is simply provided as a quick hack, expect nothing more.
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import pprint
|
|
||||||
import socket
|
|
||||||
|
|
||||||
host = ''
|
|
||||||
port = 6601
|
|
||||||
|
|
||||||
url = "13 - a-ha - White Canvas.mp3"
|
|
||||||
artist = "a-ha"
|
|
||||||
|
|
||||||
data = {'id': None, 'id2': None, 'url': url, 'artist': artist}
|
|
||||||
|
|
||||||
# Commands to run before test requests to coerce MPD into right state
|
|
||||||
setup_requests = [
|
|
||||||
'clear',
|
|
||||||
'add "%(url)s"',
|
|
||||||
'add "%(url)s"',
|
|
||||||
'add "%(url)s"',
|
|
||||||
'play',
|
|
||||||
#'pause', # Uncomment to test paused idle behaviour
|
|
||||||
#'stop', # Uncomment to test stopped idle behaviour
|
|
||||||
]
|
|
||||||
|
|
||||||
# List of commands to test for idle behaviour. Ordering of list is important in
|
|
||||||
# order to keep MPD state as intended. Commands that are obviously
|
|
||||||
# informational only or "harmfull" have been excluded.
|
|
||||||
test_requests = [
|
|
||||||
'add "%(url)s"',
|
|
||||||
'addid "%(url)s" "1"',
|
|
||||||
'clear',
|
|
||||||
#'clearerror',
|
|
||||||
#'close',
|
|
||||||
#'commands',
|
|
||||||
'consume "1"',
|
|
||||||
'consume "0"',
|
|
||||||
# 'count',
|
|
||||||
'crossfade "1"',
|
|
||||||
'crossfade "0"',
|
|
||||||
#'currentsong',
|
|
||||||
#'delete "1:2"',
|
|
||||||
'delete "0"',
|
|
||||||
'deleteid "%(id)s"',
|
|
||||||
'disableoutput "0"',
|
|
||||||
'enableoutput "0"',
|
|
||||||
#'find',
|
|
||||||
#'findadd "artist" "%(artist)s"',
|
|
||||||
#'idle',
|
|
||||||
#'kill',
|
|
||||||
#'list',
|
|
||||||
#'listall',
|
|
||||||
#'listallinfo',
|
|
||||||
#'listplaylist',
|
|
||||||
#'listplaylistinfo',
|
|
||||||
#'listplaylists',
|
|
||||||
#'lsinfo',
|
|
||||||
'move "0:1" "2"',
|
|
||||||
'move "0" "1"',
|
|
||||||
'moveid "%(id)s" "1"',
|
|
||||||
'next',
|
|
||||||
#'notcommands',
|
|
||||||
#'outputs',
|
|
||||||
#'password',
|
|
||||||
'pause',
|
|
||||||
#'ping',
|
|
||||||
'play',
|
|
||||||
'playid "%(id)s"',
|
|
||||||
#'playlist',
|
|
||||||
'playlistadd "foo" "%(url)s"',
|
|
||||||
'playlistclear "foo"',
|
|
||||||
'playlistadd "foo" "%(url)s"',
|
|
||||||
'playlistdelete "foo" "0"',
|
|
||||||
#'playlistfind',
|
|
||||||
#'playlistid',
|
|
||||||
#'playlistinfo',
|
|
||||||
'playlistadd "foo" "%(url)s"',
|
|
||||||
'playlistadd "foo" "%(url)s"',
|
|
||||||
'playlistmove "foo" "0" "1"',
|
|
||||||
#'playlistsearch',
|
|
||||||
#'plchanges',
|
|
||||||
#'plchangesposid',
|
|
||||||
'previous',
|
|
||||||
'random "1"',
|
|
||||||
'random "0"',
|
|
||||||
'rm "bar"',
|
|
||||||
'rename "foo" "bar"',
|
|
||||||
'repeat "0"',
|
|
||||||
'rm "bar"',
|
|
||||||
'save "bar"',
|
|
||||||
'load "bar"',
|
|
||||||
#'search',
|
|
||||||
'seek "1" "10"',
|
|
||||||
'seekid "%(id)s" "10"',
|
|
||||||
#'setvol "10"',
|
|
||||||
'shuffle',
|
|
||||||
'shuffle "0:1"',
|
|
||||||
'single "1"',
|
|
||||||
'single "0"',
|
|
||||||
#'stats',
|
|
||||||
#'status',
|
|
||||||
'stop',
|
|
||||||
'swap "1" "2"',
|
|
||||||
'swapid "%(id)s" "%(id2)s"',
|
|
||||||
#'tagtypes',
|
|
||||||
#'update',
|
|
||||||
#'urlhandlers',
|
|
||||||
#'volume',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def create_socketfile():
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
sock.connect((host, port))
|
|
||||||
sock.settimeout(0.5)
|
|
||||||
fd = sock.makefile('rw', 1) # 1 = line buffered
|
|
||||||
fd.readline() # Read banner
|
|
||||||
return fd
|
|
||||||
|
|
||||||
|
|
||||||
def wait(fd, prefix=None, collect=None):
|
|
||||||
while True:
|
|
||||||
line = fd.readline().rstrip()
|
|
||||||
if prefix:
|
|
||||||
logging.debug('%s: %s', prefix, repr(line))
|
|
||||||
if line.split()[0] in ('OK', 'ACK'):
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def collect_ids(fd):
|
|
||||||
fd.write('playlistinfo\n')
|
|
||||||
|
|
||||||
ids = []
|
|
||||||
while True:
|
|
||||||
line = fd.readline()
|
|
||||||
if line.split()[0] == 'OK':
|
|
||||||
break
|
|
||||||
if line.split()[0] == 'Id:':
|
|
||||||
ids.append(line.split()[1])
|
|
||||||
return ids
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
subsystems = {}
|
|
||||||
|
|
||||||
command = create_socketfile()
|
|
||||||
|
|
||||||
for test in test_requests:
|
|
||||||
# Remove any old ids
|
|
||||||
del data['id']
|
|
||||||
del data['id2']
|
|
||||||
|
|
||||||
# Run setup code to force MPD into known state
|
|
||||||
for setup in setup_requests:
|
|
||||||
command.write(setup % data + '\n')
|
|
||||||
wait(command)
|
|
||||||
|
|
||||||
data['id'], data['id2'] = collect_ids(command)[:2]
|
|
||||||
|
|
||||||
# This connection needs to be make after setup commands are done or
|
|
||||||
# else they will cause idle events.
|
|
||||||
idle = create_socketfile()
|
|
||||||
|
|
||||||
# Wait for new idle events
|
|
||||||
idle.write('idle\n')
|
|
||||||
|
|
||||||
test = test % data
|
|
||||||
|
|
||||||
logging.debug('idle: %s', repr('idle'))
|
|
||||||
logging.debug('command: %s', repr(test))
|
|
||||||
|
|
||||||
command.write(test + '\n')
|
|
||||||
wait(command, prefix='command')
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
line = idle.readline().rstrip()
|
|
||||||
except socket.timeout:
|
|
||||||
# Abort try if we time out.
|
|
||||||
idle.write('noidle\n')
|
|
||||||
break
|
|
||||||
|
|
||||||
logging.debug('idle: %s', repr(line))
|
|
||||||
|
|
||||||
if line == 'OK':
|
|
||||||
break
|
|
||||||
|
|
||||||
request_type = test.split()[0]
|
|
||||||
subsystem = line.split()[1]
|
|
||||||
subsystems.setdefault(request_type, set()).add(subsystem)
|
|
||||||
|
|
||||||
logging.debug('---')
|
|
||||||
|
|
||||||
pprint.pprint(subsystems)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
Loading…
Reference in New Issue
Block a user