41e709f8c63cee76db264fa4bda31d27b7d42d2b
[oweals/gnunet.git] / src / integration-tests / gnunet_testing.py.in
1 #!@PYTHON@
2 #    This file is part of GNUnet.
3 #    (C) 2010 Christian Grothoff (and other contributing authors)
4 #
5 #    GNUnet is free software; you can redistribute it and/or modify
6 #    it under the terms of the GNU General Public License as published
7 #    by the Free Software Foundation; either version 2, or (at your
8 #    option) any later version.
9 #
10 #    GNUnet is distributed in the hope that it will be useful, but
11 #    WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 #    General Public License for more details.
14 #
15 #    You should have received a copy of the GNU General Public License
16 #    along with GNUnet; see the file COPYING.  If not, write to the
17 #    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 #    Boston, MA 02111-1307, USA.
19 #
20 # Functions for integration testing
21 import os
22 import subprocess
23 import sys
24 import shutil
25 import time
26 from gnunet_pyexpect import pexpect
27
28 class Check:
29     def __init__(self, test):
30         self.fulfilled = False
31         self.conditions = list()
32         self.test = test
33     def add (self, condition):
34         self.conditions.append(condition)
35     def run (self):
36         fulfilled = True
37         pos = 0
38         neg = 0
39         for c in self.conditions:
40             if (False == c.check ()):
41                 fulfilled = False
42                 neg += 1
43             else:
44                 pos += 1
45         return fulfilled
46     def run_blocking (self, timeout, pos_cont, neg_cont):
47         execs = 0;
48         res = False
49         while ((False == res) and (execs < timeout)):
50             res = self.run()
51             time.sleep(1)
52             execs += 1
53         if ((False == res) and (execs >= timeout)):
54            print ('Check had timeout after ' +str(timeout)+ ' seconds')
55            neg_cont (self)
56         elif ((False == res) and (execs >= timeout)):
57                         neg_cont (self)
58         else:
59             pos_cont (self)
60         return res            
61     def run_once (self, pos_cont, neg_cont):
62         execs = 0;
63         res = False
64         res = self.run()
65         if ((res == False) and (neg_cont != None)):
66             neg_cont (self)
67         if ((res == True) and (pos_cont != None)):
68             pos_cont (self)            
69         return res
70     def evaluate (self, failed_only):
71         pos = 0
72         neg = 0
73         for c in self.conditions:
74             if (False == c.evaluate (failed_only)):
75                 neg += 1
76             else:
77                 pos += 1
78         print (str(pos) +' out of '+ str (pos+neg) + ' conditions fulfilled')
79         return self.fulfilled
80     def reset (self):
81                 self.fulfilled = False     
82                 for c in self.conditions:
83                         c.fulfilled = False
84         
85 class Condition:
86     def __init__(self):
87         self.fulfilled = False
88         self.type = 'generic'
89     def __init__(self, type):
90         self.fulfilled = False
91         self.type = type
92     def check(self):
93         return False;
94     def evaluate (self, failed_only):
95         if ((self.fulfilled == False) and (failed_only == True)):
96             print str(self.type) + 'condition for was ' + str(self.fulfilled)
97         elif (failed_only == False): 
98             print str(self.type) + 'condition for was ' + str(self.fulfilled)
99         return self.fulfilled            
100
101 class FileExistCondition (Condition):
102     def __init__(self, file):
103         self.fulfilled = False
104         self.type = 'file'
105         self.file = file
106     def check(self):
107         if (self.fulfilled == False):
108             res = os.path.isfile(self.file)
109             if (res == True):
110                 self.fulfilled = True
111                 return True
112             else:
113                 return False
114         else:
115             return True
116     def evaluate (self, failed_only):
117         if ((self.fulfilled == False) and (failed_only == True)):
118             print str(self.type) + 'condition for file '+self.file+' was ' + str(self.fulfilled)
119         elif (failed_only == False): 
120             print str(self.type) + 'condition for file '+self.file+' was ' + str(self.fulfilled)
121         return self.fulfilled
122
123 class StatisticsCondition (Condition):
124     def __init__(self, peer, subsystem, name, value):
125         self.fulfilled = False
126         self.type = 'statistics'
127         self.peer = peer;
128         self.subsystem = subsystem;
129         self.name = name;
130         self.value = value;
131         self.result = -1;
132     def check(self):
133         if (self.fulfilled == False):
134             self.result = self.peer.get_statistics_value (self.subsystem, self.name)
135             if (str(self.result) == str(self.value)):
136                 self.fulfilled = True
137                 return True
138             else:
139                 return False
140         else:
141             return True
142     def evaluate (self, failed_only):
143         if (self.result == -1):
144             res = 'NaN'
145         else:
146             res = str(self.result)
147         if (self.fulfilled == False):
148             fail = " FAIL!" 
149             op = " != "
150         else: 
151             fail = ""
152             op = " == "
153         if (((self.fulfilled == False) and (failed_only == True)) or (failed_only == False)):
154             print self.peer.id[:4] + " " +self.peer.cfg + " " +  str(self.type) + ' condition in subsystem "' + self.subsystem.ljust(12) +'" : "' + self.name.ljust(30) +'" : (expected/real value) ' + str(self.value) + op + res + fail
155         return self.fulfilled    
156
157 # Specify two statistic values and check if they are equal  
158 class EqualStatisticsCondition (Condition):
159     def __init__(self, peer, subsystem, name, peer2, subsystem2, name2):
160         self.fulfilled = False
161         self.type = 'equalstatistics'
162         self.peer = peer;
163         self.subsystem = subsystem;
164         self.name = name;
165         self.result = -1;
166         self.peer2 = peer2;
167         self.subsystem2 = subsystem2;
168         self.name2 = name2;
169         self.result2 = -1;
170     def check(self):
171         if (self.fulfilled == False):
172             self.result = self.peer.get_statistics_value (self.subsystem, self.name);
173             self.result2 = self.peer2.get_statistics_value (self.subsystem2, self.name2);
174             if (str(self.result) == str(self.result2)):
175                 self.fulfilled = True
176                 return True
177             else:
178                 return False
179         else:
180             return True
181     def evaluate (self, failed_only):
182         if (self.result == -1):
183             res = 'NaN'
184         else:
185             res = str(self.result)
186         if (self.result2 == -1):
187             res2 = 'NaN'
188         else:
189             res2 = str(self.result2)            
190         if (self.fulfilled == False):
191             fail = " FAIL!" 
192             op = " != "
193         else: 
194             fail = ""
195             op = " == "
196         if (((self.fulfilled == False) and (failed_only == True)) or (failed_only == False)):
197             print self.peer.id[:4] + ' "'  + self.subsystem.ljust(12) + '" "' + self.name.ljust(30) + '" == ' + str(self.result) +" " + self.peer2.id[:4] + ' "'  + self.subsystem2.ljust(12) + '" '+ self.name2.ljust(30) +  '" ' + str(self.result2) 
198         return self.fulfilled                    
199         
200 class Test:
201     def __init__(self, testname, verbose):
202         self.peers = list()
203         self.verbose = verbose;
204         self.name = testname;
205         srcdir = "../.."
206         gnunet_pyexpect_dir = os.path.join (srcdir, "contrib")
207         if gnunet_pyexpect_dir not in sys.path:
208             sys.path.append (gnunet_pyexpect_dir)
209         self.gnunetarm = ''        
210         self.gnunetstatistics = ''
211         if os.name == 'posix':
212             self.gnunetarm = 'gnunet-arm'
213             self.gnunetstatistics = 'gnunet-statistics'
214             self.gnunetpeerinfo = 'gnunet-peerinfo'
215         elif os.name == 'nt':
216             self.gnunetarm = 'gnunet-arm.exe'
217             self.gnunetstatistics = 'gnunet-statistics.exe'
218             self.gnunetpeerinfo = 'gnunet-peerinfo.exe'    
219         if os.name == "nt":
220             shutil.rmtree (os.path.join (os.getenv ("TEMP"), testname), True)
221         else:
222             shutil.rmtree ("/tmp/" + testname, True)
223     def add_peer (self, peer):
224         self.peers.append(peer)
225     def p (self, msg):
226         if (self.verbose == True):
227             print msg    
228
229 class Peer:
230     def __init__(self, test, cfg_file):
231         if (False == os.path.isfile(cfg_file)):
232             print ("Peer cfg " + cfg_file + ": FILE NOT FOUND")
233         self.id = "<NaN>"
234         self.test = test
235         self.started = False
236         self.cfg = cfg_file 
237     def __del__(self):
238         if (self.started == True): 
239             print 'ERROR! Peer using cfg ' + self.cfg + ' was not stopped'
240             ret = self.stop ()
241             if (False == ret):
242                 print 'ERROR! Peer using cfg ' + self.cfg + ' could not be stopped'
243                 self.started = False
244             return ret
245         else:
246             return False
247     def start (self):
248         self.test.p ("Starting peer using cfg " + self.cfg)
249         try:
250             server = subprocess.Popen ([self.test.gnunetarm, '-sq', '-c', self.cfg])
251             server.communicate ()    
252         except OSError:
253             print "Can not start peer"
254             self.started = False
255             return False
256         self.started = True;
257         test = ''
258         try:
259             server = pexpect ()
260             server.spawn (None, [self.test.gnunetpeerinfo, '-c', self.cfg ,'-s'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
261             test = server.read("stdout", 1024)
262         except OSError:
263             print "Can not get peer identity"
264         test = (test.split('`')[1])
265         self.id = test.split('\'')[0]
266         return True 
267     def stop (self):
268         if (self.started == False):
269             return False
270         self.test.p ("Stopping peer using cfg " + self.cfg)
271         try:
272             server = subprocess.Popen ([self.test.gnunetarm, '-eq', '-c', self.cfg])
273             server.communicate ()    
274         except OSError:
275             print "Can not stop peer"
276             return False
277         self.started = False
278         return True;
279     def get_statistics_value (self, subsystem, name):
280         server = pexpect ()
281         server.spawn (None, [self.test.gnunetstatistics, '-c', self.cfg ,'-q','-n', name, '-s', subsystem ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
282         #server.expect ("stdout", re.compile (r""))
283         test = server.read("stdout", 10240)
284         tests = test.partition('\n')
285         # On W32 GNUnet outputs with \r\n, rather than \n
286         if os.name == 'nt' and tests[1] == '\n' and tests[0][-1] == '\r':
287             tests = (tests[0][:-1], tests[1], tests[2])
288         tests = tests[0]
289         if (tests.isdigit() == True):
290             return tests
291         else:
292             return -1
293