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