Skip to content

Commit f02ba8e

Browse files
committed
Reworked tests to detect memory leaks
1 parent a0b7c94 commit f02ba8e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+740
-583
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ install:
2323
- travis_retry pip install -r requirements-test.txt
2424
- travis_retry pip install -e "."
2525
- pip list
26-
script: py.test tests
26+
script: py.test -v tests
2727

2828
before_deploy:
2929
- travis_retry pip install Sphinx

README.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Python bindings for the XML Security Library.
1515
Usage
1616
******
1717

18-
Check the `examples <https://github.com/mehcode/python-xmlsec/tree/master/tests/examples>`_ to see various examples of signing and verifying using the library.
18+
Check the `examples <http://pythonhosted.org/xmlsec/examples>`_ to see various examples of signing and verifying using the library.
1919

2020
************
2121
Requirements
@@ -146,6 +146,9 @@ Running the test suite
146146
147147
py.test tests
148148
149+
3. Tests configuration
150+
Env variable **PYXMLSEC_TEST_ITERATIONS** specifies number of test iterations to detect memory leaks.
151+
149152
Reporting a issue
150153
-----------------
151154
Please attach the output of following information:

tests/base.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import gc
2+
import os
3+
import resource
4+
import sys
5+
6+
from lxml import etree
7+
import xmlsec
8+
9+
import unittest
10+
11+
etype = type(etree.Element("test"))
12+
13+
ns = {'dsig': xmlsec.constants.DSigNs, 'enc': xmlsec.constants.EncNs}
14+
15+
16+
def safe_int(s):
17+
try:
18+
return int(s)
19+
except ValueError:
20+
return 0
21+
22+
23+
class TestMemoryLeaks(unittest.TestCase):
24+
maxDiff = None
25+
26+
iterations = safe_int(os.getenv("PYXMLSEC_TEST_ITERATIONS", "10"))
27+
28+
data_dir = os.path.join(os.path.dirname(__file__), "data")
29+
30+
def setUp(self):
31+
gc.disable()
32+
self.addTypeEqualityFunc(etype, "assertXmlEqual")
33+
xmlsec.enable_debug_trace(1)
34+
35+
def run(self, result=None):
36+
# run first time
37+
super(TestMemoryLeaks, self).run(result=result)
38+
if self.iterations == 0:
39+
return
40+
41+
m_usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
42+
o_count = gc.get_count()[0]
43+
m_hits = 0
44+
o_hits = 0
45+
for i in range(self.iterations):
46+
super(TestMemoryLeaks, self).run(result=result)
47+
m_usage_n = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
48+
if m_usage_n > m_usage:
49+
m_usage = m_usage_n
50+
m_hits += 1
51+
o_count_n = gc.get_count()[0]
52+
if o_count_n > o_count:
53+
o_count = o_count_n
54+
o_hits += 1
55+
del m_usage_n
56+
del o_count_n
57+
58+
if m_hits > int(self.iterations * 0.8):
59+
result.buffer = False
60+
try:
61+
raise AssertionError("memory leak detected")
62+
except AssertionError:
63+
result.addError(self, sys.exc_info())
64+
if o_hits > int(self.iterations * 0.8):
65+
result.buffer = False
66+
try:
67+
raise AssertionError("unreferenced objects detected")
68+
except AssertionError:
69+
result.addError(self, sys.exc_info())
70+
71+
def path(self, name):
72+
"""returns full path for resource"""
73+
return os.path.join(self.data_dir, name)
74+
75+
def load(self, name):
76+
"""loads resource by name"""
77+
with open(self.path(name), "rb") as stream:
78+
return stream.read()
79+
80+
def load_xml(self, name, xpath=None):
81+
"""returns xml.etree"""
82+
root = etree.parse(self.path(name)).getroot()
83+
if xpath is None:
84+
return root
85+
return root.find(xpath)
86+
87+
def dump(self, root):
88+
print(etree.tostring(root))
89+
90+
def assertXmlEqual(self, first, second, msg=None):
91+
"""Checks equality of etree.roots"""
92+
msg = msg or ''
93+
if first.tag != second.tag:
94+
self.fail('Tags do not match: %s and %s. %s' % (first.tag, second.tag, msg))
95+
for name, value in first.attrib.items():
96+
if second.attrib.get(name) != value:
97+
self.fail(
98+
'Attributes do not match: %s=%r, %s=%r. %s' % (name, value, name, second.attrib.get(name), msg)
99+
)
100+
for name in second.attrib.keys():
101+
if name not in first.attrib:
102+
self.fail('x2 has an attribute x1 is missing: %s. %s' % (name, msg))
103+
if not xml_text_compare(first.text, second.text):
104+
self.fail('text: %r != %r. %s' % (first.text, second.text, msg))
105+
if not xml_text_compare(first.tail, second.tail):
106+
self.fail('tail: %r != %r. %s' % (first.tail, second.tail, msg))
107+
cl1 = first.getchildren()
108+
cl2 = second.getchildren()
109+
if len(cl1) != len(cl2):
110+
self.fail('children length differs, %i != %i. %s' % (len(cl1), len(cl2), msg))
111+
i = 0
112+
for c1, c2 in zip(cl1, cl2):
113+
i += 1
114+
self.assertXmlEqual(c1, c2)
115+
116+
117+
def xml_text_compare(t1, t2):
118+
if not t1 and not t2:
119+
return True
120+
if t1 == '*' or t2 == '*':
121+
return True
122+
return (t1 or '').strip() == (t2 or '').strip()

tests/conftest.py

Lines changed: 0 additions & 9 deletions
This file was deleted.

tests/data/deskey.bin

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
012345670123456701234567

tests/data/dsacert.der

1.06 KB
Binary file not shown.

tests/data/dsakey.der

250 Bytes
Binary file not shown.

tests/data/enc1-in.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
XML Security Library example: Original XML doc file for enc example.
4+
-->
5+
<Envelope>
6+
<Data>Hello, World!</Data>
7+
</Envelope>

0 commit comments

Comments
 (0)