|
13 | 13 | importsocket
|
14 | 14 | importthreading
|
15 | 15 | importtyping
|
| 16 | +importuuid |
16 | 17 |
|
17 | 18 | fromtestgresimportInvalidOperationException
|
18 | 19 | fromtestgresimportExecUtilException
|
19 | 20 |
|
| 21 | +fromconcurrent.futuresimportThreadPoolExecutor |
| 22 | +fromconcurrent.futuresimportFutureasThreadFuture |
| 23 | + |
20 | 24 |
|
21 | 25 | classTestOsOpsCommon:
|
22 | 26 | sm_os_ops_descrs:typing.List[OsOpsDescr]= [
|
@@ -812,3 +816,267 @@ def LOCAL_server(s: socket.socket):
|
812 | 816 |
|
813 | 817 | ifok_count==0:
|
814 | 818 | raiseRuntimeError("No one free port was found.")
|
| 819 | + |
| 820 | +classtagData_OS_OPS__NUMS: |
| 821 | +os_ops_descr:OsOpsDescr |
| 822 | +nums:int |
| 823 | + |
| 824 | +def__init__(self,os_ops_descr:OsOpsDescr,nums:int): |
| 825 | +assertisinstance(os_ops_descr,OsOpsDescr) |
| 826 | +asserttype(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.signforxinsm_test_exclusive_creation__mt__data] |
| 839 | + ) |
| 840 | +defdata001(self,request:pytest.FixtureRequest)->tagData_OS_OPS__NUMS: |
| 841 | +assertisinstance(request,pytest.FixtureRequest) |
| 842 | +returnrequest.param |
| 843 | + |
| 844 | +deftest_mkdir__mt(self,data001:tagData_OS_OPS__NUMS): |
| 845 | +asserttype(data001)==__class__.tagData_OS_OPS__NUMS# noqa: E721 |
| 846 | + |
| 847 | +N_WORKERS=4 |
| 848 | +N_NUMBERS=data001.nums |
| 849 | +asserttype(N_NUMBERS)==int# noqa: E721 |
| 850 | + |
| 851 | +os_ops=data001.os_ops_descr.os_ops |
| 852 | +assertisinstance(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 | +assertos.path.exists(lock_dir) |
| 861 | + |
| 862 | +defMAKE_PATH(lock_dir:str,num:int)->str: |
| 863 | +asserttype(lock_dir)==str# noqa: E721 |
| 864 | +asserttype(num)==int# noqa: E721 |
| 865 | +returnos.path.join(lock_dir,str(num)+".lock") |
| 866 | + |
| 867 | +defLOCAL_WORKER(os_ops:OsOperations, |
| 868 | +workerID:int, |
| 869 | +lock_dir:str, |
| 870 | +cNumbers:int, |
| 871 | +reservedNumbers:typing.Set[int])->None: |
| 872 | +assertisinstance(os_ops,OsOperations) |
| 873 | +asserttype(workerID)==int# noqa: E721 |
| 874 | +asserttype(lock_dir)==str# noqa: E721 |
| 875 | +asserttype(cNumbers)==int# noqa: E721 |
| 876 | +asserttype(reservedNumbers)==set# noqa: E721 |
| 877 | +assertcNumbers>0 |
| 878 | +assertlen(reservedNumbers)==0 |
| 879 | + |
| 880 | +assertos.path.exists(lock_dir) |
| 881 | + |
| 882 | +defLOG_INFO(template:str,*args:list)->None: |
| 883 | +asserttype(template)==str# noqa: E721 |
| 884 | +asserttype(args)==tuple# noqa: E721 |
| 885 | + |
| 886 | +msg=template.format(*args) |
| 887 | +asserttype(msg)==str# noqa: E721 |
| 888 | + |
| 889 | +logging.info("[Worker #{}] {}".format(workerID,msg)) |
| 890 | +return |
| 891 | + |
| 892 | +LOG_INFO("HELLO! I am here!") |
| 893 | + |
| 894 | +fornuminrange(cNumbers): |
| 895 | +assertnot (numinreservedNumbers) |
| 896 | + |
| 897 | +file_path=MAKE_PATH(lock_dir,num) |
| 898 | + |
| 899 | +try: |
| 900 | +os_ops.makedir(file_path) |
| 901 | +exceptExceptionase: |
| 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 | +assertos_ops.path_exists(file_path) |
| 912 | +reservedNumbers.add(num) |
| 913 | +continue |
| 914 | + |
| 915 | +n_total=cNumbers |
| 916 | +n_ok=len(reservedNumbers) |
| 917 | +assertn_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 | +classtadWorkerData: |
| 931 | +future:ThreadFuture |
| 932 | +reservedNumbers:typing.Set[int] |
| 933 | + |
| 934 | +workerDatas:typing.List[tadWorkerData]=list() |
| 935 | + |
| 936 | +nErrors=0 |
| 937 | + |
| 938 | +try: |
| 939 | +forninrange(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 | +assertworkerDatas[n].futureisnotNone |
| 956 | + |
| 957 | +logging.info("OK. All the workers were created!") |
| 958 | +exceptExceptionase: |
| 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 | +asserttype(workerDatas)==list# noqa: E721 |
| 967 | + |
| 968 | +foriinrange(len(workerDatas)): |
| 969 | +worker=workerDatas[i].future |
| 970 | + |
| 971 | +ifworkerisNone: |
| 972 | +continue |
| 973 | + |
| 974 | +nWorkers+=1 |
| 975 | + |
| 976 | +assertisinstance(worker,ThreadFuture) |
| 977 | + |
| 978 | +try: |
| 979 | +logging.info("Wait for worker #{}".format(i)) |
| 980 | +worker.result() |
| 981 | +exceptExceptionase: |
| 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 | +assertnWorkers==N_WORKERS |
| 991 | + |
| 992 | +ifnErrors!=0: |
| 993 | +raiseRuntimeError("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 | +foriinrange(N_WORKERS): |
| 1000 | +logging.info("Worker #{} is checked ...".format(i)) |
| 1001 | + |
| 1002 | +workerNumbers=workerDatas[i].reservedNumbers |
| 1003 | +asserttype(workerNumbers)==set# noqa: E721 |
| 1004 | + |
| 1005 | +forninworkerNumbers: |
| 1006 | +ifn<0orn>=N_NUMBERS: |
| 1007 | +nErrors+=1 |
| 1008 | +logging.error("Unexpected number {}".format(n)) |
| 1009 | +continue |
| 1010 | + |
| 1011 | +ifninreservedNumbers.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 | +ifnotos_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 | +forninrange(N_NUMBERS): |
| 1031 | +ifnot (ninreservedNumbers.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 | +ifnotos_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 | +ifnErrors==0: |
| 1048 | +logging.info("Root lock-directory [{}] will be deleted.".format( |
| 1049 | +lock_dir |
| 1050 | + )) |
| 1051 | + |
| 1052 | +forninrange(N_NUMBERS): |
| 1053 | +file_path=MAKE_PATH(lock_dir,n) |
| 1054 | +try: |
| 1055 | +os_ops.rmdir(file_path) |
| 1056 | +exceptExceptionase: |
| 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 | +ifos_ops.path_exists(file_path): |
| 1066 | +nErrors+=1 |
| 1067 | +logging.error("Directory {} is not deleted!".format(file_path)) |
| 1068 | +continue |
| 1069 | + |
| 1070 | +ifnErrors==0: |
| 1071 | +try: |
| 1072 | +os_ops.rmdir(lock_dir) |
| 1073 | +exceptExceptionase: |
| 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 |