Mercurial > bzapi
annotate test.py @ 30:6b0a17f31342
we should work w/ python 2.6+ now
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Thu, 24 Dec 2009 14:27:56 -0800 |
parents | ce19838a318d |
children |
rev | line source |
---|---|
6 | 1 import unittest |
10
2731713f61a8
added more tests and a totally untested 'observer' mechanism
Atul Varma <varmaa@toolness.com>
parents:
6
diff
changeset
|
2 import StringIO |
22
01b054bc3a27
added a non-trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
21
diff
changeset
|
3 from copy import deepcopy |
26 | 4 from datetime import datetime, timedelta |
10
2731713f61a8
added more tests and a totally untested 'observer' mechanism
Atul Varma <varmaa@toolness.com>
parents:
6
diff
changeset
|
5 |
16
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
6 import pymongo |
10
2731713f61a8
added more tests and a totally untested 'observer' mechanism
Atul Varma <varmaa@toolness.com>
parents:
6
diff
changeset
|
7 import bzapi |
2731713f61a8
added more tests and a totally untested 'observer' mechanism
Atul Varma <varmaa@toolness.com>
parents:
6
diff
changeset
|
8 |
30
6b0a17f31342
we should work w/ python 2.6+ now
Atul Varma <varmaa@toolness.com>
parents:
28
diff
changeset
|
9 # Easier than having to duplicate import logic... |
6b0a17f31342
we should work w/ python 2.6+ now
Atul Varma <varmaa@toolness.com>
parents:
28
diff
changeset
|
10 json = bzapi.json |
6b0a17f31342
we should work w/ python 2.6+ now
Atul Varma <varmaa@toolness.com>
parents:
28
diff
changeset
|
11 |
16
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
12 connection = pymongo.Connection('localhost', 27017) |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
13 testdb = connection.bzapi_testing_db |
10
2731713f61a8
added more tests and a totally untested 'observer' mechanism
Atul Varma <varmaa@toolness.com>
parents:
6
diff
changeset
|
14 |
28
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
15 class MiscTests(unittest.TestCase): |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
16 def test_split_seq_with_tiny_seq(self): |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
17 self.assertEqual(repr(bzapi.split_seq([1], 2)), |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
18 '[[1]]') |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
19 |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
20 def test_split_seq_with_imperfect_split(self): |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
21 self.assertEqual(repr(bzapi.split_seq([1,2,3,4,5], 2)), |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
22 '[[1, 2], [3, 4], [5]]') |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
23 |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
24 def test_split_seq_with_perfect_split(self): |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
25 self.assertEqual(repr(bzapi.split_seq([1,2,3,4], 2)), |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
26 '[[1, 2], [3, 4]]') |
ce19838a318d
we now split large batches of bugs into small segments of 10 each
Atul Varma <varmaa@toolness.com>
parents:
26
diff
changeset
|
27 |
16
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
28 class TimestampTests(unittest.TestCase): |
6 | 29 def test_datetime_from_iso(self): |
30 date = bzapi.datetime_from_iso('2009-06-11T22:31:24Z') | |
31 self.assertEqual(str(date), '2009-06-11 22:31:24') | |
32 | |
33 def test_datetime_from_rfc1123(self): | |
34 date = bzapi.datetime_from_rfc1123('Wed, 23 Dec 2009 20:42:59 GMT') | |
35 self.assertEqual(str(date), '2009-12-23 20:42:59') | |
36 | |
16
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
37 class OpenUrlTests(unittest.TestCase): |
19 | 38 class FakeUrllib2(object): |
39 class FakeRequest(object): | |
40 def __init__(self, url): | |
41 self.url = url | |
42 | |
43 def add_header(self, name, value): | |
44 pass | |
45 | |
46 def __init__(self): | |
47 self._responses = {} | |
48 | |
49 def Request(self, url): | |
50 return self.FakeRequest(url) | |
51 | |
52 def set_url(self, url, response): | |
53 if not isinstance(response, basestring): | |
54 response = json.dumps(response) | |
55 self._responses[url] = response | |
56 | |
57 def urlopen(self, request): | |
58 return StringIO.StringIO(self._responses[request.url]) | |
59 | |
13
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
60 def test_open_url_works_without_query_args(self): |
19 | 61 urllib2 = self.FakeUrllib2() |
13
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
62 urllib2.set_url('http://foo/', 'boo') |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
63 self.assertEqual( |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
64 bzapi.open_url(url='http://foo/', |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
65 headers={'Content-Type': 'text/plain'}, |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
66 urllib2=urllib2).read(), |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
67 'boo' |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
68 ) |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
69 |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
70 def test_open_url_works_with_query_args(self): |
19 | 71 urllib2 = self.FakeUrllib2() |
13
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
72 urllib2.set_url('http://foo/?blah=hi+there', 'meh') |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
73 self.assertEqual( |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
74 bzapi.open_url(url='http://foo/', |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
75 query_args={'blah': 'hi there'}, |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
76 headers={'Content-Type': 'text/plain'}, |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
77 urllib2=urllib2).read(), |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
78 'meh' |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
79 ) |
942f278a9fff
refactored some stuff, added tests
Atul Varma <varmaa@toolness.com>
parents:
12
diff
changeset
|
80 |
17
5e68520b8d1f
added trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
16
diff
changeset
|
81 class _MongoTestCase(unittest.TestCase): |
5e68520b8d1f
added trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
16
diff
changeset
|
82 _collections = [] |
16
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
83 |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
84 def _reset_collections(self): |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
85 for name in self._collections: |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
86 testdb[name].remove({}) |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
87 |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
88 def setUp(self): |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
89 self._reset_collections() |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
90 |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
91 def tearDown(self): |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
92 self._reset_collections() |
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
93 |
17
5e68520b8d1f
added trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
16
diff
changeset
|
94 class CachedSearchTests(_MongoTestCase): |
26 | 95 class ImpartialObserver(object): |
96 def __init__(self): | |
97 self.history = [] | |
98 | |
99 def notify(self, info): | |
100 self.history.append(info) | |
101 | |
20
d9f82ab24604
added another trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
19
diff
changeset
|
102 class FakeApi(object): |
d9f82ab24604
added another trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
19
diff
changeset
|
103 def __init__(self): |
24
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
104 self._bugs = {} |
26 | 105 self._time = bzapi.datetime_from_iso('2009-01-01T00:00:00Z') |
106 | |
107 def fake_time_travel(self, **kwargs): | |
108 self._time += timedelta(**kwargs) | |
109 | |
110 def update_fake_bug(self, **info): | |
111 bug = self._bugs[info['id']] | |
112 bug.update(info) | |
113 bug['last_change_time'] = bzapi.datetime_to_iso(self._time) | |
20
d9f82ab24604
added another trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
19
diff
changeset
|
114 |
24
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
115 def add_fake_bug(self, **info): |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
116 for name in ['last_change_time', 'creation_time']: |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
117 if name not in info: |
26 | 118 info[name] = bzapi.datetime_to_iso(self._time) |
24
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
119 self._bugs[info['id']] = info |
20
d9f82ab24604
added another trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
19
diff
changeset
|
120 |
d9f82ab24604
added another trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
19
diff
changeset
|
121 def get(self, url, **kwargs): |
24
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
122 if url != '/bug': |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
123 raise ValueError(url) |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
124 if 'id' in kwargs and kwargs['id_mode'] == 'include': |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
125 ids = kwargs['id'].split(",") |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
126 bugs = [self._bugs[bugid] for bugid in ids] |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
127 else: |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
128 bugs = self._bugs.values() |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
129 bugs = deepcopy(bugs) |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
130 if kwargs.get('comments') != '1': |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
131 for info in bugs: |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
132 if 'comments' in info: |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
133 del info['comments'] |
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
134 return {'data': {'bugs': bugs}, |
26 | 135 'date': self._time} |
20
d9f82ab24604
added another trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
19
diff
changeset
|
136 |
17
5e68520b8d1f
added trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
16
diff
changeset
|
137 _collections = ['bugs'] |
5e68520b8d1f
added trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
16
diff
changeset
|
138 |
23 | 139 def setUp(self): |
140 _MongoTestCase.setUp(self) | |
141 self.api = self.FakeApi() | |
142 self.search = bzapi.CachedSearch(self.api, testdb.bugs) | |
26 | 143 self.observer = self.ImpartialObserver() |
144 self.search.add_observer(self.observer) | |
20
d9f82ab24604
added another trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
19
diff
changeset
|
145 |
26 | 146 def test_update_with_no_bugs_does_not_crash(self): |
23 | 147 self.search.update() |
22
01b054bc3a27
added a non-trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
21
diff
changeset
|
148 self.assertEqual(testdb.bugs.find().count(), 0) |
01b054bc3a27
added a non-trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
21
diff
changeset
|
149 |
26 | 150 def test_update_with_one_bug_adds_it_to_collection(self): |
24
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
151 self.api.add_fake_bug(id='1034', comments='blah') |
23 | 152 self.search.update() |
22
01b054bc3a27
added a non-trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
21
diff
changeset
|
153 self.assertEqual(testdb.bugs.find({'comments': 'blah'}).count(), 1) |
17
5e68520b8d1f
added trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
16
diff
changeset
|
154 |
26 | 155 def test_one_bug_update_notifies_observers(self): |
156 self.api.add_fake_bug(id='1034') | |
157 self.search.update() | |
158 self.api.fake_time_travel(days=1) | |
159 self.api.update_fake_bug(id='1034', comments='yo') | |
160 self.search.update() | |
161 self.assertEqual(len(self.observer.history), 2) | |
25 | 162 |
26 | 163 def test_one_bug_addition_notifies_observers(self): |
24
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
164 self.api.add_fake_bug(id='1034') |
26 | 165 self.assertEqual(len(self.observer.history), 0) |
24
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
166 self.search.update() |
26 | 167 self.assertEqual(len(self.observer.history), 1) |
168 self.assertEqual(self.observer.history[0]['bug'], '1034') | |
24
e61a42133a33
added test to ensure observers work
Atul Varma <varmaa@toolness.com>
parents:
23
diff
changeset
|
169 |
26 | 170 def test_no_bug_changes_do_not_notify_observers(self): |
171 self.api.add_fake_bug(id='1034') | |
25 | 172 self.search.update() |
26 | 173 self.assertEqual(len(self.observer.history), 1) |
174 | |
175 self.api.fake_time_travel(days=1) | |
176 self.search.update() | |
177 self.assertEqual(len(self.observer.history), 1) | |
25 | 178 |
17
5e68520b8d1f
added trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
16
diff
changeset
|
179 class ApiTests(_MongoTestCase): |
19 | 180 class FakeOpenUrl(object): |
181 def __init__(self): | |
182 self._responses = {} | |
183 | |
184 def set(self, url, query_args, response): | |
185 if not isinstance(response, basestring): | |
186 response = json.dumps(response) | |
21 | 187 self._responses[url + repr(query_args)] = response |
19 | 188 |
189 def __call__(self, url, headers, query_args=None): | |
21 | 190 response = self._responses[url + repr(query_args)] |
19 | 191 return StringIO.StringIO(response) |
192 | |
193 _FAKE_CONFIG = {'product': {}} | |
194 | |
17
5e68520b8d1f
added trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
16
diff
changeset
|
195 _collections = ['api'] |
5e68520b8d1f
added trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
16
diff
changeset
|
196 |
19 | 197 def setUp(self): |
198 _MongoTestCase.setUp(self) | |
22
01b054bc3a27
added a non-trivial cached search test
Atul Varma <varmaa@toolness.com>
parents:
21
diff
changeset
|
199 self.config = deepcopy(self._FAKE_CONFIG) |
19 | 200 |
201 def _get_basic_fake_api(self, **kwargs): | |
202 opener = self.FakeOpenUrl() | |
14 | 203 opener.set('http://foo/latest/configuration', kwargs, |
19 | 204 self.config) |
16
aa2e7f3731c1
test suite now uses a test db instead of a fake one
Atul Varma <varmaa@toolness.com>
parents:
15
diff
changeset
|
205 api = bzapi.BugzillaApi('http://foo/latest', testdb.api, |
14 | 206 open_url=opener, **kwargs) |
207 return api | |
10
2731713f61a8
added more tests and a totally untested 'observer' mechanism
Atul Varma <varmaa@toolness.com>
parents:
6
diff
changeset
|
208 |
14 | 209 def test_bzapi_uses_username_and_password(self): |
210 api = self._get_basic_fake_api(username='foo', | |
211 password='bar') | |
212 api._open_url.set('http://foo/latest/stuff', | |
213 {'username': 'foo', | |
214 'password': 'bar'}, | |
215 {}) | |
216 api.get('/stuff') | |
10
2731713f61a8
added more tests and a totally untested 'observer' mechanism
Atul Varma <varmaa@toolness.com>
parents:
6
diff
changeset
|
217 |
11 | 218 def test_bzapi_raises_err_on_bad_component(self): |
19 | 219 self.config['product']['Mozilla Labs'] = {'component': {'Jetpack': {}}} |
220 api = self._get_basic_fake_api() | |
11 | 221 self.assertRaises(ValueError, |
222 api.get, | |
223 '/blah', | |
224 product='Mozilla Labs', | |
225 component='nonexistent') | |
226 | |
227 def test_bzapi_raises_err_on_bad_product(self): | |
228 api = self._get_basic_fake_api() | |
229 self.assertRaises(ValueError, | |
230 api.get, | |
231 '/blah', | |
232 product='nonexistent') | |
233 | |
234 def test_bzapi_validates_product_and_component(self): | |
19 | 235 self.config['product']['Mozilla Labs'] = {'component': {'Jetpack': {}}} |
236 api = self._get_basic_fake_api() | |
14 | 237 api._open_url.set('http://foo/latest/stuff', |
238 {'product': 'Mozilla Labs', | |
239 'component': 'Jetpack'}, | |
240 {}) | |
11 | 241 api.get('/stuff', product='Mozilla Labs', component='Jetpack') |
242 | |
243 def test_bzapi_removes_dots_from_config(self): | |
19 | 244 self.config['product']['addons.mozilla.org'] = {} |
245 api = self._get_basic_fake_api() | |
10
2731713f61a8
added more tests and a totally untested 'observer' mechanism
Atul Varma <varmaa@toolness.com>
parents:
6
diff
changeset
|
246 self.assertTrue('addons_DOT_mozilla_DOT_org' in api.config['product']) |
2731713f61a8
added more tests and a totally untested 'observer' mechanism
Atul Varma <varmaa@toolness.com>
parents:
6
diff
changeset
|
247 |
6 | 248 if __name__ == '__main__': |
249 unittest.main() |