blob: 74d19afdda73d8705dd887acf24dbffe6eab84b4 [file] [log] [blame]
Rich Lane3f075972013-03-15 22:56:29 -07001#!/usr/bin/env python
2# Copyright 2013, Big Switch Networks, Inc.
3#
4# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
5# the following special exception:
6#
7# LOXI Exception
8#
9# As a special exception to the terms of the EPL, you may distribute libraries
10# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
11# that copyright and licensing notices generated by LoxiGen are not altered or removed
12# from the LoxiGen Libraries and the notice provided below is (i) included in
13# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
14# documentation for the LoxiGen Libraries, if distributed in binary form.
15#
16# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
17#
18# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
19# a copy of the EPL at:
20#
21# http://www.eclipse.org/legal/epl-v10.html
22#
23# Unless required by applicable law or agreed to in writing, software
24# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
25# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
26# EPL for the specific language governing permissions and limitations
27# under the EPL.
28import unittest
Rich Lane4c764982013-05-01 16:12:22 -070029import difflib
Rich Lane3f075972013-03-15 22:56:29 -070030
31try:
32 import loxi.of13 as ofp
Rich Lane57026dc2013-05-01 10:13:16 -070033 from loxi.generic_util import OFReader
Rich Lane3f075972013-03-15 22:56:29 -070034except ImportError:
35 exit("loxi package not found. Try setting PYTHONPATH.")
36
Rich Lane4c764982013-05-01 16:12:22 -070037# Human-friendly format for binary strings. 8 bytes per line.
38def format_binary(buf):
39 byts = map(ord, buf)
40 lines = [[]]
41 for byt in byts:
42 if len(lines[-1]) == 8:
43 lines.append([])
44 lines[-1].append(byt)
45 return '\n'.join([' '.join(['%02x' % y for y in x]) for x in lines])
46
47def diff(a, b):
48 return '\n'.join(difflib.ndiff(a.splitlines(), b.splitlines()))
49
50# Test serialization / deserialization of a sample object.
51# Depends on the __eq__ method being correct.
52def test_serialization(obj, buf):
53 packed = obj.pack()
54 if packed != buf:
55 a = format_binary(buf)
56 b = format_binary(packed)
57 raise AssertionError("Serialization of %s failed\nExpected:\n%s\nActual:\n%s\nDiff:\n%s" % \
58 (type(obj).__name__, a, b, diff(a, b)))
59 unpacked = type(obj).unpack(buf)
60 if obj != unpacked:
61 a = obj.show()
62 b = unpacked.show()
63 raise AssertionError("Deserialization of %s failed\nExpected:\n%s\nActual:\n%s\nDiff:\n%s" % \
64 (type(obj).__name__, a, b, diff(a, b)))
65
Rich Lane3f075972013-03-15 22:56:29 -070066class TestImports(unittest.TestCase):
67 def test_toplevel(self):
68 import loxi
69 self.assertTrue(hasattr(loxi, "ProtocolError"))
Rich Lane00549ea2013-04-25 13:33:16 -070070 self.assertEquals(loxi.version_names[4], "1.3")
Rich Lane3f075972013-03-15 22:56:29 -070071 ofp = loxi.protocol(4)
72 self.assertEquals(ofp.OFP_VERSION, 4)
73 self.assertTrue(hasattr(ofp, "action"))
74 self.assertTrue(hasattr(ofp, "common"))
75 self.assertTrue(hasattr(ofp, "const"))
76 self.assertTrue(hasattr(ofp, "message"))
Rich Lanea22233e2013-04-25 13:18:41 -070077 self.assertTrue(hasattr(ofp, "oxm"))
Rich Lane3f075972013-03-15 22:56:29 -070078
79 def test_version(self):
80 import loxi
81 self.assertTrue(hasattr(loxi.of13, "ProtocolError"))
82 self.assertTrue(hasattr(loxi.of13, "OFP_VERSION"))
83 self.assertEquals(loxi.of13.OFP_VERSION, 4)
84 self.assertTrue(hasattr(loxi.of13, "action"))
85 self.assertTrue(hasattr(loxi.of13, "common"))
86 self.assertTrue(hasattr(loxi.of13, "const"))
87 self.assertTrue(hasattr(loxi.of13, "message"))
Rich Lanea22233e2013-04-25 13:18:41 -070088 self.assertTrue(hasattr(loxi.of13, "oxm"))
Rich Lane3f075972013-03-15 22:56:29 -070089
Rich Lanee90685c2013-04-05 17:27:41 -070090class TestCommon(unittest.TestCase):
91 sample_hello_elem_buf = ''.join([
92 '\x00\x01', # type
93 '\x00\x0c', # length
94 '\x01\x23\x45\x67', # bitmaps[0]
95 '\x89\xab\xcd\xef', # bitmaps[1]
96 ])
97
98 def test_hello_elem_versionbitmap_pack(self):
99 obj = ofp.hello_elem_versionbitmap(bitmaps=[ofp.uint32(0x01234567),ofp.uint32(0x89abcdef)])
100 self.assertEquals(self.sample_hello_elem_buf, obj.pack())
101
102 def test_hello_elem_versionbitmap_unpack(self):
103 obj = ofp.hello_elem_versionbitmap.unpack(self.sample_hello_elem_buf)
104 self.assertEquals(len(obj.bitmaps), 2)
105 self.assertEquals(obj.bitmaps[0], ofp.uint32(0x01234567))
106 self.assertEquals(obj.bitmaps[1], ofp.uint32(0x89abcdef))
107
108 def test_list_hello_elem_unpack(self):
109 buf = ''.join([
110 '\x00\x01\x00\x04', # versionbitmap
111 '\x00\x00\x00\x04', # unknown type
112 '\x00\x01\x00\x04', # versionbitmap
113 ])
Rich Lane57026dc2013-05-01 10:13:16 -0700114 l = ofp.unpack_list_hello_elem(OFReader(buf))
Rich Lanee90685c2013-04-05 17:27:41 -0700115 self.assertEquals(len(l), 2)
116 self.assertTrue(isinstance(l[0], ofp.hello_elem_versionbitmap))
117 self.assertTrue(isinstance(l[1], ofp.hello_elem_versionbitmap))
118
Rich Lane4c764982013-05-01 16:12:22 -0700119class TestMessages(unittest.TestCase):
120 def test_hello(self):
121 obj = ofp.message.hello(
122 xid=0x12345678,
123 elements=[
124 ofp.hello_elem_versionbitmap(
125 bitmaps=[ofp.uint32(1), ofp.uint32(2)]),
126 ofp.hello_elem_versionbitmap(
127 bitmaps=[ofp.uint32(3), ofp.uint32(4)])])
128 buf = ''.join([
129 '\x04', '\x00', # version, type
130 '\x00\x20', # length
131 '\x12\x34\x56\x78', # xid
132 '\x00\x01', # elements[0].type
133 '\x00\x0c', # elements[0].length
134 '\x00\x00\x00\x01', # elements[0].bitmaps[0]
135 '\x00\x00\x00\x02', # elements[0].bitmaps[1]
136 '\x00\x01', # elements[1].type
137 '\x00\x0c', # elements[1].length
138 '\x00\x00\x00\x03', # elements[1].bitmaps[0]
139 '\x00\x00\x00\x04', # elements[1].bitmaps[1]
140 ])
141 test_serialization(obj, buf)
142
143 def test_error(self):
144 obj = ofp.message.error_msg(
145 xid=0x12345678,
146 err_type=ofp.OFPET_BAD_MATCH,
147 code=ofp.OFPBMC_BAD_MASK,
148 data="abc")
149 buf = ''.join([
150 '\x04', '\x01', # version, type
151 '\x00\x0f', # length
152 '\x12\x34\x56\x78', # xid
153 '\x00\x04', # err_type
154 '\x00\x08', # code
155 'abc', # data
156 ])
157 test_serialization(obj, buf)
158
159 def test_echo_request(self):
160 obj = ofp.message.echo_request(
161 xid=0x12345678,
162 data="abc")
163 buf = ''.join([
164 '\x04', '\x02', # version, type
165 '\x00\x0b', # length
166 '\x12\x34\x56\x78', # xid
167 'abc', # data
168 ])
169 test_serialization(obj, buf)
170
171 def test_echo_reply(self):
172 obj = ofp.message.echo_reply(
173 xid=0x12345678,
174 data="abc")
175 buf = ''.join([
176 '\x04', '\x03', # version, type
177 '\x00\x0b', # length
178 '\x12\x34\x56\x78', # xid
179 'abc', # data
180 ])
181 test_serialization(obj, buf)
182
183 def test_features_request(self):
184 obj = ofp.message.features_request(xid=0x12345678)
185 buf = ''.join([
186 '\x04', '\x05', # version, type
187 '\x00\x08', # length
188 '\x12\x34\x56\x78', # xid
189 ])
190 test_serialization(obj, buf)
191
192 def test_features_reply(self):
193 obj = ofp.message.features_reply(
194 xid=0x12345678,
195 datapath_id=0xFEDCBA9876543210,
196 n_buffers=64,
197 n_tables=200,
198 auxiliary_id=5,
199 capabilities=ofp.OFPC_FLOW_STATS|ofp.OFPC_PORT_BLOCKED,
200 reserved=0)
201 buf = ''.join([
202 '\x04', '\x06', # version, type
203 '\x00\x20', # length
204 '\x12\x34\x56\x78', # xid
205 '\xfe\xdc\xba\x98\x76\x54\x32\x10', # datapath_id
206 '\x00\x00\x00\x40', # n_buffers
207 '\xc8', # n_tables
208 '\x05', # auxiliary_id
209 '\x00\x00', # pad
210 '\x00\x00\x01\x01', # capabilities
211 '\x00\x00\x00\x00', # reserved
212 ])
213 test_serialization(obj, buf)
214
215 def test_get_config_request(self):
216 obj = ofp.message.get_config_request(xid=0x12345678)
217 buf = ''.join([
218 '\x04', '\x07', # version, type
219 '\x00\x08', # length
220 '\x12\x34\x56\x78', # xid
221 ])
222 test_serialization(obj, buf)
223
224 def test_get_config_reply(self):
225 obj = ofp.message.get_config_reply(
226 xid=0x12345678,
227 flags=ofp.OFPC_FRAG_REASM,
228 miss_send_len=0xffff)
229 buf = ''.join([
230 '\x04', '\x08', # version, type
231 '\x00\x0c', # length
232 '\x12\x34\x56\x78', # xid
233 '\x00\x02', # flags
234 '\xff\xff', # miss_send_len
235 ])
236 test_serialization(obj, buf)
237
238 def test_set_config(self):
239 obj = ofp.message.set_config(
240 xid=0x12345678,
241 flags=ofp.OFPC_FRAG_REASM,
242 miss_send_len=0xffff)
243 buf = ''.join([
244 '\x04', '\x09', # version, type
245 '\x00\x0c', # length
246 '\x12\x34\x56\x78', # xid
247 '\x00\x02', # flags
248 '\xff\xff', # miss_send_len
249 ])
250 test_serialization(obj, buf)
251
252 def test_packet_in(self):
253 obj = ofp.message.packet_in(
254 xid=0x12345678,
255 buffer_id=100,
256 total_len=17000,
257 reason=ofp.OFPR_ACTION,
258 table_id=20,
259 cookie=0xFEDCBA9876543210,
260 match=ofp.match(oxm_list=[
261 ofp.oxm.arp_op(value=1),
262 ofp.oxm.in_port_masked(value=4, value_mask=5)]),
263 data="abc")
264 buf = ''.join([
265 '\x04', '\x0a', # version, type
266 '\x00\x35', # length
267 '\x12\x34\x56\x78', # xid
268 '\x00\x00\x00\x64', # buffer_id
269 '\x42\x68', # total_len
270 '\x01', # reason
271 '\x14', # table_id
272 '\xfe\xdc\xba\x98\x76\x54\x32\x10', # cookie
273 '\x00\x01', # match.type
274 '\x00\x16', # match.length
275 '\x80\x00\x2A\x02', # match.oxm_list[0].type_len
276 '\x00\x01', # match.oxm_list[0].value
277 '\x80\x00\x01\x08', # match.oxm_list[1].type_len
278 '\x00\x00\x00\x04', # match.oxm_list[1].value
279 '\x00\x00\x00\x05', # match.oxm_list[1].mask
280 '\x00\x00', # match.pad
281 '\x00\x00', # pad
282 'abc', # data
283 ])
284 test_serialization(obj, buf)
285
286 def test_flow_removed(self):
287 obj = ofp.message.flow_removed(
288 xid=0x12345678,
289 cookie=0xFEDCBA9876543210,
290 priority=17000,
291 reason=ofp.OFPRR_DELETE,
292 table_id=20,
293 duration_sec=10,
294 duration_nsec=1000,
295 idle_timeout=5,
296 hard_timeout=30,
297 packet_count=1,
298 byte_count=2,
299 match=ofp.match(oxm_list=[
300 ofp.oxm.arp_op(value=1),
301 ofp.oxm.in_port_masked(value=4, value_mask=5)]))
302 buf = ''.join([
303 '\x04', '\x0b', # version, type
304 '\x00\x48', # length
305 '\x12\x34\x56\x78', # xid
306 '\xfe\xdc\xba\x98\x76\x54\x32\x10', # cookie
307 '\x42\x68', # priority
308 '\x02', # reason
309 '\x14', # table_id
310 '\x00\x00\x00\x0a', # duration_sec
311 '\x00\x00\x03\xe8', # duration_nsec
312 '\x00\x05', # idle_timeout
313 '\x00\x1e', # hard_timeout
314 '\x00\x00\x00\x00\x00\x00\x00\x01', # packet_count
315 '\x00\x00\x00\x00\x00\x00\x00\x02', # byte_count
316 '\x00\x01', # match.type
317 '\x00\x16', # match.length
318 '\x80\x00\x2A\x02', # match.oxm_list[0].type_len
319 '\x00\x01', # match.oxm_list[0].value
320 '\x80\x00\x01\x08', # match.oxm_list[1].type_len
321 '\x00\x00\x00\x04', # match.oxm_list[1].value
322 '\x00\x00\x00\x05', # match.oxm_list[1].mask
323 '\x00\x00', # match.pad
324 ])
325 test_serialization(obj, buf)
326
327 def test_port_status(self):
328 obj = ofp.message.port_status(
329 xid=0x12345678,
330 reason=ofp.OFPPR_MODIFY,
331 desc=ofp.port_desc(
332 port_no=4,
333 hw_addr=[1,2,3,4,5,6],
334 name="foo",
335 config=ofp.OFPPC_NO_FWD|ofp.OFPPC_NO_RECV,
336 state=ofp.OFPPS_BLOCKED,
337 curr=ofp.OFPPF_10MB_HD,
338 advertised=ofp.OFPPF_10MB_FD,
339 supported=ofp.OFPPF_100MB_HD,
340 peer=ofp.OFPPF_100MB_FD,
341 curr_speed=10,
342 max_speed=20))
343 buf = ''.join([
344 '\x04', '\x0c', # version, type
345 '\x00\x50', # length
346 '\x12\x34\x56\x78', # xid
347 '\x02', # reason
348 '\x00' * 7, # pad
349 '\x00\x00\x00\x04', # port_no
350 '\x00' * 4, # pad
351 '\x01\x02\x03\x04\x05\x06', # hw_addr
352 '\x00' * 2, # pad
353 'foo' + '\x00' * 13, # name
354 '\x00\x00\x00\x24', # config
355 '\x00\x00\x00\x02', # state
356 '\x00\x00\x00\x01', # curr
357 '\x00\x00\x00\x02', # advertised
358 '\x00\x00\x00\x04', # supported
359 '\x00\x00\x00\x08', # peer
360 '\x00\x00\x00\x0a', # curr_speed
361 '\x00\x00\x00\x14', # max_speed
362 ])
363 test_serialization(obj, buf)
364
365 def test_packet_out(self):
Rich Lanea4d3d2d2013-05-01 16:57:00 -0700366 obj = ofp.message.packet_out(
367 xid=0x12345678,
368 buffer_id=100,
369 in_port=4,
370 actions=[
371 ofp.action.output(port=2, max_len=0xffff),
372 ofp.action.dec_nw_ttl()],
373 data="abc")
374 buf = ''.join([
375 '\x04', '\x0d', # version, type
376 '\x00\x33', # length
377 '\x12\x34\x56\x78', # xid
378 '\x00\x00\x00\x64', # buffer_id
379 '\x00\x00\x00\x04', # in_port
380 '\x00\x18', # actions_len
381 '\x00' * 6, # pad
382 '\x00\x00', # actions[0].type
383 '\x00\x10', # actions[0].length
384 '\x00\x00\x00\x02', # actions[0].port
385 '\xff\xff', # actions[0].max_len
386 '\x00' * 6, # pad
387 '\x00\x18', # actions[1].type
388 '\x00\x08', # actions[1].length
389 '\x00' * 4, # pad
390 'abc', # data
391 ])
392 test_serialization(obj, buf)
Rich Lane4c764982013-05-01 16:12:22 -0700393
394
395 ## Flow-mods
396
397 def test_flow_add(self):
398 # TODO
399 pass
400
401 def test_flow_modify(self):
402 # TODO
403 pass
404
405 def test_flow_modify_strict(self):
406 # TODO
407 pass
408
409 def test_flow_delete(self):
410 # TODO
411 pass
412
413 def test_flow_delete_strict(self):
414 # TODO
415 pass
416
417
418 def test_group_mod(self):
Rich Lane8e27ec72013-05-02 11:04:31 -0700419 obj = ofp.message.group_mod(
420 xid=0x12345678,
421 command=ofp.OFPGC_MODIFY,
422 group_type=ofp.OFPGT_FF,
423 group_id=5,
424 buckets=[
425 ofp.bucket(
426 weight=1,
427 watch_port=5,
428 watch_group=0xffffffff,
429 actions=[
430 ofp.action.output(port=5, max_len=0),
431 ofp.action.output(port=6, max_len=0)]),
432 ofp.bucket(
433 weight=1,
434 watch_port=6,
435 watch_group=0xffffffff,
436 actions=[
437 ofp.action.output(port=5, max_len=0),
438 ofp.action.output(port=6, max_len=0)])])
439 buf = ''.join([
440 '\x04', '\x0f', # version, type
441 '\x00\x70', # length
442 '\x12\x34\x56\x78', # xid
443 '\x00\x01', # command
444 '\x03', # group_type
445 '\x00', # pad
446 '\x00\x00\x00\x05', # group_id
447 '\x00\x30', # buckets[0].len
448 '\x00\x01', # buckets[0].weight
449 '\x00\x00\x00\x05', # buckets[0].watch_port
450 '\xff\xff\xff\xff', # buckets[0].watch_group
451 '\x00' * 4, # pad
452 '\x00\x00', # buckets[0].actions[0].type
453 '\x00\x10', # buckets[0].actions[0].len
454 '\x00\x00\x00\x05', # buckets[0].actions[0].port
455 '\x00\x00', # buckets[0].actions[0].max_len
456 '\x00' * 6, # pad
457 '\x00\x00', # buckets[0].actions[1].type
458 '\x00\x10', # buckets[0].actions[1].len
459 '\x00\x00\x00\x06', # buckets[0].actions[1].port
460 '\x00\x00', # buckets[0].actions[1].max_len
461 '\x00' * 6, # pad
462 '\x00\x30', # buckets[1].len
463 '\x00\x01', # buckets[1].weight
464 '\x00\x00\x00\x06', # buckets[1].watch_port
465 '\xff\xff\xff\xff', # buckets[1].watch_group
466 '\x00' * 4, # pad
467 '\x00\x00', # buckets[1].actions[0].type
468 '\x00\x10', # buckets[1].actions[0].len
469 '\x00\x00\x00\x05', # buckets[1].actions[0].port
470 '\x00\x00', # buckets[1].actions[0].max_len
471 '\x00' * 6, # pad
472 '\x00\x00', # buckets[1].actions[1].type
473 '\x00\x10', # buckets[1].actions[1].len
474 '\x00\x00\x00\x06', # buckets[1].actions[1].port
475 '\x00\x00', # buckets[1].actions[1].max_len
476 '\x00' * 6, # pad
477 ])
478 test_serialization(obj, buf)
Rich Lane4c764982013-05-01 16:12:22 -0700479
480 def test_port_mod(self):
481 # TODO
482 pass
483
484 def test_table_mod(self):
485 # TODO
486 pass
487
488
489 ## Multipart messages
490
491 def test_desc_stats_request(self):
492 # TODO
493 pass
494
495 def test_desc_stats_reply(self):
496 # TODO
497 pass
498
499 def test_flow_stats_request(self):
500 # TODO
501 pass
502
503 def test_flow_stats_reply(self):
504 # TODO
505 pass
506
507 def test_aggregate_stats_request(self):
508 # TODO
509 pass
510
511 def test_aggregate_stats_reply(self):
512 # TODO
513 pass
514
515 def test_port_stats_request(self):
516 # TODO
517 pass
518
519 def test_port_stats_reply(self):
520 # TODO
521 pass
522
523 def test_queue_stats_request(self):
524 # TODO
525 pass
526
527 def test_queue_stats_reply(self):
528 # TODO
529 pass
530
531 def test_group_stats_request(self):
532 # TODO
533 pass
534
535 def test_group_stats_reply(self):
536 # TODO
537 pass
538
539 def test_group_desc_stats_request(self):
540 # TODO
541 pass
542
543 def test_group_desc_stats_reply(self):
544 # TODO
545 pass
546
547 def test_group_features_stats_request(self):
548 # TODO
549 pass
550
551 def test_group_features_stats_reply(self):
552 # TODO
553 pass
554
555 def test_meter_stats_request(self):
556 # TODO
557 pass
558
559 def test_meter_stats_reply(self):
560 # TODO
561 pass
562
563 def test_meter_config_stats_request(self):
564 # TODO
565 pass
566
567 def test_meter_config_stats_reply(self):
568 # TODO
569 pass
570
571 def test_meter_features_stats_request(self):
572 # TODO
573 pass
574
575 def test_meter_features_stats_reply(self):
576 # TODO
577 pass
578
579 def test_table_features_stats_request(self):
580 # TODO
581 pass
582
583 def test_table_features_stats_reply(self):
584 # TODO
585 pass
586
587 def test_port_desc_stats_request(self):
588 # TODO
589 pass
590
591 def test_port_desc_stats_reply(self):
592 # TODO
593 pass
594
595
596 def test_barrier_request(self):
597 # TODO
598 pass
599
600 def test_barrier_reply(self):
601 # TODO
602 pass
603
604 def test_queue_get_config_request(self):
605 # TODO
606 pass
607
608 def test_queue_get_config_reply(self):
609 # TODO
610 pass
611
612 def test_role_request(self):
613 # TODO
614 pass
615
616 def test_role_reply(self):
617 # TODO
618 pass
619
620 def test_get_async_request(self):
621 # TODO
622 pass
623
624 def test_get_async_reply(self):
625 # TODO
626 pass
627
628 def test_set_async(self):
629 # TODO
630 pass
631
632 def test_meter_mod(self):
633 # TODO
634 pass
635
636 # TODO test experimenter messages
637
638
Rich Laneea693752013-03-18 11:05:45 -0700639class TestOXM(unittest.TestCase):
640 def test_oxm_in_phy_port_pack(self):
641 import loxi.of13 as ofp
642 obj = ofp.oxm.in_phy_port(value=42)
643 expected = ''.join([
644 '\x80\x00', # class
645 '\x02', # type/masked
Rich Lane82e9f6e2013-04-25 17:32:22 -0700646 '\x04', # length
Rich Laneea693752013-03-18 11:05:45 -0700647 '\x00\x00\x00\x2a' # value
648 ])
649 self.assertEquals(expected, obj.pack())
650
651 def test_oxm_in_phy_port_masked_pack(self):
652 import loxi.of13 as ofp
653 obj = ofp.oxm.in_phy_port_masked(value=42, value_mask=0xaabbccdd)
654 expected = ''.join([
655 '\x80\x00', # class
656 '\x03', # type/masked
Rich Lane82e9f6e2013-04-25 17:32:22 -0700657 '\x08', # length
Rich Laneea693752013-03-18 11:05:45 -0700658 '\x00\x00\x00\x2a', # value
659 '\xaa\xbb\xcc\xdd' # mask
660 ])
661 self.assertEquals(expected, obj.pack())
662
Rich Lane41805642013-03-19 15:00:26 -0700663 def test_oxm_ipv6_dst_pack(self):
664 import loxi.of13 as ofp
665 obj = ofp.oxm.ipv6_dst(value='\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0d\x0f')
666 expected = ''.join([
667 '\x80\x00', # class
668 '\x36', # type/masked
Rich Lane82e9f6e2013-04-25 17:32:22 -0700669 '\x10', # length
Rich Lane41805642013-03-19 15:00:26 -0700670 '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0d\x0f', # value
671 ])
672 self.assertEquals(expected, obj.pack())
673
Rich Lane3f075972013-03-15 22:56:29 -0700674class TestAllOF13(unittest.TestCase):
675 """
676 Round-trips every class through serialization/deserialization.
677 Not a replacement for handcoded tests because it only uses the
678 default member values.
679 """
680
681 def setUp(self):
Rich Laneea693752013-03-18 11:05:45 -0700682 mods = [ofp.action,ofp.message,ofp.common,ofp.oxm]
Rich Lane3f075972013-03-15 22:56:29 -0700683 self.klasses = [klass for mod in mods
684 for klass in mod.__dict__.values()
685 if hasattr(klass, 'show')]
686 self.klasses.sort(key=lambda x: str(x))
687
688 def test_serialization(self):
689 expected_failures = [
Rich Lane8692ecd2013-05-02 11:33:53 -0700690 ofp.common.flow_stats_entry,
691 ofp.common.meter_config,
692 ofp.common.table_feature_prop_apply_actions,
693 ofp.common.table_feature_prop_apply_actions_miss,
694 ofp.common.table_feature_prop_instructions,
695 ofp.common.table_feature_prop_instructions_miss,
696 ofp.common.table_feature_prop_write_actions,
697 ofp.common.table_feature_prop_write_actions_miss,
698 ofp.common.table_features,
699 ofp.message.flow_add,
700 ofp.message.flow_delete,
701 ofp.message.flow_delete_strict,
702 ofp.message.flow_modify,
703 ofp.message.flow_modify_strict,
Rich Lane3f075972013-03-15 22:56:29 -0700704 ofp.message.group_desc_stats_reply,
Rich Lane3f075972013-03-15 22:56:29 -0700705 ofp.message.group_stats_reply,
Rich Lane8692ecd2013-05-02 11:33:53 -0700706 ofp.message.meter_config_stats_reply,
Rich Lanea0186052013-05-01 14:18:39 -0700707 ofp.message.meter_features_stats_reply,
Rich Lane8692ecd2013-05-02 11:33:53 -0700708 ofp.message.meter_mod,
709 ofp.message.meter_stats_reply,
Rich Lane3f075972013-03-15 22:56:29 -0700710 ofp.message.table_features_stats_reply,
711 ofp.message.table_features_stats_request,
712 ]
713 for klass in self.klasses:
714 def fn():
715 obj = klass()
716 if hasattr(obj, "xid"): obj.xid = 42
717 buf = obj.pack()
718 obj2 = klass.unpack(buf)
719 self.assertEquals(obj, obj2)
720 if klass in expected_failures:
721 self.assertRaises(Exception, fn)
722 else:
723 fn()
724
725 def test_show(self):
Rich Lane8ca3b772013-04-30 13:36:55 -0700726 expected_failures = []
Rich Lane3f075972013-03-15 22:56:29 -0700727 for klass in self.klasses:
728 def fn():
729 obj = klass()
730 if hasattr(obj, "xid"): obj.xid = 42
731 obj.show()
732 if klass in expected_failures:
733 self.assertRaises(Exception, fn)
734 else:
735 fn()
736
737if __name__ == '__main__':
738 unittest.main()