|
1
|
|
|
"""Test HTTP capabilities of the logger.""" |
|
2
|
|
|
|
|
3
|
1 |
|
import json |
|
4
|
1 |
|
import sqlite3 |
|
5
|
1 |
|
import tempfile |
|
6
|
|
|
|
|
7
|
1 |
|
from ppp_logger.logger import make_responses_forest, freeze |
|
8
|
1 |
|
from ppp_logger import app |
|
9
|
1 |
|
from ppp_libmodule.tests import PPPTestCase |
|
10
|
|
|
|
|
11
|
1 |
|
R = lambda x:{'type': 'resource', 'value': x} |
|
12
|
1 |
|
def to_trace(x): # Copy object and remove trace |
|
13
|
1 |
|
y = x.copy() # Shallow copy |
|
14
|
1 |
|
y['module'] = str(len(y['tree']['value'])) |
|
15
|
1 |
|
del y['trace'] |
|
16
|
1 |
|
return y |
|
17
|
1 |
|
def striptraces(obj): |
|
18
|
1 |
|
if isinstance(obj, list): |
|
19
|
1 |
|
return list(map(striptraces, obj)) |
|
20
|
1 |
|
elif isinstance(obj, dict): |
|
21
|
1 |
|
return {x:striptraces(y) for (x,y) in obj.items() if x != 'trace'} |
|
22
|
1 |
|
elif isinstance(obj, tuple): |
|
23
|
1 |
|
return tuple(map(striptraces, obj)) |
|
24
|
|
|
else: |
|
25
|
1 |
|
return obj |
|
26
|
1 |
|
m = lambda x:{'tree': R(x), 'measures': {}} |
|
27
|
|
|
|
|
28
|
1 |
|
def build_responses(): |
|
29
|
|
|
""" |
|
30
|
|
|
one |
|
31
|
|
|
+- two |
|
32
|
|
|
| +- three |
|
33
|
|
|
| | +- four |
|
34
|
|
|
| +- five |
|
35
|
|
|
+- six |
|
36
|
|
|
| +- seven |
|
37
|
|
|
eight |
|
38
|
|
|
nine |
|
39
|
|
|
""" |
|
40
|
1 |
|
one = {'tree': R('one'), 'measures': {}, 'trace': []} |
|
41
|
1 |
|
two = {'tree': R('two'), 'measures': {}, 'trace': [to_trace(one)]} |
|
42
|
1 |
|
three = {'tree': R('three'), 'measures': {}, 'trace': [to_trace(one), to_trace(two)]} |
|
43
|
1 |
|
four = {'tree': R('four'), 'measures': {}, 'trace': [to_trace(one), to_trace(two), to_trace(three)]} |
|
44
|
1 |
|
five = {'tree': R('five'), 'measures': {}, 'trace': [to_trace(one), to_trace(two)]} |
|
45
|
1 |
|
six = {'tree': R('six'), 'measures': {}, 'trace': [to_trace(one)]} |
|
46
|
1 |
|
seven = {'tree': R('seven'), 'measures': {}, 'trace': [to_trace(one), to_trace(six)]} |
|
47
|
1 |
|
eight = {'tree': R('eight'), 'measures': {}, 'trace': []} |
|
48
|
1 |
|
nine = {'tree': R('nine'), 'measures': {}, 'trace': []} |
|
49
|
1 |
|
L = [one, two, three, four, five, six, seven, eight, nine] |
|
50
|
1 |
|
for x in L: |
|
51
|
1 |
|
x['trace'].append({'tree': x['tree'], 'measures': x['measures'], |
|
52
|
|
|
'module': str(len(x['tree']['value']))}) |
|
53
|
1 |
|
return L |
|
54
|
|
|
|
|
55
|
1 |
|
def notrace(obj): |
|
56
|
1 |
|
if isinstance(obj, list) or isinstance(obj, tuple): |
|
57
|
1 |
|
return all(map(notrace, obj)) |
|
58
|
1 |
|
elif isinstance(obj, dict): |
|
59
|
1 |
|
return 'trace' not in obj and all(map(notrace, obj)) |
|
60
|
|
|
else: |
|
61
|
1 |
|
return True |
|
62
|
|
|
|
|
63
|
1 |
|
class LoggerTest(PPPTestCase(app)): |
|
64
|
1 |
|
config_var = 'PPP_LOGGER_CONFIG' |
|
65
|
1 |
|
def setUp(self): |
|
66
|
1 |
|
self.fd = tempfile.NamedTemporaryFile('w+') |
|
67
|
1 |
|
self.config = '{"database_url": "sqlite:///%s"}' % self.fd.name |
|
68
|
1 |
|
super(LoggerTest, self).setUp() |
|
69
|
1 |
|
def tearDown(self): |
|
70
|
1 |
|
super(LoggerTest, self).tearDown() |
|
71
|
1 |
|
self.fd.close() |
|
72
|
1 |
|
def testTree(self): |
|
73
|
|
|
# Only the last assertEqual would be enough, actually. |
|
74
|
|
|
# But the previous assertions makes it easier to debug (more precise |
|
75
|
|
|
# informations on was is going wrong). |
|
76
|
1 |
|
tree = make_responses_forest(build_responses()) |
|
77
|
1 |
|
tree = striptraces(tree) |
|
78
|
1 |
|
self.assertTrue(notrace(tree), tree) |
|
79
|
1 |
|
self.assertEqual(len(tree), 3, [x['tree']['value'] for (x,y) in tree]) |
|
80
|
1 |
|
self.assertEqual(tree, [ |
|
81
|
|
|
(m('one'), [ |
|
82
|
|
|
(m('two'), [ |
|
83
|
|
|
(m('three'), [ |
|
84
|
|
|
(m('four'), [ |
|
85
|
|
|
]), |
|
86
|
|
|
]), |
|
87
|
|
|
(m('five'), [ |
|
88
|
|
|
]), |
|
89
|
|
|
]), |
|
90
|
|
|
(m('six'), [ |
|
91
|
|
|
(m('seven'), [ |
|
92
|
|
|
]), |
|
93
|
|
|
]), |
|
94
|
|
|
]), |
|
95
|
|
|
(m('eight'), [ |
|
96
|
|
|
]), |
|
97
|
|
|
(m('nine'), [ |
|
98
|
|
|
]), |
|
99
|
|
|
]) |
|
100
|
|
|
|
|
101
|
1 |
|
def testLog(self): |
|
102
|
1 |
|
question = 'question?' |
|
103
|
1 |
|
responses = build_responses() |
|
104
|
1 |
|
q = {'id': 'foo', 'question': question, |
|
105
|
|
|
'responses': responses} |
|
106
|
1 |
|
self.assertStatusInt(q, 200) |
|
107
|
1 |
|
conn = sqlite3.connect(self.fd.name) |
|
108
|
1 |
|
with conn: |
|
109
|
1 |
|
r = conn.execute('SELECT response_id, parent_response_id, response_tree FROM responses;').fetchall() |
|
110
|
1 |
|
fields = ('id', 'parent', 'tree') |
|
111
|
1 |
|
zipper = lambda x:(x[0], {'id': x[0], 'parent': x[1], |
|
112
|
|
|
'tree': json.loads(x[2])}) |
|
113
|
1 |
|
r = dict(map(zipper, r)) |
|
114
|
1 |
|
self.assertEqual(len(r), 9, r) |
|
115
|
1 |
|
for x in r.values(): |
|
116
|
1 |
|
if x['tree']['value'] in ('three', 'five'): |
|
117
|
1 |
|
self.assertNotEqual(x['parent'], None) |
|
118
|
1 |
|
parent = r[x['parent']] |
|
119
|
1 |
|
self.assertEqual(parent['tree']['value'], 'two') |
|
120
|
|
|
|
|
121
|
1 |
|
def testTraceItemMissingFromResponses(self): |
|
122
|
|
|
# This was a bug caused by the WebUI putting the input in the trace |
|
123
|
|
|
# without putting it as a response |
|
124
|
1 |
|
i = r'''{"id":"1417024784682-682-12-webui","question":"sqrt(2)","responses":[{"measures":{"accuracy":0.5,"relevance":0.1},"trace":[{"measures":{"accuracy":1,"relevance":0},"module":"input","tree":{"type":"sentence","value":"sqrt(2)"}},{"measures":{"accuracy":0.5,"relevance":0.1},"module":"spell-checker","tree":{"value":"sq rt 2","type":"sentence"}}],"tree":{"value":"sq rt 2","type":"sentence"},"language":"en"}]}''' |
|
125
|
1 |
|
q = json.loads(i) |
|
126
|
|
|
self.assertStatusInt(q, 200) |
|
127
|
|
|
|