blob: be93239b403e6d6b090cbc87f697adedf6b7df43 [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -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 Lane9a3f1fd2013-05-10 16:29:17 -070029import test_data
Rich Lane5c4446e2013-05-16 13:53:51 -070030from testutil import add_datafiles_tests
Rich Lanea06d0c32013-03-25 08:52:03 -070031
32try:
Rich Lanefb7de0e2013-03-29 16:50:29 -070033 import loxi.of10 as ofp
Rich Lane57026dc2013-05-01 10:13:16 -070034 from loxi.generic_util import OFReader
Rich Lanea06d0c32013-03-25 08:52:03 -070035except ImportError:
36 exit("loxi package not found. Try setting PYTHONPATH.")
37
38class TestImports(unittest.TestCase):
39 def test_toplevel(self):
40 import loxi
41 self.assertTrue(hasattr(loxi, "ProtocolError"))
Rich Lane00549ea2013-04-25 13:33:16 -070042 self.assertEquals(loxi.version_names[1], "1.0")
Rich Lanea06d0c32013-03-25 08:52:03 -070043 ofp = loxi.protocol(1)
44 self.assertEquals(ofp.OFP_VERSION, 1)
45 self.assertTrue(hasattr(ofp, "action"))
46 self.assertTrue(hasattr(ofp, "common"))
47 self.assertTrue(hasattr(ofp, "const"))
48 self.assertTrue(hasattr(ofp, "message"))
49
50 def test_version(self):
Rich Lanea94fb082013-04-04 17:04:17 -070051 import loxi
Rich Lanea06d0c32013-03-25 08:52:03 -070052 self.assertTrue(hasattr(loxi.of10, "ProtocolError"))
53 self.assertTrue(hasattr(loxi.of10, "OFP_VERSION"))
54 self.assertEquals(loxi.of10.OFP_VERSION, 1)
55 self.assertTrue(hasattr(loxi.of10, "action"))
56 self.assertTrue(hasattr(loxi.of10, "common"))
57 self.assertTrue(hasattr(loxi.of10, "const"))
58 self.assertTrue(hasattr(loxi.of10, "message"))
59
60class TestActions(unittest.TestCase):
Rich Lanea06d0c32013-03-25 08:52:03 -070061 def test_output_equality(self):
Rich Lanea06d0c32013-03-25 08:52:03 -070062 action = ofp.action.output(port=1, max_len=0x1234)
63 action2 = ofp.action.output(port=1, max_len=0x1234)
64 self.assertEquals(action, action2)
65
66 action2.port = 2
67 self.assertNotEquals(action, action2)
68 action2.port = 1
69
70 action2.max_len = 0xffff
71 self.assertNotEquals(action, action2)
72 action2.max_len = 0x1234
73
Rich Lanea06d0c32013-03-25 08:52:03 -070074# Assumes action serialization/deserialization works
75class TestActionList(unittest.TestCase):
76 def test_normal(self):
Rich Lanea06d0c32013-03-25 08:52:03 -070077 expected = []
78 bufs = []
79
80 def add(action):
81 expected.append(action)
82 bufs.append(action.pack())
83
84 add(ofp.action.output(port=1, max_len=0xffff))
85 add(ofp.action.output(port=2, max_len=0xffff))
86 add(ofp.action.output(port=ofp.OFPP_IN_PORT, max_len=0xffff))
87 add(ofp.action.bsn_set_tunnel_dst(dst=0x12345678))
88 add(ofp.action.nicira_dec_ttl())
89
Rich Lane57026dc2013-05-01 10:13:16 -070090 actions = ofp.action.unpack_list(OFReader(''.join(bufs)))
Rich Lanea06d0c32013-03-25 08:52:03 -070091 self.assertEquals(actions, expected)
92
93 def test_empty_list(self):
Rich Lane57026dc2013-05-01 10:13:16 -070094 self.assertEquals(ofp.action.unpack_list(OFReader('')), [])
Rich Lanea06d0c32013-03-25 08:52:03 -070095
96 def test_invalid_list_length(self):
Rich Lanea06d0c32013-03-25 08:52:03 -070097 buf = '\x00' * 9
Rich Lane57026dc2013-05-01 10:13:16 -070098 with self.assertRaisesRegexp(ofp.ProtocolError, 'Buffer too short'):
99 ofp.action.unpack_list(OFReader(buf))
Rich Lanea06d0c32013-03-25 08:52:03 -0700100
101 def test_invalid_action_length(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700102 buf = '\x00' * 8
Rich Lane57026dc2013-05-01 10:13:16 -0700103 with self.assertRaisesRegexp(ofp.ProtocolError, 'Buffer too short'):
104 ofp.action.unpack_list(OFReader(buf))
Rich Lanea06d0c32013-03-25 08:52:03 -0700105
106 buf = '\x00\x00\x00\x04'
Rich Lane57026dc2013-05-01 10:13:16 -0700107 with self.assertRaisesRegexp(ofp.ProtocolError, 'Buffer too short'):
108 ofp.action.unpack_list(OFReader(buf))
Rich Lanea06d0c32013-03-25 08:52:03 -0700109
110 buf = '\x00\x00\x00\x10\x00\x00\x00\x00'
Rich Lane57026dc2013-05-01 10:13:16 -0700111 with self.assertRaisesRegexp(ofp.ProtocolError, 'Buffer too short'):
112 ofp.action.unpack_list(OFReader(buf))
Rich Lanea06d0c32013-03-25 08:52:03 -0700113
114 def test_invalid_action_type(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700115 buf = '\xff\xfe\x00\x08\x00\x00\x00\x00'
116 with self.assertRaisesRegexp(ofp.ProtocolError, 'unknown action type'):
Rich Lane57026dc2013-05-01 10:13:16 -0700117 ofp.action.unpack_list(OFReader(buf))
Rich Lanea06d0c32013-03-25 08:52:03 -0700118
119class TestConstants(unittest.TestCase):
120 def test_ports(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700121 self.assertEquals(0xffff, ofp.OFPP_NONE)
122
123 def test_wildcards(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700124 self.assertEquals(0xfc000, ofp.OFPFW_NW_DST_MASK)
125
126class TestCommon(unittest.TestCase):
Rich Lanea06d0c32013-03-25 08:52:03 -0700127 def test_match(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700128 match = ofp.match()
129 self.assertEquals(match.wildcards, ofp.OFPFW_ALL)
130 self.assertEquals(match.tcp_src, 0)
131 buf = match.pack()
132 match2 = ofp.match.unpack(buf)
133 self.assertEquals(match, match2)
134
135class TestMessages(unittest.TestCase):
136 def test_hello_construction(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700137 msg = ofp.message.hello()
138 self.assertEquals(msg.version, ofp.OFP_VERSION)
139 self.assertEquals(msg.type, ofp.OFPT_HELLO)
140 self.assertEquals(msg.xid, None)
141
142 msg = ofp.message.hello(xid=123)
143 self.assertEquals(msg.xid, 123)
144
145 # 0 is a valid xid distinct from None
146 msg = ofp.message.hello(xid=0)
147 self.assertEquals(msg.xid, 0)
148
Rich Lanea06d0c32013-03-25 08:52:03 -0700149 def test_echo_request_construction(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700150 msg = ofp.message.echo_request(data="abc")
151 self.assertEquals(msg.data, "abc")
152
Rich Lane5c4446e2013-05-16 13:53:51 -0700153 def test_echo_request_invalid_length(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700154 buf = "\x01\x02\x00\x07\x12\x34\x56"
155 with self.assertRaisesRegexp(ofp.ProtocolError, "buffer too short"):
156 ofp.message.echo_request.unpack(buf)
157
158 def test_echo_request_equality(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700159 msg = ofp.message.echo_request(xid=0x12345678, data="abc")
160 msg2 = ofp.message.echo_request(xid=0x12345678, data="abc")
Rich Lanea06d0c32013-03-25 08:52:03 -0700161 self.assertEquals(msg, msg2)
162
163 msg2.xid = 1
164 self.assertNotEquals(msg, msg2)
165 msg2.xid = msg.xid
166
167 msg2.data = "a"
168 self.assertNotEquals(msg, msg2)
169 msg2.data = msg.data
170
Rich Laneb1f347d2013-05-16 16:39:12 -0700171# The majority of the serialization tests are created here using the files in
172# the test_data directory.
Rich Lane5c4446e2013-05-16 13:53:51 -0700173class TestDataFiles(unittest.TestCase):
174 pass
Rich Lane5c4446e2013-05-16 13:53:51 -0700175add_datafiles_tests(TestDataFiles, 'of10/', ofp)
176
Rich Lanea06d0c32013-03-25 08:52:03 -0700177class TestParse(unittest.TestCase):
178 def test_parse_header(self):
179 import loxi
Rich Lanea06d0c32013-03-25 08:52:03 -0700180
181 msg_ver, msg_type, msg_len, msg_xid = ofp.message.parse_header("\x01\x04\xAF\xE8\x12\x34\x56\x78")
182 self.assertEquals(1, msg_ver)
183 self.assertEquals(4, msg_type)
184 self.assertEquals(45032, msg_len)
185 self.assertEquals(0x12345678, msg_xid)
186
187 with self.assertRaisesRegexp(loxi.ProtocolError, "too short"):
188 ofp.message.parse_header("\x01\x04\xAF\xE8\x12\x34\x56")
189
190 def test_parse_message(self):
191 import loxi
192 import loxi.of10 as ofp
193
194 buf = "\x01\x00\x00\x08\x12\x34\x56\x78"
195 msg = ofp.message.parse_message(buf)
196 assert(msg.xid == 0x12345678)
197
198 # Get a list of all message classes
199 test_klasses = [x for x in ofp.message.__dict__.values()
200 if type(x) == type
201 and issubclass(x, ofp.message.Message)
202 and x != ofp.message.Message]
203
204 for klass in test_klasses:
205 self.assertIsInstance(ofp.message.parse_message(klass(xid=1).pack()), klass)
206
207class TestUtils(unittest.TestCase):
Rich Lanea06d0c32013-03-25 08:52:03 -0700208 def test_pretty_wildcards(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700209 self.assertEquals("OFPFW_ALL", ofp.util.pretty_wildcards(ofp.OFPFW_ALL))
210 self.assertEquals("0", ofp.util.pretty_wildcards(0))
211 self.assertEquals("OFPFW_DL_SRC|OFPFW_DL_DST",
212 ofp.util.pretty_wildcards(ofp.OFPFW_DL_SRC|ofp.OFPFW_DL_DST))
213 self.assertEquals("OFPFW_NW_SRC_MASK&0x2000",
214 ofp.util.pretty_wildcards(ofp.OFPFW_NW_SRC_ALL))
215 self.assertEquals("OFPFW_NW_SRC_MASK&0x1a00",
216 ofp.util.pretty_wildcards(0x00001a00))
217 self.assertEquals("OFPFW_IN_PORT|0x80000000",
218 ofp.util.pretty_wildcards(ofp.OFPFW_IN_PORT|0x80000000))
219
220class TestAll(unittest.TestCase):
221 """
222 Round-trips every class through serialization/deserialization.
223 Not a replacement for handcoded tests because it only uses the
224 default member values.
225 """
226
227 def setUp(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700228 mods = [ofp.action,ofp.message,ofp.common]
229 self.klasses = [klass for mod in mods
230 for klass in mod.__dict__.values()
231 if hasattr(klass, 'show')]
232 self.klasses.sort(key=lambda x: str(x))
233
234 def test_serialization(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700235 expected_failures = []
236 for klass in self.klasses:
237 def fn():
238 obj = klass()
239 if hasattr(obj, "xid"): obj.xid = 42
240 buf = obj.pack()
241 obj2 = klass.unpack(buf)
242 self.assertEquals(obj, obj2)
243 if klass in expected_failures:
244 self.assertRaises(Exception, fn)
245 else:
246 fn()
247
Rich Lane65790d22013-06-14 00:08:52 -0700248 def test_parse_message(self):
249 expected_failures = []
250 for klass in self.klasses:
251 if not issubclass(klass, ofp.message.Message):
252 continue
253 def fn():
254 obj = klass(xid=42)
255 buf = obj.pack()
256 obj2 = ofp.message.parse_message(buf)
257 self.assertEquals(obj, obj2)
258 if klass in expected_failures:
259 self.assertRaises(Exception, fn)
260 else:
261 fn()
262
Rich Lanea06d0c32013-03-25 08:52:03 -0700263 def test_show(self):
Rich Lanea06d0c32013-03-25 08:52:03 -0700264 expected_failures = []
265 for klass in self.klasses:
266 def fn():
267 obj = klass()
268 if hasattr(obj, "xid"): obj.xid = 42
269 obj.show()
270 if klass in expected_failures:
271 self.assertRaises(Exception, fn)
272 else:
273 fn()
274
275if __name__ == '__main__':
276 unittest.main()