rework check-tcp so that we first wait for the network to be ready in the sliver
[tests.git] / system / tcptest.py
1 #!/usr/bin/env python
2
3 # Thierry Parmentelat <thierry.parmentelat@inria.fr>
4 # Copyright (C) 2010 INRIA 
5 #
6 import sys
7 import time
8 import subprocess
9 import socket
10 import SocketServer
11 import threading
12 from optparse import OptionParser    
13
14 def myprint(message, id='client'):
15     now=time.strftime("%H:%M:%S", time.localtime())
16     print "*",now,'(%s)' % id, '--',message
17     sys.stdout.flush()
18
19 def show_network_status(id):
20     myprint("ip address show", id=id)
21     subprocess.call(['ip', 'address', 'show'])
22     myprint("ip route show", id=id)
23     subprocess.call(['ip', 'route', 'show'])
24
25 class EchoRequestHandler(SocketServer.StreamRequestHandler):
26     def handle(self):
27         line = self.rfile.readline()
28         self.wfile.write(line)
29
30 class UppercaseRequestHandler(SocketServer.StreamRequestHandler):
31     def handle(self):
32         line = self.rfile.readline()
33         self.wfile.write(line.upper())
34
35 class Server:
36     """
37     A TCP server, running for some finite amount of time
38     """
39     def main(self):
40         parser = OptionParser()
41         parser.add_option("-p", "--port", action="store", dest="port", type="int",
42                           default=10000, help="port number")
43         parser.add_option("-a", "--address", action="store", dest="address", 
44                           default=socket.gethostname(), help="address")
45         parser.add_option("-t", "--timeout", action="store", dest="timeout", type="int",
46                           default="0")
47         (options, args) = parser.parse_args()
48
49         if len(args) != 0:
50             parser.print_help()
51             sys.exit(1)
52
53         show_network_status(id='server')
54         server = SocketServer.TCPServer((options.address, options.port),
55                                         UppercaseRequestHandler)
56         try:
57             if options.timeout:
58                 t = threading.Thread(target=server.serve_forever)
59                 t.setDaemon(True) # don't hang on exit
60                 t.start()
61                 time.sleep(options.timeout)
62                 sys.exit(0)
63             else:
64                 server.serve_forever()        
65         except KeyboardInterrupt as e:
66             print 'Bailing out on keyboard interrupt'
67             sys.exit(1)
68             
69 class Ready:
70     """
71     A utility that does exit(0) iff network as perceived
72     from the sliver is ready. Designed to be run before Server,
73     so one can wait for the right conditions.
74     """
75     def main(self):
76         parser = OptionParser()
77         # by default use another port so we don't run into
78         # the SO_LINGER kind of trouble
79         parser.add_option("-p", "--port", action="store", dest="port", type="int",
80                           default=9999, help="port number")
81         parser.add_option("-a", "--address", action="store", dest="address", 
82                           default=socket.gethostname(), help="address")
83         (options, args) = parser.parse_args()
84
85         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
86         try:
87             s.bind((options.address, options.port))
88             sys.exit(0)
89         except Exception as e:
90             print e
91             sys.exit(1)
92         
93 class Client:
94     """
95     Runs a client against a Server instance
96     """
97     def main(self):
98         parser = OptionParser()
99         parser.add_option("-p","--port", action="store", dest="port", type="int",
100                           default=10000, help="port number")
101         parser.add_option("-a","--address", action="store", dest="address", 
102                           default=socket.gethostname(), help="address")
103         parser.add_option("-s","--sleep", action="store", dest="sleep", type="int",
104                           default=1, help="sleep seconds")
105         parser.add_option("-l","--loops", action="store", dest="loops", type="int",
106                           default=1, help="iteration loops")
107         
108         (options, args) = parser.parse_args()
109         if len(args) != 0:
110             parser.print_help()
111             sys.exit(1)
112
113         result=True
114         for i in range(1,options.loops+1):
115             s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
116             s.connect((options.address, options.port))
117             mout=i*'ping ' + '\n'
118             min=mout.upper()
119             if s.send(mout) != len(mout):
120                 myprint("cannot send %s"%mout.strip())
121                 result=False
122                 break
123             line=s.recv(len(min))
124             if line is not line:
125                 myprint("unexpected reception\ngot:%s\nexpected: %s",line,min)
126                 result=False
127             else:
128                 myprint("OK:%s"%mout.strip())
129             # leave the connection open, but the last one (so 1 iter returns fast)
130             if i != options.loops:
131                 time.sleep(options.sleep)
132             myprint("disconnecting")
133             s.close()
134         myprint("Done")
135         exit_return=0
136         if not result:
137             exit_return=1
138         sys.exit(exit_return)
139
140 if __name__ == '__main__':
141     for arg in sys.argv[1:]:
142         if arg.find("client") >= 0:
143             sys.argv.remove(arg)
144             Client().main()
145         elif arg.find("server") >= 0:
146             sys.argv.remove(arg)
147             Server().main()
148         elif arg.find("ready") >= 0:
149             sys.argv.remove(arg)
150             Ready().main()
151     print 'you must specify either --client or --server'
152     sys.exit(1)