Skip to content

Commit

Permalink
Full test coverage for loans/types/PSMX
Browse files Browse the repository at this point in the history
This runs over:

- memcpy-safe types and non-memcpy-safe types
- use of writer loans
- use of reader loans
- use of PSMX
- writing and disposing (sample vs key)

That should provide basic test coverage for all combinations that the
code distinguishes between.

The type definitions are chosen so that raw samples and CDR have
different memory layouts and one cannot be confused for the other.

Signed-off-by: Erik Boasson <[email protected]>
  • Loading branch information
eboasson committed Dec 4, 2023
1 parent 7ce48d1 commit 05bdd5b
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/core/ddsc/tests/PsmxDataModels.idl
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,20 @@ struct PsmxType1 {
struct PsmxKeySupportCheck {
@key long k;
};

struct PsmxLoanTest0 {
PsmxType1xy xy;
@key octet z;
};

struct PsmxLoanTest1 {
PsmxType1xy xy;
@key octet z;
string str;
};

struct PsmxLoanTest2 {
PsmxType1xy xy;
@key octet z;
@key string str;
};
175 changes: 175 additions & 0 deletions src/core/ddsc/tests/psmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1396,3 +1396,178 @@ CU_Test (ddsc_psmx, zero_copy)
}
dds_delete (dds_get_parent (pp));
}

static void deepcopy_sample_contents (const dds_topic_descriptor_t *tpdesc, void *output, const void *input)
{
struct dds_cdrstream_desc desc;
dds_cdrstream_desc_from_topic_desc (&desc, tpdesc);
struct dds_ostream os;
dds_ostream_init (&os, &dds_cdrstream_default_allocator, 0, DDSI_RTPS_CDR_ENC_VERSION_2);
dds_stream_write_sample (&os, &dds_cdrstream_default_allocator, input, &desc);
struct dds_istream is;
dds_istream_init (&is, os.m_index, os.m_buffer, os.m_xcdr_version);
memset (output, 0, desc.size);
dds_stream_read_sample (&is, output, &dds_cdrstream_default_allocator, &desc);
dds_istream_fini (&is);
dds_ostream_fini (&os, &dds_cdrstream_default_allocator);
dds_cdrstream_desc_fini (&desc, &dds_cdrstream_default_allocator);
}

static const void *get_write_datapointer (dds_entity_t wr, const dds_topic_descriptor_t *tpdesc, const void *template, bool wrloan)
{
if (!wrloan)
return template;
else
{
void *tmp;
dds_return_t rc = dds_request_loan (wr, &tmp);
CU_ASSERT_FATAL (rc == 0);
deepcopy_sample_contents (tpdesc, tmp, template);
return tmp;
}
}

static bool data_equal (const dds_topic_descriptor_t *tpdesc, const void *a, const void *b, bool justkey)
{
struct dds_cdrstream_desc desc;
dds_cdrstream_desc_from_topic_desc (&desc, tpdesc);
struct dds_ostream osa, osb;
dds_ostream_init (&osa, &dds_cdrstream_default_allocator, 0, DDSI_RTPS_CDR_ENC_VERSION_2);
dds_ostream_init (&osb, &dds_cdrstream_default_allocator, 0, DDSI_RTPS_CDR_ENC_VERSION_2);
if (justkey)
{
dds_stream_write_key (&osa, DDS_CDR_KEY_SERIALIZATION_SAMPLE, &dds_cdrstream_default_allocator, a, &desc);
dds_stream_write_key (&osb, DDS_CDR_KEY_SERIALIZATION_SAMPLE, &dds_cdrstream_default_allocator, b, &desc);
}
else
{
dds_stream_write_sample (&osa, &dds_cdrstream_default_allocator, a, &desc);
dds_stream_write_sample (&osb, &dds_cdrstream_default_allocator, b, &desc);
}
const bool eq = (osa.m_index == osb.m_index) && memcmp (osa.m_buffer, osb.m_buffer, osa.m_index) == 0;
dds_ostream_fini (&osa, &dds_cdrstream_default_allocator);
dds_ostream_fini (&osb, &dds_cdrstream_default_allocator);
dds_cdrstream_desc_fini (&desc, &dds_cdrstream_default_allocator);
return eq;
}

CU_Test (ddsc_psmx, writer_loan)
{
const struct {
const dds_topic_descriptor_t *desc;
const struct {
dds_return_t (*op) (dds_entity_t wr, const void *data);
const void *data;
} step[2];
} cases[] = {
{ &PsmxLoanTest0_desc, {
{ dds_write, &(PsmxLoanTest0){ { 0x12345678, 0x55 }, 0x22 } },
{ dds_dispose, &(PsmxLoanTest0){ { 0, 0 }, 0x22 } } } },
{ &PsmxLoanTest1_desc, {
{ dds_write, &(PsmxLoanTest1){ { 0x12345678, 0x55 }, 0x22, "aap" } },
{ dds_dispose, &(PsmxLoanTest1){ { 0, 0, }, 0x22, "" } } } },
{ &PsmxLoanTest2_desc, {
{ dds_write, &(PsmxLoanTest2){ { 0x12345678, 0x55 }, 0x22, "noot" } },
{ dds_dispose, &(PsmxLoanTest2){ { 0, 0, }, 0x22, "noot" } } } },
};
dds_return_t rc;

const dds_entity_t pp = create_participant (0);
CU_ASSERT_FATAL (pp > 0);
for (size_t k = 0; k < sizeof (cases) / sizeof (cases[0]); k++)
{
char topicname[100];
create_unique_topic_name ("writer_loan", topicname, sizeof (topicname));
const dds_entity_t tp = dds_create_topic (pp, cases[k].desc, topicname, NULL, NULL);
CU_ASSERT_FATAL (tp > 0);
for (int wr_psmx_enabled_i = 0; wr_psmx_enabled_i <= 1; wr_psmx_enabled_i++)
{
const bool wr_psmx_enabled = wr_psmx_enabled_i;
for (int rd_psmx_enabled_i = 0; rd_psmx_enabled_i <= 1; rd_psmx_enabled_i++)
{
const bool rd_psmx_enabled = rd_psmx_enabled_i;
for (int wrloan_i = 0; wrloan_i <= 1; wrloan_i++)
{
const bool wrloan = wrloan_i;
for (int rdloan_i = 0; rdloan_i <= 1; rdloan_i++)
{
const bool rdloan = rdloan_i;
dds_qos_t *qos;
printf ("ddsc_psmx writer_loan: %s psmx %d %d wrloan %d rdloan %d", cases[k].desc->m_typename, wr_psmx_enabled, rd_psmx_enabled, wrloan, rdloan);
fflush (stdout);

qos = dds_create_qos ();
if (!wr_psmx_enabled)
dds_qset_psmx_instances (qos, 0, NULL);
const dds_entity_t wr = dds_create_writer (pp, tp, qos, NULL);
CU_ASSERT_FATAL (wr > 0);
CU_ASSERT_FATAL (endpoint_has_psmx_enabled (wr) == wr_psmx_enabled);
dds_delete_qos (qos);

qos = dds_create_qos ();
if (!rd_psmx_enabled)
dds_qset_psmx_instances (qos, 0, NULL);
dds_entity_t rd;
const dds_entity_t ws = dds_create_waitset (pp);
rd = dds_create_reader (pp, tp, qos, NULL);
CU_ASSERT_FATAL (rd > 0);
CU_ASSERT_FATAL (endpoint_has_psmx_enabled (rd) == rd_psmx_enabled);
dds_delete_qos (qos);

rc = dds_set_status_mask (rd, DDS_DATA_AVAILABLE_STATUS);
CU_ASSERT_FATAL (rc == 0);
rc = dds_waitset_attach (ws, rd, 0);
CU_ASSERT_FATAL (rc == 0);

for (int step_i = 0; step_i < (int) (sizeof (cases[k].step) / sizeof (cases[k].step[0])); step_i++)
{
const void *wrdata = cases[k].step[step_i].data;
dds_return_t (* const op) (dds_entity_t wr, const void *data) = cases[k].step[step_i].op;

// dispose + loan is not supported (triggers use-after-free; this is documented, but bad)
if (op == dds_dispose && wrloan)
continue;

const bool justkey = (op != dds_write);
printf (" | %s %p", (op == dds_write) ? "write" : "dispose", wrdata); fflush (stdout);
rc = op (wr, get_write_datapointer (wr, cases[k].desc, wrdata, wrloan));
CU_ASSERT_FATAL (rc == 0);
(void) dds_waitset_wait (ws, NULL, 0, DDS_INFINITY);
dds_sample_info_t si;
void *rddata;
if (rdloan)
rddata = NULL;
else
{
rddata = ddsrt_malloc (cases[k].desc->m_size);
memset (rddata, 0, cases[k].desc->m_size);
}
rc = dds_take (rd, &rddata, &si, 1, 1);
CU_ASSERT_FATAL (rc == 1);
printf (" | rddata %p", rddata); fflush (stdout);
CU_ASSERT_FATAL (data_equal (cases[k].desc, wrdata, rddata, justkey));
if (!rdloan)
dds_sample_free (rddata, cases[k].desc, DDS_FREE_ALL);
else
{
rc = dds_return_loan (rd, &rddata, 1);
CU_ASSERT_FATAL (rc == DDS_RETCODE_OK);
}
}
printf ("\n"); fflush (stdout);

rc = dds_delete (wr);
CU_ASSERT_FATAL (rc == 0);
rc = dds_delete (rd);
CU_ASSERT_FATAL (rc == 0);
rc = dds_delete (ws);
CU_ASSERT_FATAL (rc == 0);
}
}
}
}
rc = dds_delete (tp);
CU_ASSERT_FATAL (rc == 0);
}
dds_delete (dds_get_parent (pp));
}

0 comments on commit 05bdd5b

Please sign in to comment.