summaryrefslogtreecommitdiffstats
path: root/test/vol.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/vol.c')
-rw-r--r--test/vol.c926
1 files changed, 924 insertions, 2 deletions
diff --git a/test/vol.c b/test/vol.c
index d975243..c7586d5 100644
--- a/test/vol.c
+++ b/test/vol.c
@@ -20,6 +20,12 @@
/* Headers needed */
#include "h5test.h"
+#include "H5Iprivate.h" /* IDs */
+#define H5T_FRIEND /* Suppress error about including H5Tpkg */
+#include "H5Tpkg.h" /* Datatypes */
+#define H5VL_FRIEND /* Suppress error about including H5VLpkg */
+#define H5VL_TESTING
+#include "H5VLpkg.h" /* Virtual Object Layer */
/* Filename */
const char *FILENAME[] = {"native_vol_test", NULL};
@@ -35,6 +41,136 @@ const char *FILENAME[] = {"native_vol_test", NULL};
#define N_ELEMENTS 10
+/* A VOL class struct to verify registering optional operations */
+static int reg_opt_curr_op_val;
+static herr_t reg_opt_op_optional(void *obj, H5VL_optional_args_t *args, hid_t dxpl_id, void **req);
+static herr_t reg_opt_link_optional(void *obj, const H5VL_loc_params_t *loc_params,
+ H5VL_optional_args_t *args, hid_t dxpl_id, void **req);
+static herr_t reg_opt_datatype_get(void *obj, H5VL_datatype_get_args_t *args, hid_t dxpl_id, void **req);
+#define REG_OPT_VOL_NAME "reg_opt"
+#define REG_OPT_VOL_VALUE ((H5VL_class_value_t)502)
+static const H5VL_class_t reg_opt_vol_g = {
+ H5VL_VERSION, /* VOL class struct version */
+ REG_OPT_VOL_VALUE, /* value */
+ REG_OPT_VOL_NAME, /* name */
+ 0, /* version */
+ 0, /* capability flags */
+ NULL, /* initialize */
+ NULL, /* terminate */
+ {
+ /* info_cls */
+ (size_t)0, /* size */
+ NULL, /* copy */
+ NULL, /* compare */
+ NULL, /* free */
+ NULL, /* to_str */
+ NULL, /* from_str */
+ },
+ {
+ /* wrap_cls */
+ NULL, /* get_object */
+ NULL, /* get_wrap_ctx */
+ NULL, /* wrap_object */
+ NULL, /* unwrap_object */
+ NULL, /* free_wrap_ctx */
+ },
+ {
+ /* attribute_cls */
+ NULL, /* create */
+ NULL, /* open */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* get */
+ NULL, /* specific */
+ reg_opt_op_optional, /* optional */
+ NULL /* close */
+ },
+ {
+ /* dataset_cls */
+ NULL, /* create */
+ NULL, /* open */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* get */
+ NULL, /* specific */
+ reg_opt_op_optional, /* optional */
+ NULL /* close */
+ },
+ {
+ /* datatype_cls */
+ NULL, /* commit */
+ NULL, /* open */
+ reg_opt_datatype_get, /* get */
+ NULL, /* specific */
+ reg_opt_op_optional, /* optional */
+ NULL /* close */
+ },
+ {
+ /* file_cls */
+ NULL, /* create */
+ NULL, /* open */
+ NULL, /* get */
+ NULL, /* specific */
+ reg_opt_op_optional, /* optional */
+ NULL /* close */
+ },
+ {
+ /* group_cls */
+ NULL, /* create */
+ NULL, /* open */
+ NULL, /* get */
+ NULL, /* specific */
+ reg_opt_op_optional, /* optional */
+ NULL /* close */
+ },
+ {
+ /* link_cls */
+ NULL, /* create */
+ NULL, /* copy */
+ NULL, /* move */
+ NULL, /* get */
+ NULL, /* specific */
+ reg_opt_link_optional /* optional */
+ },
+ {
+ /* object_cls */
+ NULL, /* open */
+ NULL, /* copy */
+ NULL, /* get */
+ NULL, /* specific */
+ reg_opt_link_optional /* optional */
+ },
+ {
+ /* introspect_cls */
+ NULL, /* get_conn_cls */
+ NULL, /* get_cap_flags */
+ NULL, /* opt_query */
+ },
+ {
+ /* request_cls */
+ NULL, /* wait */
+ NULL, /* notify */
+ NULL, /* cancel */
+ NULL, /* specific */
+ NULL, /* optional */
+ NULL /* free */
+ },
+ {
+ /* blob_cls */
+ NULL, /* put */
+ NULL, /* get */
+ NULL, /* specific */
+ NULL /* optional */
+ },
+ {
+ /* token_cls */
+ NULL, /* cmp */
+ NULL, /* to_str */
+ NULL /* from_str */
+ },
+ NULL /* optional */
+};
+
#define FAKE_VOL_NAME "fake"
#define FAKE_VOL_VALUE ((H5VL_class_value_t)501)
@@ -90,6 +226,136 @@ static const H5VL_class_t fake_vol_g = {
},
{
/* datatype_cls */
+ NULL, /* commit */
+ NULL, /* open */
+ reg_opt_datatype_get, /* get */
+ NULL, /* specific */
+ NULL, /* optional */
+ NULL /* close */
+ },
+ {
+ /* file_cls */
+ NULL, /* create */
+ NULL, /* open */
+ NULL, /* get */
+ NULL, /* specific */
+ NULL, /* optional */
+ NULL /* close */
+ },
+ {
+ /* group_cls */
+ NULL, /* create */
+ NULL, /* open */
+ NULL, /* get */
+ NULL, /* specific */
+ NULL, /* optional */
+ NULL /* close */
+ },
+ {
+ /* link_cls */
+ NULL, /* create */
+ NULL, /* copy */
+ NULL, /* move */
+ NULL, /* get */
+ NULL, /* specific */
+ NULL /* optional */
+ },
+ {
+ /* object_cls */
+ NULL, /* open */
+ NULL, /* copy */
+ NULL, /* get */
+ NULL, /* specific */
+ NULL /* optional */
+ },
+ {
+ /* introspect_cls */
+ NULL, /* get_conn_cls */
+ NULL, /* get_cap_flags */
+ NULL, /* opt_query */
+ },
+ {
+ /* request_cls */
+ NULL, /* wait */
+ NULL, /* notify */
+ NULL, /* cancel */
+ NULL, /* specific */
+ NULL, /* optional */
+ NULL /* free */
+ },
+ {
+ /* blob_cls */
+ NULL, /* put */
+ NULL, /* get */
+ NULL, /* specific */
+ NULL /* optional */
+ },
+ {
+ /* token_cls */
+ NULL, /* cmp */
+ NULL, /* to_str */
+ NULL /* from_str */
+ },
+ NULL /* optional */
+};
+
+static herr_t fake_async_get_cap_flags(const void *info, unsigned *cap_flags);
+
+#define FAKE_ASYNC_VOL_NAME "fake_async"
+#define FAKE_ASYNC_VOL_VALUE ((H5VL_class_value_t)503)
+
+/* A VOL class struct that describes a VOL class with no
+ * functionality except to set the async capability flag.
+ */
+static const H5VL_class_t fake_async_vol_g = {
+ H5VL_VERSION, /* VOL class struct version */
+ FAKE_ASYNC_VOL_VALUE, /* value */
+ FAKE_ASYNC_VOL_NAME, /* name */
+ 0, /* connector version */
+ H5VL_CAP_FLAG_ASYNC, /* capability flags */
+ NULL, /* initialize */
+ NULL, /* terminate */
+ {
+ /* info_cls */
+ (size_t)0, /* size */
+ NULL, /* copy */
+ NULL, /* compare */
+ NULL, /* free */
+ NULL, /* to_str */
+ NULL, /* from_str */
+ },
+ {
+ /* wrap_cls */
+ NULL, /* get_object */
+ NULL, /* get_wrap_ctx */
+ NULL, /* wrap_object */
+ NULL, /* unwrap_object */
+ NULL, /* free_wrap_ctx */
+ },
+ {
+ /* attribute_cls */
+ NULL, /* create */
+ NULL, /* open */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* get */
+ NULL, /* specific */
+ NULL, /* optional */
+ NULL /* close */
+ },
+ {
+ /* dataset_cls */
+ NULL, /* create */
+ NULL, /* open */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* get */
+ NULL, /* specific */
+ NULL, /* optional */
+ NULL /* close */
+ },
+ {
+ /* datatype_cls */
NULL, /* commit */
NULL, /* open */
NULL, /* get */
@@ -134,8 +400,9 @@ static const H5VL_class_t fake_vol_g = {
},
{
/* introspect_cls */
- NULL, /* get_conn_cls */
- NULL, /* opt_query */
+ NULL, /* get_conn_cls */
+ fake_async_get_cap_flags, /* get_cap_flags */
+ NULL, /* opt_query */
},
{
/* request_cls */
@@ -163,6 +430,146 @@ static const H5VL_class_t fake_vol_g = {
};
/*-------------------------------------------------------------------------
+ * Function: reg_opt_op_optional_verify
+ *
+ * Purpose: Common verification routine for dynamic optional operations
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+reg_opt_op_optional_verify(void *obj, H5VL_optional_args_t *args)
+{
+ int *o = (int *)obj;
+ int *op_args;
+
+ /* Check for receiving correct operation value */
+ if (args->op_type != reg_opt_curr_op_val)
+ return -1;
+
+ /* Check that the object is correct */
+ if ((-1) != *o)
+ return -1;
+
+ /* Update the object, with the operation value */
+ *o = args->op_type;
+
+ /* Check that the argument is correct */
+ op_args = args->args;
+ if (NULL == op_args)
+ return -1;
+ if ((-1) != *op_args)
+ return -1;
+
+ /* Update the argument return parameter */
+ *op_args = args->op_type;
+
+ return 0;
+} /* end reg_opt_op_optional_verify() */
+
+/*-------------------------------------------------------------------------
+ * Function: reg_opt_op_optional
+ *
+ * Purpose: Common callback to perform a connector-specific operation
+ * on an object
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+reg_opt_op_optional(void *obj, H5VL_optional_args_t *args, hid_t H5_ATTR_UNUSED dxpl_id,
+ void H5_ATTR_UNUSED **req)
+{
+ /* Invoke the common value verification routine */
+ return reg_opt_op_optional_verify(obj, args);
+} /* end reg_opt_op_optional() */
+
+/*-------------------------------------------------------------------------
+ * Function: reg_opt_link_optional
+ *
+ * Purpose: Callback to perform a connector-specific operation
+ * on a link
+ *
+ * Return: Success: 0
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+reg_opt_link_optional(void *obj, const H5VL_loc_params_t *loc_params, H5VL_optional_args_t *args,
+ hid_t H5_ATTR_UNUSED dxpl_id, void H5_ATTR_UNUSED **req)
+{
+ /* Check for receiving correct loc_params info */
+ if (loc_params->type != H5VL_OBJECT_BY_NAME)
+ return -1;
+ if (loc_params->obj_type != H5I_GROUP)
+ return -1;
+ if (HDstrcmp(loc_params->loc_data.loc_by_name.name, ".") != 0)
+ return -1;
+ if (loc_params->loc_data.loc_by_name.lapl_id != H5P_LINK_ACCESS_DEFAULT)
+ return -1;
+
+ /* Invoke the common value verification routine */
+ return reg_opt_op_optional_verify(obj, args);
+} /* end reg_opt_link_optional() */
+
+/*-------------------------------------------------------------------------
+ * Function: reg_opt_datatype_get
+ *
+ * Purpose: Handles the datatype get callback
+ *
+ * Note: This is _strictly_ a testing fixture to support the
+ * exercise_reg_opt_oper() testing routine. It fakes just
+ * enough of the named datatype VOL callback for the
+ * H5VL_register_using_vol_id() call in that test routine to
+ * succeed.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+reg_opt_datatype_get(void H5_ATTR_UNUSED *obj, H5VL_datatype_get_args_t *args, hid_t H5_ATTR_UNUSED dxpl_id,
+ void H5_ATTR_UNUSED **req)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ if (H5VL_DATATYPE_GET_BINARY_SIZE == args->op_type) {
+ if (H5Tencode(H5T_NATIVE_INT, NULL, args->args.get_binary_size.size) < 0)
+ ret_value = FAIL;
+ } /* end if */
+ else if (H5VL_DATATYPE_GET_BINARY == args->op_type) {
+ if (H5Tencode(H5T_NATIVE_INT, args->args.get_binary.buf, &args->args.get_binary.buf_size) < 0)
+ ret_value = FAIL;
+ } /* end if */
+ else
+ ret_value = FAIL;
+
+ return ret_value;
+} /* end reg_opt_datatype_get() */
+
+/*-------------------------------------------------------------------------
+ * Function: fake_async_get_cap_flags
+ *
+ * Purpose: Return the capability flags for the 'fake async' connector
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+fake_async_get_cap_flags(const void H5_ATTR_UNUSED *info, unsigned *cap_flags)
+{
+ *cap_flags = fake_async_vol_g.cap_flags;
+
+ return SUCCEED;
+} /* end fake_async_get_cap_flags() */
+
+/*-------------------------------------------------------------------------
* Function: test_vol_registration()
*
* Purpose: Tests if we can load, register, and close a simple
@@ -1176,6 +1583,519 @@ error:
} /* end test_basic_datatype_operation() */
+typedef herr_t (*reg_opt_obj_oper_t)(const char *app_file, const char *app_func, unsigned app_line,
+ hid_t obj_id, H5VL_optional_args_t *args, hid_t dxpl_id, hid_t es_id);
+typedef herr_t (*reg_opt_link_oper_t)(const char *app_file, const char *app_func, unsigned app_line,
+ hid_t obj_id, const char *name, hid_t lapl_id,
+ H5VL_optional_args_t *args, hid_t dxpl_id, hid_t es_id);
+typedef union {
+ reg_opt_obj_oper_t obj_op;
+ reg_opt_link_oper_t link_op;
+} reg_opt_oper_t;
+
+/*-------------------------------------------------------------------------
+ * Function: exercise_reg_opt_oper()
+ *
+ * Purpose: Exercise a particular optional operation for a type.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+exercise_reg_opt_oper(hid_t fake_vol_id, hid_t reg_opt_vol_id, H5VL_subclass_t subcls,
+ const char *subcls_name, H5I_type_t id_type, reg_opt_oper_t reg_opt_op)
+{
+ char op_name[256]; /* Operation name to register */
+ hid_t obj_id = H5I_INVALID_HID;
+ H5VL_object_t * vol_obj;
+ H5VL_optional_args_t vol_cb_args;
+ int fake_obj, fake_arg;
+ int op_val = -1, op_val2 = -1;
+ int find_op_val;
+ herr_t ret = SUCCEED;
+
+ /* Test registering optional operation */
+ HDsnprintf(op_name, sizeof(op_name), "%s-op1", subcls_name);
+ if (H5VLregister_opt_operation(subcls, op_name, &op_val) < 0)
+ TEST_ERROR;
+
+ /* Verify that the reserved amount of optional operations is obeyed */
+ /* (The first optional operation registered should be at the lower limit) */
+ if (op_val != H5VL_RESERVED_NATIVE_OPTIONAL)
+ TEST_ERROR;
+
+ /* Look up 1st registered optional operation */
+ find_op_val = 0;
+ if (H5VLfind_opt_operation(subcls, op_name, &find_op_val) < 0)
+ TEST_ERROR;
+
+ /* Verify that the operation was looked up successfully */
+ if (op_val != find_op_val)
+ TEST_ERROR;
+
+ /* Test registering second optional operation */
+ HDsnprintf(op_name, sizeof(op_name), "%s-op2", subcls_name);
+ if (H5VLregister_opt_operation(subcls, op_name, &op_val2) < 0)
+ TEST_ERROR;
+
+ /* Verify that the reserved amount of optional operations is obeyed */
+ /* (The 2nd optional operation registered should be at the lower limit + 1) */
+ if (op_val2 != (H5VL_RESERVED_NATIVE_OPTIONAL + 1))
+ TEST_ERROR;
+
+ /* Look up 2nd registered optional operation */
+ find_op_val = 0;
+ if (H5VLfind_opt_operation(subcls, op_name, &find_op_val) < 0)
+ TEST_ERROR;
+
+ /* Verify that the operation was looked up successfully */
+ if (op_val2 != find_op_val)
+ TEST_ERROR;
+
+ /* Push a new API context on the stack */
+ /* (Necessary for the named datatype construction routines) */
+ if (H5VL_SUBCLS_DATATYPE == subcls)
+ H5CX_push();
+
+ /* Create fake object on fake VOL connector */
+ if (H5I_INVALID_HID == (obj_id = H5VL_register_using_vol_id(id_type, &fake_obj, fake_vol_id, TRUE)))
+ TEST_ERROR;
+
+ /* Pop the API context off the stack */
+ if (H5VL_SUBCLS_DATATYPE == subcls)
+ H5CX_pop(FALSE);
+
+ /* Attempt to issue operation on fake VOL connector */
+ fake_obj = -1;
+ fake_arg = -1;
+ vol_cb_args.op_type = op_val;
+ vol_cb_args.args = &fake_arg;
+ H5E_BEGIN_TRY
+ {
+ if (H5VL_SUBCLS_LINK == subcls || H5VL_SUBCLS_OBJECT == subcls)
+ ret = (*reg_opt_op.link_op)(__FILE__, __func__, __LINE__, obj_id, ".", H5P_DEFAULT, &vol_cb_args,
+ H5P_DEFAULT, H5ES_NONE);
+ else
+ ret = (*reg_opt_op.obj_op)(__FILE__, __func__, __LINE__, obj_id, &vol_cb_args, H5P_DEFAULT,
+ H5ES_NONE);
+ }
+ H5E_END_TRY;
+ if (FAIL != ret)
+ FAIL_PUTS_ERROR("should not be able to perform an optional operation with a NULL callback");
+ if ((-1) != fake_obj)
+ FAIL_PUTS_ERROR("'fake_obj' changed during failed operation?");
+ if ((-1) != fake_arg)
+ FAIL_PUTS_ERROR("'fake_arg' changed during failed operation?");
+
+ /* Named datatypes must be destroyed differently */
+ if (H5VL_SUBCLS_DATATYPE == subcls) {
+ H5T_t *dt;
+
+ /* Destroy fake datatype object */
+ if (NULL == (dt = H5I_remove(obj_id)))
+ TEST_ERROR;
+ if (H5VL_free_object(dt->vol_obj) < 0)
+ TEST_ERROR;
+ dt->vol_obj = NULL;
+ if (H5T_close(dt) < 0)
+ TEST_ERROR;
+ } /* end if */
+ else {
+ /* Destroy fake object */
+ if (NULL == (vol_obj = H5I_remove(obj_id)))
+ TEST_ERROR;
+ if (H5VL_free_object(vol_obj) < 0)
+ TEST_ERROR;
+ } /* end else */
+
+ /* Push a new API context on the stack */
+ /* (Necessary for the named datatype construction routines) */
+ if (H5VL_SUBCLS_DATATYPE == subcls)
+ H5CX_push();
+
+ /* Create fake object on reg_opt VOL connector */
+ if (H5I_INVALID_HID == (obj_id = H5VL_register_using_vol_id(id_type, &fake_obj, reg_opt_vol_id, TRUE)))
+ TEST_ERROR;
+
+ /* Pop the API context off the stack */
+ if (H5VL_SUBCLS_DATATYPE == subcls)
+ H5CX_pop(FALSE);
+
+ /* Issue first operation */
+ fake_obj = -1;
+ fake_arg = -1;
+ reg_opt_curr_op_val = op_val;
+ vol_cb_args.op_type = op_val;
+ vol_cb_args.args = &fake_arg;
+ if (H5VL_SUBCLS_LINK == subcls || H5VL_SUBCLS_OBJECT == subcls)
+ ret = (*reg_opt_op.link_op)(__FILE__, __func__, __LINE__, obj_id, ".", H5P_DEFAULT, &vol_cb_args,
+ H5P_DEFAULT, H5ES_NONE);
+ else
+ ret =
+ (*reg_opt_op.obj_op)(__FILE__, __func__, __LINE__, obj_id, &vol_cb_args, H5P_DEFAULT, H5ES_NONE);
+ if (ret < 0)
+ TEST_ERROR;
+
+ /* Verify that fake object & argument were modified correctly */
+ if (op_val != fake_obj)
+ FAIL_PUTS_ERROR("'fake_obj' not updated");
+ if (op_val != fake_arg)
+ FAIL_PUTS_ERROR("'fake_arg' not updated");
+
+ /* Issue second operation */
+ fake_obj = -1;
+ fake_arg = -1;
+ reg_opt_curr_op_val = op_val2;
+ vol_cb_args.op_type = op_val2;
+ vol_cb_args.args = &fake_arg;
+ if (H5VL_SUBCLS_LINK == subcls || H5VL_SUBCLS_OBJECT == subcls)
+ ret = (*reg_opt_op.link_op)(__FILE__, __func__, __LINE__, obj_id, ".", H5P_DEFAULT, &vol_cb_args,
+ H5P_DEFAULT, H5ES_NONE);
+ else
+ ret =
+ (*reg_opt_op.obj_op)(__FILE__, __func__, __LINE__, obj_id, &vol_cb_args, H5P_DEFAULT, H5ES_NONE);
+ if (ret < 0)
+ TEST_ERROR;
+
+ /* Verify that fake object & argument were modified correctly */
+ if (op_val2 != fake_obj)
+ FAIL_PUTS_ERROR("'fake_obj' not updated");
+ if (op_val2 != fake_arg)
+ FAIL_PUTS_ERROR("'fake_arg' not updated");
+
+ /* Named datatypes must be destroyed differently */
+ if (H5VL_SUBCLS_DATATYPE == subcls) {
+ H5T_t *dt;
+
+ /* Destroy fake datatype object */
+ if (NULL == (dt = H5I_remove(obj_id)))
+ TEST_ERROR;
+ if (H5VL_free_object(dt->vol_obj) < 0)
+ TEST_ERROR;
+ dt->vol_obj = NULL;
+ if (H5T_close(dt) < 0)
+ TEST_ERROR;
+ } /* end if */
+ else {
+ /* Destroy fake object */
+ if (NULL == (vol_obj = H5I_remove(obj_id)))
+ TEST_ERROR;
+ if (H5VL_free_object(vol_obj) < 0)
+ TEST_ERROR;
+ } /* end else */
+
+ /* Unregister 2nd registered optional operation */
+ if (H5VLunregister_opt_operation(subcls, op_name) < 0)
+ TEST_ERROR;
+
+ return SUCCEED;
+
+error:
+ return FAIL;
+} /* end exercise_reg_opt_oper() */
+
+/*-------------------------------------------------------------------------
+ * Function: test_register_opt_operation()
+ *
+ * Purpose: Tests if we can load, register, and close a simple
+ * VOL connector.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+test_register_opt_operation(void)
+{
+ hid_t fake_vol_id = H5I_INVALID_HID;
+ hid_t reg_opt_vol_id = H5I_INVALID_HID;
+ struct {
+ H5VL_subclass_t subcls;
+ const char * subcls_name;
+ H5I_type_t id_type;
+ reg_opt_oper_t reg_opt_op;
+ } test_params[] = {{H5VL_SUBCLS_ATTR, "attr", H5I_ATTR, {.obj_op = H5VLattr_optional_op}},
+ {H5VL_SUBCLS_DATASET, "dataset", H5I_DATASET, {.obj_op = H5VLdataset_optional_op}},
+ {H5VL_SUBCLS_DATATYPE, "datatype", H5I_DATATYPE, {.obj_op = H5VLdatatype_optional_op}},
+ {H5VL_SUBCLS_FILE, "file", H5I_FILE, {.obj_op = H5VLfile_optional_op}},
+ {H5VL_SUBCLS_GROUP, "group", H5I_GROUP, {.obj_op = H5VLgroup_optional_op}},
+ {H5VL_SUBCLS_LINK, "link", H5I_GROUP, {.link_op = H5VLlink_optional_op}},
+ {H5VL_SUBCLS_OBJECT, "object", H5I_GROUP, {.link_op = H5VLobject_optional_op}}};
+ int op_val = -1;
+ unsigned u;
+ herr_t ret = SUCCEED;
+
+ TESTING("dynamically registering optional operations");
+
+ /* Register the VOL connectors for testing */
+ if ((fake_vol_id = H5VLregister_connector(&fake_vol_g, H5P_DEFAULT)) < 0)
+ TEST_ERROR;
+ if ((reg_opt_vol_id = H5VLregister_connector(&reg_opt_vol_g, H5P_DEFAULT)) < 0)
+ TEST_ERROR;
+
+ /* Test registering invalid optional VOL subclass operations */
+ H5E_BEGIN_TRY
+ {
+ ret = H5VLregister_opt_operation(H5VL_SUBCLS_NONE, "fail", &op_val);
+ }
+ H5E_END_TRY;
+ if (FAIL != ret)
+ FAIL_PUTS_ERROR("should not be able to register an optional operation for the 'NONE' VOL subclass");
+ if ((-1) != op_val)
+ FAIL_PUTS_ERROR("'op_val' changed during failed operation?");
+ H5E_BEGIN_TRY
+ {
+ ret = H5VLregister_opt_operation(H5VL_SUBCLS_INFO, "fail2", &op_val);
+ }
+ H5E_END_TRY;
+ if (FAIL != ret)
+ FAIL_PUTS_ERROR("should not be able to register an optional operation for the 'INFO' VOL subclass");
+ if ((-1) != op_val)
+ FAIL_PUTS_ERROR("'op_val' changed during failed operation?");
+ H5E_BEGIN_TRY
+ {
+ ret = H5VLregister_opt_operation(H5VL_SUBCLS_WRAP, "fail3", &op_val);
+ }
+ H5E_END_TRY;
+ if (FAIL != ret)
+ FAIL_PUTS_ERROR("should not be able to register an optional operation for the 'WRAP' VOL subclass");
+ if ((-1) != op_val)
+ FAIL_PUTS_ERROR("'op_val' changed during failed operation?");
+ H5E_BEGIN_TRY
+ {
+ ret = H5VLregister_opt_operation(H5VL_SUBCLS_BLOB, "fail4", &op_val);
+ }
+ H5E_END_TRY;
+ if (FAIL != ret)
+ FAIL_PUTS_ERROR("should not be able to register an optional operation for the 'BLOB' VOL subclass");
+ if ((-1) != op_val)
+ FAIL_PUTS_ERROR("'op_val' changed during failed operation?");
+ H5E_BEGIN_TRY
+ {
+ ret = H5VLregister_opt_operation(H5VL_SUBCLS_TOKEN, "fail5", &op_val);
+ }
+ H5E_END_TRY;
+ if (FAIL != ret)
+ FAIL_PUTS_ERROR("should not be able to register an optional operation for the 'TOKEN' VOL subclass");
+ if ((-1) != op_val)
+ FAIL_PUTS_ERROR("'op_val' changed during failed operation?");
+
+ /* Test registering valid optional VOL subclass operation with NULL op_val ptr*/
+ H5E_BEGIN_TRY
+ {
+ ret = H5VLregister_opt_operation(H5VL_SUBCLS_FILE, "fail6", NULL);
+ }
+ H5E_END_TRY;
+ if (FAIL != ret)
+ FAIL_PUTS_ERROR("should not be able to register an optional operation with a NULL 'op_val'");
+
+ /* Try finding a non-existent optional VOL subclass operation */
+ H5E_BEGIN_TRY
+ {
+ ret = H5VLfind_opt_operation(H5VL_SUBCLS_DATASET, "fail", &op_val);
+ }
+ H5E_END_TRY;
+ if (FAIL != ret)
+ FAIL_PUTS_ERROR("should not be able to find a non-existent optional operation");
+
+ /* Try unregistering a non-existent optional VOL subclass operation */
+ H5E_BEGIN_TRY
+ {
+ ret = H5VLunregister_opt_operation(H5VL_SUBCLS_DATASET, "fail");
+ }
+ H5E_END_TRY;
+ if (FAIL != ret)
+ FAIL_PUTS_ERROR("should not be able to unregister a non-existent optional operation");
+
+ /* Optional operations on requests are supported (but difficult to test further) */
+ if (H5VLregister_opt_operation(H5VL_SUBCLS_REQUEST, "req_op", &op_val) < 0)
+ TEST_ERROR;
+
+ /* Register & test calling optional operations for each valid VOL subclass */
+ /* (Table-driven, with test_params array) */
+ for (u = 0; u < NELMTS(test_params); u++)
+ /* Exercise appropriate callback, for each VOL subclass */
+ if (exercise_reg_opt_oper(fake_vol_id, reg_opt_vol_id, test_params[u].subcls,
+ test_params[u].subcls_name, test_params[u].id_type,
+ test_params[u].reg_opt_op) < 0)
+ TEST_ERROR;
+
+ /* Unregister the VOL connectors */
+ if (H5VLunregister_connector(fake_vol_id) < 0)
+ TEST_ERROR;
+ if (H5VLunregister_connector(reg_opt_vol_id) < 0)
+ TEST_ERROR;
+
+ PASSED();
+
+ return SUCCEED;
+
+error:
+ H5E_BEGIN_TRY
+ {
+ H5VLunregister_connector(fake_vol_id);
+ H5VLunregister_connector(reg_opt_vol_id);
+ }
+ H5E_END_TRY;
+
+ return FAIL;
+} /* end test_register_opt_operation() */
+
+/*-------------------------------------------------------------------------
+ * Function: test_async_vol_props()
+ *
+ * Purpose: Test properties related to asynchronous VOL connector operation
+ *
+ * Note: Overrides the HDF5_VOL_CONNECTOR environment variable, to
+ * provide stable testing environment.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+test_async_vol_props(void)
+{
+ hid_t fapl_id = H5I_INVALID_HID;
+ hid_t vol_id = H5I_INVALID_HID;
+ H5VL_pass_through_info_t passthru_info;
+ unsigned cap_flags = 0;
+ char * conn_env_str = NULL;
+
+ TESTING("Async VOL props");
+
+ /* Retrieve the file access property for testing */
+ fapl_id = h5_fileaccess();
+
+ /* Test 'capability flags' property */
+
+ /* Test query w/NULL for cap_flags parameter */
+ if (H5Pget_vol_cap_flags(fapl_id, NULL) < 0)
+ FAIL_STACK_ERROR;
+
+ /* Override possible environment variable & re-initialize default VOL connector */
+ conn_env_str = HDgetenv("HDF5_VOL_CONNECTOR");
+ if (conn_env_str) {
+ if (NULL == (conn_env_str = HDstrdup(conn_env_str)))
+ TEST_ERROR
+ if (HDunsetenv("HDF5_VOL_CONNECTOR") < 0)
+ TEST_ERROR
+ if (H5VL__reparse_def_vol_conn_variable_test() < 0)
+ TEST_ERROR
+ } /* end if */
+
+ /* Test query w/default VOL, which should indicate no async, since native connector
+ * doesn't support async.
+ */
+ if (H5Pget_vol_cap_flags(fapl_id, &cap_flags) < 0)
+ FAIL_STACK_ERROR;
+ if ((cap_flags & H5VL_CAP_FLAG_ASYNC) > 0)
+ TEST_ERROR
+ if ((cap_flags & H5VL_CAP_FLAG_NATIVE_FILES) == 0)
+ TEST_ERROR
+
+ /* Close FAPL */
+ if (H5Pclose(fapl_id) < 0)
+ FAIL_STACK_ERROR;
+
+ /* Register a fake VOL connector that sets the async capability flag */
+ if ((vol_id = H5VLregister_connector(&fake_async_vol_g, H5P_DEFAULT)) < 0)
+ FAIL_STACK_ERROR;
+
+ /* Set environment variable to use 'fake async' connector & re-init default connector */
+ if (HDsetenv("HDF5_VOL_CONNECTOR", "fake_async", TRUE) < 0)
+ TEST_ERROR
+ if (H5VL__reparse_def_vol_conn_variable_test() < 0)
+ TEST_ERROR
+
+ /* Retrieve the file access property again */
+ fapl_id = h5_fileaccess();
+
+ /* Test query w/fake async VOL, which should succeed */
+ cap_flags = 0;
+ if (H5Pget_vol_cap_flags(fapl_id, &cap_flags) < 0)
+ FAIL_STACK_ERROR;
+ if ((cap_flags & H5VL_CAP_FLAG_ASYNC) == 0)
+ TEST_ERROR
+ if ((cap_flags & H5VL_CAP_FLAG_NATIVE_FILES) > 0)
+ TEST_ERROR
+
+ /* Reset environment variable & re-init default connector */
+ if (HDunsetenv("HDF5_VOL_CONNECTOR") < 0)
+ TEST_ERROR
+ if (H5VL__reparse_def_vol_conn_variable_test() < 0)
+ TEST_ERROR
+
+ /* Close FAPL */
+ if (H5Pclose(fapl_id) < 0)
+ FAIL_STACK_ERROR;
+
+ /* Retrieve the file access property again */
+ fapl_id = h5_fileaccess();
+
+ /* Set the VOL connector for the FAPL to the fake async connector */
+ if (H5Pset_vol(fapl_id, vol_id, NULL) < 0)
+ FAIL_STACK_ERROR;
+
+ /* Test query w/fake async VOL, which should succeed */
+ cap_flags = 0;
+ if (H5Pget_vol_cap_flags(fapl_id, &cap_flags) < 0)
+ FAIL_STACK_ERROR;
+ if ((cap_flags & H5VL_CAP_FLAG_ASYNC) == 0)
+ TEST_ERROR
+ if ((cap_flags & H5VL_CAP_FLAG_NATIVE_FILES) > 0)
+ TEST_ERROR
+
+ /* Stack the [internal] passthrough VOL connector on top of the fake async connector */
+ passthru_info.under_vol_id = vol_id;
+ passthru_info.under_vol_info = NULL;
+ if (H5Pset_vol(fapl_id, H5VL_PASSTHRU, &passthru_info) < 0)
+ FAIL_STACK_ERROR;
+
+ /* Test query w/passthru -> fake async VOL, which should succeed */
+ cap_flags = 0;
+ if (H5Pget_vol_cap_flags(fapl_id, &cap_flags) < 0)
+ FAIL_STACK_ERROR;
+ if ((cap_flags & H5VL_CAP_FLAG_ASYNC) == 0)
+ TEST_ERROR
+ if ((cap_flags & H5VL_CAP_FLAG_NATIVE_FILES) > 0)
+ TEST_ERROR
+
+ /* Unregister the fake async VOL ID */
+ if (H5VLunregister_connector(vol_id) < 0)
+ TEST_ERROR;
+
+ /* Close FAPL */
+ if (H5Pclose(fapl_id) < 0)
+ FAIL_STACK_ERROR;
+
+ /* Restore environment variable, if there was one */
+ if (conn_env_str) {
+ if (HDsetenv("HDF5_VOL_CONNECTOR", conn_env_str, TRUE) < 0)
+ TEST_ERROR
+ HDfree(conn_env_str);
+
+ if (H5VL__reparse_def_vol_conn_variable_test() < 0)
+ TEST_ERROR
+ } /* end if */
+
+ PASSED();
+
+ return SUCCEED;
+
+error:
+ H5E_BEGIN_TRY
+ {
+ H5Pclose(fapl_id);
+ H5VLunregister_connector(vol_id);
+ }
+ H5E_END_TRY;
+ HDfree(conn_env_str);
+
+ return FAIL;
+} /* end test_async_vol_props() */
+
/*-------------------------------------------------------------------------
* Function: main
*
@@ -1201,6 +2121,7 @@ main(void)
HDputs("Testing basic Virtual Object Layer (VOL) functionality.");
nerrors += test_vol_registration() < 0 ? 1 : 0;
+ nerrors += test_register_opt_operation() < 0 ? 1 : 0;
nerrors += test_native_vol_init() < 0 ? 1 : 0;
nerrors += test_basic_file_operation(env_h5_drvr) < 0 ? 1 : 0;
nerrors += test_basic_group_operation() < 0 ? 1 : 0;
@@ -1209,6 +2130,7 @@ main(void)
nerrors += test_basic_object_operation() < 0 ? 1 : 0;
nerrors += test_basic_link_operation() < 0 ? 1 : 0;
nerrors += test_basic_datatype_operation() < 0 ? 1 : 0;
+ nerrors += test_async_vol_props() < 0 ? 1 : 0;
if (nerrors) {
HDprintf("***** %d Virtual Object Layer TEST%s FAILED! *****\n", nerrors, nerrors > 1 ? "S" : "");