def get_pool(context, mode, size, name, svcn=1, log=None, connect=True): """Return a DAOS pool that has been created an connected. Args: context (DaosContext): the context to use to create the pool mode (int): the pool mode size (int): the size of the pool name (str): the name of the pool svcn (int): the pool service leader quantity log (DaosLog, optional): object for logging messages. Defaults to None. connect (bool, optional): connect to the new pool. Defaults to True. Returns: DaosPool: an object representing a DAOS pool """ if log: log.info("Creating a pool") pool = DaosPool(context) pool.create(mode, os.geteuid(), os.getegid(), size, name, svcn=svcn) if connect: if log: log.info("Connecting to the pool") pool.connect(1 << 1) return pool
def test_query(self): """Test ID: DAOS-???. Test Description: Pass bad parameters to pool query :avocado: tags=all,pool,full_regression,tiny,badquery """ # parameters used in pool create/connect connectmode = self.params.get("mode", '/run/querytests/connectmode/') createmode = self.params.get("mode", '/run/querytests/createmode/') createuid = os.geteuid() creategid = os.getegid() createsetid = self.params.get("setname", '/run/querytests/createset/') createsize = self.params.get("size", '/run/querytests/createsize/') # Accumulate a list of pass/fail indicators representing what is # expected for each parameter then "and" them to determine the # expected result of the test expected_for_param = [] handlelist = self.params.get("handle", '/run/querytests/handles/*/') handle = handlelist[0] expected_for_param.append(handlelist[1]) infolist = self.params.get("info", '/run/querytests/infoptr/*/') dummy_infoptr = infolist[0] expected_for_param.append(infolist[1]) # if any parameter is FAIL then the test should FAIL, in this test # virtually everyone should FAIL since we are testing bad parameters expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break try: # initialize a python pool object then create the underlying # daos storage pool = DaosPool(self.context) pool.create(createmode, createuid, creategid, createsize, createsetid, None) pool.connect(connectmode) # trash the pool handle value if not handle == 'VALID': pool.handle = handle pool.pool_query() if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: self.log.error(str(excep)) self.log.error(traceback.format_exc()) if expected_result in ['PASS']: self.fail("Test was expected to pass but it failed.\n")
class SimpleCreateDeleteTest(TestWithServers): """ Tests DAOS pool creation, trying both valid and invalid parameters. :avocado: recursive """ def test_create(self): """ Test basic pool creation. :avocado: tags=all,pool,smoke,full_regression,tiny,simplecreate """ # Accumulate a list of pass/fail indicators representing what is # expected for each parameter then "and" them to determine the # expected result of the test expected_for_param = [] modelist = self.params.get("mode", '/run/tests/modes/*') mode = modelist[0] expected_for_param.append(modelist[1]) uidlist = self.params.get("uid", '/run/tests/uids/*', os.geteuid()) if uidlist[0] == 'valid': uid = os.geteuid() else: uid = uidlist[0] expected_for_param.append(uidlist[1]) gidlist = self.params.get("gid", '/run/tests/gids/*', os.getegid()) if gidlist[0] == 'valid': gid = os.getegid() else: gid = gidlist[0] expected_for_param.append(gidlist[1]) setidlist = self.params.get("setname", '/run/tests/setnames/*') setid = setidlist[0] expected_for_param.append(setidlist[1]) expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break try: self.pool = DaosPool(self.context) self.pool.create(mode, uid, gid, 1073741824, setid) if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as exc: print(exc) print(traceback.format_exc()) if expected_result not in ['FAIL']: self.fail("Test was expected to pass but it failed.\n")
def test_null_values(self): """ Test ID: DAOS-1376 Test Description: Pass a dkey and an akey that is null. :avocado: tags=all,object,full_regression,small,objupdatenull """ try: # parameters used in pool create createmode = self.params.get("mode", '/run/conttests/createmode/') createsetid = self.params.get("setname", '/run/conttests/createset/') createsize = self.params.get("size", '/run/conttests/createsize/') createuid = os.geteuid() creategid = os.getegid() # initialize a python pool object then create the underlying # daos storage pool = DaosPool(self.context) pool.create(createmode, createuid, creategid, createsize, createsetid, None) self.plog.info("Pool %s created.", pool.get_uuid_str()) # need a connection to create container pool.connect(1 << 1) # create a container container = DaosContainer(self.context) container.create(pool.handle) self.plog.info("Container %s created.", container.get_uuid_str()) # now open it container.open() # data used in the test thedata = "a string that I want to stuff into an object" thedatasize = len(thedata) + 1 except DaosApiError as excep: print(excep) print(traceback.format_exc()) self.fail("Test failed during setup .\n") try: # try using a null dkey dkey = None akey = "this is the akey" container.write_an_obj(thedata, thedatasize, dkey, akey, None, None, 2) container.close() container.destroy() pool.disconnect() pool.destroy(1) self.plog.error("Didn't get expected return code.") self.fail("Test was expected to return a -1003 but it has not.\n") except DaosApiError as excep: if '-1003' not in str(excep): container.close() container.destroy() pool.disconnect() pool.destroy(1) self.plog.error("Didn't get expected return code.") print(excep) print(traceback.format_exc()) self.fail("Test was expected to get -1003 but it has not.\n") try: # try using a null akey/io descriptor dkey = "this is the dkey" akey = None container.write_an_obj(thedata, thedatasize, dkey, akey, None, None, 2) self.fail("Test was expected to return a -1003 but it has not.\n") except DaosApiError as excep: if '-1003' not in str(excep): self.plog.error("Didn't get expected return code.") print(excep) print(traceback.format_exc()) self.fail("Test was expected to get -1003 but it has not.\n") try: # lastly try passing no data thedata = None thedatasize = 0 dkey = "this is the dkey" akey = "this is the akey" container.write_an_obj(thedata, thedatasize, dkey, akey, None, None, 2) self.plog.info("Update with no data worked") except DaosApiError as excep: container.close() container.destroy() pool.disconnect() pool.destroy(1) print(excep) print(traceback.format_exc()) self.plog.error("Update with no data failed") self.fail("Update with no data failed.\n") container.close() container.destroy() pool.disconnect() pool.destroy(1) self.plog.info("Test Complete")
class Permission(TestWithServers): """Test pool permissions. Test Class Description: Tests DAOS pool permissions while connect, whether modifying file with specific permissions work as expected. :avocado: recursive """ def test_connectpermission(self): """Test ID: DAOS-???. Test Description: Test pool connections with specific permissions. :avocado: tags=pool,permission,connectpermission """ # parameters used in pool create createmode = self.params.get("mode", '/run/createtests/createmode/*/') createuid = os.geteuid() creategid = os.getegid() createsetid = self.params.get("setname", '/run/createtests/createset/') createsize = self.params.get("size", '/run/createtests/createsize/') # parameters used for pool connect permissions = self.params.get("perm", '/run/createtests/permissions/*') if createmode == 73 or \ (createmode == 146 and permissions != 1) or \ (createmode == 292 and permissions != 3): self.cancelForTicket("DAOS-3442") if createmode == 73: expected_result = 'FAIL' if createmode == 511 and permissions == 0: expected_result = 'PASS' elif createmode in [146, 511] and permissions == 1: expected_result = 'PASS' elif createmode in [292, 511] and permissions == 2: expected_result = 'PASS' else: expected_result = 'FAIL' try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.multi_log("Pool initialisation successful", "debug") self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) self.multi_log("Pool Creation successful", "debug") self.pool.connect(1 << permissions) self.multi_log("Pool Connect successful", "debug") if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: self.log.error(str(excep)) if expected_result == 'PASS': self.fail("Test was expected to pass but it failed.\n") def test_filemodification(self): """Test ID: DAOS-???. Test Description: Test whether file modification happens as expected under different permission levels. :avocado: tags=pool,permission,filemodification """ # parameters used in pool create createmode = self.params.get("mode", '/run/createtests/createmode/*/') createuid = self.params.get("uid", '/run/createtests/createuid/') creategid = self.params.get("gid", '/run/createtests/creategid/') createsetid = self.params.get("setname", '/run/createtests/createset/') createsize = self.params.get("size", '/run/createtests/createsize/') if createmode == 73: expected_result = 'FAIL' elif createmode in [146, 511]: permissions = 1 expected_result = 'PASS' elif createmode == 292: permissions = 2 expected_result = 'PASS' try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.multi_log("Pool initialisation successful", "debug") self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) self.multi_log("Pool Creation successful", "debug") self.pool.connect(1 << permissions) self.multi_log("Pool Connect successful", "debug") self.container = DaosContainer(self.context) self.multi_log("Contianer initialisation successful", "debug") self.container.create(self.pool.handle) self.multi_log("Container create successful", "debug") # now open it self.container.open() self.multi_log("Container open successful", "debug") thedata = "a string that I want to stuff into an object" size = 45 dkey = "this is the dkey" akey = "this is the akey" self.container.write_an_obj(thedata, size, dkey, akey) self.multi_log("Container write successful", "debug") if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: self.log.error(str(excep)) if expected_result == 'PASS': self.fail("Test was expected to pass but it failed.\n")
class GlobalHandle(TestWithServers): """ This class contains tests to verify the ability to share pool handles amoung processes. :avocado: recursive """ def tearDown(self): try: super(GlobalHandle, self).tearDown() finally: # really make sure everything is gone check_for_pool.cleanup_pools(self.hostlist_servers) def check_handle(self, buf_len, iov_len, buf, uuidstr, rank): """ This gets run in a child process and verifyes the global handle can be turned into a local handle in another process. """ pool = DaosPool(self.context) pool.set_uuid_str(uuidstr) pool.set_svc(rank) pool.group = "daos_server" # note that the handle is stored inside the pool as well dummy_local_handle = pool.global2local(self.context, iov_len, buf_len, buf) # perform some operations that will use the new handle pool.pool_query() container = DaosContainer(self.context) container.create(pool.handle) def test_global_handle(self): """ Test ID: DAO Test Description: Use a pool handle in another process. :avocado: tags=all,pool,pr,tiny,poolglobalhandle """ try: # use the uid/gid of the user running the test, these should # be perfectly valid createuid = os.geteuid() creategid = os.getegid() # parameters used in pool create that are in yaml createmode = self.params.get("mode", '/run/testparams/createmode/') createsetid = self.params.get("setname", '/run/testparams/createset/') createsize = self.params.get("size", '/run/testparams/createsize/') # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) self.pool.connect(1 << 1) # create a container just to make sure handle is good self.container = DaosContainer(self.context) self.container.create(self.pool.handle) # create a global handle iov_len, buf_len, buf = self.pool.local2global() # this should work in the future but need on-line server addition #arg_list = (buf_len, iov_len, buf, pool.get_uuid_str(), 0) #p = Process(target=check_handle, args=arg_list) #p.start() #p.join() # for now verifying global handle in the same process which is not # the intended use case self.check_handle(buf_len, iov_len, buf, self.pool.get_uuid_str(), 0) except DaosApiError as excep: print(excep) print(traceback.format_exc()) self.fail("Expecting to pass but test has failed.\n")
class BasicTxTest(TestWithServers): """ A very simple test verifying the use of transactions. This test was butchered in the transition from epoch to transaction. Need to revisit and make more useful when transactions are fully working. :avocado: recursive """ def test_tx_basics(self): """ Perform I/O to an object in a container in 2 different transactions, verifying basic I/O and transactions in particular. NOTE: this was an epoch test and all I did was get it working with tx Not a good test at this point, need to redesign when tx is fully working. :avocado: tags=all,container,tx,small,smoke,pr,basictx """ self.pool = None try: # parameters used in pool create createmode = self.params.get("mode", '/run/poolparams/createmode/') createuid = os.geteuid() creategid = os.getegid() createsetid = self.params.get("setname", '/run/poolparams/createset/') createsize = self.params.get("size", '/run/poolparams/createsize/') # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) # need a connection to create container self.pool.connect(1 << 1) # create a container container = DaosContainer(self.context) container.create(self.pool.handle) # now open it container.open() # do a query and compare the UUID returned from create with # that returned by query container.query() if container.get_uuid_str() != c_uuid_to_str( container.info.ci_uuid): self.fail("Container UUID did not match the one in info\n") # create an object and write some data into it thedata = "a string that I want to stuff into an object" thedatasize = 45 dkey = "this is the dkey" akey = "this is the akey" oid, txn = container.write_an_obj(thedata, thedatasize, dkey, akey, None, None, 2) # read the data back and make sure its correct thedata2 = container.read_an_obj(thedatasize, dkey, akey, oid, txn) if thedata != thedata2.value: print("thedata>" + thedata) print("thedata2>" + thedata2.value) self.fail("Write data 1, read it back, didn't match\n") # repeat above, but know that the write_an_obj call is advancing # the epoch so the original copy remains and the new copy is in # a new epoch. thedata3 = "a different string" thedatasize2 = 19 # note using the same keys so writing to the same spot dkey = "this is the dkey" akey = "this is the akey" oid, tx2 = container.write_an_obj(thedata3, thedatasize2, dkey, akey, oid, None, 2) # read the data back and make sure its correct thedata4 = container.read_an_obj(thedatasize2, dkey, akey, oid, tx2) if thedata3 != thedata4.value: self.fail("Write data 2, read it back, didn't match\n") # transactions generally don't work this way but need to explore # an alternative to below code once model is complete, maybe # read from a snapshot or read from TX_NONE etc. # the original data should still be there too #thedata5 = container.read_an_obj(thedatasize, dkey, akey, # oid, transaction) #if thedata != thedata5.value: # self.fail("Write data 3, read it back, didn't match\n") container.close() # wait a few seconds and then destroy time.sleep(5) container.destroy() except DaosApiError as excep: print(excep) print(traceback.format_exc()) self.fail("Test was expected to pass but it failed.\n")
class GlobalHandle(TestWithServers): """ This class contains tests to verify the ability to share container handles amoung processes. :avocado: recursive """ def tearDown(self): try: super(GlobalHandle, self).tearDown() finally: # really make sure everything is gone check_for_pool.cleanup_pools(self.hostlist_servers) @fail_on(DaosApiError) def check_handle(self, pool_glob_handle, uuidstr, cont_glob_handle, rank): """ This gets run in a child process and verifyes the global handles can be turned into local handles in another process. """ # setup the pool and connect using global handle pool = DaosPool(self.context) pool.uuid = uuidstr pool.set_svc(rank) pool.group = "daos_server" buf = ctypes.cast( pool_glob_handle.iov_buf, ctypes.POINTER(ctypes.c_byte * pool_glob_handle.iov_buf_len)) buf2 = bytearray() buf2.extend(buf.contents) pool_handle = pool.global2local(self.context, pool_glob_handle.iov_len, pool_glob_handle.iov_buf_len, buf2) # perform an operation that will use the new handle, if it # doesn't throw an exception, then all is well. pool.pool_query() # setup the container and then connect using the global handle container = DaosContainer(self.context) container.poh = pool_handle buf = ctypes.cast( cont_glob_handle.iov_buf, ctypes.POINTER(ctypes.c_byte * cont_glob_handle.iov_buf_len)) buf2 = bytearray() buf2.extend(buf.contents) dummy_cont_handle = container.global2local( self.context, cont_glob_handle.iov_len, cont_glob_handle.iov_buf_len, buf2) # just try one thing to make sure handle is good container.query() def test_global_handle(self): """ Test ID: DAO Test Description: Use a pool handle in another process. :avocado: tags=all,container,tiny,pr,conthandle """ try: # use the uid/gid of the user running the test, these should # be perfectly valid createuid = os.geteuid() creategid = os.getegid() # parameters used in pool create that are in yaml createmode = self.params.get("mode", '/run/testparams/createmode/') createsetid = self.params.get("setname", '/run/testparams/createset/') createsize = self.params.get("size", '/run/testparams/createsize/') # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) self.pool.connect(1 << 1) # create a pool global handle iov_len, buf_len, buf = self.pool.local2global() buftype = ctypes.c_byte * buf_len c_buf = buftype.from_buffer(buf) sct_pool_handle = (sharedctypes.RawValue( IOV, ctypes.cast(c_buf, ctypes.c_void_p), buf_len, iov_len)) # create a container self.container = DaosContainer(self.context) self.container.create(self.pool.handle) self.container.open() # create a container global handle iov_len, buf_len, buf = self.container.local2global() buftype = ctypes.c_byte * buf_len c_buf = buftype.from_buffer(buf) sct_cont_handle = (sharedctypes.RawValue( IOV, ctypes.cast(c_buf, ctypes.c_void_p), buf_len, iov_len)) sct_pool_uuid = sharedctypes.RawArray(ctypes.c_byte, self.pool.uuid) # this should work in the future but need on-line server addition #arg_list = ( #p = Process(target=check_handle, args=arg_list) #p.start() #p.join() # for now verifying global handle in the same process which is not # the intended use case self.check_handle(sct_pool_handle, sct_pool_uuid, sct_cont_handle, 0) except DaosApiError as excep: print(excep) print(traceback.format_exc()) self.fail("Expecting to pass but test has failed.\n")
class LlnlMpi4pyHdf5(TestWithServers): """ Runs LLNL, MPI4PY and HDF5 test suites. :avocado: recursive """ def __init__(self, *args, **kwargs): """Initialize a TestWithServers object.""" super(LlnlMpi4pyHdf5, self).__init__(*args, **kwargs) self.hostfile_clients_slots = None self.mpio = None def setUp(self): super(LlnlMpi4pyHdf5, self).setUp() try: # parameters used in pool create createmode = self.params.get("mode", '/run/pool/createmode/*/') createuid = os.geteuid() creategid = os.getegid() createsetid = self.params.get("setname", '/run/pool/createset/') createsize = self.params.get("size", '/run/pool/createsize/') self.createsvc = self.params.get("svcn", '/run/pool/createsvc/') # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None, None, self.createsvc) except (DaosApiError) as excep: self.fail("<Test Failed at pool create> \n{}".format(excep)) def run_test(self, test_repo, test_name): """ Executable function to be used by test functions below test_repo --location of test repository test_name --name of the test to be run """ # initialize MpioUtils self.mpio = MpioUtils() if not self.mpio.mpich_installed(self.hostlist_clients): self.fail("Exiting Test: Mpich not installed") try: # initialise test specific variables client_processes = self.params.get("np", '/run/client_processes/') # obtaining pool uuid and svc list pool_uuid = self.pool.get_uuid_str() svc_list = "" for i in range(self.createsvc): svc_list += str(int(self.pool.svc.rl_ranks[i])) + ":" svc_list = svc_list[:-1] # running tests self.mpio.run_llnl_mpi4py_hdf5(self.hostfile_clients, pool_uuid, test_repo, test_name, client_processes) # Parsing output to look for failures # stderr directed to stdout stdout = self.logdir + "/stdout" searchfile = open(stdout, "r") error_message = [ "non-zero exit code", "MPI_Abort", "MPI_ABORT", "ERROR" ] for line in searchfile: # pylint: disable=C0200 for i in range(len(error_message)): if error_message[i] in line: self.fail("Test Failed with error_message: {}".format( error_message[i])) except (MpioFailed, DaosApiError) as excep: self.fail("<{0} Test Failed> \n{1}".format(test_name, excep))
class OpenClose(TestWithServers): """ Tests DAOS container open/close function with handle parameter. :avocado: recursive """ def test_closehandle(self): """ Test container close function with container handle paramter. :avocado: tags=all,smoke,full_regression,tiny,container,closehandle """ self.container = [] saved_coh = None # parameters used in pool create createmode = self.params.get("mode", '/run/pool/createmode/') createuid = os.geteuid() creategid = os.getegid() createsetid = self.params.get("setname", '/run/pool/createset/') createsize = self.params.get("size", '/run/pool/createsize/') coh_params = self.params.get("coh", '/run/container/container_handle/*/') expected_result = coh_params[1] try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) poh = self.pool.handle self.pool.connect(1 << 1) # Container initialization and creation self.container.append(DaosContainer(self.context)) self.container[0].create(poh) str_cuuid = self.container[0].get_uuid_str() cuuid = uuid.UUID(str_cuuid) self.container[0].open(poh, cuuid, 2, None) # Defining 'good' and 'bad' container handles saved_coh = self.container[0].coh if coh_params[0] == 'GOOD': coh = self.container[0].coh else: # create a second container, open to get a handle # then close & destroy so handle is invalid self.container.append(DaosContainer(self.context)) self.container[1].create(poh) self.container[1].open(poh, cuuid, 2, None) coh = self.container[1].coh self.container[1].close() self.container[1].destroy() # close container with either good or bad handle self.container[0].close(coh) if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: if expected_result == 'PASS': print(excep) print(traceback.format_exc()) self.fail("Test was expected to pass but it failed.\n") # close above failed so close for real with the right coh if saved_coh is not None: self.container[0].close(saved_coh)
def test_connect(self): """ Pass bad parameters to pool connect :avocado: tags=all,pool,full_regression,tiny,badconnect """ # parameters used in pool create createmode = self.params.get("mode", '/run/connecttests/createmode/') createuid = self.params.get("uid", '/run/connecttests/uids/createuid/') creategid = self.params.get("gid", '/run/connecttests/gids/creategid/') createsetid = self.params.get("setname", '/run/connecttests/setnames/createset/') createsize = self.params.get("size", '/run/connecttests/psize/createsize/') # Accumulate a list of pass/fail indicators representing what is # expected for each parameter then "and" them to determine the # expected result of the test expected_for_param = [] modelist = self.params.get("mode", '/run/connecttests/connectmode/*/') connectmode = modelist[0] expected_for_param.append(modelist[1]) svclist = self.params.get("ranklist", '/run/connecttests/svrlist/*/') svc = svclist[0] expected_for_param.append(svclist[1]) setlist = self.params.get("setname", '/run/connecttests/connectsetnames/*/') connectset = setlist[0] expected_for_param.append(setlist[1]) uuidlist = self.params.get("uuid", '/run/connecttests/UUID/*/') connectuuid = uuidlist[0] expected_for_param.append(uuidlist[1]) # if any parameter is FAIL then the test should FAIL, in this test # virtually everyone should FAIL since we are testing bad parameters expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break puuid = (ctypes.c_ubyte * 16)() psvc = RankList() pgroup = ctypes.create_string_buffer(0) pool = None try: # initialize a python pool object then create the underlying # daos storage pool = DaosPool(self.context) pool.create(createmode, createuid, creategid, createsize, createsetid, None) # save this uuid since we might trash it as part of the test ctypes.memmove(puuid, pool.uuid, 16) # trash the the pool service rank list psvc.rl_ranks = pool.svc.rl_ranks psvc.rl_nr = pool.svc.rl_nr if not svc == 'VALID': rl_ranks = ctypes.POINTER(ctypes.c_uint)() pool.svc = RankList(rl_ranks, 1) # trash the pool group value pgroup = pool.group if connectset == 'NULLPTR': pool.group = None # trash the UUID value in various ways if connectuuid == 'NULLPTR': pool.uuid = None if connectuuid == 'JUNK': pool.uuid[4] = 244 pool.connect(connectmode) if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: print(excep) print(traceback.format_exc()) if expected_result in ['PASS']: self.fail("Test was expected to pass but it failed.\n") # cleanup the pool finally: if pool is not None and pool.attached == 1: # restore values in case we trashed them during test pool.svc.rl_ranks = psvc.rl_ranks pool.svc.rl_nr = psvc.rl_nr pool.group = pgroup ctypes.memmove(pool.uuid, puuid, 16) print("pool uuid after restore {}".format(pool.get_uuid_str())) pool.disconnect() pool.destroy(1)
class SameKeyDifferentValue(TestWithServers): """ Test Description: Test to verify different type of values passed to same akey and dkey. :avocado: recursive """ def setUp(self): try: super(SameKeyDifferentValue, self).setUp() # parameters used in pool create createmode = self.params.get("mode", '/run/pool/createmode/') createsetid = self.params.get("setname", '/run/pool/createset/') createsize = self.params.get("size", '/run/pool/createsize/') createuid = os.geteuid() creategid = os.getegid() # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) self.pool.connect(1 << 1) # create a container self.container = DaosContainer(self.context) self.container.create(self.pool.handle) # now open it self.container.open() except DaosApiError as excpn: print(excpn) print(traceback.format_exc()) self.fail("Test failed during setup.\n") def test_single_to_array_value(self): """ Jira ID: DAOS-2218 Test Description: Test to verify different type of values passed (i.e. single to array value) to the same akey and dkey. Case1: Insert akey,dkey with single value Insert same akey,dkey with array value Result: should return -1001 ERR. Case2: Insert akey,dkey with single value Punch the keys Insert same akey,dkey under same object with array value Result: should either pass or return -1001 ERR Case3: Insert akey,dkey with single value Punch the keys Trigger aggregation Insert same akey,dkey under same object with array value Result: should either pass or return -1001 ERR :avocado: tags=object,samekeydifferentvalue,singletoarray,vm,small """ # define akey,dkey, single value data and array value data single_value_data = "a string that I want to stuff into an object" array_value_data = [] array_value_data.append("data string one") array_value_data.append("data string two") array_value_data.append("data string tre") dkey = "this is the dkey" akey = "this is the akey" aggregation = False for i in range(3): try: # create an object and write single value data into it obj, txn = self.container.write_an_obj(single_value_data, len(single_value_data)+1, dkey, akey, obj_cls=1) # read the data back and make sure its correct read_back_data = self.container.read_an_obj( len(single_value_data)+1, dkey, akey, obj, txn) if single_value_data != read_back_data.value: print("data I wrote:" + single_value_data) print("data I read back" + read_back_data.value) self.fail("Write data, read it back, didn't match\n") # test case 1 if i == 0: try: # write array value data to same keys, expected to fail self.container.write_an_array_value(array_value_data, dkey, akey, obj, obj_cls=1) # above line is expected to return an error, # if not fail the test self.fail("Array value write to existing single value" + " key should have failed\n") # should fail with -1001 ERR except DaosApiError as excp: if "-1001" not in str(excp): print(excp) self.fail("Should have failed with -1001 error" + " message, but it did not\n") # test case 2 and 3 elif i == 1 or 2: try: # punch the keys obj.punch_akeys(0, dkey, [akey]) obj.punch_dkeys(0, [dkey]) if aggregation is True: # trigger aggregation self.container.aggregate(self.container.coh, 0) # write to the same set of keys under same object # with array value type self.container.write_an_array_value(array_value_data, dkey, akey, obj, obj_cls=1) # above write of array value should either succeed # or fail with -1001 ERR except DaosApiError as excp: if "-1001" not in str(excp): print(excp) self.fail("Should have failed with -1001 error" + " message or the write should have" + " been successful, but it did not\n") # change the value of aggregation to test Test Case 3 aggregation = True # punch the entire object after each iteration obj.close() # catch the exception if test fails to write to an object # or fails to punch the written object except DaosApiError as excp: self.fail("Failed to write to akey/dkey or punch the object") def test_array_to_single_value(self): """ Jira ID: DAOS-2218 Test Description: Test to verify different type of values passed (i.e array to single value) to the same akey and dkey. Case1: Insert akey,dkey with array value Insert same akey,dkey with single value Result: should return -1001 ERR. Case2: Insert akey,dkey with array value Punch the keys Insert same akey,dkey under same object with single value Result: should either pass or return -1001 ERR Case3: Insert akey,dkey with array value Punch the keys Trigger aggregation Insert same akey,dkey under same object with single value Result: should either pass or return -1001 ERR :avocado: tags=object,samekeydifferentvalue,arraytosingle,vm,small """ # define akey,dkey, single value data and array value data single_value_data = "a string that I want to stuff into an object" array_value_data = [] array_value_data.append("data string one") array_value_data.append("data string two") array_value_data.append("data string tre") dkey = "this is the dkey" akey = "this is the akey" aggregation = False for i in range(3): try: # create an object and write array value data into it obj, txn = self.container.write_an_array_value(array_value_data, dkey, akey, obj_cls=1) # read the data back and make sure its correct length = len(array_value_data[0]) read_back_data = self.container.read_an_array( len(array_value_data), length + 1, dkey, akey, obj, txn) for j in range(3): if (array_value_data[j][0:length-1] != read_back_data[j][0:length-1]): print("Written Data: {}".format(array_value_data[j])) print("Read Data: {}".format(read_back_data[j])) self.fail("Data mismatch\n") # test case 1 if i == 0: try: # write single value data to same keys, expected to fail self.container.write_an_obj(single_value_data, len(single_value_data)+1, dkey, akey, obj, obj_cls=1) # above line is expected to return an error, # if not fail the test self.fail("Single value write to existing array value" + " key should have failed\n") # should fail with -1001 ERR except DaosApiError as excp: if "-1001" not in str(excp): print(excp) self.fail("Should have failed with -1001 error" + " message, but it did not\n") # test case 2 and 3 elif i == 1 or 2: try: # punch the keys obj.punch_akeys(0, dkey, [akey]) obj.punch_dkeys(0, [dkey]) if aggregation is True: # trigger aggregation self.container.aggregate(self.container.coh, 0) # write to the same set of keys under same object # with single value type self.container.write_an_obj(single_value_data, len(single_value_data)+1, dkey, akey, obj, obj_cls=1) # above write of array value should either succeed # or fail with -1001 ERR except DaosApiError as excp: if "-1001" not in str(excp): print(excp) self.fail("Should have failed with -1001 error" + " message or the write should have" + " been successful, but it did not\n") # change the value of aggregation to test Test Case 3 aggregation = True # punch the entire object after each iteration obj.close() # catch the exception if test fails to write to an object # or fails to punch the written object except DaosApiError as excp: self.fail("Failed to write to akey/dkey or punch the object")
def test_create(self): """Test ID: DAOS-???. Test Description: Pass bad parameters to pool create. :avocado: tags=all,pool,full_regression,tiny,badcreate """ # Accumulate a list of pass/fail indicators representing what is # expected for each parameter then "and" them to determine the # expected result of the test pool = None expected_for_param = [] modelist = self.params.get("mode", '/run/createtests/modes/*') mode = modelist[0] expected_for_param.append(modelist[1]) uidlist = self.params.get("uid", '/run/createtests/uids/*') uid = uidlist[0] if uid == 'VALID': uid = os.geteuid() expected_for_param.append(uidlist[1]) gidlist = self.params.get("gid", '/run/createtests/gids/*') gid = gidlist[0] if gid == 'VALID': gid = os.getegid() expected_for_param.append(gidlist[1]) setidlist = self.params.get("setname", '/run/createtests/setnames/*') if setidlist[0] == 'NULLPTR': group = None self.cancel("skipping this test until DAOS-1991 is fixed") else: group = setidlist[0] expected_for_param.append(setidlist[1]) targetlist = self.params.get("rankptr", '/run/createtests/target/*') if targetlist[0] == 'NULL': targetptr = None else: targetptr = [0] expected_for_param.append(targetlist[1]) # not ready for this yet # devicelist = self.params.get("devptr", '/run/createtests/device/*') # if devicelist[0] == 'NULL': # devptr = None # else: # devptr = devicelist[0] # expected_for_param.append(devicelist[1]) sizelist = self.params.get("size", '/run/createtests/psize/*') size = sizelist[0] expected_for_param.append(sizelist[1]) # parameter not presently supported # svclist = self.params.get("rankptr", '/run/createtests/svc/*') # if svclist[0] == 'NULL': # svc = None # else: # svc = None # expected_for_param.append(devicelist[1]) # if any parameter is FAIL then the test should FAIL, in this test # virtually everyone should FAIL since we are testing bad parameters expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break try: # initialize a python pool object then create the underlying # daos storage pool = DaosPool(self.context) pool.create(mode, uid, gid, size, group, targetptr) if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: self.log.error(str(excep)) self.log.error(traceback.format_exc()) if expected_result == 'PASS': self.fail("Test was expected to pass but it failed.\n") finally: if pool is not None and pool.attached: pool.destroy(1)
def test_exclude(self): """ Pass bad parameters to pool connect :avocado: tags=all,pool,full_regression,tiny,badexclude """ # parameters used in pool create createmode = self.params.get("mode", '/run/pool/createmode/') createsetid = self.params.get("setname", '/run/pool/createset/') createsize = self.params.get("size", '/run/pool/createsize/') createuid = os.geteuid() creategid = os.getegid() # Accumulate a list of pass/fail indicators representing what is # expected for each parameter then "and" them to determine the # expected result of the test expected_for_param = [] tgtlist = self.params.get("ranklist", '/run/testparams/tgtlist/*/') targets = [] if tgtlist[0] == "NULLPTR": targets = None self.cancel("skipping null pointer test until DAOS-1929 is fixed") else: targets.append(tgtlist[0]) expected_for_param.append(tgtlist[1]) svclist = self.params.get("ranklist", '/run/testparams/svrlist/*/') svc = svclist[0] expected_for_param.append(svclist[1]) setlist = self.params.get("setname", '/run/testparams/connectsetnames/*/') connectset = setlist[0] expected_for_param.append(setlist[1]) uuidlist = self.params.get("uuid", '/run/testparams/UUID/*/') excludeuuid = uuidlist[0] expected_for_param.append(uuidlist[1]) # if any parameter is FAIL then the test should FAIL, in this test # virtually everyone should FAIL since we are testing bad parameters expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break saved_svc = None saved_grp = None saved_uuid = None pool = None try: # initialize a python pool object then create the underlying # daos storage pool = DaosPool(self.context) pool.create(createmode, createuid, creategid, createsize, createsetid, None) # trash the the pool service rank list if not svc == 'VALID': self.cancel("skipping this test until DAOS-1931 is fixed") saved_svc = RankList(pool.svc.rl_ranks, pool.svc.rl_nr) pool.svc = None # trash the pool group value if connectset == 'NULLPTR': saved_grp = pool.group pool.group = None # trash the UUID value in various ways if excludeuuid == 'NULLPTR': self.cancel("skipping this test until DAOS-1932 is fixed") ctypes.memmove(saved_uuid, pool.uuid, 16) pool.uuid = 0 if excludeuuid == 'CRAP': self.cancel("skipping this test until DAOS-1932 is fixed") ctypes.memmove(saved_uuid, pool.uuid, 16) pool.uuid[4] = 244 pool.exclude(targets) if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: print(excep) print(traceback.format_exc()) if expected_result in ['PASS']: self.fail("Test was expected to pass but it failed.\n") finally: if pool is not None: if saved_svc is not None: pool.svc = saved_svc if saved_grp is not None: pool.group = saved_grp if saved_uuid is not None: ctypes.memmove(pool.uuid, saved_uuid, 16) pool.destroy(1)
class BasicSnapshot(TestWithServers): """DAOS-1370 Basic snapshot test. Test Class Description: Test that a snapshot taken of a container remains unchaged even after an object in the container has been updated 500 times. Create the container. Write an object to the container. Take a snapshot. Write 500 changes to the KV pair of the object. Check that the snapshot is still there. Confirm that the data in the snapshot is unchanged. Destroy the snapshot :avocado: recursive """ def __init__(self, *args, **kwargs): """Initialize a BasicSnapshot object.""" super(BasicSnapshot, self).__init__(*args, **kwargs) self.snapshot = None def test_basic_snapshot(self): """Test ID: DAOS-1370. Test Description: Create a pool, container in the pool, object in the container, add one key:value to the object. Commit the transaction. Perform a snapshot create on the container. Create 500 additional transactions with a small change to the object in each and commit each after the object update is done. Verify the snapshot is still available and the contents remain in their original state. :avocado: tags=snap,basicsnap """ # Set up the pool and container. try: # parameters used in pool create createmode = self.params.get("mode", '/run/pool/createmode/') createsetid = self.params.get("setname", '/run/pool/createset/') createsize = self.params.get("size", '/run/pool/createsize/*') createuid = os.geteuid() creategid = os.getegid() # initialize a pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) # need a connection to create container self.pool.connect(1 << 1) # create a container self.container = DaosContainer(self.context) self.container.create(self.pool.handle) # now open it self.container.open() except DaosApiError as error: self.log.error(str(error)) self.fail("Test failed before snapshot taken") try: # create an object and write some data into it obj_cls = self.params.get("obj_class", '/run/object_class/*') thedata = "Now is the winter of our discontent made glorious" datasize = len(thedata) + 1 dkey = "dkey" akey = "akey" tx_handle = self.container.get_new_tx() obj = self.container.write_an_obj(thedata, datasize, dkey, akey, obj_cls=obj_cls, txn=tx_handle) self.container.commit_tx(tx_handle) obj.close() # Take a snapshot of the container self.snapshot = DaosSnapshot(self.context) self.snapshot.create(self.container.coh, tx_handle) self.log.info("Wrote an object and created a snapshot") except DaosApiError as error: self.fail( "Test failed during the initial object write.\n{0}".format( error)) # Make 500 changes to the data object. The write_an_obj function does a # commit when the update is complete try: self.log.info( "Committing 500 additional transactions to the same KV") more_transactions = 500 while more_transactions: size = random.randint(1, 250) + 1 new_data = get_random_string(size) new_obj = self.container.write_an_obj(new_data, size, dkey, akey, obj_cls=obj_cls) new_obj.close() more_transactions -= 1 except DaosApiError as error: self.fail( "Test failed during the write of 500 objects.\n{0}".format( error)) # List the snapshot try: reported_epoch = self.snapshot.list(self.container.coh) except DaosApiError as error: self.fail( "Test was unable to list the snapshot\n{0}".format(error)) # Make sure the snapshot reflects the original epoch if self.snapshot.epoch != reported_epoch: self.fail( "The snapshot epoch returned from snapshot list is not the " "same as the original epoch snapshotted.") self.log.info( "After 500 additional commits the snapshot is still available") # Make sure the data in the snapshot is the original data. # Get a handle for the snapshot and read the object at dkey, akey. try: obj.open() snap_handle = self.snapshot.open(self.container.coh) thedata2 = self.container.read_an_obj(datasize, dkey, akey, obj, txn=snap_handle.value) except DaosApiError as error: self.fail( "Error when retrieving the snapshot data.\n{0}".format(error)) # Compare the snapshot to the originally written data. if thedata2.value != thedata: self.fail( "The data in the snapshot is not the same as the original data" ) self.log.info("The snapshot data matches the data originally written.") # Now destroy the snapshot try: self.snapshot.destroy(self.container.coh) self.log.info("Snapshot successfully destroyed") except DaosApiError as error: self.fail(str(error))
class LlnlMpi4pyHdf5(TestWithServers): """ Runs LLNL, MPI4PY and HDF5 test suites. :avocado: recursive """ def setUp(self): super(LlnlMpi4pyHdf5, self).setUp() # initialising variables self.mpio = None self.hostfile_clients = None # setting client variables self.hostfile_clients = write_host_file.write_host_file( self.hostlist_clients, self.workdir, None) try: # parameters used in pool create createmode = self.params.get("mode", '/run/pool/createmode/*/') createuid = os.geteuid() creategid = os.getegid() createsetid = self.params.get("setname", '/run/pool/createset/') createsize = self.params.get("size", '/run/pool/createsize/') self.createsvc = self.params.get("svcn", '/run/pool/createsvc/') # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None, None, self.createsvc) except (DaosApiError) as excep: self.fail("<Test Failed at pool create> \n{1}".format(excep)) def run_test(self, test_repo, test_name): """ Executable function to be used by test functions below test_repo --location of test repository test_name --name of the test to be run """ # initialize MpioUtils self.mpio = MpioUtils() if not self.mpio.mpich_installed(self.hostlist_clients): self.fail("Exiting Test: Mpich not installed") try: # initialise test specific variables client_processes = self.params.get("np", '/run/client_processes/') # obtaining pool uuid and svc list pool_uuid = self.pool.get_uuid_str() svc_list = "" for i in range(self.createsvc): svc_list += str(int(self.pool.svc.rl_ranks[i])) + ":" svc_list = svc_list[:-1] # running tests self.mpio.run_llnl_mpi4py_hdf5(self.basepath, self.hostfile_clients, pool_uuid, test_repo, test_name, client_processes) # Parsing output to look for failures # stderr directed to stdout stdout = self.logdir + "/stdout" searchfile = open(stdout, "r") error_message = [ "non-zero exit code", "MPI_Abort", "MPI_ABORT", "ERROR" ] for line in searchfile: # pylint: disable=C0200 for i in range(len(error_message)): if error_message[i] in line: self.fail("Test Failed with error_message: {}".format( error_message[i])) except (MpioFailed, DaosApiError) as excep: self.fail("<{0} Test Failed> \n{1}".format(test_name, excep)) @skipForTicket("CORCI-635") def test_llnl(self): """ Jira ID: DAOS-2231 Test Description: Run LLNL test suite. Testing various I/O functions provided in llnl test suite such as:- test_collective, test_datareps, test_errhandlers, test_filecontrol, test_localpointer, test_manycomms, test_manyopens, test_openclose, test_openmodes, test_nb_collective, test_nb_localpointer, test_nb_rdwr, test_nb_readwrite, test_rdwr, test_readwrite :avocado: tags=all,mpiio,smoke,pr,small,llnlmpi4py """ test_repo = self.params.get("llnl", '/run/test_repo/') self.run_test(test_repo, "llnl") @skipForTicket("CORCI-635") def test_mpi4py(self): """ Jira ID: DAOS-2231 Test Description: Run mpi4py io test provided in mpi4py package Testing various I/O functions provided in mpi4py test suite such as:- testReadWriteAt, testIReadIWriteAt, testReadWrite testIReadIWrite, testReadWriteAtAll, testIReadIWriteAtAll testReadWriteAtAllBeginEnd, testReadWriteAll testIReadIWriteAll, testReadWriteAllBeginEnd :avocado: tags=all,mpiio,pr,small,llnlmpi4py,mpi4py """ test_repo = self.params.get("mpi4py", '/run/test_repo/') self.run_test(test_repo, "mpi4py") @skipForTicket("CORCI-635") def test_hdf5(self): """ Jira ID: DAOS-2252 Test Description: Run HDF5 testphdf5 and t_shapesame provided in HDF5 package. Testing various I/O functions provided in HDF5 test suite such as:- test_fapl_mpio_dup, test_split_comm_access, test_page_buffer_access, test_file_properties, dataset_writeInd, dataset_readInd, dataset_writeAll, dataset_readAll, extend_writeInd, extend_readInd, extend_writeAll, extend_readAll,extend_writeInd2,none_selection_chunk, zero_dim_dset, multiple_dset_write, multiple_group_write, multiple_group_read, compact_dataset, collective_group_write, independent_group_read, big_dataset, coll_chunk1, coll_chunk2, coll_chunk3, coll_chunk4, coll_chunk5, coll_chunk6, coll_chunk7, coll_chunk8, coll_chunk9, coll_chunk10, coll_irregular_cont_write, coll_irregular_cont_read, coll_irregular_simple_chunk_write, coll_irregular_simple_chunk_read , coll_irregular_complex_chunk_write, coll_irregular_complex_chunk_read , null_dataset , io_mode_confusion, rr_obj_hdr_flush_confusion, chunk_align_bug_1,lower_dim_size_comp_test, link_chunk_collective_io_test, actual_io_mode_tests, no_collective_cause_tests, test_plist_ed, file_image_daisy_chain_test, test_dense_attr, test_partial_no_selection_coll_md_read :avocado: tags=mpio,llnlmpi4pyhdf5,hdf5 """ test_repo = self.params.get("hdf5", '/run/test_repo/') self.run_test(test_repo, "hdf5")
def test_bad_handle(self): """ Test ID: DAOS-1376 Test Description: Pass a bogus object handle, should return bad handle. :avocado: tags=all,object,full_regression,small,objbadhand """ try: # parameters used in pool create createmode = self.params.get("mode", '/run/conttests/createmode/') createsetid = self.params.get("setname", '/run/conttests/createset/') createsize = self.params.get("size", '/run/conttests/createsize/') createuid = os.geteuid() creategid = os.getegid() # initialize a python pool object then create the underlying # daos storage pool = DaosPool(self.context) pool.create(createmode, createuid, creategid, createsize, createsetid, None) self.plog.info("Pool %s created.", pool.get_uuid_str()) # need a connection to create container pool.connect(1 << 1) # create a container container = DaosContainer(self.context) container.create(pool.handle) self.plog.info("Container %s created.", container.get_uuid_str()) # now open it container.open() # create an object and write some data into it thedata = "a string that I want to stuff into an object" thedatasize = len(thedata) + 1 dkey = "this is the dkey" akey = "this is the akey" obj, dummy_tx = container.write_an_obj(thedata, thedatasize, dkey, akey, None, None, 2) saved_oh = obj.obj_handle obj.obj_handle = 99999 obj, dummy_tx = container.write_an_obj(thedata, thedatasize, dkey, akey, obj, None, 2) container.oh = saved_oh container.close() container.destroy() pool.disconnect() pool.destroy(1) self.fail("Test was expected to return a -1002 but it has not.\n") except DaosApiError as excep: container.oh = saved_oh container.close() container.destroy() pool.disconnect() pool.destroy(1) self.plog.info("Test Complete") if '-1002' not in str(excep): print(excep) print(traceback.format_exc()) self.fail("Test was expected to get -1002 but it has not.\n")
class DeleteContainerTest(TestWithServers): """ Tests DAOS container delete and close. :avocado: recursive """ def setUp(self): super(DeleteContainerTest, self).setUp() # parameters used in pool create self.createmode = self.params.get("mode", '/run/createtests/createmode/') self.createuid = os.geteuid() self.creategid = os.getegid() self.createsetid = self.params.get("setname", '/run/createtests/createset/') self.createsize = self.params.get("size", '/run/createtests/createsize/') def test_container_delete(self): """ Test basic container delete :avocado: tags=all,container,tiny,smoke,pr,contdelete """ expected_for_param = [] uuidlist = self.params.get("uuid", '/run/createtests/ContainerUUIDS/*/') cont_uuid = uuidlist[0] expected_for_param.append(uuidlist[1]) pohlist = self.params.get("poh", '/run/createtests/PoolHandles/*/') poh = pohlist[0] expected_for_param.append(pohlist[1]) openlist = self.params.get("opened", "/run/createtests/ConnectionOpened/*/") opened = openlist[0] expected_for_param.append(openlist[1]) forcelist = self.params.get("force", "/run/createtests/ForceDestroy/*/") force = forcelist[0] expected_for_param.append(forcelist[1]) if force >= 1: self.cancel("Force >= 1 blocked by issue described in " "https://jira.hpdd.intel.com/browse/DAOS-689") if force == 0: self.cancel("Force = 0 blocked by " "https://jira.hpdd.intel.com/browse/DAOS-1935") expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(self.createmode, self.createuid, self.creategid, self.createsize, self.createsetid, None) # need a connection to create container self.pool.connect(1 << 1) self.container = DaosContainer(self.context) # create should always work (testing destroy) if not cont_uuid == 'INVALID': cont_uuid = uuid.UUID(uuidlist[0]) self.container.create(self.pool.handle, cont_uuid) else: self.container.create(self.pool.handle) # Opens the container if required if opened: self.container.open(self.pool.handle) # wait a few seconds and then attempts to destroy container time.sleep(5) if poh == 'VALID': poh = self.pool.handle # if container is INVALID, overwrite with non existing UUID if cont_uuid == 'INVALID': cont_uuid = uuid.uuid4() self.container.destroy(force=force, poh=poh, con_uuid=cont_uuid) self.container = None if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: self.d_log.error(excep) self.d_log.error(traceback.format_exc()) if expected_result == 'PASS': self.fail("Test was expected to pass but it failed.\n")
class ContainerAttributeTest(TestWithServers): """ Tests DAOS container attribute get/set/list. :avocado: recursive """ def setUp(self): super(ContainerAttributeTest, self).setUp() self.large_data_set = {} self.pool = DaosPool(self.context) self.pool.create( self.params.get("mode", '/run/attrtests/createmode/*'), os.geteuid(), os.getegid(), self.params.get("size", '/run/attrtests/createsize/*'), self.params.get("setname", '/run/attrtests/createset/*'), None) self.pool.connect(1 << 1) poh = self.pool.handle self.container = DaosContainer(self.context) self.container.create(poh) self.container.open() def create_data_set(self): """ To create the large attribute dictionary """ allchar = string.ascii_letters + string.digits for i in range(1024): self.large_data_set[str(i)] = ("".join( random.choice(allchar) for x in range(random.randint(1, 100)))) def test_container_large_attributes(self): """ Test ID: DAOS-1359 Test description: Test large randomly created container attribute. :avocado: tags=container,container_attr,attribute,large_conattribute """ self.create_data_set() attr_dict = self.large_data_set try: self.container.set_attr(data=attr_dict) size, buf = self.container.list_attr() verify_list_attr(attr_dict, size, buf) results = {} results = self.container.get_attr(attr_dict.keys()) verify_get_attr(attr_dict, results) except DaosApiError as excep: print(excep) print(traceback.format_exc()) self.fail("Test was expected to pass but it failed.\n") def test_container_attribute(self): """ Test basic container attribute tests. :avocado: tags=all,tiny,full_regression,container,sync_conattribute """ expected_for_param = [] name = self.params.get("name", '/run/attrtests/name_handles/*/') expected_for_param.append(name[1]) value = self.params.get("value", '/run/attrtests/value_handles/*/') expected_for_param.append(value[1]) attr_dict = {name[0]: value[0]} expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break try: self.container.set_attr(data=attr_dict) size, buf = self.container.list_attr() verify_list_attr(attr_dict, size, buf) # Request something that doesn't exist if name[0] is not None and "Negative" in name[0]: name[0] = "rubbish" results = {} results = self.container.get_attr([name[0]]) verify_get_attr(attr_dict, results) if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except (DaosApiError, DaosTestError) as excep: print(excep) print(traceback.format_exc()) if expected_result == 'PASS': self.fail("Test was expected to pass but it failed.\n") def test_container_attribute_asyn(self): """ Test basic container attribute tests. :avocado: tags=all,small,full_regression,container,async_conattribute """ global GLOB_SIGNAL global GLOB_RC expected_for_param = [] name = self.params.get("name", '/run/attrtests/name_handles/*/') expected_for_param.append(name[1]) value = self.params.get("value", '/run/attrtests/value_handles/*/') expected_for_param.append(value[1]) attr_dict = {name[0]: value[0]} expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break try: GLOB_SIGNAL = threading.Event() self.container.set_attr(data=attr_dict, cb_func=cb_func) GLOB_SIGNAL.wait() if GLOB_RC != 0 and expected_result in ['PASS']: self.fail("RC not as expected after set_attr First {0}".format( GLOB_RC)) GLOB_SIGNAL = threading.Event() size, buf = self.container.list_attr(cb_func=cb_func) GLOB_SIGNAL.wait() if GLOB_RC != 0 and expected_result in ['PASS']: self.fail( "RC not as expected after list_attr First {0}".format( GLOB_RC)) if expected_result in ['PASS']: verify_list_attr(attr_dict, size, buf, mode="async") # Request something that doesn't exist if name[0] is not None and "Negative" in name[0]: name[0] = "rubbish" GLOB_SIGNAL = threading.Event() self.container.get_attr([name[0]], cb_func=cb_func) GLOB_SIGNAL.wait() if GLOB_RC != 0 and expected_result in ['PASS']: self.fail( "RC not as expected after get_attr {0}".format(GLOB_RC)) # not verifying the get_attr since its not available asynchronously if value[0] is not None: if GLOB_RC == 0 and expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: print(excep) print(traceback.format_exc()) if expected_result == 'PASS': self.fail("Test was expected to pass but it failed.\n")
class ObjOpenBadParam(TestWithServers): """ Test Class Description: Pass an assortment of bad parameters to the daos_obj_open function. :avocado: recursive """ def setUp(self): super(ObjOpenBadParam, self).setUp() try: # parameters used in pool create createmode = self.params.get("mode", '/run/pool/createmode/') createsetid = self.params.get("setname", '/run/pool/createset/') createsize = self.params.get("size", '/run/pool/createsize/') createuid = os.geteuid() creategid = os.getegid() # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) # need a connection to create container self.pool.connect(1 << 1) # create a container self.container = DaosContainer(self.context) self.container.create(self.pool.handle) # now open it self.container.open() # create an object and write some data into it thedata = "a string that I want to stuff into an object" self.datasize = len(thedata) + 1 self.dkey = "this is the dkey" self.akey = "this is the akey" self.obj = self.container.write_an_obj(thedata, self.datasize, self.dkey, self.akey, obj_cls=1) thedata2 = self.container.read_an_obj(self.datasize, self.dkey, self.akey, self.obj) if thedata not in thedata2.value: print(thedata) print(thedata2.value) err_str = "Error reading back data, test failed during the " \ "initial setup." self.d_log.error(err_str) self.fail(err_str) # setup leaves object in open state, so closing to start clean self.obj.close() except DaosApiError as excep: print(excep) print(traceback.format_exc()) self.fail("Test failed during the initial setup.") def test_bad_obj_handle(self): """ Test ID: DAOS-1320 Test Description: Attempt to open a garbage object handle. :avocado: tags=all,object,full_regression,tiny,objopenbadhandle """ saved_handle = self.obj.obj_handle self.obj.obj_handle = 8675309 try: dummy_obj = self.obj.open() except DaosApiError as excep: if '-1002' not in str(excep): self.d_log.error("test expected a -1002 but did not get it") self.d_log.error(traceback.format_exc()) self.fail("test expected a -1002 but did not get it") finally: self.obj.obj_handle = saved_handle def test_invalid_container_handle(self): """ Test ID: DAOS-1320 Test Description: Attempt to open an object with a garbage container handle. :avocado: tags=all,object,full_regression,tiny,objopenbadcont """ saved_coh = self.container.coh self.container.coh = 8675309 try: dummy_obj = self.obj.open() except DaosApiError as excep: if '-1002' not in str(excep): self.d_log.error("test expected a -1002 but did not get it") self.d_log.error(traceback.format_exc()) self.fail("test expected a -1002 but did not get it") finally: self.container.coh = saved_coh def test_closed_container_handle(self): """ Test ID: DAOS-1320 Test Description: Attempt to open an object in a container with a closed handle. :avocado: tags=all,object,full_regression,tiny,objopenclosedcont """ self.container.close() try: dummy_obj = self.obj.open() except DaosApiError as excep: if '-1002' not in str(excep): self.d_log.error("test expected a -1002 but did not get it") self.d_log.error(traceback.format_exc()) self.fail("test expected a -1002 but did not get it") finally: self.container.open() def test_pool_handle_as_obj_handle(self): """ Test ID: DAOS-1320 Test Description: Adding this test by request, this test attempts to open an object that's had its handle set to be the same as a valid pool handle. :avocado: tags=all,object,full_regression,tiny,objopenbadpool """ saved_oh = self.obj.obj_handle self.obj.obj_handle = self.pool.handle try: dummy_obj = self.obj.open() except DaosApiError as excep: if '-1002' not in str(excep): self.d_log.error("test expected a -1002 but did not get it") self.d_log.error(traceback.format_exc()) self.fail("test expected a -1002 but did not get it") finally: self.obj.obj_handle = saved_oh def test_null_ranklist(self): """ Test ID: DAOS-1320 Test Description: Attempt to open an object in a container with an empty ranklist. :avocado: tags=all,object,full_regression,tiny,objopennullrl """ # null rl saved_rl = self.obj.tgt_rank_list self.obj.tgt_rank_list = None try: dummy_obj = self.obj.open() except DaosApiError as excep: if '-1003' not in str(excep): self.d_log.error("test expected a -1003 but did not get it") self.d_log.error(traceback.format_exc()) self.fail("test expected a -1003 but did not get it") finally: self.obj.tgt_rank_list = saved_rl def test_null_oid(self): """ Test ID: DAOS-1320 Test Description: Attempt to open an object in a container with null object id. :avocado: tags=all,object,full_regression,tiny,objopennulloid """ # null oid saved_oid = self.obj.c_oid self.obj.c_oid = DaosObjId(0, 0) try: dummy_obj = self.obj.open() except DaosApiError as excep: if '-1003' not in str(excep): self.d_log.error("Test expected a -1003 but did not get it") self.d_log.error(traceback.format_exc()) self.fail("test expected a -1003 but did not get it") finally: self.obj.c_oid = saved_oid def test_null_tgts(self): """ Test ID: DAOS-1320 Test Description: Attempt to open an object in a container with null tgt. :avocado: tags=all,object,full_regression,tiny,objopennulltgts """ # null tgts saved_ctgts = self.obj.c_tgts self.obj.c_tgts = 0 try: dummy_obj = self.obj.open() except DaosApiError as excep: if '-1003' not in str(excep): self.d_log.error("Test expected a -1003 but did not get it") self.d_log.error(traceback.format_exc()) self.fail("test expected a -1003 but did not get it") finally: self.obj.c_tgts = saved_ctgts def test_null_attrs(self): """ Test ID: DAOS-1320 Test Description: Attempt to open an object in a container with null object attributes. :avocado: tags=all,object,full_regression,tiny,objopennullattr """ # null attr saved_attr = self.obj.attr self.obj.attr = 0 try: dummy_obj = self.obj.open() except DaosApiError as excep: if '-1003' not in str(excep): self.d_log.error("test expected a -1003 but did not get it") self.d_log.error(traceback.format_exc()) self.fail("test expected a -1003 but did not get it") finally: self.obj.attr = saved_attr
def test_container_create(self): """ Test ID: DAOS-689 Test Description: valid and invalid container creation and close. :avocado: tags=all,container,tiny,smoke,full_regression,containercreate """ pool = None contuuid = None expected_results = [] try: # initialize a python pool object then create the underlying # daos storage createmode = self.params.get("mode", '/run/poolparams/') createuid = os.geteuid() creategid = os.getegid() createsetid = self.params.get("setname", '/run/poolparams/') createsize = self.params.get("size", '/run/poolparams/') # setup the pool pool = DaosPool(self.context) pool.create(createmode, createuid, creategid, createsize, createsetid) pool.connect(1 << 1) # maybe use the good handle, maybe not handleparam = self.params.get("handle", '/run/poolhandle/*') if handleparam == 'VALID': poh = pool.handle else: poh = handleparam expected_results.append('FAIL') # maybe use a good UUID, maybe not uuidparam = self.params.get("uuid", "/uuids/*") expected_results.append(uuidparam[1]) if uuidparam[0] == 'NULLPTR': self.cancel("skipping this test until DAOS-2043 is fixed") # Commenting the line below as it will result in an # AttributeError and never get to the DAOS API code. # Should be further investigated as part of DAOS-3081 # contuuid = 'NULLPTR' else: contuuid = uuid.UUID(uuidparam[0]) should_fail = False for result in expected_results: if result == 'FAIL': should_fail = True break self.container = DaosContainer(self.context) self.container.create(poh, contuuid) # check UUID is the specified one if (uuidparam[0]).upper() != self.container.get_uuid_str().upper(): print("uuidparam[0] is {}, uuid_str is {}".format( uuidparam[0], self.container.get_uuid_str())) self.fail("Container UUID differs from specified at create\n") if should_fail: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: print(excep) print(traceback.format_exc()) if not should_fail: self.fail("Test was expected to pass but it failed.\n")
class PoolAttributeTest(TestWithServers): """ Test class Description: Tests DAOS pool attribute get/set/list. :avocado: recursive """ def setUp(self): super(PoolAttributeTest, self).setUp() self.large_data_set = {} createmode = self.params.get("mode", '/run/attrtests/createmode/') createuid = os.geteuid() creategid = os.getgid() createsetid = self.params.get("setname", '/run/attrtests/createset/') createsize = self.params.get("size", '/run/attrtests/createsize/') try: self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid) self.pool.connect(1 << 1) except DaosApiError as excep: print("In the setup exception handler\n") print(excep) print(traceback.format_exc()) def create_data_set(self): """ To create the large attribute dictionary """ allchar = string.ascii_letters + string.digits for i in range(1024): self.large_data_set[str(i)] = ("".join( random.choice(allchar) for x in range(random.randint(1, 100)))) def test_pool_large_attributes(self): """ Test ID: DAOS-1359 Test description: Test large randomly created pool attribute. :avocado: tags=regression,pool,pool_attr,attribute,large_poolattribute """ self.create_data_set() attr_dict = self.large_data_set try: self.pool.set_attr(data=attr_dict) size, buf = self.pool.list_attr() verify_list_attr(attr_dict, size.value, buf) results = {} results = self.pool.get_attr(attr_dict.keys()) verify_get_attr(attr_dict, results) except DaosApiError as excep: print(excep) print(traceback.format_exc()) self.fail("Test was expected to pass but it failed.\n") def test_pool_attributes(self): """ Test ID: DAOS-1359 Test description: Test basic pool attribute tests (sync). :avocado: tags=all,pool,pr,tiny,sync_poolattribute """ expected_for_param = [] name = self.params.get("name", '/run/attrtests/name_handles/*/') expected_for_param.append(name[1]) value = self.params.get("value", '/run/attrtests/value_handles/*/') expected_for_param.append(value[1]) expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break attr_dict = {name[0]: value[0]} try: self.pool.set_attr(data=attr_dict) size, buf = self.pool.list_attr() verify_list_attr(attr_dict, size.value, buf) if name[0] is not None: # Request something that doesn't exist if "Negative" in name[0]: name[0] = "rubbish" results = {} results = self.pool.get_attr([name[0]]) verify_get_attr(attr_dict, results) if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: print(excep) print(traceback.format_exc()) if expected_result == 'PASS': self.fail("Test was expected to pass but it failed.\n") def test_pool_attribute_asyn(self): """ Test ID: DAOS-1359 Test description: Test basic pool attribute tests (async). :avocado: tags=all,pool,full_regression,tiny,async_poolattribute """ global GLOB_SIGNAL global GLOB_RC expected_for_param = [] name = self.params.get("name", '/run/attrtests/name_handles/*/') # workaround until async functions are fixed if name[0] is not None and "Negative" in name[0]: pass else: expected_for_param.append(name[1]) value = self.params.get("value", '/run/attrtests/value_handles/*/') expected_for_param.append(value[1]) expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break attr_dict = {name[0]: value[0]} try: GLOB_SIGNAL = threading.Event() self.pool.set_attr(attr_dict, None, cb_func) GLOB_SIGNAL.wait() if expected_result == 'PASS' and GLOB_RC != 0: self.fail( "RC not as expected after set_attr {0}".format(GLOB_RC)) if expected_result == 'FAIL' and GLOB_RC == 0: self.fail( "RC not as expected after set_attr {0}".format(GLOB_RC)) except DaosApiError as excep: print(excep) print(traceback.format_exc()) if expected_result == 'PASS': self.fail("Test was expected to pass but it failed.\n")
def test_array_obj(self): """ Test ID: DAOS-961 Test Description: Writes an array to an object and then reads it back and verifies it. :avocado: tags=all,smoke,pr,object,tiny,basicobject """ try: # parameters used in pool create createmode = self.params.get("mode", '/run/pool_params/createmode/') createsetid = self.params.get("setname", '/run/pool_params/createset/') createsize = self.params.get("size", '/run/pool_params/createsize/') createuid = os.geteuid() creategid = os.getegid() # initialize a python pool object then create the underlying # daos storage pool = DaosPool(self.context) pool.create(createmode, createuid, creategid, createsize, createsetid, None) self.plog.info("Pool %s created.", pool.get_uuid_str()) # need a connection to create container pool.connect(1 << 1) # create a container container = DaosContainer(self.context) container.create(pool.handle) self.plog.info("Container %s created.", container.get_uuid_str()) # now open it container.open() # do a query and compare the UUID returned from create with # that returned by query container.query() if container.get_uuid_str() != c_uuid_to_str( container.info.ci_uuid): self.fail("Container UUID did not match the one in info\n") # create an object and write some data into it thedata = [] thedata.append("data string one") thedata.append("data string two") thedata.append("data string tre") dkey = "this is the dkey" akey = "this is the akey" self.plog.info("writing array to dkey >%s< akey >%s<.", dkey, akey) oid, epoch = container.write_an_array_value(thedata, dkey, akey, obj_cls=3) # read the data back and make sure its correct length = len(thedata[0]) thedata2 = container.read_an_array(len(thedata), length + 1, dkey, akey, oid, epoch) if thedata[0][0:length - 1] != thedata2[0][0:length - 1]: self.plog.error("Data mismatch") self.plog.error("Wrote: >%s<", thedata[0]) self.plog.error("Read: >%s<", thedata2[0]) self.fail("Write data, read it back, didn't match\n") if thedata[2][0:length - 1] != thedata2[2][0:length - 1]: self.plog.error("Data mismatch") self.plog.error("Wrote: >%s<", thedata[2]) self.plog.error("Read: >%s<", thedata2[2]) self.fail("Write data, read it back, didn't match\n") container.close() # wait a few seconds and then destroy time.sleep(5) container.destroy() # cleanup the pool pool.disconnect() pool.destroy(1) self.plog.info("Test Complete") except DaosApiError as excep: self.plog.error("Test Failed, exception was thrown.") print(excep) print(traceback.format_exc()) self.fail("Test was expected to pass but it failed.\n")
class Snapshot(TestWithServers): """ Epic: DAOS-2249 Create system level tests that cover basic snapshot functionality. Testcase: DAOS-1370 Basic snapshot test DAOS-1386 Test container SnapShot information DAOS-1371 Test list snapshots DAOS-1395 Test snapshot destroy DAOS-1402 Test creating multiple snapshots Test Class Description: Start DAOS servers, set up the pool and container for the above snapshot Epic and Testcases, including snapshot basic, container information, list, creation and destroy. :avocado: recursive """ def setUp(self): """ set up method """ super(Snapshot, self).setUp() # get parameters from yaml file, set default createmode = self.params.get("mode", '/run/poolparams/createmode/', 511) createuid = os.geteuid() creategid = os.getegid() createsetid = self.params.get("setname", '/run/poolparams/createset/') createsize = self.params.get("size", '/run/poolparams/createsize/') self.log.info("==In setUp, self.context= %s", self.context) try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) # need a connection to the pool with rw permission # DAOS_PC_RO = int(1 << 0) # DAOS_PC_RW = int(1 << 1) # DAOS_PC_EX = int(1 << 2) self.pool.connect(1 << 1) # create a container self.container = DaosContainer(self.context) self.container.create(self.pool.handle) except DaosApiError as error: self.log.info("Error detected in DAOS pool container setup: %s", str(error)) self.log.info(traceback.format_exc()) self.fail("##Test failed on setUp, before snapshot taken") # now open it self.container.open() # do a query and compare the UUID returned from create with # that returned by query self.container.query() if self.container.get_uuid_str() != c_uuid_to_str( self.container.info.ci_uuid): self.fail("##Container UUID did not match the one in info.") def display_snapshot(self, snapshot): """ To display the snapshot information. Args: snapshot: snapshot handle to be displayed. Return: none. """ self.log.info("==display_snapshot================") self.log.info("snapshot= %s", snapshot) self.log.info("snapshot.context= %s", snapshot.context) self.log.info("snapshot.context.libdaos= %s", snapshot.context.libdaos) self.log.info("snapshot.context.libtest= %s", snapshot.context.libtest) self.log.info("snapshot.context.ftable= %s", snapshot.context.ftable) self.log.info("snapshot.context.ftable[list-attr]= %s", snapshot.context.ftable["list-attr"]) self.log.info("snapshot.context.ftable[test-event]=%s", snapshot.context.ftable["test-event"]) self.log.info("snapshot.name= %s", snapshot.name) self.log.info("snapshot.epoch= %s", snapshot.epoch) self.log.info("==================================") def take_snapshot(self, container, epoch): """ To take a snapshot on the container with current epoch. Args: container: container for the snapshot epoch: the container epoch for the snapshot Return: An object representing the snapshot """ self.log.info("==Taking snapshot for:") self.log.info(" coh= %s", container.coh) self.log.info(" epoch= %s", epoch) snapshot = DaosSnapshot(self.context) snapshot.create(container.coh, epoch) self.display_snapshot(snapshot) return snapshot def invalid_snapshot_test(self, coh, epoch): """ Negative snapshot test with invalid container handle or epoch. Args: container: container for the snapshot epoch: the container epoch for the snapshot Return: 0: Failed 1: Passed (expected failure detected) """ status = 0 try: snapshot = DaosSnapshot(self.context) snapshot.create(coh, epoch) except Exception as error: self.log.info("==>Negative test, expected error: %s", str(error)) status = 1 return status def test_snapshot_negativecases(self): """ Test ID: DAOS-1390 Verify snap_create bad parameter behavior. DAOS-1322 Create a new container, verify snapshot state. as expected for a brand new container. DAOS-1392 Verify snap_destroy bad parameter behavior. DAOS-1388 Verify snap_list bad parameter behavior. Test Description: (0)Take a snapshot of the newly created container. (1)Create an object, write random data into it, and take a snapshot. (2)Verify the snapshot is working properly. (3)Test snapshot with an invalid container handle. (4)Test snapshot with a NULL container handle. (5)Test snapshot with an invalid epoch. (6)Verify snap_destroy with a bad parameter. (7)Verify snap_list bad parameter behavior. Use Cases: Combinations with minimun 1 client and 1 server. :avocado: tags=all,small,smoke,pr,snap,snapshot_negative, :avocado: tags=snapshotcreate_negative """ #DAOS-1322 Create a new container, verify snapshot state as expected # for a brand new container. try: self.log.info( "==(0)Take a snapshot of the newly created container.") snapshot = DaosSnapshot(self.context) snapshot.create(self.container.coh, 0) self.display_snapshot(snapshot) except Exception as error: self.fail("##(0)Error on a snapshot on a new container %s", str(error)) #(1)Create an object, write some data into it, and take a snapshot obj_cls = self.params.get("obj_class", '/run/object_class/*') akey = self.params.get("akey", '/run/snapshot/*', default="akey") dkey = self.params.get("dkey", '/run/snapshot/*', default="dkey") data_size = self.params.get("test_datasize", '/run/snapshot/*', default=150) rand_str = lambda n: ''.join( [random.choice(string.lowercase) for i in xrange(n)]) thedata = "--->>>Happy Daos Snapshot-Create Negative Testing " + \ "<<<---" + rand_str(random.randint(1, data_size)) try: tx_handle = self.container.get_new_tx() obj = self.container.write_an_obj(thedata, len(thedata) + 1, dkey, akey, obj_cls=obj_cls, txn=tx_handle) self.container.commit_tx(tx_handle) except DaosApiError as error: self.fail("##(1)Test failed during the initial object write: %s", str(error)) obj.close() ##Take a snapshot of the container snapshot = self.take_snapshot(self.container, tx_handle) self.log.info("==(1)Container epoch= %s", tx_handle) self.log.info(" snapshot.epoch= %s", snapshot.epoch) #(2)Verify the snapshot is working properly. try: obj.open() snap_handle = snapshot.open(self.container.coh, snapshot.epoch) thedata2 = self.container.read_an_obj(len(thedata) + 1, dkey, akey, obj, txn=snap_handle.value) except Exception as error: self.fail("##(2)Error when retrieving the snapshot data: %s", str(error)) self.log.info("==(2)snapshot_list[ind]=%s", snapshot) self.log.info("==snapshot.epoch= %s", snapshot.epoch) self.log.info("==written thedata=%s", thedata) self.log.info("==thedata2.value= %s", thedata2.value) if thedata2.value != thedata: raise Exception("##(2)The data in the snapshot is not the " "same as the original data") self.log.info("==Snapshot data matches the data originally " "written.") #(3)Test snapshot with an invalid container handle self.log.info("==(3)Snapshot with an invalid container handle.") if self.invalid_snapshot_test(self.container, tx_handle): self.log.info( "==>Negative test 1, expecting failed on taking " "snapshot with an invalid container.coh: %s", self.container) else: self.fail( "##(3)Negative test 1 passing, expecting failed on" " taking snapshot with an invalid container.coh: %s", self.container) #(4)Test snapshot with a NULL container handle self.log.info("==(4)Snapshot with a NULL container handle.") if self.invalid_snapshot_test(None, tx_handle): self.log.info("==>Negative test 2, expecting failed on taking " "snapshot on a NULL container.coh.") else: self.fail("##(4)Negative test 2 passing, expecting failed on " "taking snapshot with a NULL container.coh.") #(5)Test snapshot with an invalid epoch self.log.info("==(5)Snapshot with a NULL epoch.") if self.invalid_snapshot_test(self.container.coh, None): self.log.info("==>Negative test 3, expecting failed on taking " "snapshot with a NULL epoch.") else: self.fail("##(5)Negative test 3 passing, expecting failed on " "taking snapshot with a NULL epoch.") #(6)DAOS-1392 destroy snapshot with an invalid handle self.log.info( "==(6)DAOS-1392 destroy snapshot with an invalid handle.") try: snapshot.destroy(None, tx_handle) self.fail("##(6)Negative test destroy snapshot with an " "invalid coh handle, expected fail, shown Passing##") except Exception as error: self.log.info( "==>Negative test, destroy snapshot with an invalid handle.") self.log.info(" Expected Error: %s", str(error)) expected_error = "RC: -1002" if expected_error not in str(error): self.fail("##(6.1)Expecting error RC: -1002 did not show.") #(7)DAOS-1388 Verify snap_list bad parameter behavior self.log.info( "==(7)DAOS-1388 Verify snap_list bad parameter behavior.") try: snapshot.list(None, 0) self.fail("##(7)Negative test snapshot list with an " "invalid coh and epoch, expected fail, shown Passing##") except Exception as error: self.log.info( "==>Negative test, snapshot list with an invalid coh.") self.log.info(" Expected Error: %s", str(error)) expected_error = "RC: -1002" if expected_error not in str(error): self.fail("##(7.1)Expecting error RC: -1002 did not show.") def display_snapshot_test_data(self, test_data, ss_index): """Display the snapshot test data. Args: test_data: list of snapshot testdata dictionary keys: coh: container handle container_epoch: container epoch snapshot: snapshot handle tst_obj: test object tst_data: test data ss_index: snapshot-list index to be displayed. """ if len(test_data) < ss_index - 1: self.log.info("##Under to display test_data info, " "index out of range.") else: ind = ss_index - 1 self.log.info(" =Snapshot number : %s", ss_index) self.log.info(" ==container_coh =%s", test_data[ind]["coh"]) self.log.info(" ==container_epoch =%s", test_data[ind]["container_epoch"]) self.log.info(" ==snapshot =%s", test_data[ind]["snapshot"]) self.log.info(" ==snapshot.epoch =%s", test_data[ind]["snapshot"].epoch) self.log.info(" ==data obj =%s", test_data[ind]["tst_obj"]) self.log.info(" ==snapshot tst_data_size= %s", len(test_data[ind]["tst_data"]) + 1) self.log.info(" ==original tst_data =%s", test_data[ind]["tst_data"]) return def test_snapshots(self): """ Test ID: DAOS-1386 Test container SnapShot information DAOS-1371 Test list snapshots DAOS-1395 Test snapshot destroy DAOS-1402 Test creating multiple snapshots Test Description: (1)Create an object, write random data into it, and take a snapshot. (2)Make changes to the data object. The write_an_obj function does a commit when the update is complete. (3)Verify the data in the snapshot is the original data. Get a handle for the snapshot and read the object at dkey, akey. Compare it to the originally written data. (4)List the snapshot and make sure it reflects the original epoch. ==>Repeat step(1) to step(4) for multiple snapshot tests. (5)Verify the snapshots data. (6)Destroy the snapshot individually. (7)Check if still able to Open the destroyed snapshot and Verify the snapshot removed from the snapshot list. (8)Destroy the container snapshot. Use Cases: Require 1 client and 1 server to run snapshot test. 1 pool and 1 container is used, num_of_snapshot defined in the snapshot.yaml will be performed and verified. :avocado: tags=all,small,smoke,snap,snapshots,full_regression """ test_data = [] ss_number = 0 obj_cls = self.params.get("obj_class", '/run/object_class/*') akey = self.params.get("akey", '/run/snapshot/*', default="akey") dkey = self.params.get("dkey", '/run/snapshot/*', default="dkey") data_size = self.params.get("test_datasize", '/run/snapshot/*', default=150) snapshot_loop = self.params.get("num_of_snapshot", '/run/snapshot/*', default=3) rand_str = lambda n: ''.join( [random.choice(string.lowercase) for i in xrange(n)]) # #Test loop for creat, modify and snapshot object in the DAOS container. # while ss_number < snapshot_loop: #(1)Create an object, write some data into it, and take a snapshot ss_number += 1 thedata = "--->>>Happy Daos Snapshot Testing " + \ str(ss_number) + \ "<<<---" + rand_str(random.randint(1, data_size)) datasize = len(thedata) + 1 try: tx_handle = self.container.get_new_tx() obj = self.container.write_an_obj(thedata, datasize, dkey, akey, obj_cls=obj_cls, txn=tx_handle) self.container.commit_tx(tx_handle) obj.close() except DaosApiError as error: self.fail("##(1)Test failed during the initial object " "write: {}".format(str(error))) #Take a snapshot of the container snapshot = DaosSnapshot(self.context) snapshot.create(self.container.coh, tx_handle) self.log.info("==Wrote an object and created a snapshot") #Display snapshot self.log.info("=(1.%s)snapshot test loop: %s", ss_number, ss_number) self.log.info(" ==self.container epoch= %s", tx_handle) self.log.info(" ==snapshot.epoch= %s", snapshot.epoch) self.display_snapshot(snapshot) #Save snapshot test data test_data.append({ "coh": self.container.coh, "container_epoch": tx_handle, "tst_obj": obj, "snapshot": snapshot, "tst_data": thedata }) #(2)Make changes to the data object. The write_an_obj function does # a commit when the update is complete num_transactions = more_transactions = 200 self.log.info( "=(2.%s)Committing %d additional transactions to " "the same KV.", ss_number, more_transactions) while more_transactions: size = random.randint(1, 250) + 1 new_data = rand_str(size) try: new_obj = self.container.write_an_obj(new_data, size, dkey, akey, obj_cls=obj_cls) new_obj.close() except Exception as error: self.fail("##(2)Test failed during the write of " "multi-objects: {}".format(str(error))) more_transactions -= 1 #(3)Verify the data in the snapshot is the original data. # Get a handle for the snapshot and read the object at dkey, akey # Compare it to the originally written data. self.log.info("=(3.%s)snapshot test loop: %s", ss_number, ss_number) try: obj.open() snap_handle = snapshot.open(self.container.coh, snapshot.epoch) thedata3 = self.container.read_an_obj(datasize, dkey, akey, obj, txn=snap_handle.value) obj.close() except Exception as error: self.fail("##(3.1)Error when retrieving the snapshot data: {}". format(str(error))) self.display_snapshot_test_data(test_data, ss_number) self.log.info(" ==thedata3.value= %s", thedata3.value) if thedata3.value != thedata: raise Exception("##(3.2)The data in the snapshot is not the " "same as the original data") self.log.info(" ==The snapshot data matches the data originally" " written.") #(4)List the snapshot and make sure it reflects the original epoch try: ss_list = snapshot.list(self.container.coh, tx_handle) self.log.info("=(4.%s)snapshot.list(self.container.coh)= %s", ss_number, ss_list) self.log.info(" ==snapshot.epoch= %s", snapshot.epoch) self.log.info(" ==container epoch= %s", tx_handle) except Exception as error: self.fail( "##(4)Test was unable to list the snapshot: {}".format( str(error))) self.log.info( " ==After %s additional commits the snapshot is " "still available", num_transactions) #(5)Verify the snapshots data for ind in range(len(test_data)): ss_number = ind + 1 self.log.info("=(5.%s)Verify the snapshot number %s:", ss_number, ss_number) self.display_snapshot_test_data(test_data, ss_number) coh = test_data[ind]["coh"] epoch = test_data[ind]["container_epoch"] current_ss = test_data[ind]["snapshot"] obj = test_data[ind]["tst_obj"] tst_data = test_data[ind]["tst_data"] datasize = len(tst_data) + 1 try: obj.open() snap_handle5 = snapshot.open(coh, current_ss.epoch) thedata5 = self.container.read_an_obj(datasize, dkey, akey, obj, txn=snap_handle5.value) obj.close() except Exception as error: self.fail("##(5.1)Error when retrieving the snapshot data: {}". format(str(error))) self.log.info(" ==snapshot tst_data =%s", thedata5.value) if thedata5.value != tst_data: raise Exception( "##(5.2)Snapshot #%s, test data Mis-matches" "the original data written.", ss_number) self.log.info( " snapshot test number %s, test data matches" " the original data written.", ss_number) #(6)Destroy the individual snapshot self.log.info("=(6.%s)Destroy the snapshot epoch: %s", ss_number, epoch) try: snapshot.destroy(coh, epoch) self.log.info(" ==snapshot epoch %s successfully destroyed", epoch) except Exception as error: self.fail("##(6)Error on snapshot.destroy: {}".format( str(error))) #(7)Check if still able to Open the destroyed snapshot and # Verify the snapshot removed from the snapshot list try: obj.open() snap_handle7 = snapshot.open(coh, snapshot.epoch) thedata7 = self.container.read_an_obj(datasize, dkey, akey, obj, txn=snap_handle7.value) obj.close() except Exception as error: self.fail( "##(7)Error when retrieving the snapshot data: {}".format( str(error))) self.log.info("=(7)=>thedata_after_snapshot.destroyed.value= %s", thedata7.value) self.log.info(" ==>snapshot.epoch= %s", snapshot.epoch) #Still able to open the snapshot and read data after destroyed. try: ss_list = snapshot.list(coh, epoch) self.log.info(" -->snapshot.list(coh, epoch)= %s", ss_list) except Exception as error: self.fail("##(7)Error when calling the snapshot list: {}".format( str(error))) #(8)Destroy the snapshot on the container try: snapshot.destroy(coh) self.log.info("=(8)Container snapshot destroyed successfully.") except Exception as error: self.fail("##(8)Error on snapshot.destroy. {}".format(str(error))) self.log.info("===DAOS container Multiple snapshots test passed.")
class PunchTest(TestWithServers): """ Simple test to verify the 3 different punch calls. :avocado: recursive """ def setUp(self): try: super(PunchTest, self).setUp() # parameters used in pool create createmode = self.params.get("mode", '/run/pool/createmode/') createsetid = self.params.get("setname", '/run/pool/createset/') createsize = self.params.get("size", '/run/pool/createsize/') createuid = os.geteuid() creategid = os.getegid() # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) self.pool.connect(1 << 1) # create a container self.container = DaosContainer(self.context) self.container.create(self.pool.handle) # now open it self.container.open() except DaosApiError as excpn: print(excpn) print(traceback.format_exc()) self.fail("Test failed during setup.\n") def test_dkey_punch(self): """ The most basic test of the dkey punch function. :avocado: tags=all,object,pr,small,dkeypunch """ try: # create an object and write some data into it thedata = "a string that I want to stuff into an object" dkey = "this is the dkey" akey = "this is the akey" obj, txn = self.container.write_an_obj(thedata, len(thedata) + 1, dkey, akey, obj_cls=1) # read the data back and make sure its correct thedata2 = self.container.read_an_obj( len(thedata) + 1, dkey, akey, obj, txn) if thedata != thedata2.value: print("data I wrote:" + thedata) print("data I read back" + thedata2.value) self.fail("Wrote data, read it back, didn't match\n") # now punch this data, should fail, can't punch committed data obj.punch_dkeys(txn, [dkey]) # expecting punch of commit data above to fail self.fail("Punch should have failed but it didn't.\n") # expecting an exception so do nothing except DaosApiError as dummy_e: pass try: # now punch this data obj.punch_dkeys(0, [dkey]) # this one should work so error if exception occurs except DaosApiError as dummy_e: self.fail("Punch should have worked.\n") # there are a bunch of other cases to test here, # --test punching the same updating and punching the same data in # the same tx, should fail # --test non updated data in an open tx, should work def test_akey_punch(self): """ The most basic test of the akey punch function. :avocado: tags=all,object,pr,small,akeypunch """ try: # create an object and write some data into it dkey = "this is the dkey" data1 = [("this is akey 1", "this is data value 1"), ("this is akey 2", "this is data value 2"), ("this is akey 3", "this is data value 3")] obj, txn = self.container.write_multi_akeys(dkey, data1, obj_cls=1) # read back the 1st epoch's data and check 1 value just to make sure # everything is on the up and up readbuf = [(data1[0][0], len(data1[0][1]) + 1), (data1[1][0], len(data1[1][1]) + 1), (data1[2][0], len(data1[2][1]) + 1)] retrieved_data = self.container.read_multi_akeys( dkey, readbuf, obj, txn) if retrieved_data[data1[1][0]] != data1[1][1]: print("middle akey: {}".format(retrieved_data[data1[1][0]])) self.fail("data retrieval failure") # now punch one akey from this data obj.punch_akeys(txn, dkey, [data1[1][0]]) # expecting punch of commit data above to fail self.fail("Punch should have failed but it didn't.\n") # expecting an exception so do nothing except DaosApiError as excep: print(excep) try: # now punch the object without a tx obj.punch_akeys(0, dkey, [data1[1][0]]) # expecting it to work this time so error except DaosApiError as excep: self.fail("Punch should have worked: {}\n".format(excep)) def test_obj_punch(self): """ The most basic test of the object punch function. Really similar to above except the whole object is deleted. :avocado: tags=all,object,pr,small,objpunch """ try: # create an object and write some data into it thedata = "a string that I want to stuff into an object" dkey = "this is the dkey" akey = "this is the akey" obj, txn = self.container.write_an_obj(thedata, len(thedata) + 1, dkey, akey, obj_cls=1) # read the data back and make sure its correct thedata2 = self.container.read_an_obj( len(thedata) + 1, dkey, akey, obj, txn) if thedata != thedata2.value: print("data I wrote:" + thedata) print("data I read back" + thedata2.value) self.fail("Wrote data, read it back, didn't match\n") # now punch the object, commited so not expecting it to work obj.punch(txn) # expecting punch of commit data above to fail self.fail("Punch should have failed but it didn't.\n") # expecting an exception so do nothing except DaosApiError as excep: print(excep) try: obj.punch(0) # expecting it to work without a tx except DaosApiError as excep: print(excep) self.fail("Punch should have worked.\n")
class FullPoolContainerCreate(TestWithServers): """ Class for test to create a container in a pool with no remaining free space. :avocado: recursive """ def __init__(self, *args, **kwargs): super(FullPoolContainerCreate, self).__init__(*args, **kwargs) self.cont = None self.cont2 = None @skipForTicket("DAOS-3142") def test_no_space_cont_create(self): """ :avocado: tags=all,container,tiny,full_regression,fullpoolcontcreate """ # full storage rc err = "-1007" # probably should be -1007, revisit later err2 = "-1009" # create pool self.pool = DaosPool(self.context) mode = self.params.get("mode", '/conttests/createmode/') self.d_log.debug("mode is {0}".format(mode)) uid = os.geteuid() gid = os.getegid() # 16 mb pool, minimum size currently possible size = 16777216 self.d_log.debug("creating pool") self.pool.create(mode, uid, gid, size, self.server_group, None) self.d_log.debug("created pool") # connect to the pool self.d_log.debug("connecting to pool") self.pool.connect(1 << 1) self.d_log.debug("connected to pool") # query the pool self.d_log.debug("querying pool info") dummy_pool_info = self.pool.pool_query() self.d_log.debug("queried pool info") # create a container try: self.d_log.debug("creating container") self.cont = DaosContainer(self.context) self.cont.create(self.pool.handle) self.d_log.debug("created container") except DaosApiError as excep: self.d_log.error("caught exception creating container: " "{0}".format(excep)) self.fail("caught exception creating container: {0}".format(excep)) self.d_log.debug("opening container") self.cont.open() self.d_log.debug("opened container") # generate random dkey, akey each time # write 1mb until no space, then 1kb, etc. to fill pool quickly for obj_sz in [1048576, 10240, 10, 1]: write_count = 0 while True: self.d_log.debug("writing obj {0}, sz {1} to " "container".format(write_count, obj_sz)) my_str = "a" * obj_sz my_str_sz = obj_sz dkey = (''.join( random.choice(string.lowercase) for i in range(5))) akey = (''.join( random.choice(string.lowercase) for i in range(5))) try: dummy_oid = self.cont.write_an_obj(my_str, my_str_sz, dkey, akey, obj_cls="OC_SX") self.d_log.debug("wrote obj {0}, sz {1}".format( write_count, obj_sz)) write_count += 1 except DaosApiError as excep: if not (err in repr(excep) or err2 in repr(excep)): self.d_log.error("caught exception while writing " "object: {0}".format(repr(excep))) self.fail("caught exception while writing object: {0}". format(repr(excep))) else: self.d_log.debug("pool is too full for {0} byte " "objects".format(obj_sz)) break self.d_log.debug("closing container") self.cont.close() self.d_log.debug("closed container") # create a 2nd container now that pool is full try: self.d_log.debug("creating 2nd container") self.cont2 = DaosContainer(self.context) self.cont2.create(self.pool.handle) self.d_log.debug("created 2nd container") self.d_log.debug("opening container 2") self.cont2.open() self.d_log.debug("opened container 2") self.d_log.debug("writing one more object, write expected to fail") self.cont2.write_an_obj(my_str, my_str_sz, dkey, akey, obj_cls="OC_SX") self.fail("wrote one more object after pool was completely filled," " this should never print") except DaosApiError as excep: if not (err in repr(excep) or err2 in repr(excep)): self.d_log.error("caught unexpected exception while " "writing object: {0}".format(repr(excep))) self.fail("caught unexpected exception while writing " "object: {0}".format(repr(excep))) else: self.d_log.debug("correctly caught -1007 while attempting " "to write object in full pool")
def test_evict(self): """Test ID: DAOS-427. Test Description: Pass bad parameters to the pool evict clients call. :avocado: tags=all,pool,full_regression,tiny,badevict """ # parameters used in pool create createmode = self.params.get("mode", '/run/evicttests/createmode/') createsetid = self.params.get("setname", '/run/evicttests/createset/') createsize = self.params.get("size", '/run/evicttests/createsize/') createuid = os.geteuid() creategid = os.getegid() # Accumulate a list of pass/fail indicators representing what is # expected for each parameter then "and" them to determine the # expected result of the test expected_for_param = [] svclist = self.params.get("ranklist", '/run/evicttests/svrlist/*/') svc = svclist[0] expected_for_param.append(svclist[1]) setlist = self.params.get("setname", '/run/evicttests/connectsetnames/*/') evictset = setlist[0] expected_for_param.append(setlist[1]) uuidlist = self.params.get("uuid", '/run/evicttests/UUID/*/') excludeuuid = uuidlist[0] expected_for_param.append(uuidlist[1]) # if any parameter is FAIL then the test should FAIL, in this test # virtually everyone should FAIL since we are testing bad parameters expected_result = 'PASS' for result in expected_for_param: if result == 'FAIL': expected_result = 'FAIL' break saveduuid = None savedgroup = None savedsvc = None pool = None try: # initialize a python pool object then create the underlying # daos storage pool = DaosPool(self.context) pool.create(createmode, createuid, creategid, createsize, createsetid, None) # trash the the pool service rank list if not svc == 'VALID': savedsvc = pool.svc rl_ranks = ctypes.POINTER(ctypes.c_uint)() pool.svc = RankList(rl_ranks, 1) # trash the pool group value savedgroup = pool.group if evictset is None: pool.group = None else: pool.set_group(evictset) # trash the UUID value in various ways if excludeuuid is None: saveduuid = (ctypes.c_ubyte * 16)(0) for item in range(0, len(saveduuid)): saveduuid[item] = pool.uuid[item] pool.uuid[0:] = [0 for item in range(0, len(pool.uuid))] elif excludeuuid == 'JUNK': saveduuid = (ctypes.c_ubyte * 16)(0) for item in range(0, len(saveduuid)): saveduuid[item] = pool.uuid[item] pool.uuid[4] = 244 pool.evict() if expected_result in ['FAIL']: self.fail("Test was expected to fail but it passed.\n") except DaosApiError as excep: self.log.error(str(excep)) self.log.error(traceback.format_exc()) if expected_result in ['PASS']: self.fail("Test was expected to pass but it failed.\n") finally: if pool is not None: # if the test trashed some pool parameter, put it back the # way it was pool.group = savedgroup if saveduuid is not None: for item in range(0, len(saveduuid)): pool.uuid[item] = saveduuid[item] if savedsvc is not None: pool.svc = savedsvc pool.destroy(0)
class NvmeIo(IorTestBase): # pylint: disable=too-many-ancestors """Test class for NVMe with IO tests. Test Class Description: Test the general Metadata operations and boundary conditions. :avocado: recursive """ @avocado.fail_on(DaosApiError) def test_nvme_io(self): """Jira ID: DAOS-2082. Test Description: Test will run IOR with standard and non standard sizes. IOR will be run for all Object type supported. Purpose is to verify pool size (SCM and NVMe) for IOR file. Use Cases: Running multiple IOR on same server start instance. :avocado: tags=all,daosio,full_regression,hw,nvme_io """ # Pool params pool_mode = self.params.get("mode", '/run/pool/createmode/*') pool_uid = os.geteuid() pool_gid = os.getegid() pool_group = self.params.get("setname", '/run/pool/createset/*') pool_svcn = self.params.get("svcn", '/run/pool/createsvc/') # Test params tests = self.params.get("ior_sequence", '/run/ior/*') object_type = self.params.get("object_type", '/run/ior/*') # Loop for every IOR object type for obj_type in object_type: for ior_param in tests: # There is an issue with NVMe if Transfer size>64M, # Skipped this sizes for now if ior_param[2] > 67108864: self.log.warning("Xfersize > 64M fails - DAOS-1264") continue # Create and connect to a pool self.pool = DaosPool(self.context) self.pool.create( pool_mode, pool_uid, pool_gid, ior_param[0], pool_group, svcn=pool_svcn, nvme_size=ior_param[1]) self.pool.connect(1 << 1) # Get the current pool sizes size_before_ior = self.pool.pool_query() # Run ior with the parameters specified for this pass self.ior_cmd.transfer_size.update(ior_param[2]) self.ior_cmd.block_size.update(ior_param[3]) self.ior_cmd.daos_oclass.update(obj_type) self.ior_cmd.set_daos_params(self.server_group, self.pool) self.run_ior(self.get_job_manager_command(), ior_param[4]) # Verify IOR consumed the expected amount ofrom the pool self.verify_pool_size(size_before_ior, ior_param[4]) try: if self.pool: self.destroy_pools(self.pool) except DaosApiError as error: self.log.error( "Pool disconnect/destroy error: %s", str(error)) self.fail("Failed to Destroy/Disconnect the Pool")
class ObjectDataValidation(avocado.Test): """ Test Class Description: Tests that create Different length records, Disconnect the pool/container and reconnect, validate the data after reconnect. """ # pylint: disable=too-many-instance-attributes def setUp(self): self.agent_sessions = None self.pool = None self.container = None self.obj = None self.ioreq = None self.hostlist = None self.hostfile = None self.no_of_dkeys = None self.no_of_akeys = None self.array_size = None self.record_length = None with open('../../.build_vars.json') as json_f: build_paths = json.load(json_f) self.basepath = os.path.normpath(build_paths['PREFIX'] + "/../") server_group = self.params.get("name", '/server_config/', 'daos_server') self.context = DaosContext(build_paths['PREFIX'] + '/lib64/') self.d_log = DaosLog(self.context) self.hostlist = self.params.get("test_machines", '/run/hosts/*') self.hostfile = write_host_file.write_host_file( self.hostlist, self.workdir) self.no_of_dkeys = self.params.get("no_of_dkeys", '/run/dkeys/*')[0] self.no_of_akeys = self.params.get("no_of_akeys", '/run/akeys/*')[0] self.array_size = self.params.get("size", '/array_size/') self.record_length = self.params.get("length", '/run/record/*') self.agent_sessions = agent_utils.run_agent(self.basepath, self.hostlist) server_utils.run_server(self, self.hostfile, server_group) self.pool = DaosPool(self.context) self.pool.create(self.params.get("mode", '/run/pool/createmode/*'), os.geteuid(), os.getegid(), self.params.get("size", '/run/pool/createsize/*'), self.params.get("setname", '/run/pool/createset/*'), None) self.pool.connect(2) self.container = DaosContainer(self.context) self.container.create(self.pool.handle) self.container.open() self.obj = DaosObj(self.context, self.container) self.obj.create(objcls=1) self.obj.open() self.ioreq = IORequest(self.context, self.container, self.obj, objtype=4) def tearDown(self): try: if self.container: self.container.close() self.container.destroy() if self.pool: self.pool.disconnect() self.pool.destroy(1) finally: if self.agent_sessions: agent_utils.stop_agent(self.agent_sessions) server_utils.stop_server(hosts=self.hostlist) def reconnect(self): ''' Function to reconnect the pool/container and reopen the Object for read verification. ''' #Close the Obj/Container, Disconnect the Pool. self.obj.close() self.container.close() self.pool.disconnect() time.sleep(5) #Connect Pool, Open Container and Object self.pool.connect(2) self.container.open() self.obj.open() self.ioreq = IORequest(self.context, self.container, self.obj, objtype=4) @avocado.fail_on(DaosApiError) def test_invalid_tx_commit_close(self): """ Test ID: (1)DAOS-1346: Verify commit tx bad parameter behavior. (2)DAOS-1343: Verify tx_close bad parameter behavior. (3)DAOS-1342: Verify tx_close through daos_api. (4)DAOS-1338: Add and verify tx_abort through daos_api. (5)DAOS-1339: Verify tx_abort bad parameter behavior. Test Description: Write Avocado Test to verify commit tx and close tx bad parameter behavior. :avocado: tags=all,object,full_regression,small,invalid_tx """ self.d_log.info("==Writing the Single Dataset for negative test...") record_index = 0 expected_error = "RC: -1002" dkey = 0 akey = 0 indata = ("{0}".format(str(akey)[0]) * self.record_length[record_index]) c_dkey = ctypes.create_string_buffer("dkey {0}".format(dkey)) c_akey = ctypes.create_string_buffer("akey {0}".format(akey)) c_value = ctypes.create_string_buffer(indata) c_size = ctypes.c_size_t(ctypes.sizeof(c_value)) try: new_transaction = self.container.get_new_tx() except DaosApiError as excep: #initial container get_new_tx failed, skip rest of the test self.fail("##container get_new_tx failed: {}".format(excep)) invalid_transaction = new_transaction + random.randint(1000, 383838) self.log.info("==new_transaction= %s", new_transaction) self.log.info("==invalid_transaction= %s", invalid_transaction) self.ioreq.single_insert(c_dkey, c_akey, c_value, c_size, new_transaction) try: self.container.commit_tx(invalid_transaction) self.fail("##(1.1)Container.commit_tx passing with invalid handle") except DaosApiError as excep: self.log.info(str(excep)) self.log.info( "==(1)Expecting failure: invalid Container.commit_tx.") if expected_error not in str(excep): self.fail( "##(1.2)Expecting error RC: -1002, but got {}.".format( str(excep))) try: self.container.close_tx(invalid_transaction) self.fail("##(2.1)Container.close_tx passing with invalid handle") except DaosApiError as excep: self.log.info(str(excep)) self.log.info( "==(2)Expecting failure: invalid Container.commit_tx.") if expected_error not in str(excep): self.fail( "##(2.2)Expecting error RC: -1002, but got {}.".format( str(excep))) try: self.container.close_tx(new_transaction) self.log.info("==(3)container.close_tx test passed.") except DaosApiError as excep: self.log.info(str(excep)) self.fail("##(3)Failed on close_tx.") try: self.container.abort_tx(invalid_transaction) self.fail("##(4.1)Container.abort_tx passing with invalid handle") except DaosApiError as excep: self.log.info(str(excep)) self.log.info( "==(4)Expecting failure: invalid Container.abort_tx.") if expected_error not in str(excep): self.fail( "##(4.2)Expecting error RC: -1002, but got {}.".format( str(excep))) #Try to abort the transaction which already closed. try: self.container.abort_tx(new_transaction) self.fail("##(5.1)Container.abort_tx passing with a closed handle") except DaosApiError as excep: self.log.info(str(excep)) self.log.info( "==(5)Expecting failure: Container.abort_tx closed handle.") if expected_error not in str(excep): self.fail( "##(5.2)Expecting error RC: -1002, but got {}.".format( str(excep))) #open another transaction for abort test try: new_transaction2 = self.container.get_new_tx() except DaosApiError as excep: self.fail("##(6.1)container get_new_tx failed: {}".format(excep)) self.log.info("==new_transaction2= %s", new_transaction2) self.ioreq.single_insert(c_dkey, c_akey, c_value, c_size, new_transaction2) try: self.container.abort_tx(new_transaction2) self.log.info("==(6)container.abort_tx test passed.") except DaosApiError as excep: self.log.info(str(excep)) self.fail("##(6.2)Failed on abort_tx.") @avocado.fail_on(DaosApiError) @skipForTicket("DAOS-3208") def test_single_object_validation(self): """ Test ID: DAOS-707 Test Description: Write Avocado Test to verify single data after pool/container disconnect/reconnect. :avocado: tags=all,object,full_regression,small,single_object """ self.d_log.info("Writing the Single Dataset") record_index = 0 transaction = [] for dkey in range(self.no_of_dkeys): for akey in range(self.no_of_akeys): indata = ("{0}".format(str(akey)[0]) * self.record_length[record_index]) c_dkey = ctypes.create_string_buffer("dkey {0}".format(dkey)) c_akey = ctypes.create_string_buffer("akey {0}".format(akey)) c_value = ctypes.create_string_buffer(indata) c_size = ctypes.c_size_t(ctypes.sizeof(c_value)) new_transaction = self.container.get_new_tx() self.ioreq.single_insert(c_dkey, c_akey, c_value, c_size, new_transaction) self.container.commit_tx(new_transaction) transaction.append(new_transaction) record_index = record_index + 1 if record_index == len(self.record_length): record_index = 0 self.reconnect() self.d_log.info("Single Dataset Verification -- Started") record_index = 0 transaction_index = 0 for dkey in range(self.no_of_dkeys): for akey in range(self.no_of_akeys): indata = ("{0}".format(str(akey)[0]) * self.record_length[record_index]) c_dkey = ctypes.create_string_buffer("dkey {0}".format(dkey)) c_akey = ctypes.create_string_buffer("akey {0}".format(akey)) val = self.ioreq.single_fetch(c_dkey, c_akey, len(indata) + 1) if indata != (repr(val.value)[1:-1]): self.d_log.error("ERROR:Data mismatch for " "dkey = {0}, " "akey = {1}".format( "dkey {0}".format(dkey), "akey {0}".format(akey))) self.fail( "ERROR: Data mismatch for dkey = {0}, akey={1}".format( "dkey {0}".format(dkey), "akey {0}".format(akey))) transaction_index = transaction_index + 1 record_index = record_index + 1 if record_index == len(self.record_length): record_index = 0 @avocado.fail_on(DaosApiError) @skipForTicket("DAOS-3208") def test_array_object_validation(self): """ Test ID: DAOS-707 Test Description: Write Avocado Test to verify Array data after pool/container disconnect/reconnect. :avocado: tags=all,object,full_regression,small,array_object """ self.d_log.info("Writing the Array Dataset") record_index = 0 transaction = [] for dkey in range(self.no_of_dkeys): for akey in range(self.no_of_akeys): c_values = [] value = ("{0}".format(str(akey)[0]) * self.record_length[record_index]) for item in range(self.array_size): c_values.append( (ctypes.create_string_buffer(value), len(value) + 1)) c_dkey = ctypes.create_string_buffer("dkey {0}".format(dkey)) c_akey = ctypes.create_string_buffer("akey {0}".format(akey)) new_transaction = self.container.get_new_tx() self.ioreq.insert_array(c_dkey, c_akey, c_values, new_transaction) self.container.commit_tx(new_transaction) transaction.append(new_transaction) record_index = record_index + 1 if record_index == len(self.record_length): record_index = 0 self.reconnect() self.d_log.info("Array Dataset Verification -- Started") record_index = 0 transaction_index = 0 for dkey in range(self.no_of_dkeys): for akey in range(self.no_of_akeys): indata = [] value = ("{0}".format(str(akey)[0]) * self.record_length[record_index]) for item in range(self.array_size): indata.append(value) c_dkey = ctypes.create_string_buffer("dkey {0}".format(dkey)) c_akey = ctypes.create_string_buffer("akey {0}".format(akey)) c_rec_count = ctypes.c_uint(len(indata)) c_rec_size = ctypes.c_size_t(len(indata[0]) + 1) outdata = self.ioreq.fetch_array(c_dkey, c_akey, c_rec_count, c_rec_size) for item in enumerate(indata): if indata[item[0]] != outdata[item[0]][:-1]: self.d_log.error("ERROR:Data mismatch for " "dkey = {0}, " "akey = {1}".format( "dkey {0}".format(dkey), "akey {0}".format(akey))) self.fail( "ERROR:Data mismatch for dkey = {0}, akey={1}". format("dkey {0}".format(dkey), "akey {0}".format(akey))) transaction_index = transaction_index + 1 record_index = record_index + 1 if record_index == len(self.record_length): record_index = 0
class ContainerAsync(TestWithServers): """ Tests DAOS pool connect permissions (non existing pool handle, bad uuid) and close. :avocado: recursive """ def __init__(self, *args, **kwargs): super(ContainerAsync, self).__init__(*args, **kwargs) self.container1 = None self.container2 = None self.pool = None def test_createasync(self): """ Test container create for asynchronous mode. :avocado: tags=all,small,full_regression,container,createasync """ global GLOB_SIGNAL global GLOB_RC # parameters used in pool create createmode = self.params.get("mode", '/run/createtests/createmode/*/') createsetid = self.params.get("setname", '/run/createtests/createset/') createsize = self.params.get("size", '/run/createtests/createsize/') createuid = os.geteuid() creategid = os.getegid() try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) poh = self.pool.handle self.pool.connect(1 << 1) # Container initialization and creation self.container1 = DaosContainer(self.context) self.container2 = DaosContainer(self.context) GLOB_SIGNAL = threading.Event() self.container1.create(poh, None, cb_func) GLOB_SIGNAL.wait() if GLOB_RC != 0: self.fail("RC not as expected in async test") print("RC after successful container create: ", GLOB_RC) # Try to recreate container after destroying pool, # this should fail. Checking rc after failure. self.pool.disconnect() self.pool.destroy(1) GLOB_SIGNAL = threading.Event() GLOB_RC = -9900000 self.container2.create(poh, None, cb_func) GLOB_SIGNAL.wait() if GLOB_RC == 0: self.fail("RC not as expected in async test") print("RC after unsuccessful container create: ", GLOB_RC) # cleanup the pool and container self.pool = None except DaosApiError as excep: print(excep) print(traceback.format_exc()) def test_destroyasync(self): """ Test container destroy for asynchronous mode. :avocado: tags=all,small,full_regression,container,contdestroyasync """ global GLOB_SIGNAL global GLOB_RC # parameters used in pool create createmode = self.params.get("mode", '/run/createtests/createmode/*/') createsetid = self.params.get("setname", '/run/createtests/createset/') createsize = self.params.get("size", '/run/createtests/createsize/') createuid = os.geteuid() creategid = os.getegid() try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) poh = self.pool.handle self.pool.connect(1 << 1) # Container initialization and creation self.container1 = DaosContainer(self.context) self.container2 = DaosContainer(self.context) self.container1.create(poh) GLOB_SIGNAL = threading.Event() self.container1.destroy(1, poh, None, cb_func) GLOB_SIGNAL.wait() if GLOB_RC != 0: self.fail("RC not as expected in async test") print("RC after successful container create: ", GLOB_RC) # Try to destroy container again, this should fail, as non-existent. # Checking rc after failure. GLOB_SIGNAL = threading.Event() GLOB_RC = -9900000 self.container2.destroy(1, poh, None, cb_func) GLOB_SIGNAL.wait() if GLOB_RC != -1003: self.fail("RC not as expected in async test") print("RC after container destroy failed:", GLOB_RC) except DaosApiError as excep: print(excep) print(traceback.format_exc()) def test_openasync(self): """ Test container open for asynchronous mode. :avocado: tags=all,small,full_regression,container,openasync """ global GLOB_SIGNAL global GLOB_RC # parameters used in pool create createmode = self.params.get("mode", '/run/createtests/createmode/*/') createsetid = self.params.get("setname", '/run/createtests/createset/') createsize = self.params.get("size", '/run/createtests/createsize/') createuid = os.geteuid() creategid = os.getegid() try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) poh = self.pool.handle self.pool.connect(1 << 1) # Container initialization and creation self.container1 = DaosContainer(self.context) self.container2 = DaosContainer(self.context) self.container1.create(poh) str_cuuid = self.container1.get_uuid_str() cuuid = uuid.UUID(str_cuuid) GLOB_SIGNAL = threading.Event() self.container1.open(poh, cuuid, 2, cb_func) GLOB_SIGNAL.wait() if GLOB_RC != 0: self.fail("RC not as expected in async test") print("RC after successful container create: ", GLOB_RC) # Try to open container2, this should fail, as non-existent. # Checking rc after failure. GLOB_SIGNAL = threading.Event() GLOB_RC = -9900000 self.container2.open(None, None, None, cb_func) GLOB_SIGNAL.wait() if GLOB_RC == 0: self.fail("RC not as expected in async test") print("RC after container destroy failed:", GLOB_RC) # cleanup the container self.container1.close() self.container1.destroy() except DaosApiError as excep: print(excep) print(traceback.format_exc()) def test_closeasync(self): """ Test container close for asynchronous mode. :avocado: tags=all,small,full_regression,container,closeasync """ global GLOB_SIGNAL global GLOB_RC # parameters used in pool create createmode = self.params.get("mode", '/run/createtests/createmode/*/') createsetid = self.params.get("setname", '/run/createtests/createset/') createsize = self.params.get("size", '/run/createtests/createsize/') createuid = os.geteuid() creategid = os.getegid() try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) poh = self.pool.handle self.pool.connect(1 << 1) # Container initialization and creation self.container1 = DaosContainer(self.context) self.container2 = DaosContainer(self.context) self.container1.create(poh) str_cuuid = self.container1.get_uuid_str() cuuid = uuid.UUID(str_cuuid) self.container1.open(poh, cuuid, 2) GLOB_SIGNAL = threading.Event() self.container1.close(cb_func=cb_func) GLOB_SIGNAL.wait() if GLOB_RC != 0: self.fail("RC not as expected in async test: " "{0}".format(GLOB_RC)) print("RC after successful container create: ", GLOB_RC) # Try to open container2, this should fail, as non-existent. # Checking rc after failure. GLOB_SIGNAL = threading.Event() GLOB_RC = -9900000 self.container2.close(cb_func=cb_func) GLOB_SIGNAL.wait() if GLOB_RC == 0: self.fail("RC not as expected in async test: " "{0}".format(GLOB_RC)) print("RC after container destroy failed:", GLOB_RC) # cleanup the container self.container1.destroy() except DaosApiError as excep: print(excep) print(traceback.format_exc()) def test_queryasync(self): """ Test container query for asynchronous mode. :avocado: tags=all,small,full_regression,container,queryasync """ global GLOB_SIGNAL global GLOB_RC # parameters used in pool create createmode = self.params.get("mode", '/run/createtests/createmode/*/') createsetid = self.params.get("setname", '/run/createtests/createset/') createsize = self.params.get("size", '/run/createtests/createsize/') createuid = os.geteuid() creategid = os.getegid() try: # initialize a python pool object then create the underlying # daos storage self.pool = DaosPool(self.context) self.pool.create(createmode, createuid, creategid, createsize, createsetid, None) poh = self.pool.handle self.pool.connect(1 << 1) # Container initialization and creation self.container1 = DaosContainer(self.context) self.container2 = DaosContainer(self.context) self.container1.create(poh) dummy_str_cuuid = self.container1.get_uuid_str() # Open container self.container1.open(poh, None, 2, None) GLOB_SIGNAL = threading.Event() self.container1.query(cb_func=cb_func) GLOB_SIGNAL.wait() if GLOB_RC != 0: self.fail("RC not as expected in async test: " "{0}".format(GLOB_RC)) print("RC after successful container create: ", GLOB_RC) # Close opened container self.container1.close() # Try to open container2, this should fail, as non-existent. # Checking rc after failure. GLOB_SIGNAL = threading.Event() GLOB_RC = -9900000 self.container2.query(cb_func=cb_func) GLOB_SIGNAL.wait() if GLOB_RC == 0: self.fail("RC not as expected in async test: " "{0}".format(GLOB_RC)) print("RC after container destroy failed:", GLOB_RC) # cleanup the container self.container1.destroy() except DaosApiError as excep: print(excep) print(traceback.format_exc())