11import logging
2+ import queue
3+ from typing import Optional
24
35from PySide6 .QtCore import QTimer
46from PySide6 .QtGui import QIntValidator
5- from PySide6 .QtWidgets import QWidget , QFormLayout , QLineEdit , QComboBox , QPushButton , QTextEdit , QVBoxLayout , QLabel
7+ from PySide6 .QtWidgets import (
8+ QWidget , QFormLayout , QLineEdit , QComboBox ,
9+ QPushButton , QTextEdit , QVBoxLayout , QLabel , QMessageBox
10+ )
611
712from je_load_density .gui .load_density_gui_thread import LoadDensityGUIThread
813from je_load_density .gui .language_wrapper .multi_language_wrapper import language_wrapper
9- from je_load_density .gui .log_to_ui_filter import InterceptAllFilter , locust_log_queue
14+ from je_load_density .gui .log_to_ui_filter import InterceptAllFilter , log_message_queue
1015
1116
1217class LoadDensityWidget (QWidget ):
18+ """
19+ 負載測試 GUI 控制元件
20+ Load Test GUI Widget
1321
14- def __init__ (self , parent = None ):
22+ 提供使用者輸入測試參數並啟動負載測試,
23+ 並將日誌訊息即時顯示在 GUI 中。
24+ Provides input fields for test parameters, starts load tests,
25+ and displays log messages in real-time.
26+ """
27+
28+ def __init__ (self , parent : Optional [QWidget ] = None ):
1529 super ().__init__ (parent )
16- # from
30+
31+ # === 表單區域 (Form Section) ===
1732 form_layout = QFormLayout ()
33+
34+ # URL 輸入框 (Target URL input)
1835 self .url_input = QLineEdit ()
36+
37+ # 測試時間 (Test duration, must be int)
1938 self .test_time_input = QLineEdit ()
2039 self .test_time_input .setValidator (QIntValidator ())
40+
41+ # 使用者數量 (User count)
2142 self .user_count_input = QLineEdit ()
2243 self .user_count_input .setValidator (QIntValidator ())
44+
45+ # 生成速率 (Spawn rate)
2346 self .spawn_rate_input = QLineEdit ()
2447 self .spawn_rate_input .setValidator (QIntValidator ())
48+
49+ # HTTP 方法選擇 (HTTP method selection)
2550 self .method_combobox = QComboBox ()
2651 self .method_combobox .addItems ([
2752 language_wrapper .language_word_dict .get ("get" ),
@@ -32,50 +57,75 @@ def __init__(self, parent=None):
3257 language_wrapper .language_word_dict .get ("head" ),
3358 language_wrapper .language_word_dict .get ("options" ),
3459 ])
60+
61+ # 將元件加入表單 (Add widgets to form layout)
3562 form_layout .addRow (language_wrapper .language_word_dict .get ("url" ), self .url_input )
3663 form_layout .addRow (language_wrapper .language_word_dict .get ("test_time" ), self .test_time_input )
3764 form_layout .addRow (language_wrapper .language_word_dict .get ("user_count" ), self .user_count_input )
3865 form_layout .addRow (language_wrapper .language_word_dict .get ("spawn_rate" ), self .spawn_rate_input )
3966 form_layout .addRow (language_wrapper .language_word_dict .get ("test_method" ), self .method_combobox )
4067
68+ # === 啟動按鈕 (Start button) ===
4169 self .start_button = QPushButton (language_wrapper .language_word_dict .get ("start_button" ))
4270 self .start_button .clicked .connect (self .run_load_density )
4371
44- # Log panel
72+ # === 日誌面板 ( Log panel) ===
4573 self .log_panel = QTextEdit ()
4674 self .log_panel .setReadOnly (True )
4775
48- # Add widget to vertical layout
76+ # === 主版面配置 (Main layout) ===
4977 main_layout = QVBoxLayout ()
5078 main_layout .addLayout (form_layout )
5179 main_layout .addWidget (self .start_button )
5280 main_layout .addWidget (QLabel (language_wrapper .language_word_dict .get ("log" )))
5381 main_layout .addWidget (self .log_panel )
5482
55- # Param
56- self .run_load_density_thread = None
83+ # === 執行緒與計時器 (Thread & Timer) ===
84+ self .run_load_density_thread : Optional [ LoadDensityGUIThread ] = None
5785 self .pull_log_timer = QTimer ()
58- self .pull_log_timer .setInterval (20 )
86+ self .pull_log_timer .setInterval (50 ) # 稍微放大間隔,避免 UI 卡頓
5987 self .pull_log_timer .timeout .connect (self .add_text_to_log )
6088
6189 self .setLayout (main_layout )
6290
63- def run_load_density (self ):
91+ def run_load_density (self ) -> None :
92+ """
93+ 啟動負載測試
94+ Start the load test
95+ """
96+ try :
97+ test_time = int (self .test_time_input .text ())
98+ user_count = int (self .user_count_input .text ())
99+ spawn_rate = int (self .spawn_rate_input .text ())
100+ except ValueError :
101+ QMessageBox .warning (self , "Invalid Input" , "請輸入有效的數字\n Please enter valid numbers" )
102+ return
103+
64104 self .run_load_density_thread = LoadDensityGUIThread ()
65- self .run_load_density_thread .url = self .url_input .text ()
66- self .run_load_density_thread .test_time = int (self .test_time_input .text ())
67- self .run_load_density_thread .user_count = int (self .user_count_input .text ())
68- self .run_load_density_thread .spawn_rate = int (self .spawn_rate_input .text ())
69- self .run_load_density_thread .method = self .method_combobox .currentText ().lower ()
70- log_handler_list = [handler for handler in logging .getLogger ("root" ).handlers if handler .name == "log_reader" ]
105+ self .run_load_density_thread .request_url = self .url_input .text ()
106+ self .run_load_density_thread .test_duration = test_time
107+ self .run_load_density_thread .user_count = user_count
108+ self .run_load_density_thread .spawn_rate = spawn_rate
109+ self .run_load_density_thread .http_method = self .method_combobox .currentText ().lower ()
110+
111+ # 設定日誌攔截器 (Attach log filter)
112+ root_logger = logging .getLogger ("root" )
113+ log_handler_list = [handler for handler in root_logger .handlers if handler .name == "log_reader" ]
71114 if log_handler_list :
72115 log_handler = log_handler_list [0 ]
73- log_handler .addFilter (InterceptAllFilter ())
116+ # 避免重複新增 Filter (Prevent duplicate filters)
117+ if not any (isinstance (f , InterceptAllFilter ) for f in log_handler .filters ):
118+ log_handler .addFilter (InterceptAllFilter ())
119+
120+ # 啟動執行緒與計時器 (Start thread & timer)
74121 self .run_load_density_thread .start ()
75- self .pull_log_timer .stop ()
76122 self .pull_log_timer .start ()
77123 self .log_panel .clear ()
78124
79- def add_text_to_log (self ):
80- if not locust_log_queue .empty ():
81- self .log_panel .append (locust_log_queue .get_nowait ())
125+ def add_text_to_log (self ) -> None :
126+ """
127+ 將日誌訊息加入到 GUI 面板
128+ Append log messages to GUI panel
129+ """
130+ while not log_message_queue .empty ():
131+ self .log_panel .append (log_message_queue .get_nowait ())
0 commit comments