Skip to content

Commit a0a8506

Browse files
New OsOperations methods: makedir, rmdir (#253)
Signatures: def makedir(self, path: str) def rmdir(self, path: str) It is a part of work for #247.
1 parent df4f545 commit a0a8506

File tree

4 files changed

+294
-0
lines changed

4 files changed

+294
-0
lines changed

testgres/operations/local_ops.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ def makedirs(self, path, remove_existing=False):
250250
except FileExistsError:
251251
pass
252252

253+
def makedir(self, path: str):
254+
assert type(path) == str # noqa: E721
255+
os.mkdir(path)
256+
253257
# [2025-02-03] Old name of parameter attempts is "retries".
254258
def rmdirs(self, path, ignore_errors=True, attempts=3, delay=1):
255259
"""
@@ -293,6 +297,10 @@ def rmdirs(self, path, ignore_errors=True, attempts=3, delay=1):
293297
# OK!
294298
return True
295299

300+
def rmdir(self, path: str):
301+
assert type(path) == str # noqa: E721
302+
os.rmdir(path)
303+
296304
def listdir(self, path):
297305
return os.listdir(path)
298306

testgres/operations/os_ops.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,17 @@ def get_name(self):
5353
def makedirs(self, path, remove_existing=False):
5454
raise NotImplementedError()
5555

56+
def makedir(self, path: str):
57+
assert type(path) == str # noqa: E721
58+
raise NotImplementedError()
59+
5660
def rmdirs(self, path, ignore_errors=True):
5761
raise NotImplementedError()
5862

63+
def rmdir(self, path: str):
64+
assert type(path) == str # noqa: E721
65+
raise NotImplementedError()
66+
5967
def listdir(self, path):
6068
raise NotImplementedError()
6169

testgres/operations/remote_ops.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ def makedirs(self, path, remove_existing=False):
225225
raise Exception("Couldn't create dir {} because of error {}".format(path, error))
226226
return result
227227

228+
def makedir(self, path: str):
229+
assert type(path) == str # noqa: E721
230+
cmd = ["mkdir", path]
231+
self.exec_command(cmd)
232+
228233
def rmdirs(self, path, ignore_errors=True):
229234
"""
230235
Remove a directory in the remote server.
@@ -265,6 +270,11 @@ def rmdirs(self, path, ignore_errors=True):
265270
return False
266271
return True
267272

273+
def rmdir(self, path: str):
274+
assert type(path) == str # noqa: E721
275+
cmd = ["rmdir", path]
276+
self.exec_command(cmd)
277+
268278
def listdir(self, path):
269279
"""
270280
List all files and directories in a directory.

tests/test_os_ops_common.py

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@
1313
import socket
1414
import threading
1515
import typing
16+
import uuid
1617

1718
from testgres import InvalidOperationException
1819
from testgres import ExecUtilException
1920

21+
from concurrent.futures import ThreadPoolExecutor
22+
from concurrent.futures import Future as ThreadFuture
23+
2024

2125
class TestOsOpsCommon:
2226
sm_os_ops_descrs: typing.List[OsOpsDescr] = [
@@ -812,3 +816,267 @@ def LOCAL_server(s: socket.socket):
812816

813817
if ok_count == 0:
814818
raise RuntimeError("No one free port was found.")
819+
820+
class tagData_OS_OPS__NUMS:
821+
os_ops_descr: OsOpsDescr
822+
nums: int
823+
824+
def __init__(self, os_ops_descr: OsOpsDescr, nums: int):
825+
assert isinstance(os_ops_descr, OsOpsDescr)
826+
assert type(nums) == int # noqa: E721
827+
828+
self.os_ops_descr = os_ops_descr
829+
self.nums = nums
830+
831+
sm_test_exclusive_creation__mt__data = [
832+
tagData_OS_OPS__NUMS(OsOpsDescrs.sm_local_os_ops_descr, 100000),
833+
tagData_OS_OPS__NUMS(OsOpsDescrs.sm_remote_os_ops_descr, 120),
834+
]
835+
836+
@pytest.fixture(
837+
params=sm_test_exclusive_creation__mt__data,
838+
ids=[x.os_ops_descr.sign for x in sm_test_exclusive_creation__mt__data]
839+
)
840+
def data001(self, request: pytest.FixtureRequest) -> tagData_OS_OPS__NUMS:
841+
assert isinstance(request, pytest.FixtureRequest)
842+
return request.param
843+
844+
def test_mkdir__mt(self, data001: tagData_OS_OPS__NUMS):
845+
assert type(data001) == __class__.tagData_OS_OPS__NUMS # noqa: E721
846+
847+
N_WORKERS = 4
848+
N_NUMBERS = data001.nums
849+
assert type(N_NUMBERS) == int # noqa: E721
850+
851+
os_ops = data001.os_ops_descr.os_ops
852+
assert isinstance(os_ops, OsOperations)
853+
854+
lock_dir_prefix = "test_mkdir_mt--" + uuid.uuid4().hex
855+
856+
lock_dir = os_ops.mkdtemp(prefix=lock_dir_prefix)
857+
858+
logging.info("A lock file [{}] is creating ...".format(lock_dir))
859+
860+
assert os.path.exists(lock_dir)
861+
862+
def MAKE_PATH(lock_dir: str, num: int) -> str:
863+
assert type(lock_dir) == str # noqa: E721
864+
assert type(num) == int # noqa: E721
865+
return os.path.join(lock_dir, str(num) + ".lock")
866+
867+
def LOCAL_WORKER(os_ops: OsOperations,
868+
workerID: int,
869+
lock_dir: str,
870+
cNumbers: int,
871+
reservedNumbers: typing.Set[int]) -> None:
872+
assert isinstance(os_ops, OsOperations)
873+
assert type(workerID) == int # noqa: E721
874+
assert type(lock_dir) == str # noqa: E721
875+
assert type(cNumbers) == int # noqa: E721
876+
assert type(reservedNumbers) == set # noqa: E721
877+
assert cNumbers > 0
878+
assert len(reservedNumbers) == 0
879+
880+
assert os.path.exists(lock_dir)
881+
882+
def LOG_INFO(template: str, *args: list) -> None:
883+
assert type(template) == str # noqa: E721
884+
assert type(args) == tuple # noqa: E721
885+
886+
msg = template.format(*args)
887+
assert type(msg) == str # noqa: E721
888+
889+
logging.info("[Worker #{}] {}".format(workerID, msg))
890+
return
891+
892+
LOG_INFO("HELLO! I am here!")
893+
894+
for num in range(cNumbers):
895+
assert not (num in reservedNumbers)
896+
897+
file_path = MAKE_PATH(lock_dir, num)
898+
899+
try:
900+
os_ops.makedir(file_path)
901+
except Exception as e:
902+
LOG_INFO(
903+
"Can't reserve {}. Error ({}): {}",
904+
num,
905+
type(e).__name__,
906+
str(e)
907+
)
908+
continue
909+
910+
LOG_INFO("Number {} is reserved!", num)
911+
assert os_ops.path_exists(file_path)
912+
reservedNumbers.add(num)
913+
continue
914+
915+
n_total = cNumbers
916+
n_ok = len(reservedNumbers)
917+
assert n_ok <= n_total
918+
919+
LOG_INFO("Finish! OK: {}. FAILED: {}.", n_ok, n_total - n_ok)
920+
return
921+
922+
# -----------------------
923+
logging.info("Worker are creating ...")
924+
925+
threadPool = ThreadPoolExecutor(
926+
max_workers=N_WORKERS,
927+
thread_name_prefix="ex_creator"
928+
)
929+
930+
class tadWorkerData:
931+
future: ThreadFuture
932+
reservedNumbers: typing.Set[int]
933+
934+
workerDatas: typing.List[tadWorkerData] = list()
935+
936+
nErrors = 0
937+
938+
try:
939+
for n in range(N_WORKERS):
940+
logging.info("worker #{} is creating ...".format(n))
941+
942+
workerDatas.append(tadWorkerData())
943+
944+
workerDatas[n].reservedNumbers = set()
945+
946+
workerDatas[n].future = threadPool.submit(
947+
LOCAL_WORKER,
948+
os_ops,
949+
n,
950+
lock_dir,
951+
N_NUMBERS,
952+
workerDatas[n].reservedNumbers
953+
)
954+
955+
assert workerDatas[n].future is not None
956+
957+
logging.info("OK. All the workers were created!")
958+
except Exception as e:
959+
nErrors += 1
960+
logging.error("A problem is detected ({}): {}".format(type(e).__name__, str(e)))
961+
962+
logging.info("Will wait for stop of all the workers...")
963+
964+
nWorkers = 0
965+
966+
assert type(workerDatas) == list # noqa: E721
967+
968+
for i in range(len(workerDatas)):
969+
worker = workerDatas[i].future
970+
971+
if worker is None:
972+
continue
973+
974+
nWorkers += 1
975+
976+
assert isinstance(worker, ThreadFuture)
977+
978+
try:
979+
logging.info("Wait for worker #{}".format(i))
980+
worker.result()
981+
except Exception as e:
982+
nErrors += 1
983+
logging.error("Worker #{} finished with error ({}): {}".format(
984+
i,
985+
type(e).__name__,
986+
str(e),
987+
))
988+
continue
989+
990+
assert nWorkers == N_WORKERS
991+
992+
if nErrors != 0:
993+
raise RuntimeError("Some problems were detected. Please examine the log messages.")
994+
995+
logging.info("OK. Let's check worker results!")
996+
997+
reservedNumbers: typing.Dict[int, int] = dict()
998+
999+
for i in range(N_WORKERS):
1000+
logging.info("Worker #{} is checked ...".format(i))
1001+
1002+
workerNumbers = workerDatas[i].reservedNumbers
1003+
assert type(workerNumbers) == set # noqa: E721
1004+
1005+
for n in workerNumbers:
1006+
if n < 0 or n >= N_NUMBERS:
1007+
nErrors += 1
1008+
logging.error("Unexpected number {}".format(n))
1009+
continue
1010+
1011+
if n in reservedNumbers.keys():
1012+
nErrors += 1
1013+
logging.error("Number {} was already reserved by worker #{}".format(
1014+
n,
1015+
reservedNumbers[n]
1016+
))
1017+
else:
1018+
reservedNumbers[n] = i
1019+
1020+
file_path = MAKE_PATH(lock_dir, n)
1021+
if not os_ops.path_exists(file_path):
1022+
nErrors += 1
1023+
logging.error("File {} is not found!".format(file_path))
1024+
continue
1025+
1026+
continue
1027+
1028+
logging.info("OK. Let's check reservedNumbers!")
1029+
1030+
for n in range(N_NUMBERS):
1031+
if not (n in reservedNumbers.keys()):
1032+
nErrors += 1
1033+
logging.error("Number {} is not reserved!".format(n))
1034+
continue
1035+
1036+
file_path = MAKE_PATH(lock_dir, n)
1037+
if not os_ops.path_exists(file_path):
1038+
nErrors += 1
1039+
logging.error("File {} is not found!".format(file_path))
1040+
continue
1041+
1042+
# OK!
1043+
continue
1044+
1045+
logging.info("Verification is finished! Total error count is {}.".format(nErrors))
1046+
1047+
if nErrors == 0:
1048+
logging.info("Root lock-directory [{}] will be deleted.".format(
1049+
lock_dir
1050+
))
1051+
1052+
for n in range(N_NUMBERS):
1053+
file_path = MAKE_PATH(lock_dir, n)
1054+
try:
1055+
os_ops.rmdir(file_path)
1056+
except Exception as e:
1057+
nErrors += 1
1058+
logging.error("Cannot delete directory [{}]. Error ({}): {}".format(
1059+
file_path,
1060+
type(e).__name__,
1061+
str(e)
1062+
))
1063+
continue
1064+
1065+
if os_ops.path_exists(file_path):
1066+
nErrors += 1
1067+
logging.error("Directory {} is not deleted!".format(file_path))
1068+
continue
1069+
1070+
if nErrors == 0:
1071+
try:
1072+
os_ops.rmdir(lock_dir)
1073+
except Exception as e:
1074+
nErrors += 1
1075+
logging.error("Cannot delete directory [{}]. Error ({}): {}".format(
1076+
lock_dir,
1077+
type(e).__name__,
1078+
str(e)
1079+
))
1080+
1081+
logging.info("Test is finished! Total error count is {}.".format(nErrors))
1082+
return

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy