Skip to content

Commit 279eb80

Browse files
author
Kevin Vu te Laar
committed
binding tests: CI fix and reformat
- Updated PYTHONPATH to match directory structure. - Python integration tests are now executed. - Binding related `.py`-files now adhere to 79-character line length. Signed-off-by: Kevin Vu te Laar <vu.te@rwth-aachen.de>
1 parent 5b887a4 commit 279eb80

7 files changed

Lines changed: 146 additions & 76 deletions

File tree

.gitlab-ci.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ test:unit:
173173
image: ${DOCKER_IMAGE_DEV}:${DOCKER_TAG}
174174
script:
175175
- cmake -S . -B build ${CMAKE_OPTS}
176-
- export PYTHONPATH=$PYTHONPATH:${PWD}/build/clients/python-binding/:${PWD}/python/villas/node/
177-
- cmake --build build ${CMAKE_BUILD_OPTS} --target run-unit-tests run-unit-tests-common run-python-binding-tests
176+
- export PYTHONPATH=$PYTHONPATH:${PWD}/build/python/binding/:${PWD}/python/villas/node/
177+
- cmake --build build ${CMAKE_BUILD_OPTS} --target run-unit-tests run-unit-tests-common run-python-unit-tests
178178
needs:
179179
- job: "build:source: [fedora]"
180180
artifacts: true
@@ -184,7 +184,8 @@ test:integration:
184184
image: ${DOCKER_IMAGE_DEV}:${DOCKER_TAG}
185185
script:
186186
- cmake -S . -B build ${CMAKE_OPTS}
187-
- cmake --build build ${CMAKE_BUILD_OPTS} --target run-integration-tests
187+
- export PYTHONPATH=$PYTHONPATH:${PWD}/build/python/binding/:${PWD}/python/villas/node/
188+
- cmake --build build ${CMAKE_BUILD_OPTS} --target run-integration-tests run-python-integration-tests
188189
artifacts:
189190
name: ${CI_PROJECT_NAME}-integration-tests-${CI_BUILD_REF}
190191
when: always

python/villas/node/binding.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ class SamplesArray:
2020
Wrapper for a block of samples with automatic memory management.
2121
2222
Supports:
23-
- Reading block slices in combination with node_read().
24-
- Writing block slices in combination with node_write().
23+
- Reading block slices in combination with `node_read()`.
24+
- Writing block slices in combination with `node_write()`.
2525
- Automatic (de-)allocation of samples.
2626
2727
Notes:
@@ -39,7 +39,8 @@ def _bulk_allocation(self, start_idx: int, end_idx: int, smpl_length: int):
3939
4040
Notes:
4141
- Block is determined by `start_idx`, `end_idx`
42-
- A sample can hold multiple signals. smpl_length corresponds to the number of signals.
42+
- Samples can hold multiple signals.
43+
- `smpl_length` corresponds to the number of signals.
4344
"""
4445
return self._smps.bulk_alloc(start_idx, end_idx, smpl_length)
4546

@@ -48,10 +49,10 @@ def _get_block_handle(self, start_idx: Optional[int] = None):
4849
Get a handle to a block of samples.
4950
5051
Args:
51-
start_idx (Optional[int]): Starting index of the block. Defaults to 0.
52+
start_idx (Optional[int]): Starting index of the block. Default 0.
5253
5354
Returns:
54-
vsample**: Pointer/handle to the underlying block masked as `void *`.
55+
vsample**: Handle to the underlying block masked as `void *`.
5556
"""
5657
if start_idx is None:
5758
return self._smps.get_block(0)
@@ -63,18 +64,21 @@ def __init__(self, length: int):
6364
Initialize a SamplesArray.
6465
6566
Notes:
66-
Each sample slot can hold one node::Sample allocated via node_read().
67-
node::Sample can contain multiple signals, depending on smpl_length.
67+
- Each sample slot can hold one sample allocated via `node_read()`.
68+
- Sample can contain multiple signals, depending on `smpl_length`.
6869
"""
6970
self._smps = vn.smps_array(length)
7071
self._len = length
7172

7273
def __len__(self):
73-
"""Returns the length of the SamplesArray, which corresponds to the amount of samples it holds."""
74+
"""
75+
Returns the length of the SamplesArray.
76+
Corresponds to the amount of samples it holds.
77+
"""
7478
return self._len
7579

7680
def __getitem__(self, idx: Union[int, slice]):
77-
"""Return a tuple containing self and an index or slice for node operations."""
81+
"""Return tuple containing self and index/slice for node operations."""
7882
if isinstance(idx, slice):
7983
return (self, idx)
8084
elif isinstance(idx, int):
@@ -99,7 +103,7 @@ def __deepcopy__(self):
99103
# that would return -1 if a function is not implemented
100104
def _warn_if_not_implemented(func):
101105
"""
102-
Decorator to warn if specific node_* functions are not implemented and return -1.
106+
Decorator to warn if specific `node_*()` functions are not implemented.
103107
104108
Returns:
105109
Wrapping function that logs a warning if the return value is -1.
@@ -109,7 +113,8 @@ def _warn_if_not_implemented(func):
109113
def wrapper(*args, **kwargs):
110114
ret = func(*args, **kwargs)
111115
if ret == -1:
112-
msg = f"[\033[33mWarning\033[0m]: Function '{func.__name__}()' is not implemented for node type '{vn.node_name(*args)}'."
116+
msg = f"[\033[33mWarning\033[0m]: Function '{func.__name__}()' \
117+
is not implemented for node type '{vn.node_name(*args)}'."
113118
logger.warning(msg)
114119
return ret
115120

@@ -183,7 +188,8 @@ def node_new(config, uuid: Optional[str] = None):
183188
184189
Args:
185190
config (json/str): Configuration of the node.
186-
uuid (Optional[str]): Unique identifier of the node. If `None`/empty, VILLASnode will assign one by default.
191+
uuid (Optional[str]): Unique identifier of the node.
192+
If `None`, VILLASnode will assign one by default.
187193
188194
Returns:
189195
vnode *: Handle to a node.
@@ -215,11 +221,11 @@ def node_prepare(node):
215221
@_warn_if_not_implemented
216222
def node_read(node, samples, sample_length, count):
217223
"""
218-
Read samples from a node into a SamplesArray or a block slice of its samples.
224+
Read samples from a node into SamplesArray or a block slice of its samples.
219225
220226
Args:
221227
node: Node handle.
222-
samples: Either a SamplesArray or a tuple of (SamplesArray, index/slice).
228+
samples: Either a SamplesArray or a tuple (SamplesArray, index/slice).
223229
sample_length: Length of each sample (number of signals).
224230
count: Number of samples to read.
225231
@@ -241,7 +247,7 @@ def node_read(node, samples, sample_length, count):
241247

242248
# check for length mismatch
243249
if (stop - start) != count:
244-
raise ValueError("Sample slice length and sample count do not match.")
250+
raise ValueError("Slice length and sample count do not match.")
245251
# check if out of bounds
246252
if stop > len(smpls):
247253
raise IndexError("Out of bounds")
@@ -273,7 +279,8 @@ def node_reverse(node):
273279
274280
Notes:
275281
- Hooks are not reversed.
276-
- Some nodes should be stopped or restarted before reversing. Especially nodes with in-/output buffers.
282+
- Some nodes should be stopped or restarted before reversing.
283+
- Nodes with in-/output buffers should be stopped before reversing.
277284
"""
278285
return vn.node_reverse(node)
279286

@@ -294,6 +301,7 @@ def node_stop(node):
294301
295302
Notes:
296303
- Use before starting a node again.
304+
- May delete in-/output buffers of a node.
297305
"""
298306
return vn.node_stop(node)
299307

@@ -329,7 +337,7 @@ def node_write(node, samples, count):
329337
330338
Args:
331339
node: Node handle.
332-
samples: Either a SamplesArray or a tuple of (SamplesArray, index/slice).
340+
samples: Either a SamplesArray or a tuple (SamplesArray, index/slice).
333341
count: Number of samples to write.
334342
335343
Returns:
@@ -348,7 +356,7 @@ def node_write(node, samples, count):
348356

349357
# check for length mismatch
350358
if (stop - start) != count:
351-
raise ValueError("Sample slice length and sample count do not match.")
359+
raise ValueError("Slice length and sample count do not match.")
352360
# check for out of bounds
353361
if stop > len(smpls):
354362
raise IndexError("Out of bounds")

tests/integration/python/test_binding_wrapper.py

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,12 @@ def test_reverse_node(self):
7171
# function test_rw_socket_and_reverse() below
7272
self.assertEqual(1, vn.node_input_signals_max_cnt(self.test_node))
7373
self.assertEqual(0, vn.node_output_signals_max_cnt(self.test_node))
74-
# self.assertEqual(0, vn.node_input_signals_max_cnt(self.test_node))
75-
# self.assertEqual(1, vn.node_output_signals_max_cnt(self.test_node))
7674
except Exception as e:
7775
self.fail(f"Reversing node in and output failed: {e}")
7876

79-
# Test whether or not a node can be recreated with the string from node_to_json_str
80-
# node_to_json_str has a wrong config format causing the config string to create
81-
# a node without a name
77+
# Test if a node can be recreated with the string from node_to_json_str
78+
# node_to_json_str has a wrong config format causing the config string
79+
# to create a node without a name
8280
# uuid can not match
8381
def test_config_from_string(self):
8482
try:
@@ -91,7 +89,9 @@ def test_config_from_string(self):
9189

9290
self.assertEqual(
9391
re.sub(
94-
r"^[^:]+: uuid=[0-9a-fA-F-]+, ", "", vn.node_name_full(test_node)
92+
r"^[^:]+: uuid=[0-9a-fA-F-]+, ",
93+
"",
94+
vn.node_name_full(test_node),
9595
),
9696
re.sub(
9797
r"^[^:]+: uuid=[0-9a-fA-F-]+, ",
@@ -120,7 +120,7 @@ def test_rw_socket_and_reverse(self):
120120
raise RuntimeError("Failed to verify node configuration")
121121
if vn.node_prepare(node):
122122
raise RuntimeError(
123-
f"Failed to verify {vn.node_name(node)} node configuration"
123+
f"Failed to verify {vn.node_name(node)} node config"
124124
)
125125
vn.node_start(node)
126126

@@ -132,29 +132,47 @@ def test_rw_socket_and_reverse(self):
132132
for i in range(100):
133133
# Generate signals and send over send_socket
134134
self.assertEqual(
135-
vn.node_read(test_nodes["signal_generator"], send_smpls, 2, 1), 1
135+
vn.node_read(
136+
test_nodes["signal_generator"], send_smpls, 2, 1
137+
),
138+
1,
136139
)
137140
self.assertEqual(
138141
vn.node_write(test_nodes["send_socket"], send_smpls, 1), 1
139142
)
140143

141144
# read received signals and send them to recv_socket
142145
self.assertEqual(
143-
vn.node_read(test_nodes["intmdt_socket"], intmdt_smpls, 2, 100), 100
146+
vn.node_read(
147+
test_nodes["intmdt_socket"], intmdt_smpls, 2, 100
148+
),
149+
100,
144150
)
145151
self.assertEqual(
146-
vn.node_write(test_nodes["intmdt_socket"], intmdt_smpls[0:50], 50), 50
152+
vn.node_write(
153+
test_nodes["intmdt_socket"], intmdt_smpls[0:50], 50
154+
),
155+
50,
147156
)
148157
self.assertEqual(
149-
vn.node_write(test_nodes["intmdt_socket"], intmdt_smpls[50:100], 50), 50
158+
vn.node_write(
159+
test_nodes["intmdt_socket"], intmdt_smpls[50:100], 50
160+
),
161+
50,
150162
)
151163

152164
# confirm rev_socket signals
153165
self.assertEqual(
154-
vn.node_read(test_nodes["recv_socket"], recv_smpls[0:50], 2, 50), 50
166+
vn.node_read(
167+
test_nodes["recv_socket"], recv_smpls[0:50], 2, 50
168+
),
169+
50,
155170
)
156171
self.assertEqual(
157-
vn.node_read(test_nodes["recv_socket"], recv_smpls[50:100], 2, 50), 50
172+
vn.node_read(
173+
test_nodes["recv_socket"], recv_smpls[50:100], 2, 50
174+
),
175+
50,
158176
)
159177

160178
# reversing in and outputs
@@ -169,13 +187,17 @@ def test_rw_socket_and_reverse(self):
169187
for node in test_nodes.values():
170188
vn.node_start(node)
171189

172-
# if another 100 samples have not been allocated, sending 200 at once is impossible with recv_smpls
190+
# if another 50 samples have not been allocated,
191+
# sending 100 at once is impossible with recv_smpls
173192
self.assertEqual(
174193
vn.node_write(test_nodes["recv_socket"], recv_smpls, 100), 100
175194
)
176195
# try writing as full slice
177196
self.assertEqual(
178-
vn.node_write(test_nodes["intmdt_socket"], recv_smpls[0:100], 100), 100
197+
vn.node_write(
198+
test_nodes["intmdt_socket"], recv_smpls[0:100], 100
199+
),
200+
100,
179201
)
180202

181203
# cleanup
@@ -194,7 +216,9 @@ def test_rw_socket_and_reverse(self):
194216
"layer": "udp",
195217
"in": {
196218
"address": "*:12000",
197-
"signals": [{"name": "tap_position", "type": "integer", "init": 0}],
219+
"signals": [
220+
{"name": "tap_position", "type": "integer", "init": 0}
221+
],
198222
},
199223
"out": {"address": "127.0.0.1:12001"},
200224
}
@@ -252,7 +276,7 @@ def test_rw_socket_and_reverse(self):
252276
"multicast": {"enabled": False},
253277
},
254278
},
255-
"signal_generator": {
279+
"signal_gen": {
256280
"type": "signal.v2",
257281
"limit": 100,
258282
"rate": 10,

tests/integration/python/test_python_binding.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,12 @@ def test_reverse_node(self):
7171
# function test_rw_socket_and_reverse() below
7272
self.assertEqual(1, vn.node_input_signals_max_cnt(self.test_node))
7373
self.assertEqual(0, vn.node_output_signals_max_cnt(self.test_node))
74-
# self.assertEqual(0, vn.node_input_signals_max_cnt(self.test_node))
75-
# self.assertEqual(1, vn.node_output_signals_max_cnt(self.test_node))
7674
except Exception as e:
7775
self.fail(f"Reversing node in and output failed: {e}")
7876

79-
# Test whether or not a node can be recreated with the string from node_to_json_str
80-
# node_to_json_str has a wrong config format causing the config string to create
81-
# a node without a name
77+
# Test if a node can be recreated with the string from node_to_json_str
78+
# node_to_json_str has a wrong config format causing the config string
79+
# to create a node without a name
8280
# uuid can not match
8381
def test_config_from_string(self):
8482
try:
@@ -91,7 +89,9 @@ def test_config_from_string(self):
9189

9290
self.assertEqual(
9391
re.sub(
94-
r"^[^:]+: uuid=[0-9a-fA-F-]+, ", "", vn.node_name_full(test_node)
92+
r"^[^:]+: uuid=[0-9a-fA-F-]+, ",
93+
"",
94+
vn.node_name_full(test_node),
9595
),
9696
re.sub(
9797
r"^[^:]+: uuid=[0-9a-fA-F-]+, ",
@@ -120,7 +120,7 @@ def test_rw_socket_and_reverse(self):
120120
raise RuntimeError("Failed to verify node configuration")
121121
if vn.node_prepare(node):
122122
raise RuntimeError(
123-
f"Failed to verify {vn.node_name(node)} node configuration"
123+
f"Failed to verify {vn.node_name(node)} node config"
124124
)
125125
vn.node_start(node)
126126

@@ -130,26 +130,32 @@ def test_rw_socket_and_reverse(self):
130130
recv_smpls = vn.smps_array(100)
131131

132132
for i in range(100):
133-
# send_smpls holds a new sample each time, but the old one still has a reference in the socket buffer (below)
134-
# it is necessary to allocate a new sample each time to send_smpls
133+
# send_smpls holds a new sample each time, but the
134+
# old one still has a reference in the socket buffer (below)
135+
# it is necessary to allocate a new sample each time
135136
send_smpls[0] = vn.sample_alloc(2)
136137
intmdt_smpls[i] = vn.sample_alloc(2)
137138
recv_smpls[i] = vn.sample_alloc(2)
138139

139140
# Generate signals and send over send_socket
140141
self.assertEqual(
141-
vn.node_read(test_nodes["signal_generator"], send_smpls, 1), 1
142+
vn.node_read(
143+
test_nodes["signal_generator"], send_smpls, 1
144+
),
145+
1,
142146
)
143147
self.assertEqual(
144148
vn.node_write(test_nodes["send_socket"], send_smpls, 1), 1
145149
)
146150

147151
# read received signals and send them to recv_socket
148152
self.assertEqual(
149-
vn.node_read(test_nodes["intmdt_socket"], intmdt_smpls, 100), 100
153+
vn.node_read(test_nodes["intmdt_socket"], intmdt_smpls, 100),
154+
100,
150155
)
151156
self.assertEqual(
152-
vn.node_write(test_nodes["intmdt_socket"], intmdt_smpls, 100), 100
157+
vn.node_write(test_nodes["intmdt_socket"], intmdt_smpls, 100),
158+
100,
153159
)
154160

155161
# confirm rev_socket signals
@@ -173,7 +179,8 @@ def test_rw_socket_and_reverse(self):
173179
vn.node_write(test_nodes["recv_socket"], recv_smpls, 100), 100
174180
)
175181
self.assertEqual(
176-
vn.node_write(test_nodes["intmdt_socket"], intmdt_smpls, 100), 100
182+
vn.node_write(test_nodes["intmdt_socket"], intmdt_smpls, 100),
183+
100,
177184
)
178185

179186
# cleanup
@@ -192,7 +199,9 @@ def test_rw_socket_and_reverse(self):
192199
"layer": "udp",
193200
"in": {
194201
"address": "*:12000",
195-
"signals": [{"name": "tap_position", "type": "integer", "init": 0}],
202+
"signals": [
203+
{"name": "tap_position", "type": "integer", "init": 0}
204+
],
196205
},
197206
"out": {"address": "127.0.0.1:12001"},
198207
}

0 commit comments

Comments
 (0)