mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-25 02:49:46 +00:00
Next contribution to key tests from John McCabe-Dansted.
http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg152761.html git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@30451 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
20f8c82aa8
commit
149bd1ab7b
12
development/keystest/TODO
Normal file
12
development/keystest/TODO
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
HTML out with links.
|
||||||
|
Try to get KEYCODES to be repeatible and useable (DONE)
|
||||||
|
semi protect home dir for repeatibility.
|
||||||
|
Support mouse clicks.
|
||||||
|
Do not spend hours reproducing a bug that has already been reproduced. (DONE)
|
||||||
|
Support other failure modes (e.g. freezes and Python tracebacks)
|
||||||
|
Tally of failures vs successes
|
||||||
|
If come across different bug when trying to reproduce another, reproduce *both* bugs
|
||||||
|
Add report as to how easy bug is to reproduce
|
||||||
|
Try e.g. electric fence
|
||||||
|
Automatically update from svn every 24 hours, recheck if bugs have been fixed.
|
||||||
|
Make it easy to use Xvfb instead of VM.
|
@ -7,28 +7,258 @@
|
|||||||
|
|
||||||
DIRNAME0=`dirname "$0"`
|
DIRNAME0=`dirname "$0"`
|
||||||
OUTDIR="$DIRNAME0/out"
|
OUTDIR="$DIRNAME0/out"
|
||||||
|
ROOT_OUTDIR="$DIRNAME0/out"
|
||||||
|
THIS_PID=$$
|
||||||
|
|
||||||
|
|
||||||
|
BORED_AFTER_SECS=3600 #If we have spend more than 3600 secs (an hour) replaying a file, without learning anything new, go and start looking for more bugs instead
|
||||||
|
|
||||||
|
#############################
|
||||||
|
# This section of code is LyX Specific
|
||||||
|
#############################
|
||||||
|
|
||||||
|
if [ ! -e lib/doc.orig ]
|
||||||
|
then
|
||||||
|
mv lib/doc lib/doc.orig
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_cannot_print () {
|
||||||
|
lpq && (
|
||||||
|
echo We can print, this is bad!
|
||||||
|
echo use lpadmin to stop keytest from destroying a forest.
|
||||||
|
full_exit
|
||||||
|
sleep 999999 ; read
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
extras_save () {
|
||||||
|
for f in `ls lib/doc`
|
||||||
|
do
|
||||||
|
if [ lib/doc/$f -nt lib/doc.orig/$f -o ! -e lib/doc.orig/$f ]
|
||||||
|
then
|
||||||
|
echo making doc dir $OUTDIR/$SEC.doc
|
||||||
|
mkdir -p $OUTDIR/$SEC.doc
|
||||||
|
cp -a lib/doc/$f $OUTDIR/$SEC.doc/
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
extras_prepare () {
|
||||||
|
mkdir -p lib/doc/
|
||||||
|
rm lib/doc/*.lyx
|
||||||
|
cp -p lib/doc.orig/*.lyx lib/doc/
|
||||||
|
}
|
||||||
|
|
||||||
|
get_crash_id () {
|
||||||
|
name=`(cat $GDB | grep -o ' in lyx::[[:alnum:]:]*' ; cat $GDB | grep -o ' [ai][nt] [[:alnum:]:]*' ) | head -n3 | sed s/in// | sed 's/ //g'`
|
||||||
|
echo $name | sed 's/ /__/g'
|
||||||
|
}
|
||||||
|
|
||||||
|
calc_confirm_file() {
|
||||||
|
id=`get_crash_id`
|
||||||
|
echo "$ROOT_OUTDIR/$id.reproduced"
|
||||||
|
}
|
||||||
|
|
||||||
|
full_exit() {
|
||||||
|
echo attempting to exit this entire script... normal exit may just exit one function
|
||||||
|
|
||||||
|
kill $THIS_PID
|
||||||
|
sleep 1
|
||||||
|
echo We should not get this far
|
||||||
|
sleep 1
|
||||||
|
kill -9 $THIS_PIS
|
||||||
|
echo We really should not get this far
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
###########################
|
||||||
|
|
||||||
|
get_pid () {
|
||||||
|
echo getting pidof "$1" 1>&2
|
||||||
|
PID=`ps a"$2" | grep "$1" | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'`
|
||||||
|
echo "$PID" | ( grep " " > /dev/null && ( echo too many PIDs 1>&2 ; full_exit ) )
|
||||||
|
nPIDs=`echo PID "$PID" | wc -l`
|
||||||
|
if [ "$nPIDs" != "1" ]
|
||||||
|
then
|
||||||
|
echo autolyx: Wrong number of PIDs "$nPIDs" 1>&2
|
||||||
|
fi
|
||||||
|
echo "$PID"
|
||||||
|
}
|
||||||
|
|
||||||
|
try_replay () {
|
||||||
|
id=`get_crash_id`
|
||||||
|
echo CRASH_ID
|
||||||
|
export CONFIRM_FILE=`calc_confirm_file`
|
||||||
|
if [ ! -e "$CONFIRM_FILE" ]
|
||||||
|
then
|
||||||
|
echo $CONFIRM_FILE does not exist
|
||||||
|
echo This bug appears not to have been reproduced before
|
||||||
|
echo Will try to reproduce now
|
||||||
|
echo
|
||||||
|
do_replay
|
||||||
|
echo
|
||||||
|
echo Finished attempt at replay
|
||||||
|
else
|
||||||
|
echo $CONFIRM_FILE exists
|
||||||
|
echo This bugs has already been reproduced
|
||||||
|
echo Will not attempt to reproduce again
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
do_replay() {
|
||||||
|
(REPLAYFILE="$KEYCODEpure" TAIL_LINES=25 MAX_TAIL_LINES=10000 bash "$0")&
|
||||||
|
TEST_PID="$!"
|
||||||
|
echo Backgrounded $TEST_PID
|
||||||
|
echo waiting for $TEST_PID to finish
|
||||||
|
wait "$TEST_PID"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_queued_replays() {
|
||||||
|
for f in `ls development/keytest/out/toreplay/*KEYCODEpure`
|
||||||
|
do
|
||||||
|
if [ ! -e "$f.replay/last_crash_sec" ]
|
||||||
|
then
|
||||||
|
#./development/keytest/killtest
|
||||||
|
killall lyx
|
||||||
|
sleep 1
|
||||||
|
killall -9 lyx
|
||||||
|
KEYCODEpure="$f" do_replay
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if [ ! -z "$REPLAYFILE" ]
|
||||||
|
then
|
||||||
|
echo REPLAYMODE
|
||||||
|
OUTDIR="$REPLAYFILE.replay/"
|
||||||
|
mkdir -p $REPLAYFILE.replay/ || full_exit
|
||||||
|
export KEYTEST_INFILE=$REPLAYFILE
|
||||||
|
if [ ! -e "$REPLAYFILE" ]
|
||||||
|
then
|
||||||
|
echo "$REPLAYFILE" does not exist
|
||||||
|
echo exiting
|
||||||
|
full_exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
do_queued_replays
|
||||||
|
echo RANDOM MODE
|
||||||
|
fi
|
||||||
|
|
||||||
|
get_pid [0-9].x-session-manager"$" x
|
||||||
|
export X_PID=`get_pid [0-9].x-session-manager x`
|
||||||
|
echo X_PID $X_PID
|
||||||
|
|
||||||
|
export TAIL_LINES=$TAIL_LINES
|
||||||
|
echo TL $TAIL_LINES
|
||||||
|
|
||||||
|
|
||||||
|
BAK="$OUTDIR/backup"
|
||||||
|
mkdir -p $BAK
|
||||||
|
|
||||||
#rename other windows to avoid confusion.
|
#rename other windows to avoid confusion.
|
||||||
wmctrl -N __renamed__ -r lyx
|
wmctrl -N __renamed__ -r lyx
|
||||||
wmctrl -N __renamed__ -r lyx
|
wmctrl -N __renamed__ -r lyx
|
||||||
wmctrl -N __renamed__ -r lyx
|
wmctrl -N __renamed__ -r lyx
|
||||||
wmctrl -N __renamed__ -r lyx
|
wmctrl -N __renamed__ -r lyx
|
||||||
|
export PATH=`cd $DIRNAME0; pwd`/path:$PATH
|
||||||
(
|
(
|
||||||
|
echo TTL $TAIL_LINES
|
||||||
|
|
||||||
|
LAST_EVENT=`date +%s` # Last time something interesting happened. If nothing interesting has happened for a while, we should quit.
|
||||||
|
|
||||||
|
ensure_cannot_print
|
||||||
|
echo X_PID $X_PID
|
||||||
|
export X_PID=`get_pid [0-9].x-session-manager"$" x`
|
||||||
|
echo PATH $PATH
|
||||||
while true
|
while true
|
||||||
do
|
do
|
||||||
|
echo Currently running autolyx PID=$$
|
||||||
|
if [ ! -z "$TAIL_LINES" ]
|
||||||
|
then
|
||||||
|
echo TAIL_LINES: "$TAIL_LINES"
|
||||||
|
TAIL_FILE=$OUTDIR/tail_"$TAIL_LINES"
|
||||||
|
tail -n "$TAIL_LINES" "$REPLAYFILE" > $TAIL_FILE
|
||||||
|
KEYTEST_INFILE=$TAIL_FILE
|
||||||
|
MAX_DROP=0
|
||||||
|
else
|
||||||
|
MAX_DROP=0.2
|
||||||
|
fi
|
||||||
|
export MAX_DROP
|
||||||
SEC=`date +%s`
|
SEC=`date +%s`
|
||||||
|
if [ ! -z "$REPLAYFILE" ]
|
||||||
|
then
|
||||||
|
echo Boredom factor: $SEC-$LAST_EVENT'=' $(($SEC-$LAST_EVENT))
|
||||||
|
if [ $(($SEC-$LAST_EVENT)) -gt $BORED_AFTER_SECS ]
|
||||||
|
then
|
||||||
|
echo
|
||||||
|
echo Is is now $SEC seconds
|
||||||
|
echo The last time we managed to eliminate a keycode was at $LAST_EVENT
|
||||||
|
echo We get bored after $BORED_AFTER_SECS seconds
|
||||||
|
echo Giving up now.
|
||||||
|
echo
|
||||||
|
echo $LAST_CRASH_SEC > $OUTDIR/Finished
|
||||||
|
mkdir $OUTDIR/final
|
||||||
|
ln $OUTDIR/$SEC* $OUTDIR/final
|
||||||
|
CONFIRM_FILE=`calc_confirm_file`
|
||||||
|
echo Reproducible > "$CONFIRM_FILE"
|
||||||
|
|
||||||
|
|
||||||
|
full_exit
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
GDB=$OUTDIR/$SEC.GDB
|
GDB=$OUTDIR/$SEC.GDB
|
||||||
KEYCODE=$OUTDIR/$SEC.KEYCODE
|
KEYCODE=$OUTDIR/$SEC.KEYCODE
|
||||||
( sleep 20 && python $DIRNAME0/test.py | tee $KEYCODE) &
|
KEYCODEpure=$OUTDIR/$SEC.KEYCODEpure
|
||||||
|
NEWHOME=~/kt.dir/$SEC.dir
|
||||||
|
mkdir -p $NEWHOME
|
||||||
|
NEWHOME=`cd $NEWHOME; pwd`
|
||||||
|
echo NEWHOME $NEWHOME
|
||||||
|
mkdir -p "$NEWHOME"
|
||||||
|
cp -rv ~/.lyx "$NEWHOME"/
|
||||||
|
killall -9 lyx
|
||||||
|
( sleep 25 &&
|
||||||
|
ps a | grep lyx
|
||||||
|
echo -- 1
|
||||||
|
LYX_PID=""
|
||||||
|
i=0
|
||||||
|
while [ -z "$LYX_PID" -a 200 -gt $i ]
|
||||||
|
do
|
||||||
|
export LYX_PID=`ps a | grep /src/lyx | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'`
|
||||||
|
echo LYXPID "$LYX_PID"
|
||||||
|
sleep 0.1
|
||||||
|
i=$(($i+1))
|
||||||
|
done
|
||||||
|
echo `ps a | grep /src/lyx`
|
||||||
|
echo -- 2
|
||||||
|
echo `ps a | grep /src/lyx | grep -v grep`
|
||||||
|
echo -- 3
|
||||||
|
echo `ps a | grep /src/lyx | grep -v grep | sed 's/ [a-z].*$//'`
|
||||||
|
echo -- 4
|
||||||
|
echo LYX_PID=$LYX_PID
|
||||||
|
echo XA_PRIMARY | xclip -selection XA_PRIMARY
|
||||||
|
echo XA_SECONDARY | xclip -selection XA_SECONDARY
|
||||||
|
echo XA_CLIPBOARD | xclip -selection XA_CLIPBOARD
|
||||||
|
|
||||||
|
if [ ! -z "$LYX_PID" ]
|
||||||
|
then
|
||||||
|
kill `ps a | grep keytest.py | grep -v grep | cut -c 1-5`
|
||||||
|
sleep 0.2
|
||||||
|
kill -9 `ps a | grep keytest.py | grep -v grep | cut -c 1-5`
|
||||||
|
KEYTEST_OUTFILE="$KEYCODEpure" nice -19 python $DIRNAME0/keytest.py | tee $KEYCODE
|
||||||
|
fi
|
||||||
|
killall lyx) &
|
||||||
CHILD_PID="$!"
|
CHILD_PID="$!"
|
||||||
ls src/lyx ; sleep 1
|
ls src/lyx ; sleep 1
|
||||||
pwd
|
pwd
|
||||||
#sleep 10
|
|
||||||
|
|
||||||
#You may want to use the following to simulate SIGFPE
|
#You may want to use the following to simulate SIGFPE
|
||||||
#(sleep 90 && killall -8 lyx) &
|
#(sleep 90 && killall -8 lyx) &
|
||||||
|
echo TTL $TAIL_LINES
|
||||||
|
extras_prepare
|
||||||
|
ensure_cannot_print
|
||||||
|
echo Starting GDB
|
||||||
(echo "
|
(echo "
|
||||||
shell svn info src/
|
shell svn info src/
|
||||||
run
|
run
|
||||||
@ -43,18 +273,55 @@ do
|
|||||||
shell wmctrl -r term -b add,shaded
|
shell wmctrl -r term -b add,shaded
|
||||||
shell wmctrl -R lyx
|
shell wmctrl -R lyx
|
||||||
shell import -window root '$GDB..png'
|
shell import -window root '$GDB..png'
|
||||||
" ; yes q) | gdb src/lyx 2>&1 | strings| tee $GDB
|
" ; yes q) | HOME="$NEWHOME" gdb src/lyx 2>&1 | strings| tee $GDB
|
||||||
|
echo END gdb
|
||||||
kill $CHILD_PID
|
kill $CHILD_PID
|
||||||
#sleep 2 kill -9 $CHILD_PID
|
sleep 0.3
|
||||||
grep " signal " $GDB || (
|
kill -9 $CHILD_PID
|
||||||
rm $OUTDIR/*GDB*.bak
|
# Or use "exited normally":
|
||||||
rm $OUTDIR/*KEYCODE*.bak
|
if grep " signal SIG[^T]" $GDB
|
||||||
mv $KEYCODE $KEYCODE.bak
|
then
|
||||||
mv $GDB $GDB.bak
|
extras_save
|
||||||
mv $GDB.png $GDB.png.bak
|
LAST_CRASH_SEC=$SEC
|
||||||
mv $GDB..png $GDB..png.bak
|
echo $LAST_CRASH_SEC > $OUTDIR/last_crash_sec
|
||||||
#rm $OUTDIR/KEYCODE.$SEC
|
if [ ! -z "$TAIL_LINES" ]
|
||||||
#rm $OUTDIR/GDB.$SEC
|
then
|
||||||
)
|
LAST_EVENT="$SEC"
|
||||||
|
echo Reproducible > $OUTDIR/Reproducible
|
||||||
|
fi
|
||||||
|
TAIL_LINES=""
|
||||||
|
if [ -z "$REPLAYFILE" ]
|
||||||
|
then
|
||||||
|
echo ATTEMPTING TO REPLAY
|
||||||
|
try_replay
|
||||||
|
else
|
||||||
|
export KEYTEST_INFILE=$KEYCODEpure
|
||||||
|
NUM_KEYCODES=`wc -l < $KEYCODEpure`
|
||||||
|
echo NUM_KEYCODES $NUM_KEYCODES, was $LAST_NUM_KEYCODES
|
||||||
|
if [ "$NUM_KEYCODES" != "$LAST_NUM_KEYCODES" ]
|
||||||
|
then
|
||||||
|
LAST_EVENT="$SEC"
|
||||||
|
LAST_NUM_KEYCODES=$NUM_KEYCODES
|
||||||
|
echo "Hooray! we have eleminated some keycodes"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
rm -r $BAK/*
|
||||||
|
mv $OUTDIR/$SEC.* $BAK/
|
||||||
|
if [ ! -z "$TAIL_LINES" ]
|
||||||
|
then
|
||||||
|
echo TTL3 $TAIL_LINES
|
||||||
|
echo MAX_TAIL_LINES "$MAX_TAIL_LINES"
|
||||||
|
TAIL_LINES=$(($TAIL_LINES*2))
|
||||||
|
echo TTL4 $TAIL_LINES
|
||||||
|
if [ "$TAIL_LINES" -ge "0$MAX_TAIL_LINES" -a ! -z "$MAX_TAIL_LINES" ]
|
||||||
|
then
|
||||||
|
echo Giving up because $TAIL_LINES '>' $MAX_TAIL_LINES
|
||||||
|
echo Irreproducible > $OUTDIR/Irreproducible
|
||||||
|
full_exit
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo TTL2 $TAIL_LINES
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
) 2>&1 |tee $OUTDIR/log
|
) 2>&1 |tee $OUTDIR/log
|
||||||
|
9
development/keystest/find_in_finals
Normal file
9
development/keystest/find_in_finals
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Searchs for a string in all the final versions
|
||||||
|
|
||||||
|
for f in `find . -name "last_crash_sec"`
|
||||||
|
do
|
||||||
|
SEC=`cat $f`
|
||||||
|
g=`echo $f| sed s/last_crash_sec/$SEC/`
|
||||||
|
grep "$1" $g*
|
||||||
|
done
|
178
development/keystest/keytest.py
Normal file
178
development/keystest/keytest.py
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#This script generated hundreds of random keypresses per second,
|
||||||
|
# and sends them to the lyx window
|
||||||
|
#It requires xvkbd and wmctrl
|
||||||
|
#It generates a log of the KEYCODES it sends as development/keystest/out/KEYCODES
|
||||||
|
|
||||||
|
import random
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
print "Beginning keytest.py"
|
||||||
|
|
||||||
|
|
||||||
|
class CommandSource:
|
||||||
|
def __init__(self):
|
||||||
|
keycode=["\[Left]",'\[Right]','\[Down]','\[Up]','\[BackSpace]','\[Delete]','\[Escape]']
|
||||||
|
keycode[:0]=keycode
|
||||||
|
keycode[:0]=keycode
|
||||||
|
|
||||||
|
keycode[:0]=['\\']
|
||||||
|
|
||||||
|
for k in range(97, 123):
|
||||||
|
keycode[:0]=chr(k)
|
||||||
|
|
||||||
|
for k in range(97, 123):
|
||||||
|
keycode[:0]=["\A"+chr(k)]
|
||||||
|
|
||||||
|
for k in range(97, 123):
|
||||||
|
keycode[:0]=["\A"+chr(k)]
|
||||||
|
|
||||||
|
for k in range(97, 123):
|
||||||
|
keycode[:0]=["\C"+chr(k)]
|
||||||
|
|
||||||
|
self.keycode=keycode;
|
||||||
|
self.count=0;
|
||||||
|
self.count_max=1999;
|
||||||
|
|
||||||
|
def getCommand(self):
|
||||||
|
self.count=self.count+1;
|
||||||
|
#if self.count > self.count_max:
|
||||||
|
if self.count%200==0:
|
||||||
|
#self.count=0
|
||||||
|
return ("RaiseLyx")
|
||||||
|
elif self.count > self.count_max:
|
||||||
|
os._exit(0)
|
||||||
|
else:
|
||||||
|
keystr=""
|
||||||
|
for k in range(1,2):
|
||||||
|
keystr=keystr+self.keycode[random.randint(1,len(self.keycode))-1]
|
||||||
|
return "KK: "+keystr
|
||||||
|
|
||||||
|
class CommandSourceFromFile(CommandSource):
|
||||||
|
def __init__(self,filename,p):
|
||||||
|
self.infile=open(filename,'r')
|
||||||
|
self.lines=self.infile.readlines()
|
||||||
|
self.p=p
|
||||||
|
self.i=0
|
||||||
|
self.count=0
|
||||||
|
self.loops=0
|
||||||
|
#Now we start randomly dropping lines, which we hope are redundant
|
||||||
|
#p is the probability that any given line will be removed
|
||||||
|
if (p>0):
|
||||||
|
#The next couple of lines are to ensure that at least one line is dropped
|
||||||
|
drop=random.randint(0,len(self.lines)-1)
|
||||||
|
del self.lines[drop]
|
||||||
|
p=p-(1/len(self.lines))
|
||||||
|
j=0
|
||||||
|
origlines=self.lines
|
||||||
|
self.lines=[];
|
||||||
|
for l in origlines:
|
||||||
|
if random.uniform(0,1) < self.p:
|
||||||
|
print "Randomly dropping line "+l+"\n"
|
||||||
|
else:
|
||||||
|
self.lines.append(l)
|
||||||
|
print "LINES\n"
|
||||||
|
print self.lines
|
||||||
|
sys.stdout.flush()
|
||||||
|
os.system("sleep 2")
|
||||||
|
|
||||||
|
def getCommand(self):
|
||||||
|
if self.i >= len(self.lines):
|
||||||
|
if self.count >= 100 or self.loops>1:
|
||||||
|
os.system("sleep 1")
|
||||||
|
os._exit(0)
|
||||||
|
else:
|
||||||
|
self.loops=self.loops+1
|
||||||
|
self.i=0
|
||||||
|
return("Loop")
|
||||||
|
line=self.lines[self.i]
|
||||||
|
print "Line read: <<"+line+">>\n"
|
||||||
|
self.count=self.count+1
|
||||||
|
self.i=self.i+1
|
||||||
|
return(line.rstrip())
|
||||||
|
|
||||||
|
def sendKeystring(keystr,LYX_PID):
|
||||||
|
print "sending keystring "+keystr+"\n"
|
||||||
|
if not re.match(".*\w.*", keystr):
|
||||||
|
print ("print ."+keystr+".\n")
|
||||||
|
keystr="a"
|
||||||
|
os.system("while ( test -e /proc/$LYX_PID/status && ! grep 'tate.*[(]sleeping[)]' /proc/$LYX_PID/status); do echo -n . ; sleep 0.02; done")
|
||||||
|
cmd="xvkbd -xsendevent -text '"+keystr+"';sleep 0.03"
|
||||||
|
sys.stdout.flush()
|
||||||
|
os.system(cmd)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def RaiseWindow():
|
||||||
|
os.system("echo x-session-manager PID: $X_PID.")
|
||||||
|
os.system("echo x-session-manager open files: `lsof -p $X_PID | grep ICE-unix | wc -l`")
|
||||||
|
os.system("wmctrl -l | ( grep '"+lyx_window_name+"' || ( killall lyx ; sleep 1 ; killall -9 lyx ))")
|
||||||
|
os.system("wmctrl -R '"+lyx_window_name+"' ;sleep 0.1")
|
||||||
|
|
||||||
|
|
||||||
|
lyx_pid=os.environ.get("LYX_PID")
|
||||||
|
print("lyx_pid: "+lyx_pid+"\n");
|
||||||
|
infilename=os.environ.get("KEYTEST_INFILE")
|
||||||
|
outfilename=os.environ.get("KEYTEST_OUTFILE")
|
||||||
|
max_drop=os.environ.get("MAX_DROP")
|
||||||
|
lyx_window_name=os.environ.get("LYX_WINDOW_NAME");
|
||||||
|
|
||||||
|
file_new_command=os.environ.get("FILE_NEW_COMMAND");
|
||||||
|
if file_new_command is None:
|
||||||
|
file_new_command="\Afn"
|
||||||
|
|
||||||
|
ResetCommand=os.environ.get("RESET_COMMAND");
|
||||||
|
if ResetCommand is None:
|
||||||
|
ResetCommand="\[Escape]\[Escape]\[Escape]\[Escape]"+file_new_command
|
||||||
|
#ResetCommand="\[Escape]\[Escape]\[Escape]\[Escape]\Cw\Cw\Cw\Cw\Cw\Afn"
|
||||||
|
|
||||||
|
if lyx_window_name is None:
|
||||||
|
lyx_window_name="LyX";
|
||||||
|
|
||||||
|
print("outfilename: "+outfilename+"\n")
|
||||||
|
print("max_drop: "+max_drop+"\n")
|
||||||
|
|
||||||
|
if infilename is None:
|
||||||
|
print("infilename is None\n")
|
||||||
|
x=CommandSource()
|
||||||
|
print ("Using x=CommandSource\n");
|
||||||
|
else:
|
||||||
|
print("infilename: "+infilename+"\n")
|
||||||
|
probability_we_drop_a_command=random.uniform(0,float(max_drop))
|
||||||
|
print ("probability_we_drop_a_command: ")
|
||||||
|
print '%s'%(probability_we_drop_a_command)
|
||||||
|
print "\n"
|
||||||
|
x=CommandSourceFromFile(infilename,probability_we_drop_a_command)
|
||||||
|
print ("Using x=CommandSourceFromFile\n");
|
||||||
|
|
||||||
|
outfile=open(outfilename,'w')
|
||||||
|
|
||||||
|
RaiseWindow()
|
||||||
|
sendKeystring("\Afn",lyx_pid)
|
||||||
|
write_commands=True;
|
||||||
|
|
||||||
|
while True:
|
||||||
|
os.system("echo -n LOADAVG:; cat /proc/loadavg")
|
||||||
|
c=x.getCommand()
|
||||||
|
if (c=="Loop"):
|
||||||
|
outfile.close()
|
||||||
|
outfile=open(outfilename+'+','w')
|
||||||
|
print ("Now Looping")
|
||||||
|
outfile.writelines(c+'\n')
|
||||||
|
outfile.flush()
|
||||||
|
if c=="RaiseLyx":
|
||||||
|
print ("Raising Lyx");
|
||||||
|
RaiseWindow()
|
||||||
|
elif c[0:4]=="KK: ":
|
||||||
|
if os.path.exists("/proc/"+lyx_pid+"/status"):
|
||||||
|
sendKeystring(c[4:],lyx_pid)
|
||||||
|
else:
|
||||||
|
os.system("killall lyx; sleep 2 ; killall -9 lyx")
|
||||||
|
print ("No path /proc/"+lyx_pid+"/status, exiting")
|
||||||
|
os._exit(1)
|
||||||
|
elif (c=="Loop"):
|
||||||
|
RaiseWindow()
|
||||||
|
sendKeystring(ResetCommand,lyx_pid)
|
||||||
|
else:
|
||||||
|
print ("Unrecognised Command '"+c+"'\n")
|
@ -11,7 +11,7 @@ if ! [ -d $LT ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p $LT/out
|
mkdir -p $LT/out
|
||||||
if which wmctrl xvkbd bash xterm python
|
if which wmctrl xvkbd bash xterm python xclip
|
||||||
then
|
then
|
||||||
|
|
||||||
if [ a"$1" == a--update ]; then
|
if [ a"$1" == a--update ]; then
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# This script starts LyX, and restarts LyX if it is closed
|
|
||||||
# it logs all output, including backtraces to development/keystest/out/GDB
|
|
||||||
|
|
||||||
#rename other windows to avoid confusion.
|
|
||||||
DIRNAME0=`dirname "$0"`
|
|
||||||
OUTDIR="$DIRNAME0/out"
|
|
||||||
WAITSECS=20
|
|
||||||
INFILE="$1"
|
|
||||||
LINES_TO_INCLUDE=8
|
|
||||||
|
|
||||||
if [ ! -e "$INFILE" ]
|
|
||||||
then
|
|
||||||
echo cannot find "$INFILE"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
killall lyx
|
|
||||||
|
|
||||||
wmctrl -N __renamed__ -r lyx
|
|
||||||
wmctrl -N __renamed__ -r lyx
|
|
||||||
wmctrl -N __renamed__ -r lyx
|
|
||||||
wmctrl -N __renamed__ -r lyx
|
|
||||||
|
|
||||||
while ! grep " signal SIG[^T]" "$INFILE.new_gdb"
|
|
||||||
do
|
|
||||||
SEC=`date +%s`
|
|
||||||
echo GDB---------------- >> "$INFILE.new_gdb.bak"
|
|
||||||
cat "$INFILE.new_gdb" >> "$INFILE.new_gdb.bak"
|
|
||||||
echo LINES_TO_INCLUDE $LINES_TO_INCLUDE
|
|
||||||
#cat $NUMLINES
|
|
||||||
tail -n $LINES_TO_INCLUDE < $INFILE > $INFILE.new_key
|
|
||||||
NUMLINES=`wc -l "$INFILE.new_key"`
|
|
||||||
echo NUMLINES $NUMLINES
|
|
||||||
( i=0
|
|
||||||
echo Waiting $WAITSECS before starting replay
|
|
||||||
sleep $WAITSECS
|
|
||||||
echo Starting replay
|
|
||||||
wmctrl -R LyX && xvkbd -xsendevent -text '\Afn'
|
|
||||||
cat "$INFILE.new_key" |
|
|
||||||
while read -r l
|
|
||||||
do
|
|
||||||
wmctrl -R LyX && xvkbd -xsendevent -text "$l"
|
|
||||||
#echo -- "$l"
|
|
||||||
i=$(($i+1))
|
|
||||||
echo $i/$NUMLINES
|
|
||||||
sleep 0.1
|
|
||||||
done
|
|
||||||
echo FINISHED REPLAY
|
|
||||||
sleep 4
|
|
||||||
killall lyx
|
|
||||||
sleep 2
|
|
||||||
killall lyx -9
|
|
||||||
echo FINISHED REPLAY and killed lyx
|
|
||||||
) &
|
|
||||||
CHILD_PID="$!"
|
|
||||||
echo "Starting Lyx"
|
|
||||||
(echo "run
|
|
||||||
bt" ; yes q) | gdb src/lyx 2>&1 | strings| tee "$INFILE.new_gdb"
|
|
||||||
kill $CHILD_PID
|
|
||||||
sleep 2 kill -9 $CHILD_PID
|
|
||||||
LINES_TO_INCLUDE=$(($LINES_TO_INCLUDE*2))
|
|
||||||
|
|
||||||
done
|
|
||||||
echo END
|
|
@ -1,10 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
LT=development/keystest
|
LT=development/keystest
|
||||||
|
|
||||||
# echo 'grep "#1 " $LT/out/GDB | sed 's/0x[^ )]*[ )]/.*/g' | sort | uniq' >> report.sh
|
GEOM=320x200
|
||||||
|
convert -normalize -scale $GEOM -quality $QUALITY $f $GEOM/$f
|
||||||
|
|
||||||
UNIQUE_LINE=1
|
UNIQUE_LINE=1
|
||||||
SRC=
|
SRC=
|
||||||
|
|
||||||
|
|
||||||
if [ -e out/log ]
|
if [ -e out/log ]
|
||||||
then
|
then
|
||||||
LT=.
|
LT=.
|
||||||
@ -19,60 +22,117 @@ do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
OUT=$LT/out
|
OUT=$LT/out/html
|
||||||
|
mkdir -p $OUT
|
||||||
rm $OUT/index*.html
|
rm $OUT/index*.html
|
||||||
#rm $OUT/indexreport.html
|
|
||||||
ls $OUT/*.html
|
ls $OUT/*.html
|
||||||
|
|
||||||
|
CPP_HTML_DIR_REL=cpp_html
|
||||||
|
CPP_HTML_DIR=$out/cpp_html
|
||||||
|
|
||||||
strings $LT/out/GDB.* > $LT/out/GDBs
|
strings $LT/out/GDB.* > $LT/out/GDBs
|
||||||
grep "#$UNIQUE_LINE " $LT/out/GDBs > $LT/out/list
|
grep "#$UNIQUE_LINE " $LT/out/GDBs > $LT/out/list
|
||||||
#cat $LT/out/list | grep -o ' in [[:alnum:]:]* ' | sort | uniq| tee $LT/out/listuniq
|
|
||||||
#cat $LT/out/list | grep -o ' in [[:alnum:]:]* ' | sort | uniq| tee $LT/out/listuniq
|
|
||||||
cat $LT/out/list | sed 's/0x[^ )]*[ )]/.*/g' | sort | uniq | tee $LT/out/listuniq
|
cat $LT/out/list | sed 's/0x[^ )]*[ )]/.*/g' | sort | uniq | tee $LT/out/listuniq
|
||||||
|
|
||||||
NUM_REPORTS=`wc -l < $LT/out/list`
|
|
||||||
echo NUM_REPORTS $NUM_REPORTS
|
|
||||||
|
|
||||||
echo > $LT/out/overview
|
|
||||||
|
|
||||||
echo '<html>' >> $OUT/indexreport.html
|
echo '<html>' >> $OUT/indexreport.html
|
||||||
|
|
||||||
#cat $LT/out/listuniq | while read l
|
tidy_keycode () {
|
||||||
for f in $LT/out/*GDB
|
while read -r k
|
||||||
do
|
do
|
||||||
|
if [ "$k" = Raiselyx ]
|
||||||
|
then
|
||||||
|
echo -n '\[!Raiselyx]'
|
||||||
|
elif [ "$k" = Loop ]
|
||||||
|
then
|
||||||
|
echo -n '\[!Loop]'
|
||||||
|
else
|
||||||
|
echo -n "$k" | sed s/^KK:\ //
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
html_keycode() {
|
||||||
|
cat "$f_base.KEYCODEpure" | tidy_keycode
|
||||||
|
echo -n '<font color=gray>'
|
||||||
|
cat "$f_base.KEYCODEpure+" | tidy_keycode
|
||||||
|
echo -n '</font><br/>'
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb2html() {
|
||||||
|
cat $g | sed 's/&/&/g' | sed 's/</</g' | while read -r l
|
||||||
|
do
|
||||||
|
c=`echo $l | grep -i -o "at [[:alnum:].]*:[0-9]*"`
|
||||||
|
if [ -z "$c" ]
|
||||||
|
then
|
||||||
|
echo -- "$l" | sed s/--//
|
||||||
|
else
|
||||||
|
cpp=`echo "$c" | sed s/at\ // | sed s/:.*//g`
|
||||||
|
lineno=`echo "$c" | sed s/.*://g`
|
||||||
|
echo $cpp,$lineno 1>&2
|
||||||
|
#if [ -e "$CPP_HTML_DIR/$cpp.html" ]
|
||||||
|
if true
|
||||||
|
then
|
||||||
|
echo "$l" | sed "s/$c/<a href=$CPP_HTML_DIR_REL\/$cpp.html\#line$lineno>$c<\/a>/"
|
||||||
|
else
|
||||||
|
echo "$l"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done | sed 's/^/<br\/>/'
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in `find $LT/out/ | grep replay/last_crash_sec`
|
||||||
|
do
|
||||||
|
echo last_crash_sec file: $file
|
||||||
|
SEC=`cat $file`
|
||||||
|
echo SEC $SEC
|
||||||
|
f_base=`echo $file | sed s/last_crash_sec/$SEC/g`
|
||||||
|
NUM_KEYCODES=`wc -l < "$f_base.KEYCODEpure"`
|
||||||
|
echo NUM_KEYCODES=$NUM_KEYCODES...
|
||||||
|
if [ "$NUM_KEYCODES" -lt 80 ]
|
||||||
|
then
|
||||||
|
echo f_base $f_base
|
||||||
|
f=$f_base.GDB
|
||||||
echo $f
|
echo $f
|
||||||
g=$f.short
|
g=$f.short
|
||||||
if egrep '([Ii][Nn] .*[:[:alnum:]][:][0-9]*[^0-9]|#0 | signal SIG)' -A9999 <$f >$g
|
#if egrep '([Ii][Nn] .*[:[:alnum:]][:][0-9]*[^0-9]|#0 | signal SIG[^T])' -A9999 <$f >$g
|
||||||
|
egrep '([Ii][Nn] .*[:[:alnum:]][:][0-9]*[^0-9]|#0 | signal SIG[^T])' -A9999 <$f >$g
|
||||||
|
if true
|
||||||
then
|
then
|
||||||
#egrep '(([Ii][Nn]|at) .*[:[:alnum:]][:][0-9]*[^0-9]|#0 | signal SIG)' -A9999 <$f
|
IN_AT=`egrep -o '([Ii][Nn]|at) ([:lower:]* )?[:_[:alnum:]]*(::[:_[:alnum:]]*|:[0-9]*)' <$f | grep -v lyx_exit | grep -v [Aa]ssert | head -n 1 `
|
||||||
SEC=`echo $f | sed s/[^[:digit:]]//g`
|
|
||||||
#IN_AT=`egrep -o '([Ii][Nn]|at) ([:lower:]* )[:_[:alnum:]]*(::[:_[:alnum:]]*|:[0-9]*)' <$f | head -n 1 `
|
|
||||||
IN_AT=`egrep -o '([Ii][Nn]|at) ([:lower:]* )?[:_[:alnum:]]*(::[:_[:alnum:]]*|:[0-9]*)' <$f | head -n 1 `
|
|
||||||
SIGNAL=`grep -o ' signal SIG[[:alnum:]_]*[, ]' <$g | sed s/[^[:upper:]]//g | head -n 1`
|
SIGNAL=`grep -o ' signal SIG[[:alnum:]_]*[, ]' <$g | sed s/[^[:upper:]]//g | head -n 1`
|
||||||
TITLE="$SIGNAL $IN_AT"
|
TITLE="$SIGNAL $IN_AT"
|
||||||
TITLE_=`echo $TITLE|sed s/[^[:alnum:]]/_/g`
|
TITLE_=`echo $TITLE|sed s/[^[:alnum:]]/_/g`
|
||||||
INDEX="index_$TITLE_.html"
|
INDEX="index.html"
|
||||||
echo TITLE $TITLE
|
echo TITLE $TITLE
|
||||||
echo INDEX $INDEX
|
echo INDEX $INDEX
|
||||||
if [ ! -e $LT/out/$INDEX ]
|
echo NEW $INDEX
|
||||||
then
|
echo '<html>' >> $LT/out/$INDEX
|
||||||
echo NEW $INDEX
|
echo -n "<a href=\"$SEC.html\">$TITLE</a> " >> $OUT/indexreport.html
|
||||||
echo '<html>' >> $LT/out/$INDEX
|
html_keycode >> $OUT/indexreport.html
|
||||||
echo -n '<a href="'"$INDEX"'">'"$TITLE</a>" >> $OUT/indexreport.html
|
echo >> $OUT/indexreport.html
|
||||||
echo '[<a href="'"$SEC.html"'">'1'</a>]<br/>' >> $OUT/indexreport.html
|
|
||||||
else
|
|
||||||
echo exists $INDEX
|
|
||||||
fi
|
|
||||||
( echo '<html>'
|
( echo '<html>'
|
||||||
echo "<h1>$TITLE</h1>"
|
echo "<h1>$TITLE</h1>"
|
||||||
echo "<img src=$SEC.GDB.png>$TITLE</img>"
|
html_keycode
|
||||||
# head -n 20 $g | txt2html -pi | sed 's/^/<br\/>/' | sed 's/<br\/>$//g'
|
echo "<a href=$SEC.KEYCODE>KEYCODES</a> "
|
||||||
#head -n 20 $g | txt2html -pi | sed 's/^#/#<br\/>/'
|
echo "<a href=$SEC.GDB>GDB</a><br/>"
|
||||||
# cat $g | txt2html -pi | sed 's/^#/#<br\/>/'
|
echo "<a href=$SEC.GDB.png><img src=$SEC.small.png/></a><br/><br/>"
|
||||||
cat $g | sed 's/&/&/g' | sed 's/</</g' | sed 's/^/<br\/>/'
|
gdb2html
|
||||||
) > $OUT/$SEC.html
|
) > $OUT/$SEC.html
|
||||||
echo '<a href="'"$SEC.html"'">'$SEC'</a><br/>' >> $OUT/$INDEX
|
echo '<a href="'"$SEC.html"'">'$SEC'</a><br/>' >> $OUT/$INDEX
|
||||||
echo '<a href="'"$SEC.html"'">'$SEC'</a><br/>'
|
echo '<a href="'"$SEC.html"'">'$SEC'</a><br/>'
|
||||||
|
if [ ! -e $OUT/$SEC.small.png ]
|
||||||
|
then
|
||||||
|
convert -normalize -scale $GEOM $f.png $OUT/$SEC.small.png -quality 85
|
||||||
|
fi
|
||||||
|
chmod a+r $f $f.png $f_base.KEYCODE $f_base.html $OUT/indexreport.html
|
||||||
|
ln $f $f.png $f_base.KEYCODE $f_base.html $OUT/
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
mv $OUT/indexreport.html $OUT/indexreport.html.bak
|
||||||
|
echo "<html>" >> $OUT/indexreport.html
|
||||||
|
echo "<h1>List of bugs found</h1>" >> $OUT/indexreport.html
|
||||||
|
sort -k 2 -t '>' < $OUT/indexreport.html.bak >> $OUT/indexreport.html
|
||||||
|
|
||||||
|
$OUT/
|
||||||
exit
|
exit
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#This script generated hundreds of random keypresses per second,
|
|
||||||
# and sends them to the lyx window
|
|
||||||
#It requires xvkbd and wmctrl
|
|
||||||
#It generates a log of the KEYCODES it sends as development/keystest/out/KEYCODES
|
|
||||||
|
|
||||||
import random
|
|
||||||
import os
|
|
||||||
|
|
||||||
keycode=["\[Left]",'\[Right]','\[Down]','\[Up]','\[BackSpace]','\[Delete]','\[Escape]']
|
|
||||||
keycode[:0]=keycode
|
|
||||||
keycode[:0]=keycode
|
|
||||||
|
|
||||||
keycode[:0]=['\\']
|
|
||||||
|
|
||||||
for k in range(97, 123):
|
|
||||||
keycode[:0]=chr(k)
|
|
||||||
|
|
||||||
for k in range(97, 123):
|
|
||||||
keycode[:0]=["\A"+chr(k)]
|
|
||||||
|
|
||||||
for k in range(97, 123):
|
|
||||||
keycode[:0]=["\A"+chr(k)]
|
|
||||||
|
|
||||||
for k in range(97, 123):
|
|
||||||
keycode[:0]=["\C"+chr(k)]
|
|
||||||
|
|
||||||
|
|
||||||
print (keycode[1])
|
|
||||||
print(keycode)
|
|
||||||
print (random.randint(1,len(keycode)))
|
|
||||||
for k in range(97, 123):
|
|
||||||
print (keycode[random.randint(1,len(keycode))-1])
|
|
||||||
|
|
||||||
#Start a new file. We could also open a random Help file.
|
|
||||||
#os.system("wmctrl -R LyX && xvkbd -xsendevent -text '\Afn';sleep 1")
|
|
||||||
keystr="'\Afn'"
|
|
||||||
os.system("wmctrl -R LyX && xvkbd -xsendevent -text '"+keystr+"';sleep 1")
|
|
||||||
os.system("echo '"+keystr+"'")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
keystr=""
|
|
||||||
for k in range(1,80):
|
|
||||||
keystr=keystr+keycode[random.randint(1,len(keycode))-1]
|
|
||||||
#output keystr before using, to make sure it is output before we are killed
|
|
||||||
os.system("echo '"+keystr+"'")
|
|
||||||
os.system("wmctrl -R LyX && xvkbd -xsendevent -text '"+keystr+"';sleep 1")
|
|
47
development/keystest/watch_keytest.sh
Normal file
47
development/keystest/watch_keytest.sh
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
NOW_SEC=`date +%s`
|
||||||
|
echo NOW_SEC $NOW_SEC
|
||||||
|
echo recently modified files:
|
||||||
|
LATEST_FILE=`ls out/* -td -1 | grep -v log | head -n1`
|
||||||
|
echo $LATEST_FILE | (
|
||||||
|
grep replay > /dev/null || (
|
||||||
|
ls out/* -lotd | head
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ls out/* -tdo -1 | grep replay
|
||||||
|
|
||||||
|
LATEST_FILE=`ls out/* -td -1 | grep replay | head -n1`
|
||||||
|
echo LATEST_FILE $LATEST_FILE
|
||||||
|
echo $LATEST_FILE | (
|
||||||
|
grep replay > /dev/null && (
|
||||||
|
if [ -e $LATEST_FILE/last_crash_sec ]
|
||||||
|
then
|
||||||
|
ls $LATEST_FILE/*re -lotd | head
|
||||||
|
SEC=`cat $LATEST_FILE/last_crash_sec`
|
||||||
|
echo $SEC $(($NOW_SEC-$SEC))
|
||||||
|
ls -l $LATEST_FILE/$SEC.KEYCODEpure
|
||||||
|
echo `cat $LATEST_FILE/$SEC.KEYCODEpure | sed s/KK:\//g`
|
||||||
|
cat $LATEST_FILE/$SEC.GDB | grep "signal SIG" -A 15
|
||||||
|
else
|
||||||
|
ls $LATEST_FILE -lot | head
|
||||||
|
cat `echo $LATEST_FILE | sed s/KEYCODEpure.replay/GDB/` | grep "signal SIG" -A 9
|
||||||
|
fi
|
||||||
|
cat $LATEST_FILE/log | grep Bore | tail -n2
|
||||||
|
) || (
|
||||||
|
ls out/* -lotd | head
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
grep -F "autolyx:
|
||||||
|
Trace
|
||||||
|
reproduced
|
||||||
|
X_PID
|
||||||
|
x-session" out/log | grep -v kill | grep -v Terminated | tail -n 9
|
||||||
|
exit
|
||||||
|
echo autolyx crashes ---------
|
||||||
|
grep autolyx: out/log | grep -v kill | grep -v Terminated #-A 5
|
||||||
|
echo python crashes ---------
|
||||||
|
grep -i Trace out/log -A 5
|
||||||
|
echo misc ----
|
||||||
|
grep reproduced out/log | tail -n5
|
Loading…
Reference in New Issue
Block a user