From 57386964b043e778e32ff76ea386bd0c6bea16dc Mon Sep 17 00:00:00 2001 From: Watchtek Date: Fri, 17 Oct 2025 16:50:57 +0900 Subject: [PATCH 1/9] #6 add flag - take screenshot onlt on first and last session --- load_check.py | 59 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/load_check.py b/load_check.py index 7b429c7..6d96261 100644 --- a/load_check.py +++ b/load_check.py @@ -103,6 +103,22 @@ class MultipleTest(unittest.TestCase): os.makedirs(self.screenshots_folder, exist_ok=True) self.screenshot_base_dir = self.screenshots_folder + # Debug screenshot toggle: + # - Environment variable SCREENSHOT_ALL=1 / true / y will enable all screenshots (non-interactive) + # - Otherwise ask interactively (default No) + env_flag = os.getenv("SCREENSHOT_ALL", "").lower() + if env_flag in ("1", "true", "y", "yes"): + self.screenshot_all = True + print("[INFO] SCREENSHOT_ALL environment variable enabled: saving screenshots for ALL drivers (debug mode).") + else: + print("\n6. [선택] 모든 세션에서 스크린샷을 저장하시겠습니까? (y/N): ") + ans = input().strip().lower() + self.screenshot_all = ans in ("y", "yes") + if self.screenshot_all: + print("[INFO] Debug mode ON: saving screenshots for ALL drivers.") + else: + print("[INFO] Default mode: saving screenshots only for first and last drivers.") + def check_http_status(self, url: str, max_retry: int = 3, ignore_cert: bool = True) -> bool: """ Checks the HTTP status of the given URL. @@ -158,20 +174,49 @@ class MultipleTest(unittest.TestCase): self.accept_next_alert = True def _take_screenshot(self, driver, action_name): - """Saves a screenshot with a unique, descriptive filename.""" + """Saves screenshots according to the screenshot_all flag. + + - If self.screenshot_all is True -> save for every driver. + - Otherwise only save for driver.instance_number == 1 or == self.max_connections. + """ try: + inst = getattr(driver, "instance_number", None) + if inst is None: + # No instance number set; skip silently + return + + # If debug flag set -> save for everyone + if getattr(self, "screenshot_all", False): + do_save = True + else: + last_inst = getattr(self, "max_connections", None) + # Default behavior: only save for instance 1 and planned last instance + do_save = (inst == 1) or (last_inst is not None and inst == last_inst) + + if not do_save: + return + + # proceed to save screenshot for allowed instances time.sleep(0.2) - session_folder = os.path.join(self.screenshot_base_dir, f"session_{driver.instance_number}") + session_folder = os.path.join(self.screenshot_base_dir, f"session_{inst}") os.makedirs(session_folder, exist_ok=True) - counter = getattr(driver, 'screenshot_counter', 0) + 1 - setattr(driver, 'screenshot_counter', counter) + + counter = getattr(driver, "screenshot_counter", 0) + 1 + setattr(driver, "screenshot_counter", counter) counter_str = str(counter).zfill(4) filename = os.path.join(session_folder, f"{counter_str}_{action_name}.png") - time.sleep(3) # Set common wait time before save screenshot(except custom dashboard) + + # allow page to settle (your previous behavior) + time.sleep(3) driver.save_screenshot(filename) + # optionally show debug # print(f"Screenshot saved: {filename}") - except (FileNotFoundError, PermissionError): - print(f"Error saving screenshot for session {driver.instance_number}") + + except (FileNotFoundError, PermissionError) as e: + print(f"Error saving screenshot for session {getattr(driver, 'instance_number', 'unknown')}: {e}") + except Exception as e: + print(f"Unexpected error in _take_screenshot for session {getattr(driver, 'instance_number', 'unknown')}: {e}") + def _interact_with_time_filters(self, driver): """ -- GitLab From 45676bcc92a7f566348ec459fb963c7672c3555a Mon Sep 17 00:00:00 2001 From: Watchtek Date: Fri, 17 Oct 2025 16:56:16 +0900 Subject: [PATCH 2/9] Solved pylint --- .pylintrc | 2 +- load_check.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.pylintrc b/.pylintrc index 1019147..120adfd 100644 --- a/.pylintrc +++ b/.pylintrc @@ -3,7 +3,7 @@ # disable=too-many-instance-attributes, too-many-arguments, too-many-positional-arguments, too-many-locals # Same with above # Disable specific message IDs. -disable=R0902, R0913, R0915, R0917, R0914 +disable=R0902, R0913, R0915, R0917, R0914, R0912 [FORMAT] # Maximum number of characters on a single line. diff --git a/load_check.py b/load_check.py index 6d96261..50e77c4 100644 --- a/load_check.py +++ b/load_check.py @@ -214,9 +214,6 @@ class MultipleTest(unittest.TestCase): except (FileNotFoundError, PermissionError) as e: print(f"Error saving screenshot for session {getattr(driver, 'instance_number', 'unknown')}: {e}") - except Exception as e: - print(f"Unexpected error in _take_screenshot for session {getattr(driver, 'instance_number', 'unknown')}: {e}") - def _interact_with_time_filters(self, driver): """ -- GitLab From 82019aee09b3658c1bbc6330971f9c28c5823da1 Mon Sep 17 00:00:00 2001 From: Watchtek Date: Fri, 17 Oct 2025 17:13:00 +0900 Subject: [PATCH 3/9] #17 mutiple input to single input on account --- load_check.py | 67 +++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/load_check.py b/load_check.py index 50e77c4..a2649dd 100644 --- a/load_check.py +++ b/load_check.py @@ -34,42 +34,20 @@ class MultipleTest(unittest.TestCase): print("EMS 접속이 원할하지 않습니다. 프로그램을 종료합니다") sys.exit(1) - # A list is created to store multiple account configurations. self.account_configs = [] - # print("\n[필수 입력] 계정 정보를 한 줄씩 입력하세요. (포맷: 유형 / 아이디, 비번 / 세션 수)") print("\n3. [필수 입력] 계정유형(1-어드민,2-(지역)관리자,3-사용자) / 계정 접속정보 / 커넥션 비중") - print("ex) 1 / admin, admin / 3") - print("ex) 2 / watchall, watchall / 3") - print("ex) 3 / monitor, monitor / 4") - print("입력을 마치려면 빈 줄에서 엔터키를 누르세요.") + print("형식 예시: 1 / admin, admin / 3") + print("한 줄만 입력하세요. (빈 줄은 허용되지 않음)") - # A loop reads each line of input until an empty line is entered. while True: user_input = input("").strip() - if not user_input: - # Exit the loop if the input is empty. - if not self.account_configs: - print("입력된 계정 정보가 없습니다. 프로그램을 종료합니다.") - sys.exit(1) - break try: - # Each line is parsed and appended to the list as a dictionary. - parts = user_input.split(' / ') - account_type = int(parts[0].strip()) - credentials = parts[1].split(',') - username = credentials[0].strip() - password = credentials[1].strip() - duplicate_count = int(parts[2].strip()) - - config = { - "account_type": account_type, - "username": username, - "password": password, - "duplicate_count": duplicate_count - } + config = self._parse_account_line(user_input) self.account_configs.append(config) - except (ValueError, IndexError): - print(f"잘못된 입력 형식입니다: '{user_input}'. 해당 줄은 무시됩니다.") + # success -> stop re-prompting + break + except ValueError as e: + print(f"입력 형식 오류: {e}. 다시 입력하세요.") # New inputs for connection management print("\n4. [선택] 테스트 유형(기본값: 일반접속): 일반 접속(1), 일시 접속(2), 부하 화면 접근(3)") @@ -119,6 +97,37 @@ class MultipleTest(unittest.TestCase): else: print("[INFO] Default mode: saving screenshots only for first and last drivers.") + def _parse_account_line(self, user_input: str): + """Parse a single account config line in the format: + ' / username, password / duplicate_count' + Returns a dict on success or raises ValueError on bad format. + """ + if not user_input or not user_input.strip(): + raise ValueError("빈 입력입니다. 입력을 반복합니다.") + + parts = user_input.split(' / ') + if len(parts) < 3: + raise ValueError("입력 형식이 잘못되었습니다. 예시: 1 / admin, admin / 3") + + try: + account_type = int(parts[0].strip()) + credentials = parts[1].split(',') + if len(credentials) < 2: + raise ValueError("아이디와 비밀번호를 쉼표로 구분하세요. 예시: admin, admin") + username = credentials[0].strip() + password = credentials[1].strip() + duplicate_count = int(parts[2].strip()) + except ValueError as e: + # Preserve the original exception context for better debugging and satisfy pylint W0707 + raise ValueError(f"입력 형식 오류: {e}") from e + + return { + "account_type": account_type, + "username": username, + "password": password, + "duplicate_count": duplicate_count + } + def check_http_status(self, url: str, max_retry: int = 3, ignore_cert: bool = True) -> bool: """ Checks the HTTP status of the given URL. -- GitLab From ab78f76b2ffba5017717648ffe32dc3e1eaaa47c Mon Sep 17 00:00:00 2001 From: Watchtek Date: Fri, 17 Oct 2025 17:22:49 +0900 Subject: [PATCH 4/9] =?UTF-8?q?#12=20headless=20=EC=98=B5=EC=85=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- load_check.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/load_check.py b/load_check.py index a2649dd..9c6d2d3 100644 --- a/load_check.py +++ b/load_check.py @@ -572,7 +572,11 @@ class MultipleTest(unittest.TestCase): # Guest Mode options.add_argument('--guest') options.add_argument("--window-size=1920,1080") - options.add_argument("--headless=new") + headless = os.getenv("HEADLESS", "").lower() + if headless in ("0", "false", "n", "no"): + pass + else: + options.add_argument("--headless=new") # options.add_argument("--disable-gpu") options.binary_location = self.binary_location # Linux Only -- GitLab From d692368d6787e0422e224f081b9017fbee407e2f Mon Sep 17 00:00:00 2001 From: Watchtek Date: Thu, 23 Oct 2025 09:59:03 +0900 Subject: [PATCH 5/9] fix pyinstaller runtime error --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 037b84e..2fe374b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,6 +36,7 @@ variables: artifacts: false script: - echo "Creating artifact for $TARGET_OS" + - export HOME=/tmp - pip install -r requirements.txt - pyinstaller --onefile ${BINARY_NAME}.py - export TS=$(date +%Y-%m-%d_%H%M) -- GitLab From a35ce7a0f4195e283f72cc1316837669941fc411 Mon Sep 17 00:00:00 2001 From: Watchtek Date: Thu, 23 Oct 2025 10:46:39 +0900 Subject: [PATCH 6/9] Change user input on account type(remove dup count) --- load_check.py | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/load_check.py b/load_check.py index 9c6d2d3..fa095e1 100644 --- a/load_check.py +++ b/load_check.py @@ -35,9 +35,8 @@ class MultipleTest(unittest.TestCase): sys.exit(1) self.account_configs = [] - print("\n3. [필수 입력] 계정유형(1-어드민,2-(지역)관리자,3-사용자) / 계정 접속정보 / 커넥션 비중") - print("형식 예시: 1 / admin, admin / 3") - print("한 줄만 입력하세요. (빈 줄은 허용되지 않음)") + print("\n3. [필수 입력] 계정유형(1-어드민,2-(지역)관리자,3-사용자) / 계정 접속정보") + print("형식 예시: 1 / admin, admin") while True: user_input = input("").strip() @@ -50,12 +49,26 @@ class MultipleTest(unittest.TestCase): print(f"입력 형식 오류: {e}. 다시 입력하세요.") # New inputs for connection management - print("\n4. [선택] 테스트 유형(기본값: 일반접속): 일반 접속(1), 일시 접속(2), 부하 화면 접근(3)") - try: - self.function_to_execute = int(input().strip()) - except ValueError: - print("잘못된 입력입니다. 기본값 '일반 접속(1)'으로 설정합니다.") + print("\n4. [선택] 테스트 유형(기본값: 일반접속): 일반 접속(1), 대시보드 부하(2)") + user_input = input().strip() + + if not user_input: + # ✅ empty input → default + print("입력이 비어있습니다. 기본값 '일반 접속(1)'으로 설정합니다.") self.function_to_execute = 1 + else: + try: + choice = int(user_input) + # if choice in (1, 2): + if choice == 1: + self.function_to_execute = choice + else: + print("현재 스크립트는 일반 접속 방법만 지원합니다. '일반 접속(1)'으로 설정합니다.") + self.function_to_execute = 1 + except ValueError: + print("잘못 입력하셨습니다. 기본값 '일반 접속(1)'으로 설정합니다.") + self.function_to_execute = 1 + print("\n5. [선택] 커넥션 수 / 테스트 시간(분)(기본값: 30개 / 120분)") try: @@ -99,15 +112,15 @@ class MultipleTest(unittest.TestCase): def _parse_account_line(self, user_input: str): """Parse a single account config line in the format: - ' / username, password / duplicate_count' + ' / username, password' Returns a dict on success or raises ValueError on bad format. """ if not user_input or not user_input.strip(): - raise ValueError("빈 입력입니다. 입력을 반복합니다.") + raise ValueError("다시 입력해 주십시요.") parts = user_input.split(' / ') - if len(parts) < 3: - raise ValueError("입력 형식이 잘못되었습니다. 예시: 1 / admin, admin / 3") + if len(parts) < 2: + raise ValueError("입력 형식이 잘못되었습니다. 예시: 1 / admin, admin") try: account_type = int(parts[0].strip()) @@ -116,7 +129,6 @@ class MultipleTest(unittest.TestCase): raise ValueError("아이디와 비밀번호를 쉼표로 구분하세요. 예시: admin, admin") username = credentials[0].strip() password = credentials[1].strip() - duplicate_count = int(parts[2].strip()) except ValueError as e: # Preserve the original exception context for better debugging and satisfy pylint W0707 raise ValueError(f"입력 형식 오류: {e}") from e @@ -125,7 +137,6 @@ class MultipleTest(unittest.TestCase): "account_type": account_type, "username": username, "password": password, - "duplicate_count": duplicate_count } def check_http_status(self, url: str, max_retry: int = 3, ignore_cert: bool = True) -> bool: -- GitLab From 216fcf27ef8131b561019e7921f2f923df84878e Mon Sep 17 00:00:00 2001 From: Watchtek Date: Thu, 23 Oct 2025 10:58:21 +0900 Subject: [PATCH 7/9] Add validation check on user input 1 --- load_check.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/load_check.py b/load_check.py index fa095e1..59cb88d 100644 --- a/load_check.py +++ b/load_check.py @@ -23,8 +23,20 @@ class MultipleTest(unittest.TestCase): def _get_user_inputs(self): """Helper method to get user inputs and set up initial configuration.""" # Test case user input - print("1. [필수 입력] Chrome 위치 (e.g., /opt/chrome-linux64/chrome, D:\\tmp\\chrome-win64\\chrome.exe): ") - self.binary_location = input().strip() + while True: + print("1. [필수 입력] Chrome 위치 (e.g., /opt/chrome-linux64/chrome, D:\\tmp\\chrome-win64\\chrome.exe): ") + chrome_path = input().strip() + + if not chrome_path: + print("잘못 입력하였습니다. 다시 입력해주세요.\n") + continue + + if os.path.exists(chrome_path) and os.path.isfile(chrome_path): + self.binary_location = chrome_path + break + else: + print(f"입력한 경로가 존재하지 않거나 파일이 아닙니다: {chrome_path}") + print("다시 입력해주세요.\n") print("\n2. [필수 입력] 테스트 대상 웹 (e.g., https://example.com:8443/): ") self.dc_address = input() -- GitLab From 0fa0a707fd16185978d5c8e25fb550049c03c2cf Mon Sep 17 00:00:00 2001 From: Watchtek Date: Thu, 23 Oct 2025 11:03:16 +0900 Subject: [PATCH 8/9] fix R1723 --- load_check.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/load_check.py b/load_check.py index 59cb88d..913d7bf 100644 --- a/load_check.py +++ b/load_check.py @@ -34,9 +34,9 @@ class MultipleTest(unittest.TestCase): if os.path.exists(chrome_path) and os.path.isfile(chrome_path): self.binary_location = chrome_path break - else: - print(f"입력한 경로가 존재하지 않거나 파일이 아닙니다: {chrome_path}") - print("다시 입력해주세요.\n") + + print(f"입력한 경로가 존재하지 않거나 파일이 아닙니다: {chrome_path}") + print("다시 입력해주세요.\n") print("\n2. [필수 입력] 테스트 대상 웹 (e.g., https://example.com:8443/): ") self.dc_address = input() -- GitLab From 74f1db2b483fde1968e622d4c53dc9345def3e0c Mon Sep 17 00:00:00 2001 From: Watchtek Date: Thu, 23 Oct 2025 11:05:24 +0900 Subject: [PATCH 9/9] fix C0303 --- load_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/load_check.py b/load_check.py index 913d7bf..68bb714 100644 --- a/load_check.py +++ b/load_check.py @@ -34,7 +34,7 @@ class MultipleTest(unittest.TestCase): if os.path.exists(chrome_path) and os.path.isfile(chrome_path): self.binary_location = chrome_path break - + print(f"입력한 경로가 존재하지 않거나 파일이 아닙니다: {chrome_path}") print("다시 입력해주세요.\n") -- GitLab