pyrad 2.3__py3-none-any.whl → 2.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- docs/Makefile +20 -0
- docs/make.bat +36 -0
- docs/source/_static/logo.png +0 -0
- docs/source/api/client.rst +10 -0
- docs/source/api/dictionary.rst +10 -0
- docs/source/api/host.rst +7 -0
- docs/source/api/packet.rst +48 -0
- docs/source/api/proxy.rst +7 -0
- docs/source/api/server.rst +13 -0
- docs/source/conf.py +158 -0
- docs/source/index.rst +75 -0
- example/acct.py +41 -0
- example/auth.py +37 -0
- example/auth_async.py +164 -0
- example/client-coa.py +61 -0
- example/coa.py +40 -0
- example/dictionary +405 -0
- example/dictionary.freeradius +91 -0
- example/pyrad.log +0 -0
- example/server.py +68 -0
- example/server_async.py +117 -0
- example/status.py +26 -0
- pyrad/__init__.py +3 -3
- pyrad/client.py +54 -9
- pyrad/client_async.py +22 -14
- pyrad/dictfile.py +2 -5
- pyrad/dictionary.py +12 -1
- pyrad/host.py +1 -1
- pyrad/packet.py +208 -133
- pyrad/proxy.py +2 -2
- pyrad/server.py +3 -7
- pyrad/server_async.py +4 -5
- pyrad/tests/__init__.py +2 -2
- pyrad/tests/mock.py +5 -1
- pyrad/tests/{testBidict.py → test_bidict.py} +2 -2
- pyrad/tests/{testClient.py → test_client.py} +28 -30
- pyrad/tests/{testDictionary.py → test_dictionary.py} +38 -21
- pyrad/tests/{testHost.py → test_host.py} +10 -10
- pyrad/tests/test_packet.py +679 -0
- pyrad/tests/{testProxy.py → test_proxy.py} +11 -11
- pyrad/tests/{testServer.py → test_server.py} +35 -33
- pyrad/tests/test_tools.py +126 -0
- pyrad/tools.py +254 -158
- {pyrad-2.3.dist-info → pyrad-2.5.0.dist-info}/METADATA +44 -20
- pyrad-2.5.0.dist-info/RECORD +51 -0
- {pyrad-2.3.dist-info → pyrad-2.5.0.dist-info}/WHEEL +1 -1
- {pyrad-2.3.dist-info → pyrad-2.5.0.dist-info/licenses}/LICENSE.txt +2 -1
- pyrad-2.5.0.dist-info/top_level.txt +3 -0
- pyrad/tests/testPacket.py +0 -530
- pyrad/tests/testTools.py +0 -122
- pyrad-2.3.dist-info/RECORD +0 -29
- pyrad-2.3.dist-info/top_level.txt +0 -1
- {pyrad-2.3.dist-info → pyrad-2.5.0.dist-info}/zip-safe +0 -0
pyrad/proxy.py
CHANGED
|
@@ -25,7 +25,7 @@ class Proxy(Server):
|
|
|
25
25
|
self._proxyfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
26
26
|
self._fdmap[self._proxyfd.fileno()] = self._proxyfd
|
|
27
27
|
self._poll.register(self._proxyfd.fileno(),
|
|
28
|
-
|
|
28
|
+
(select.POLLIN | select.POLLPRI | select.POLLERR))
|
|
29
29
|
|
|
30
30
|
def _HandleProxyPacket(self, pkt):
|
|
31
31
|
"""Process a packet received on the reply socket.
|
|
@@ -41,7 +41,7 @@ class Proxy(Server):
|
|
|
41
41
|
pkt.secret = self.hosts[pkt.source[0]].secret
|
|
42
42
|
|
|
43
43
|
if pkt.code not in [packet.AccessAccept, packet.AccessReject,
|
|
44
|
-
|
|
44
|
+
packet.AccountingResponse]:
|
|
45
45
|
raise ServerPacketError('Received non-response on proxy socket')
|
|
46
46
|
|
|
47
47
|
def _ProcessInput(self, fd):
|
pyrad/server.py
CHANGED
|
@@ -114,7 +114,7 @@ class Server(host.Host):
|
|
|
114
114
|
"""
|
|
115
115
|
results = set()
|
|
116
116
|
try:
|
|
117
|
-
tmp = socket.getaddrinfo(addr,
|
|
117
|
+
tmp = socket.getaddrinfo(addr, 80)
|
|
118
118
|
except socket.gaierror:
|
|
119
119
|
return []
|
|
120
120
|
|
|
@@ -123,10 +123,9 @@ class Server(host.Host):
|
|
|
123
123
|
|
|
124
124
|
return results
|
|
125
125
|
|
|
126
|
-
|
|
127
126
|
def BindToAddress(self, addr):
|
|
128
|
-
"""Add an address to listen
|
|
129
|
-
|
|
127
|
+
"""Add an address to listen on a specific interface.
|
|
128
|
+
String "0.0.0.0" indicates you want to listen on all interfaces.
|
|
130
129
|
|
|
131
130
|
:param addr: IP address to listen on
|
|
132
131
|
:type addr: string
|
|
@@ -151,7 +150,6 @@ class Server(host.Host):
|
|
|
151
150
|
coafd.bind((address, self.coaport))
|
|
152
151
|
self.coafds.append(coafd)
|
|
153
152
|
|
|
154
|
-
|
|
155
153
|
def HandleAuthPacket(self, pkt):
|
|
156
154
|
"""Authentication packet handler.
|
|
157
155
|
This is an empty function that is called when a valid
|
|
@@ -247,7 +245,6 @@ class Server(host.Host):
|
|
|
247
245
|
:type pkt: Packet class instance
|
|
248
246
|
"""
|
|
249
247
|
self._AddSecret(pkt)
|
|
250
|
-
pkt.secret = self.hosts[pkt.source[0]].secret
|
|
251
248
|
if pkt.code == packet.CoARequest:
|
|
252
249
|
self.HandleCoaPacket(pkt)
|
|
253
250
|
elif pkt.code == packet.DisconnectRequest:
|
|
@@ -255,7 +252,6 @@ class Server(host.Host):
|
|
|
255
252
|
else:
|
|
256
253
|
raise ServerPacketError('Received non-coa packet on coa port')
|
|
257
254
|
|
|
258
|
-
|
|
259
255
|
def _GrabPacket(self, pktgen, fd):
|
|
260
256
|
"""Read a packet from a network connection.
|
|
261
257
|
This method assumes there is data waiting for to be read.
|
pyrad/server_async.py
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import logging
|
|
7
|
-
import traceback
|
|
8
7
|
|
|
9
8
|
from abc import abstractmethod, ABCMeta
|
|
10
9
|
from enum import Enum
|
|
@@ -58,7 +57,7 @@ class DatagramProtocolServer(asyncio.Protocol):
|
|
|
58
57
|
if addr[0] in self.hosts:
|
|
59
58
|
remote_host = self.hosts[addr[0]]
|
|
60
59
|
elif '0.0.0.0' in self.hosts:
|
|
61
|
-
remote_host = self.hosts['0.0.0.0']
|
|
60
|
+
remote_host = self.hosts['0.0.0.0']
|
|
62
61
|
else:
|
|
63
62
|
self.logger.warn('[%s:%d] Drop package from unknown source %s', self.ip, self.port, addr)
|
|
64
63
|
return
|
|
@@ -81,7 +80,7 @@ class DatagramProtocolServer(asyncio.Protocol):
|
|
|
81
80
|
dict=self.server.dict,
|
|
82
81
|
packet=data)
|
|
83
82
|
if self.server.enable_pkt_verify:
|
|
84
|
-
if req.VerifyAuthRequest():
|
|
83
|
+
if not req.VerifyAuthRequest():
|
|
85
84
|
raise PacketError('Packet verification failed')
|
|
86
85
|
|
|
87
86
|
elif self.server_type == ServerType.Coa:
|
|
@@ -91,7 +90,7 @@ class DatagramProtocolServer(asyncio.Protocol):
|
|
|
91
90
|
dict=self.server.dict,
|
|
92
91
|
packet=data)
|
|
93
92
|
if self.server.enable_pkt_verify:
|
|
94
|
-
if req.VerifyCoARequest():
|
|
93
|
+
if not req.VerifyCoARequest():
|
|
95
94
|
raise PacketError('Packet verification failed')
|
|
96
95
|
|
|
97
96
|
elif self.server_type == ServerType.Acct:
|
|
@@ -102,7 +101,7 @@ class DatagramProtocolServer(asyncio.Protocol):
|
|
|
102
101
|
dict=self.server.dict,
|
|
103
102
|
packet=data)
|
|
104
103
|
if self.server.enable_pkt_verify:
|
|
105
|
-
if req.VerifyAcctRequest():
|
|
104
|
+
if not req.VerifyAcctRequest():
|
|
106
105
|
raise PacketError('Packet verification failed')
|
|
107
106
|
|
|
108
107
|
# Call request callback
|
pyrad/tests/__init__.py
CHANGED
pyrad/tests/mock.py
CHANGED
|
@@ -43,11 +43,14 @@ class MockSocket:
|
|
|
43
43
|
self.address = None
|
|
44
44
|
self.output = []
|
|
45
45
|
|
|
46
|
+
# Always initialize data so recv() never fails.
|
|
47
|
+
# If data is provided, use it; otherwise behave like "no data available".
|
|
48
|
+
self.data = data if data is not None else b""
|
|
49
|
+
|
|
46
50
|
if data is not None:
|
|
47
51
|
(self.read_end, self.write_end) = os.pipe()
|
|
48
52
|
fcntl.fcntl(self.write_end, fcntl.F_SETFL, os.O_NONBLOCK)
|
|
49
53
|
os.write(self.write_end, data)
|
|
50
|
-
self.data = data
|
|
51
54
|
else:
|
|
52
55
|
self.read_end = 1
|
|
53
56
|
self.write_end = None
|
|
@@ -59,6 +62,7 @@ class MockSocket:
|
|
|
59
62
|
self.address = address
|
|
60
63
|
|
|
61
64
|
def recv(self, buffer):
|
|
65
|
+
# Return up to `buffer` bytes; if empty, return b"" (no data).
|
|
62
66
|
return self.data[:buffer]
|
|
63
67
|
|
|
64
68
|
def sendto(self, data, target):
|
|
@@ -52,5 +52,5 @@ class BiDictTests(unittest.TestCase):
|
|
|
52
52
|
self.bidict.Add("shake", "vanilla")
|
|
53
53
|
self.bidict.Add("pie", "custard")
|
|
54
54
|
self.assertRaises(KeyError, operator.getitem, self.bidict, "missing")
|
|
55
|
-
self.
|
|
56
|
-
self.
|
|
55
|
+
self.assertEqual(self.bidict["shake"], "vanilla")
|
|
56
|
+
self.assertEqual(self.bidict["pie"], "custard")
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import select
|
|
2
2
|
import socket
|
|
3
3
|
import unittest
|
|
4
|
-
import
|
|
4
|
+
from .mock import MockPacket
|
|
5
|
+
from .mock import MockPoll
|
|
6
|
+
from .mock import MockSocket
|
|
5
7
|
from pyrad.client import Client
|
|
6
8
|
from pyrad.client import Timeout
|
|
7
9
|
from pyrad.packet import AuthPacket
|
|
8
10
|
from pyrad.packet import AcctPacket
|
|
9
11
|
from pyrad.packet import AccessRequest
|
|
10
12
|
from pyrad.packet import AccountingRequest
|
|
11
|
-
from pyrad.tests.mock import MockPacket
|
|
12
|
-
from pyrad.tests.mock import MockPoll
|
|
13
|
-
from pyrad.tests.mock import MockSocket
|
|
14
13
|
|
|
15
14
|
BIND_IP = "127.0.0.1"
|
|
16
15
|
BIND_PORT = 53535
|
|
@@ -22,33 +21,33 @@ class ConstructionTests(unittest.TestCase):
|
|
|
22
21
|
|
|
23
22
|
def testSimpleConstruction(self):
|
|
24
23
|
client = Client(self.server)
|
|
25
|
-
self.
|
|
24
|
+
self.assertTrue(client.server is self.server)
|
|
26
25
|
self.assertEqual(client.authport, 1812)
|
|
27
26
|
self.assertEqual(client.acctport, 1813)
|
|
28
|
-
self.assertEqual(client.secret,
|
|
27
|
+
self.assertEqual(client.secret, b'')
|
|
29
28
|
self.assertEqual(client.retries, 3)
|
|
30
29
|
self.assertEqual(client.timeout, 5)
|
|
31
|
-
self.
|
|
30
|
+
self.assertTrue(client.dict is None)
|
|
32
31
|
|
|
33
32
|
def testParameterOrder(self):
|
|
34
33
|
marker = object()
|
|
35
34
|
client = Client(self.server, 123, 456, 789, "secret", marker)
|
|
36
|
-
self.
|
|
35
|
+
self.assertTrue(client.server is self.server)
|
|
37
36
|
self.assertEqual(client.authport, 123)
|
|
38
37
|
self.assertEqual(client.acctport, 456)
|
|
39
38
|
self.assertEqual(client.coaport, 789)
|
|
40
39
|
self.assertEqual(client.secret, "secret")
|
|
41
|
-
self.
|
|
40
|
+
self.assertTrue(client.dict is marker)
|
|
42
41
|
|
|
43
42
|
def testNamedParameters(self):
|
|
44
43
|
marker = object()
|
|
45
44
|
client = Client(server=self.server, authport=123, acctport=456,
|
|
46
|
-
|
|
47
|
-
self.
|
|
45
|
+
secret="secret", dict=marker)
|
|
46
|
+
self.assertTrue(client.server is self.server)
|
|
48
47
|
self.assertEqual(client.authport, 123)
|
|
49
48
|
self.assertEqual(client.acctport, 456)
|
|
50
49
|
self.assertEqual(client.secret, "secret")
|
|
51
|
-
self.
|
|
50
|
+
self.assertTrue(client.dict is marker)
|
|
52
51
|
|
|
53
52
|
|
|
54
53
|
class SocketTests(unittest.TestCase):
|
|
@@ -58,7 +57,6 @@ class SocketTests(unittest.TestCase):
|
|
|
58
57
|
self.orgsocket = socket.socket
|
|
59
58
|
socket.socket = MockSocket
|
|
60
59
|
|
|
61
|
-
|
|
62
60
|
def tearDown(self):
|
|
63
61
|
socket.socket = self.orgsocket
|
|
64
62
|
|
|
@@ -66,13 +64,13 @@ class SocketTests(unittest.TestCase):
|
|
|
66
64
|
self.client._SocketOpen()
|
|
67
65
|
sock = self.client._socket
|
|
68
66
|
self.client._SocketOpen()
|
|
69
|
-
self.
|
|
67
|
+
self.assertTrue(sock is self.client._socket)
|
|
70
68
|
|
|
71
69
|
def testBind(self):
|
|
72
70
|
self.client.bind((BIND_IP, BIND_PORT))
|
|
73
71
|
self.assertEqual(self.client._socket.address, (BIND_IP, BIND_PORT))
|
|
74
72
|
self.assertEqual(self.client._socket.options,
|
|
75
|
-
|
|
73
|
+
[(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)])
|
|
76
74
|
|
|
77
75
|
def testBindClosesSocket(self):
|
|
78
76
|
s = MockSocket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
@@ -107,7 +105,7 @@ class SocketTests(unittest.TestCase):
|
|
|
107
105
|
packet = MockPacket(AccessRequest)
|
|
108
106
|
self.assertRaises(Timeout, self.client._SendPacket, packet, 432)
|
|
109
107
|
self.assertEqual(self.client._socket.output,
|
|
110
|
-
|
|
108
|
+
[("request packet", (self.server, 432))])
|
|
111
109
|
|
|
112
110
|
def testDoubleRetry(self):
|
|
113
111
|
self.client.retries = 2
|
|
@@ -115,15 +113,15 @@ class SocketTests(unittest.TestCase):
|
|
|
115
113
|
packet = MockPacket(AccessRequest)
|
|
116
114
|
self.assertRaises(Timeout, self.client._SendPacket, packet, 432)
|
|
117
115
|
self.assertEqual(self.client._socket.output,
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
[("request packet", (self.server, 432)),
|
|
117
|
+
("request packet", (self.server, 432))])
|
|
120
118
|
|
|
121
119
|
def testAuthDelay(self):
|
|
122
120
|
self.client.retries = 2
|
|
123
121
|
self.client.timeout = 1
|
|
124
122
|
packet = MockPacket(AccessRequest)
|
|
125
123
|
self.assertRaises(Timeout, self.client._SendPacket, packet, 432)
|
|
126
|
-
self.
|
|
124
|
+
self.assertFalse("Acct-Delay-Time" in packet)
|
|
127
125
|
|
|
128
126
|
def testSingleAccountDelay(self):
|
|
129
127
|
self.client.retries = 2
|
|
@@ -142,24 +140,24 @@ class SocketTests(unittest.TestCase):
|
|
|
142
140
|
def testIgnorePacketError(self):
|
|
143
141
|
self.client.retries = 1
|
|
144
142
|
self.client.timeout = 1
|
|
145
|
-
self.client._socket = MockSocket(1, 2,
|
|
143
|
+
self.client._socket = MockSocket(1, 2, b'valid reply')
|
|
146
144
|
packet = MockPacket(AccountingRequest, verify=True, error=True)
|
|
147
145
|
self.assertRaises(Timeout, self.client._SendPacket, packet, 432)
|
|
148
146
|
|
|
149
147
|
def testValidReply(self):
|
|
150
148
|
self.client.retries = 1
|
|
151
149
|
self.client.timeout = 1
|
|
152
|
-
self.client._socket = MockSocket(1, 2,
|
|
150
|
+
self.client._socket = MockSocket(1, 2, b'valid reply')
|
|
153
151
|
self.client._poll = MockPoll()
|
|
154
152
|
MockPoll.results = [(1, select.POLLIN)]
|
|
155
153
|
packet = MockPacket(AccountingRequest, verify=True)
|
|
156
154
|
reply = self.client._SendPacket(packet, 432)
|
|
157
|
-
self.
|
|
155
|
+
self.assertTrue(reply is packet.reply)
|
|
158
156
|
|
|
159
157
|
def testInvalidReply(self):
|
|
160
158
|
self.client.retries = 1
|
|
161
159
|
self.client.timeout = 1
|
|
162
|
-
self.client._socket = MockSocket(1, 2,
|
|
160
|
+
self.client._socket = MockSocket(1, 2, b'invalid reply')
|
|
163
161
|
MockPoll.results = [(1, select.POLLIN)]
|
|
164
162
|
packet = MockPacket(AccountingRequest, verify=False)
|
|
165
163
|
self.assertRaises(Timeout, self.client._SendPacket, packet, 432)
|
|
@@ -168,18 +166,18 @@ class SocketTests(unittest.TestCase):
|
|
|
168
166
|
class OtherTests(unittest.TestCase):
|
|
169
167
|
def setUp(self):
|
|
170
168
|
self.server = object()
|
|
171
|
-
self.client = Client(self.server, secret=
|
|
169
|
+
self.client = Client(self.server, secret=b'zeer geheim')
|
|
172
170
|
|
|
173
171
|
def testCreateAuthPacket(self):
|
|
174
172
|
packet = self.client.CreateAuthPacket(id=15)
|
|
175
|
-
self.
|
|
176
|
-
self.
|
|
173
|
+
self.assertTrue(isinstance(packet, AuthPacket))
|
|
174
|
+
self.assertTrue(packet.dict is self.client.dict)
|
|
177
175
|
self.assertEqual(packet.id, 15)
|
|
178
|
-
self.assertEqual(packet.secret,
|
|
176
|
+
self.assertEqual(packet.secret, b'zeer geheim')
|
|
179
177
|
|
|
180
178
|
def testCreateAcctPacket(self):
|
|
181
179
|
packet = self.client.CreateAcctPacket(id=15)
|
|
182
|
-
self.
|
|
183
|
-
self.
|
|
180
|
+
self.assertTrue(isinstance(packet, AcctPacket))
|
|
181
|
+
self.assertTrue(packet.dict is self.client.dict)
|
|
184
182
|
self.assertEqual(packet.id, 15)
|
|
185
|
-
self.assertEqual(packet.secret,
|
|
183
|
+
self.assertEqual(packet.secret, b'zeer geheim')
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
import operator
|
|
3
3
|
import os
|
|
4
|
-
from
|
|
5
|
-
|
|
4
|
+
from io import StringIO
|
|
5
|
+
|
|
6
|
+
from . import home
|
|
6
7
|
from pyrad.dictionary import Attribute
|
|
7
8
|
from pyrad.dictionary import Dictionary
|
|
8
9
|
from pyrad.dictionary import ParseError
|
|
@@ -26,7 +27,7 @@ class AttributeTests(unittest.TestCase):
|
|
|
26
27
|
|
|
27
28
|
def testNamedConstructionParameters(self):
|
|
28
29
|
attr = Attribute(name='name', code='code', datatype='integer',
|
|
29
|
-
|
|
30
|
+
vendor='vendor')
|
|
30
31
|
self.assertEqual(attr.name, 'name')
|
|
31
32
|
self.assertEqual(attr.code, 'code')
|
|
32
33
|
self.assertEqual(attr.type, 'integer')
|
|
@@ -35,7 +36,7 @@ class AttributeTests(unittest.TestCase):
|
|
|
35
36
|
|
|
36
37
|
def testValues(self):
|
|
37
38
|
attr = Attribute('name', 'code', 'integer', False, 'vendor',
|
|
38
|
-
|
|
39
|
+
dict(pie='custard', shake='vanilla'))
|
|
39
40
|
self.assertEqual(len(attr.values), 2)
|
|
40
41
|
self.assertEqual(attr.values['shake'], 'vanilla')
|
|
41
42
|
|
|
@@ -54,14 +55,13 @@ class DictionaryInterfaceTests(unittest.TestCase):
|
|
|
54
55
|
self.assertEqual(dict.has_key('test'), True)
|
|
55
56
|
|
|
56
57
|
def testReadonlyContainer(self):
|
|
57
|
-
import six
|
|
58
58
|
dict = Dictionary()
|
|
59
59
|
self.assertRaises(TypeError,
|
|
60
|
-
|
|
60
|
+
operator.setitem, dict, 'test', 'dummy')
|
|
61
61
|
self.assertRaises(AttributeError,
|
|
62
|
-
|
|
62
|
+
operator.attrgetter('clear'), dict)
|
|
63
63
|
self.assertRaises(AttributeError,
|
|
64
|
-
|
|
64
|
+
operator.attrgetter('update'), dict)
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
class DictionaryParsingTests(unittest.TestCase):
|
|
@@ -69,7 +69,7 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
69
69
|
simple_dict_values = [
|
|
70
70
|
('Test-String', 1, 'string'),
|
|
71
71
|
('Test-Octets', 2, 'octets'),
|
|
72
|
-
('Test-Integer',
|
|
72
|
+
('Test-Integer', 0x03, 'integer'),
|
|
73
73
|
('Test-Ip-Address', 4, 'ipaddr'),
|
|
74
74
|
('Test-Ipv6-Address', 5, 'ipv6addr'),
|
|
75
75
|
('Test-If-Id', 6, 'ifid'),
|
|
@@ -78,11 +78,13 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
78
78
|
('Test-Tlv', 9, 'tlv'),
|
|
79
79
|
('Test-Tlv-Str', 1, 'string'),
|
|
80
80
|
('Test-Tlv-Int', 2, 'integer'),
|
|
81
|
-
('Test-Integer64', 10, 'integer64')
|
|
81
|
+
('Test-Integer64', 10, 'integer64'),
|
|
82
|
+
('Test-Integer64-Hex', 10, 'integer64'),
|
|
83
|
+
('Test-Integer64-Oct', 10, 'integer64'),
|
|
82
84
|
]
|
|
83
85
|
|
|
84
86
|
def setUp(self):
|
|
85
|
-
self.path = os.path.join(home, '
|
|
87
|
+
self.path = os.path.join(home, 'data')
|
|
86
88
|
self.dict = Dictionary(os.path.join(self.path, 'simple'))
|
|
87
89
|
|
|
88
90
|
def testParseEmptyDictionary(self):
|
|
@@ -98,7 +100,7 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
98
100
|
self.assertEqual(len(dict), 2)
|
|
99
101
|
|
|
100
102
|
def testParseSimpleDictionary(self):
|
|
101
|
-
self.assertEqual(len(self.dict),len(self.simple_dict_values))
|
|
103
|
+
self.assertEqual(len(self.dict), len(self.simple_dict_values))
|
|
102
104
|
for (attr, code, type) in self.simple_dict_values:
|
|
103
105
|
attr = self.dict[attr]
|
|
104
106
|
self.assertEqual(attr.code, code)
|
|
@@ -167,7 +169,7 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
167
169
|
self.assertEqual(len(self.dict['Test-Integer'].values), 1)
|
|
168
170
|
self.assertEqual(
|
|
169
171
|
DecodeAttr('integer',
|
|
170
|
-
|
|
172
|
+
self.dict['Test-Integer'].values['Value-Six']),
|
|
171
173
|
5)
|
|
172
174
|
|
|
173
175
|
def testInteger64ValueParsing(self):
|
|
@@ -176,7 +178,7 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
176
178
|
self.assertEqual(len(self.dict['Test-Integer64'].values), 1)
|
|
177
179
|
self.assertEqual(
|
|
178
180
|
DecodeAttr('integer64',
|
|
179
|
-
|
|
181
|
+
self.dict['Test-Integer64'].values['Value-Six']),
|
|
180
182
|
5)
|
|
181
183
|
|
|
182
184
|
def testStringValueParsing(self):
|
|
@@ -186,12 +188,28 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
186
188
|
self.assertEqual(len(self.dict['Test-String'].values), 1)
|
|
187
189
|
self.assertEqual(
|
|
188
190
|
DecodeAttr('string',
|
|
189
|
-
|
|
191
|
+
self.dict['Test-String'].values['Value-Custard']),
|
|
190
192
|
'custardpie')
|
|
191
193
|
|
|
194
|
+
def testOctetValueParsing(self):
|
|
195
|
+
self.assertEqual(len(self.dict['Test-Octets'].values), 0)
|
|
196
|
+
self.dict.ReadDictionary(StringIO(
|
|
197
|
+
'ATTRIBUTE Test-Octets 1 octets\n'
|
|
198
|
+
'VALUE Test-Octets Value-A 65\n' # "A"
|
|
199
|
+
'VALUE Test-Octets Value-B 0x42\n')) # "B"
|
|
200
|
+
self.assertEqual(len(self.dict['Test-Octets'].values), 2)
|
|
201
|
+
self.assertEqual(
|
|
202
|
+
DecodeAttr('octets',
|
|
203
|
+
self.dict['Test-Octets'].values['Value-A']),
|
|
204
|
+
b'A')
|
|
205
|
+
self.assertEqual(
|
|
206
|
+
DecodeAttr('octets',
|
|
207
|
+
self.dict['Test-Octets'].values['Value-B']),
|
|
208
|
+
b'B')
|
|
209
|
+
|
|
192
210
|
def testTlvParsing(self):
|
|
193
211
|
self.assertEqual(len(self.dict['Test-Tlv'].sub_attributes), 2)
|
|
194
|
-
self.assertEqual(self.dict['Test-Tlv'].sub_attributes, {1:'Test-Tlv-Str', 2: 'Test-Tlv-Int'})
|
|
212
|
+
self.assertEqual(self.dict['Test-Tlv'].sub_attributes, {1: 'Test-Tlv-Str', 2: 'Test-Tlv-Int'})
|
|
195
213
|
|
|
196
214
|
def testSubTlvParsing(self):
|
|
197
215
|
for (attr, _, _) in self.simple_dict_values:
|
|
@@ -209,7 +227,6 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
209
227
|
self.assertEqual(full_dict['Simplon-Tlv-Int'].is_sub_attribute, True)
|
|
210
228
|
self.assertEqual(full_dict['Simplon-Tlv-Int'].parent, full_dict['Simplon-Tlv'])
|
|
211
229
|
|
|
212
|
-
|
|
213
230
|
def testVenderTooFewColumnsError(self):
|
|
214
231
|
try:
|
|
215
232
|
self.dict.ReadDictionary(StringIO('VENDOR Simplon'))
|
|
@@ -220,7 +237,7 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
220
237
|
|
|
221
238
|
def testVendorParsing(self):
|
|
222
239
|
self.assertRaises(ParseError, self.dict.ReadDictionary,
|
|
223
|
-
|
|
240
|
+
StringIO('ATTRIBUTE Test-Type 1 integer Simplon'))
|
|
224
241
|
self.dict.ReadDictionary(StringIO('VENDOR Simplon 42'))
|
|
225
242
|
self.assertEqual(self.dict.vendors['Simplon'], 42)
|
|
226
243
|
self.dict.ReadDictionary(StringIO(
|
|
@@ -229,7 +246,7 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
229
246
|
|
|
230
247
|
def testVendorOptionError(self):
|
|
231
248
|
self.assertRaises(ParseError, self.dict.ReadDictionary,
|
|
232
|
-
|
|
249
|
+
StringIO('ATTRIBUTE Test-Type 1 integer Simplon'))
|
|
233
250
|
try:
|
|
234
251
|
self.dict.ReadDictionary(StringIO('VENDOR Simplon 42 badoption'))
|
|
235
252
|
except ParseError as e:
|
|
@@ -239,7 +256,7 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
239
256
|
|
|
240
257
|
def testVendorFormatError(self):
|
|
241
258
|
self.assertRaises(ParseError, self.dict.ReadDictionary,
|
|
242
|
-
|
|
259
|
+
StringIO('ATTRIBUTE Test-Type 1 integer Simplon'))
|
|
243
260
|
try:
|
|
244
261
|
self.dict.ReadDictionary(StringIO(
|
|
245
262
|
'VENDOR Simplon 42 format=5,4'))
|
|
@@ -250,7 +267,7 @@ class DictionaryParsingTests(unittest.TestCase):
|
|
|
250
267
|
|
|
251
268
|
def testVendorFormatSyntaxError(self):
|
|
252
269
|
self.assertRaises(ParseError, self.dict.ReadDictionary,
|
|
253
|
-
|
|
270
|
+
StringIO('ATTRIBUTE Test-Type 1 integer Simplon'))
|
|
254
271
|
try:
|
|
255
272
|
self.dict.ReadDictionary(StringIO(
|
|
256
273
|
'VENDOR Simplon 42 format=a,1'))
|
|
@@ -32,20 +32,20 @@ class PacketCreationTests(unittest.TestCase):
|
|
|
32
32
|
|
|
33
33
|
def testCreatePacket(self):
|
|
34
34
|
packet = self.host.CreatePacket(id=15)
|
|
35
|
-
self.
|
|
36
|
-
self.
|
|
35
|
+
self.assertTrue(isinstance(packet, Packet))
|
|
36
|
+
self.assertTrue(packet.dict is self.host.dict)
|
|
37
37
|
self.assertEqual(packet.id, 15)
|
|
38
38
|
|
|
39
39
|
def testCreateAuthPacket(self):
|
|
40
40
|
packet = self.host.CreateAuthPacket(id=15)
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
41
|
+
self.assertTrue(isinstance(packet, AuthPacket))
|
|
42
|
+
self.assertTrue(packet.dict is self.host.dict)
|
|
43
43
|
self.assertEqual(packet.id, 15)
|
|
44
44
|
|
|
45
45
|
def testCreateAcctPacket(self):
|
|
46
46
|
packet = self.host.CreateAcctPacket(id=15)
|
|
47
|
-
self.
|
|
48
|
-
self.
|
|
47
|
+
self.assertTrue(isinstance(packet, AcctPacket))
|
|
48
|
+
self.assertTrue(packet.dict is self.host.dict)
|
|
49
49
|
self.assertEqual(packet.id, 15)
|
|
50
50
|
|
|
51
51
|
|
|
@@ -78,10 +78,10 @@ class PacketSendTest(unittest.TestCase):
|
|
|
78
78
|
|
|
79
79
|
def testSendPacket(self):
|
|
80
80
|
self.host.SendPacket(self.fd, self.packet)
|
|
81
|
-
self.
|
|
82
|
-
self.
|
|
81
|
+
self.assertTrue(self.fd.data is self.packet.packet)
|
|
82
|
+
self.assertTrue(self.fd.target is self.packet.source)
|
|
83
83
|
|
|
84
84
|
def testSendReplyPacket(self):
|
|
85
85
|
self.host.SendReplyPacket(self.fd, self.packet)
|
|
86
|
-
self.
|
|
87
|
-
self.
|
|
86
|
+
self.assertTrue(self.fd.data is self.packet.replypacket)
|
|
87
|
+
self.assertTrue(self.fd.target is self.packet.source)
|