Skip to content

Instantly share code, notes, and snippets.

@bgschiller
Last active December 14, 2015 10:39
Show Gist options
  • Save bgschiller/5073528 to your computer and use it in GitHub Desktop.
Save bgschiller/5073528 to your computer and use it in GitHub Desktop.
Server tests for CSCI 367 Network Blackjack. Description and usage is in a comment following the code.
import string
import pexpect
import sys
import random
import argparse
import os
from utils import colors
def is_server_running(host,port):
'''Try to connect to the server, send a join and expect a conn'''
try:
client = pexpect.spawn('telnet {} {}'.format(host,port),
logfile=sys.stdout)
# setting logfile to sys.stdout prints the IO for the child process to the screen
client.expect('Connected',timeout=2)
client.sendline('[join|Brian ]')
client.expect('join')
client.sendline('[exit]')
client.kill(9)
return True
except (pexpect.TIMEOUT, pexpect.EOF):
return False
def simple_test(host, port):
'''Server should function properly up to the deal and first turn message, then exit.'''
try:
client = pexpect.spawn('telnet {} {}'.format(host,port),
logfile=sys.stdout)
client.expect('Connected',timeout=2)
name = ''.join(random.sample(string.lowercase,12))
client.sendline('[join|{}]'.format(name))
client.expect('join')
client.expect('ante')
client.sendline('[ante|0000000100]')
client.expect('deal')
client.expect_exact('turn|{}'.format(name))
client.sendline('[exit]')
client.kill(9)
return True
except (pexpect.TIMEOUT, pexpect.EOF):
return False
def resilient_server(host, port):
'''Sends a bunch of junk across the wire. Test passes if the server closes this socket and remains available for other connections'''
client = pexpect.spawn('telnet {} {}'.format(host,port))
for i in range(20):
random_string = os.urandom(45).strip('\x1d')
#\x1d is Ctrl-], the escape character for telnet
try:
client.sendline(random_string)
except:
pass
return is_server_running(host,port)
def big_spender(host,port):
'''Tries to make a $2000 bet, which should be too large'''
try:
client = pexpect.spawn('telnet {} {}'.format(host,port),
logfile=sys.stdout)
client.expect('Connected',timeout=2)
name = ''.join(random.sample(string.lowercase, 12))
client.sendline('[join|{}]'.format(name))
client.expect('join')
client.expect('ante')
client.sendline('[ante|0000002000]')
if client.expect(['errr','deal']) == 1:
return False
client.sendline('[exit]')
return True
except (pexpect.TIMEOUT, pexpect.EOF):
return False
def long_winded(host,port):
'''Client tries to send a chat that is too long.'''
try:
watson = pexpect.spawn('telnet {} {}'.format(host,port),
logfile=sys.stdout)
watson.expect('Connected',timeout=2)
watson.sendline('[join|JohnWatson ]')
watson.expect('join')
watson.sendline('[chat|' + '''When I glance over my notes and records of the Sherlock Holmes
cases between the years '82 and '90, I am faced by so many which
present strange and interesting features that it is no easy
matter to know which to choose and which to leave. Some, however,
have already gained publicity through the papers, and others have
not offered a field for those peculiar qualities which my friend
possessed in so high a degree, and which it is the object of
these]''')
watson.expect_exact('[errr|1|Chat message too long. Must be 450 characters or less.]',timeout=2)
watson.sendline('[exit]')
return True
except (pexpect.TIMEOUT, pexpect.EOF):
return False
def confused_player(host,port):
'''This player doesn't know when it's their turn'''
try:
bob = pexpect.spawn('telnet {} {}'.format(host,port),
logfile=sys.stdout)
bob.expect('Connected',timeout=2)
bob.sendline('[join|GrandpaBob ]')
bob.expect('join')
bob.sendline('[turn|hitt]')
bob.expect_exact("[errr|1|It's not your turn!]',timeout=2")
bob.sendline('[exit]')
return True
except( pexpect.TIMEOUT, pexpect.EOF):
return False
def big_spender2(host,port):
'''Tries to make a $600 bet, then double down'''
try:
client = pexpect.spawn('telnet {} {}'.format(host,port),
logfile=sys.stdout)
client.expect('Connected',timeout=2)
name = ''.join(random.sample(string.lowercase,12))
client.sendline('[join|{}]'.format(name))
client.expect('join')
client.expect('ante')
client.sendline('[ante|0000000600]')
client.expect_exact('[turn|{}]'.format(name))
client.sendline('[turn|down]')
client.expect_exact("[errr|1|You don't have enough cash to double down.]",
timeout=2)
client.sendline('[exit]')
return True
except (pexpect.TIMEOUT, pexpect.EOF):
return False
tests = [is_server_running, simple_test, resilient_server, big_spender,
long_winded, confused_player, big_spender2]
def main():
'''To run these tests, start your server running and pass along the host and port.'''
parser = argparse.ArgumentParser(
description='Test scripts for CSCI 367 network blackjack game')
parser.add_argument('-p','--port',
default=36709,
type=int,
help='the port where the server is listening',
metavar='port',
dest='port')
parser.add_argument(
'-s','--server',
default='localhost',
type=str,
help='the host where the server is listening',
metavar='host',
dest='host')
parser.add_argument(
'-t','--tough',
dest='rigor', action='store_const',
const='tough', default='lenient',
help='stop testing after any test fails')
args = vars(parser.parse_args())
for test in tests:
print colors.OKBLUE + 'running test "{}"'.format(test.__name__)
print test.__doc__ + colors.ENDC
if test(args['host'],args['port']):
print colors.OKGREEN + 'test passed' + colors.ENDC
else:
print colors.FAIL + 'test failed' + colors.ENDC
if args['rigor'] == 'tough':
break
if __name__ == '__main__':
main()
@bgschiller
Copy link
Author

To add a test:

  • Make a new function, taking a hostname and port number.
  • The function must include a docstring, which will be printed preceding to running the test
  • The test should return True for pass and False for failure.
  • Be sure to add your test function to the 'tests' list (defined just above main()

If you don't want to mess with git, feel free to email me your test and I can do it. (my email is listed on moodle)
My idea is that this can be a first step towards making sure we're all on the same page.

To run the tests:
Start your server running first. The port and host arguments default to 'localhost' and '36709'.
usage: python servertests.py [-h] [-p port] [-s host] [-t]

optional arguments:
-h, --help show this help message and exit
-p port, --port port the port where the server is listening
-s host, --server host the host where the server is listening
-t, --tough stop testing after any test fails

@PlanetLotus
Copy link

This is great. Thanks for taking the time to do this. I'm not "quite there" yet...still tons of work to do before I really know what all of the "problems" are...but I will definitely see if I can contribute anything once I catch up.

@cordovc3
Copy link

cordovc3 commented Mar 5, 2013

Hmm. So I'm definitely not running a server right now but I'm getting this on the first test

CF416-03/test :) $ python servertests.py -p 42426 -s localhost
running test "is_server_running"
Try to connect to the server, send a join and expect a conn
[join|tom ]
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
[join|tom ][exit]
test passed

It looks like the rest of the tests are failing though...
If I'm reading it right, it looks like [join|tom ] is sent before telnet establishes a connection. Hmm. Probably not a big deal since most everybody who is using this test will probably actually have a server running :p

@bgschiller
Copy link
Author

Should be fixed now.

@cordovc3
Copy link

cordovc3 commented Mar 6, 2013

So, I haven't done much of the networking yet but have been setting up classes and all that good stuff, so I'm not quite ready to write tests, but I did write up a bunch of strings to test if I was parsing and getting correct error messages. I'm going to post them here just incase anybody wants them, and then try to add some of them to the test script. There are a few places in the spec where I'm not sure what error we should be producing, I'll comment there.

String[] tests = 
                {
                    //bad commands
                    "][][][][][][][][][][][",
                    "[][][][][][][][][][][][][]",
                    "[join][join][join][join][join][join][join][join][join][join][join][join]",
                    "[insu|531][insu|531][insu|531][insu|531][turn|down]",
                    @"3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559
                     64462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001
                     13305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907
                     02179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034
                     41815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349
                     04287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989",
                    @"[chat|3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559
                     64462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001
                     13305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907
                     02179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034
                     41815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349
                     04287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989]",
                    "asdf",
                    "[feiaojfeoafijae]",
                    "[||]",
                    "[join|]",
                    "[ante|93599333333]", //11 digits
                    "[insu|92929292929]", //11
                    "[ante|]",
                    "[insu|]\n",
                    "[exit ]",
                    "[ exit]",
                    "[ join | player 1 ]",
                    "[join| no $ymbols]",
                    "[join|P|PEMAN]",
                    "[time]",
                    "[' or 1 = 1; DROP TABLE USERS;]",
                    "[strk]",
                    "[join|name|extrafield]",
                    "[ante|-2]",
                    "[turn|hit]",
                    "[turn|strk]",
                    "[turn|split]",
                    "[join|SERVER      ]",
                    //legitimate commands
                    "[join|kingyeezus  ]",
                    "[join|aoijw       ]\t\n",
                    "[join|twelv3charnm]",
                    "[join|three1415926]",
                    "[join|c           ]",
                    "[ante|0000000010]",
                    "[ante|1000000000]",
                    "[ante|9999999999]",
                    "[ante|0000000001]",
                    "[turn|hitt]\n\t",
                    "[turn|stay]\n",
                    "[turn|down]\v",
                    "[turn|splt]",
                    "[insu|0000000010]",
                    "[insu|1000000000]",
                    "[insu|9999999999]",
                    "[insu|0000000001]",
                    "[exit]",
                    "[chat|Hello there everybody. 1 4m 1337. u$!ng @!! ()f 7he $ymb0l$ !@#$%^&*()_+-=998765213{}.,?><]",
                    "[chat|ifjeoaifjeoifjeoafijeaofijeaiofjeofiejaofiejaofijeofijaeofiejaofiaejfoiaejfoieajfoaeijfoaeifjaeoifjeoaiefjoe,fjaeoifjeaofijeaofieajofiejaofiej]",
                    "[chat|-a reply to ANTE from server, which specifies the min bet)-amount is cash value, at least min bet, less than or equal to your cash on hand]",
                    "[chat|~!@#$%^&*()_+`1234567890-=qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM\\{};':\",./<>?]",
                    "[chat|Codes 20hex to 7Ehex, known as the printable characters, represent letters, digits, punctuation marks, and a few miscellaneous symbols. There are 95 printable characters in total.]"

                };

@cordovc3
Copy link

From utilities import colors is breaking script, unless I'm missing something. My forked copy has colors defined in it again.

@cordovc3
Copy link

echo "Spawning 1000 processes"
for i in {1..1000} 
do
    python servertests.py &
done

good to make sure your server won't die

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment