Skip to content

Commit 03a02c5

Browse files
committed
Merge remote-tracking branch 'origin/master' into parallelize-run-interoperability-tests
2 parents 74fe173 + 416a368 commit 03a02c5

12 files changed

+377
-147
lines changed

README.md

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ The Shape application allows the following parameters:
191191
Default: 33ms
192192
--read-period <ms> : waiting period between 'read()' or 'take()' operations
193193
in ms. Default: 100ms
194-
--time-filter <interval> : apply 'time based filter' with interval
194+
--time-filter <interval> : apply 'time based filter' with interval
195195
in ms [0: OFF]
196196
--lifespan <int> : indicates the lifespan of a sample in ms
197197
--num-iterations <int>: indicates the number of iterations of the main loop
@@ -225,7 +225,8 @@ The Shape application allows the following parameters:
225225
large data)
226226
--take-read : uses take()/read() instead of take_next_instance()
227227
read_next_instance()
228-
228+
--periodic-announcement <ms> : indicates the periodic participant
229+
announcement period in ms. Default 0 (off)
229230
~~~
230231

231232
## Return Code
@@ -356,62 +357,72 @@ The `interoperability_report.py` may configure the following options:
356357
$ python3 interoperability_report.py -h
357358
358359
usage: interoperability_report.py [-h] -P publisher_executable_name -S subscriber_executable_name
359-
[-v] [-s test_suite_dictionary_file]
360-
[-t test_cases [test_cases ...] | -d
361-
test_cases_disabled
362-
[test_cases_disabled ...]] [-o filename]
360+
[-v] [-x {1,2}] [-a periodic_announcement_period]
361+
[-s test_suite_dictionary_file]
362+
[-t test_cases [test_cases ...] | -d test_cases_disabled [test_cases_disabled ...]]
363+
[-o filename]
363364
364-
Validation of interoperability of products compliant with OMG DDS-RTPS
365-
standard. This script generates automatically the verification between two
366-
shape_main executables. It also generates an XML report in JUnit format.
365+
Validation of interoperability of products compliant with OMG DDS-RTPS standard.
366+
This script generates automatically the verification between two shape_main
367+
executables. It also generates an XML report in JUnit format.
367368
368369
optional arguments:
369370
-h, --help show this help message and exit
370371
371372
general options:
372373
-P publisher_executable_name, --publisher publisher_executable_name
373-
Path to the Publisher shape_main application. It may
374-
be absolute or relative path. Example: if the
375-
executable is in the same folder as the script: "-P
376-
./rti_connext_dds-6.1.1_shape_main_linux".
374+
Path to the Publisher shape_main application. It may be
375+
absolute or relative path. Example: if the executable is
376+
in the same folder as the script:
377+
"-P ./rti_connext_dds-6.1.1_shape_main_linux".
377378
-S subscriber_executable_name, --subscriber subscriber_executable_name
378-
Path to the Subscriber shape_main application. It may
379-
be absolute or relative path. Example: if the
380-
executable is in the same folder as the script: "-S
381-
./rti_connext_dds-6.1.1_shape_main_linux".
379+
Path to the Subscriber shape_main application. It may be
380+
absolute or relative path. Example: if the executable is
381+
in the same folder as the script:
382+
"-S ./rti_connext_dds-6.1.1_shape_main_linux".
382383
383384
optional parameters:
384385
-v, --verbose Print debug information to stdout. This option also
385386
shows the shape_main application output in case of
386-
error. If this option is not used, only the test
387-
results are printed in the stdout. (Default: False).
387+
error. If this option is not used, only the test results
388+
are printed in the stdout.
389+
Default: False.
390+
-x {1,2}, --data-representation {1,2}
391+
Data Representation used if no provided when running the
392+
shape_main application. If this application already sets
393+
the data representation, this parameter is not used. The
394+
potential values are 1 for XCDR1 and 2 for XCDR2.
395+
Default value 2.
396+
-a periodic_announcement_period, --periodic-announcement periodic_announcement_ms
397+
Indicates the periodic participant announcement period in ms.
398+
Default: 0 (off).
388399
389400
Test Case and Test Suite:
390401
-s test_suite_dictionary_file, --suite test_suite_dictionary_file
391402
Test Suite that is going to be tested. Test Suite is a
392403
file with a Python dictionary defined. It must be
393-
located on the same directory as
394-
interoperability_report. This value should not contain
395-
the extension ".py", only the name of the file. It
396-
will run all the dictionaries defined in the file.
397-
(Default: test_suite).
404+
located on the same directory as interoperability_report.
405+
This value should not contain the extension ".py", only
406+
the name of the file. It will run all the dictionaries
407+
defined in the file.
408+
Default: test_suite.
398409
-t test_cases [test_cases ...], --test test_cases [test_cases ...]
399410
Test Case that the script will run. This option is not
400411
supported with --disable-test. This allows to set
401-
multiple values separated by a space. (Default: run
402-
all Test Cases from the Test Suite.)
412+
multiple values separated by a space.
413+
Default: run all Test Cases from the Test Suite.
403414
-d test_cases_disabled [test_cases_disabled ...], --disable-test test_cases_disabled [test_cases_disabled ...]
404-
Test Case that the script will skip. This allows to
405-
set multiple values separated by a space. This option
406-
is not supported with --test. (Default: None)
415+
Test Case that the script will skip. This allows to set
416+
multiple values separated by a space. This option is not
417+
supported with --test.
418+
Default: None
407419
408420
output options:
409421
-o filename, --output-name filename
410422
Name of the xml report that will be generated. If the
411-
file passed already exists, it will add the new
412-
results to it. In other case it will create a new
413-
file. (Default:
414-
<publisher_name>-<subscriber_name>-date.xml)
423+
file passed already exists, it will add the new results
424+
to it. In other case it will create a new file.
425+
Default: <publisher_name>-<subscriber_name>-date.xml
415426
```
416427

417428

doc/test_description.template.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ product versions.
6060

6161
* Content Filtered Topic expression created with single quotes around strings
6262
values
63+
* Content Filtered Topic uses MATCH operator for string comparisons.
64+
* Increased the periodic discovery announcements to 5s in the tests where
65+
the subscriber is OpenDDS and the publisher is Connext DDS.
6366

6467
* **FastDDS**:
6568

interoperability_report.py

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,38 @@
3030
# MAX_SAMPLES_SAVED is the maximum number of samples saved.
3131
MAX_SAMPLES_SAVED = 500
3232

33+
def stop_process(child_process, timeout=30, poll_interval=0.2):
34+
"""
35+
Stops a pexpect child process using SIGINT (Ctrl+C),
36+
and forcefully terminates it if it doesn't exit within the timeout.
37+
38+
Parameters:
39+
child_process (pexpect.spawn): The process to stop.
40+
timeout (int): Max time (in seconds) to wait for graceful exit.
41+
poll_interval (float): Time between checks in seconds.
42+
43+
Returns:
44+
bool: True if process exited gracefully, False if it was killed.
45+
"""
46+
if child_process.isalive():
47+
try:
48+
child_process.sendintr()
49+
except Exception as e:
50+
return True # Process already exited
51+
else:
52+
return True # Process already exited
53+
54+
start_time = time.time()
55+
56+
while child_process.isalive() and (time.time() - start_time < timeout):
57+
time.sleep(poll_interval)
58+
59+
if child_process.isalive():
60+
child_process.terminate(force=True)
61+
return False # Process was forcefully terminated
62+
63+
return True
64+
3365
def run_subscriber_shape_main(
3466
name_executable: str,
3567
parameters: str,
@@ -165,11 +197,13 @@ def run_subscriber_shape_main(
165197
log_message(f'Subscriber {subscriber_index}: Waiting for Publishers to '
166198
'finish', verbosity)
167199
for element in publishers_finished:
168-
element.wait() # wait for all publishers to finish
169-
# Send SIGINT to nicely close the application
170-
if child_sub.isalive():
171-
child_sub.sendintr()
172-
child_sub.wait()
200+
element.wait() # wait for all publishers to finish
201+
# Stop process
202+
if not stop_process(child_sub):
203+
log_message(f'Subscriber {subscriber_index} process did not exit '
204+
'gracefully; it was forcefully terminated.',
205+
verbosity)
206+
173207
return
174208

175209

@@ -332,10 +366,12 @@ def run_publisher_shape_main(
332366
for element in subscribers_finished:
333367
element.wait() # wait for all subscribers to finish
334368
publisher_finished.set() # set publisher as finished
335-
# Send SIGINT to nicely close the application
336-
if child_pub.isalive():
337-
child_pub.sendintr()
338-
child_pub.wait()
369+
# Stop process
370+
if not stop_process(child_pub):
371+
log_message(f'Publisher {publisher_index} process did not exit '
372+
'gracefully; it was forcefully terminated.',
373+
verbosity)
374+
339375
return
340376

341377

@@ -599,18 +635,27 @@ def parser():
599635
help='Print debug information to stdout. This option also shows the '
600636
'shape_main application output in case of error. '
601637
'If this option is not used, only the test results are printed '
602-
'in the stdout. (Default: False).')
638+
'in the stdout. '
639+
'Default: False')
603640
optional.add_argument('-x','--data-representation',
604641
default="2",
605642
required=None,
606643
type=str,
607644
choices=["1","2"],
608645
help='Data Representation used if no provided when running the '
609646
'shape_main application. If this application already sets the '
610-
'data representation, this parameter is not used.'
647+
'data representation, this parameter is not used. '
611648
'The potential values are 1 for XCDR1 and 2 for XCDR2.'
612649
'Default value 2.')
613650

651+
optional.add_argument('-a', '--periodic-announcement',
652+
default=0,
653+
required=False,
654+
type=int,
655+
metavar='periodic_announcement_ms',
656+
help='Indicates the periodic participant announcement period in ms. '
657+
'Default: 0 (off).')
658+
614659
tests = parser.add_argument_group(title='Test Case and Test Suite')
615660
tests.add_argument('-s', '--suite',
616661
default='test_suite',
@@ -623,7 +668,7 @@ def parser():
623668
'This value should not contain the extension ".py", '
624669
'only the name of the file. '
625670
'It will run all the dictionaries defined in the file. '
626-
'(Default: test_suite).')
671+
'Default: test_suite.')
627672

628673
enable_disable = tests.add_mutually_exclusive_group(required=False)
629674
enable_disable.add_argument('-t', '--test',
@@ -635,7 +680,7 @@ def parser():
635680
help='Test Case that the script will run. '
636681
'This option is not supported with --disable-test. '
637682
'This allows to set multiple values separated by a space. '
638-
'(Default: run all Test Cases from the Test Suite.)')
683+
'Default: run all Test Cases from the Test Suite.')
639684
enable_disable.add_argument('-d', '--disable-test',
640685
nargs='+',
641686
default=None,
@@ -644,7 +689,8 @@ def parser():
644689
metavar='test_cases_disabled',
645690
help='Test Case that the script will skip. '
646691
'This allows to set multiple values separated by a space. '
647-
'This option is not supported with --test. (Default: None)')
692+
'This option is not supported with --test. '
693+
'Default: None')
648694

649695
out_opts = parser.add_argument_group(title='output options')
650696
out_opts.add_argument('-o', '--output-name',
@@ -655,7 +701,7 @@ def parser():
655701
'If the file passed already exists, it will add '
656702
'the new results to it. In other case it will create '
657703
'a new file. '
658-
'(Default: <publisher_name>-<subscriber_name>-date.xml)')
704+
'Default: <publisher_name>-<subscriber_name>-date.xml')
659705

660706
return parser
661707

@@ -682,6 +728,7 @@ def main():
682728
'test_cases': args.test,
683729
'test_cases_disabled': args.disable_test,
684730
'data_representation': args.data_representation,
731+
'periodic_announcement_ms': args.periodic_announcement,
685732
}
686733

687734
# The executables's names are supposed to follow the pattern: name_shape_main
@@ -714,7 +761,7 @@ def main():
714761
# applications. A TestSuite contains a collection of TestCases.
715762
suite = junitparser.TestSuite(f"{name_publisher}---{name_subscriber}")
716763

717-
timeout = 10
764+
timeout = 15
718765
now = datetime.now()
719766

720767
t_suite_module = importlib.import_module(options['test_suite'])
@@ -768,9 +815,16 @@ def main():
768815

769816
assert(len(parameters) == len(expected_codes))
770817

771-
for element in parameters:
818+
for i,element in enumerate(parameters):
772819
if not '-x ' in element:
773-
element += f'-x {options["data_representation"]}'
820+
element += f' -x {options["data_representation"]}'
821+
# Add periodic announcement argument if needed
822+
if options['periodic_announcement_ms'] > 0 \
823+
and not '--periodic-announcement ' in element \
824+
and 'connext' in options['publisher'].lower() \
825+
and '-P' in element:
826+
element += f' --periodic-announcement {options["periodic_announcement_ms"]}'
827+
parameters[i] = element # Update the list in place
774828

775829
case = junitparser.TestCase(f'{test_suite_name}_{test_case_name}')
776830
now_test_case = datetime.now()

run_tests.sh

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ done
5959
# If publisher is not provided, find publisher applications
6060
if [[ -z $publisher ]]; then
6161
echo "Searching for publisher applications in directory: $input"
62-
publisher=$(find "$input" -type f -name '*_shape_main_linux')
62+
publisher=$(find "$input" -type f -name '*shape_main_linux')
6363
fi
6464

6565
# If subscriber is not provided, find subscriber applications
@@ -80,10 +80,14 @@ for i in $publisher; do
8080
publisher_name=$(basename "$i" _shape_main_linux)
8181
subscriber_name=$(basename "$j" _shape_main_linux)
8282
echo "Testing Publisher $publisher_name --- Subscriber $subscriber_name"
83+
extra_args=""
84+
if [[ "${subscriber,,}" == *opendds* && "${publisher,,}" == *connext* ]]; then
85+
extra_args="--periodic-announcement 5000"
86+
fi;
8387
if [[ -n $output ]]; then
84-
python3 ./interoperability_report.py -P "$i" -S "$j" -o "$output"
88+
python3 ./interoperability_report.py -P "$i" -S "$j" -o "$output" $extra_args
8589
else
86-
python3 ./interoperability_report.py -P "$i" -S "$j"
90+
python3 ./interoperability_report.py -P "$i" -S "$j" $extra_args
8791
fi
8892
if [ -d "./OpenDDS-durable-data-dir" ]; then
8993
echo Deleting OpenDDS-durable-data-dir;

srcCxx/makefile_rti_connext_dds_linux

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ ifndef NDDSHOME
1818
$(error NDDSHOME not defined)
1919
endif
2020

21+
ifndef CONNEXTDDS_ARCH
22+
$(error CONNEXTDDS_ARCH not defined)
23+
endif
24+
2125
COMPILER_FLAGS = -m64
2226
LINKER_FLAGS = -m64 -static-libgcc
2327

@@ -27,7 +31,7 @@ version_name = $(lastword $(split_path_name))
2731
common_name = "_shape_main_linux"
2832
executable_name = $(version_name)$(common_name)
2933

30-
TARGET_ARCH = x64Linux4gcc7.3.0
34+
TARGET_ARCH = $(CONNEXTDDS_ARCH)
3135

3236
ifndef COMPILER
3337
COMPILER = g++

srcCxx/shape_configurator_eprosima_fast_dds.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,18 @@ uint64_t DDS_UInt8Seq_get_length(const std::vector<unsigned char>* seq)
6565
{
6666
return seq->size();
6767
}
68+
69+
void DDS_UInt8Seq_ensure_length(std::vector<unsigned char>* seq, uint64_t length, uint64_t = 0)
70+
{
71+
seq->resize(length);
72+
}
73+
74+
unsigned char* DDS_UInt8Seq_get_reference(std::vector<unsigned char>* seq, uint64_t index)
75+
{
76+
return &((*seq)[index]);
77+
}
78+
79+
const unsigned char* DDS_UInt8Seq_get_reference(const std::vector<unsigned char>* seq, uint64_t index)
80+
{
81+
return &((*seq)[index]);
82+
}

srcCxx/shape_configurator_intercom_dds.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#define DDS_UInt8Seq_ensure_length(s,l,x) (s)->resize(l)
1414
#define DDS_UInt8Seq_get_reference(s,l) &( (*s)[l] )
1515

16+
#define DDS_BOOLEAN_TRUE true
17+
#define DDS_BOOLEAN_FALSE false
18+
1619
inline const char *get_qos_policy_name(DDS::QosPolicyId_t policy_id) {
1720
switch (policy_id) {
1821
case DDS::USERDATA_QOS_POLICY_ID:

0 commit comments

Comments
 (0)