Multi Process Testing framework

Signed-off-by: Martin Bremmer <martin.bremmer@adlinktech.com>
This commit is contained in:
Martin Bremmer 2019-04-10 17:57:29 +02:00
parent 0269774a60
commit 17f9c361ea
30 changed files with 2934 additions and 1 deletions

View file

@ -0,0 +1,23 @@
#
# Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0 which is available at
# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
# v. 1.0 which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
#
include(${MPT_CMAKE})
set(sources
"procs/hello.c"
"helloworld.c"
"multi.c")
add_mpt_executable(mpt_basic ${sources})
idlc_generate(mpt_basic_helloworlddata_lib "procs/helloworlddata.idl")
target_link_libraries(mpt_basic PRIVATE mpt_basic_helloworlddata_lib)

View file

@ -0,0 +1,30 @@
<!--
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
-->
<CycloneDDS>
<Domain>
<Id>any</Id>
</Domain>
<DDSI2E>
<General>
<NetworkInterfaceAddress>auto</NetworkInterfaceAddress>
<AllowMulticast>true</AllowMulticast>
<EnableMulticastLoopback>true</EnableMulticastLoopback>
</General>
<Compatibility>
<StandardsConformance>lax</StandardsConformance>
</Compatibility>
<!--Tracing>
<Verbosity>finest</Verbosity>
<OutputFile>ddsi_${MPT_PROCESS_NAME}.log</OutputFile>
</Tracing-->
</DDSI2E>
</CycloneDDS>

View file

@ -0,0 +1,30 @@
<!--
Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
v. 1.0 which is available at
http://www.eclipse.org/org/documents/edl-v10.php.
SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
-->
<CycloneDDS>
<Domain>
<Id>${DOMAIN_ID}</Id>
</Domain>
<DDSI2E>
<General>
<NetworkInterfaceAddress>auto</NetworkInterfaceAddress>
<AllowMulticast>true</AllowMulticast>
<EnableMulticastLoopback>true</EnableMulticastLoopback>
</General>
<Compatibility>
<StandardsConformance>lax</StandardsConformance>
</Compatibility>
<!--Tracing>
<Verbosity>finest</Verbosity>
<OutputFile>ddsi_${MPT_PROCESS_NAME}.log</OutputFile>
</Tracing-->
</DDSI2E>
</CycloneDDS>

View file

@ -0,0 +1,63 @@
#include "dds/dds.h"
#include "mpt/mpt.h"
#include "mpt/resource.h" /* MPT_SOURCE_ROOT_DIR */
#include "procs/hello.h" /* publisher and subscriber entry points. */
/*
* Tests to check simple communication between a publisher and subscriber.
* The published text should be received by the subscriber.
*/
/* Environments */
static mpt_env_t environment_any[] = {
{ "ETC_DIR", MPT_SOURCE_ROOT_DIR"/tests/basic/etc" },
{ "CYCLONEDDS_URI", "file://${ETC_DIR}/config_any.xml" },
{ NULL, NULL }
};
static mpt_env_t environment_42[] = {
{ "ETC_DIR", MPT_SOURCE_ROOT_DIR"/tests/basic/etc" },
{ "DOMAIN_ID", "42" },
{ "CYCLONEDDS_URI", "file://${ETC_DIR}/config_specific.xml" },
{ NULL, NULL }
};
/**********************************************************************
* No CYCLONEDDS_URI set.
**********************************************************************/
#define TEST_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "hello_def", 1, "No environment set")
MPT_TestProcess(helloworld, default, pub, hello_publisher, TEST_ARGS);
MPT_TestProcess(helloworld, default, sub, hello_subscriber, TEST_ARGS);
MPT_Test(helloworld, default, .init=hello_init, .fini=hello_fini);
#undef TEST_ARGS
/**********************************************************************
* Config domain is any. Test domain is default.
**********************************************************************/
#define TEST_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "hello_any", 1, "Some nice text over any domain")
MPT_TestProcess(helloworld, domain_any, pub, hello_publisher, TEST_ARGS);
MPT_TestProcess(helloworld, domain_any, sub, hello_subscriber, TEST_ARGS);
MPT_Test(helloworld, domain_any, .init=hello_init, .fini=hello_fini, .environment=environment_any);
#undef TEST_ARGS
/**********************************************************************
* Pub: Config domain is any. Test domain is 42.
* Sub: Config domain is 42 (through DOMAIN_ID env). Test domain is default.
**********************************************************************/
#define TEST_PUB_ARGS MPT_ArgValues(42, "hello_42", 1, "Now domain 42 is used")
#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "hello_42", 1, "Now domain 42 is used")
MPT_TestProcess(helloworld, domain_42, pub, hello_publisher, TEST_PUB_ARGS, .environment=environment_any);
MPT_TestProcess(helloworld, domain_42, sub, hello_subscriber, TEST_SUB_ARGS, .environment=environment_42);
MPT_Test(helloworld, domain_42, .init=hello_init, .fini=hello_fini);
#undef TEST_SUB_ARGS
#undef TEST_PUB_ARGS

View file

@ -0,0 +1,50 @@
#include "mpt/mpt.h"
#include "procs/hello.h"
/*
* Tests to check communication between multiple publisher(s) and subscriber(s).
*/
/*
* The publisher expects 2 publication matched.
* The subscribers expect 1 sample each.
*/
#define TEST_PUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubsubsub", 2, "pubsubsub")
#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubsubsub", 1, "pubsubsub")
MPT_TestProcess(multi, pubsubsub, pub, hello_publisher, TEST_PUB_ARGS);
MPT_TestProcess(multi, pubsubsub, sub1, hello_subscriber, TEST_SUB_ARGS);
MPT_TestProcess(multi, pubsubsub, sub2, hello_subscriber, TEST_SUB_ARGS);
MPT_Test(multi, pubsubsub, .init=hello_init, .fini=hello_fini);
#undef TEST_SUB_ARGS
#undef TEST_PUB_ARGS
/*
* The publishers expect 1 publication matched each.
* The subscriber expects 2 samples.
*/
#define TEST_PUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubpubsub", 1, "pubpubsub")
#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubpubsub", 2, "pubpubsub")
MPT_TestProcess(multi, pubpubsub, pub1, hello_publisher, TEST_PUB_ARGS);
MPT_TestProcess(multi, pubpubsub, pub2, hello_publisher, TEST_PUB_ARGS);
MPT_TestProcess(multi, pubpubsub, sub, hello_subscriber, TEST_SUB_ARGS);
MPT_Test(multi, pubpubsub, .init=hello_init, .fini=hello_fini);
#undef TEST_SUB_ARGS
#undef TEST_PUB_ARGS
/*
* The publishers expect 2 publication matched each.
* The subscribers expect 2 samples each.
*/
#define TEST_PUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubpubsubsub", 2, "pubpubsubsub")
#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_pubpubsubsub", 2, "pubpubsubsub")
MPT_TestProcess(multi, pubpubsubsub, pub1, hello_publisher, TEST_PUB_ARGS);
MPT_TestProcess(multi, pubpubsubsub, pub2, hello_publisher, TEST_PUB_ARGS);
MPT_TestProcess(multi, pubpubsubsub, sub1, hello_subscriber, TEST_SUB_ARGS);
MPT_TestProcess(multi, pubpubsubsub, sub2, hello_subscriber, TEST_SUB_ARGS);
MPT_Test(multi, pubpubsubsub, .init=hello_init, .fini=hello_fini);
#undef TEST_SUB_ARGS
#undef TEST_PUB_ARGS

View file

@ -0,0 +1,239 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "mpt/mpt.h"
#include "dds/dds.h"
#include "helloworlddata.h"
#include "dds/ddsrt/time.h"
#include "dds/ddsrt/strtol.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/sync.h"
/* An array of one message (aka sample in dds terms) will be used. */
#define MAX_SAMPLES 1
static int g_publication_matched_count = 0;
static ddsrt_mutex_t g_mutex;
static ddsrt_cond_t g_cond;
static void
publication_matched_cb(
dds_entity_t writer,
const dds_publication_matched_status_t status,
void* arg)
{
(void)arg;
(void)writer;
ddsrt_mutex_lock(&g_mutex);
g_publication_matched_count = (int)status.current_count;
ddsrt_cond_broadcast(&g_cond);
ddsrt_mutex_unlock(&g_mutex);
}
static void
data_available_cb(
dds_entity_t reader,
void* arg)
{
(void)arg;
(void)reader;
ddsrt_mutex_lock(&g_mutex);
ddsrt_cond_broadcast(&g_cond);
ddsrt_mutex_unlock(&g_mutex);
}
void
hello_init(void)
{
ddsrt_init();
ddsrt_mutex_init(&g_mutex);
ddsrt_cond_init(&g_cond);
}
void
hello_fini(void)
{
ddsrt_cond_destroy(&g_cond);
ddsrt_mutex_destroy(&g_mutex);
ddsrt_fini();
}
/*
* The HelloWorld publisher.
* It waits for a publication matched, and then writes a sample.
* It quits when the publication matched has been reset again.
*/
MPT_ProcessEntry(hello_publisher,
MPT_Args(dds_domainid_t domainid,
const char *topic_name,
int sub_cnt,
const char *text))
{
HelloWorldData_Msg msg;
dds_listener_t *listener;
dds_entity_t participant;
dds_entity_t topic;
dds_entity_t writer;
dds_return_t rc;
dds_qos_t *qos;
int id = (int)ddsrt_getpid();
assert(topic_name);
assert(text);
printf("=== [Publisher(%d)] Start(%d) ...\n", id, domainid);
/*
* A reliable volatile sample, written after publication matched, can still
* be lost when the subscriber wasn't able to match its subscription yet.
* Use transient_local reliable to make sure the sample is received.
*/
qos = dds_create_qos();
dds_qset_durability(qos, DDS_DURABILITY_TRANSIENT_LOCAL);
dds_qset_reliability(qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10));
/* Use listener to get number of publications matched. */
listener = dds_create_listener(NULL);
MPT_ASSERT_FATAL_NOT_NULL(listener, "Could not create listener");
dds_lset_publication_matched(listener, publication_matched_cb);
/* Create a Writer. */
participant = dds_create_participant (domainid, NULL, NULL);
MPT_ASSERT_FATAL_GT(participant, 0, "Could not create participant: %s\n", dds_strretcode(-participant));
topic = dds_create_topic (
participant, &HelloWorldData_Msg_desc, topic_name, qos, NULL);
MPT_ASSERT_FATAL_GT(topic, 0, "Could not create topic: %s\n", dds_strretcode(-topic));
writer = dds_create_writer (participant, topic, qos, listener);
MPT_ASSERT_FATAL_GT(writer, 0, "Could not create writer: %s\n", dds_strretcode(-writer));
/* Wait for expected nr of subscriber(s). */
ddsrt_mutex_lock(&g_mutex);
while (g_publication_matched_count != sub_cnt) {
ddsrt_cond_waitfor(&g_cond, &g_mutex, DDS_INFINITY);
}
ddsrt_mutex_unlock(&g_mutex);
/* Write sample. */
msg.userID = (int32_t)id;
msg.message = (char*)text;
printf("=== [Publisher(%d)] Send: { %d, %s }\n", id, msg.userID, msg.message);
rc = dds_write (writer, &msg);
MPT_ASSERT_EQ(rc, DDS_RETCODE_OK, "Could not write sample\n");
/* Wait for subscriber(s) to have finished. */
ddsrt_mutex_lock(&g_mutex);
while (g_publication_matched_count != 0) {
ddsrt_cond_waitfor(&g_cond, &g_mutex, DDS_INFINITY);
}
ddsrt_mutex_unlock(&g_mutex);
rc = dds_delete (participant);
MPT_ASSERT_EQ(rc, DDS_RETCODE_OK, "Teardown failed\n");
dds_delete_listener(listener);
dds_delete_qos(qos);
printf("=== [Publisher(%d)] Done\n", id);
}
/*
* The HelloWorld subscriber.
* It waits for sample(s) and checks the content.
*/
MPT_ProcessEntry(hello_subscriber,
MPT_Args(dds_domainid_t domainid,
const char *topic_name,
int sample_cnt,
const char *text))
{
HelloWorldData_Msg *msg;
void *samples[MAX_SAMPLES];
dds_sample_info_t infos[MAX_SAMPLES];
dds_listener_t *listener;
dds_entity_t participant;
dds_entity_t topic;
dds_entity_t reader;
dds_return_t rc;
dds_qos_t *qos;
int recv_cnt;
int id = (int)ddsrt_getpid();
assert(topic_name);
assert(text);
printf("--- [Subscriber(%d)] Start(%d) ...\n", id, domainid);
/*
* A reliable volatile sample, written after publication matched, can still
* be lost when the subscriber wasn't able to match its subscription yet.
* Use transient_local reliable to make sure the sample is received.
*/
qos = dds_create_qos();
dds_qset_durability(qos, DDS_DURABILITY_TRANSIENT_LOCAL);
dds_qset_reliability(qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(10));
/* Use listener to get data available trigger. */
listener = dds_create_listener(NULL);
MPT_ASSERT_FATAL_NOT_NULL(listener, "Could not create listener");
dds_lset_data_available(listener, data_available_cb);
/* Create a Reader. */
participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
MPT_ASSERT_FATAL_GT(participant, 0, "Could not create participant: %s\n", dds_strretcode(-participant));
topic = dds_create_topic (
participant, &HelloWorldData_Msg_desc, topic_name, qos, NULL);
MPT_ASSERT_FATAL_GT(topic, 0, "Could not create topic: %s\n", dds_strretcode(-topic));
reader = dds_create_reader (participant, topic, qos, listener);
MPT_ASSERT_FATAL_GT(reader, 0, "Could not create reader: %s\n", dds_strretcode(-reader));
printf("--- [Subscriber(%d)] Waiting for %d sample(s) ...\n", id, sample_cnt);
/* Initialize sample buffer, by pointing the void pointer within
* the buffer array to a valid sample memory location. */
samples[0] = HelloWorldData_Msg__alloc ();
/* Wait until expected nr of samples have been taken. */
ddsrt_mutex_lock(&g_mutex);
recv_cnt = 0;
while (recv_cnt < sample_cnt) {
/* Use a take with mask to work around the #146 issue. */
rc = dds_take_mask(reader, samples, infos, MAX_SAMPLES, MAX_SAMPLES, DDS_NEW_VIEW_STATE);
MPT_ASSERT_GEQ(rc, 0, "Could not read: %s\n", dds_strretcode(-rc));
/* Check if we read some data and it is valid. */
if ((rc > 0) && (infos[0].valid_data)) {
/* Print Message. */
msg = (HelloWorldData_Msg*)samples[0];
printf("--- [Subscriber(%d)] Received: { %d, %s }\n", id,
msg->userID, msg->message);
MPT_ASSERT_STR_EQ(msg->message, text,
"Messages do not match: \"%s\" vs \"%s\"\n",
msg->message, text);
recv_cnt++;
} else {
ddsrt_cond_waitfor(&g_cond, &g_mutex, DDS_INFINITY);
}
}
ddsrt_mutex_unlock(&g_mutex);
/* Free the data location. */
HelloWorldData_Msg_free (samples[0], DDS_FREE_ALL);
rc = dds_delete (participant);
MPT_ASSERT_EQ(rc, DDS_RETCODE_OK, "Teardown failed\n");
dds_delete_listener(listener);
dds_delete_qos(qos);
printf("--- [Subscriber(%d)] Done\n", id);
}

View file

@ -0,0 +1,52 @@
/*
* Copyright(c) 2006 to 2018 ADLINK Technology Limited and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
* v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
/** @file
*
* @brief DDS C Communication Status API
*
* This header file defines the public API of the Communication Status in the
* Eclipse Cyclone DDS C language binding.
*/
#ifndef MPT_BASIC_PROCS_HELLO_H
#define MPT_BASIC_PROCS_HELLO_H
#include <stdio.h>
#include <string.h>
#include "dds/dds.h"
#include "mpt/mpt.h"
#if defined (__cplusplus)
extern "C" {
#endif
void hello_init(void);
void hello_fini(void);
MPT_ProcessEntry(hello_publisher,
MPT_Args(dds_domainid_t domainid,
const char *topic_name,
int sub_cnt,
const char *text));
MPT_ProcessEntry(hello_subscriber,
MPT_Args(dds_domainid_t domainid,
const char *topic_name,
int sample_cnt,
const char *text));
#if defined (__cplusplus)
}
#endif
#endif /* MPT_BASIC_PROCS_HELLO_H */

View file

@ -0,0 +1,9 @@
module HelloWorldData
{
struct Msg
{
long userID;
string message;
};
#pragma keylist Msg userID
};