CP_StressTest
This commit is contained in:
parent
b44e165212
commit
e7b7a7538a
@ -8,4 +8,17 @@ python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--start 0 --end 1 \
|
||||
--workers 1 \
|
||||
--metrics-interval 1 \
|
||||
--headless
|
||||
--headless
|
||||
|
||||
|
||||
|
||||
PC 1 - 60 Students (20 from each CSV)
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 0 --end 20 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 0 --end 20 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 0 --end 20 --workers 10 --headless --metrics-interval 5 & wait
|
||||
PC 2 - 60 Students (20 from each CSV)
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 20 --end 40 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 20 --end 40 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 20 --end 40 --workers 10 --headless --metrics-interval 5 & wait
|
||||
PC 3 - 60 Students (20 from each CSV)
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 40 --end 60 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 40 --end 60 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 40 --end 60 --workers 10 --headless --metrics-interval 5 & wait
|
||||
PC 4 - 60 Students (20 from each CSV)
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 60 --end 80 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 60 --end 80 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 60 --end 80 --workers 10 --headless --metrics-interval 5 & wait
|
||||
PC 5 - 60 Students (20 from each CSV)
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 80 --end 100 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 80 --end 100 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 80 --end 100 --workers 10 --headless --metrics-interval 5 & wait
|
||||
|
||||
@ -34,7 +34,8 @@ class BasePage:
|
||||
self.wait_for_page_load()
|
||||
|
||||
def wait_for_page_load(self):
|
||||
"""Wait for page to load completely"""
|
||||
"""Wait for page to load completely (machine-speed optimized)"""
|
||||
# Machine-speed: Both methods now return immediately if already ready
|
||||
self.wait.wait_for_page_load()
|
||||
self.wait.wait_for_loading_to_disappear()
|
||||
|
||||
|
||||
@ -234,9 +234,9 @@ class DomainAssessmentPage(BasePage):
|
||||
self.wait_for_page_load()
|
||||
|
||||
def click_next(self):
|
||||
"""Click Next button"""
|
||||
"""Click Next button (machine-speed optimized)"""
|
||||
self.click_element(self.NEXT_BUTTON)
|
||||
# Wait for next question to load
|
||||
# Machine-speed: Minimal wait - page load check returns immediately if already loaded
|
||||
self.wait_for_page_load()
|
||||
|
||||
def click_submit(self):
|
||||
|
||||
132
scripts/5_PC_LOAD_TEST_COMMANDS.md
Normal file
132
scripts/5_PC_LOAD_TEST_COMMANDS.md
Normal file
@ -0,0 +1,132 @@
|
||||
# 5 PC Load Test Commands - Complete Distribution
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
All 3 CSVs have 100 students each (300 total). Distributed across 5 PCs:
|
||||
- **Each PC**: 20 students from CSV 1 + 20 from CSV 2 + 20 from CSV 3 = **60 students per PC**
|
||||
- **Total**: 300 students across 5 PCs
|
||||
- **Concurrent browsers**: 30 per PC (10 per CSV batch) = **150 total browsers**
|
||||
|
||||
---
|
||||
|
||||
## 📊 Distribution Plan
|
||||
|
||||
| PC | CSV 1 | CSV 2 | CSV 3 | Total Students | Workers |
|
||||
|----|-------|-------|-------|----------------|---------|
|
||||
| PC 1 | 0-19 (20) | 0-19 (20) | 0-19 (20) | 60 | 30 (10×3) |
|
||||
| PC 2 | 20-39 (20) | 20-39 (20) | 20-39 (20) | 60 | 30 (10×3) |
|
||||
| PC 3 | 40-59 (20) | 40-59 (20) | 40-59 (20) | 60 | 30 (10×3) |
|
||||
| PC 4 | 60-79 (20) | 60-79 (20) | 60-79 (20) | 60 | 30 (10×3) |
|
||||
| PC 5 | 80-99 (20) | 80-99 (20) | 80-99 (20) | 60 | 30 (10×3) |
|
||||
| **Total** | **100** | **100** | **100** | **300** | **150** |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Complete Commands (Copy-Paste Ready)
|
||||
|
||||
### **PC 1 - 60 Students (20 from each CSV)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 0 --end 20 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 0 --end 20 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 0 --end 20 --workers 10 --headless --metrics-interval 5 & wait
|
||||
```
|
||||
|
||||
### **PC 2 - 60 Students (20 from each CSV)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 20 --end 40 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 20 --end 40 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 20 --end 40 --workers 10 --headless --metrics-interval 5 & wait
|
||||
```
|
||||
|
||||
### **PC 3 - 60 Students (20 from each CSV)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 40 --end 60 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 40 --end 60 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 40 --end 60 --workers 10 --headless --metrics-interval 5 & wait
|
||||
```
|
||||
|
||||
### **PC 4 - 60 Students (20 from each CSV)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 60 --end 80 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 60 --end 80 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 60 --end 80 --workers 10 --headless --metrics-interval 5 & wait
|
||||
```
|
||||
|
||||
### **PC 5 - 60 Students (20 from each CSV)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 80 --end 100 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 80 --end 100 --workers 10 --headless --metrics-interval 5 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 80 --end 100 --workers 10 --headless --metrics-interval 5 & wait
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Using Shell Scripts (Recommended)
|
||||
|
||||
### **On PC 1:**
|
||||
```bash
|
||||
chmod +x scripts/PC1_60_students.sh
|
||||
./scripts/PC1_60_students.sh
|
||||
```
|
||||
|
||||
### **On PC 2:**
|
||||
```bash
|
||||
chmod +x scripts/PC2_60_students.sh
|
||||
./scripts/PC2_60_students.sh
|
||||
```
|
||||
|
||||
### **On PC 3:**
|
||||
```bash
|
||||
chmod +x scripts/PC3_60_students.sh
|
||||
./scripts/PC3_60_students.sh
|
||||
```
|
||||
|
||||
### **On PC 4:**
|
||||
```bash
|
||||
chmod +x scripts/PC4_60_students.sh
|
||||
./scripts/PC4_60_students.sh
|
||||
```
|
||||
|
||||
### **On PC 5:**
|
||||
```bash
|
||||
chmod +x scripts/PC5_60_students.sh
|
||||
./scripts/PC5_60_students.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌐 With Custom URL
|
||||
|
||||
Add `--url` to each command in the script, or modify the shell scripts:
|
||||
|
||||
**Example for PC 1 with custom URL:**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 0 --end 20 --workers 10 --headless --metrics-interval 5 --url http://localhost:3983 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 0 --end 20 --workers 10 --headless --metrics-interval 5 --url http://localhost:3983 & python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 0 --end 20 --workers 10 --headless --metrics-interval 5 --url http://localhost:3983 & wait
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Summary
|
||||
|
||||
- **Total Students**: 300 (100 from each CSV)
|
||||
- **Total PCs**: 5
|
||||
- **Students per PC**: 60 (20 from each CSV)
|
||||
- **Concurrent Browsers per PC**: 30 (10 per CSV batch)
|
||||
- **Total Concurrent Browsers**: 150
|
||||
- **Distribution**: Evenly distributed across all CSVs and PCs
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Execution Steps
|
||||
|
||||
1. **On PC 1**: Run PC 1 command/script
|
||||
2. **On PC 2**: Run PC 2 command/script
|
||||
3. **On PC 3**: Run PC 3 command/script
|
||||
4. **On PC 4**: Run PC 4 command/script
|
||||
5. **On PC 5**: Run PC 5 command/script
|
||||
6. **Monitor**: Each PC will run 3 parallel processes (one per CSV)
|
||||
|
||||
---
|
||||
|
||||
## 💡 Notes
|
||||
|
||||
- Each PC runs **3 parallel processes** (one for each CSV)
|
||||
- Each process handles **20 students** with **10 workers**
|
||||
- All processes run in **background** and wait for completion
|
||||
- **Metrics** printed every 5 students per process
|
||||
- **Reports** saved separately for each CSV batch
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ Ready to Execute - 300 Students Across 5 PCs
|
||||
|
||||
93
scripts/6_PC_LOAD_TEST_COMMANDS.md
Normal file
93
scripts/6_PC_LOAD_TEST_COMMANDS.md
Normal file
@ -0,0 +1,93 @@
|
||||
# 6 PC Load Test Commands - 50 Students Each
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
6 PCs, each running 50 students simultaneously. Total: 300 students (100 from each CSV).
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Complete Commands (Copy-Paste Ready)
|
||||
|
||||
### **PC 1 - 50 Students from CSV 1 (indices 0-49)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 0 --end 50 --workers 50 --headless --metrics-interval 10
|
||||
```
|
||||
|
||||
### **PC 2 - 50 Students from CSV 1 (indices 50-99)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 50 --end 100 --workers 50 --headless --metrics-interval 10
|
||||
```
|
||||
|
||||
### **PC 3 - 50 Students from CSV 2 (indices 0-49)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 0 --end 50 --workers 50 --headless --metrics-interval 10
|
||||
```
|
||||
|
||||
### **PC 4 - 50 Students from CSV 2 (indices 50-99)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 50 --end 100 --workers 50 --headless --metrics-interval 10
|
||||
```
|
||||
|
||||
### **PC 5 - 50 Students from CSV 3 (indices 0-49)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 0 --end 50 --workers 50 --headless --metrics-interval 10
|
||||
```
|
||||
|
||||
### **PC 6 - 50 Students from CSV 3 (indices 50-99)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 50 --end 100 --workers 50 --headless --metrics-interval 10
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Distribution
|
||||
|
||||
| PC | CSV File | Students | Indices | Workers |
|
||||
|----|----------|----------|---------|---------|
|
||||
| PC 1 | CSV 1 | 50 | 0-49 | 50 |
|
||||
| PC 2 | CSV 1 | 50 | 50-99 | 50 |
|
||||
| PC 3 | CSV 2 | 50 | 0-49 | 50 |
|
||||
| PC 4 | CSV 2 | 50 | 50-99 | 50 |
|
||||
| PC 5 | CSV 3 | 50 | 0-49 | 50 |
|
||||
| PC 6 | CSV 3 | 50 | 50-99 | 50 |
|
||||
| **Total** | **3 CSVs** | **300** | **-** | **300** |
|
||||
|
||||
---
|
||||
|
||||
## 📝 Using Shell Scripts
|
||||
|
||||
**On each PC:**
|
||||
```bash
|
||||
# PC 1
|
||||
./scripts/PC1_50_students.sh
|
||||
|
||||
# PC 2
|
||||
./scripts/PC2_50_students.sh
|
||||
|
||||
# PC 3
|
||||
./scripts/PC3_50_students.sh
|
||||
|
||||
# PC 4
|
||||
./scripts/PC4_50_students.sh
|
||||
|
||||
# PC 5
|
||||
./scripts/PC5_50_students.sh
|
||||
|
||||
# PC 6
|
||||
./scripts/PC6_50_students.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌐 With Custom URL
|
||||
|
||||
Add `--url` to any command:
|
||||
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 0 --end 50 --workers 50 --headless --metrics-interval 10 --url http://localhost:3983
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ Ready - 6 PCs, 50 Students Each, All Running Simultaneously
|
||||
|
||||
132
scripts/MULTI_SYSTEM_COMMANDS.md
Normal file
132
scripts/MULTI_SYSTEM_COMMANDS.md
Normal file
@ -0,0 +1,132 @@
|
||||
# Multi-System Load Test Commands
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
Complete commands to run load tests across multiple systems, with each system handling 50 students from different CSV files.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Available CSV Files
|
||||
|
||||
1. `students_with_passwords_2025-12-15T10-49-08_01.csv`
|
||||
2. `students_with_passwords_2025-12-15T10-59-02_03.csv`
|
||||
3. `students_with_passwords_2025-12-15T11-06-37_05.csv`
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Complete Commands (Copy-Paste Ready)
|
||||
|
||||
### **SYSTEM 1 - PC 1**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 0 --end 50 --workers 20 --headless --metrics-interval 10
|
||||
```
|
||||
|
||||
### **SYSTEM 2 - PC 2**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 0 --end 50 --workers 20 --headless --metrics-interval 10
|
||||
```
|
||||
|
||||
### **SYSTEM 3 - PC 3**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 0 --end 50 --workers 20 --headless --metrics-interval 10
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌐 With Custom URL
|
||||
|
||||
If you need to specify a custom frontend URL, add `--url` argument:
|
||||
|
||||
### **SYSTEM 1 - PC 1 (with custom URL)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-49-08_01.csv --start 0 --end 50 --workers 20 --headless --metrics-interval 10 --url http://localhost:3983
|
||||
```
|
||||
|
||||
### **SYSTEM 2 - PC 2 (with custom URL)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T10-59-02_03.csv --start 0 --end 50 --workers 20 --headless --metrics-interval 10 --url http://localhost:3983
|
||||
```
|
||||
|
||||
### **SYSTEM 3 - PC 3 (with custom URL)**
|
||||
```bash
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && source venv/bin/activate && python3 tests/load_tests/test_generic_load_assessments.py --csv students_with_passwords_2025-12-15T11-06-37_05.csv --start 0 --end 50 --workers 20 --headless --metrics-interval 10 --url http://localhost:3983
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Using Shell Scripts
|
||||
|
||||
Alternatively, use the provided shell scripts:
|
||||
|
||||
### **On PC 1:**
|
||||
```bash
|
||||
chmod +x scripts/PC1_50_students.sh
|
||||
./scripts/PC1_50_students.sh
|
||||
```
|
||||
|
||||
### **On PC 2:**
|
||||
```bash
|
||||
chmod +x scripts/PC2_50_students.sh
|
||||
./scripts/PC2_50_students.sh
|
||||
```
|
||||
|
||||
### **On PC 3:**
|
||||
```bash
|
||||
chmod +x scripts/PC3_50_students.sh
|
||||
./scripts/PC3_50_students.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Configuration Summary
|
||||
|
||||
| System | CSV File | Students | Indices | Workers | Total Load |
|
||||
|--------|----------|----------|---------|---------|------------|
|
||||
| PC 1 | `2025-12-15T10-49-08_01.csv` | 50 | 0-49 | 20 | 50 students |
|
||||
| PC 2 | `2025-12-15T10-59-02_03.csv` | 50 | 0-49 | 20 | 50 students |
|
||||
| PC 3 | `2025-12-15T11-06-37_05.csv` | 50 | 0-49 | 20 | 50 students |
|
||||
| **Total** | **3 CSVs** | **150** | **-** | **60** | **150 students** |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Command Breakdown
|
||||
|
||||
- `--csv`: CSV file path
|
||||
- `--start 0`: Start from first student (index 0)
|
||||
- `--end 50`: End at 50th student (exclusive, so indices 0-49)
|
||||
- `--workers 20`: 20 concurrent browsers per system
|
||||
- `--headless`: Run in headless mode
|
||||
- `--metrics-interval 10`: Print metrics every 10 students
|
||||
- `--url` (optional): Custom frontend URL
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Execution Steps
|
||||
|
||||
1. **On PC 1**: Run the PC 1 command
|
||||
2. **On PC 2**: Run the PC 2 command
|
||||
3. **On PC 3**: Run the PC 3 command
|
||||
4. **Monitor**: Each system will print real-time metrics
|
||||
|
||||
---
|
||||
|
||||
## 📈 Expected Results
|
||||
|
||||
- **Total Students**: 150 (50 per system)
|
||||
- **Concurrent Browsers**: 60 total (20 per system)
|
||||
- **Load Distribution**: Evenly distributed across 3 systems
|
||||
- **Execution Time**: ~20-40 minutes per system (depending on performance)
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips
|
||||
|
||||
1. **Start all systems simultaneously** for maximum load
|
||||
2. **Monitor each system** for real-time metrics
|
||||
3. **Check reports** in `reports/load_tests/` after completion
|
||||
4. **Use `--url`** if testing against different environments
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ Ready to Execute
|
||||
|
||||
66
scripts/MULTI_SYSTEM_LOAD_TEST.sh
Executable file
66
scripts/MULTI_SYSTEM_LOAD_TEST.sh
Executable file
@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
# Multi-System Load Test Commands
|
||||
# Each system takes 50 students from different CSVs
|
||||
# Run these commands on respective systems
|
||||
|
||||
# ============================================================================
|
||||
# SYSTEM 1 - PC 1
|
||||
# ============================================================================
|
||||
# 50 students from first CSV (indices 0-49)
|
||||
# Command to run on PC 1:
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && \
|
||||
source venv/bin/activate && \
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 50 \
|
||||
--workers 20 \
|
||||
--headless \
|
||||
--metrics-interval 10
|
||||
|
||||
# ============================================================================
|
||||
# SYSTEM 2 - PC 2
|
||||
# ============================================================================
|
||||
# 50 students from second CSV (indices 0-49)
|
||||
# Command to run on PC 2:
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && \
|
||||
source venv/bin/activate && \
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-59-02_03.csv \
|
||||
--start 0 --end 50 \
|
||||
--workers 20 \
|
||||
--headless \
|
||||
--metrics-interval 10
|
||||
|
||||
# ============================================================================
|
||||
# SYSTEM 3 - PC 3
|
||||
# ============================================================================
|
||||
# 50 students from third CSV (indices 0-49)
|
||||
# Command to run on PC 3:
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test && \
|
||||
source venv/bin/activate && \
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T11-06-37_05.csv \
|
||||
--start 0 --end 50 \
|
||||
--workers 20 \
|
||||
--headless \
|
||||
--metrics-interval 10
|
||||
|
||||
# ============================================================================
|
||||
# WITH CUSTOM URL (if needed)
|
||||
# ============================================================================
|
||||
# Add --url argument to use custom frontend URL
|
||||
# Example for PC 1 with custom URL:
|
||||
|
||||
# cd /home/tech4biz/work/CP_Front_Automation_Test && \
|
||||
# source venv/bin/activate && \
|
||||
# python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
# --csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
# --start 0 --end 50 \
|
||||
# --workers 20 \
|
||||
# --headless \
|
||||
# --metrics-interval 10 \
|
||||
# --url http://localhost:3983
|
||||
|
||||
13
scripts/PC1_50_students.sh
Executable file
13
scripts/PC1_50_students.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
# PC 1 - 50 students from CSV 1 (indices 0-49)
|
||||
# Run this on PC 1
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 50 \
|
||||
--workers 50 \
|
||||
--headless \
|
||||
--metrics-interval 10
|
||||
36
scripts/PC1_60_students.sh
Executable file
36
scripts/PC1_60_students.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# PC 1 - Load Test Command
|
||||
# 20 students from each CSV (60 total)
|
||||
# CSV 1: indices 0-19, CSV 2: indices 0-19, CSV 3: indices 0-19
|
||||
# Run this on PC 1
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
# Run CSV 1 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 20 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 2 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-59-02_03.csv \
|
||||
--start 0 --end 20 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 3 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T11-06-37_05.csv \
|
||||
--start 0 --end 20 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Wait for all background processes
|
||||
wait
|
||||
|
||||
13
scripts/PC2_50_students.sh
Executable file
13
scripts/PC2_50_students.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
# PC 2 - 50 students from CSV 1 (indices 50-99)
|
||||
# Run this on PC 2
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 50 --end 100 \
|
||||
--workers 50 \
|
||||
--headless \
|
||||
--metrics-interval 10
|
||||
36
scripts/PC2_60_students.sh
Executable file
36
scripts/PC2_60_students.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# PC 2 - Load Test Command
|
||||
# 20 students from each CSV (60 total)
|
||||
# CSV 1: indices 20-39, CSV 2: indices 20-39, CSV 3: indices 20-39
|
||||
# Run this on PC 2
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
# Run CSV 1 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 20 --end 40 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 2 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-59-02_03.csv \
|
||||
--start 20 --end 40 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 3 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T11-06-37_05.csv \
|
||||
--start 20 --end 40 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Wait for all background processes
|
||||
wait
|
||||
|
||||
13
scripts/PC3_50_students.sh
Executable file
13
scripts/PC3_50_students.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
# PC 3 - 50 students from CSV 2 (indices 0-49)
|
||||
# Run this on PC 3
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-59-02_03.csv \
|
||||
--start 0 --end 50 \
|
||||
--workers 50 \
|
||||
--headless \
|
||||
--metrics-interval 10
|
||||
36
scripts/PC3_60_students.sh
Executable file
36
scripts/PC3_60_students.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# PC 3 - Load Test Command
|
||||
# 20 students from each CSV (60 total)
|
||||
# CSV 1: indices 40-59, CSV 2: indices 40-59, CSV 3: indices 40-59
|
||||
# Run this on PC 3
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
# Run CSV 1 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 40 --end 60 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 2 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-59-02_03.csv \
|
||||
--start 40 --end 60 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 3 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T11-06-37_05.csv \
|
||||
--start 40 --end 60 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Wait for all background processes
|
||||
wait
|
||||
|
||||
14
scripts/PC4_50_students.sh
Executable file
14
scripts/PC4_50_students.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# PC 4 - 50 students from CSV 2 (indices 50-99)
|
||||
# Run this on PC 4
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-59-02_03.csv \
|
||||
--start 50 --end 100 \
|
||||
--workers 50 \
|
||||
--headless \
|
||||
--metrics-interval 10
|
||||
|
||||
36
scripts/PC4_60_students.sh
Executable file
36
scripts/PC4_60_students.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# PC 4 - Load Test Command
|
||||
# 20 students from each CSV (60 total)
|
||||
# CSV 1: indices 60-79, CSV 2: indices 60-79, CSV 3: indices 60-79
|
||||
# Run this on PC 4
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
# Run CSV 1 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 60 --end 80 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 2 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-59-02_03.csv \
|
||||
--start 60 --end 80 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 3 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T11-06-37_05.csv \
|
||||
--start 60 --end 80 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Wait for all background processes
|
||||
wait
|
||||
|
||||
14
scripts/PC5_50_students.sh
Executable file
14
scripts/PC5_50_students.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# PC 5 - 50 students from CSV 3 (indices 0-49)
|
||||
# Run this on PC 5
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T11-06-37_05.csv \
|
||||
--start 0 --end 50 \
|
||||
--workers 50 \
|
||||
--headless \
|
||||
--metrics-interval 10
|
||||
|
||||
36
scripts/PC5_60_students.sh
Executable file
36
scripts/PC5_60_students.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# PC 5 - Load Test Command
|
||||
# 20 students from each CSV (60 total)
|
||||
# CSV 1: indices 80-99, CSV 2: indices 80-99, CSV 3: indices 80-99
|
||||
# Run this on PC 5
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
# Run CSV 1 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 80 --end 100 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 2 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-59-02_03.csv \
|
||||
--start 80 --end 100 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Run CSV 3 (20 students)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T11-06-37_05.csv \
|
||||
--start 80 --end 100 \
|
||||
--workers 10 \
|
||||
--headless \
|
||||
--metrics-interval 5 &
|
||||
|
||||
# Wait for all background processes
|
||||
wait
|
||||
|
||||
14
scripts/PC6_50_students.sh
Executable file
14
scripts/PC6_50_students.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# PC 6 - 50 students from CSV 3 (indices 50-99)
|
||||
# Run this on PC 6
|
||||
|
||||
cd /home/tech4biz/work/CP_Front_Automation_Test
|
||||
source venv/bin/activate
|
||||
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T11-06-37_05.csv \
|
||||
--start 50 --end 100 \
|
||||
--workers 50 \
|
||||
--headless \
|
||||
--metrics-interval 10
|
||||
|
||||
138
tests/load_tests/CUSTOM_URL_USAGE.md
Normal file
138
tests/load_tests/CUSTOM_URL_USAGE.md
Normal file
@ -0,0 +1,138 @@
|
||||
# Custom URL Usage Guide
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
The load test script now supports a `--url` argument to use any frontend URL dynamically.
|
||||
|
||||
---
|
||||
|
||||
## 📝 Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
# Use default URL from config (localhost:3983 or live)
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 1 --workers 1 --headless
|
||||
```
|
||||
|
||||
### Custom URL Usage
|
||||
|
||||
```bash
|
||||
# Use custom local URL
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 1 --workers 1 --headless \
|
||||
--url http://localhost:3983
|
||||
|
||||
# Use custom port
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 1 --workers 1 --headless \
|
||||
--url http://localhost:5000
|
||||
|
||||
# Use live/staging URL
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 1 --workers 1 --headless \
|
||||
--url https://cognitiveprism.tech4bizsolutions.com
|
||||
|
||||
# Use any custom URL
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 100 --workers 30 --headless \
|
||||
--url https://staging.example.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 How It Works
|
||||
|
||||
1. **URL Override**: When `--url` is provided, it overrides `BASE_URL` in `config.config`
|
||||
2. **Derived URLs**: Automatically updates:
|
||||
- `LOGIN_URL`: `{url}/`
|
||||
- `DASHBOARD_URL`: `{url}/student/dashboard`
|
||||
- `ASSESSMENTS_URL`: `{url}/assessments`
|
||||
- `PROFILE_EDITOR_URL`: `{url}/student/profile-builder`
|
||||
3. **Page Objects**: All page objects use the updated URLs when instantiated
|
||||
|
||||
---
|
||||
|
||||
## 📋 Examples
|
||||
|
||||
### Example 1: Local Development
|
||||
```bash
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students.csv \
|
||||
--start 0 --end 10 \
|
||||
--workers 5 \
|
||||
--headless \
|
||||
--url http://localhost:3983
|
||||
```
|
||||
|
||||
### Example 2: Staging Environment
|
||||
```bash
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students.csv \
|
||||
--start 0 --end 100 \
|
||||
--workers 30 \
|
||||
--headless \
|
||||
--url https://staging.cognitiveprism.com
|
||||
```
|
||||
|
||||
### Example 3: Production (with visible browsers for debugging)
|
||||
```bash
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students.csv \
|
||||
--start 0 --end 1 \
|
||||
--workers 1 \
|
||||
--visible \
|
||||
--url https://cognitiveprism.tech4bizsolutions.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ URL Format
|
||||
|
||||
- **With protocol**: `http://localhost:3983` or `https://example.com`
|
||||
- **Trailing slash**: Automatically removed (both `http://localhost:3983/` and `http://localhost:3983` work)
|
||||
- **Port**: Can specify any port (e.g., `http://localhost:5000`)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Verification
|
||||
|
||||
When you run the script, it will print:
|
||||
- `🌐 Using custom URL: {your_url}` if `--url` is provided
|
||||
- `🌐 Using default URL: {default_url}` if `--url` is not provided
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notes
|
||||
|
||||
- The URL override happens **before** page objects are instantiated
|
||||
- All page objects will use the custom URL automatically
|
||||
- No need to modify config files or environment variables
|
||||
- Works with all existing functionality (login, password reset, profile, assessments, etc.)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Reference
|
||||
|
||||
```bash
|
||||
# Full command with all options
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv <csv_file> \
|
||||
--start <start_index> \
|
||||
--end <end_index> \
|
||||
--workers <num_workers> \
|
||||
--headless \
|
||||
--url <custom_url> \
|
||||
--metrics-interval <interval>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ Ready to Use
|
||||
|
||||
189
tests/load_tests/MACHINE_SPEED_OPTIMIZATION.md
Normal file
189
tests/load_tests/MACHINE_SPEED_OPTIMIZATION.md
Normal file
@ -0,0 +1,189 @@
|
||||
# Machine-Speed Optimization - World Class Automation
|
||||
|
||||
## 🚀 Objective
|
||||
|
||||
Transform the automation from **human-like behavior** to **machine-speed execution** while maintaining 100% reliability.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Optimizations Applied
|
||||
|
||||
### 1. **Removed Human-Like Delays** (Major Impact)
|
||||
- **Removed**: `RandomizedWait.wait_for_question_answer()` - was adding 2-6 seconds
|
||||
- **Replaced**: Minimal 0.1s wait for click to register
|
||||
- **Savings**: ~2-6 seconds per question
|
||||
|
||||
### 2. **Smart Page Load Check** (Major Impact)
|
||||
- **Optimized**: `wait_for_page_load()` now checks if page is already loaded
|
||||
- **Returns immediately** if `document.readyState == "complete"`
|
||||
- **Reduced timeout**: 15s → 3s (with early return)
|
||||
- **Savings**: ~10-12 seconds per question (when page already loaded)
|
||||
|
||||
### 3. **Minimal Loading Indicator Wait** (Medium Impact)
|
||||
- **Reduced**: `wait_for_loading_to_disappear()` timeout: 2s → 0.5s
|
||||
- **Reason**: Loading indicators disappear instantly or don't exist
|
||||
- **Savings**: ~1.5 seconds per question
|
||||
|
||||
### 4. **Fast Question Type Detection** (Medium Impact)
|
||||
- **Reduced**: All question detection timeouts: 2-3s → 0.5s
|
||||
- **Optimized**: Smart wait returns immediately if element already visible
|
||||
- **Savings**: ~1-2 seconds per question
|
||||
|
||||
### 5. **Reduced Element Wait Timeouts** (Small Impact)
|
||||
- **Reduced**: All `WebDriverWait` timeouts: 10s → 2s
|
||||
- **Reason**: Elements should be ready quickly after page load
|
||||
- **Savings**: ~0.5-1 second per question (when elements are ready)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Performance Comparison
|
||||
|
||||
### Before Optimization:
|
||||
- **Per Question**: ~25 seconds (observed)
|
||||
- **100 Questions**: ~42 minutes (observed)
|
||||
- **Wait Strategy**: Human-like, realistic delays
|
||||
|
||||
### After Machine-Speed Optimization:
|
||||
- **Per Question**: ~3-8 seconds (estimated)
|
||||
- **100 Questions**: ~5-13 minutes (estimated)
|
||||
- **Wait Strategy**: Machine-speed, minimal delays
|
||||
- **Improvement**: **70-80% faster** (30+ minutes saved!)
|
||||
|
||||
### Breakdown (Machine-Speed):
|
||||
1. Get question type: 0.1-0.5s (was 0.5-3s)
|
||||
2. Answer question: 0.5-2s (was 2-6s)
|
||||
3. Click registration: 0.1s (was 2-6s)
|
||||
4. Click Next + page load: 0.5-2s (was 15-30s)
|
||||
5. **Total**: ~1.2-4.5s per question
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Technical Changes
|
||||
|
||||
### Files Modified:
|
||||
|
||||
1. **`tests/load_tests/test_generic_load_assessments.py`**
|
||||
- Removed `RandomizedWait.wait_for_question_answer()`
|
||||
- Added minimal 0.1s wait for click registration
|
||||
|
||||
2. **`utils/wait_helpers.py`**
|
||||
- `wait_for_page_load()`: Smart check, returns immediately if ready
|
||||
- `wait_for_loading_to_disappear()`: Reduced timeout 2s → 0.5s
|
||||
|
||||
3. **`utils/question_answer_helper.py`**
|
||||
- All `_element_exists()` timeouts: 2-3s → 0.5s
|
||||
- All `WebDriverWait` timeouts: 10s → 2s
|
||||
- Smart wait for question container (0.5s instead of hardcoded sleep)
|
||||
|
||||
4. **`pages/domain_assessment_page.py`**
|
||||
- Optimized `click_next()` with smart waits
|
||||
|
||||
5. **`pages/base_page.py`**
|
||||
- Optimized `wait_for_page_load()` with smart waits
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Key Optimizations
|
||||
|
||||
### 1. **Early Return Pattern**
|
||||
```python
|
||||
# Before: Always waits full timeout
|
||||
WebDriverWait(driver, 15).until(condition)
|
||||
|
||||
# After: Returns immediately if ready
|
||||
if condition_met():
|
||||
return
|
||||
WebDriverWait(driver, 3).until(condition)
|
||||
```
|
||||
|
||||
### 2. **Minimal Timeouts**
|
||||
- Question detection: 0.5s (was 2-3s)
|
||||
- Element waits: 2s (was 10s)
|
||||
- Loading indicator: 0.5s (was 2s)
|
||||
- Page load: 3s with early return (was 15s)
|
||||
|
||||
### 3. **Removed Human-Like Delays**
|
||||
- No "thinking time" after answering
|
||||
- No "reading time" for options
|
||||
- No "navigation delay" after clicking
|
||||
- Minimal wait only for click registration (0.1s)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Expected Results
|
||||
|
||||
### Single Student (100 Questions):
|
||||
- **Before**: ~42 minutes
|
||||
- **After**: ~5-13 minutes
|
||||
- **Improvement**: **70-80% faster**
|
||||
|
||||
### Load Test (100 Students):
|
||||
- **Before**: ~42 minutes per student (sequential)
|
||||
- **After**: ~5-13 minutes per student (sequential)
|
||||
- **With 30 workers**: ~20-40 minutes total (was 2+ hours)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Safety Considerations
|
||||
|
||||
1. **Explicit Waits Preserved**: Still using explicit waits for reliability
|
||||
2. **Smart Waits**: Return immediately when ready, don't wait unnecessarily
|
||||
3. **Minimum Timeouts**: Reduced but not eliminated (still safe)
|
||||
4. **No Logic Changes**: Only wait-time optimizations, no functional changes
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Recommendations
|
||||
|
||||
### Phase 1: Single Student Test
|
||||
```bash
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 1 --workers 1 --headless
|
||||
```
|
||||
|
||||
**Expected**: Should complete in ~5-13 minutes (was 42 minutes)
|
||||
|
||||
### Phase 2: Small Batch Test
|
||||
```bash
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 10 --workers 5 --headless
|
||||
```
|
||||
|
||||
**Expected**: Should complete in ~10-20 minutes (was 42 minutes per student)
|
||||
|
||||
### Phase 3: Full Load Test
|
||||
```bash
|
||||
./scripts/PC1_100_students.sh
|
||||
```
|
||||
|
||||
**Expected**: Should complete in ~20-40 minutes (was 2+ hours)
|
||||
|
||||
---
|
||||
|
||||
## 📈 Success Metrics
|
||||
|
||||
- **Target**: <8 seconds per question (average)
|
||||
- **Target**: <15 minutes for 100 questions
|
||||
- **Target**: 0% increase in failure rate
|
||||
- **Target**: Maintain 100% reliability
|
||||
- **Target**: Machine-speed execution (no human-like delays)
|
||||
|
||||
---
|
||||
|
||||
## 💡 Philosophy
|
||||
|
||||
**Before**: "Simulate human behavior with realistic delays"
|
||||
**After**: "Machine-speed execution with minimal necessary waits"
|
||||
|
||||
The automation now:
|
||||
- ✅ Returns immediately when conditions are met
|
||||
- ✅ Uses minimal timeouts (not excessive)
|
||||
- ✅ Removes all "thinking time" delays
|
||||
- ✅ Optimizes for speed while maintaining reliability
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ Ready for Testing - Machine-Speed Optimized
|
||||
|
||||
131
tests/load_tests/OPTIMIZATION_SUMMARY.md
Normal file
131
tests/load_tests/OPTIMIZATION_SUMMARY.md
Normal file
@ -0,0 +1,131 @@
|
||||
# Performance Optimization Summary
|
||||
|
||||
## ✅ Optimizations Applied
|
||||
|
||||
### 1. **Removed Redundant Waits** (Major Impact)
|
||||
- **Removed**: `RandomizedWait.wait_for_navigation('next')` after all `click_next()` calls
|
||||
- **Reason**: `click_next()` already waits for page load internally
|
||||
- **Savings**: ~1-3 seconds per question
|
||||
- **Locations**: 4 places in `test_generic_load_assessments.py`
|
||||
|
||||
### 2. **Removed Unnecessary Start Wait** (Medium Impact)
|
||||
- **Removed**: `RandomizedWait.wait_for_page_load('navigation')` at start of question loop
|
||||
- **Reason**: Page is already loaded from previous Next click
|
||||
- **Savings**: ~1-3 seconds per question
|
||||
- **Location**: Start of question loop in `test_generic_load_assessments.py`
|
||||
|
||||
### 3. **Optimized Loading Indicator Wait** (Major Impact)
|
||||
- **Changed**: `wait_for_loading_to_disappear()` timeout from 15s to 2s
|
||||
- **Reason**: Loading indicators disappear quickly (1-2s), and if they don't exist, we shouldn't wait
|
||||
- **Savings**: ~10-13 seconds per question (when loading doesn't exist)
|
||||
- **Location**: `utils/wait_helpers.py`
|
||||
|
||||
### 4. **Replaced Hardcoded Sleep** (Small Impact)
|
||||
- **Changed**: `time.sleep(0.5)` → Smart wait for question element visibility
|
||||
- **Reason**: Waits only if element not ready, returns immediately if ready
|
||||
- **Savings**: ~0.3-0.5 seconds per question
|
||||
- **Location**: `utils/question_answer_helper.py`
|
||||
|
||||
---
|
||||
|
||||
## 📊 Expected Performance Improvement
|
||||
|
||||
### Before Optimization:
|
||||
- **Per Question**: ~25 seconds (observed)
|
||||
- **100 Questions**: ~42 minutes (observed)
|
||||
|
||||
### After Optimization:
|
||||
- **Per Question**: ~10-15 seconds (estimated)
|
||||
- **100 Questions**: ~17-25 minutes (estimated)
|
||||
- **Improvement**: **~40-60% faster**
|
||||
|
||||
### Breakdown (Optimized):
|
||||
1. Get question type: 0.1-0.5s (was 0.5s)
|
||||
2. Answer question: 2-6s (unchanged)
|
||||
3. After answer wait: 2-6s (unchanged)
|
||||
4. Click Next + page load: 1-3s (was 15-30s)
|
||||
5. **Total**: ~5-15s per question
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Recommendations
|
||||
|
||||
### Phase 1: Single Student Test
|
||||
```bash
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 1 --workers 1 --headless
|
||||
```
|
||||
|
||||
**Expected**: Should complete in ~10-15 minutes (was 50+ minutes)
|
||||
|
||||
### Phase 2: Small Batch Test
|
||||
```bash
|
||||
python3 tests/load_tests/test_generic_load_assessments.py \
|
||||
--csv students_with_passwords_2025-12-15T10-49-08_01.csv \
|
||||
--start 0 --end 10 --workers 5 --headless
|
||||
```
|
||||
|
||||
**Expected**: Should complete in ~15-20 minutes (was 50+ minutes per student)
|
||||
|
||||
### Phase 3: Full Load Test
|
||||
```bash
|
||||
./scripts/PC1_100_students.sh
|
||||
```
|
||||
|
||||
**Expected**: Should complete in ~20-30 minutes (was 50+ minutes per student)
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Safety Notes
|
||||
|
||||
1. **No Functional Changes**: All optimizations are wait-time reductions, no logic changes
|
||||
2. **Explicit Waits Preserved**: Still using explicit waits for reliability
|
||||
3. **Smart Waits**: Replaced fixed sleeps with smart waits that return immediately when ready
|
||||
4. **Backward Compatible**: All changes are safe and won't break existing flows
|
||||
|
||||
---
|
||||
|
||||
## 🔍 What to Monitor
|
||||
|
||||
1. **Failure Rate**: Should remain 0% (same as before)
|
||||
2. **Question Detection**: Should still detect all questions correctly
|
||||
3. **Navigation**: Should still navigate between questions smoothly
|
||||
4. **Answer Submission**: Should still submit answers correctly
|
||||
|
||||
---
|
||||
|
||||
## 📝 Files Modified
|
||||
|
||||
1. `tests/load_tests/test_generic_load_assessments.py`
|
||||
- Removed 4 redundant `RandomizedWait.wait_for_navigation()` calls
|
||||
- Removed 1 redundant `RandomizedWait.wait_for_page_load()` call
|
||||
|
||||
2. `utils/wait_helpers.py`
|
||||
- Optimized `wait_for_loading_to_disappear()` timeout from 15s to 2s
|
||||
|
||||
3. `utils/question_answer_helper.py`
|
||||
- Replaced `time.sleep(0.5)` with smart wait for question element
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
1. ✅ Run single student test to verify no breakage
|
||||
2. ✅ Monitor performance improvement
|
||||
3. ✅ If successful, proceed with full load test
|
||||
4. ✅ Document actual performance gains
|
||||
|
||||
---
|
||||
|
||||
## 💡 Additional Optimization Opportunities (Future)
|
||||
|
||||
1. **Parallel Question Detection**: Detect question type while waiting for answer
|
||||
2. **Batch Answer Submission**: Submit multiple answers at once (if backend supports)
|
||||
3. **Connection Pooling**: Reuse connections for faster API calls
|
||||
4. **Smart Retry Logic**: Retry only on actual failures, not timeouts
|
||||
|
||||
---
|
||||
|
||||
**Status**: ✅ Ready for Testing
|
||||
|
||||
133
tests/load_tests/PERFORMANCE_OPTIMIZATION_ANALYSIS.md
Normal file
133
tests/load_tests/PERFORMANCE_OPTIMIZATION_ANALYSIS.md
Normal file
@ -0,0 +1,133 @@
|
||||
# Performance Optimization Analysis - Question Timing
|
||||
|
||||
## 🔍 Current Problem
|
||||
|
||||
**Observed**: ~25 seconds per question (50+ minutes for 100 questions)
|
||||
|
||||
**Expected**: ~4-8 seconds per question (7-13 minutes for 100 questions)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Current Wait Chain Per Question
|
||||
|
||||
### Breakdown of Current Waits:
|
||||
|
||||
1. **Start of loop**: `RandomizedWait.wait_for_page_load('navigation')` → **1-3s**
|
||||
2. **Get question type**: `time.sleep(0.5)` → **0.5s** (hardcoded!)
|
||||
3. **Answer question**: Depends on type → **2-6s** (multiple choice)
|
||||
4. **After answer**: `RandomizedWait.wait_for_question_answer()` → **2-6s**
|
||||
5. **Click Next**: `click_next()` which calls:
|
||||
- `wait_for_page_load()` → **Up to 15s** (waits for document.readyState)
|
||||
- `wait_for_loading_to_disappear()` → **Up to 15s** (waits for loading indicator)
|
||||
6. **After Next**: `RandomizedWait.wait_for_navigation('next')` → **1-3s** (REDUNDANT!)
|
||||
|
||||
### Total Per Question:
|
||||
- **Minimum**: 1 + 0.5 + 2 + 2 + 0 + 0 + 1 = **6.5s**
|
||||
- **Maximum**: 3 + 0.5 + 6 + 6 + 15 + 15 + 3 = **48.5s**
|
||||
- **Average**: ~2 + 0.5 + 4 + 4 + 5 + 5 + 2 = **22.5s** ✅ **Matches your observation!**
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Issues Identified
|
||||
|
||||
### 1. **Redundant Waits** (Major Issue)
|
||||
- `click_next()` already waits for page load
|
||||
- Then we wait again with `RandomizedWait.wait_for_navigation()`
|
||||
- **Waste**: 1-3 seconds per question
|
||||
|
||||
### 2. **Hardcoded Sleep** (Minor Issue)
|
||||
- `get_question_type()` has `time.sleep(0.5)`
|
||||
- Should use smart wait instead
|
||||
- **Waste**: 0.5 seconds per question
|
||||
|
||||
### 3. **Excessive Explicit Waits** (Major Issue)
|
||||
- `wait_for_loading_to_disappear()` waits up to 15 seconds
|
||||
- Loading indicators usually disappear in 1-2 seconds
|
||||
- **Waste**: 10-13 seconds per question (if loading doesn't exist)
|
||||
|
||||
### 4. **Double Page Load Check** (Minor Issue)
|
||||
- `wait_for_page_load()` checks document.readyState
|
||||
- `wait_for_loading_to_disappear()` checks loading indicator
|
||||
- Both might be redundant
|
||||
- **Waste**: 5-10 seconds per question
|
||||
|
||||
### 5. **Unnecessary Start Wait** (Minor Issue)
|
||||
- `RandomizedWait.wait_for_page_load('navigation')` at start of loop
|
||||
- Page is already loaded from previous Next click
|
||||
- **Waste**: 1-3 seconds per question
|
||||
|
||||
---
|
||||
|
||||
## ✅ Optimization Strategy
|
||||
|
||||
### Phase 1: Remove Redundant Waits (Quick Win)
|
||||
1. Remove `RandomizedWait.wait_for_navigation('next')` after `click_next()`
|
||||
2. Remove `RandomizedWait.wait_for_page_load('navigation')` at start of loop
|
||||
3. **Savings**: ~2-6 seconds per question
|
||||
|
||||
### Phase 2: Optimize Explicit Waits (Medium Win)
|
||||
1. Reduce `wait_for_loading_to_disappear()` timeout to 2-3 seconds
|
||||
2. Make it non-blocking (don't fail if loading doesn't exist)
|
||||
3. **Savings**: ~10-13 seconds per question (if loading doesn't exist)
|
||||
|
||||
### Phase 3: Replace Hardcoded Sleeps (Small Win)
|
||||
1. Replace `time.sleep(0.5)` in `get_question_type()` with smart wait
|
||||
2. Wait for question element to be visible instead
|
||||
3. **Savings**: ~0.3-0.5 seconds per question
|
||||
|
||||
### Phase 4: Smart Wait Strategy (Advanced)
|
||||
1. Use explicit waits that return immediately when condition is met
|
||||
2. Don't wait full timeout if element is ready
|
||||
3. **Savings**: Variable, but significant
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Expected Results After Optimization
|
||||
|
||||
### Optimized Wait Chain:
|
||||
|
||||
1. **Get question type**: Smart wait → **0.1-0.5s** (was 0.5s)
|
||||
2. **Answer question**: Depends on type → **2-6s** (unchanged)
|
||||
3. **After answer**: `RandomizedWait.wait_for_question_answer()` → **2-6s** (unchanged)
|
||||
4. **Click Next**: `click_next()` with optimized waits → **1-3s** (was 15-30s)
|
||||
5. **No redundant wait** → **0s** (was 1-3s)
|
||||
|
||||
### Total Per Question (Optimized):
|
||||
- **Minimum**: 0.1 + 2 + 2 + 1 = **5.1s**
|
||||
- **Maximum**: 0.5 + 6 + 6 + 3 = **15.5s**
|
||||
- **Average**: ~0.3 + 4 + 4 + 2 = **10.3s**
|
||||
|
||||
### For 100 Questions:
|
||||
- **Current**: ~25s × 100 = **~42 minutes**
|
||||
- **Optimized**: ~10s × 100 = **~17 minutes**
|
||||
- **Improvement**: **~60% faster** (25 minutes saved!)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Implementation Plan
|
||||
|
||||
1. ✅ Remove redundant `RandomizedWait.wait_for_navigation()` calls
|
||||
2. ✅ Remove redundant `RandomizedWait.wait_for_page_load()` at start
|
||||
3. ✅ Optimize `wait_for_loading_to_disappear()` timeout (2-3s instead of 15s)
|
||||
4. ✅ Replace hardcoded `time.sleep(0.5)` with smart wait
|
||||
5. ✅ Test with 1 student to verify no breakage
|
||||
6. ✅ Test with 10 students to verify performance improvement
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Safety Considerations
|
||||
|
||||
- **Don't remove explicit waits entirely** - they ensure elements are ready
|
||||
- **Keep minimum wait times** - prevents race conditions
|
||||
- **Test thoroughly** - ensure no flakiness introduced
|
||||
- **Monitor for failures** - if optimization causes issues, revert
|
||||
|
||||
---
|
||||
|
||||
## 📈 Success Metrics
|
||||
|
||||
- **Target**: <15 seconds per question (average)
|
||||
- **Target**: <20 minutes for 100 questions
|
||||
- **Target**: 0% increase in failure rate
|
||||
- **Target**: Maintain 100% reliability
|
||||
|
||||
131
tests/load_tests/QUESTION_TIMING_ANALYSIS.md
Normal file
131
tests/load_tests/QUESTION_TIMING_ANALYSIS.md
Normal file
@ -0,0 +1,131 @@
|
||||
# Question Timing Analysis
|
||||
|
||||
## ⏱️ Current Per-Question Timing (Approximate)
|
||||
|
||||
Based on `RandomizedWait` wait ranges, here's how long each question type takes:
|
||||
|
||||
### Question Answer Times
|
||||
|
||||
| Question Type | Min Time | Max Time | Average | Notes |
|
||||
|--------------|----------|----------|---------|-------|
|
||||
| **Rating Scale** | 1s | 4s | ~2.5s | Quick selection (1-5 stars) |
|
||||
| **Multiple Choice** | 2s | 6s | ~4s | Reading options (A, B, C, D, E) |
|
||||
| **True/False** | 1s | 3s | ~2s | Binary choice (True/False) |
|
||||
| **Open Ended** | 5s | 15s | ~10s | Typing text response |
|
||||
| **Matrix** | 3s | 8s | ~5.5s | Multiple cell selections |
|
||||
|
||||
### Navigation Times
|
||||
|
||||
| Action | Min Time | Max Time | Average |
|
||||
|--------|----------|----------|---------|
|
||||
| **Click Next** | 1s | 3s | ~2s |
|
||||
| **Page Load** | 1s | 3s | ~2s |
|
||||
|
||||
### Total Time Per Question (Approximate)
|
||||
|
||||
**Formula**: Answer Time + Navigation Time
|
||||
|
||||
| Question Type | Min Total | Max Total | Average Total |
|
||||
|--------------|-----------|-----------|---------------|
|
||||
| Rating Scale | 2s | 7s | ~4.5s |
|
||||
| Multiple Choice | 3s | 9s | ~6s |
|
||||
| True/False | 2s | 6s | ~4s |
|
||||
| Open Ended | 6s | 18s | ~12s |
|
||||
| Matrix | 4s | 11s | ~7.5s |
|
||||
|
||||
### Example: 108 Questions (Emotional Intelligence)
|
||||
|
||||
If all questions are **Multiple Choice** (most common):
|
||||
- **Average**: 108 questions × 6s = **~10.8 minutes**
|
||||
- **Min**: 108 questions × 3s = **~5.4 minutes**
|
||||
- **Max**: 108 questions × 9s = **~16.2 minutes**
|
||||
|
||||
If mixed question types:
|
||||
- **Average**: ~8-12 minutes (depending on mix)
|
||||
- **Min**: ~5-7 minutes
|
||||
- **Max**: ~15-20 minutes
|
||||
|
||||
---
|
||||
|
||||
## 📊 What We Currently Track
|
||||
|
||||
### In Load Test Results
|
||||
|
||||
✅ **Tracked:**
|
||||
- Total duration per student (entire flow)
|
||||
- Total questions answered
|
||||
- Average duration across students
|
||||
- Success/failure rate
|
||||
|
||||
❌ **NOT Tracked:**
|
||||
- Time per individual question
|
||||
- Time breakdown by question type
|
||||
- Question-level performance metrics
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Adding Per-Question Timing (Optional)
|
||||
|
||||
If you want to track per-question timing, I can add:
|
||||
|
||||
1. **Question-level timing** in load test results
|
||||
2. **Breakdown by question type** (avg time per type)
|
||||
3. **Detailed metrics** in JSON report
|
||||
|
||||
**Would you like me to add this?**
|
||||
|
||||
---
|
||||
|
||||
## 💡 Current Behavior
|
||||
|
||||
### How Questions Are Answered
|
||||
|
||||
```python
|
||||
# For each question:
|
||||
1. Detect question (0.5-1s)
|
||||
2. Answer question (1-15s depending on type)
|
||||
3. Wait for answer confirmation (0.5-1s)
|
||||
4. Click Next (1-3s)
|
||||
5. Wait for next question to load (1-3s)
|
||||
|
||||
Total: ~4-20s per question (depending on type)
|
||||
```
|
||||
|
||||
### Realistic Timing
|
||||
|
||||
The automation uses **randomized waits** to simulate human behavior:
|
||||
- Not too fast (doesn't look like a bot)
|
||||
- Not too slow (efficient testing)
|
||||
- Varies per question type (realistic)
|
||||
|
||||
---
|
||||
|
||||
## 📈 Backend Perspective
|
||||
|
||||
The **backend** tracks time per question when answers are submitted:
|
||||
- Frontend sends `timeSpent` with each answer
|
||||
- Backend stores it in the database
|
||||
- Available in backend analytics
|
||||
|
||||
**But our automation doesn't currently track this** - we just use realistic wait times.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Summary
|
||||
|
||||
**Current State:**
|
||||
- ✅ We know approximate times per question type
|
||||
- ✅ We track total duration per student
|
||||
- ❌ We don't track individual question times
|
||||
|
||||
**Approximate Times:**
|
||||
- **Fast questions** (True/False, Rating): ~2-4s each
|
||||
- **Medium questions** (Multiple Choice, Matrix): ~4-8s each
|
||||
- **Slow questions** (Open Ended): ~6-18s each
|
||||
|
||||
**For 108 questions:**
|
||||
- **Average**: ~8-12 minutes
|
||||
- **Range**: ~5-20 minutes (depending on question types)
|
||||
|
||||
Would you like me to add detailed per-question timing tracking to the load test?
|
||||
|
||||
@ -404,7 +404,7 @@ def complete_assessment_flow_for_student(
|
||||
max_consecutive_failures = 3
|
||||
|
||||
while questions_answered < max_questions:
|
||||
RandomizedWait.wait_for_page_load('navigation')
|
||||
# Removed redundant wait_for_page_load - page is already loaded from previous Next click
|
||||
|
||||
# Get current question ID
|
||||
question_id = question_helper.get_question_id()
|
||||
@ -418,7 +418,7 @@ def complete_assessment_flow_for_student(
|
||||
if domain_assessment_page.is_next_button_visible():
|
||||
try:
|
||||
domain_assessment_page.click_next()
|
||||
RandomizedWait.wait_for_navigation('next')
|
||||
# Removed redundant wait_for_navigation - click_next() already waits
|
||||
except:
|
||||
pass
|
||||
continue
|
||||
@ -433,7 +433,8 @@ def complete_assessment_flow_for_student(
|
||||
f"[data-testid='domain_question__{question_id}']"
|
||||
)
|
||||
driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", question_elem)
|
||||
RandomizedWait.wait_for_page_load('navigation')
|
||||
# Small wait for scroll animation, but not full page load
|
||||
RandomizedWait.wait_for_page_load('modal') # Use shorter modal wait instead
|
||||
question_type = question_helper.get_question_type(question_id)
|
||||
except:
|
||||
pass
|
||||
@ -441,7 +442,7 @@ def complete_assessment_flow_for_student(
|
||||
if question_type == "unknown":
|
||||
if domain_assessment_page.is_next_button_visible():
|
||||
domain_assessment_page.click_next()
|
||||
RandomizedWait.wait_for_navigation('next')
|
||||
# Removed redundant wait_for_navigation - click_next() already waits
|
||||
continue
|
||||
|
||||
# Answer the question
|
||||
@ -449,7 +450,8 @@ def complete_assessment_flow_for_student(
|
||||
question_helper.answer_question(question_id, question_type)
|
||||
questions_answered += 1
|
||||
consecutive_failures = 0
|
||||
RandomizedWait.wait_for_question_answer(question_type)
|
||||
# Machine-speed: Minimal wait for click to register (0.1s instead of 2-6s)
|
||||
time.sleep(0.1)
|
||||
except Exception as e:
|
||||
consecutive_failures += 1
|
||||
if consecutive_failures >= max_consecutive_failures:
|
||||
@ -457,7 +459,7 @@ def complete_assessment_flow_for_student(
|
||||
if domain_assessment_page.is_next_button_visible():
|
||||
try:
|
||||
domain_assessment_page.click_next()
|
||||
RandomizedWait.wait_for_navigation('next')
|
||||
# Removed redundant wait_for_navigation - click_next() already waits
|
||||
except:
|
||||
pass
|
||||
continue
|
||||
@ -481,7 +483,7 @@ def complete_assessment_flow_for_student(
|
||||
if domain_assessment_page.is_next_button_visible():
|
||||
try:
|
||||
domain_assessment_page.click_next()
|
||||
RandomizedWait.wait_for_navigation('next')
|
||||
# Removed redundant wait_for_navigation - click_next() already waits
|
||||
except Exception as e:
|
||||
print(f"⚠️ Error clicking Next after question {question_id}: {e}")
|
||||
# Try to continue anyway
|
||||
@ -761,9 +763,28 @@ if __name__ == "__main__":
|
||||
parser.add_argument('--headless', action='store_true', default=True, help='Run in headless mode')
|
||||
parser.add_argument('--visible', action='store_true', help='Run in visible mode (overrides headless)')
|
||||
parser.add_argument('--metrics-interval', type=int, default=10, help='Print metrics every N students')
|
||||
parser.add_argument('--url', type=str, default=None, help='Frontend URL to use (e.g., http://localhost:3983 or https://cognitiveprism.tech4bizsolutions.com). If not provided, uses default from config.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Override BASE_URL if --url is provided
|
||||
if args.url:
|
||||
# Remove trailing slash if present
|
||||
custom_url = args.url.rstrip('/')
|
||||
# Override BASE_URL in config before importing pages
|
||||
import config.config as config_module
|
||||
config_module.BASE_URL = custom_url
|
||||
# Update all derived URLs
|
||||
config_module.LOGIN_URL = f"{custom_url}/"
|
||||
config_module.DASHBOARD_URL = f"{custom_url}/student/dashboard"
|
||||
config_module.ASSESSMENTS_URL = f"{custom_url}/assessments"
|
||||
config_module.PROFILE_EDITOR_URL = f"{custom_url}/student/profile-builder"
|
||||
print(f"🌐 Using custom URL: {custom_url}")
|
||||
else:
|
||||
# Import to show default URL
|
||||
from config.config import BASE_URL
|
||||
print(f"🌐 Using default URL: {BASE_URL}")
|
||||
|
||||
run_assessment_load_test(
|
||||
csv_path=args.csv,
|
||||
start_index=args.start,
|
||||
|
||||
@ -84,54 +84,64 @@ class QuestionAnswerHelper:
|
||||
str: Question type (multiple_choice, true_false, rating_scale, open_ended, matrix)
|
||||
"""
|
||||
try:
|
||||
# Wait a moment for question to fully render
|
||||
import time
|
||||
time.sleep(0.5)
|
||||
# Machine-speed: Quick check if question is already visible (returns immediately if ready)
|
||||
try:
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
WebDriverWait(self.driver, 0.5).until(
|
||||
EC.presence_of_element_located(
|
||||
(By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}']")
|
||||
)
|
||||
)
|
||||
except:
|
||||
# Question might already be visible, continue
|
||||
pass
|
||||
|
||||
# First, check for container elements (more reliable)
|
||||
# Check for multiple choice container
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__multiple_choice']", timeout=3):
|
||||
# Machine-speed: Reduced timeout from 3s to 0.5s
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__multiple_choice']", timeout=0.5):
|
||||
return "multiple_choice"
|
||||
|
||||
# Check for true/false container
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__true_false']", timeout=3):
|
||||
# Check for true/false container - machine-speed: 0.5s timeout
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__true_false']", timeout=0.5):
|
||||
return "true_false"
|
||||
|
||||
# Check for rating scale container
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__rating_scale']", timeout=3):
|
||||
# Check for rating scale container - machine-speed: 0.5s timeout
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__rating_scale']", timeout=0.5):
|
||||
return "rating_scale"
|
||||
|
||||
# Check for open ended container
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__open_ended']", timeout=3):
|
||||
# Check for open ended container - machine-speed: 0.5s timeout
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__open_ended']", timeout=0.5):
|
||||
return "open_ended"
|
||||
|
||||
# Check for matrix container
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__matrix']", timeout=3):
|
||||
# Check for matrix container - machine-speed: 0.5s timeout
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__matrix']", timeout=0.5):
|
||||
return "matrix"
|
||||
|
||||
# Fallback: Check for individual answer elements (if containers not found)
|
||||
# Check for multiple choice options (A, B, C, D, E)
|
||||
# Check for multiple choice options (A, B, C, D, E) - machine-speed: 0.5s timeout
|
||||
for label in ['A', 'B', 'C', 'D', 'E']:
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__option_{label}']", timeout=2):
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__option_{label}']", timeout=0.5):
|
||||
return "multiple_choice"
|
||||
|
||||
# Check for true/false buttons
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__truefalse_True']", timeout=2):
|
||||
# Check for true/false buttons - machine-speed: 0.5s timeout
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__truefalse_True']", timeout=0.5):
|
||||
return "true_false"
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__truefalse_False']", timeout=2):
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__truefalse_False']", timeout=0.5):
|
||||
return "true_false"
|
||||
|
||||
# Check for rating scale buttons
|
||||
# Check for rating scale buttons - machine-speed: 0.5s timeout
|
||||
for rating in ['1', '2', '3', '4', '5']:
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__rating_{rating}']", timeout=2):
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__rating_{rating}']", timeout=0.5):
|
||||
return "rating_scale"
|
||||
|
||||
# Check for open ended textarea
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__textarea']", timeout=2):
|
||||
# Check for open ended textarea - machine-speed: 0.5s timeout
|
||||
if self._element_exists(f"[data-testid='domain_question__{question_id}__textarea']", timeout=0.5):
|
||||
return "open_ended"
|
||||
|
||||
# Check for matrix cells
|
||||
if self._element_exists(f"[data-testid^='domain_question__{question_id}__matrix_']", timeout=2):
|
||||
# Check for matrix cells - machine-speed: 0.5s timeout
|
||||
if self._element_exists(f"[data-testid^='domain_question__{question_id}__matrix_']", timeout=0.5):
|
||||
return "matrix"
|
||||
|
||||
return "unknown"
|
||||
@ -139,8 +149,8 @@ class QuestionAnswerHelper:
|
||||
print(f"⚠️ Error detecting question type for {question_id}: {e}")
|
||||
return "unknown"
|
||||
|
||||
def _element_exists(self, css_selector, timeout=2):
|
||||
"""Check if element exists quickly"""
|
||||
def _element_exists(self, css_selector, timeout=0.5):
|
||||
"""Check if element exists quickly (machine-speed optimized)"""
|
||||
try:
|
||||
WebDriverWait(self.driver, timeout).until(
|
||||
EC.presence_of_element_located((By.CSS_SELECTOR, css_selector))
|
||||
@ -160,12 +170,12 @@ class QuestionAnswerHelper:
|
||||
Returns:
|
||||
str: Selected option label
|
||||
"""
|
||||
# Get available options
|
||||
# Get available options (machine-speed: reduced timeout from 2s to 0.5s)
|
||||
options = []
|
||||
for label in ['A', 'B', 'C', 'D', 'E']:
|
||||
locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__option_{label}']")
|
||||
try:
|
||||
element = WebDriverWait(self.driver, 2).until(
|
||||
element = WebDriverWait(self.driver, 0.5).until(
|
||||
EC.presence_of_element_located(locator)
|
||||
)
|
||||
if element.is_displayed():
|
||||
@ -183,7 +193,8 @@ class QuestionAnswerHelper:
|
||||
option_label = random.choice(options) # Fallback to random
|
||||
|
||||
locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__option_{option_label}']")
|
||||
element = WebDriverWait(self.driver, self.wait_timeout).until(
|
||||
# Machine-speed: Reduced timeout from 10s to 2s (element should be ready quickly)
|
||||
element = WebDriverWait(self.driver, 2).until(
|
||||
EC.element_to_be_clickable(locator)
|
||||
)
|
||||
element.click()
|
||||
@ -207,7 +218,8 @@ class QuestionAnswerHelper:
|
||||
value_str = "True" if value else "False"
|
||||
locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__truefalse_{value_str}']")
|
||||
|
||||
element = WebDriverWait(self.driver, self.wait_timeout).until(
|
||||
# Machine-speed: Reduced timeout from 10s to 2s
|
||||
element = WebDriverWait(self.driver, 2).until(
|
||||
EC.element_to_be_clickable(locator)
|
||||
)
|
||||
element.click()
|
||||
@ -276,7 +288,8 @@ class QuestionAnswerHelper:
|
||||
|
||||
locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__rating_{selected_value}']")
|
||||
|
||||
element = WebDriverWait(self.driver, self.wait_timeout).until(
|
||||
# Machine-speed: Reduced timeout from 10s to 2s
|
||||
element = WebDriverWait(self.driver, 2).until(
|
||||
EC.element_to_be_clickable(locator)
|
||||
)
|
||||
element.click()
|
||||
@ -299,7 +312,8 @@ class QuestionAnswerHelper:
|
||||
|
||||
locator = (By.CSS_SELECTOR, f"[data-testid='domain_question__{question_id}__textarea']")
|
||||
|
||||
element = WebDriverWait(self.driver, self.wait_timeout).until(
|
||||
# Machine-speed: Reduced timeout from 10s to 2s
|
||||
element = WebDriverWait(self.driver, 2).until(
|
||||
EC.presence_of_element_located(locator)
|
||||
)
|
||||
element.clear()
|
||||
@ -357,7 +371,8 @@ class QuestionAnswerHelper:
|
||||
locator = (By.CSS_SELECTOR,
|
||||
f"[data-testid='domain_question__{question_id}__matrix_{row_index}_{column_index}']")
|
||||
|
||||
element = WebDriverWait(self.driver, self.wait_timeout).until(
|
||||
# Machine-speed: Reduced timeout from 10s to 2s
|
||||
element = WebDriverWait(self.driver, 2).until(
|
||||
EC.element_to_be_clickable(locator)
|
||||
)
|
||||
element.click()
|
||||
|
||||
@ -105,24 +105,35 @@ class WaitHelpers:
|
||||
return self.wait.until(EC.url_contains(url_part))
|
||||
|
||||
def wait_for_page_load(self):
|
||||
"""Wait for page to load completely"""
|
||||
self.wait.until(lambda driver: driver.execute_script("return document.readyState") == "complete")
|
||||
"""Wait for page to load completely (machine-speed optimized)"""
|
||||
# Check if already loaded - return immediately if ready
|
||||
if self.driver.execute_script("return document.readyState") == "complete":
|
||||
return
|
||||
# Otherwise wait, but with shorter timeout for machine-speed
|
||||
try:
|
||||
WebDriverWait(self.driver, 3).until(
|
||||
lambda driver: driver.execute_script("return document.readyState") == "complete"
|
||||
)
|
||||
except TimeoutException:
|
||||
# Page might be interactive even if not "complete" - continue
|
||||
pass
|
||||
|
||||
def wait_for_loading_to_disappear(self, timeout=None):
|
||||
"""
|
||||
Wait for loading indicator to disappear
|
||||
Wait for loading indicator to disappear (machine-speed optimized)
|
||||
|
||||
Args:
|
||||
timeout: Optional timeout override
|
||||
timeout: Optional timeout override (defaults to 0.5s for machine-speed)
|
||||
"""
|
||||
wait_time = timeout or EXPLICIT_WAIT
|
||||
# Machine-speed: Use minimal timeout (0.5s) - loading indicators disappear instantly or don't exist
|
||||
wait_time = timeout or 0.5 # Reduced from 2s to 0.5s for machine-speed
|
||||
wait = WebDriverWait(self.driver, wait_time)
|
||||
try:
|
||||
wait.until(EC.invisibility_of_element_located(
|
||||
(By.XPATH, "//div[contains(., 'Loading')]")
|
||||
))
|
||||
except TimeoutException:
|
||||
# Loading might not be present, which is fine
|
||||
# Loading might not be present, which is fine - don't fail
|
||||
pass
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user