test_error.py: remove dangling print()
[babeltrace.git] / tests / bindings / python / bt2 / test_error.py
CommitLineData
ce4923b0
SM
1#
2# Copyright (C) 2019 EfficiOS Inc.
3#
4# This program is free software; you can redistribute it and/or
5# modify it under the terms of the GNU General Public License
6# as published by the Free Software Foundation; only version 2
7# of the License.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17#
18
19from bt2 import native_bt
20import bt2
21import unittest
22
23
24class FailingIter(bt2._UserMessageIterator):
25 def __next__(self):
26 raise ValueError('User message iterator is failing')
27
28
29class SourceWithFailingIter(
30 bt2._UserSourceComponent, message_iterator_class=FailingIter
31):
32 def __init__(self, params):
33 self._add_output_port('out')
34
35
36class SourceWithFailingInit(
37 bt2._UserSourceComponent, message_iterator_class=FailingIter
38):
39 def __init__(self, params):
40 raise ValueError('Source is failing')
41
42
43class WorkingSink(bt2._UserSinkComponent):
44 def __init__(self, params):
45 self._in = self._add_input_port('in')
46
47 def _graph_is_configured(self):
ca02df0a 48 self._iter = self._create_input_port_message_iterator(self._in)
ce4923b0
SM
49
50 def _consume(self):
51 next(self._iter)
52
53
54class SinkWithExceptionChaining(bt2._UserSinkComponent):
55 def __init__(self, params):
56 self._in = self._add_input_port('in')
57
58 def _graph_is_configured(self):
ca02df0a 59 self._iter = self._create_input_port_message_iterator(self._in)
ce4923b0
SM
60
61 def _consume(self):
62 try:
ce4923b0 63 next(self._iter)
694c792b 64 except bt2._Error as e:
ce4923b0
SM
65 raise ValueError('oops') from e
66
67
68class SinkWithFailingQuery(bt2._UserSinkComponent):
69 def _graph_is_configured(self):
70 pass
71
72 def _consume(self):
73 pass
74
75 @staticmethod
76 def _query(executor, obj, params, log_level):
77 raise ValueError('Query is failing')
78
79
80class ErrorTestCase(unittest.TestCase):
81 def _run_failing_graph(self, source_cc, sink_cc):
694c792b 82 with self.assertRaises(bt2._Error) as ctx:
ce4923b0
SM
83 graph = bt2.Graph()
84 src = graph.add_component(source_cc, 'src')
85 snk = graph.add_component(sink_cc, 'snk')
86 graph.connect_ports(src.output_ports['out'], snk.input_ports['in'])
87 graph.run()
88
89 return ctx.exception
90
91 def test_current_thread_error_none(self):
694c792b 92 # When a bt2._Error is raised, it steals the current thread's error.
ce4923b0
SM
93 # Verify that it is now NULL.
94 exc = self._run_failing_graph(SourceWithFailingInit, WorkingSink)
95 self.assertIsNone(native_bt.current_thread_take_error())
96
97 def test_len(self):
98 exc = self._run_failing_graph(SourceWithFailingIter, WorkingSink)
99
100 # The exact number of causes is not too important (it can change if we
101 # append more or less causes along the way), but the idea is to verify is
102 # has a value that makes sense.
103 self.assertEqual(len(exc), 4)
104
105 def test_iter(self):
106 exc = self._run_failing_graph(SourceWithFailingIter, WorkingSink)
107
108 for c in exc:
109 # Each cause is an instance of _ErrorCause (including subclasses).
110 self.assertIsInstance(c, bt2.error._ErrorCause)
111
112 def test_getitem(self):
113 exc = self._run_failing_graph(SourceWithFailingIter, WorkingSink)
114
115 for i in range(len(exc)):
116 c = exc[i]
117 # Each cause is an instance of _ErrorCause (including subclasses).
118 self.assertIsInstance(c, bt2.error._ErrorCause)
119
120 def test_getitem_indexerror(self):
121 exc = self._run_failing_graph(SourceWithFailingIter, WorkingSink)
122
123 with self.assertRaises(IndexError):
124 exc[len(exc)]
125
126 def test_exception_chaining(self):
127 # Test that if we do:
128 #
129 # try:
130 # ...
694c792b 131 # except bt2._Error as exc:
ce4923b0
SM
132 # raise ValueError('oh noes') from exc
133 #
694c792b 134 # We are able to fetch the causes of the original bt2._Error in the
ce4923b0
SM
135 # exception chain. Also, each exception in the chain should become one
136 # cause once caught.
137 exc = self._run_failing_graph(SourceWithFailingIter, SinkWithExceptionChaining)
138
139 self.assertEqual(len(exc), 5)
140
141 self.assertIsInstance(exc[0], bt2.error._MessageIteratorErrorCause)
142 self.assertEqual(exc[0].component_class_name, 'SourceWithFailingIter')
143 self.assertIn('ValueError: User message iterator is failing', exc[0].message)
144
145 self.assertIsInstance(exc[1], bt2.error._ErrorCause)
146
147 self.assertIsInstance(exc[2], bt2.error._ComponentErrorCause)
148 self.assertEqual(exc[2].component_class_name, 'SinkWithExceptionChaining')
149 self.assertIn(
694c792b 150 'bt2.error._Error: unexpected error: cannot advance the message iterator',
ce4923b0
SM
151 exc[2].message,
152 )
153
154 self.assertIsInstance(exc[3], bt2.error._ComponentErrorCause)
155 self.assertEqual(exc[3].component_class_name, 'SinkWithExceptionChaining')
156 self.assertIn('ValueError: oops', exc[3].message)
157
158 self.assertIsInstance(exc[4], bt2.error._ErrorCause)
159
160 def _common_cause_tests(self, cause):
161 self.assertIsInstance(cause.module_name, str)
162 self.assertIsInstance(cause.file_name, str)
163 self.assertIsInstance(cause.line_number, int)
164
165 def test_unknown_error_cause(self):
166 exc = self._run_failing_graph(SourceWithFailingIter, SinkWithExceptionChaining)
167 cause = exc[-1]
168 self.assertIs(type(cause), bt2.error._ErrorCause)
169 self._common_cause_tests(cause)
170
171 def test_component_error_cause(self):
172 exc = self._run_failing_graph(SourceWithFailingInit, SinkWithExceptionChaining)
173 cause = exc[0]
174 self.assertIs(type(cause), bt2.error._ComponentErrorCause)
175 self._common_cause_tests(cause)
176
177 self.assertIn('Source is failing', cause.message)
178 self.assertEqual(cause.component_name, 'src')
179 self.assertEqual(cause.component_class_type, bt2.ComponentClassType.SOURCE)
180 self.assertEqual(cause.component_class_name, 'SourceWithFailingInit')
181 self.assertIsNone(cause.plugin_name)
182
183 def test_component_class_error_cause(self):
184 q = bt2.QueryExecutor()
185
694c792b 186 with self.assertRaises(bt2._Error) as ctx:
ce4923b0
SM
187 q.query(SinkWithFailingQuery, 'hello')
188
189 cause = ctx.exception[0]
190 self.assertIs(type(cause), bt2.error._ComponentClassErrorCause)
191 self._common_cause_tests(cause)
192
193 self.assertIn('Query is failing', cause.message)
194
195 self.assertEqual(cause.component_class_type, bt2.ComponentClassType.SINK)
196 self.assertEqual(cause.component_class_name, 'SinkWithFailingQuery')
197 self.assertIsNone(cause.plugin_name)
198
199 def test_message_iterator_error_cause(self):
200 exc = self._run_failing_graph(SourceWithFailingIter, SinkWithExceptionChaining)
201 cause = exc[0]
202 self.assertIs(type(cause), bt2.error._MessageIteratorErrorCause)
203 self._common_cause_tests(cause)
204
205 self.assertIn('User message iterator is failing', cause.message)
206 self.assertEqual(cause.component_name, 'src')
207 self.assertEqual(cause.component_output_port_name, 'out')
208 self.assertEqual(cause.component_class_type, bt2.ComponentClassType.SOURCE)
209 self.assertEqual(cause.component_class_name, 'SourceWithFailingIter')
210 self.assertIsNone(cause.plugin_name)
This page took 0.029911 seconds and 4 git commands to generate.