499 lines
14 KiB
C++
499 lines
14 KiB
C++
/**
|
||
* @file bluetooth_provisioning_test.cc
|
||
* @brief 蓝牙配网功能测试文件
|
||
* @author AI Assistant
|
||
* @date 2024-01-01
|
||
*/
|
||
|
||
#include "bluetooth_provisioning.h"
|
||
#include "bluetooth_provisioning_config.h"
|
||
#include <cstring>
|
||
#include <cassert>
|
||
#include <iostream>
|
||
#include <chrono>
|
||
#include <thread>
|
||
|
||
// 为了避免IDE环境中的头文件错误,使用条件编译
|
||
#ifdef ESP_PLATFORM
|
||
#include "esp_wifi.h"
|
||
#include "esp_netif.h"
|
||
#include "esp_event.h"
|
||
#include "nvs_flash.h"
|
||
#include "freertos/FreeRTOS.h"
|
||
#include "freertos/task.h"
|
||
#include "freertos/event_groups.h"
|
||
#include "esp_log.h"
|
||
#else
|
||
// 在非ESP环境中定义必要的宏和类型
|
||
#define ESP_LOGI(tag, format, ...) printf("[INFO][%s] " format "\n", tag, ##__VA_ARGS__)
|
||
#define ESP_LOGE(tag, format, ...) printf("[ERROR][%s] " format "\n", tag, ##__VA_ARGS__)
|
||
#define ESP_LOGW(tag, format, ...) printf("[WARN][%s] " format "\n", tag, ##__VA_ARGS__)
|
||
#define pdMS_TO_TICKS(ms) (ms)
|
||
typedef void* TaskHandle_t;
|
||
void vTaskDelay(int ticks) { std::this_thread::sleep_for(std::chrono::milliseconds(ticks)); }
|
||
void vTaskDelete(TaskHandle_t task) { (void)task; }
|
||
int xTaskCreate(void (*task_func)(void*), const char* name, int stack_size, void* params, int priority, TaskHandle_t* handle) {
|
||
(void)task_func; (void)name; (void)stack_size; (void)params; (void)priority; (void)handle;
|
||
return 1; // 模拟成功
|
||
}
|
||
#endif
|
||
|
||
#define TAG "BluetoothProvisioningTest"
|
||
|
||
// 测试事件组
|
||
static EventGroupHandle_t test_event_group = nullptr;
|
||
#define TEST_WIFI_CONNECTED_BIT BIT0
|
||
#define TEST_WIFI_FAILED_BIT BIT1
|
||
#define TEST_BT_CONNECTED_BIT BIT2
|
||
#define TEST_TIMEOUT_BIT BIT3
|
||
|
||
// 测试结果统计
|
||
static struct {
|
||
int total_tests;
|
||
int passed_tests;
|
||
int failed_tests;
|
||
} test_stats = {0, 0, 0};
|
||
|
||
/**
|
||
* @brief 测试事件回调函数
|
||
*/
|
||
void test_provisioning_callback(BluetoothProvisioningEvent event, void* data) {
|
||
switch (event) {
|
||
case BluetoothProvisioningEvent::STATE_CHANGED:
|
||
ESP_LOGI(TAG, "[测试] 配网状态变更");
|
||
break;
|
||
|
||
case BluetoothProvisioningEvent::CLIENT_CONNECTED:
|
||
ESP_LOGI(TAG, "[测试] 蓝牙客户端已连接");
|
||
xEventGroupSetBits(test_event_group, TEST_BT_CONNECTED_BIT);
|
||
break;
|
||
|
||
case BluetoothProvisioningEvent::CLIENT_DISCONNECTED:
|
||
ESP_LOGI(TAG, "[测试] 蓝牙客户端已断开");
|
||
xEventGroupClearBits(test_event_group, TEST_BT_CONNECTED_BIT);
|
||
break;
|
||
|
||
case BluetoothProvisioningEvent::WIFI_CREDENTIALS: {
|
||
WiFiCredentials* credentials = static_cast<WiFiCredentials*>(data);
|
||
ESP_LOGI(TAG, "[测试] 收到WiFi凭据: SSID=%s", credentials->ssid.c_str());
|
||
break;
|
||
}
|
||
|
||
case BluetoothProvisioningEvent::WIFI_CONNECTED: {
|
||
esp_ip4_addr_t* ip = static_cast<esp_ip4_addr_t*>(data);
|
||
ESP_LOGI(TAG, "[测试] WiFi连接成功: IP=" IPSTR, IP2STR(ip));
|
||
xEventGroupSetBits(test_event_group, TEST_WIFI_CONNECTED_BIT);
|
||
break;
|
||
}
|
||
|
||
case BluetoothProvisioningEvent::WIFI_FAILED: {
|
||
uint8_t* reason = static_cast<uint8_t*>(data);
|
||
ESP_LOGE(TAG, "[测试] WiFi连接失败: 原因=%d", *reason);
|
||
xEventGroupSetBits(test_event_group, TEST_WIFI_FAILED_BIT);
|
||
break;
|
||
}
|
||
|
||
default:
|
||
ESP_LOGD(TAG, "[测试] 未处理的事件: %d", static_cast<int>(event));
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 测试辅助函数 - 记录测试结果
|
||
*/
|
||
void record_test_result(const char* test_name, bool passed) {
|
||
test_stats.total_tests++;
|
||
if (passed) {
|
||
test_stats.passed_tests++;
|
||
ESP_LOGI(TAG, "✅ [测试通过] %s", test_name);
|
||
} else {
|
||
test_stats.failed_tests++;
|
||
ESP_LOGE(TAG, "❌ [测试失败] %s", test_name);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 测试1:基本初始化和反初始化
|
||
*/
|
||
bool test_basic_initialization() {
|
||
ESP_LOGI(TAG, "开始测试:基本初始化和反初始化");
|
||
|
||
BluetoothProvisioning* prov = new BluetoothProvisioning();
|
||
if (!prov) {
|
||
return false;
|
||
}
|
||
|
||
// 测试初始化
|
||
bool init_result = prov->Initialize();
|
||
if (!init_result) {
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 检查初始状态
|
||
BluetoothProvisioningState state = prov->GetState();
|
||
if (state != BluetoothProvisioningState::IDLE) {
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 测试反初始化
|
||
bool deinit_result = prov->Deinitialize();
|
||
delete prov;
|
||
|
||
return init_result && deinit_result;
|
||
}
|
||
|
||
/**
|
||
* @brief 测试2:配网服务启动和停止
|
||
*/
|
||
bool test_provisioning_start_stop() {
|
||
ESP_LOGI(TAG, "开始测试:配网服务启动和停止");
|
||
|
||
BluetoothProvisioning* prov = new BluetoothProvisioning();
|
||
if (!prov || !prov->Initialize()) {
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 测试启动配网
|
||
bool start_result = prov->StartProvisioning("测试设备");
|
||
if (!start_result) {
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 检查状态
|
||
BluetoothProvisioningState state = prov->GetState();
|
||
if (state != BluetoothProvisioningState::ADVERTISING) {
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 等待一段时间
|
||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||
|
||
// 测试停止配网
|
||
bool stop_result = prov->StopProvisioning();
|
||
|
||
// 检查状态
|
||
state = prov->GetState();
|
||
bool state_ok = (state == BluetoothProvisioningState::IDLE);
|
||
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
|
||
return start_result && stop_result && state_ok;
|
||
}
|
||
|
||
/**
|
||
* @brief 测试3:回调函数设置和触发
|
||
*/
|
||
bool test_callback_functionality() {
|
||
ESP_LOGI(TAG, "开始测试:回调函数设置和触发");
|
||
|
||
BluetoothProvisioning* prov = new BluetoothProvisioning();
|
||
if (!prov || !prov->Initialize()) {
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 设置回调函数
|
||
prov->SetCallback(test_provisioning_callback);
|
||
|
||
// 启动配网(这会触发状态变更回调)
|
||
bool start_result = prov->StartProvisioning("回调测试设备");
|
||
|
||
// 等待回调触发
|
||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||
|
||
// 停止配网
|
||
prov->StopProvisioning();
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
|
||
return start_result;
|
||
}
|
||
|
||
/**
|
||
* @brief 测试4:状态管理
|
||
*/
|
||
bool test_state_management() {
|
||
ESP_LOGI(TAG, "开始测试:状态管理");
|
||
|
||
BluetoothProvisioning* prov = new BluetoothProvisioning();
|
||
if (!prov) {
|
||
return false;
|
||
}
|
||
|
||
// 检查初始状态
|
||
BluetoothProvisioningState state = prov->GetState();
|
||
if (state != BluetoothProvisioningState::IDLE) {
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 初始化后检查状态
|
||
if (!prov->Initialize()) {
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
state = prov->GetState();
|
||
if (state != BluetoothProvisioningState::IDLE) {
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 启动配网后检查状态
|
||
prov->StartProvisioning("状态测试设备");
|
||
state = prov->GetState();
|
||
bool advertising_state_ok = (state == BluetoothProvisioningState::ADVERTISING);
|
||
|
||
// 停止配网后检查状态
|
||
prov->StopProvisioning();
|
||
state = prov->GetState();
|
||
bool idle_state_ok = (state == BluetoothProvisioningState::IDLE);
|
||
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
|
||
return advertising_state_ok && idle_state_ok;
|
||
}
|
||
|
||
/**
|
||
* @brief 测试5:错误处理
|
||
*/
|
||
bool test_error_handling() {
|
||
ESP_LOGI(TAG, "开始测试:错误处理");
|
||
|
||
BluetoothProvisioning* prov = new BluetoothProvisioning();
|
||
if (!prov) {
|
||
return false;
|
||
}
|
||
|
||
// 测试未初始化时启动配网
|
||
bool should_fail = prov->StartProvisioning("错误测试设备");
|
||
if (should_fail) {
|
||
// 这应该失败
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 正常初始化
|
||
if (!prov->Initialize()) {
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 测试重复初始化
|
||
bool repeat_init = prov->Initialize();
|
||
if (!repeat_init) {
|
||
// 重复初始化应该返回true(已经初始化)
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
// 测试重复启动配网
|
||
prov->StartProvisioning("错误测试设备1");
|
||
bool repeat_start = prov->StartProvisioning("错误测试设备2");
|
||
if (!repeat_start) {
|
||
// 重复启动应该返回true(已经在运行)
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
return false;
|
||
}
|
||
|
||
prov->StopProvisioning();
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* @brief 测试6:内存管理
|
||
*/
|
||
bool test_memory_management() {
|
||
ESP_LOGI(TAG, "开始测试:内存管理");
|
||
|
||
size_t free_heap_before = esp_get_free_heap_size();
|
||
ESP_LOGI(TAG, "测试前可用内存: %d 字节", free_heap_before);
|
||
|
||
// 创建和销毁多个实例
|
||
for (int i = 0; i < 3; i++) {
|
||
BluetoothProvisioning* prov = new BluetoothProvisioning();
|
||
if (!prov) {
|
||
return false;
|
||
}
|
||
|
||
if (prov->Initialize()) {
|
||
prov->StartProvisioning("内存测试设备");
|
||
vTaskDelay(pdMS_TO_TICKS(500));
|
||
prov->StopProvisioning();
|
||
prov->Deinitialize();
|
||
}
|
||
|
||
delete prov;
|
||
vTaskDelay(pdMS_TO_TICKS(100));
|
||
}
|
||
|
||
size_t free_heap_after = esp_get_free_heap_size();
|
||
ESP_LOGI(TAG, "测试后可用内存: %d 字节", free_heap_after);
|
||
|
||
// 检查内存泄漏(允许一定的误差)
|
||
int memory_diff = free_heap_before - free_heap_after;
|
||
bool memory_ok = (memory_diff < 1024); // 允许1KB的误差
|
||
|
||
if (!memory_ok) {
|
||
ESP_LOGW(TAG, "可能存在内存泄漏: %d 字节", memory_diff);
|
||
}
|
||
|
||
return memory_ok;
|
||
}
|
||
|
||
/**
|
||
* @brief 运行所有测试
|
||
*/
|
||
void run_all_tests() {
|
||
ESP_LOGI(TAG, "=== 开始蓝牙配网功能测试 ===");
|
||
|
||
// 创建测试事件组
|
||
test_event_group = xEventGroupCreate();
|
||
if (!test_event_group) {
|
||
ESP_LOGE(TAG, "测试事件组创建失败");
|
||
return;
|
||
}
|
||
|
||
// 运行各项测试
|
||
record_test_result("基本初始化和反初始化", test_basic_initialization());
|
||
record_test_result("配网服务启动和停止", test_provisioning_start_stop());
|
||
record_test_result("回调函数设置和触发", test_callback_functionality());
|
||
record_test_result("状态管理", test_state_management());
|
||
record_test_result("错误处理", test_error_handling());
|
||
record_test_result("内存管理", test_memory_management());
|
||
|
||
// 输出测试结果
|
||
ESP_LOGI(TAG, "=== 测试结果统计 ===");
|
||
ESP_LOGI(TAG, "总测试数: %d", test_stats.total_tests);
|
||
ESP_LOGI(TAG, "通过测试: %d", test_stats.passed_tests);
|
||
ESP_LOGI(TAG, "失败测试: %d", test_stats.failed_tests);
|
||
|
||
if (test_stats.failed_tests == 0) {
|
||
ESP_LOGI(TAG, "🎉 所有测试通过!蓝牙配网功能正常");
|
||
} else {
|
||
ESP_LOGE(TAG, "⚠️ 有 %d 个测试失败,请检查实现", test_stats.failed_tests);
|
||
}
|
||
|
||
// 清理资源
|
||
vEventGroupDelete(test_event_group);
|
||
test_event_group = nullptr;
|
||
}
|
||
|
||
/**
|
||
* @brief 蓝牙配网测试任务
|
||
*/
|
||
void bluetooth_provisioning_test_task(void* pvParameters) {
|
||
ESP_LOGI(TAG, "蓝牙配网测试任务启动");
|
||
|
||
// 等待系统稳定
|
||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||
|
||
// 运行测试
|
||
run_all_tests();
|
||
|
||
ESP_LOGI(TAG, "蓝牙配网测试任务完成");
|
||
vTaskDelete(nullptr);
|
||
}
|
||
|
||
/**
|
||
* @brief 启动蓝牙配网测试
|
||
*
|
||
* 在主程序中调用此函数来启动测试
|
||
*/
|
||
void start_bluetooth_provisioning_test() {
|
||
BaseType_t ret = xTaskCreate(
|
||
bluetooth_provisioning_test_task,
|
||
"bt_prov_test",
|
||
8192,
|
||
nullptr,
|
||
3, // 较低优先级
|
||
nullptr
|
||
);
|
||
|
||
if (ret != pdPASS) {
|
||
ESP_LOGE(TAG, "蓝牙配网测试任务创建失败");
|
||
} else {
|
||
ESP_LOGI(TAG, "蓝牙配网测试任务已创建");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 简单的配网功能演示
|
||
*
|
||
* 演示如何使用蓝牙配网功能
|
||
*/
|
||
void bluetooth_provisioning_demo() {
|
||
ESP_LOGI(TAG, "=== 蓝牙配网功能演示 ===");
|
||
|
||
BluetoothProvisioning* prov = new BluetoothProvisioning();
|
||
if (!prov) {
|
||
ESP_LOGE(TAG, "配网对象创建失败");
|
||
return;
|
||
}
|
||
|
||
// 设置回调
|
||
prov->SetCallback(test_provisioning_callback);
|
||
|
||
// 初始化
|
||
if (!prov->Initialize()) {
|
||
ESP_LOGE(TAG, "配网初始化失败");
|
||
delete prov;
|
||
return;
|
||
}
|
||
|
||
// 启动配网
|
||
if (!prov->StartProvisioning("小智AI-演示")) {
|
||
ESP_LOGE(TAG, "配网启动失败");
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
return;
|
||
}
|
||
|
||
ESP_LOGI(TAG, "配网服务已启动,请使用配网APP连接设备");
|
||
ESP_LOGI(TAG, "设备名称: 小智AI-演示");
|
||
ESP_LOGI(TAG, "等待客户端连接...");
|
||
|
||
// 运行30秒演示
|
||
for (int i = 0; i < 30; i++) {
|
||
BluetoothProvisioningState state = prov->GetState();
|
||
const char* state_names[] = {
|
||
"空闲", "初始化中", "广播中", "已连接",
|
||
"配网中", "成功", "失败", "已停止"
|
||
};
|
||
|
||
ESP_LOGI(TAG, "当前状态: %s, 客户端连接: %s",
|
||
state_names[static_cast<int>(state)],
|
||
prov->IsClientConnected() ? "是" : "否");
|
||
|
||
if (state == BluetoothProvisioningState::SUCCESS) {
|
||
ESP_LOGI(TAG, "配网成功!演示结束");
|
||
break;
|
||
}
|
||
|
||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||
}
|
||
|
||
// 清理资源
|
||
prov->StopProvisioning();
|
||
prov->Deinitialize();
|
||
delete prov;
|
||
|
||
ESP_LOGI(TAG, "演示结束");
|
||
} |