Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Commit 04b96f2

Browse files
author
w-vi
committed
(fix) Attempt to improve exception handling of ValueError
Fixes #43 Unfortunatelly it is hard to propagate exceptions from hook files without propagating hook handler exceptions too. This attempt tries to propagate everything but json decoding errors which are manifestation of either the connection being closed or some internal error. If anybody knows a better solution I am happy to hear about it.
1 parent 281fe27 commit 04b96f2

File tree

2 files changed

+148
-6
lines changed

2 files changed

+148
-6
lines changed

dredd_hooks/dredd.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,18 @@ def handle(self):
109109
self.wfile.write(msg.encode('utf-8'))
110110
else:
111111
self.wfile.write(msg)
112-
except ValueError:
113-
print("\nConnection closed\n", file=sys.stderr)
114-
except Exception:
115-
traceback.print_exc(file=sys.stderr)
116-
sys.stderr.flush()
117-
raise
112+
113+
except Exception as e:
114+
if sys.version_info[0] > 2 and isinstance(e, json.JSONDecodeError):
115+
print('Connection closed, could not parse JSON',
116+
file=sys.stderr)
117+
elif str(e) == "No JSON object could be decoded":
118+
print('Connection closed, could not parse JSON',
119+
file=sys.stderr)
120+
else:
121+
traceback.print_exc(file=sys.stderr)
122+
sys.stderr.flush()
123+
raise
118124

119125

120126
def add_named_hook(obj, hook, name):

test/test_excepts_hook.py

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
from __future__ import print_function
4+
import unittest
5+
import sys
6+
import socket
7+
import os
8+
import json
9+
import threading
10+
import time
11+
import dredd_hooks as hooks
12+
if sys.version_info[0] > 2:
13+
import io
14+
else:
15+
import StringIO as io
16+
17+
hooks_thr = None
18+
19+
20+
class Connection(object):
21+
22+
def __init__(self):
23+
self.connection = socket.create_connection((hooks.HOST, hooks.PORT))
24+
self.rfile = self.connection.makefile('rb', -1) # buffered input
25+
self.wfile = self.connection.makefile('wb', 0) # unbuffered output
26+
27+
def writeline(self, msg):
28+
msg = msg + hooks.MESSAGE_DELIMITER
29+
if sys.version_info[0] > 2:
30+
self.wfile.write(msg.encode('utf-8'))
31+
else:
32+
self.wfile.write(msg)
33+
34+
def readline(self):
35+
if sys.version_info[0] > 2:
36+
return self.rfile.readline().decode('utf-8').strip()
37+
else:
38+
return self.rfile.readline().strip()
39+
40+
def close(self):
41+
self.rfile.close()
42+
self.wfile.close()
43+
self.connection.close()
44+
45+
46+
class TestValueError(unittest.TestCase):
47+
"""
48+
Tests exception handling.
49+
"""
50+
@classmethod
51+
def setUpClass(cls):
52+
cls.output = io.StringIO()
53+
cls.saved_stderr = sys.stderr
54+
sys.stderr = cls.output
55+
cls.hooks_thr = threading.Thread(target=hooks.main,
56+
args=([os.path.abspath(__file__)],))
57+
cls.hooks_thr.start()
58+
time.sleep(1)
59+
cls.conn = Connection()
60+
61+
@classmethod
62+
def tearDownClass(cls):
63+
cls.output.close()
64+
sys.stderr = cls.saved_stderr
65+
cls.conn.close()
66+
hooks.shutdown()
67+
cls.hooks_thr.join()
68+
69+
def setUp(self):
70+
self.conn.writeline(json.dumps({"event": "beforeAll", "data": [{}]}))
71+
try:
72+
json.loads(self.conn.readline())
73+
except Exception:
74+
pass
75+
76+
def tearDown(self):
77+
pass
78+
79+
def test_output(self):
80+
out = self.output.getvalue()
81+
self.assertNotEqual(out.find('ValueErrorRaised'), -1)
82+
83+
84+
class TestGenericException(unittest.TestCase):
85+
"""
86+
Tests exception handling.
87+
"""
88+
@classmethod
89+
def setUpClass(cls):
90+
cls.output = io.StringIO()
91+
cls.saved_stderr = sys.stderr
92+
sys.stderr = cls.output
93+
cls.hooks_thr = threading.Thread(target=hooks.main,
94+
args=([os.path.abspath(__file__)],))
95+
cls.hooks_thr.start()
96+
time.sleep(1)
97+
cls.conn = Connection()
98+
99+
@classmethod
100+
def tearDownClass(cls):
101+
cls.output.close()
102+
sys.stderr = cls.saved_stderr
103+
cls.conn.close()
104+
hooks.shutdown()
105+
cls.hooks_thr.join()
106+
107+
def setUp(self):
108+
self.conn.writeline(json.dumps({"event": "afterAll", "data": [{}]}))
109+
try:
110+
json.loads(self.conn.readline())
111+
except Exception:
112+
pass
113+
114+
def tearDown(self):
115+
pass
116+
117+
def test_output(self):
118+
out = self.output.getvalue()
119+
self.assertNotEqual(out.find("ExceptionRaised"), -1)
120+
121+
122+
@hooks.before_all
123+
def before_all_test(transactions):
124+
raise ValueError("ValueErrorRaised")
125+
126+
127+
@hooks.after_all
128+
def after_all_test(transactions):
129+
raise Exception("ExceptionRaised")
130+
131+
132+
if __name__ == '__main__':
133+
try:
134+
unittest.main()
135+
except Exception as e:
136+
exit(-1)

0 commit comments

Comments
 (0)