CP_StressTest

This commit is contained in:
Kenil Bhikadiya 2025-12-16 17:43:41 +05:30
parent b44e165212
commit e7b7a7538a
26 changed files with 1517 additions and 50 deletions

View File

@ -9,3 +9,16 @@ python3 tests/load_tests/test_generic_load_assessments.py \
--workers 1 \
--metrics-interval 1 \
--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

View File

@ -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()

View File

@ -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):

View 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

View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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

View 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

View 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

View 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

View 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?

View File

@ -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,

View File

@ -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()

View File

@ -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