1"""
2Unit tests for the stem.client.cell.
3"""
4
5import datetime
6import hashlib
7import os
8import unittest
9
10from stem.client.datatype import ZERO, CertType, CloseReason, Address, Certificate
11from test.unit.client import test_data
12
13from stem.client.cell import (
14  FIXED_PAYLOAD_LEN,
15  Cell,
16  PaddingCell,
17  RelayCell,
18  DestroyCell,
19  CreateFastCell,
20  CreatedFastCell,
21  VersionsCell,
22  NetinfoCell,
23  VPaddingCell,
24  CertsCell,
25  AuthChallengeCell,
26)
27
28RANDOM_PAYLOAD = os.urandom(FIXED_PAYLOAD_LEN)
29CHALLENGE = b'\x89Y\t\x99\xb2\x1e\xd9*V\xb6\x1bn\n\x05\xd8/\xe3QH\x85\x13Z\x17\xfc\x1c\x00{\xa9\xae\x83^K'
30
31PADDING_CELLS = {
32  b'\x00\x00\x00' + RANDOM_PAYLOAD: (RANDOM_PAYLOAD, 2),
33}
34
35RELAY_CELLS = {
36  b'\x00\x01\x03\r\x00\x00\x00\x01!\xa3?\xec\x00\x00' + ZERO * 498: ('RELAY_BEGIN_DIR', 13, 1, 1, b'', 564346860, ZERO * 498, 2),
37  b'\x00\x01\x03\x02\x00\x00\x00\x01\x15:m\xe0\x00&GET /tor/server/authority HTTP/1.0\r\n\r\n' + ZERO * 460: ('RELAY_DATA', 2, 1, 1, b'GET /tor/server/authority HTTP/1.0\r\n\r\n', 356150752, ZERO * 460, 2),
38  b'\x00\x01\x03\x02\x00\x00\x00\x01\x15:m\xe0\x00&GET /tor/server/authority HTTP/1.0\r\n\r\n' + b'\x01' + ZERO * 459: ('RELAY_DATA', 2, 1, 1, b'GET /tor/server/authority HTTP/1.0\r\n\r\n', 356150752, b'\x01' + ZERO * 459, 2),
39}
40
41DESTROY_CELLS = {
42  b'\x80\x00\x00\x00\x04\x00' + ZERO * 508: (2147483648, CloseReason.NONE, 0, ZERO * 508, 5),
43  b'\x80\x00\x00\x00\x04\x03' + ZERO * 508: (2147483648, CloseReason.REQUESTED, 3, ZERO * 508, 5),
44  b'\x80\x00\x00\x00\x04\x01' + b'\x01' + ZERO * 507: (2147483648, CloseReason.PROTOCOL, 1, b'\x01' + ZERO * 507, 5),
45}
46
47CREATE_FAST_CELLS = {
48  (b'\x80\x00\x00\x00\x05\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce' + ZERO * 489): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', ZERO * 489, 5),
49  (b'\x80\x00\x00\x00\x05\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\x00' + ZERO * 489): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\x00', ZERO * 489, 5),
50  (b'\x80\x00\x00\x00\x05\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\x00' + b'\x01' + ZERO * 488): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\x00', b'\x01' + ZERO * 488, 5),
51}
52
53CREATED_FAST_CELLS = {
54  (b'\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\xb2' + ZERO * 469): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\xb2', ZERO * 469, 5),
55  (b'\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00' + ZERO * 469): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00', ZERO * 469, 5),
56  (b'\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00' + b'\x01' + ZERO * 468): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00', b'\x01' + ZERO * 468, 5),
57}
58
59VERSIONS_CELLS = {
60  b'\x00\x00\x07\x00\x00': ([], 2),
61  b'\x00\x00\x07\x00\x02\x00\x01': ([1], 2),
62  b'\x00\x00\x07\x00\x06\x00\x01\x00\x02\x00\x03': ([1, 2, 3], 2),
63  b'\x00\x00\x00\x00\x07\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04': ([1, 2, 3, 4], 4),
64}
65
66NETINFO_CELLS = {
67  b'\x00\x00\x08ZZ\xb6\x90\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02' + ZERO * (FIXED_PAYLOAD_LEN - 17): (datetime.datetime(2018, 1, 14, 1, 46, 56), Address('127.0.0.1'), [Address('97.113.15.2')], ZERO * 492, 2),
68  b'\x00\x00\x08ZZ\xb6\x90\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02' + b'\x01' + ZERO * (FIXED_PAYLOAD_LEN - 18): (datetime.datetime(2018, 1, 14, 1, 46, 56), Address('127.0.0.1'), [Address('97.113.15.2')], b'\x01' + ZERO * 491, 2),
69}
70
71VPADDING_CELL_EMPTY_PACKED = b'\x00\x00\x80\x00\x00'
72
73VPADDING_CELLS = {
74  VPADDING_CELL_EMPTY_PACKED: (b'', 2),
75  b'\x00\x00\x80\x00\x01\x08': (b'\x08', 2),
76  b'\x00\x00\x80\x00\x02\x08\x11': (b'\x08\x11', 2),
77  b'\x00\x00\x80\x01\xfd' + RANDOM_PAYLOAD: (RANDOM_PAYLOAD, 2),
78}
79
80CERTS_CELLS = {
81  b'\x00\x00\x81\x00\x01\x00': ([], b'', 2),
82  b'\x00\x00\x81\x00\x04\x01\x01\x00\x00': ([Certificate(1, b'')], b'', 2),
83  b'\x00\x00\x81\x00\x05\x01\x01\x00\x01\x08': ([Certificate(1, b'\x08')], b'', 2),
84  b'\x00\x00\x81\x00\x07\x01\x01\x00\x01\x08' + b'\x06\x04': ([Certificate(1, b'\x08')], b'\x06\x04', 2),
85}
86
87AUTH_CHALLENGE_CELLS = {
88  b'\x00\x00\x82\x00\x26' + CHALLENGE + b'\x00\x02\x00\x01\x00\x03': (CHALLENGE, [1, 3], b'', 2),
89  b'\x00\x00\x82\x00\x28' + CHALLENGE + b'\x00\x02\x00\x01\x00\x03' + b'\x01\x02': (CHALLENGE, [1, 3], b'\x01\x02', 2),
90}
91
92
93class TestCell(unittest.TestCase):
94  def test_by_name(self):
95    cls = Cell.by_name('NETINFO')
96    self.assertEqual('NETINFO', cls.NAME)
97    self.assertEqual(8, cls.VALUE)
98    self.assertEqual(True, cls.IS_FIXED_SIZE)
99
100    self.assertRaises(ValueError, Cell.by_name, 'NOPE')
101    self.assertRaises(ValueError, Cell.by_name, 85)
102    self.assertRaises(ValueError, Cell.by_name, None)
103
104  def test_by_value(self):
105    cls = Cell.by_value(8)
106    self.assertEqual('NETINFO', cls.NAME)
107    self.assertEqual(8, cls.VALUE)
108    self.assertEqual(True, cls.IS_FIXED_SIZE)
109
110    self.assertRaises(ValueError, Cell.by_value, 'NOPE')
111    self.assertRaises(ValueError, Cell.by_value, 85)
112    self.assertRaises(ValueError, Cell.by_value, None)
113
114  def test_unimplemented_cell_methods(self):
115    cell_instance = Cell()
116
117    self.assertRaisesWith(NotImplementedError, 'Packing not yet implemented for UNKNOWN cells', cell_instance.pack, 2)
118    self.assertRaisesWith(NotImplementedError, 'Unpacking not yet implemented for UNKNOWN cells', cell_instance._unpack, b'dummy', 0, 2)
119
120  def test_payload_too_large(self):
121    class OversizedCell(Cell):
122      NAME = 'OVERSIZED'
123      VALUE = 127  # currently nonsense, but potentially will be allocated in the distant future
124      IS_FIXED_SIZE = True
125
126      def pack(self, link_protocol):
127        return OversizedCell._pack(link_protocol, ZERO * (FIXED_PAYLOAD_LEN + 1))
128
129    instance = OversizedCell()
130
131    expected_message = 'Cell of type OVERSIZED is too large (%i bytes), must not be more than %i. Check payload size (was %i bytes)' % (FIXED_PAYLOAD_LEN + 4, FIXED_PAYLOAD_LEN + 3, FIXED_PAYLOAD_LEN + 1)
132    self.assertRaisesWith(ValueError, expected_message, instance.pack, 2)
133
134  def test_circuit_id_validation(self):
135    # only CircuitCell subclasses should provide a circ_id
136
137    self.assertRaisesWith(ValueError, 'PADDING cells should not specify a circuit identifier', PaddingCell._pack, 5, b'', circ_id = 12)
138
139    # CircuitCell should validate its circ_id
140
141    self.assertRaisesWith(ValueError, 'RELAY cells require a circuit identifier', RelayCell._pack, 5, b'', circ_id = None)
142
143    for circ_id in (0, -1, -50):
144      expected_msg = 'Circuit identifiers must a positive integer, not %s' % circ_id
145      self.assertRaisesWith(ValueError, expected_msg, RelayCell._pack, 5, b'', circ_id = circ_id)
146
147  def test_unpack_for_new_link(self):
148    expected_certs = (
149      (CertType.LINK, 1, b'0\x82\x02F0\x82\x01\xaf'),
150      (CertType.IDENTITY, 2, b'0\x82\x01\xc90\x82\x012'),
151      (CertType.ED25519_SIGNING, 4, b'\x01\x04\x00\x06m\x1f'),
152      (CertType.LINK_CERT, 5, b'\x01\x05\x00\x06m\n\x01'),
153      (CertType.ED25519_IDENTITY, 7, b'\x1a\xa5\xb3\xbd\x88\xb1C'),
154    )
155
156    content = test_data('new_link_cells')
157
158    version_cell, content = Cell.pop(content, 2)
159    self.assertEqual(VersionsCell([3, 4, 5]), version_cell)
160
161    certs_cell, content = Cell.pop(content, 2)
162    self.assertEqual(CertsCell, type(certs_cell))
163    self.assertEqual(len(expected_certs), len(certs_cell.certificates))
164
165    for i, (cert_type, cert_type_int, cert_prefix) in enumerate(expected_certs):
166      self.assertEqual(cert_type, certs_cell.certificates[i].type)
167      self.assertEqual(cert_type_int, certs_cell.certificates[i].type_int)
168      self.assertTrue(certs_cell.certificates[i].value.startswith(cert_prefix))
169
170    auth_challenge_cell, content = Cell.pop(content, 2)
171    self.assertEqual(AuthChallengeCell([1, 3], b'\x89Y\t\x99\xb2\x1e\xd9*V\xb6\x1bn\n\x05\xd8/\xe3QH\x85\x13Z\x17\xfc\x1c\x00{\xa9\xae\x83^K'), auth_challenge_cell)
172
173    netinfo_cell, content = Cell.pop(content, 2)
174    self.assertEqual(NetinfoCell, type(netinfo_cell))
175    self.assertEqual(datetime.datetime(2018, 1, 14, 1, 46, 56), netinfo_cell.timestamp)
176    self.assertEqual(Address('127.0.0.1'), netinfo_cell.receiver_address)
177    self.assertEqual([Address('97.113.15.2')], netinfo_cell.sender_addresses)
178    self.assertEqual(ZERO * 492, netinfo_cell.unused)
179
180    self.assertEqual(b'', content)  # check that we've consumed all of the bytes
181
182  def test_padding_cell(self):
183    for cell_bytes, (payload, link_protocol) in PADDING_CELLS.items():
184      self.assertEqual(cell_bytes, PaddingCell(payload).pack(link_protocol))
185
186      cell = Cell.pop(cell_bytes, link_protocol)[0]
187      self.assertEqual(payload, cell.payload)
188      self.assertEqual(b'', cell.unused)  # always empty
189      self.assertEqual(cell_bytes, cell.pack(link_protocol))
190
191  def test_relay_cell(self):
192    for cell_bytes, (command, command_int, circ_id, stream_id, data, digest, unused, link_protocol) in RELAY_CELLS.items():
193      if not unused.strip(ZERO):
194        self.assertEqual(cell_bytes, RelayCell(circ_id, command, data, digest, stream_id).pack(link_protocol))
195        self.assertEqual(cell_bytes, RelayCell(circ_id, command_int, data, digest, stream_id).pack(link_protocol))
196      else:
197        self.assertEqual(cell_bytes, RelayCell(circ_id, command, data, digest, stream_id, unused = unused).pack(link_protocol))
198        self.assertEqual(cell_bytes, RelayCell(circ_id, command_int, data, digest, stream_id, unused = unused).pack(link_protocol))
199
200      cell = Cell.pop(cell_bytes, link_protocol)[0]
201      self.assertEqual(circ_id, cell.circ_id)
202      self.assertEqual(command, cell.command)
203      self.assertEqual(command_int, cell.command_int)
204      self.assertEqual(data, cell.data)
205      self.assertEqual(digest, cell.digest)
206      self.assertEqual(stream_id, cell.stream_id)
207      self.assertEqual(unused, cell.unused)
208
209      self.assertEqual(cell_bytes, cell.pack(link_protocol))
210
211    digest = hashlib.sha1(b'hi')
212    self.assertEqual(3257622417, RelayCell(5, 'RELAY_BEGIN_DIR', '', digest, 564346860).digest)
213    self.assertEqual(3257622417, RelayCell(5, 'RELAY_BEGIN_DIR', '', digest.digest(), 564346860).digest)
214    self.assertEqual(3257622417, RelayCell(5, 'RELAY_BEGIN_DIR', '', 3257622417, 564346860).digest)
215    self.assertRaisesWith(ValueError, 'RELAY cell digest must be a hash, string, or int but was a list', RelayCell, 5, 'RELAY_BEGIN_DIR', '', [], 564346860)
216    self.assertRaisesRegexp(ValueError, "Invalid enumeration 'NO_SUCH_COMMAND', options are RELAY_BEGIN, RELAY_DATA", RelayCell, 5, 'NO_SUCH_COMMAND', '', 5, 564346860)
217
218    mismatched_data_length_bytes = b''.join((
219      b'\x00\x01',  # circ ID
220      b'\x03',  # command
221      b'\x02',  # relay command
222      b'\x00\x00',  # 'recognized'
223      b'\x00\x01',  # stream ID
224      b'\x15:m\xe0',  # digest
225      b'\xFF\xFF',  # data len (65535, clearly invalid)
226      ZERO * 498,  # data
227    ))
228
229    self.assertRaisesWith(ValueError, 'RELAY cell said it had 65535 bytes of data, but only had 498', Cell.pop, mismatched_data_length_bytes, 2)
230
231  def test_destroy_cell(self):
232    for cell_bytes, (circ_id, reason, reason_int, unused, link_protocol) in DESTROY_CELLS.items():
233      if not unused.strip(ZERO):
234        self.assertEqual(cell_bytes, DestroyCell(circ_id, reason).pack(link_protocol))
235        self.assertEqual(cell_bytes, DestroyCell(circ_id, reason_int).pack(link_protocol))
236      else:
237        self.assertEqual(cell_bytes, DestroyCell(circ_id, reason, unused = unused).pack(link_protocol))
238        self.assertEqual(cell_bytes, DestroyCell(circ_id, reason_int, unused = unused).pack(link_protocol))
239
240      cell = Cell.pop(cell_bytes, link_protocol)[0]
241      self.assertEqual(circ_id, cell.circ_id)
242      self.assertEqual(reason, cell.reason)
243      self.assertEqual(reason_int, cell.reason_int)
244      self.assertEqual(unused, cell.unused)
245      self.assertEqual(cell_bytes, cell.pack(link_protocol))
246
247  def test_create_fast_cell(self):
248    for cell_bytes, (circ_id, key_material, unused, link_protocol) in CREATE_FAST_CELLS.items():
249      if not unused.strip(ZERO):
250        self.assertEqual(cell_bytes, CreateFastCell(circ_id, key_material).pack(link_protocol))
251      else:
252        self.assertEqual(cell_bytes, CreateFastCell(circ_id, key_material, unused = unused).pack(link_protocol))
253
254      cell = Cell.pop(cell_bytes, link_protocol)[0]
255      self.assertEqual(circ_id, cell.circ_id)
256      self.assertEqual(key_material, cell.key_material)
257      self.assertEqual(unused, cell.unused)
258      self.assertEqual(cell_bytes, cell.pack(link_protocol))
259
260    self.assertRaisesWith(ValueError, 'Key material should be 20 bytes, but was 3', CreateFastCell, 5, 'boo')
261
262  def test_created_fast_cell(self):
263    for cell_bytes, (circ_id, key_material, derivative_key, unused, link_protocol) in CREATED_FAST_CELLS.items():
264      if not unused.strip(ZERO):
265        self.assertEqual(cell_bytes, CreatedFastCell(circ_id, derivative_key, key_material).pack(link_protocol))
266      else:
267        self.assertEqual(cell_bytes, CreatedFastCell(circ_id, derivative_key, key_material, unused = unused).pack(link_protocol))
268
269      cell = Cell.pop(cell_bytes, link_protocol)[0]
270      self.assertEqual(circ_id, cell.circ_id)
271      self.assertEqual(key_material, cell.key_material)
272      self.assertEqual(derivative_key, cell.derivative_key)
273      self.assertEqual(unused, cell.unused)
274      self.assertEqual(cell_bytes, cell.pack(link_protocol))
275
276    self.assertRaisesWith(ValueError, 'Key material should be 20 bytes, but was 3', CreateFastCell, 5, 'boo')
277
278  def test_versions_cell(self):
279    for cell_bytes, (versions, link_protocol) in VERSIONS_CELLS.items():
280      self.assertEqual(cell_bytes, VersionsCell(versions).pack(link_protocol))
281
282      cell = Cell.pop(cell_bytes, link_protocol)[0]
283      self.assertEqual(versions, cell.versions)
284      self.assertEqual(b'', cell.unused)  # always empty
285      self.assertEqual(cell_bytes, cell.pack(link_protocol))
286
287  def test_netinfo_cell(self):
288    for cell_bytes, (timestamp, receiver_address, sender_addresses, unused, link_protocol) in NETINFO_CELLS.items():
289      if not unused.strip(ZERO):
290        self.assertEqual(cell_bytes, NetinfoCell(receiver_address, sender_addresses, timestamp).pack(link_protocol))
291      else:
292        self.assertEqual(cell_bytes, NetinfoCell(receiver_address, sender_addresses, timestamp, unused = unused).pack(link_protocol))
293
294      cell = Cell.pop(cell_bytes, link_protocol)[0]
295      self.assertEqual(timestamp, cell.timestamp)
296      self.assertEqual(receiver_address, cell.receiver_address)
297      self.assertEqual(sender_addresses, cell.sender_addresses)
298      self.assertEqual(unused, cell.unused)
299      self.assertEqual(cell_bytes, cell.pack(link_protocol))
300
301  def test_vpadding_cell(self):
302    for cell_bytes, (payload, link_protocol) in VPADDING_CELLS.items():
303      self.assertEqual(cell_bytes, VPaddingCell(payload = payload).pack(link_protocol))
304
305      cell = Cell.pop(cell_bytes, link_protocol)[0]
306      self.assertEqual(payload, cell.payload)
307      self.assertEqual(b'', cell.unused)  # always empty
308      self.assertEqual(cell_bytes, cell.pack(link_protocol))
309
310    empty_constructed_cell = VPaddingCell(size = 0)
311    self.assertEqual(VPADDING_CELL_EMPTY_PACKED, empty_constructed_cell.pack(2))
312    self.assertEqual(b'', empty_constructed_cell.payload)
313
314    self.assertRaisesWith(ValueError, 'VPaddingCell constructor specified both a size of 5 bytes and payload of 1 bytes', VPaddingCell, 5, '\x02')
315    self.assertRaisesWith(ValueError, 'VPaddingCell size (-15) cannot be negative', VPaddingCell, -15)
316    self.assertRaisesWith(ValueError, 'VPaddingCell constructor must specify payload or size', VPaddingCell)
317
318  def test_certs_cell(self):
319    for cell_bytes, (certs, unused, link_protocol) in CERTS_CELLS.items():
320      if not unused.strip(ZERO):
321        self.assertEqual(cell_bytes, CertsCell(certs).pack(link_protocol))
322      else:
323        self.assertEqual(cell_bytes, CertsCell(certs, unused = unused).pack(link_protocol))
324
325      cell = Cell.pop(cell_bytes, link_protocol)[0]
326      self.assertEqual(certs, cell.certificates)
327      self.assertEqual(unused, cell.unused)
328      self.assertEqual(cell_bytes, cell.pack(link_protocol))
329
330    # truncated or missing certificates should error
331
332    self.assertRaisesWith(ValueError, 'CERTS cell should have a certificate with 3 bytes, but only had 1 remaining', Cell.pop, b'\x00\x00\x81\x00\x05\x01\x01\x00\x03\x08', 2)
333    self.assertRaisesWith(ValueError, 'CERTS cell indicates it should have 2 certificates, but only contained 1', Cell.pop, b'\x00\x00\x81\x00\x05\x02\x01\x00\x01\x08', 2)
334
335  def test_auth_challenge_cell(self):
336    for cell_bytes, (challenge, methods, unused, link_protocol) in AUTH_CHALLENGE_CELLS.items():
337      if not unused.strip(ZERO):
338        self.assertEqual(cell_bytes, AuthChallengeCell(methods, challenge).pack(link_protocol))
339      else:
340        self.assertEqual(cell_bytes, AuthChallengeCell(methods, challenge, unused = unused).pack(link_protocol))
341
342      cell = Cell.pop(cell_bytes, link_protocol)[0]
343      self.assertEqual(challenge, cell.challenge)
344      self.assertEqual(methods, cell.methods)
345      self.assertEqual(unused, cell.unused)
346      self.assertEqual(cell_bytes, cell.pack(link_protocol))
347
348    self.assertRaisesWith(ValueError, 'AUTH_CHALLENGE cell should have a payload of 38 bytes, but only had 16', Cell.pop, b'\x00\x00\x82\x00&' + CHALLENGE[:10] + b'\x00\x02\x00\x01\x00\x03', 2)
349    self.assertRaisesWith(ValueError, 'AUTH_CHALLENGE should have 3 methods, but only had 4 bytes for it', Cell.pop, b'\x00\x00\x82\x00&' + CHALLENGE + b'\x00\x03\x00\x01\x00\x03', 2)
350