refactor test framework
[vpp.git] / test / hook.py
1 import signal
2 import os
3 import pexpect
4 from logging import *
5
6
7 class Hook(object):
8     """
9     Generic hooks before/after API/CLI calls
10     """
11
12     def before_api(self, api_name, api_args):
13         """
14         Function called before API call
15         Emit a debug message describing the API name and arguments
16
17         @param api_name: name of the API
18         @param api_args: tuple containing the API arguments
19         """
20         debug("API: %s (%s)" % (api_name, api_args))
21
22     def after_api(self, api_name, api_args):
23         """
24         Function called after API call
25
26         @param api_name: name of the API
27         @param api_args: tuple containing the API arguments
28         """
29         pass
30
31     def before_cli(self, cli):
32         """
33         Function called before CLI call
34         Emit a debug message describing the CLI
35
36         @param cli: CLI string
37         """
38         debug("CLI: %s" % (cli))
39
40     def after_cli(self, cli):
41         """
42         Function called after CLI call
43         """
44         pass
45
46
47 class VppDiedError(Exception):
48     pass
49
50
51 class PollHook(Hook):
52     """ Hook which checks if the vpp subprocess is alive """
53
54     def __init__(self, testcase):
55         self.vpp_dead = False
56         self.testcase = testcase
57
58     def spawn_gdb(self, gdb_path, core_path):
59         gdb_cmdline = gdb_path + ' ' + self.testcase.vpp_bin + ' ' + core_path
60         gdb = pexpect.spawn(gdb_cmdline)
61         gdb.interact()
62         try:
63             gdb.terminate(True)
64         except:
65             pass
66         if gdb.isalive():
67             raise Exception("GDB refused to die...")
68
69     def on_crash(self, core_path):
70         if self.testcase.interactive:
71             gdb_path = '/usr/bin/gdb'
72             if os.path.isfile(gdb_path) and os.access(gdb_path, os.X_OK):
73                 # automatically attach gdb
74                 self.spawn_gdb(gdb_path, core_path)
75                 return
76             else:
77                 error("Debugger '%s' does not exist or is not an executable.." %
78                       gdb_path)
79
80         critical('core file present, debug with: gdb ' +
81                  self.testcase.vpp_bin + ' ' + core_path)
82
83     def poll_vpp(self):
84         """
85         Poll the vpp status and throw an exception if it's not running
86         :raises VppDiedError: exception if VPP is not running anymore
87         """
88         if self.vpp_dead:
89             # already dead, nothing to do
90             return
91
92         self.testcase.vpp.poll()
93         if self.testcase.vpp.returncode is not None:
94             signaldict = dict(
95                 (k, v) for v, k in reversed(sorted(signal.__dict__.items()))
96                 if v.startswith('SIG') and not v.startswith('SIG_'))
97             msg = "VPP subprocess died unexpectedly with returncode %d [%s]" % (
98                 self.testcase.vpp.returncode,
99                 signaldict[abs(self.testcase.vpp.returncode)])
100             critical(msg)
101             core_path = self.testcase.tempdir + '/core'
102             if os.path.isfile(core_path):
103                 self.on_crash(core_path)
104             self.testcase.vpp_dead = True
105             raise VppDiedError(msg)
106
107     def after_api(self, api_name, api_args):
108         """
109         Check if VPP died after executing an API
110
111         :param api_name: name of the API
112         :param api_args: tuple containing the API arguments
113         :raises VppDiedError: exception if VPP is not running anymore
114
115         """
116         super(PollHook, self).after_api(api_name, api_args)
117         self.poll_vpp()
118
119     def after_cli(self, cli):
120         """
121         Check if VPP died after executing a CLI
122
123         :param cli: CLI string
124         :raises Exception: exception if VPP is not running anymore
125
126         """
127         super(PollHook, self).after_cli(cli)
128         self.poll_vpp()