testing/mozbase/mozcrash/tests/test.py

changeset 2
7e26c7da4463
equal deleted inserted replaced
-1:000000000000 0:0d4c59ae5b5b
1 #!/usr/bin/env python
2 #
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 # You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 import os, unittest, subprocess, tempfile, shutil, urlparse, zipfile, StringIO
8 import mozcrash, mozlog, mozhttpd
9
10 # Make logs go away
11 log = mozlog.getLogger("mozcrash", handler=mozlog.FileHandler(os.devnull))
12
13 def popen_factory(stdouts):
14 """
15 Generate a class that can mock subprocess.Popen. |stdouts| is an iterable that
16 should return an iterable for the stdout of each process in turn.
17 """
18 class mock_popen(object):
19 def __init__(self, args, *args_rest, **kwargs):
20 self.stdout = stdouts.next()
21 self.returncode = 0
22
23 def wait(self):
24 return 0
25
26 def communicate(self):
27 return (self.stdout.next(), "")
28
29 return mock_popen
30
31 class TestCrash(unittest.TestCase):
32 def setUp(self):
33 self.tempdir = tempfile.mkdtemp()
34 # a fake file to use as a stackwalk binary
35 self.stackwalk = os.path.join(self.tempdir, "stackwalk")
36 open(self.stackwalk, "w").write("fake binary")
37 self._subprocess_popen = subprocess.Popen
38 subprocess.Popen = popen_factory(self.next_mock_stdout())
39 self.stdouts = []
40
41 def tearDown(self):
42 subprocess.Popen = self._subprocess_popen
43 shutil.rmtree(self.tempdir)
44
45 def next_mock_stdout(self):
46 if not self.stdouts:
47 yield iter([])
48 for s in self.stdouts:
49 yield iter(s)
50
51 def test_nodumps(self):
52 """
53 Test that check_for_crashes returns False if no dumps are present.
54 """
55 self.stdouts.append(["this is some output"])
56 self.assertFalse(mozcrash.check_for_crashes(self.tempdir,
57 'symbols_path',
58 stackwalk_binary=self.stackwalk,
59 quiet=True))
60
61 def test_simple(self):
62 """
63 Test that check_for_crashes returns True if a dump is present.
64 """
65 open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
66 self.stdouts.append(["this is some output"])
67 self.assert_(mozcrash.check_for_crashes(self.tempdir,
68 'symbols_path',
69 stackwalk_binary=self.stackwalk,
70 quiet=True))
71
72 def test_stackwalk_envvar(self):
73 """
74 Test that check_for_crashes uses the MINIDUMP_STACKWALK environment var.
75 """
76 open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
77 self.stdouts.append(["this is some output"])
78 os.environ['MINIDUMP_STACKWALK'] = self.stackwalk
79 self.assert_(mozcrash.check_for_crashes(self.tempdir,
80 'symbols_path',
81 quiet=True))
82 del os.environ['MINIDUMP_STACKWALK']
83
84 def test_save_path(self):
85 """
86 Test that dump_save_path works.
87 """
88 open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
89 open(os.path.join(self.tempdir, "test.extra"), "w").write("bar")
90 save_path = os.path.join(self.tempdir, "saved")
91 os.mkdir(save_path)
92 self.stdouts.append(["this is some output"])
93 self.assert_(mozcrash.check_for_crashes(self.tempdir,
94 'symbols_path',
95 stackwalk_binary=self.stackwalk,
96 dump_save_path=save_path,
97 quiet=True))
98 self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
99 self.assert_(os.path.isfile(os.path.join(save_path, "test.extra")))
100
101 def test_save_path_not_present(self):
102 """
103 Test that dump_save_path works when the directory doesn't exist.
104 """
105 open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
106 open(os.path.join(self.tempdir, "test.extra"), "w").write("bar")
107 save_path = os.path.join(self.tempdir, "saved")
108 self.stdouts.append(["this is some output"])
109 self.assert_(mozcrash.check_for_crashes(self.tempdir,
110 'symbols_path',
111 stackwalk_binary=self.stackwalk,
112 dump_save_path=save_path,
113 quiet=True))
114 self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
115 self.assert_(os.path.isfile(os.path.join(save_path, "test.extra")))
116
117 def test_save_path_isfile(self):
118 """
119 Test that dump_save_path works when the directory doesn't exist,
120 but a file with the same name exists.
121 """
122 open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
123 open(os.path.join(self.tempdir, "test.extra"), "w").write("bar")
124 save_path = os.path.join(self.tempdir, "saved")
125 open(save_path, "w").write("junk")
126 self.stdouts.append(["this is some output"])
127 self.assert_(mozcrash.check_for_crashes(self.tempdir,
128 'symbols_path',
129 stackwalk_binary=self.stackwalk,
130 dump_save_path=save_path,
131 quiet=True))
132 self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
133 self.assert_(os.path.isfile(os.path.join(save_path, "test.extra")))
134
135 def test_save_path_envvar(self):
136 """
137 Test that the MINDUMP_SAVE_PATH environment variable works.
138 """
139 open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
140 open(os.path.join(self.tempdir, "test.extra"), "w").write("bar")
141 save_path = os.path.join(self.tempdir, "saved")
142 os.mkdir(save_path)
143 self.stdouts.append(["this is some output"])
144 os.environ['MINIDUMP_SAVE_PATH'] = save_path
145 self.assert_(mozcrash.check_for_crashes(self.tempdir,
146 'symbols_path',
147 stackwalk_binary=self.stackwalk,
148 quiet=True))
149 del os.environ['MINIDUMP_SAVE_PATH']
150 self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
151 self.assert_(os.path.isfile(os.path.join(save_path, "test.extra")))
152
153 def test_symbol_path_url(self):
154 """
155 Test that passing a URL as symbols_path correctly fetches the URL.
156 """
157 open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
158 self.stdouts.append(["this is some output"])
159
160 def make_zipfile():
161 data = StringIO.StringIO()
162 z = zipfile.ZipFile(data, 'w')
163 z.writestr("symbols.txt", "abc/xyz")
164 z.close()
165 return data.getvalue()
166 def get_symbols(req):
167 headers = {}
168 return (200, headers, make_zipfile())
169 httpd = mozhttpd.MozHttpd(port=0,
170 urlhandlers=[{'method':'GET', 'path':'/symbols', 'function':get_symbols}])
171 httpd.start()
172 symbol_url = urlparse.urlunsplit(('http', '%s:%d' % httpd.httpd.server_address,
173 '/symbols','',''))
174 self.assert_(mozcrash.check_for_crashes(self.tempdir,
175 symbol_url,
176 stackwalk_binary=self.stackwalk,
177 quiet=True))
178
179 class TestJavaException(unittest.TestCase):
180 def setUp(self):
181 self.test_log = ["01-30 20:15:41.937 E/GeckoAppShell( 1703): >>> REPORTING UNCAUGHT EXCEPTION FROM THREAD 9 (\"GeckoBackgroundThread\")",
182 "01-30 20:15:41.937 E/GeckoAppShell( 1703): java.lang.NullPointerException",
183 "01-30 20:15:41.937 E/GeckoAppShell( 1703): at org.mozilla.gecko.GeckoApp$21.run(GeckoApp.java:1833)",
184 "01-30 20:15:41.937 E/GeckoAppShell( 1703): at android.os.Handler.handleCallback(Handler.java:587)"]
185
186 def test_uncaught_exception(self):
187 """
188 Test for an exception which should be caught
189 """
190 self.assert_(mozcrash.check_for_java_exception(self.test_log, quiet=True))
191
192 def test_fatal_exception(self):
193 """
194 Test for an exception which should be caught
195 """
196 fatal_log = list(self.test_log)
197 fatal_log[0] = "01-30 20:15:41.937 E/GeckoAppShell( 1703): >>> FATAL EXCEPTION FROM THREAD 9 (\"GeckoBackgroundThread\")"
198 self.assert_(mozcrash.check_for_java_exception(fatal_log, quiet=True))
199
200 def test_truncated_exception(self):
201 """
202 Test for an exception which should be caught which
203 was truncated
204 """
205 truncated_log = list(self.test_log)
206 truncated_log[0], truncated_log[1] = truncated_log[1], truncated_log[0]
207 self.assert_(mozcrash.check_for_java_exception(truncated_log, quiet=True))
208
209 def test_unchecked_exception(self):
210 """
211 Test for an exception which should not be caught
212 """
213 passable_log = list(self.test_log)
214 passable_log[0] = "01-30 20:15:41.937 E/GeckoAppShell( 1703): >>> NOT-SO-BAD EXCEPTION FROM THREAD 9 (\"GeckoBackgroundThread\")"
215 self.assert_(not mozcrash.check_for_java_exception(passable_log, quiet=True))
216
217 if __name__ == '__main__':
218 unittest.main()

mercurial