hdf5/test/vol.c
2023-09-26 13:11:22 -07:00

2667 lines
80 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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: Tests the virtual object layer (H5VL)
*
* This is a minimal test to ensure VOL usage (setting a VOL, etc.)
* works as expected. Actual VOL functionality is tested using
* other mechanisms.
*/
/* 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 */
static const char *FILENAME[] = {"vol_test_file", NULL};
#define NATIVE_VOL_TEST_GROUP_NAME "test_group"
#define NATIVE_VOL_TEST_DATASET_NAME "test_dataset"
#define NATIVE_VOL_TEST_ATTRIBUTE_NAME "test_dataset"
#define NATIVE_VOL_TEST_HARD_LINK_NAME "test_hard_link"
#define NATIVE_VOL_TEST_SOFT_LINK_NAME "test_soft_link"
#define NATIVE_VOL_TEST_MOVE_LINK_NAME "test_move_link"
#define NATIVE_VOL_TEST_COPY_LINK_NAME "test_copy_link"
#define NATIVE_VOL_TEST_DATATYPE_NAME "test_datatype"
#define N_ELEMENTS 10
#define NAME_LEN 512
/* 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 */
H5VL_CAP_FLAG_NONE, /* 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 */
};
static herr_t fake_get_cap_flags(const void *info, uint64_t *cap_flags);
static herr_t fake_vol_info_to_str(const void *info, char **str);
static herr_t fake_vol_str_to_info(const char *str, void **info);
static herr_t fake_vol_free_info(void *info);
#define FAKE_VOL_NAME "fake"
#define FAKE_VOL_VALUE ((H5VL_class_value_t)501)
#define H5VL_FAKE_CAP_FLAGS \
(H5VL_CAP_FLAG_DATASET_BASIC | H5VL_CAP_FLAG_GROUP_BASIC | H5VL_CAP_FLAG_FILE_BASIC)
/* A VOL class struct that describes a VOL class with no
* functionality.
*/
static const H5VL_class_t fake_vol_g = {
H5VL_VERSION, /* VOL class struct version */
FAKE_VOL_VALUE, /* value */
FAKE_VOL_NAME, /* name */
0, /* connector version */
H5VL_FAKE_CAP_FLAGS, /* capability flags */
NULL, /* initialize */
NULL, /* terminate */
{
/* info_cls */
(size_t)0, /* size */
NULL, /* copy */
NULL, /* compare */
fake_vol_free_info, /* free */
fake_vol_info_to_str, /* to_str */
fake_vol_str_to_info, /* 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 */
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 */
fake_get_cap_flags, /* 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, uint64_t *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 */
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 */
fake_async_get_cap_flags, /* 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 */
};
/*-------------------------------------------------------------------------
* 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 (strcmp(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_vol_info_to_str
*
* Purpose: Convert the fake VOL info to a string
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
fake_vol_info_to_str(const void *info, char **str)
{
const int val = *(const int *)info;
const size_t str_size = 16; /* The size of the string */
herr_t ret_value = SUCCEED;
/* Verify the info is correct before continuing */
if (val != INT_MAX) {
printf("The value of info (%d) is incorrect\n", val);
return FAIL;
}
/* Allocate the string long enough for the info */
if (NULL == (*str = (char *)calloc(1, str_size)))
return FAIL;
snprintf(*str, str_size, "%d", val);
return ret_value;
} /* end fake_vol_info_to_str() */
/*-------------------------------------------------------------------------
* Function: fake_vol_str_to_info
*
* Purpose: Convert a string to a VOL info
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
fake_vol_str_to_info(const char *str, void **info /*out*/)
{
herr_t ret_value = SUCCEED; /* Return value */
*((int **)info) = (int *)malloc(sizeof(int));
**((int **)info) = atoi(str);
return ret_value;
} /* end fake_vol_str_to_info() */
/*-------------------------------------------------------------------------
* Function: fake_vol_free_info
*
* Purpose: Free the memory of a VOL info
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
fake_vol_free_info(void *info)
{
herr_t ret_value = SUCCEED; /* Return value */
if (info)
free(info);
return ret_value;
} /* end fake_vol_free_info() */
/*-------------------------------------------------------------------------
* Function: fake_get_cap_flags
*
* Purpose: Return the capability flags for the 'fake' connector
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
fake_get_cap_flags(const void H5_ATTR_UNUSED *info, uint64_t *cap_flags)
{
*cap_flags = fake_vol_g.cap_flags;
return SUCCEED;
} /* end fake_get_cap_flags() */
/*-------------------------------------------------------------------------
* 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, uint64_t *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
* VOL connector.
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_vol_registration(void)
{
hid_t native_id = H5I_INVALID_HID;
hid_t lapl_id = H5I_INVALID_HID;
hid_t vipl_id = H5I_INVALID_HID;
herr_t ret = SUCCEED;
htri_t is_registered = FAIL;
hid_t vol_id = H5I_INVALID_HID;
hid_t vol_id2 = H5I_INVALID_HID;
H5VL_class_t *bad_fake_vol_class = NULL;
TESTING("VOL registration");
/* The test/fake VOL connector should not be registered at the start of the test */
if ((is_registered = H5VLis_connector_registered_by_name(FAKE_VOL_NAME)) < 0)
TEST_ERROR;
if (is_registered > 0)
FAIL_PUTS_ERROR("VOL connector is inappropriately registered");
if ((is_registered = H5VLis_connector_registered_by_value(FAKE_VOL_VALUE)) < 0)
TEST_ERROR;
if (is_registered > 0)
FAIL_PUTS_ERROR("VOL connector is inappropriately registered");
/* Test registering a connector with an incorrect property list (SHOULD FAIL) */
if ((lapl_id = H5Pcreate(H5P_LINK_ACCESS)) < 0)
TEST_ERROR;
H5E_BEGIN_TRY
{
vol_id = H5VLregister_connector(&fake_vol_g, lapl_id);
}
H5E_END_TRY
if (H5I_INVALID_HID != vol_id)
FAIL_PUTS_ERROR("should not be able to register a connector with an incorrect property list");
if (H5Pclose(lapl_id) < 0)
TEST_ERROR;
/* Test registering a VOL connector with an incompatible version # */
if (NULL == (bad_fake_vol_class = malloc(sizeof(H5VL_class_t))))
TEST_ERROR;
memcpy(bad_fake_vol_class, &fake_vol_g, sizeof(H5VL_class_t));
bad_fake_vol_class->version = H5VL_VERSION + 1;
H5E_BEGIN_TRY
{
vol_id = H5VLregister_connector(bad_fake_vol_class, H5P_DEFAULT);
}
H5E_END_TRY
if (H5I_INVALID_HID != vol_id)
FAIL_PUTS_ERROR("should not be able to register a connector with an incompatible version #");
free(bad_fake_vol_class);
bad_fake_vol_class = NULL;
/* Load a VOL interface
* The vipl_id does nothing without a VOL that needs it, but we do need to
* test creating a property list of that class and passing it along as a
* smoke check.
*/
if ((vipl_id = H5Pcreate(H5P_VOL_INITIALIZE)) < 0)
TEST_ERROR;
if ((vol_id = H5VLregister_connector(&fake_vol_g, vipl_id)) < 0)
TEST_ERROR;
if (H5Pclose(vipl_id) < 0)
TEST_ERROR;
/* The test/fake VOL connector should be registered now */
if ((is_registered = H5VLis_connector_registered_by_name(FAKE_VOL_NAME)) < 0)
TEST_ERROR;
if (0 == is_registered)
FAIL_PUTS_ERROR("VOL connector is un-registered");
if ((is_registered = H5VLis_connector_registered_by_value(FAKE_VOL_VALUE)) < 0)
TEST_ERROR;
if (0 == is_registered)
FAIL_PUTS_ERROR("VOL connector is un-registered");
/* Re-register a VOL connector */
if ((vol_id2 = H5VLregister_connector(&fake_vol_g, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* The test/fake VOL connector should still be registered now */
if ((is_registered = H5VLis_connector_registered_by_name(FAKE_VOL_NAME)) < 0)
TEST_ERROR;
if (0 == is_registered)
FAIL_PUTS_ERROR("VOL connector is un-registered");
if ((is_registered = H5VLis_connector_registered_by_value(FAKE_VOL_VALUE)) < 0)
TEST_ERROR;
if (0 == is_registered)
FAIL_PUTS_ERROR("VOL connector is un-registered");
/* Unregister the second test/fake VOL ID */
if (H5VLunregister_connector(vol_id2) < 0)
TEST_ERROR;
/* The test/fake VOL connector should still be registered now */
if ((is_registered = H5VLis_connector_registered_by_name(FAKE_VOL_NAME)) < 0)
TEST_ERROR;
if (0 == is_registered)
FAIL_PUTS_ERROR("VOL connector is un-registered");
if ((is_registered = H5VLis_connector_registered_by_value(FAKE_VOL_VALUE)) < 0)
TEST_ERROR;
if (0 == is_registered)
FAIL_PUTS_ERROR("VOL connector is un-registered");
/* Unregister the original test/fake VOL ID */
if (H5VLunregister_connector(vol_id) < 0)
TEST_ERROR;
/* Try to unregister the native VOL connector (should fail) */
if (H5I_INVALID_HID == (native_id = H5VLget_connector_id_by_name(H5VL_NATIVE_NAME)))
TEST_ERROR;
H5E_BEGIN_TRY
{
ret = H5VLunregister_connector(native_id);
}
H5E_END_TRY
if (FAIL != ret)
FAIL_PUTS_ERROR("should not be able to unregister the native VOL connector");
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5VLunregister_connector(vol_id);
H5Pclose(lapl_id);
H5Pclose(vipl_id);
}
H5E_END_TRY
if (bad_fake_vol_class)
free(bad_fake_vol_class);
return FAIL;
} /* end test_vol_registration() */
/*-------------------------------------------------------------------------
* Function: test_native_vol_init()
*
* Purpose: Tests if the native VOL connector gets initialized.
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_native_vol_init(void)
{
htri_t is_registered;
TESTING("Native VOL connector initialization");
/* The native VOL connector should always be registered */
if ((is_registered = H5VLis_connector_registered_by_name(H5VL_NATIVE_NAME)) < 0)
TEST_ERROR;
if (0 == is_registered)
FAIL_PUTS_ERROR("native VOL connector is un-registered");
if ((is_registered = H5VLis_connector_registered_by_value(H5VL_NATIVE_VALUE)) < 0)
TEST_ERROR;
if (0 == is_registered)
FAIL_PUTS_ERROR("native VOL connector is un-registered");
PASSED();
return SUCCEED;
error:
return FAIL;
} /* end test_native_vol_init() */
/*-------------------------------------------------------------------------
* Function: test_basic_file_operation()
*
* Purpose: Uses the native VOL connector to test basic VOL file operations
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_basic_file_operation(const char *env_h5_drvr)
{
hid_t fid = H5I_INVALID_HID;
hid_t fid_reopen = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
hid_t fapl_id2 = H5I_INVALID_HID;
hid_t fcpl_id = H5I_INVALID_HID;
char filename[1024];
ssize_t obj_count;
hid_t obj_id_list[1];
hsize_t file_size;
unsigned intent;
void *os_file_handle = NULL;
H5F_info2_t finfo;
char name[32];
TESTING("Basic VOL file operations");
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
/* Set the file close degree to a non-default value, to make the H5Pequal
* work out. This is kinda odd, but the library's current behavior with
* a default value is to return the value chosen (H5F_CLOSE_SEMI) instead
* of the default value (H5F_CLOSE_DEFAULT) from the property and then
* the H5Pequal doesn't detect that the property lists are the same. Since
* this is the documented behavior for file close degree for many years,
* I'm not fighting it, just getting the testing to verify that the VOL
* connector property is returned correctly. -QAK, 2018/11/17
*/
if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI) < 0)
TEST_ERROR;
if (H5Pset_metadata_read_attempts(fapl_id, 9) < 0)
TEST_ERROR;
/* H5Fcreate */
if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
/* H5Fget_obj_count */
if ((obj_count = H5Fget_obj_count(fid, H5F_OBJ_FILE)) < 0)
TEST_ERROR;
if ((obj_count = H5Fget_obj_count(fid, H5F_OBJ_ALL)) < 0)
TEST_ERROR;
if ((obj_count = H5Fget_obj_count((hid_t)H5F_OBJ_ALL, H5F_OBJ_DATASET)) < 0)
TEST_ERROR;
/* H5Fget_obj_ids */
if ((obj_count = H5Fget_obj_ids(fid, H5F_OBJ_ALL, 2, obj_id_list)) < 0)
TEST_ERROR;
if ((obj_count = H5Fget_obj_ids((hid_t)H5F_OBJ_ALL, H5F_OBJ_DATASET, 2, obj_id_list)) < 0)
TEST_ERROR;
/* Can't compare VFD properties for several VFDs */
if ((bool)(strcmp(env_h5_drvr, "split") != 0 && strcmp(env_h5_drvr, "multi") != 0 &&
strcmp(env_h5_drvr, "family") != 0 && strcmp(env_h5_drvr, "direct") != 0 &&
strcmp(env_h5_drvr, "core") != 0 && strcmp(env_h5_drvr, "core_paged") != 0 &&
strcmp(env_h5_drvr, "mpio") != 0 && strcmp(env_h5_drvr, "splitter") != 0)) {
/* H5Fget_access_plist */
if ((fapl_id2 = H5Fget_access_plist(fid)) < 0)
TEST_ERROR;
if (H5Pequal(fapl_id, fapl_id2) != true)
TEST_ERROR;
if (H5Pclose(fapl_id2) < 0)
TEST_ERROR;
} /* end if */
/* H5Fget_create_plist */
if ((fcpl_id = H5Fget_create_plist(fid)) < 0)
TEST_ERROR;
if (H5Pclose(fcpl_id) < 0)
TEST_ERROR;
/* H5Fget_filesize */
if (H5Fget_filesize(fid, &file_size) < 0)
TEST_ERROR;
/* Can't retrieve VFD handle for split / multi / family VFDs */
if ((bool)(strcmp(env_h5_drvr, "split") != 0 && strcmp(env_h5_drvr, "multi") != 0 &&
strcmp(env_h5_drvr, "family") != 0)) {
/* H5Fget_vfd_handle */
if (H5Fget_vfd_handle(fid, H5P_DEFAULT, &os_file_handle) < 0)
TEST_ERROR;
} /* end if */
/* H5Fget_intent */
if (H5Fget_intent(fid, &intent) < 0)
TEST_ERROR;
/* H5Fget_info2 */
if (H5Fget_info2(fid, &finfo) < 0)
TEST_ERROR;
/* H5Fget_name */
if (H5Fget_name(fid, name, 32) < 0)
TEST_ERROR;
/* H5Fclear_elink_file_cache */
if (H5Fclear_elink_file_cache(fid) < 0)
TEST_ERROR;
/* H5Fflush */
if (H5Fflush(fid, H5F_SCOPE_GLOBAL) < 0)
TEST_ERROR;
/* H5Fclose */
if (H5Fclose(fid) < 0)
TEST_ERROR;
/* H5Fis_accessible */
if (H5Fis_accessible(filename, fapl_id) < 0)
TEST_ERROR;
/* H5Fopen */
if ((fid = H5Fopen(filename, H5F_ACC_RDWR, fapl_id)) < 0)
TEST_ERROR;
/* Can't compare VFD properties for several VFDs */
if ((bool)(strcmp(env_h5_drvr, "split") != 0 && strcmp(env_h5_drvr, "multi") != 0 &&
strcmp(env_h5_drvr, "family") != 0 && strcmp(env_h5_drvr, "direct") != 0 &&
strcmp(env_h5_drvr, "core") != 0 && strcmp(env_h5_drvr, "core_paged") != 0 &&
strcmp(env_h5_drvr, "mpio") != 0 && strcmp(env_h5_drvr, "splitter") != 0)) {
/* H5Fget_access_plist */
if ((fapl_id2 = H5Fget_access_plist(fid)) < 0)
TEST_ERROR;
if (H5Pequal(fapl_id, fapl_id2) != true)
TEST_ERROR;
if (H5Pclose(fapl_id2) < 0)
TEST_ERROR;
} /* end if */
if ((fid_reopen = H5Freopen(fid)) < 0)
TEST_ERROR;
/* Can't compare VFD properties for several VFDs */
if ((bool)(strcmp(env_h5_drvr, "split") != 0 && strcmp(env_h5_drvr, "multi") != 0 &&
strcmp(env_h5_drvr, "family") != 0 && strcmp(env_h5_drvr, "direct") != 0 &&
strcmp(env_h5_drvr, "core") != 0 && strcmp(env_h5_drvr, "core_paged") != 0 &&
strcmp(env_h5_drvr, "mpio") != 0 && strcmp(env_h5_drvr, "splitter") != 0)) {
/* H5Fget_access_plist */
if ((fapl_id2 = H5Fget_access_plist(fid_reopen)) < 0)
TEST_ERROR;
if (H5Pequal(fapl_id, fapl_id2) != true)
TEST_ERROR;
if (H5Pclose(fapl_id2) < 0)
TEST_ERROR;
} /* end if */
if (H5Fclose(fid) < 0)
TEST_ERROR;
if (H5Fclose(fid_reopen) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
/* H5Pclose */
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Fclose(fid);
H5Fclose(fid_reopen);
H5Pclose(fapl_id);
H5Pclose(fapl_id2);
H5Pclose(fcpl_id);
}
H5E_END_TRY
return FAIL;
} /* end test_basic_file_operation() */
/*-------------------------------------------------------------------------
* Function: test_basic_group_operation()
*
* Purpose: Uses the native VOL connector to test basic VOL group operations
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_basic_group_operation(void)
{
hid_t fid = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
hid_t gid = H5I_INVALID_HID;
hid_t gid_a = H5I_INVALID_HID;
hid_t gcpl_id = H5I_INVALID_HID;
char filename[1024];
H5G_info_t info;
bool driver_is_parallel;
TESTING("Basic VOL group operations");
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
/* H5Gcreate */
if ((gid = H5Gcreate2(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Gget_create_plist */
if ((gcpl_id = H5Gget_create_plist(gid)) < 0)
TEST_ERROR;
if (H5Pclose(gcpl_id) < 0)
TEST_ERROR;
/* H5Gget_info */
if (H5Gget_info(gid, &info) < 0)
TEST_ERROR;
if (H5Gget_info(fid, &info) < 0)
TEST_ERROR;
/* H5Gget_info_by_name */
if (H5Gget_info_by_name(fid, NATIVE_VOL_TEST_GROUP_NAME, &info, H5P_DEFAULT) < 0)
TEST_ERROR;
/* H5Gget_info_by_idx */
if (H5Gget_info_by_idx(fid, "/", H5_INDEX_NAME, H5_ITER_NATIVE, 0, &info, H5P_DEFAULT) < 0)
TEST_ERROR;
/* H5Gflush - skip for parallel file drivers as flush calls cause assertions in the library */
if (h5_using_parallel_driver(fapl_id, &driver_is_parallel) < 0)
TEST_ERROR;
if (!driver_is_parallel)
if (H5Gflush(gid) < 0)
TEST_ERROR;
/* H5Gclose */
if (H5Gclose(gid) < 0)
TEST_ERROR;
/* H5Gopen */
if ((gid = H5Gopen2(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Gcreate_anon */
if ((gid_a = H5Gcreate_anon(fid, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Grefresh */
if (H5Grefresh(gid) < 0)
TEST_ERROR;
if (H5Gclose(gid) < 0)
TEST_ERROR;
if (H5Gclose(gid_a) < 0)
TEST_ERROR;
if (H5Fclose(fid) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
/* H5Pclose */
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Fclose(fid);
H5Gclose(gid);
H5Pclose(fapl_id);
H5Pclose(gcpl_id);
}
H5E_END_TRY
return FAIL;
} /* end test_basic_group_operation() */
/*-------------------------------------------------------------------------
* Function: test_basic_dataset_operation()
*
* Purpose: Uses the native VOL connector to test basic VOL dataset operations
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_basic_dataset_operation(void)
{
hid_t fid = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
hid_t dcpl_id = H5I_INVALID_HID;
hid_t dapl_id = H5I_INVALID_HID;
hid_t did = H5I_INVALID_HID;
hid_t did_a = H5I_INVALID_HID;
hid_t sid = H5I_INVALID_HID;
hid_t tid = H5I_INVALID_HID;
char filename[1024];
hsize_t curr_dims = 0;
hsize_t max_dims = H5S_UNLIMITED;
hsize_t storage_size;
haddr_t offset;
H5D_space_status_t status;
bool driver_is_parallel;
int in_buf[N_ELEMENTS];
int out_buf[N_ELEMENTS];
int i;
TESTING("Basic VOL dataset operations");
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
for (i = 0; i < N_ELEMENTS; i++) {
in_buf[i] = i;
out_buf[i] = 0;
}
/* H5Dcreate */
curr_dims = 0;
if ((sid = H5Screate_simple(1, &curr_dims, &max_dims)) < 0)
TEST_ERROR;
curr_dims = N_ELEMENTS;
if ((dcpl_id = H5Pcreate(H5P_DATASET_CREATE)) < 0)
TEST_ERROR;
if (H5Pset_chunk(dcpl_id, 1, &curr_dims) < 0)
TEST_ERROR;
if ((did = H5Dcreate2(fid, NATIVE_VOL_TEST_DATASET_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl_id,
H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Dcreate_anon */
if ((did_a = H5Dcreate_anon(fid, H5T_NATIVE_INT, sid, dcpl_id, H5P_DEFAULT)) < 0)
TEST_ERROR;
if (H5Sclose(sid) < 0)
TEST_ERROR;
if (H5Pclose(dcpl_id) < 0)
TEST_ERROR;
/* H5Dset_extent */
curr_dims = N_ELEMENTS;
if (H5Dset_extent(did, &curr_dims) < 0)
TEST_ERROR;
/* H5Dflush - skip for parallel file drivers as flush calls cause assertions in the library */
if (h5_using_parallel_driver(fapl_id, &driver_is_parallel) < 0)
TEST_ERROR;
if (!driver_is_parallel)
if (H5Dflush(did) < 0)
TEST_ERROR;
/* H5Dwrite */
if (H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, in_buf) < 0)
TEST_ERROR;
/* H5Drefresh */
if (H5Drefresh(did) < 0)
TEST_ERROR;
/* H5Dclose */
if (H5Dclose(did) < 0)
TEST_ERROR;
if (H5Dclose(did_a) < 0)
TEST_ERROR;
/* H5Dopen */
if ((did = H5Dopen2(fid, NATIVE_VOL_TEST_DATASET_NAME, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Dget_space */
if ((sid = H5Dget_space(did)) < 0)
TEST_ERROR;
if (H5Sclose(sid) < 0)
TEST_ERROR;
/* H5Dget_space_status */
if (H5Dget_space_status(did, &status) < 0)
TEST_ERROR;
/* H5Dget_type */
if ((tid = H5Dget_type(did)) < 0)
TEST_ERROR;
if (H5Tclose(tid) < 0)
TEST_ERROR;
/* H5Tcopy (when used w/ a dataset, it gets an H5VL struct */
if ((tid = H5Tcopy(did)) < 0)
TEST_ERROR;
if (H5Tclose(tid) < 0)
TEST_ERROR;
/* H5Dget_create_plist */
if ((dcpl_id = H5Dget_create_plist(did)) < 0)
TEST_ERROR;
if (H5Pclose(dcpl_id) < 0)
TEST_ERROR;
/* H5Dget_access_plist */
if ((dapl_id = H5Dget_access_plist(did)) < 0)
TEST_ERROR;
if (H5Pclose(dapl_id) < 0)
TEST_ERROR;
/* H5Dget_storage_size */
/* XXX: This is a terrible API call that can't truly indicate failure */
if (0 == (storage_size = H5Dget_storage_size(did)))
TEST_ERROR;
/* H5Dget_offset */
/* XXX: Another bad API call that can't flag error values. Also, this
* returns HADDR_UNDEF for chunked datasets, which is bizarre.
*/
if (HADDR_UNDEF != (offset = H5Dget_offset(did)))
TEST_ERROR;
/* H5Dread */
if (H5Dread(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, out_buf) < 0)
TEST_ERROR;
for (i = 0; i < N_ELEMENTS; i++)
if (in_buf[i] != out_buf[i])
TEST_ERROR;
if (H5Dclose(did) < 0)
TEST_ERROR;
if (H5Fclose(fid) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
/* H5Pclose */
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Fclose(fid);
H5Dclose(did);
H5Dclose(did_a);
H5Sclose(sid);
H5Tclose(tid);
H5Pclose(fapl_id);
H5Pclose(dapl_id);
H5Pclose(dcpl_id);
}
H5E_END_TRY
return FAIL;
} /* end test_basic_dataset_operation() */
/*-------------------------------------------------------------------------
* Function: test_basic_attribute_operation()
*
* Purpose: Uses the native VOL connector to test basic VOL attribute operations
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_basic_attribute_operation(void)
{
hid_t fid = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
hid_t gid = H5I_INVALID_HID;
hid_t aid = H5I_INVALID_HID;
hid_t aid_name = H5I_INVALID_HID;
hid_t sid = H5I_INVALID_HID;
char filename[1024];
hsize_t dims = 1;
int data_in = 42;
int data_out = 0;
TESTING("Basic VOL attribute operations");
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
if ((gid = H5Gcreate2(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR;
dims = 1;
if ((sid = H5Screate_simple(1, &dims, &dims)) < 0)
TEST_ERROR;
/* H5Acreate */
if ((aid = H5Acreate2(fid, NATIVE_VOL_TEST_ATTRIBUTE_NAME, H5T_NATIVE_INT, sid, H5P_DEFAULT,
H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Awrite */
if (H5Awrite(aid, H5T_NATIVE_INT, &data_in) < 0)
TEST_ERROR;
/* H5Aread */
if (H5Aread(aid, H5T_NATIVE_INT, &data_out) < 0)
TEST_ERROR;
if (data_in != data_out)
TEST_ERROR;
/* H5Aclose */
if (H5Aclose(aid) < 0)
TEST_ERROR;
/* H5Aopen */
if ((aid = H5Aopen(fid, NATIVE_VOL_TEST_ATTRIBUTE_NAME, H5P_DEFAULT)) < 0)
TEST_ERROR;
if (H5Aclose(aid) < 0)
TEST_ERROR;
/* H5Adelete */
if (H5Adelete(fid, NATIVE_VOL_TEST_ATTRIBUTE_NAME) < 0)
TEST_ERROR;
/* H5Acreate_by_name */
if ((aid_name = H5Acreate_by_name(fid, NATIVE_VOL_TEST_GROUP_NAME, NATIVE_VOL_TEST_ATTRIBUTE_NAME,
H5T_NATIVE_INT, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Aclose */
if (H5Aclose(aid_name) < 0)
TEST_ERROR;
/* H5Adelete_by_name */
if (H5Adelete_by_name(fid, NATIVE_VOL_TEST_GROUP_NAME, NATIVE_VOL_TEST_ATTRIBUTE_NAME, H5P_DEFAULT) < 0)
TEST_ERROR;
if (H5Sclose(sid) < 0)
TEST_ERROR;
if (H5Gclose(gid) < 0)
TEST_ERROR;
if (H5Fclose(fid) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
/* H5Pclose */
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Fclose(fid);
H5Pclose(fapl_id);
H5Gclose(gid);
H5Sclose(sid);
H5Aclose(aid);
H5Aclose(aid_name);
}
H5E_END_TRY
return FAIL;
} /* end test_basic_attribute_operation() */
/*-------------------------------------------------------------------------
* Function: test_basic_object_operation()
*
* Purpose: Uses the native VOL connector to test basic VOL object operations
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_basic_object_operation(void)
{
hid_t fid = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
hid_t gid = H5I_INVALID_HID;
hid_t oid = H5I_INVALID_HID;
char filename[1024];
H5O_info2_t object_info;
TESTING("Basic VOL object operations");
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
if ((gid = H5Gcreate2(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Oget_info */
if (H5Oget_info3(fid, &object_info, H5O_INFO_ALL) < 0)
TEST_ERROR;
//! [H5Oget_info_by_name3_snip]
/* H5Oget_info_by_name */
if (H5Oget_info_by_name3(fid, NATIVE_VOL_TEST_GROUP_NAME, &object_info, H5O_INFO_ALL, H5P_DEFAULT) < 0)
TEST_ERROR;
//! [H5Oget_info_by_name3_snip]
/* H5Oexists_by_name */
if (H5Oexists_by_name(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT) != true)
TEST_ERROR;
/* H5Oopen/close */
if ((oid = H5Oopen(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT)) < 0)
TEST_ERROR;
if (H5Oclose(oid) < 0)
TEST_ERROR;
if (H5Gclose(gid) < 0)
TEST_ERROR;
if (H5Fclose(fid) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
/* H5Pclose */
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Fclose(fid);
H5Pclose(fapl_id);
H5Gclose(gid);
}
H5E_END_TRY
return FAIL;
} /* end test_basic_object_operation() */
/*-------------------------------------------------------------------------
* Function: test_basic_link_operation()
*
* Purpose: Uses the native VOL connector to test basic VOL link operations
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_basic_link_operation(void)
{
hid_t fid = H5I_INVALID_HID;
hid_t gid = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
char filename[1024];
TESTING("Basic VOL link operations");
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
if ((gid = H5Gcreate2(fid, NATIVE_VOL_TEST_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Lcreate_hard */
if (H5Lcreate_hard(fid, "/", gid, NATIVE_VOL_TEST_HARD_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0)
TEST_ERROR;
/* H5Lcreate_soft (to itself) */
if (H5Lcreate_soft("/", fid, NATIVE_VOL_TEST_SOFT_LINK_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0)
TEST_ERROR;
/* H5Lexists */
if (H5Lexists(gid, NATIVE_VOL_TEST_HARD_LINK_NAME, H5P_DEFAULT) < 0)
TEST_ERROR;
if (H5Lexists(fid, NATIVE_VOL_TEST_SOFT_LINK_NAME, H5P_DEFAULT) < 0)
TEST_ERROR;
/* H5Lcopy */
if (H5Lcopy(gid, NATIVE_VOL_TEST_HARD_LINK_NAME, fid, NATIVE_VOL_TEST_COPY_LINK_NAME, H5P_DEFAULT,
H5P_DEFAULT) < 0)
TEST_ERROR;
/* H5Lmove */
if (H5Lmove(fid, NATIVE_VOL_TEST_COPY_LINK_NAME, gid, NATIVE_VOL_TEST_MOVE_LINK_NAME, H5P_DEFAULT,
H5P_DEFAULT) < 0)
TEST_ERROR;
if (H5Gclose(gid) < 0)
TEST_ERROR;
if (H5Fclose(fid) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
/* H5Pclose */
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Fclose(fid);
H5Fclose(gid);
H5Pclose(fapl_id);
}
H5E_END_TRY
return FAIL;
} /* end test_basic_link_operation() */
/*-------------------------------------------------------------------------
* Function: test_basic_datatype_operation()
*
* Purpose: Uses the native VOL connector to test basic VOL datatype operations
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_basic_datatype_operation(void)
{
hid_t fid = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
hid_t tid = H5I_INVALID_HID;
hid_t tid_anon = H5I_INVALID_HID;
hid_t tcpl_id = H5I_INVALID_HID;
char filename[1024];
bool driver_is_parallel;
TESTING("Basic VOL datatype operations");
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
if ((fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
if ((tid = H5Tcopy(H5T_NATIVE_INT)) < 0)
TEST_ERROR;
/* H5Tcommit */
if (H5Tcommit2(fid, NATIVE_VOL_TEST_DATATYPE_NAME, tid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0)
TEST_ERROR;
/* H5Tflush - skip for parallel file drivers as flush calls cause assertions in the library */
if (h5_using_parallel_driver(fapl_id, &driver_is_parallel) < 0)
TEST_ERROR;
if (!driver_is_parallel)
if (H5Tflush(tid) < 0)
TEST_ERROR;
/* H5Trefresh */
if (H5Trefresh(tid) < 0)
TEST_ERROR;
/* H5Tclose */
if (H5Tclose(tid) < 0)
TEST_ERROR;
/* H5Topen */
if ((tid = H5Topen2(fid, NATIVE_VOL_TEST_DATATYPE_NAME, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* H5Tget_create_plist */
if ((tcpl_id = H5Tget_create_plist(tid)) < 0)
TEST_ERROR;
/* H5Tcommit_anon */
if ((tid_anon = H5Tcopy(H5T_NATIVE_INT)) < 0)
TEST_ERROR;
if (H5Tcommit_anon(fid, tid_anon, H5P_DEFAULT, H5P_DEFAULT) < 0)
TEST_ERROR;
if (H5Pclose(tcpl_id) < 0)
TEST_ERROR;
if (H5Tclose(tid) < 0)
TEST_ERROR;
if (H5Tclose(tid_anon) < 0)
TEST_ERROR;
if (H5Fclose(fid) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
/* H5Pclose */
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Pclose(tcpl_id);
H5Fclose(fid);
H5Pclose(fapl_id);
H5Tclose(tid);
H5Tclose(tid_anon);
}
H5E_END_TRY
return FAIL;
} /* 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 */
snprintf(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 */
snprintf(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;
char *conn_env_str = NULL;
TESTING("Async VOL props");
vol_cap_flags_g = H5VL_CAP_FLAG_NONE;
/* 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 = getenv(HDF5_VOL_CONNECTOR);
if (conn_env_str) {
if (NULL == (conn_env_str = strdup(conn_env_str)))
TEST_ERROR;
if (HDunsetenv(HDF5_VOL_CONNECTOR) < 0)
TEST_ERROR;
if (H5VL__reparse_def_vol_conn_variable_test() < 0)
TEST_ERROR;
}
/* Test query w/default VOL, which should indicate no async, since native connector
* doesn't support async.
*/
if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0)
FAIL_STACK_ERROR;
if ((vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC) > 0)
TEST_ERROR;
if ((vol_cap_flags_g & 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 */
vol_cap_flags_g = H5VL_CAP_FLAG_NONE;
if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0)
FAIL_STACK_ERROR;
if ((vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC) == 0)
TEST_ERROR;
if ((vol_cap_flags_g & 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 */
vol_cap_flags_g = H5VL_CAP_FLAG_NONE;
if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0)
FAIL_STACK_ERROR;
if ((vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC) == 0)
TEST_ERROR;
if ((vol_cap_flags_g & 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 */
vol_cap_flags_g = H5VL_CAP_FLAG_NONE;
if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0)
FAIL_STACK_ERROR;
if ((vol_cap_flags_g & H5VL_CAP_FLAG_ASYNC) == 0)
TEST_ERROR;
if ((vol_cap_flags_g & 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;
free(conn_env_str);
if (H5VL__reparse_def_vol_conn_variable_test() < 0)
TEST_ERROR;
}
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Pclose(fapl_id);
H5VLunregister_connector(vol_id);
}
H5E_END_TRY
free(conn_env_str);
return FAIL;
} /* end test_async_vol_props() */
/*-------------------------------------------------------------------------
* Function: test_vol_cap_flags()
*
* Purpose: Tests the VOL cap flags
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_vol_cap_flags(void)
{
hid_t fapl_id = H5I_INVALID_HID;
hid_t vol_id = H5I_INVALID_HID;
char *vol_env = NULL;
H5VL_pass_through_info_t passthru_info;
TESTING("VOL capability flags");
vol_cap_flags_g = H5VL_CAP_FLAG_NONE;
/* Register a fake VOL */
if ((vol_id = H5VLregister_connector(&fake_vol_g, H5P_DEFAULT)) < 0)
TEST_ERROR;
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
TEST_ERROR;
if (H5Pset_vol(fapl_id, vol_id, NULL) < 0)
TEST_ERROR;
/* Verify the correctness of the VOL capacity flags */
if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0)
TEST_ERROR;
if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC))
TEST_ERROR;
if (vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)
TEST_ERROR;
/* If using the native VOL by default, check flags again with H5P_DEFAULT */
vol_env = getenv(HDF5_VOL_CONNECTOR);
if (!vol_env || (0 == strcmp(vol_env, "native"))) {
H5VL_class_t *cls;
hid_t connector_id;
if (H5Pget_vol_id(H5P_DEFAULT, &connector_id) < 0)
TEST_ERROR;
if (NULL == (cls = H5I_object(connector_id)))
TEST_ERROR;
vol_cap_flags_g = H5VL_CAP_FLAG_NONE;
if (H5Pget_vol_cap_flags(H5P_DEFAULT, &vol_cap_flags_g) < 0)
TEST_ERROR;
if (vol_cap_flags_g != cls->cap_flags)
TEST_ERROR;
if (H5VLclose(connector_id) < 0)
TEST_ERROR;
}
/* Stack the [internal] passthrough VOL connector on top of the fake 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;
/* Verify the correctness of the VOL capacity flags */
vol_cap_flags_g = H5VL_CAP_FLAG_NONE;
if (H5Pget_vol_cap_flags(fapl_id, &vol_cap_flags_g) < 0)
TEST_ERROR;
if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC))
TEST_ERROR;
if (vol_cap_flags_g & H5VL_CAP_FLAG_ATTR_BASIC)
TEST_ERROR;
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
/* Unregister the fake VOL ID */
if (H5VLunregister_connector(vol_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5VLunregister_connector(vol_id);
H5Pclose(fapl_id);
}
H5E_END_TRY
return FAIL;
} /* end test_vol_cap_flags() */
/*-------------------------------------------------------------------------
* Function: test_get_vol_name()
*
* Purpose: Tests getting VOL name using H5VLget_connector_name
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_get_vol_name(void)
{
hid_t fapl_id = H5I_INVALID_HID;
hid_t file_id = H5I_INVALID_HID;
char filename[NAME_LEN];
char vol_name[NAME_LEN];
const char *conn_env_str = NULL;
TESTING("getting connector name");
conn_env_str = getenv(HDF5_VOL_CONNECTOR);
if (NULL == (conn_env_str = getenv("HDF5_VOL_CONNECTOR")))
conn_env_str = "native";
/* Skip the connectors other than the native and pass_through connector */
if (strcmp(conn_env_str, "native") && strcmp(conn_env_str, "pass_through")) {
SKIPPED();
printf(" only test the native or internal pass_through connector\n");
return SUCCEED;
}
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
if ((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
if (H5VLget_connector_name(file_id, vol_name, NAME_LEN) < 0)
TEST_ERROR;
/* When comparing the pass_through connector, ignore the rest information (under_vol=0;under_info={}) */
if ((!strcmp(conn_env_str, "native") && strcmp(vol_name, "native")) ||
(!strcmp(conn_env_str, "pass_through") && strcmp(vol_name, "pass_through")))
TEST_ERROR;
if (H5Fclose(file_id) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Fclose(file_id);
H5Pclose(fapl_id);
}
H5E_END_TRY
return FAIL;
} /* end test_get_vol_name() */
/*-------------------------------------------------------------------------
* Function: test_wrap_register()
*
* Purpose: Tests the failure of calling H5VLwrap_register in application
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_wrap_register(void)
{
hid_t fapl_id = H5I_INVALID_HID;
hid_t file_id = H5I_INVALID_HID;
hid_t group_id = H5I_INVALID_HID;
hid_t wrap_id = H5I_INVALID_HID;
char filename[NAME_LEN];
void *vol_obj;
TESTING("failure of calling H5VLwrap_register");
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
if ((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
if ((group_id = H5Gcreate2(file_id, "test", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* Retrieve the VOL object for the group */
if (!(vol_obj = H5VLobject(group_id)))
TEST_ERROR;
/* Try to register a second ID for the group. It should fail because this routine is mainly
* targeted toward wrapping objects for iteration routine callbacks, not for application use
*/
H5E_BEGIN_TRY
{
wrap_id = H5VLwrap_register(vol_obj, H5I_GROUP);
}
H5E_END_TRY
if (H5I_INVALID_HID != wrap_id)
FAIL_PUTS_ERROR("should not be able to call H5VLwrap_register in an application");
if (H5Gclose(group_id) < 0)
TEST_ERROR;
if (H5Fclose(file_id) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Gclose(group_id);
H5Fclose(file_id);
H5Pclose(fapl_id);
}
H5E_END_TRY
return FAIL;
} /* end test_wrap_register() */
/*-------------------------------------------------------------------------
* Function: test_info_to_str()
*
* Purpose: Tests the conversion between a VOL info and a string
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_info_to_str(void)
{
hid_t fapl_id = H5I_INVALID_HID;
hid_t vol_id = H5I_INVALID_HID;
int info = INT_MAX;
char *ret_str = NULL;
int *ret_info = NULL;
TESTING("conversion between a VOL info and a string");
/* Register a fake VOL */
if ((vol_id = H5VLregister_connector(&fake_vol_g, H5P_DEFAULT)) < 0)
TEST_ERROR;
if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0)
TEST_ERROR;
if (H5Pset_vol(fapl_id, vol_id, NULL) < 0)
TEST_ERROR;
/* Serialize the VOL info into a string */
if (H5VLconnector_info_to_str(&info, vol_id, &ret_str) < 0)
TEST_ERROR;
/* Parse the string and construct it into a VOL info */
if (H5VLconnector_str_to_info(ret_str, vol_id, (void **)(&ret_info)) < 0)
TEST_ERROR;
if (*ret_info != info)
FAIL_PUTS_ERROR("the returned VOL info doesn't match the original info");
/* Free the VOL info being returned */
if (H5VLfree_connector_info(vol_id, ret_info) < 0)
TEST_ERROR;
/* Free the string being returned */
if (ret_str)
free(ret_str);
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
/* Unregister the fake VOL ID */
if (H5VLunregister_connector(vol_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5VLunregister_connector(vol_id);
H5Pclose(fapl_id);
}
H5E_END_TRY
return FAIL;
} /* end test_info_to_str() */
/*-------------------------------------------------------------------------
* Function: test_query_optional
*
* Purpose: Tests the bug fix (HDFFV-11208) that a committed datatype
* triggered an assertion failure in H5VLquery_optional
*
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
static herr_t
test_query_optional(void)
{
hid_t fapl_id = H5I_INVALID_HID;
hid_t file_id = H5I_INVALID_HID;
hid_t group_id = H5I_INVALID_HID;
hid_t dtype_id = H5I_INVALID_HID;
char filename[NAME_LEN];
uint64_t supported = 0;
TESTING("H5VLquery_optional");
/* Retrieve the file access property for testing */
fapl_id = h5_fileaccess();
h5_fixname(FILENAME[0], fapl_id, filename, sizeof filename);
if ((file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0)
TEST_ERROR;
if ((group_id = H5Gcreate2(file_id, "test_group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
TEST_ERROR;
/* Test H5VLquery_optional with a group */
if (H5VLquery_optional(group_id, H5VL_SUBCLS_OBJECT, H5VL_NATIVE_OBJECT_GET_COMMENT, &supported) < 0)
TEST_ERROR;
if ((dtype_id = H5Tcopy(H5T_NATIVE_INT)) < 0)
TEST_ERROR;
/* Commit the datatype into the file */
if (H5Tcommit2(file_id, "test_dtype", dtype_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT) < 0)
TEST_ERROR;
/* Test H5VLquery_optional with a committed datatype where the assertion failure happened in the past */
if (H5VLquery_optional(dtype_id, H5VL_SUBCLS_OBJECT, H5VL_NATIVE_OBJECT_GET_COMMENT, &supported) < 0)
TEST_ERROR;
if (H5Gclose(group_id) < 0)
TEST_ERROR;
if (H5Tclose(dtype_id) < 0)
TEST_ERROR;
if (H5Fclose(file_id) < 0)
TEST_ERROR;
h5_delete_test_file(FILENAME[0], fapl_id);
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return SUCCEED;
error:
H5E_BEGIN_TRY
{
H5Gclose(group_id);
H5Tclose(dtype_id);
H5Fclose(file_id);
H5Pclose(fapl_id);
}
H5E_END_TRY
return FAIL;
} /* end test_query_optional() */
/*-------------------------------------------------------------------------
* Function: main
*
* Purpose: Tests the virtual object layer interface (H5VL)
*
* Return: EXIT_SUCCESS/EXIT_FAILURE
*
*-------------------------------------------------------------------------
*/
int
main(void)
{
const char *env_h5_drvr; /* File driver value from environment */
int nerrors = 0;
/* Get the VFD to use */
env_h5_drvr = getenv(HDF5_DRIVER);
if (env_h5_drvr == NULL)
env_h5_drvr = "nomatch";
h5_reset();
puts("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;
nerrors += test_basic_dataset_operation() < 0 ? 1 : 0;
nerrors += test_basic_attribute_operation() < 0 ? 1 : 0;
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;
nerrors += test_vol_cap_flags() < 0 ? 1 : 0;
nerrors += test_get_vol_name() < 0 ? 1 : 0;
nerrors += test_wrap_register() < 0 ? 1 : 0;
nerrors += test_info_to_str() < 0 ? 1 : 0;
nerrors += test_query_optional() < 0 ? 1 : 0;
if (nerrors) {
printf("***** %d Virtual Object Layer TEST%s FAILED! *****\n", nerrors, nerrors > 1 ? "S" : "");
exit(EXIT_FAILURE);
}
puts("All Virtual Object Layer (VOL) tests passed.");
exit(EXIT_SUCCESS);
} /* end main() */