import csv import os import time from datetime import datetime import pytest from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from tests.browser import create_chrome_driver from tests.config_reader import load_config from tests.helpers import login, logout from tests.locators import Locator LOGIN_ATTEMPTS = 50 MAX_CAPTCHA_RETRIES = 7 @pytest.mark.captcha def test_captcha_login_stress(): """Run bounded EasyOCR login attempts and retain auditable CAPTCHA evidence.""" config = load_config() output_dir = os.path.abspath(os.path.join("reports", "captcha_login_stress")) os.makedirs(output_dir, exist_ok=True) started = datetime.now().strftime("%Y%m%d_%H%M%S") csv_path = os.path.join(output_dir, f"captcha_login_{started}.csv") rows = [] passed = 0 failed = 0 def record(row): rows.append(row) for login_number in range(1, LOGIN_ATTEMPTS + 1): login_started = datetime.now().isoformat(timespec="seconds") captcha_rows = [] driver = create_chrome_driver() try: driver.get(config["url"]) login_status = "FAILED" logout_status = "NOT_ATTEMPTED" error_text = "" captcha_metrics = {"captcha_attempts": []} try: login( driver, config["login"]["username"], config["login"]["password"], max_captcha_retries=MAX_CAPTCHA_RETRIES, captcha_metrics=captcha_metrics, max_login_duration_seconds=1200, ) login_status = "PASSED" passed += 1 except Exception as exc: failed += 1 error_text = f"{type(exc).__name__}: {exc}" try: driver.save_screenshot(os.path.join(output_dir, f"login_{login_number:03d}_failure.png")) except Exception: pass finally: # Explicitly log out after a successful authenticated flow, # then close the browser session. if login_status == "PASSED": try: logout_status = "PASSED" if logout(driver) else "FAILED" except Exception as exc: logout_status = "FAILED" print(f"Logout error: {type(exc).__name__}: {exc}") try: driver.quit() except Exception: pass captcha_rows = captcha_metrics.get("captcha_attempts", []) or [{ "attempt": 0, "captcha_text": "", "variant": "", "status": "no_captcha_record", "screenshot": "", "error": error_text, }] for item in captcha_rows: record({ "login_attempt": login_number, "started_at": login_started, "login_status": login_status, "logout_status": logout_status, "captcha_attempt": item["attempt"], "attempted_captcha": item["variant"], "ocr_captcha": item["captcha_text"], "screenshot_path": item["screenshot"], "captcha_status": item["status"], "captcha_entered_count": sum( 1 for captcha_row in captcha_rows if captcha_row["variant"] ), "error": item["error"] or error_text, "attempts_to_result": len(captcha_rows), "passed_count": passed, "failed_count": failed, }) finally: # Clean up the driver after all attempts try: driver.quit() except Exception: pass fieldnames = [ "login_attempt", "started_at", "login_status", "captcha_attempt", "logout_status", "attempted_captcha", "ocr_captcha", "screenshot_path", "captcha_status", "captcha_entered_count", "error", "attempts_to_result", "passed_count", "failed_count", ] with open(csv_path, "w", newline="", encoding="utf-8") as report: writer = csv.DictWriter(report, fieldnames=fieldnames) writer.writeheader() writer.writerows(rows) print(f"CAPTCHA stress report: {csv_path}") print(f"Passed: {passed}; Failed: {failed}; Total: {LOGIN_ATTEMPTS}")