Skip to content

Commit 6ad0444

Browse files
committed
Test updated C*Logix reply_elements calculation
1 parent 73a90c4 commit 6ad0444

File tree

3 files changed

+45
-45
lines changed

3 files changed

+45
-45
lines changed

server/enip/logix.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -230,19 +230,21 @@ def reply_elements( self, attribute, data, context ):
230230
# have a 'beg' Element that contains the first byte at offset 'off'; compute the endmax
231231
# that contains the last byte at offset off+max_siz-1. The data may specify the
232232
# (remaining) .max_size payload available.
233-
endadvance = max(( offremains + max_size + siz - 1 ) // siz, 1 ) # rounds up
234-
endmax = beg + endadvance
233+
endadv = max(( offremains + max_size + siz - 1 ) // siz, 1 ) # rounds up
234+
endmax = beg + endadv
235235
else:
236-
endadvance = len( data[context].data )
237-
endmax = beg + endadvance
236+
endadv = len( data[context].data )
237+
endmax = beg + endadv
238238
assert endmax <= endactual, \
239239
"Attribute %s capacity exceeded; writing %d elements beginning at index %d" % (
240240
attribute, len( data[context].data ), beg )
241241
end = min( endactual, endmax )
242-
log.info( "offset: {off:6d} siz: {siz:3d}, beg: {beg:3d}, end: {end:3d}, endmax: {endmax:3d}, offremains: {offremains}".format(
243-
off=off, siz=siz, beg=beg, end=end, endmax=endmax, offremains=offremains ))
242+
log.info( "offset: {off:6d} siz: {siz:3d}, beg: {beg:3d}, endadv: {endadv:3d}, end: {end:3d}, endmax: {endmax:3d}, offremains: {offremains}".format(
243+
off=off, siz=siz, beg=beg, end=end, endadv=endadv, endmax=endmax, offremains=offremains ))
244244
assert 0 <= beg < cnt, \
245245
"Attribute %r initial element invalid: %r" % ( attribute, (beg, end) )
246+
assert elm <= cnt, \
247+
"Attribute %r elements requested invalid: %r" % ( attribute, elm )
246248
assert beg < end, \
247249
"Attribute %r ending element before beginning: %r" % ( attribute, (beg, end) )
248250
return (beg,end,endactual,offremains,max_size)
@@ -421,9 +423,9 @@ def request( self, data, addr=None ):
421423
else:
422424
# We don't presently support a non-zero .offset for indeterminately sized types
423425
# (eg. STRING/SSTRING, etc.), or a sub-element offset for basic data types.
424-
assert off == 0 or (
426+
assert offremains == 0 or (
425427
attribute.parser.tag_type < STRING.tag_type
426-
and off % attribute.parser.struct_calcsize == 0 )
428+
and offremains % attribute.parser.struct_calcsize == 0 )
427429
completed = end == endactual
428430
data[context].data = recs
429431
log.detail( "%s Reading %3d elements %3d-%3d %s from %s: %r",

server/enip/parser_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def test_enip_format():
8282
'empty.sub': [],
8383
'empty.totally_null': None,
8484
'empty.true_false': (True, False),
85-
'long_bytes': bytes(hexload('''
85+
'long_bytes': bytes(hexload(r'''
8686
00000000: 6f 00 00 00 06 00 00 00 52 54 31 2d 31 37 00 00 |o.......RT1-17..|
8787
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
8888
00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -122,7 +122,7 @@ def test_enip_format():
122122
00000240: 0c 00 00 00 07 00 00 00 0a 00 00 00 28 00 00 00 |............(...|
123123
00000250: 34 00 00 00 fe 58 0a 00 |4....X..|
124124
''')),
125-
'short_bytes': bytes(hexload('''
125+
'short_bytes': bytes(hexload(r'''
126126
00000000: 6f 00 00 00 |o...|
127127
''')),
128128
'some_ascii': 'The quick brown fox \\\\ jumped over the "lazy" dog',

server/logix_test.py

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ def test_logix_multiple():
204204
description, encoded, response )
205205

206206

207-
# Test that we correctly compute beg,end,endactual for various Read Tag Fragmented scenarios,
207+
# Test that we correctly compute beg,end,endact for various Read Tag Fragmented scenarios,
208208
# with 2-byte and 4-byte types. For the purposes of this test, we only look at path...elements.
209209
data = cpppo.dotdict()
210210
data.service = Obj.RD_FRG_RPY
@@ -215,28 +215,29 @@ def test_logix_multiple():
215215
data.read_frag = {}
216216
data.read_frag.elements = 1000
217217
data.read_frag.offset = 0
218+
data.read_frag.max_size = 500
218219

219220
# Reply maximum size limited
220-
beg,end,endactual = Obj.reply_elements( Obj_a1, data, 'read_frag' )
221-
assert beg == 0 and end == 125 and endactual == 1000 # DINT == 4 bytes
222-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
223-
assert beg == 0 and end == 250 and endactual == 1000 # INT == 2 bytes
221+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a1, data, 'read_frag' )
222+
assert beg == 0 and end == 125 and endact == 1000 and offrem == 0 and maxsiz == 500 # DINT == 4 bytes
223+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
224+
assert beg == 0 and end == 250 and endact == 1000 and offrem == 0 and maxsiz == 500 # INT == 2 bytes
224225

225226
data.read_frag.offset = 125*4 # OK, second request; begin after byte offset of first
226-
beg,end,endactual = Obj.reply_elements( Obj_a1, data, 'read_frag' )
227-
assert beg == 125 and end == 250 and endactual == 1000 # DINT == 4 bytes
227+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a1, data, 'read_frag' )
228+
assert beg == 125 and end == 250 and endact == 1000 and offrem == 0 and maxsiz == 500 # DINT == 4 bytes
228229

229230
# Request elements limited; 0 offset
230231
data.read_frag.elements = 30
231232
data.read_frag.offset = 0
232-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
233-
assert beg == 0 and end == 30 and endactual == 30 # INT == 2 bytes
233+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
234+
assert beg == 0 and end == 30 and endact == 30 and offrem == 0 and maxsiz == 500 # INT == 2 bytes
234235

235236
# Request elements limited; +'ve offset
236237
data.read_frag.elements = 70
237238
data.read_frag.offset = 80
238-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
239-
assert beg == 40 and end == 70 and endactual == 70 # INT == 2 bytes
239+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
240+
assert beg == 40 and end == 70 and endact == 70 and offrem == 0 and maxsiz == 500 # INT == 2 bytes
240241

241242
# Request limited by size of data provided (Write Tag [Fragmented])
242243
data = cpppo.dotdict()
@@ -249,16 +250,16 @@ def test_logix_multiple():
249250
data.write_frag.data = [0] * 100 # 100 elements provided in this request
250251
data.write_frag.elements = 200 # Total request is to write 200 elements
251252
data.write_frag.offset = 16 # request starts 16 bytes in (8 INTs)
252-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'write_frag' )
253-
assert beg == 8 and end == 108 and endactual == 200 # INT == 2 bytes
253+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'write_frag' )
254+
assert beg == 8 and end == 108 and endact == 200 # INT == 2 bytes
254255

255256
# ... same, but lets say request started somewhere in the middle of the array
256257
data.path = { 'segment': [ cpppo.dotdict( d )
257258
for d in [
258259
{'element': 222 },
259260
]] }
260-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'write_frag' )
261-
assert beg == 8+222 and end == 108+222 and endactual == 200+222 # INT == 2 bytes
261+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'write_frag' )
262+
assert beg == 8+222 and end == 108+222 and endact == 200+222 # INT == 2 bytes
262263

263264
# Ensure correct computation of (beg,end] that are byte-offset and data/size limited
264265
data = cpppo.dotdict()
@@ -268,15 +269,15 @@ def test_logix_multiple():
268269
data.write_frag = {}
269270
data.write_frag.data = [3,4,5,6]
270271
data.write_frag.offset = 6
271-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'write_frag' )
272-
assert beg == 3 and end == 7 and endactual == 1000 # INT == 2 bytes
272+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'write_frag' )
273+
assert beg == 3 and end == 7 and endact == 1000 # INT == 2 bytes
273274

274275
# Trigger the error cases only accessible via write
275276

276277
# Too many elements provided for attribute capacity
277278
data.write_frag.offset = ( 1000 - 3 ) * 2
278279
try:
279-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'write_frag' )
280+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'write_frag' )
280281
assert False, "Should have raised Exception due to capacity"
281282
except Exception as exc:
282283
assert "capacity exceeded" in str( exc )
@@ -287,38 +288,36 @@ def test_logix_multiple():
287288

288289
data.read_frag = {}
289290
data.read_frag.offset = 6
290-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
291-
assert beg == 3 and end == 253 and endactual == 1000 # INT == 2 bytes
291+
data.read_frag.max_size = 500
292+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
293+
assert beg == 3 and end == 253 and endact == 1000 # INT == 2 bytes
292294

293295
# And we should be able to read with an offset right up to the last element
294296
data.read_frag.offset = 1998
295-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
296-
assert beg == 999 and end == 1000 and endactual == 1000 # INT == 2 bytes
297+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
298+
assert beg == 999 and end == 1000 and endact == 1000 # INT == 2 bytes
297299

298300

299301
# Trigger all the remaining error cases
300302

301303
# Unknown service
302304
data.service = Obj.RD_FRG_REQ
303305
try:
304-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
306+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
305307
assert False, "Should have raised Exception due to service"
306308
except Exception as exc:
307309
assert "unknown service" in str( exc )
308310

309311
# Offset indivisible by element size
310312
data.service = Obj.RD_FRG_RPY
311313
data.read_frag.offset = 7
312-
try:
313-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
314-
assert False, "Should have raised Exception due to odd byte offset"
315-
except Exception as exc:
316-
assert "element boundary" in str( exc )
314+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
315+
assert beg == 3 and end == 254 and endact == 1000 and offrem == 1 and maxsiz == 500
317316

318317
# Initial element outside bounds
319318
data.read_frag.offset = 2000
320319
try:
321-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
320+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
322321
assert False, "Should have raised Exception due to initial element"
323322
except Exception as exc:
324323
assert "initial element invalid" in str( exc )
@@ -327,26 +326,25 @@ def test_logix_multiple():
327326
data.read_frag.offset = 0
328327
data.read_frag.elements = 1001
329328
try:
330-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
329+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
331330
assert False, "Should have raised Exception due to ending element"
332331
except Exception as exc:
333-
assert "ending element invalid" in str( exc )
332+
assert "elements requested invalid" in str( exc )
334333

335334
# Beginning element after ending (should be no way to trigger). This request doesn't specify an
336335
# element in the path, hence defaults to element 0, and asks for a number of elements == 2.
337336
# Thus, there is no 6-byte offset possible (a 2-byte offset is, though).
338337
data.read_frag.offset = 6
339338
data.read_frag.elements = 2
340339
try:
341-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
340+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
342341
assert False, "Should have raised Exception due to ending element order"
343342
except Exception as exc:
344343
assert "ending element before beginning" in str( exc )
345344
data.read_frag.offset = 2
346345
data.read_frag.elements = 2
347-
beg,end,endactual = Obj.reply_elements( Obj_a3, data, 'read_frag' )
348-
assert beg == 1 and end == 2 and endactual == 2 # INT == 2 bytes
349-
346+
beg,end,endact,offrem,maxsiz= Obj.reply_elements( Obj_a3, data, 'read_frag' )
347+
assert beg == 1 and end == 2 and endact == 2 # INT == 2 bytes
350348

351349
# Test an example valid multiple request
352350
data = cpppo.dotdict()

0 commit comments

Comments
 (0)