blob: 9489aa9d8bb8884435fa889fc0e12ec2e26c6572 [file] [log] [blame]
Klement Sekeraf62ae122016-10-11 11:47:09 +02001import signal
2import os
3import pexpect
4from logging import *
5
6
7class 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
47class VppDiedError(Exception):
48 pass
49
50
51class 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()