From 6e7099ea9c78cb9dce56b01d9ab0e5d0133b54c3 Mon Sep 17 00:00:00 2001 From: jack ning Date: Thu, 31 Jul 2025 20:01:44 +0800 Subject: [PATCH] update --- jmeter/01_login.jmx | 560 ++++++++++++++++++++++++++++++ jmeter/bytedesk-load-test-plan.md | 2 +- jmeter/quick_test.jmx | 262 ++++++++++++++ jmeter/readme.md | 259 ++++++++++++-- jmeter/run_login_test.sh | 81 +++++ jmeter/run_quick_test.sh | 84 +++++ jmeter/users.csv | 101 ++++++ 7 files changed, 1311 insertions(+), 38 deletions(-) create mode 100644 jmeter/quick_test.jmx create mode 100755 jmeter/run_login_test.sh create mode 100755 jmeter/run_quick_test.sh create mode 100644 jmeter/users.csv diff --git a/jmeter/01_login.jmx b/jmeter/01_login.jmx index e69de29bb2..1a41875c44 100644 --- a/jmeter/01_login.jmx +++ b/jmeter/01_login.jmx @@ -0,0 +1,560 @@ + + + + + Bytedesk登录性能测试计划 + false + true + false + + + + host + localhost + = + + + port + 9003 + = + + + protocol + http + = + + + base_url + ${protocol}://${host}:${port} + = + + + + + + + + + + + + ${host} + ${port} + ${protocol} + UTF-8 + + 6 + 5000 + 30000 + + + + + + + + Content-Type + application/json;charset=UTF-8 + + + Accept + application/json + + + User-Agent + JMeter/5.5 + + + + + + + + continue + + false + 1 + + 100 + 10 + false + + + true + + + + + + + + + + + + /kaptcha/api/v1/get + GET + true + false + true + false + + + + + + + + captchaUid,captchaImage + $.data.captchaUid,$.data.captchaImage + + + false + + + + + + + + continue + + false + 1 + + 500 + 30 + true + 600 + 0 + true + + + + + , + UTF-8 + users.csv + true + false + true + shareMode.all + false + username,password,email,mobile + + + + + + + + + false + { + "username": "${username}", + "password": "${password}", + "captchaUid": "${captchaUid}", + "captchaCode": "1234", + "platform": "BYTEDESK", + "channel": "WEB", + "device": "JMeter Test" +} + = + true + + + + + + + + + /auth/v1/login + POST + true + false + true + false + + + + + + + + accessToken,refreshToken + $.data.accessToken,$.data.refreshToken + + + false + + + + + + + + continue + + false + 1 + + 200 + 20 + true + 300 + 0 + true + + + + + + + + false + { + "mobile": "${mobile}", + "captchaUid": "${captchaUid}", + "captchaCode": "1234", + "platform": "BYTEDESK", + "channel": "WEB", + "type": "mobile" +} + = + true + + + + + + + + + /auth/v1/send/mobile + POST + true + false + true + false + + + + + + + + + + + + false + { + "mobile": "${mobile}", + "code": "123456", + "captchaUid": "${captchaUid}", + "captchaCode": "1234", + "platform": "BYTEDESK", + "channel": "WEB", + "device": "JMeter Test" +} + = + true + + + + + + + + + /auth/v1/login/mobile + POST + true + false + true + false + + + + + + + + + + continue + + false + 1 + + 100 + 10 + true + 300 + 0 + true + + + + + + + + false + { + "email": "${email}", + "captchaUid": "${captchaUid}", + "captchaCode": "1234", + "platform": "BYTEDESK", + "channel": "WEB", + "type": "email" +} + = + true + + + + + + + + + /auth/v1/send/email + POST + true + false + true + false + + + + + + + + + + + + false + { + "email": "${email}", + "code": "123456", + "platform": "BYTEDESK", + "channel": "WEB", + "device": "JMeter Test" +} + = + true + + + + + + + + + /auth/v1/login/email + POST + true + false + true + false + + + + + + + + + + continue + + false + 1 + + 300 + 15 + true + 300 + 0 + true + + + + + + + + false + { + "accessToken": "${accessToken}", + "platform": "BYTEDESK", + "channel": "WEB" +} + = + true + + + + + + + + + /auth/v1/login/accessToken + POST + true + false + true + false + + + + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + + + 200 + + + Assertion.response_code + false + 8 + + + + + + $.success + true + true + false + false + false + + + + + + diff --git a/jmeter/bytedesk-load-test-plan.md b/jmeter/bytedesk-load-test-plan.md index 67a9533a95..c0bee8571d 100644 --- a/jmeter/bytedesk-load-test-plan.md +++ b/jmeter/bytedesk-load-test-plan.md @@ -166,7 +166,7 @@ #### 6.1.1 JMeter脚本结构 -``` +```bash jmeter/ ├── scripts/ │ ├── 01_login_test.jmx diff --git a/jmeter/quick_test.jmx b/jmeter/quick_test.jmx new file mode 100644 index 0000000000..d1b76470a7 --- /dev/null +++ b/jmeter/quick_test.jmx @@ -0,0 +1,262 @@ + + + + + Bytedesk快速登录功能验证测试 + false + true + false + + + + host + localhost + = + + + port + 9003 + = + + + protocol + http + = + + + + + + + + + + + + ${host} + ${port} + ${protocol} + UTF-8 + + 6 + 5000 + 30000 + + + + + + + + Content-Type + application/json;charset=UTF-8 + + + Accept + application/json + + + User-Agent + JMeter/5.5 + + + + + + + + continue + + false + 1 + + 5 + 1 + false + + + true + + + + + + + + + + + + /kaptcha/api/v1/get + GET + true + false + true + false + + + + + + + + captchaUid,captchaImage + $.data.captchaUid,$.data.captchaImage + + + false + + + + + + + + + + false + { + "username": "admin", + "password": "admin123", + "captchaUid": "${captchaUid}", + "captchaCode": "1234", + "platform": "BYTEDESK", + "channel": "WEB", + "device": "JMeter Quick Test" +} + = + true + + + + + + + + + /auth/v1/login + POST + true + false + true + false + + + + + + + + accessToken,refreshToken + $.data.accessToken,$.data.refreshToken + + + false + + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + true + true + false + true + true + true + true + true + 0 + true + true + true + true + true + true + + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + + + 200 + + + Assertion.response_code + false + 8 + + + + + + $.success + true + true + false + false + false + + + + + + \ No newline at end of file diff --git a/jmeter/readme.md b/jmeter/readme.md index a93c602168..f8116f5448 100644 --- a/jmeter/readme.md +++ b/jmeter/readme.md @@ -1,53 +1,238 @@ - -# JMeter Performance Tests +# Bytedesk登录性能测试 -This folder contains JMeter test plans for testing the visitor flow functionality. +本目录包含用于测试Bytedesk系统登录功能的JMeter测试脚本。 -## Test Files +## 文件说明 -- `visitor_flow_test.jmx`: Tests single visitor flow -- `multiple_visitors_test.jmx`: Tests multiple concurrent visitors +- `01_login.jmx` - JMeter测试计划文件,包含多种登录方式的测试 +- `users.csv` - 测试用户数据文件 +- `run_login_test.sh` - 测试执行脚本 +- `README.md` - 本说明文件 -## Running Tests +## 测试覆盖范围 -1. Create a `report` folder in the same directory as the .jmx files: +### 1. 获取验证码测试 +- **接口**: `GET /kaptcha/api/v1/get` +- **并发用户**: 100 +- **加压时间**: 10秒 +- **测试目的**: 验证验证码生成服务的性能 +### 2. 用户名密码登录测试 +- **接口**: `POST /auth/v1/login` +- **并发用户**: 500 +- **加压时间**: 30秒 +- **持续时间**: 10分钟 +- **测试目的**: 测试传统用户名密码登录的性能 + +### 3. 手机验证码登录测试 +- **发送验证码接口**: `POST /auth/v1/send/mobile` +- **登录接口**: `POST /auth/v1/login/mobile` +- **并发用户**: 200 +- **加压时间**: 20秒 +- **持续时间**: 5分钟 +- **测试目的**: 测试手机验证码登录流程的性能 + +### 4. 邮箱验证码登录测试 +- **发送验证码接口**: `POST /auth/v1/send/email` +- **登录接口**: `POST /auth/v1/login/email` +- **并发用户**: 100 +- **加压时间**: 10秒 +- **持续时间**: 5分钟 +- **测试目的**: 测试邮箱验证码登录流程的性能 + +### 5. AccessToken登录测试 +- **接口**: `POST /auth/v1/login/accessToken` +- **并发用户**: 300 +- **加压时间**: 15秒 +- **持续时间**: 5分钟 +- **测试目的**: 测试Token验证登录的性能 + +## 环境要求 + +### 软件要求 +- Apache JMeter 5.5+ +- Java 8+ +- Bash shell (用于执行脚本) + +### 系统要求 +- 内存: 至少4GB可用内存 +- 磁盘: 至少1GB可用空间用于存储测试结果 +- 网络: 稳定的网络连接到测试目标服务器 + +## 安装和配置 + +### 1. 安装JMeter + +#### Linux/macOS ```bash -mkdir report +# 下载JMeter +wget https://downloads.apache.org/jmeter/binaries/apache-jmeter-5.5.tgz + +# 解压 +tar -xzf apache-jmeter-5.5.tgz + +# 移动到合适位置 +sudo mv apache-jmeter-5.5 /usr/local/ ``` -2. Run the tests using JMeter GUI or command line: +#### Windows +1. 下载JMeter: https://jmeter.apache.org/download_jmeter.cgi +2. 解压到合适目录 +3. 将bin目录添加到PATH环境变量 -```bash -jmeter -n -t visitor_flow_test.jmx -l report/visitor_flow.log -e -o report/visitor_flow_dashboard -jmeter -n -t multiple_visitors_test.jmx -l report/multiple_visitors.log -e -o report/multiple_visitors_dashboard +### 2. 配置测试环境 + +#### 修改测试目标地址 +编辑 `01_login.jmx` 文件中的用户定义变量: +```xml + + host + your-server-host + + + port + 9003 + ``` -## Test Results +#### 准备测试数据 +确保 `users.csv` 文件包含有效的测试用户数据: +```csv +username,password,email,mobile +testuser1,password123,testuser1@example.com,13800138001 +... +``` -Results are stored in the `report` folder: +## 执行测试 -- `*_results.jtl`: Detailed test results -- `*_aggregate.jtl`: Aggregate statistics -- `*_graph.jtl`: Performance graphs -- `*_dashboard`: HTML dashboard reports +### 方法1: 使用脚本执行(推荐) -## Report Structure +```bash +# 使用默认JMeter路径 +./run_login_test.sh -- Response times -- Throughput -- Error rates -- Detailed request/response data -- Performance graphs +# 指定JMeter路径 +./run_login_test.sh /path/to/jmeter/bin +``` + +### 方法2: 直接使用JMeter命令 + +```bash +# 进入jmeter目录 +cd jmeter + +# 执行测试 +jmeter -n -t 01_login.jmx -l results/test_result.jtl -e -o reports/test_report +``` + +### 方法3: 使用JMeter GUI + +1. 启动JMeter GUI +```bash +jmeter +``` + +2. 打开测试计划文件 `01_login.jmx` +3. 点击运行按钮开始测试 + +## 测试结果分析 + +### 结果文件 +- `results/` - 原始测试结果文件(.jtl) +- `reports/` - HTML格式的测试报告 + +### 关键指标 +- **响应时间**: 平均响应时间、90/95/99百分位响应时间 +- **吞吐量**: 每秒处理的请求数(TPS) +- **错误率**: 请求失败的比例 +- **并发用户数**: 系统能够支持的最大并发用户数 + +### 性能基准 +根据测试计划文档,建议的性能基准: +- 登录响应时间 < 2秒 +- 错误率 < 1% +- 支持500并发用户登录 + +## 故障排除 + +### 常见问题 + +#### 1. JMeter找不到 +``` +错误: 找不到JMeter可执行文件 +``` +**解决方案**: 确保JMeter已正确安装,或通过参数指定正确的路径 + +#### 2. 测试数据文件不存在 +``` +错误: 找不到测试数据文件: users.csv +``` +**解决方案**: 确保 `users.csv` 文件存在于当前目录 + +#### 3. 网络连接失败 +``` +错误: 连接被拒绝 +``` +**解决方案**: +- 检查目标服务器是否运行 +- 验证端口配置是否正确 +- 检查防火墙设置 + +#### 4. 验证码错误 +``` +错误: 验证码验证失败 +``` +**解决方案**: +- 检查验证码接口是否正常工作 +- 确认验证码缓存服务配置正确 + +### 调试技巧 + +1. **启用详细日志** +```bash +jmeter -n -t 01_login.jmx -l results/test_result.jtl -e -o reports/test_report -L DEBUG +``` + +2. **查看JMeter日志** +```bash +tail -f jmeter.log +``` + +3. **使用JMeter GUI调试** +- 在GUI模式下运行单个请求 +- 查看请求和响应详情 + +## 扩展和定制 + +### 添加新的登录方式 +1. 在测试计划中添加新的线程组 +2. 配置相应的HTTP请求 +3. 添加必要的断言和提取器 + +### 修改测试参数 +- 调整并发用户数 +- 修改加压时间 +- 更改测试持续时间 + +### 集成到CI/CD +```bash +# 在CI/CD流水线中执行测试 +./run_login_test.sh +# 检查测试结果 +if [ $? -eq 0 ]; then + echo "性能测试通过" +else + echo "性能测试失败" + exit 1 +fi +``` + +## 联系和支持 + +如有问题或建议,请联系开发团队或提交Issue。 + +## 更新日志 + +- v1.0 - 初始版本,支持基本登录功能测试 +- 支持用户名密码、手机验证码、邮箱验证码、AccessToken四种登录方式 +- 包含完整的测试数据准备和结果分析 diff --git a/jmeter/run_login_test.sh b/jmeter/run_login_test.sh new file mode 100755 index 0000000000..d32784f1e1 --- /dev/null +++ b/jmeter/run_login_test.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# Bytedesk登录性能测试执行脚本 +# 使用方法: ./run_login_test.sh [JMeter安装路径] + +# 设置默认JMeter路径 +DEFAULT_JMETER_PATH="/usr/local/apache-jmeter-5.5/bin" +JMETER_PATH=${1:-$DEFAULT_JMETER_PATH} + +# 测试配置 +TEST_PLAN="01_login.jmx" +RESULTS_DIR="results" +REPORT_DIR="reports" +TIMESTAMP=$(date +"%Y%m%d_%H%M%S") + +# 创建结果目录 +mkdir -p "$RESULTS_DIR" +mkdir -p "$REPORT_DIR" + +echo "==========================================" +echo "Bytedesk登录性能测试开始" +echo "时间: $(date)" +echo "JMeter路径: $JMETER_PATH" +echo "测试计划: $TEST_PLAN" +echo "==========================================" + +# 检查JMeter是否存在 +if [ ! -f "$JMETER_PATH/jmeter" ]; then + echo "错误: 找不到JMeter可执行文件: $JMETER_PATH/jmeter" + echo "请确保JMeter已正确安装,或通过参数指定正确的路径" + echo "使用方法: $0 [JMeter安装路径]" + exit 1 +fi + +# 检查测试计划文件是否存在 +if [ ! -f "$TEST_PLAN" ]; then + echo "错误: 找不到测试计划文件: $TEST_PLAN" + exit 1 +fi + +# 检查测试数据文件是否存在 +if [ ! -f "users.csv" ]; then + echo "错误: 找不到测试数据文件: users.csv" + exit 1 +fi + +echo "开始执行测试..." + +# 执行JMeter测试 +"$JMETER_PATH/jmeter" -n \ + -t "$TEST_PLAN" \ + -l "$RESULTS_DIR/login_test_${TIMESTAMP}.jtl" \ + -e -o "$REPORT_DIR/login_test_${TIMESTAMP}" + +# 检查测试执行结果 +if [ $? -eq 0 ]; then + echo "==========================================" + echo "测试执行完成!" + echo "结果文件: $RESULTS_DIR/login_test_${TIMESTAMP}.jtl" + echo "报告目录: $REPORT_DIR/login_test_${TIMESTAMP}" + echo "==========================================" + + # 显示测试结果摘要 + echo "测试结果摘要:" + echo "------------------------------------------" + if [ -f "$RESULTS_DIR/login_test_${TIMESTAMP}.jtl" ]; then + echo "总请求数: $(grep -c "200" "$RESULTS_DIR/login_test_${TIMESTAMP}.jtl" 2>/dev/null || echo "0")" + echo "成功请求: $(grep -c "200" "$RESULTS_DIR/login_test_${TIMESTAMP}.jtl" 2>/dev/null || echo "0")" + echo "失败请求: $(grep -v "200" "$RESULTS_DIR/login_test_${TIMESTAMP}.jtl" | grep -c "HTTP" 2>/dev/null || echo "0")" + fi +else + echo "==========================================" + echo "测试执行失败!" + echo "请检查错误信息并重试" + echo "==========================================" + exit 1 +fi + +echo "" +echo "测试完成时间: $(date)" +echo "可以在浏览器中打开 $REPORT_DIR/login_test_${TIMESTAMP}/index.html 查看详细报告" \ No newline at end of file diff --git a/jmeter/run_quick_test.sh b/jmeter/run_quick_test.sh new file mode 100755 index 0000000000..e06859d903 --- /dev/null +++ b/jmeter/run_quick_test.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# Bytedesk快速登录功能验证测试 +# 使用方法: ./run_quick_test.sh [JMeter安装路径] + +# 设置默认JMeter路径 +DEFAULT_JMETER_PATH="/usr/local/apache-jmeter-5.5/bin" +JMETER_PATH=${1:-$DEFAULT_JMETER_PATH} + +# 测试配置 +TEST_PLAN="quick_test.jmx" +RESULTS_DIR="quick_results" +TIMESTAMP=$(date +"%Y%m%d_%H%M%S") + +# 创建结果目录 +mkdir -p "$RESULTS_DIR" + +echo "==========================================" +echo "Bytedesk快速登录功能验证测试" +echo "时间: $(date)" +echo "JMeter路径: $JMETER_PATH" +echo "测试计划: $TEST_PLAN" +echo "==========================================" + +# 检查JMeter是否存在 +if [ ! -f "$JMETER_PATH/jmeter" ]; then + echo "错误: 找不到JMeter可执行文件: $JMETER_PATH/jmeter" + echo "请确保JMeter已正确安装,或通过参数指定正确的路径" + echo "使用方法: $0 [JMeter安装路径]" + exit 1 +fi + +# 检查测试计划文件是否存在 +if [ ! -f "$TEST_PLAN" ]; then + echo "错误: 找不到测试计划文件: $TEST_PLAN" + exit 1 +fi + +echo "开始执行快速验证测试..." + +# 执行JMeter测试 +"$JMETER_PATH/jmeter" -n \ + -t "$TEST_PLAN" \ + -l "$RESULTS_DIR/quick_test_${TIMESTAMP}.jtl" + +# 检查测试执行结果 +if [ $? -eq 0 ]; then + echo "==========================================" + echo "快速验证测试完成!" + echo "结果文件: $RESULTS_DIR/quick_test_${TIMESTAMP}.jtl" + echo "==========================================" + + # 显示测试结果摘要 + echo "测试结果摘要:" + echo "------------------------------------------" + if [ -f "$RESULTS_DIR/quick_test_${TIMESTAMP}.jtl" ]; then + total_requests=$(grep -c "HTTP" "$RESULTS_DIR/quick_test_${TIMESTAMP}.jtl" 2>/dev/null || echo "0") + success_requests=$(grep -c "200" "$RESULTS_DIR/quick_test_${TIMESTAMP}.jtl" 2>/dev/null || echo "0") + failed_requests=$((total_requests - success_requests)) + + echo "总请求数: $total_requests" + echo "成功请求: $success_requests" + echo "失败请求: $failed_requests" + + if [ $failed_requests -eq 0 ]; then + echo "✅ 所有请求都成功了!登录功能正常工作。" + else + echo "❌ 有 $failed_requests 个请求失败,请检查系统配置。" + echo "详细错误信息请查看结果文件。" + fi + fi +else + echo "==========================================" + echo "快速验证测试失败!" + echo "请检查错误信息并重试" + echo "==========================================" + exit 1 +fi + +echo "" +echo "测试完成时间: $(date)" +echo "" +echo "如果快速测试通过,可以运行完整性能测试:" +echo " ./run_login_test.sh" \ No newline at end of file diff --git a/jmeter/users.csv b/jmeter/users.csv new file mode 100644 index 0000000000..687f08ce5b --- /dev/null +++ b/jmeter/users.csv @@ -0,0 +1,101 @@ +username,password,email,mobile +testuser1,password123,testuser1@example.com,13800138001 +testuser2,password123,testuser2@example.com,13800138002 +testuser3,password123,testuser3@example.com,13800138003 +testuser4,password123,testuser4@example.com,13800138004 +testuser5,password123,testuser5@example.com,13800138005 +testuser6,password123,testuser6@example.com,13800138006 +testuser7,password123,testuser7@example.com,13800138007 +testuser8,password123,testuser8@example.com,13800138008 +testuser9,password123,testuser9@example.com,13800138009 +testuser10,password123,testuser10@example.com,13800138010 +testuser11,password123,testuser11@example.com,13800138011 +testuser12,password123,testuser12@example.com,13800138012 +testuser13,password123,testuser13@example.com,13800138013 +testuser14,password123,testuser14@example.com,13800138014 +testuser15,password123,testuser15@example.com,13800138015 +testuser16,password123,testuser16@example.com,13800138016 +testuser17,password123,testuser17@example.com,13800138017 +testuser18,password123,testuser18@example.com,13800138018 +testuser19,password123,testuser19@example.com,13800138019 +testuser20,password123,testuser20@example.com,13800138020 +testuser21,password123,testuser21@example.com,13800138021 +testuser22,password123,testuser22@example.com,13800138022 +testuser23,password123,testuser23@example.com,13800138023 +testuser24,password123,testuser24@example.com,13800138024 +testuser25,password123,testuser25@example.com,13800138025 +testuser26,password123,testuser26@example.com,13800138026 +testuser27,password123,testuser27@example.com,13800138027 +testuser28,password123,testuser28@example.com,13800138028 +testuser29,password123,testuser29@example.com,13800138029 +testuser30,password123,testuser30@example.com,13800138030 +testuser31,password123,testuser31@example.com,13800138031 +testuser32,password123,testuser32@example.com,13800138032 +testuser33,password123,testuser33@example.com,13800138033 +testuser34,password123,testuser34@example.com,13800138034 +testuser35,password123,testuser35@example.com,13800138035 +testuser36,password123,testuser36@example.com,13800138036 +testuser37,password123,testuser37@example.com,13800138037 +testuser38,password123,testuser38@example.com,13800138038 +testuser39,password123,testuser39@example.com,13800138039 +testuser40,password123,testuser40@example.com,13800138040 +testuser41,password123,testuser41@example.com,13800138041 +testuser42,password123,testuser42@example.com,13800138042 +testuser43,password123,testuser43@example.com,13800138043 +testuser44,password123,testuser44@example.com,13800138044 +testuser45,password123,testuser45@example.com,13800138045 +testuser46,password123,testuser46@example.com,13800138046 +testuser47,password123,testuser47@example.com,13800138047 +testuser48,password123,testuser48@example.com,13800138048 +testuser49,password123,testuser49@example.com,13800138049 +testuser50,password123,testuser50@example.com,13800138050 +testuser51,password123,testuser51@example.com,13800138051 +testuser52,password123,testuser52@example.com,13800138052 +testuser53,password123,testuser53@example.com,13800138053 +testuser54,password123,testuser54@example.com,13800138054 +testuser55,password123,testuser55@example.com,13800138055 +testuser56,password123,testuser56@example.com,13800138056 +testuser57,password123,testuser57@example.com,13800138057 +testuser58,password123,testuser58@example.com,13800138058 +testuser59,password123,testuser59@example.com,13800138059 +testuser60,password123,testuser60@example.com,13800138060 +testuser61,password123,testuser61@example.com,13800138061 +testuser62,password123,testuser62@example.com,13800138062 +testuser63,password123,testuser63@example.com,13800138063 +testuser64,password123,testuser64@example.com,13800138064 +testuser65,password123,testuser65@example.com,13800138065 +testuser66,password123,testuser66@example.com,13800138066 +testuser67,password123,testuser67@example.com,13800138067 +testuser68,password123,testuser68@example.com,13800138068 +testuser69,password123,testuser69@example.com,13800138069 +testuser70,password123,testuser70@example.com,13800138070 +testuser71,password123,testuser71@example.com,13800138071 +testuser72,password123,testuser72@example.com,13800138072 +testuser73,password123,testuser73@example.com,13800138073 +testuser74,password123,testuser74@example.com,13800138074 +testuser75,password123,testuser75@example.com,13800138075 +testuser76,password123,testuser76@example.com,13800138076 +testuser77,password123,testuser77@example.com,13800138077 +testuser78,password123,testuser78@example.com,13800138078 +testuser79,password123,testuser79@example.com,13800138079 +testuser80,password123,testuser80@example.com,13800138080 +testuser81,password123,testuser81@example.com,13800138081 +testuser82,password123,testuser82@example.com,13800138082 +testuser83,password123,testuser83@example.com,13800138083 +testuser84,password123,testuser84@example.com,13800138084 +testuser85,password123,testuser85@example.com,13800138085 +testuser86,password123,testuser86@example.com,13800138086 +testuser87,password123,testuser87@example.com,13800138087 +testuser88,password123,testuser88@example.com,13800138088 +testuser89,password123,testuser89@example.com,13800138089 +testuser90,password123,testuser90@example.com,13800138090 +testuser91,password123,testuser91@example.com,13800138091 +testuser92,password123,testuser92@example.com,13800138092 +testuser93,password123,testuser93@example.com,13800138093 +testuser94,password123,testuser94@example.com,13800138094 +testuser95,password123,testuser95@example.com,13800138095 +testuser96,password123,testuser96@example.com,13800138096 +testuser97,password123,testuser97@example.com,13800138097 +testuser98,password123,testuser98@example.com,13800138098 +testuser99,password123,testuser99@example.com,13800138099 +testuser100,password123,testuser100@example.com,13800138100 \ No newline at end of file