summaryrefslogtreecommitdiffstats
path: root/test/mirror_vfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/mirror_vfd.c')
-rw-r--r--test/mirror_vfd.c2483
1 files changed, 2483 insertions, 0 deletions
diff --git a/test/mirror_vfd.c b/test/mirror_vfd.c
new file mode 100644
index 0000000..b4f4c2c
--- /dev/null
+++ b/test/mirror_vfd.c
@@ -0,0 +1,2483 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://www.hdfgroup.org/licenses. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose: Test the Mirror VFD functionality.
+ */
+
+/* WARNING: The use of realpath() is probably system-dependent, as are
+ * other things here such as the socket calls.
+ * Notable to realpath() in particular is the use of "PATH_MAX", which
+ * apparently has some major potential issues if paths are abused.
+ * http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
+ * so BE CAREFUL about the paths we throw around?
+ */
+
+#include "h5test.h"
+#include "cache_common.h"
+#include "genall5.h"
+
+#ifdef H5_HAVE_MIRROR_VFD
+
+#include "H5FDmirror_priv.h" /* Private header for the mirror VFD */
+
+/* For future consideration, IP address and port number might be
+ * environment variables?
+ */
+#define SERVER_IP_ADDRESS "127.0.0.1"
+
+/* Primary listening port on server. */
+#define SERVER_HANDSHAKE_PORT 3000
+
+#define DATABUFFER_SIZE 128
+#define DSET_NAME_LEN 16
+
+/* Parameters for the "large chunked dataset" writing */
+#define MAX_DSET_COUNT 255
+#define DSET_DIM 32
+#define CHUNK_DIM 8
+
+#define CONCURRENT_COUNT 3 /* Number of files in concurrent test */
+
+/* Macro: LOGPRINT()
+ * Prints logging and debugging messages to the output stream based
+ * on the level of verbosity.
+ * 0 : no logging
+ * 1 : errors only
+ * 2 : details
+ * 3 : all
+ */
+#define DEFAULT_VERBOSITY 1
+static unsigned int g_verbosity = DEFAULT_VERBOSITY;
+
+/* Macro for selective debug printing / logging */
+#define LOGPRINT(lvl, ...) \
+ do { \
+ if ((lvl) <= g_verbosity) { \
+ HDfprintf(g_log_stream, __VA_ARGS__); \
+ HDfflush(g_log_stream); \
+ } \
+ } while (0)
+
+#define MIRROR_RW_DIR "mirror_rw/"
+#define MIRROR_WO_DIR "mirror_wo/"
+
+/* String buffer for error messages */
+#define MIRR_MESG_SIZE 128
+static char mesg[MIRR_MESG_SIZE + 1];
+
+/* ----------------------------------------------------------------------------
+ * Structure: struct mt_opts
+ *
+ * Purpose: Convenience structure to hold options as parsed from the
+ * command line.
+ *
+ * `portno` (int)
+ * Port number, as received from arguments.
+ *
+ * `ip` (char *)
+ * IP address string as received from arguments.
+ *
+ * ----------------------------------------------------------------------------
+ */
+struct mt_opts {
+ int portno;
+ char ip[H5FD_MIRROR_MAX_IP_LEN + 1];
+};
+
+/* Convenience structure for passing file names via helper functions.
+ */
+struct mirrortest_filenames {
+ char rw[H5FD_SPLITTER_PATH_MAX + 1];
+ char wo[H5FD_SPLITTER_PATH_MAX + 1];
+ char log[H5FD_SPLITTER_PATH_MAX + 1];
+};
+
+static FILE *g_log_stream = NULL; /* initialized at runtime */
+
+static herr_t _verify_datasets(unsigned min_dset, unsigned max_dset, hid_t *filespace_id, hid_t *dataset_id,
+ hid_t memspace_id);
+
+static herr_t _create_chunking_ids(hid_t file_id, unsigned min_dset, unsigned max_dset, hsize_t *chunk_dims,
+ hsize_t *dset_dims, hid_t *dataspace_ids, hid_t *filespace_ids,
+ hid_t *dataset_ids, hid_t *memspace_id);
+
+static herr_t _close_chunking_ids(unsigned min_dset, unsigned max_dset, hid_t *dataspace_ids,
+ hid_t *filespace_ids, hid_t *dataset_ids, hid_t *memspace_id);
+
+static herr_t populate_filepath(const char *dirname, const char *_basename, hid_t fapl_id, char *path_out,
+ hbool_t h5suffix);
+
+static hid_t create_mirroring_split_fapl(const char *_basename, struct mirrortest_filenames *names,
+ const struct mt_opts *opts);
+
+/* ----------------------------------------------------------------------------
+ * Function: populate_filepath
+ *
+ * Purpose: Given a directory name and a base name, concatenate the two and
+ * run h5fixname() to get the "actual" path to the intended target.
+ * `h5suffix' should be FALSE to keep the base name unaltered;
+ * TRUE will append the '.h5' h5suffix to the basename...
+ * FALSE -> h5fixname_no_suffix(), TRUE -> h5fixname()
+ * <h5fixname_prefix> / <dirname> / <basename> <h5prefix?>
+ *
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+populate_filepath(const char *dirname, const char *basename, hid_t fapl_id, char *path_out, hbool_t h5suffix)
+{
+ char *path = NULL;
+
+ if ((basename == NULL) || (*basename == 0) || (dirname == NULL) || (*dirname == 0) || (path_out == NULL))
+ TEST_ERROR;
+
+ if (NULL == (path = HDcalloc(H5FD_SPLITTER_PATH_MAX, sizeof(char))))
+ TEST_ERROR;
+
+ if (HDsnprintf(path, H5FD_SPLITTER_PATH_MAX, "%s%s%s", dirname,
+ (dirname[HDstrlen(dirname)] == '/') ? "" : "/", /* slash iff needed */
+ basename) > H5FD_SPLITTER_PATH_MAX)
+ TEST_ERROR;
+
+ if (h5suffix == TRUE) {
+ if (h5_fixname(path, fapl_id, path_out, H5FD_SPLITTER_PATH_MAX) == NULL)
+ TEST_ERROR;
+ }
+ else {
+ if (h5_fixname_no_suffix(path, fapl_id, path_out, H5FD_SPLITTER_PATH_MAX) == NULL)
+ TEST_ERROR;
+ }
+
+ HDfree(path);
+
+ return SUCCEED;
+
+error:
+ HDfree(path);
+ return FAIL;
+} /* end populate_filepath() */
+
+/* ---------------------------------------------------------------------------
+ * Function: build_paths
+ *
+ * Purpose: Convenience function to create the three file paths used in
+ * most mirror tests.
+ *
+ * Return: SUCCEED/FAIL
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+build_paths(const char *basename, H5FD_splitter_vfd_config_t *splitter_config,
+ struct mirrortest_filenames *names)
+{
+ char *baselogname = NULL;
+
+ if (NULL == (baselogname = HDcalloc(H5FD_SPLITTER_PATH_MAX, sizeof(char))))
+ TEST_ERROR;
+
+ if (populate_filepath(MIRROR_RW_DIR, basename, splitter_config->rw_fapl_id, names->rw, TRUE) < 0)
+ TEST_ERROR;
+
+ if (populate_filepath(MIRROR_WO_DIR, basename, splitter_config->wo_fapl_id, names->wo, TRUE) < 0)
+ TEST_ERROR;
+
+ if (basename == NULL || *basename == 0)
+ TEST_ERROR;
+ if (HDsnprintf(baselogname, H5FD_SPLITTER_PATH_MAX, "%s_err.log", basename) > H5FD_SPLITTER_PATH_MAX)
+ TEST_ERROR;
+
+ if (populate_filepath(MIRROR_WO_DIR, baselogname, splitter_config->wo_fapl_id, names->log, FALSE) < 0)
+ TEST_ERROR;
+
+ HDfree(baselogname);
+
+ return SUCCEED;
+
+error:
+ HDfree(baselogname);
+ return FAIL;
+} /* end build_paths() */
+
+/* ---------------------------------------------------------------------------
+ * Function: test_fapl_configuration
+ *
+ * Purpose: Test FAPL configuration and examination.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_fapl_configuration(void)
+{
+ hid_t fapl_id = H5I_INVALID_HID;
+ H5FD_mirror_fapl_t mirror_conf = {
+ H5FD_MIRROR_FAPL_MAGIC, /* magic */
+ H5FD_MIRROR_CURR_FAPL_T_VERSION, /* version */
+ SERVER_HANDSHAKE_PORT, /* handhake_port */
+ SERVER_IP_ADDRESS, /* remote_ip "IP address" */
+ };
+ H5FD_mirror_fapl_t fa_out = {0, 0, 0, ""};
+
+ TESTING("Mirror fapl configuration (set/get)");
+
+ if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
+ TEST_ERROR;
+
+ if (H5Pset_fapl_mirror(fapl_id, &mirror_conf) < 0)
+ TEST_ERROR;
+
+ if (H5Pget_fapl_mirror(fapl_id, &fa_out) < 0)
+ TEST_ERROR;
+
+ if (H5FD_MIRROR_FAPL_MAGIC != fa_out.magic)
+ TEST_ERROR;
+
+ if (H5FD_MIRROR_CURR_FAPL_T_VERSION != fa_out.version)
+ TEST_ERROR;
+
+ if (SERVER_HANDSHAKE_PORT != fa_out.handshake_port)
+ TEST_ERROR;
+
+ if (HDstrncmp(SERVER_IP_ADDRESS, (const char *)fa_out.remote_ip, H5FD_MIRROR_MAX_IP_LEN))
+ TEST_ERROR;
+
+ if (H5Pclose(fapl_id) < 0)
+ TEST_ERROR;
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY
+ {
+ H5Pclose(fapl_id);
+ }
+ H5E_END_TRY;
+ return -1;
+} /* end test_fapl_configuration() */
+
+#define PRINT_BUFFER_DIFF(act, exp, len) \
+ do { \
+ size_t _x = 0; \
+ while ((act)[_x] == (exp)[_x]) { \
+ _x++; \
+ } \
+ if (_x != (len)) { \
+ size_t _y = 0; \
+ HDprintf("First bytes differ at %zu\n", _x); \
+ HDprintf("exp "); \
+ for (_y = _x; _y < (len); _y++) { \
+ HDprintf("%02X", (unsigned char)(exp)[_y]); \
+ } \
+ HDprintf("\nact "); \
+ for (_y = _x; _y < (len); _y++) { \
+ HDprintf("%02X", (unsigned char)(act)[_y]); \
+ } \
+ HDprintf("\n"); \
+ } \
+ } while (0); /* end PRINT_BUFFER_DIFF */
+
+/*******************************************/
+/* Encode/decode tests for various C types */
+/*******************************************/
+
+/* Test uint8_t encode/decode */
+static int
+test_encdec_uint8_t(void)
+{
+ unsigned char buf[8];
+ unsigned char expected[8];
+ const uint8_t v = 200;
+ unsigned char out = 0;
+
+ TESTING("Mirror encode/decode of uint8_t data");
+
+ /* Start of buffer uint8_t */
+ HDmemset(buf, 0, 8);
+ HDmemset(expected, 0, 8);
+ expected[0] = 200;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint8(buf, v) != 1)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint8(&out, buf) != 1)
+ TEST_ERROR;
+ if (v != out)
+ TEST_ERROR;
+
+ /* Middle of buffer uint8_t */
+ HDmemset(buf, 0, 8);
+ HDmemset(expected, 0, 8);
+ expected[3] = v;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint8((buf + 3), v) != 1)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint8(&out, (buf + 3)) != 1)
+ TEST_ERROR;
+ if (v != out)
+ TEST_ERROR;
+
+ /* End of buffer uint8_t */
+ HDmemset(buf, 0, 8);
+ HDmemset(expected, 0, 8);
+ expected[7] = v;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint8((buf + 7), v) != 1)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint8(&out, (buf + 7)) != 1)
+ TEST_ERROR;
+ if (v != out)
+ TEST_ERROR;
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+}
+
+/* Test uint16_t encode/decode */
+static int
+test_encdec_uint16_t(void)
+{
+ unsigned char buf[8];
+ unsigned char expected[8];
+ const uint16_t v = 0x8F02;
+ uint16_t out = 0;
+
+ TESTING("Mirror encode/decode of uint16_t data");
+
+ /* Start of buffer uint16_t */
+ HDmemset(buf, 0, 8);
+ HDmemset(expected, 0, 8);
+ expected[0] = 0x8F;
+ expected[1] = 0x02;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint16(buf, v) != 2)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint16(&out, buf) != 2)
+ TEST_ERROR;
+ if (out != v)
+ TEST_ERROR;
+
+ /* Middle of buffer uint16_t */
+ HDmemset(buf, 0, 8);
+ HDmemset(expected, 0, 8);
+ expected[3] = 0x8F;
+ expected[4] = 0x02;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint16((buf + 3), v) != 2)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint16(&out, (buf + 3)) != 2)
+ TEST_ERROR;
+ if (out != v)
+ TEST_ERROR;
+
+ /* slice */
+ if (H5FD__mirror_xmit_decode_uint16(&out, (buf + 4)) != 2)
+ TEST_ERROR;
+ if (out != 0x0200)
+ TEST_ERROR;
+
+ /* End of buffer uint16_t */
+ HDmemset(buf, 0, 8);
+ HDmemset(expected, 0, 8);
+ expected[6] = 0x8F;
+ expected[7] = 0x02;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint16((buf + 6), v) != 2)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint16(&out, (buf + 6)) != 2)
+ TEST_ERROR;
+ if (out != v)
+ TEST_ERROR;
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+}
+
+/* Test uint32_t encode/decode */
+static int
+test_encdec_uint32_t(void)
+{
+ unsigned char buf[8];
+ unsigned char expected[8];
+ const uint32_t v = 0x8F020048;
+ uint32_t out = 0;
+
+ TESTING("Mirror encode/decode of uint32_t data");
+
+ /* Start of buffer uint32_t */
+ HDmemset(buf, 0, 8);
+ HDmemset(expected, 0, 8);
+ expected[0] = 0x8F;
+ expected[1] = 0x02;
+ expected[2] = 0x00;
+ expected[3] = 0x48;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint32(buf, v) != 4)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint32(&out, buf) != 4)
+ TEST_ERROR;
+ if (out != v)
+ TEST_ERROR;
+
+ /* Middle of buffer uint32_t */
+ HDmemset(buf, 0, 8);
+ HDmemset(expected, 0, 8);
+ expected[3] = 0x8F;
+ expected[4] = 0x02;
+ expected[5] = 0x00;
+ expected[6] = 0x48;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint32((buf + 3), v) != 4)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint32(&out, (buf + 3)) != 4)
+ TEST_ERROR;
+ if (out != v)
+ TEST_ERROR;
+ /* slice */
+ if (H5FD__mirror_xmit_decode_uint32(&out, (buf + 4)) != 4)
+ TEST_ERROR;
+ if (out != 0x02004800)
+ TEST_ERROR;
+
+ /* End of buffer uint32_t */
+ HDmemset(buf, 0, 8);
+ HDmemset(expected, 0, 8);
+ expected[4] = 0x8F;
+ expected[5] = 0x02;
+ expected[6] = 0x00;
+ expected[7] = 0x48;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint32((buf + 4), v) != 4)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 8);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint32(&out, (buf + 4)) != 4)
+ TEST_ERROR;
+ if (out != v)
+ TEST_ERROR;
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+}
+
+/* Test uint64_t encode/decode */
+static int
+test_encdec_uint64_t(void)
+{
+ unsigned char buf[16];
+ unsigned char expected[16];
+ const uint64_t v = 0x90DCBE17939CE4BB;
+ uint64_t out = 0;
+
+ TESTING("Mirror encode/decode of uint64_t data");
+
+ /* Start of buffer uint64_t */
+ HDmemset(buf, 0, 16);
+ HDmemset(expected, 0, 16);
+ expected[0] = 0x90;
+ expected[1] = 0xDC;
+ expected[2] = 0xBE;
+ expected[3] = 0x17;
+ expected[4] = 0x93;
+ expected[5] = 0x9C;
+ expected[6] = 0xE4;
+ expected[7] = 0xBB;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint64(buf, v) != 8)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 16) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 16);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint64(&out, buf) != 8)
+ TEST_ERROR;
+ if (out != v)
+ TEST_ERROR;
+
+ /* Middle of buffer uint64_t */
+ HDmemset(buf, 0, 16);
+ HDmemset(expected, 0, 16);
+ expected[3] = 0x90;
+ expected[4] = 0xDC;
+ expected[5] = 0xBE;
+ expected[6] = 0x17;
+ expected[7] = 0x93;
+ expected[8] = 0x9C;
+ expected[9] = 0xE4;
+ expected[10] = 0xBB;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint64((buf + 3), v) != 8)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 16) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 16);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint64(&out, (buf + 3)) != 8)
+ TEST_ERROR;
+ if (out != v)
+ TEST_ERROR;
+ /* Slice */
+ if (H5FD__mirror_xmit_decode_uint64(&out, (buf + 6)) != 8)
+ TEST_ERROR;
+ if (out != 0x17939CE4BB000000)
+ TEST_ERROR;
+
+ /* End of buffer uint64_t */
+ HDmemset(buf, 0, 16);
+ HDmemset(expected, 0, 16);
+ expected[8] = 0x90;
+ expected[9] = 0xDC;
+ expected[10] = 0xBE;
+ expected[11] = 0x17;
+ expected[12] = 0x93;
+ expected[13] = 0x9C;
+ expected[14] = 0xE4;
+ expected[15] = 0xBB;
+ out = 0;
+ if (H5FD__mirror_xmit_encode_uint64((buf + 8), v) != 8)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, 16) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, 16);
+ TEST_ERROR;
+ }
+ if (H5FD__mirror_xmit_decode_uint64(&out, (buf + 8)) != 8)
+ TEST_ERROR;
+ if (out != v)
+ TEST_ERROR;
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+}
+
+/*****************************/
+/* Other Encode/decode tests */
+/*****************************/
+
+/* Test xmit header structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+static int
+test_encdec_header(H5FD_mirror_xmit_t xmit_mock)
+{
+ unsigned char buf[H5FD_MIRROR_XMIT_HEADER_SIZE + 8];
+ unsigned char expected[H5FD_MIRROR_XMIT_HEADER_SIZE + 8];
+ H5FD_mirror_xmit_t xmit_out;
+ size_t i = 0;
+
+ TESTING("Mirror encode/decode of xmit header");
+
+ /* Sanity check */
+ if (14 != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+
+ /* Populate the expected buffer; expect end padding of 0xFF */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_HEADER_SIZE + 8);
+ for (i = 0; i < H5FD_MIRROR_XMIT_HEADER_SIZE; i++) {
+ expected[i + 2] = (unsigned char)i;
+ }
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_HEADER_SIZE + 8);
+ if (H5FD_mirror_xmit_encode_header((buf + 2), &xmit_mock) != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_HEADER_SIZE + 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_HEADER_SIZE + 8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer */
+ if (H5FD_mirror_xmit_decode_header(&xmit_out, (buf + 2)) != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ TEST_ERROR;
+ if (xmit_out.magic != xmit_mock.magic)
+ TEST_ERROR;
+ if (xmit_out.version != xmit_mock.version)
+ TEST_ERROR;
+ if (xmit_out.session_token != xmit_mock.session_token)
+ TEST_ERROR;
+ if (xmit_out.xmit_count != xmit_mock.xmit_count)
+ TEST_ERROR;
+ if (xmit_out.op != xmit_mock.op)
+ TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_header(&xmit_out, buf) != H5FD_MIRROR_XMIT_HEADER_SIZE)
+ TEST_ERROR;
+ if (xmit_out.magic != 0xFFFF0001)
+ TEST_ERROR;
+ if (xmit_out.version != 0x02)
+ TEST_ERROR;
+ if (xmit_out.session_token != 0x03040506)
+ TEST_ERROR;
+ if (xmit_out.xmit_count != 0x0708090A)
+ TEST_ERROR;
+ if (xmit_out.op != 0x0B)
+ TEST_ERROR;
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+}
+
+/* Test xmit set-eoa structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+static int
+test_encdec_set_eoa(H5FD_mirror_xmit_t xmit_mock)
+{
+ unsigned char buf[H5FD_MIRROR_XMIT_EOA_SIZE + 8];
+ unsigned char expected[H5FD_MIRROR_XMIT_EOA_SIZE + 8];
+ H5FD_mirror_xmit_eoa_t xmit_in;
+ H5FD_mirror_xmit_eoa_t xmit_out;
+ size_t i = 0;
+
+ TESTING("Mirror encode/decode of xmit set-eoa");
+
+ /* Sanity check */
+ if ((14 + 9) != H5FD_MIRROR_XMIT_EOA_SIZE)
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ if (xmit_mock.op != 0x0D)
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+
+ /* Populate the expected buffer; expect end padding of 0xFF */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_EOA_SIZE + 8);
+ for (i = 0; i < H5FD_MIRROR_XMIT_EOA_SIZE; i++)
+ expected[i + 2] = (unsigned char)i;
+
+ /* Set xmit_in */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.type = 0x0E;
+ xmit_in.eoa_addr = 0x0F10111213141516;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_EOA_SIZE + 8);
+ if (H5FD_mirror_xmit_encode_set_eoa((buf + 2), &xmit_in) != H5FD_MIRROR_XMIT_EOA_SIZE)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_EOA_SIZE + 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_EOA_SIZE + 8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer */
+ if (H5FD_mirror_xmit_decode_set_eoa(&xmit_out, (buf + 2)) != H5FD_MIRROR_XMIT_EOA_SIZE)
+ TEST_ERROR;
+ if (xmit_out.pub.magic != xmit_mock.magic)
+ TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version)
+ TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token)
+ TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count)
+ TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op)
+ TEST_ERROR;
+ if (xmit_out.type != 0x0E)
+ TEST_ERROR;
+ if (xmit_out.eoa_addr != 0x0F10111213141516)
+ TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_set_eoa(&xmit_out, buf) != H5FD_MIRROR_XMIT_EOA_SIZE)
+ TEST_ERROR;
+ if (xmit_out.pub.magic != 0xFFFF0001)
+ TEST_ERROR;
+ if (xmit_out.pub.version != 0x02)
+ TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506)
+ TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A)
+ TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B)
+ TEST_ERROR;
+ if (xmit_out.type != 0x0C)
+ TEST_ERROR;
+ if (xmit_out.eoa_addr != 0x0D0E0F1011121314)
+ TEST_ERROR;
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+}
+
+/* Test xmit lock structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+static int
+test_encdec_lock(H5FD_mirror_xmit_t xmit_mock)
+{
+ unsigned char buf[H5FD_MIRROR_XMIT_LOCK_SIZE + 8];
+ unsigned char expected[H5FD_MIRROR_XMIT_LOCK_SIZE + 8];
+ H5FD_mirror_xmit_lock_t xmit_in;
+ H5FD_mirror_xmit_lock_t xmit_out;
+ size_t i = 0;
+
+ TESTING("Mirror encode/decode of xmit lock");
+
+ /* Sanity check */
+ if ((14 + 8) != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ if (xmit_mock.op != 0x0D)
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+
+ /* Populate the expected buffer; expect end padding of 0xFF */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_LOCK_SIZE + 8);
+ for (i = 0; i < H5FD_MIRROR_XMIT_LOCK_SIZE; i++)
+ expected[i + 2] = (unsigned char)i;
+
+ /* Set xmit_in */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.rw = 0x0E0F101112131415;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_LOCK_SIZE + 8);
+ if (H5FD_mirror_xmit_encode_lock((buf + 2), &xmit_in) != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_LOCK_SIZE + 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_LOCK_SIZE + 8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer */
+ if (H5FD_mirror_xmit_decode_lock(&xmit_out, (buf + 2)) != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ TEST_ERROR;
+ if (xmit_out.pub.magic != xmit_mock.magic)
+ TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version)
+ TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token)
+ TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count)
+ TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op)
+ TEST_ERROR;
+ if (xmit_out.rw != 0x0E0F101112131415)
+ TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_lock(&xmit_out, buf) != H5FD_MIRROR_XMIT_LOCK_SIZE)
+ TEST_ERROR;
+ if (xmit_out.pub.magic != 0xFFFF0001)
+ TEST_ERROR;
+ if (xmit_out.pub.version != 0x02)
+ TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506)
+ TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A)
+ TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B)
+ TEST_ERROR;
+ if (xmit_out.rw != 0x0C0D0E0F10111213)
+ TEST_ERROR;
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+}
+
+/* Test xmit open structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ *
+ * Verifies that the first zero character in the filepath will end the
+ * string, with all following bytes in the encoded buffer being zeroed.
+ */
+static int
+test_encdec_open(H5FD_mirror_xmit_t xmit_mock)
+{
+ unsigned char *buf = NULL;
+ unsigned char *expected = NULL;
+ H5FD_mirror_xmit_open_t *xmit_in = NULL;
+ H5FD_mirror_xmit_open_t *xmit_out = NULL;
+
+ TESTING("Mirror encode/decode of xmit open");
+
+ /* Sanity check */
+ if ((14 + 20 + 4097) != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ if (xmit_mock.op != 0x0D)
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+
+ /* Allocate memory */
+ if (NULL == (buf = HDmalloc((H5FD_MIRROR_XMIT_OPEN_SIZE + 8) * sizeof(unsigned char))))
+ FAIL_PUTS_ERROR("Unable to allocate memory for buf");
+ if (NULL == (expected = HDmalloc((H5FD_MIRROR_XMIT_OPEN_SIZE + 8) * sizeof(unsigned char))))
+ FAIL_PUTS_ERROR("Unable to allocate memory for expected");
+ if (NULL == (xmit_in = HDmalloc(sizeof(H5FD_mirror_xmit_open_t))))
+ FAIL_PUTS_ERROR("Unable to allocate memory for xmit_in");
+ if (NULL == (xmit_out = HDmalloc(sizeof(H5FD_mirror_xmit_open_t))))
+ FAIL_PUTS_ERROR("Unable to allocate memory for xmit_out");
+
+ /* Populate the expected buffer; expect end padding of 0xFF */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_OPEN_SIZE + 8);
+ for (size_t i = 0; i < H5FD_MIRROR_XMIT_OPEN_SIZE; i++) {
+ /* 0x100 is "zero" in a byte, so encode will treat it as a NULL-
+ * terminator in the filepath string. Expect all zeroes following.
+ */
+ expected[i + 2] = (i > 0xFF) ? 0 : (unsigned char)i;
+ }
+
+ /* Set xmit_in */
+ xmit_in->pub = xmit_mock; /* shared/common */
+ xmit_in->flags = 0x0E0F1011;
+ xmit_in->maxaddr = 0x1213141516171819;
+ xmit_in->size_t_blob = 0x1A1B1C1D1E1F2021;
+ for (size_t i = 0x22; i < H5FD_MIRROR_XMIT_FILEPATH_MAX + 0x22; i++) {
+ /* Non-zero values repeat after 0x100, but will not be encoded */
+ xmit_in->filename[i - 0x22] = (char)(i % 0x100);
+ }
+ xmit_in->filename[H5FD_MIRROR_XMIT_FILEPATH_MAX - 1] = 0;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_OPEN_SIZE + 8);
+ if (H5FD_mirror_xmit_encode_open((buf + 2), xmit_in) != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_OPEN_SIZE + 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_OPEN_SIZE + 8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer */
+ if (H5FD_mirror_xmit_decode_open(xmit_out, (buf + 2)) != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ TEST_ERROR;
+ if (xmit_out->pub.magic != xmit_mock.magic)
+ TEST_ERROR;
+ if (xmit_out->pub.version != xmit_mock.version)
+ TEST_ERROR;
+ if (xmit_out->pub.session_token != xmit_mock.session_token)
+ TEST_ERROR;
+ if (xmit_out->pub.xmit_count != xmit_mock.xmit_count)
+ TEST_ERROR;
+ if (xmit_out->pub.op != xmit_mock.op)
+ TEST_ERROR;
+ if (xmit_out->flags != xmit_in->flags)
+ TEST_ERROR;
+ if (xmit_out->maxaddr != xmit_in->maxaddr)
+ TEST_ERROR;
+ if (xmit_out->size_t_blob != xmit_in->size_t_blob)
+ TEST_ERROR;
+ if (HDstrncmp(xmit_out->filename, xmit_in->filename, H5FD_MIRROR_XMIT_FILEPATH_MAX) != 0) {
+ PRINT_BUFFER_DIFF(xmit_out->filename, xmit_in->filename, H5FD_MIRROR_XMIT_FILEPATH_MAX);
+ TEST_ERROR;
+ }
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_open(xmit_out, buf) != H5FD_MIRROR_XMIT_OPEN_SIZE)
+ TEST_ERROR;
+ if (xmit_out->pub.magic != 0xFFFF0001)
+ TEST_ERROR;
+ if (xmit_out->pub.version != 0x02)
+ TEST_ERROR;
+ if (xmit_out->pub.session_token != 0x03040506)
+ TEST_ERROR;
+ if (xmit_out->pub.xmit_count != 0x0708090A)
+ TEST_ERROR;
+ if (xmit_out->pub.op != 0x0B)
+ TEST_ERROR;
+ if (xmit_out->flags != 0x0C0D0E0F)
+ TEST_ERROR;
+ if (xmit_out->maxaddr != 0x1011121314151617)
+ TEST_ERROR;
+ if (xmit_out->size_t_blob != 0x18191A1B1C1D1E1F)
+ TEST_ERROR;
+ /* Update expected "filepath" in structure */
+ for (size_t i = 0x20; i < H5FD_MIRROR_XMIT_FILEPATH_MAX + 0x20; i++)
+ xmit_in->filename[i - 0x20] = (i > 0xFF) ? 0 : (char)i;
+ if (HDstrncmp(xmit_out->filename, xmit_in->filename, H5FD_MIRROR_XMIT_FILEPATH_MAX) != 0) {
+ PRINT_BUFFER_DIFF(xmit_out->filename, xmit_in->filename, H5FD_MIRROR_XMIT_FILEPATH_MAX);
+ TEST_ERROR;
+ }
+
+ HDfree(buf);
+ HDfree(expected);
+ HDfree(xmit_in);
+ HDfree(xmit_out);
+
+ PASSED();
+ return 0;
+
+error:
+ HDfree(buf);
+ HDfree(expected);
+ HDfree(xmit_in);
+ HDfree(xmit_out);
+
+ return -1;
+}
+
+/* Test xmit reply structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ *
+ * Verifies that the first zero character in the filepath will end the
+ * string, with all following bytes in the encoded buffer being zeroed.
+ */
+static int
+test_encdec_reply(H5FD_mirror_xmit_t xmit_mock)
+{
+ unsigned char buf[H5FD_MIRROR_XMIT_REPLY_SIZE + 8];
+ unsigned char expected[H5FD_MIRROR_XMIT_REPLY_SIZE + 8];
+ H5FD_mirror_xmit_reply_t xmit_in;
+ H5FD_mirror_xmit_reply_t xmit_out;
+ size_t i = 0;
+
+ TESTING("Mirror encode/decode of xmit reply");
+
+ /* Sanity check */
+ if ((14 + 4 + 256) != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ if (xmit_mock.op != 0x0D)
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+
+ /* Populate the expected buffer; expect end padding of 0xFF */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_REPLY_SIZE + 8);
+ for (i = 0; i < H5FD_MIRROR_XMIT_REPLY_SIZE; i++) {
+ /* 0x100 is "zero" in a byte, so encode will treat it as a NULL-
+ * terminator in the filepath string. Expect all zeroes following.
+ */
+ expected[i + 2] = (i > 0xFF) ? 0 : (unsigned char)i;
+ }
+
+ /* Set xmit_in */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.status = 0x0E0F1011;
+ for (i = 0x12; i < H5FD_MIRROR_STATUS_MESSAGE_MAX + 0x12; i++) {
+ /* Non-zero values repeat after 0x100, but will not be encoded */
+ xmit_in.message[i - 0x12] = (char)(i % 0x100);
+ }
+ xmit_in.message[H5FD_MIRROR_STATUS_MESSAGE_MAX - 1] = 0;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_REPLY_SIZE + 8);
+ if (H5FD_mirror_xmit_encode_reply((buf + 2), &xmit_in) != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_REPLY_SIZE + 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_REPLY_SIZE + 8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer */
+ if (H5FD_mirror_xmit_decode_reply(&xmit_out, (buf + 2)) != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ TEST_ERROR;
+ if (xmit_out.pub.magic != xmit_mock.magic)
+ TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version)
+ TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token)
+ TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count)
+ TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op)
+ TEST_ERROR;
+ if (xmit_out.status != xmit_in.status)
+ TEST_ERROR;
+ if (HDstrncmp(xmit_out.message, xmit_in.message, H5FD_MIRROR_STATUS_MESSAGE_MAX) != 0) {
+ PRINT_BUFFER_DIFF(xmit_out.message, xmit_in.message, H5FD_MIRROR_STATUS_MESSAGE_MAX);
+ TEST_ERROR;
+ }
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_reply(&xmit_out, buf) != H5FD_MIRROR_XMIT_REPLY_SIZE)
+ TEST_ERROR;
+ if (xmit_out.pub.magic != 0xFFFF0001)
+ TEST_ERROR;
+ if (xmit_out.pub.version != 0x02)
+ TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506)
+ TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A)
+ TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B)
+ TEST_ERROR;
+ if (xmit_out.status != 0x0C0D0E0F)
+ TEST_ERROR;
+ /* Update expected "message" in structure */
+ for (i = 0x10; i < H5FD_MIRROR_STATUS_MESSAGE_MAX + 0x10; i++)
+ xmit_in.message[i - 0x10] = (i > 0xFF) ? 0 : (char)i;
+ if (HDstrncmp(xmit_out.message, xmit_in.message, H5FD_MIRROR_STATUS_MESSAGE_MAX) != 0) {
+ PRINT_BUFFER_DIFF(xmit_out.message, xmit_in.message, H5FD_MIRROR_STATUS_MESSAGE_MAX);
+ TEST_ERROR;
+ }
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+}
+
+/* Test xmit write structure encode/decode
+ * Write bogus but easily verifiable data to inside a buffer, and compare.
+ * Then decode the buffer and compare the structure contents.
+ * Then repeat from a different offset in the buffer and compare.
+ */
+static int
+test_encdec_write(H5FD_mirror_xmit_t xmit_mock)
+{
+ unsigned char buf[H5FD_MIRROR_XMIT_WRITE_SIZE + 8];
+ unsigned char expected[H5FD_MIRROR_XMIT_WRITE_SIZE + 8];
+ H5FD_mirror_xmit_write_t xmit_in;
+ H5FD_mirror_xmit_write_t xmit_out;
+ size_t i = 0;
+
+ TESTING("Mirror encode/decode of xmit write");
+
+ /* Sanity check */
+ if ((14 + 17) != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ FAIL_PUTS_ERROR("Header size definition does not match test\n");
+ if (xmit_mock.op != 0x0D)
+ FAIL_PUTS_ERROR("shared header structure is not in expected state");
+
+ /* Populate the expected buffer; expect end padding of 0xFF */
+ HDmemset(expected, 0xFF, H5FD_MIRROR_XMIT_WRITE_SIZE + 8);
+ for (i = 0; i < H5FD_MIRROR_XMIT_WRITE_SIZE; i++)
+ expected[i + 2] = (unsigned char)i;
+
+ /* Set xmit_in */
+ xmit_in.pub = xmit_mock; /* shared/common */
+ xmit_in.type = 0x0E;
+ xmit_in.offset = 0x0F10111213141516;
+ xmit_in.size = 0x1718191A1B1C1D1E;
+
+ /* Encode, and compare buffer contents
+ * Initial buffer is filled with 0xFF to match expected padding
+ */
+ HDmemset(buf, 0xFF, H5FD_MIRROR_XMIT_WRITE_SIZE + 8);
+ if (H5FD_mirror_xmit_encode_write((buf + 2), &xmit_in) != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ TEST_ERROR;
+ if (HDmemcmp(buf, expected, H5FD_MIRROR_XMIT_WRITE_SIZE + 8) != 0) {
+ PRINT_BUFFER_DIFF(buf, expected, H5FD_MIRROR_XMIT_WRITE_SIZE + 8);
+ TEST_ERROR;
+ }
+
+ /* Decode from buffer */
+ if (H5FD_mirror_xmit_decode_write(&xmit_out, (buf + 2)) != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ TEST_ERROR;
+ if (xmit_out.pub.magic != xmit_mock.magic)
+ TEST_ERROR;
+ if (xmit_out.pub.version != xmit_mock.version)
+ TEST_ERROR;
+ if (xmit_out.pub.session_token != xmit_mock.session_token)
+ TEST_ERROR;
+ if (xmit_out.pub.xmit_count != xmit_mock.xmit_count)
+ TEST_ERROR;
+ if (xmit_out.pub.op != xmit_mock.op)
+ TEST_ERROR;
+ if (xmit_out.type != 0x0E)
+ TEST_ERROR;
+ if (xmit_out.offset != 0x0F10111213141516)
+ TEST_ERROR;
+ if (xmit_out.size != 0x1718191A1B1C1D1E)
+ TEST_ERROR;
+
+ /* Decode from different offset in buffer
+ * Observe changes when ingesting the padding
+ */
+ if (H5FD_mirror_xmit_decode_write(&xmit_out, buf) != H5FD_MIRROR_XMIT_WRITE_SIZE)
+ TEST_ERROR;
+ if (xmit_out.pub.magic != 0xFFFF0001)
+ TEST_ERROR;
+ if (xmit_out.pub.version != 0x02)
+ TEST_ERROR;
+ if (xmit_out.pub.session_token != 0x03040506)
+ TEST_ERROR;
+ if (xmit_out.pub.xmit_count != 0x0708090A)
+ TEST_ERROR;
+ if (xmit_out.pub.op != 0x0B)
+ TEST_ERROR;
+ if (xmit_out.type != 0x0C)
+ TEST_ERROR;
+ if (xmit_out.offset != 0x0D0E0F1011121314)
+ TEST_ERROR;
+ if (xmit_out.size != 0x15161718191A1B1C)
+ TEST_ERROR;
+
+ PASSED();
+ return 0;
+
+error:
+ return -1;
+}
+
+/* ---------------------------------------------------------------------------
+ * Function: create_mirroring_split_fapl
+ *
+ * Purpose: Create and populate a mirroring FAPL ID.
+ * Creates target files with the given base name -- ideally the
+ * test name -- and creates mirroring/split FAPL set to use the
+ * global mirroring info and a sec2 R/W channel driver.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: HID of the top-level (splitter) FAPL, a non-negative
+ * value.
+ * Failure: H5I_INVALID_HID, a negative value.
+ * ---------------------------------------------------------------------------
+ */
+static hid_t
+create_mirroring_split_fapl(const char *basename, struct mirrortest_filenames *names,
+ const struct mt_opts *opts)
+{
+ H5FD_splitter_vfd_config_t *splitter_config = NULL;
+ H5FD_mirror_fapl_t mirror_conf;
+ hid_t ret_value = H5I_INVALID_HID;
+
+ if (NULL == (splitter_config = HDmalloc(sizeof(H5FD_splitter_vfd_config_t))))
+ TEST_ERROR;
+
+ /* Initialize the fapls, too, so the library doesn't try to
+ * close non-existing IDs on errors
+ */
+ splitter_config->magic = H5FD_SPLITTER_MAGIC;
+ splitter_config->version = H5FD_CURR_SPLITTER_VFD_CONFIG_VERSION;
+ splitter_config->ignore_wo_errs = FALSE;
+ splitter_config->rw_fapl_id = H5I_INVALID_HID;
+ splitter_config->wo_fapl_id = H5I_INVALID_HID;
+
+ if (basename == NULL || *basename == '\0')
+ TEST_ERROR;
+
+ /* Create Splitter R/W channel driver (sec2) */
+ if ((splitter_config->rw_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
+ TEST_ERROR;
+ if (H5Pset_fapl_sec2(splitter_config->rw_fapl_id) < 0)
+ TEST_ERROR;
+
+ /* Create Splitter W/O channel driver (mirror) */
+ mirror_conf.magic = H5FD_MIRROR_FAPL_MAGIC;
+ mirror_conf.version = H5FD_MIRROR_CURR_FAPL_T_VERSION;
+ mirror_conf.handshake_port = opts->portno;
+ if (HDstrncpy(mirror_conf.remote_ip, opts->ip, H5FD_MIRROR_MAX_IP_LEN) == NULL)
+ TEST_ERROR;
+ if ((splitter_config->wo_fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
+ TEST_ERROR;
+ if (H5Pset_fapl_mirror(splitter_config->wo_fapl_id, &mirror_conf) < 0)
+ TEST_ERROR;
+
+ /* Build r/w, w/o, and log file paths */
+ if (build_paths(basename, splitter_config, names) < 0)
+ TEST_ERROR;
+
+ /* Set file paths for w/o and logfile */
+ if (HDstrncpy(splitter_config->wo_path, (const char *)names->wo, H5FD_SPLITTER_PATH_MAX) == NULL)
+ TEST_ERROR;
+ if (HDstrncpy(splitter_config->log_file_path, (const char *)names->log, H5FD_SPLITTER_PATH_MAX) == NULL)
+ TEST_ERROR;
+
+ /* Create Splitter FAPL */
+ if ((ret_value = H5Pcreate(H5P_FILE_ACCESS)) < 0)
+ TEST_ERROR;
+ if (H5Pset_fapl_splitter(ret_value, splitter_config) < 0)
+ TEST_ERROR;
+
+ /* Close FAPLs created for child channels */
+ if (H5Pclose(splitter_config->rw_fapl_id) < 0)
+ TEST_ERROR;
+ if (H5Pclose(splitter_config->wo_fapl_id) < 0)
+ TEST_ERROR;
+
+ HDfree(splitter_config);
+
+ return ret_value;
+
+error:
+ HDfree(splitter_config);
+ H5E_BEGIN_TRY
+ {
+ H5Pclose(splitter_config->wo_fapl_id);
+ H5Pclose(splitter_config->rw_fapl_id);
+ H5Pclose(ret_value);
+ }
+ H5E_END_TRY;
+
+ return H5I_INVALID_HID;
+} /* end create_mirroring_split_fapl() */
+
+/* ---------------------------------------------------------------------------
+ * Function: test_create_and_close
+ *
+ * Purpose: Test/demonstrate a do-nothing file open and close.
+ *
+ * Verifying file existence and contents is part of other tests.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_create_and_close(const struct mt_opts *opts)
+{
+ struct mirrortest_filenames *names = NULL;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5I_INVALID_HID;
+
+ TESTING("File creation and immediate close");
+
+ if (NULL == (names = HDmalloc(sizeof(struct mirrortest_filenames))))
+ TEST_ERROR;
+
+ /* Create FAPL for splitter[sec2|mirror] */
+ if ((fapl_id = create_mirroring_split_fapl("basic_create", names, opts)) < 0)
+ TEST_ERROR;
+
+ if ((file_id = H5Fcreate(names->rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
+ TEST_ERROR;
+
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+ if (H5Pclose(fapl_id) < 0)
+ TEST_ERROR;
+
+ HDfree(names);
+
+ PASSED();
+ return 0;
+
+error:
+ HDfree(names);
+ H5E_BEGIN_TRY
+ {
+ H5Fclose(file_id);
+ H5Pclose(fapl_id);
+ }
+ H5E_END_TRY;
+ return -1;
+} /* end test_create_and_close() */
+
+/* ----------------------------------------------------------------------------
+ * Function: create_datasets
+ *
+ * Purpose: Given a file ID and least and greateset dataset indices, create
+ * populated chunked datasets in the target file from min_dset to
+ * (and including) max_dset.
+ * Uses #defined constants to determine chunk and dataset sizes
+ * and values.
+ *
+ * Return: SUCCEED/FAIL
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+create_datasets(hid_t file_id, unsigned min_dset, unsigned max_dset)
+{
+ hid_t dataspace_ids[MAX_DSET_COUNT + 1];
+ hid_t dataset_ids[MAX_DSET_COUNT + 1];
+ hid_t filespace_ids[MAX_DSET_COUNT + 1];
+ int data_chunk[CHUNK_DIM][CHUNK_DIM];
+ unsigned int i, j, k, l, m;
+ hsize_t offset[2];
+ hid_t memspace_id = H5I_INVALID_HID;
+ hsize_t a_size[2] = {CHUNK_DIM, CHUNK_DIM};
+ hsize_t chunk_dims[2] = {CHUNK_DIM, CHUNK_DIM};
+ hsize_t dset_dims[2] = {DSET_DIM, DSET_DIM};
+
+ HDassert(file_id >= 0);
+ HDassert(min_dset <= max_dset);
+ HDassert(max_dset <= MAX_DSET_COUNT);
+
+ LOGPRINT(2, "create_dataset()\n");
+
+ /* Initialize ID arrays */
+ for (i = 0; i < MAX_DSET_COUNT; i++) {
+ LOGPRINT(3, "clearing IDs [%d]\n", i);
+ dataspace_ids[i] = H5I_INVALID_HID;
+ dataset_ids[i] = H5I_INVALID_HID;
+ filespace_ids[i] = H5I_INVALID_HID;
+ }
+
+ /* Generate dataspace, dataset, and 'filespace' IDs */
+ if (_create_chunking_ids(file_id, min_dset, max_dset, chunk_dims, dset_dims, dataspace_ids, filespace_ids,
+ dataset_ids, &memspace_id) < 0)
+ TEST_ERROR;
+
+ /* Initialize (write) all datasets in a "round robin"...
+ * for a given chunk 'location', write chunk data to each dataset.
+ */
+ for (i = 0; i < DSET_DIM; i += CHUNK_DIM) {
+ LOGPRINT(3, "i: %d\n", i);
+ for (j = 0; j < DSET_DIM; j += CHUNK_DIM) {
+ LOGPRINT(3, " j: %d\n", j);
+ for (m = min_dset; m <= max_dset; m++) {
+ LOGPRINT(3, " m: %d\n", m);
+ for (k = 0; k < CHUNK_DIM; k++) {
+ for (l = 0; l < CHUNK_DIM; l++) {
+ data_chunk[k][l] = (int)((DSET_DIM * DSET_DIM * m) + (DSET_DIM * (i + k)) + j + l);
+ LOGPRINT(3, " data_chunk[%d][%d]: %d\n", k, l, data_chunk[k][l]);
+ }
+ }
+
+ /* Select on disk hyperslab */
+ offset[0] = (hsize_t)i;
+ offset[1] = (hsize_t)j;
+ LOGPRINT(3, " H5Sselect_hyperslab()\n");
+ if (H5Sselect_hyperslab(filespace_ids[m], H5S_SELECT_SET, offset, NULL, a_size, NULL) < 0)
+ TEST_ERROR;
+
+ LOGPRINT(3, " H5Dwrite()\n");
+ if (H5Dwrite(dataset_ids[m], H5T_NATIVE_INT, memspace_id, filespace_ids[m], H5P_DEFAULT,
+ data_chunk) < 0)
+ TEST_ERROR;
+ }
+ }
+ }
+
+ /* Read and verify data from datasets */
+ if (_verify_datasets(min_dset, max_dset, filespace_ids, dataset_ids, memspace_id) < 0)
+ TEST_ERROR;
+
+ /* Cleanup */
+ if (_close_chunking_ids(min_dset, max_dset, dataspace_ids, filespace_ids, dataset_ids, &memspace_id) < 0)
+ TEST_ERROR;
+
+ return SUCCEED;
+
+error:
+ (void)_close_chunking_ids(min_dset, max_dset, dataspace_ids, filespace_ids, dataset_ids, &memspace_id);
+ LOGPRINT(1, "create_datasets() FAILED\n");
+ return FAIL;
+} /* end create_datasets() */
+
+/* ----------------------------------------------------------------------------
+ * Function: _create_chunking_ids
+ *
+ * Purpose: Create new IDs to be used with the associated file.
+ *
+ * Return: SUCCEED/FAIL
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+_create_chunking_ids(hid_t file_id, unsigned min_dset, unsigned max_dset, hsize_t *chunk_dims,
+ hsize_t *dset_dims, hid_t *dataspace_ids, hid_t *filespace_ids, hid_t *dataset_ids,
+ hid_t *memspace_id)
+{
+ char dset_name[DSET_NAME_LEN + 1];
+ hid_t dcpl_id = H5I_INVALID_HID;
+
+ LOGPRINT(2, "_create_chunking_ids()\n");
+
+ /* Create chunking DCPL */
+ if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0)
+ TEST_ERROR;
+ if (H5Pset_chunk(dcpl_id, 2, chunk_dims) < 0)
+ TEST_ERROR;
+
+ /* Create dataspace IDs */
+ for (unsigned m = min_dset; m <= max_dset; m++) {
+ if ((dataspace_ids[m] = H5Screate_simple(2, dset_dims, NULL)) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to create dataspace ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* Create dataset IDs */
+ for (unsigned m = min_dset; m <= max_dset; m++) {
+ if (HDsnprintf(dset_name, DSET_NAME_LEN, "/dset%03d", m) > DSET_NAME_LEN) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to compose dset name %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+
+ if ((dataset_ids[m] = H5Dcreate2(file_id, dset_name, H5T_STD_I32BE, dataspace_ids[m], H5P_DEFAULT,
+ dcpl_id, H5P_DEFAULT)) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to create dset ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* Get file space IDs */
+ for (unsigned m = min_dset; m <= max_dset; m++) {
+ if ((filespace_ids[m] = H5Dget_space(dataset_ids[m])) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to create filespace ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* Create mem space to be used to read and write chunks */
+ if ((*memspace_id = H5Screate_simple(2, chunk_dims, NULL)) < 0)
+ TEST_ERROR;
+
+ /* Clean up the DCPL */
+ if (H5Pclose(dcpl_id) < 0)
+ TEST_ERROR;
+
+ return SUCCEED;
+
+error:
+ H5E_BEGIN_TRY
+ {
+ /* Note that it's the caller's responsibility to clean up any IDs
+ * passed back via out parameters
+ */
+ H5Pclose(dcpl_id);
+ }
+ H5E_END_TRY;
+
+ LOGPRINT(1, "_create_chunking_ids() FAILED\n");
+
+ return FAIL;
+} /* end _create_chunking_ids() */
+
+/* ----------------------------------------------------------------------------
+ * Function: _open_chunking_ids
+ *
+ * Purpose: Open/access IDs from the given file.
+ *
+ * Return: SUCCEED/FAIL
+ * ----------------------------------------------------------------------------
+ */
+static herr_t
+_open_chunking_ids(hid_t file_id, unsigned min_dset, unsigned max_dset, hsize_t *chunk_dims,
+ hid_t *filespace_ids, hid_t *dataset_ids, hid_t *memspace_id)
+{
+ char dset_name[DSET_NAME_LEN + 1];
+
+ LOGPRINT(2, "_open_chunking_ids()\n");
+
+ /* Open dataset IDs */
+ for (unsigned m = min_dset; m <= max_dset; m++) {
+ if (HDsnprintf(dset_name, DSET_NAME_LEN, "/dset%03d", m) > DSET_NAME_LEN) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to compose dset name %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+
+ if ((dataset_ids[m] = H5Dopen2(file_id, dset_name, H5P_DEFAULT)) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to open dset ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* Open filespace IDs */
+ for (unsigned m = min_dset; m <= max_dset; m++) {
+ if ((filespace_ids[m] = H5Dget_space(dataset_ids[m])) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to get filespace ID %d\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ /* Create mem space to be used to read and write chunks */
+ if ((*memspace_id = H5Screate_simple(2, chunk_dims, NULL)) < 0)
+ TEST_ERROR;
+
+ return SUCCEED;
+
+error:
+ /* Note that the caller is responsible for cleaning up IDs returned
+ * as out parameters
+ */
+ LOGPRINT(1, "_open_chunking_ids() FAILED\n");
+ return FAIL;
+} /* end _open_chunking_ids() */
+
+/* ---------------------------------------------------------------------------
+ * Function: _close_chunking_ids
+ *
+ * Purpose: Close IDs that were created or opened.
+ * Pass NULL into `dataspace_ids` when closing items opened with
+ * _open_chunking_ids(). (as opposed to created IDs)
+ *
+ * Return: SUCCEED/FAIL
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+_close_chunking_ids(unsigned min_dset, unsigned max_dset, hid_t *dataspace_ids, hid_t *filespace_ids,
+ hid_t *dataset_ids, hid_t *memspace_id)
+{
+ LOGPRINT(2, "_close_chunking_ids()\n");
+
+ for (unsigned m = min_dset; m <= max_dset; m++) {
+ LOGPRINT(3, "closing ids[%d]\n", m);
+ if (dataspace_ids) {
+ if (H5Sclose(dataspace_ids[m]) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to close dataspace_id[%d]\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+ if (H5Dclose(dataset_ids[m]) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to close dataset_id[%d]\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ if (H5Sclose(filespace_ids[m]) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, "unable to close filespace_id[%d]\n", m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+
+ if (*memspace_id != H5I_INVALID_HID)
+ if (H5Sclose(*memspace_id) < 0)
+ TEST_ERROR;
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "_close_chunking_ids() FAILED\n");
+ return FAIL;
+} /* end _close_chunking_ids() */
+
+/* ---------------------------------------------------------------------------
+ * Function: _verify_datasets
+ *
+ * Purpose: Check that each chunk's contents are as expected, as pertaining
+ * to create_datasets().
+ *
+ * Return: SUCCEED/FAIL
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+_verify_datasets(unsigned min_dset, unsigned max_dset, hid_t *filespace_ids, hid_t *dataset_ids,
+ hid_t memspace_id)
+{
+ unsigned i, j, k, l, m;
+ int data_chunk[CHUNK_DIM][CHUNK_DIM];
+ hsize_t offset[2];
+ hsize_t a_size[2] = {CHUNK_DIM, CHUNK_DIM};
+
+ LOGPRINT(2, "_verify_datasets()\n");
+
+ for (i = 0; i < DSET_DIM; i += CHUNK_DIM) {
+ LOGPRINT(3, "i: %d\n", i);
+ for (j = 0; j < DSET_DIM; j += CHUNK_DIM) {
+ LOGPRINT(3, " j: %d\n", j);
+ for (m = min_dset; m <= max_dset; m++) {
+ LOGPRINT(3, " m: %d\n", m);
+
+ /* select on disk hyperslab */
+ offset[0] = (hsize_t)i;
+ offset[1] = (hsize_t)j;
+ if (H5Sselect_hyperslab(filespace_ids[m], H5S_SELECT_SET, offset, NULL, a_size, NULL) < 0)
+ TEST_ERROR;
+
+ if (H5Dread(dataset_ids[m], H5T_NATIVE_INT, memspace_id, filespace_ids[m], H5P_DEFAULT,
+ data_chunk) < 0) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, " H5Dread() [%d][%d][%d]\n", i, j, m);
+ FAIL_PUTS_ERROR(mesg);
+ }
+
+ for (k = 0; k < CHUNK_DIM; k++) {
+ for (l = 0; l < CHUNK_DIM; l++) {
+ if ((unsigned)data_chunk[k][l] !=
+ ((DSET_DIM * DSET_DIM * m) + (DSET_DIM * (i + k)) + j + l)) {
+ HDsnprintf(mesg, MIRR_MESG_SIZE, " MISMATCH [%d][%d][%d][%d][%d]\n", i, j, m,
+ k, l);
+ FAIL_PUTS_ERROR(mesg);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "_verify_datasets() FAILED\n");
+ return FAIL;
+} /* end _verify_datasets() */
+
+/* ---------------------------------------------------------------------------
+ * Function: verify_datasets
+ *
+ * Purpose: Inspect the datasets in the file created by create_datasets().
+ * Wrapper for _verify_datasets() -- this function sets up and
+ * tears down accessor information.
+ *
+ * Return: SUCCEED/FAIL
+ * ---------------------------------------------------------------------------
+ */
+static herr_t
+verify_datasets(hid_t file_id, unsigned min_dset, unsigned max_dset)
+{
+ hid_t dataset_ids[MAX_DSET_COUNT + 1];
+ hid_t filespace_ids[MAX_DSET_COUNT + 1];
+ hid_t memspace_id = H5I_INVALID_HID;
+ hsize_t chunk_dims[2] = {CHUNK_DIM, CHUNK_DIM};
+
+ HDassert(file_id >= 0);
+ HDassert(min_dset <= max_dset);
+ HDassert(max_dset <= MAX_DSET_COUNT);
+
+ LOGPRINT(2, "verify_datasets()\n");
+
+ /* Initialize ID arrays */
+ for (unsigned i = 0; i < MAX_DSET_COUNT; i++) {
+ LOGPRINT(3, "clearing IDs [%d]\n", i);
+ dataset_ids[i] = H5I_INVALID_HID;
+ filespace_ids[i] = H5I_INVALID_HID;
+ }
+
+ /* Generate dataspace, dataset, and 'filespace' IDs */
+ if (_open_chunking_ids(file_id, min_dset, max_dset, chunk_dims, filespace_ids, dataset_ids,
+ &memspace_id) < 0)
+ TEST_ERROR;
+
+ /* Read and verify data from datasets */
+ if (_verify_datasets(min_dset, max_dset, filespace_ids, dataset_ids, memspace_id) < 0)
+ TEST_ERROR;
+
+ /* Cleanup */
+ if (_close_chunking_ids(min_dset, max_dset, NULL, filespace_ids, dataset_ids, &memspace_id) < 0)
+ TEST_ERROR;
+
+ return SUCCEED;
+
+error:
+ LOGPRINT(1, "verify_datasets() FAILED\n");
+ (void)_close_chunking_ids(min_dset, max_dset, NULL, filespace_ids, dataset_ids, &memspace_id);
+ return FAIL;
+
+} /* end verify_datasets() */
+
+/* ---------------------------------------------------------------------------
+ * Function: test_basic_dataset_write
+ *
+ * Purpose: Create and close files; repoen files and write a dataset,
+ * close; compare files.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_basic_dataset_write(const struct mt_opts *opts)
+{
+ struct mirrortest_filenames *names = NULL;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5I_INVALID_HID;
+ hid_t dset_id = H5I_INVALID_HID;
+ hid_t dspace_id = H5I_INVALID_HID;
+ hid_t dtype_id = H5T_NATIVE_INT;
+ hsize_t dims[2] = {DATABUFFER_SIZE, DATABUFFER_SIZE};
+ int *buf = NULL;
+ int i = 0;
+ int j = 0;
+
+ TESTING("Mirror open and dataset writing");
+
+ if (NULL == (names = HDmalloc(sizeof(struct mirrortest_filenames))))
+ TEST_ERROR;
+
+ /* Create FAPL for Splitter[sec2|mirror] */
+ if ((fapl_id = create_mirroring_split_fapl("basic_write", names, opts)) < 0)
+ TEST_ERROR;
+
+ /* Prepare data to be written */
+ if (NULL == (buf = HDmalloc(DATABUFFER_SIZE * DATABUFFER_SIZE * sizeof(int))))
+ TEST_ERROR;
+ for (i = 0; i < DATABUFFER_SIZE; i++) {
+ for (j = 0; j < DATABUFFER_SIZE; j++) {
+ int k = i * DATABUFFER_SIZE + j;
+ buf[k] = k;
+ }
+ }
+
+ /* -------------------- */
+ /* TEST: Create and Close */
+
+ if ((file_id = H5Fcreate(names->rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
+ TEST_ERROR;
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Repoen and Write */
+
+ if ((file_id = H5Fopen(names->rw, H5F_ACC_RDWR, fapl_id)) < 0)
+ TEST_ERROR;
+
+ if ((dspace_id = H5Screate_simple(2, dims, NULL)) < 0)
+ TEST_ERROR;
+ if ((dset_id =
+ H5Dcreate2(file_id, "dataset", dtype_id, dspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
+ TEST_ERROR;
+
+ if (H5Dwrite(dset_id, dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
+ TEST_ERROR;
+
+ /* Cleanup */
+
+ if (H5Dclose(dset_id) < 0)
+ TEST_ERROR;
+ if (H5Sclose(dspace_id) < 0)
+ TEST_ERROR;
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+ if (H5Pclose(fapl_id) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ if (h5_compare_file_bytes(names->rw, names->wo) < 0)
+ TEST_ERROR;
+
+ HDfree(buf);
+ HDfree(names);
+
+ PASSED();
+ return 0;
+
+error:
+ HDfree(buf);
+ HDfree(names);
+
+ H5E_BEGIN_TRY
+ {
+ H5Fclose(file_id);
+ H5Dclose(dset_id);
+ H5Sclose(dspace_id);
+ H5Pclose(fapl_id);
+ }
+ H5E_END_TRY;
+ return -1;
+} /* end test_basic_dataset_write() */
+
+/* ---------------------------------------------------------------------------
+ * Function: test_chunked_dataset_write
+ *
+ * Purpose: Create and close files; repoen files and write a dataset,
+ * close; compare files.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_chunked_dataset_write(const struct mt_opts *opts)
+{
+ struct mirrortest_filenames *names = NULL;
+
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5P_DEFAULT;
+
+ TESTING("Mirror open and dataset writing (chunked)");
+
+ if (NULL == (names = HDmalloc(sizeof(struct mirrortest_filenames))))
+ TEST_ERROR;
+
+ /* Create FAPL for Splitter[sec2|mirror] */
+ if ((fapl_id = create_mirroring_split_fapl("chunked_write", names, opts)) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Create and Close */
+
+ if ((file_id = H5Fcreate(names->rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
+ TEST_ERROR;
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Reopen and Write */
+
+ if ((file_id = H5Fopen(names->rw, H5F_ACC_RDWR, fapl_id)) < 0)
+ TEST_ERROR;
+
+ /* Write datasets to file */
+ if (create_datasets(file_id, 0, MAX_DSET_COUNT) < 0)
+ TEST_ERROR;
+
+ /* Close to 'flush to disk', and reopen file */
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+
+ /* Reopen file */
+ if ((file_id = H5Fopen(names->rw, H5F_ACC_RDWR, fapl_id)) < 0)
+ TEST_ERROR;
+
+ /* Verify written data integrity */
+ if (verify_datasets(file_id, 0, MAX_DSET_COUNT) < 0)
+ TEST_ERROR;
+
+ /* Cleanup */
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+ if (H5Pclose(fapl_id) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ if (h5_compare_file_bytes(names->rw, names->wo) < 0) {
+ TEST_ERROR;
+ }
+
+ HDfree(names);
+
+ PASSED();
+ return 0;
+
+error:
+ HDfree(names);
+ H5E_BEGIN_TRY
+ {
+ H5Fclose(file_id);
+ H5Pclose(fapl_id);
+ }
+ H5E_END_TRY;
+ return -1;
+} /* end test_chunked_dataset_write() */
+
+/* ---------------------------------------------------------------------------
+ * Function: test_on_disk_zoo
+ *
+ * Purpose: Verify that the mirror can handle the passing of all the
+ * various on-disk data structures over the wire, as implemented
+ * in genall5.c:create_zoo().
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_on_disk_zoo(const struct mt_opts *opts)
+{
+ const char grp_name[] = "/only";
+ struct mirrortest_filenames *names = NULL;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t grp_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5I_INVALID_HID;
+
+ TESTING("'Zoo' of on-disk structures");
+
+ if (NULL == (names = HDmalloc(sizeof(struct mirrortest_filenames))))
+ TEST_ERROR;
+
+ /* Create FAPL for Splitter[sec2|mirror] */
+ if ((fapl_id = create_mirroring_split_fapl("zoo", names, opts)) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Create file */
+ if ((file_id = H5Fcreate(names->rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
+ TEST_ERROR;
+
+ if ((grp_id = H5Gcreate2(file_id, grp_name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
+ TEST_ERROR;
+
+ /* Create datasets in file, close (flush) and reopen, validate.
+ * Use of ( pass ) a conceit required for using create_ and validate_zoo()
+ * from cache_common and/or genall5.
+ */
+
+ if (pass)
+ create_zoo(file_id, grp_name, 0);
+ if (pass) {
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+ if ((file_id = H5Fopen(names->rw, H5F_ACC_RDWR, fapl_id)) < 0)
+ TEST_ERROR;
+ }
+ if (pass)
+ validate_zoo(file_id, grp_name, 0); /* sanity-check */
+
+ if (!pass) {
+ HDprintf("%s", failure_mssg);
+ TEST_ERROR;
+ }
+
+ /* Cleanup */
+
+ if (H5Pclose(fapl_id) < 0)
+ TEST_ERROR;
+ if (H5Gclose(grp_id) < 0)
+ TEST_ERROR;
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ if (h5_compare_file_bytes(names->rw, names->wo) < 0)
+ TEST_ERROR;
+
+ HDfree(names);
+
+ PASSED();
+ return 0;
+
+error:
+ HDfree(names);
+ H5E_BEGIN_TRY
+ {
+ H5Fclose(file_id);
+ H5Gclose(grp_id);
+ H5Pclose(fapl_id);
+ }
+ H5E_END_TRY;
+ return -1;
+} /* end test_on_disk_zoo() */
+
+/* ---------------------------------------------------------------------------
+ * Function: test_vanishing_datasets
+ *
+ * Purpose: Verify behavior when writing to a file where data is deleted.
+ *
+ * Each dataset is populated with the value of its suffix
+ * (dset5 is all fives).
+ *
+ * Opens 0..15 create one new dataset each, '/dset[i]'.
+ * Opens 3..18 delete '/dset[1-3]'
+ *
+ * Should end with no data in file.
+ *
+ * Return: Success: 0
+ * Failure: -1
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_vanishing_datasets(const struct mt_opts *opts)
+{
+ struct mirrortest_filenames *names = NULL;
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t fapl_id = H5I_INVALID_HID;
+ hid_t dset_id = H5I_INVALID_HID;
+ hid_t dspace_id = H5I_INVALID_HID;
+ hsize_t dims[2] = {DATABUFFER_SIZE, DATABUFFER_SIZE};
+ H5G_info_t group_info;
+ unsigned int i, j, k;
+ const unsigned int max_loops = 20;
+ const unsigned int max_at_one_time = 3;
+ struct {
+ uint32_t arr[DATABUFFER_SIZE][DATABUFFER_SIZE];
+ } *buf = NULL;
+
+ TESTING("Vanishing Datasets");
+
+ if (NULL == (names = HDmalloc(sizeof(struct mirrortest_filenames))))
+ TEST_ERROR;
+ if (NULL == (buf = HDcalloc(1, sizeof(*buf))))
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* Set up recurrent data (FAPL, dataspace) */
+
+ /* Create FAPL for Splitter[sec2|mirror] */
+ if ((fapl_id = create_mirroring_split_fapl("vanishing", names, opts)) < 0)
+ TEST_ERROR;
+
+ if ((dspace_id = H5Screate_simple(2, dims, NULL)) < 0)
+ TEST_ERROR;
+
+ /* Create file */
+ if ((file_id = H5Fcreate(names->rw, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
+ TEST_ERROR;
+
+ for (i = 0; i < max_loops; i++) {
+ char namebuf[DSET_NAME_LEN + 1];
+
+ /* Delete datasets */
+ if (i >= max_at_one_time) {
+ if (HDsnprintf(namebuf, DSET_NAME_LEN, "/dset%02d", (i - max_at_one_time)) > DSET_NAME_LEN)
+ TEST_ERROR;
+ if (H5Ldelete(file_id, namebuf, H5P_DEFAULT) < 0)
+ TEST_ERROR;
+ }
+
+ /* Write to datasets */
+ if (i < (max_loops - max_at_one_time)) {
+ if (HDsnprintf(namebuf, DSET_NAME_LEN, "/dset%02d", i) > DSET_NAME_LEN)
+ TEST_ERROR;
+ if ((dset_id = H5Dcreate2(file_id, namebuf, H5T_STD_U32LE, dspace_id, H5P_DEFAULT, H5P_DEFAULT,
+ H5P_DEFAULT)) < 0)
+ TEST_ERROR;
+
+ for (j = 0; j < DATABUFFER_SIZE; j++)
+ for (k = 0; k < DATABUFFER_SIZE; k++)
+ buf->arr[j][k] = (uint32_t)i;
+
+ if (H5Dwrite(dset_id, H5T_STD_U32LE, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
+ TEST_ERROR;
+
+ if (H5Dclose(dset_id) < 0)
+ TEST_ERROR;
+ }
+
+ } /* end for dataset create-destroy cycles */
+
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+
+ /* verify there are no datasets in file */
+ if ((file_id = H5Fopen(names->rw, H5F_ACC_RDONLY, fapl_id)) < 0)
+ TEST_ERROR;
+ if (H5Gget_info(file_id, &group_info) < 0)
+ TEST_ERROR;
+ if (group_info.nlinks > 0) {
+ HDfprintf(stderr, "links in rw file: %" PRIuHSIZE "\n", group_info.nlinks);
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+ if ((file_id = H5Fopen(names->wo, H5F_ACC_RDONLY, fapl_id)) < 0)
+ TEST_ERROR;
+ if (H5Gget_info(file_id, &group_info) < 0)
+ TEST_ERROR;
+ if (group_info.nlinks > 0) {
+ HDfprintf(stderr, "links in wo file: %" PRIuHSIZE "\n", group_info.nlinks);
+ TEST_ERROR;
+ }
+ if (H5Fclose(file_id) < 0)
+ TEST_ERROR;
+
+ if (h5_compare_file_bytes(names->rw, names->wo) < 0)
+ TEST_ERROR;
+
+ /* Teardown */
+
+ if (H5Sclose(dspace_id) < 0)
+ TEST_ERROR;
+ if (H5Pclose(fapl_id) < 0)
+ TEST_ERROR;
+
+ HDfree(names);
+ HDfree(buf);
+
+ PASSED();
+ return 0;
+
+error:
+ HDfree(names);
+ HDfree(buf);
+ H5E_BEGIN_TRY
+ {
+ H5Pclose(fapl_id);
+ H5Fclose(file_id);
+ H5Dclose(dset_id);
+ H5Sclose(dspace_id);
+ }
+ H5E_END_TRY;
+ return -1;
+} /* test_vanishing_datasets() */
+
+/* ---------------------------------------------------------------------------
+ * Function: test_concurrent_access
+ *
+ * Purpose: Verify that more than one file may be opened at a time.
+ *
+ * TODO: receive target IP from caller?
+ *
+ * Return: Success: 0
+ * Failure: -1
+ * ---------------------------------------------------------------------------
+ */
+static int
+test_concurrent_access(const struct mt_opts *opts)
+{
+ struct file_bundle {
+ struct mirrortest_filenames names;
+ hid_t dset_id;
+ hid_t fapl_id;
+ hid_t file_id;
+ };
+
+ struct file_bundle *bundle = NULL;
+
+ hid_t dspace_id = H5I_INVALID_HID;
+ hid_t dtype_id = H5T_NATIVE_INT;
+ hsize_t dims[2] = {DATABUFFER_SIZE, DATABUFFER_SIZE};
+ int *buf = NULL;
+ int i = 0;
+ int j = 0;
+
+ TESTING("Concurrent opened mirrored files");
+
+ if (NULL == (bundle = HDmalloc(sizeof(struct file_bundle) * CONCURRENT_COUNT)))
+ TEST_ERROR;
+
+ /* Initialize bundle */
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ bundle[i].dset_id = H5I_INVALID_HID;
+ bundle[i].fapl_id = H5I_INVALID_HID;
+ bundle[i].file_id = H5I_INVALID_HID;
+ *bundle[i].names.rw = '\0';
+ *bundle[i].names.wo = '\0';
+ *bundle[i].names.log = '\0';
+ }
+
+ /* Create FAPL for Splitter[sec2|mirror] */
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ char name[16] = "";
+ hid_t fapl_id = H5I_INVALID_HID;
+
+ HDsnprintf(name, 15, "concurrent%d", i);
+ if ((fapl_id = create_mirroring_split_fapl(name, &bundle[i].names, opts)) < 0)
+ TEST_ERROR;
+ bundle[i].fapl_id = fapl_id;
+ }
+
+ /* Prepare data to be written */
+ if (NULL == (buf = HDmalloc(DATABUFFER_SIZE * DATABUFFER_SIZE * sizeof(int))))
+ TEST_ERROR;
+ for (i = 0; i < DATABUFFER_SIZE; i++) {
+ for (j = 0; j < DATABUFFER_SIZE; j++) {
+ int k = i * DATABUFFER_SIZE + j;
+ buf[k] = k;
+ }
+ }
+
+ /* Prepare generic dataspace */
+ if ((dspace_id = H5Screate_simple(2, dims, NULL)) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Create file and open elements */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ hid_t file_id = H5I_INVALID_HID;
+ hid_t dset_id = H5I_INVALID_HID;
+
+ if ((file_id = H5Fcreate(bundle[i].names.rw, H5F_ACC_TRUNC, H5P_DEFAULT, bundle[i].fapl_id)) < 0)
+ TEST_ERROR;
+
+ bundle[i].file_id = file_id;
+
+ if ((dset_id = H5Dcreate2(file_id, "dataset", dtype_id, dspace_id, H5P_DEFAULT, H5P_DEFAULT,
+ H5P_DEFAULT)) < 0)
+ TEST_ERROR;
+ bundle[i].dset_id = dset_id;
+ }
+
+ /* -------------------- */
+ /* TEST: Write to files */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++)
+ if (H5Dwrite(bundle[i].dset_id, dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Close elements */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ if (H5Dclose(bundle[i].dset_id) < 0)
+ TEST_ERROR;
+ if (H5Fclose(bundle[i].file_id) < 0)
+ TEST_ERROR;
+ if (H5Pclose(bundle[i].fapl_id) < 0)
+ TEST_ERROR;
+ }
+
+ if (H5Sclose(dspace_id) < 0)
+ TEST_ERROR;
+
+ /* -------------------- */
+ /* TEST: Verify that the R/W and W/O files are identical */
+
+ for (i = 0; i < CONCURRENT_COUNT; i++)
+ if (h5_compare_file_bytes(bundle[i].names.rw, bundle[i].names.wo) < 0)
+ TEST_ERROR;
+
+ HDfree(bundle);
+ HDfree(buf);
+
+ PASSED();
+ return 0;
+
+error:
+ H5E_BEGIN_TRY
+ {
+ H5Sclose(dspace_id);
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ H5Dclose(bundle[i].dset_id);
+ H5Fclose(bundle[i].file_id);
+ H5Pclose(bundle[i].fapl_id);
+ }
+ }
+ H5E_END_TRY;
+ HDfree(bundle);
+ HDfree(buf);
+ return -1;
+} /* end test_concurrent_access() */
+
+/* ----------------------------------------------------------------------------
+ * Function: parse_args
+ *
+ * Purpose: Parse command-line arguments, populating the options struct
+ * pointer as appropriate.
+ * Default values will be set for unspecified options.
+ *
+ * Return: 0 on success, negative (-1) if error.
+ * ----------------------------------------------------------------------------
+ */
+static int
+parse_args(int argc, char **argv, struct mt_opts *opts)
+{
+ int i = 0;
+
+ opts->portno = SERVER_HANDSHAKE_PORT;
+ HDstrncpy(opts->ip, SERVER_IP_ADDRESS, H5FD_MIRROR_MAX_IP_LEN);
+
+ for (i = 1; i < argc; i++) { /* start with first possible option argument */
+ if (!HDstrncmp(argv[i], "--ip=", 5))
+ HDstrncpy(opts->ip, argv[i] + 5, H5FD_MIRROR_MAX_IP_LEN);
+ else if (!HDstrncmp(argv[i], "--port=", 7))
+ opts->portno = HDatoi(argv[i] + 7);
+ else {
+ HDprintf("Unrecognized option: '%s'\n", argv[i]);
+ return -1;
+ }
+ } /* end for each argument from command line */
+
+ /* Auto-replace 'localhost' with numeric IP */
+ if (!HDstrncmp(opts->ip, "localhost", 10)) /* include NUL terminator */
+ HDstrncpy(opts->ip, "127.0.0.1", H5FD_MIRROR_MAX_IP_LEN);
+
+ return 0;
+} /* end parse_args() */
+
+/* ----------------------------------------------------------------------------
+ * Function: confirm_server
+ *
+ * Purpose: Create socket and confirm remote server is available.
+ *
+ * Return: 0 on success, negative (-1) if error.
+ * ----------------------------------------------------------------------------
+ */
+static int
+confirm_server(struct mt_opts *opts)
+{
+ char mybuf[16];
+ int live_socket;
+ struct sockaddr_in target_addr;
+ unsigned attempt = 0;
+
+ live_socket = HDsocket(AF_INET, SOCK_STREAM, 0);
+ if (live_socket < 0) {
+ HDprintf("ERROR socket()\n");
+ return -1;
+ }
+
+ target_addr.sin_family = AF_INET;
+ target_addr.sin_port = HDhtons((uint16_t)opts->portno);
+ target_addr.sin_addr.s_addr = HDinet_addr(opts->ip);
+ HDmemset(target_addr.sin_zero, '\0', sizeof(target_addr.sin_zero));
+
+ while (1) {
+ if (HDconnect(live_socket, (struct sockaddr *)&target_addr, (socklen_t)sizeof(target_addr)) < 0) {
+ if (attempt > 10) {
+ HDprintf("ERROR connect() (%d)\n%s\n", errno, HDstrerror(errno));
+ return -1;
+ }
+ attempt++;
+ HDsleep(1);
+ HDprintf("attempt #%u: ERROR connect() (%d)\n%s\n", attempt, errno, HDstrerror(errno));
+ }
+ else
+ break;
+ }
+
+ /* Request confirmation from the server */
+ if (HDwrite(live_socket, "CONFIRM", 8) == -1) {
+ HDprintf("ERROR write() (%d)\n%s\n", errno, HDstrerror(errno));
+ return -1;
+ }
+
+ /* Read & verify response from port connection. */
+ if (HDread(live_socket, &mybuf, sizeof(mybuf)) == -1) {
+ HDprintf("ERROR read() can't receive data\n");
+ return -1;
+ }
+ if (HDstrncmp("ALIVE", mybuf, 6)) {
+ HDprintf("ERROR read() didn't receive data from server\n");
+ return -1;
+ }
+
+ if (HDclose(live_socket) < 0) {
+ HDprintf("ERROR close() can't close socket\n");
+ return -1;
+ }
+
+ return 0;
+} /* end confirm_server() */
+
+/* ---------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: Run tests
+ *
+ * Return: Success: 0
+ * Failure: 1
+ * ---------------------------------------------------------------------------
+ */
+int
+main(int argc, char **argv)
+{
+ struct mt_opts opts;
+ int nerrors = 0;
+
+ h5_reset();
+
+ g_log_stream = stdout; /* default debug/logging output stream */
+
+ HDprintf("Testing Mirror VFD functionality.\n");
+
+ /* SETUP */
+
+ /* Create directories for test-generated .h5 files */
+ if (nerrors == 0) {
+ if ((HDmkdir(MIRROR_RW_DIR, (mode_t)0755) < 0) && (errno != EEXIST))
+ nerrors++;
+ }
+ if (nerrors == 0) {
+ if ((HDmkdir(MIRROR_WO_DIR, (mode_t)0755) < 0) && (errno != EEXIST))
+ nerrors++;
+ }
+
+ if (parse_args(argc, argv, &opts) < 0) {
+ HDprintf("Unable to parse arguments\n");
+ HDexit(EXIT_FAILURE);
+ }
+
+ if (confirm_server(&opts) < 0) {
+ HDprintf("Unable to confirm server is running\n");
+ HDexit(EXIT_FAILURE);
+ }
+
+ /* TESTS */
+
+ if (nerrors == 0) {
+ H5FD_mirror_xmit_t xmit_mock; /* Re-used header in various xmit tests */
+
+ /* Set bogus values matching expected; encoding doesn't care
+ * Use sequential values to easily generate the expected buffer with a
+ * for loop.
+ */
+ xmit_mock.magic = 0x00010203;
+ xmit_mock.version = 0x04;
+ xmit_mock.session_token = 0x05060708;
+ xmit_mock.xmit_count = 0x090A0B0C;
+ xmit_mock.op = 0x0D;
+
+ nerrors += test_fapl_configuration() < 0 ? 1 : 0;
+
+ nerrors += test_encdec_uint8_t() < 0 ? 1 : 0;
+ nerrors += test_encdec_uint16_t() < 0 ? 1 : 0;
+ nerrors += test_encdec_uint32_t() < 0 ? 1 : 0;
+ nerrors += test_encdec_uint64_t() < 0 ? 1 : 0;
+
+ nerrors += test_encdec_header(xmit_mock) < 0 ? 1 : 0;
+ nerrors += test_encdec_set_eoa(xmit_mock) < 0 ? 1 : 0;
+ nerrors += test_encdec_lock(xmit_mock) < 0 ? 1 : 0;
+ nerrors += test_encdec_open(xmit_mock) < 0 ? 1 : 0;
+ nerrors += test_encdec_reply(xmit_mock) < 0 ? 1 : 0;
+ nerrors += test_encdec_write(xmit_mock) < 0 ? 1 : 0;
+
+ nerrors += test_create_and_close(&opts) < 0 ? 1 : 0;
+ nerrors += test_basic_dataset_write(&opts) < 0 ? 1 : 0;
+ nerrors += test_chunked_dataset_write(&opts) < 0 ? 1 : 0;
+ nerrors += test_on_disk_zoo(&opts) < 0 ? 1 : 0;
+ nerrors += test_vanishing_datasets(&opts) < 0 ? 1 : 0;
+ nerrors += test_concurrent_access(&opts) < 0 ? 1 : 0;
+ }
+
+ if (nerrors) {
+ HDprintf("***** %d Mirror VFD TEST%s FAILED! *****\n", nerrors, nerrors > 1 ? "S" : "");
+ return EXIT_FAILURE;
+ }
+
+ HDprintf("All Mirror Virtual File Driver tests passed.\n");
+ return EXIT_SUCCESS;
+} /* end main() */
+
+#else /* H5_HAVE_MIRROR_VFD */
+
+int
+main(void)
+{
+ HDprintf("Testing Mirror VFD functionality.\n");
+ HDprintf("SKIPPED - Mirror VFD not built.\n");
+ return EXIT_SUCCESS;
+}
+
+#endif /* H5_HAVE_MIRROR_VFD */