W17: extract ai_common shared module + fix anthropic data race + brace bugs
- New plugins_upper/ai_common/ static library: shared PluginConfig, ToolCallAccum, StreamContext, secure_zero, extract_host_port, serialize_tool_calls, free_chat_result - Refactored openai/anthropic plugins to use dstalk_ai:: namespace from ai_common - Fixed anthropic g_config raw pointer → std::atomic (data race) - Added SSE parse error counter with threshold abort (kMaxSseParseErrors=5) - Fixed missing closing brace in both plugins' error-body catch block - Updated test targets: ai_common include path + link, using namespace dstalk_ai - plugin_loader_test: added stub_unreg + service_registry.cpp for unregister_service - Includes pre-existing uncommitted changes from prior waves Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,210 +2,215 @@
|
||||
# tests — 单元测试
|
||||
# ============================================================
|
||||
|
||||
add_executable(dstalk-smoke-test
|
||||
add_executable(dstalk_smoke_test
|
||||
smoke_test.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(dstalk-smoke-test
|
||||
target_link_libraries(dstalk_smoke_test
|
||||
PRIVATE dstalk
|
||||
)
|
||||
|
||||
add_test(NAME dstalk-smoke-test COMMAND dstalk-smoke-test)
|
||||
add_test(NAME dstalk_smoke_test COMMAND dstalk_smoke_test)
|
||||
|
||||
# ============================================================
|
||||
# dstalk-host-api-test — host API 单元测试
|
||||
# dstalk_host_api_test — host API 单元测试
|
||||
# ============================================================
|
||||
|
||||
add_executable(dstalk-host-api-test
|
||||
add_executable(dstalk_host_api_test
|
||||
host_api_test.cpp
|
||||
${CMAKE_SOURCE_DIR}/dstalk_core/src/service_registry.cpp
|
||||
)
|
||||
|
||||
target_include_directories(dstalk-host-api-test
|
||||
target_include_directories(dstalk_host_api_test
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/src
|
||||
)
|
||||
|
||||
target_compile_features(dstalk-host-api-test
|
||||
target_compile_features(dstalk_host_api_test
|
||||
PRIVATE cxx_std_17
|
||||
)
|
||||
|
||||
target_link_libraries(dstalk-host-api-test
|
||||
target_link_libraries(dstalk_host_api_test
|
||||
PRIVATE dstalk
|
||||
)
|
||||
|
||||
add_test(NAME dstalk-host-api-test COMMAND dstalk-host-api-test)
|
||||
add_test(NAME dstalk_host_api_test COMMAND dstalk_host_api_test)
|
||||
|
||||
# ============================================================
|
||||
# dstalk-event-bus-test — EventBus 单元测试
|
||||
# dstalk_event_bus_test — EventBus 单元测试
|
||||
# ============================================================
|
||||
|
||||
add_executable(dstalk-event-bus-test
|
||||
add_executable(dstalk_event_bus_test
|
||||
event_bus_test.cpp
|
||||
${CMAKE_SOURCE_DIR}/dstalk_core/src/event_bus.cpp
|
||||
)
|
||||
|
||||
target_include_directories(dstalk-event-bus-test
|
||||
target_include_directories(dstalk_event_bus_test
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/src
|
||||
)
|
||||
|
||||
target_compile_features(dstalk-event-bus-test
|
||||
target_compile_features(dstalk_event_bus_test
|
||||
PRIVATE cxx_std_17
|
||||
)
|
||||
|
||||
add_test(NAME dstalk-event-bus-test COMMAND dstalk-event-bus-test)
|
||||
add_test(NAME dstalk_event_bus_test COMMAND dstalk_event_bus_test)
|
||||
|
||||
# ============================================================
|
||||
# dstalk-service-registry-test — ServiceRegistry 补充单元测试
|
||||
# dstalk_service_registry_test — ServiceRegistry 补充单元测试
|
||||
# ============================================================
|
||||
|
||||
add_executable(dstalk-service-registry-test
|
||||
add_executable(dstalk_service_registry_test
|
||||
service_registry_test.cpp
|
||||
${CMAKE_SOURCE_DIR}/dstalk_core/src/service_registry.cpp
|
||||
)
|
||||
|
||||
target_include_directories(dstalk-service-registry-test
|
||||
target_include_directories(dstalk_service_registry_test
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/src
|
||||
)
|
||||
|
||||
target_compile_features(dstalk-service-registry-test
|
||||
target_compile_features(dstalk_service_registry_test
|
||||
PRIVATE cxx_std_17
|
||||
)
|
||||
|
||||
add_test(NAME dstalk-service-registry-test COMMAND dstalk-service-registry-test)
|
||||
add_test(NAME dstalk_service_registry_test COMMAND dstalk_service_registry_test)
|
||||
|
||||
# ============================================================
|
||||
# dstalk-context-plugin-test — Context 插件单元测试
|
||||
# dstalk_context_plugin_test — Context 插件单元测试
|
||||
# W18.1 (qa-wang + architect-lin): 覆盖 token 计数/trim/UTF-8 边界
|
||||
# ============================================================
|
||||
|
||||
add_executable(dstalk-context-plugin-test
|
||||
add_executable(dstalk_context_plugin_test
|
||||
context_plugin_test.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(dstalk-context-plugin-test
|
||||
target_link_libraries(dstalk_context_plugin_test
|
||||
PRIVATE dstalk
|
||||
)
|
||||
|
||||
add_test(NAME dstalk-context-plugin-test COMMAND dstalk-context-plugin-test)
|
||||
add_test(NAME dstalk_context_plugin_test COMMAND dstalk_context_plugin_test)
|
||||
|
||||
# ============================================================
|
||||
# dstalk-plugin-loader-test — PluginLoader 安全回归测试
|
||||
# dstalk_plugin_loader_test — PluginLoader 安全回归测试
|
||||
# W20.3 (qa-xu): 覆盖 W19 F-18.3-1~5 修复验证
|
||||
# ============================================================
|
||||
|
||||
add_executable(dstalk-plugin-loader-test
|
||||
add_executable(dstalk_plugin_loader_test
|
||||
plugin_loader_test.cpp
|
||||
${CMAKE_SOURCE_DIR}/dstalk_core/src/plugin_loader.cpp
|
||||
${CMAKE_SOURCE_DIR}/dstalk_core/src/service_registry.cpp
|
||||
${CMAKE_SOURCE_DIR}/dstalk_core/src/boost_json.cpp
|
||||
)
|
||||
|
||||
target_include_directories(dstalk-plugin-loader-test
|
||||
target_include_directories(dstalk_plugin_loader_test
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/src
|
||||
)
|
||||
|
||||
target_compile_features(dstalk-plugin-loader-test
|
||||
target_compile_features(dstalk_plugin_loader_test
|
||||
PRIVATE cxx_std_17
|
||||
)
|
||||
|
||||
find_package(Boost REQUIRED CONFIG)
|
||||
|
||||
target_compile_definitions(dstalk-plugin-loader-test
|
||||
target_compile_definitions(dstalk_plugin_loader_test
|
||||
PRIVATE
|
||||
BOOST_JSON_HEADER_ONLY
|
||||
BOOST_ALL_NO_LIB
|
||||
DSTALK_TEST_PLUGINS_DIR="${CMAKE_BINARY_DIR}/plugins"
|
||||
)
|
||||
|
||||
target_link_libraries(dstalk-plugin-loader-test
|
||||
target_link_libraries(dstalk_plugin_loader_test
|
||||
PRIVATE
|
||||
dstalk
|
||||
boost::boost
|
||||
)
|
||||
|
||||
add_test(NAME dstalk-plugin-loader-test COMMAND dstalk-plugin-loader-test)
|
||||
add_test(NAME dstalk_plugin_loader_test COMMAND dstalk_plugin_loader_test)
|
||||
|
||||
# ============================================================
|
||||
# dstalk-anthropic-plugin-test — Anthropic AI 插件单元测试
|
||||
# dstalk_anthropic_plugin_test — Anthropic AI 插件单元测试
|
||||
# W21.6 (qa-wang): 通过 #include source 访问 static 函数
|
||||
# ============================================================
|
||||
|
||||
add_executable(dstalk-anthropic-plugin-test
|
||||
add_executable(dstalk_anthropic_plugin_test
|
||||
anthropic_plugin_test.cpp
|
||||
)
|
||||
|
||||
target_include_directories(dstalk-anthropic-plugin-test
|
||||
target_include_directories(dstalk_anthropic_plugin_test
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/include
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/plugins_upper/ai_common/include
|
||||
)
|
||||
|
||||
target_compile_definitions(dstalk-anthropic-plugin-test
|
||||
target_compile_definitions(dstalk_anthropic_plugin_test
|
||||
PRIVATE
|
||||
BOOST_JSON_HEADER_ONLY
|
||||
BOOST_ALL_NO_LIB
|
||||
)
|
||||
|
||||
target_link_libraries(dstalk-anthropic-plugin-test
|
||||
target_link_libraries(dstalk_anthropic_plugin_test
|
||||
PRIVATE
|
||||
dstalk
|
||||
ai_common
|
||||
boost::boost
|
||||
)
|
||||
|
||||
add_test(NAME dstalk-anthropic-plugin-test COMMAND dstalk-anthropic-plugin-test)
|
||||
add_test(NAME dstalk_anthropic_plugin_test COMMAND dstalk_anthropic_plugin_test)
|
||||
|
||||
# ============================================================
|
||||
# dstalk-openai-plugin-test — OpenAI 兼容 AI 插件单元测试
|
||||
# dstalk_openai_plugin_test — OpenAI 兼容 AI 插件单元测试
|
||||
# W21.6 (qa-wang): 通过 #include source 访问 static 函数
|
||||
# ============================================================
|
||||
|
||||
add_executable(dstalk-openai-plugin-test
|
||||
add_executable(dstalk_openai_plugin_test
|
||||
openai_plugin_test.cpp
|
||||
)
|
||||
|
||||
target_include_directories(dstalk-openai-plugin-test
|
||||
target_include_directories(dstalk_openai_plugin_test
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/include
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/plugins_upper/ai_common/include
|
||||
)
|
||||
|
||||
target_compile_definitions(dstalk-openai-plugin-test
|
||||
target_compile_definitions(dstalk_openai_plugin_test
|
||||
PRIVATE
|
||||
BOOST_JSON_HEADER_ONLY
|
||||
BOOST_ALL_NO_LIB
|
||||
)
|
||||
|
||||
target_link_libraries(dstalk-openai-plugin-test
|
||||
target_link_libraries(dstalk_openai_plugin_test
|
||||
PRIVATE
|
||||
dstalk
|
||||
ai_common
|
||||
boost::boost
|
||||
)
|
||||
|
||||
add_test(NAME dstalk-openai-plugin-test COMMAND dstalk-openai-plugin-test)
|
||||
add_test(NAME dstalk_openai_plugin_test COMMAND dstalk_openai_plugin_test)
|
||||
|
||||
# ============================================================
|
||||
# dstalk-network-plugin-test — Network 插件单元测试
|
||||
# dstalk_network_plugin_test — Network 插件单元测试
|
||||
# W22.2 (qa-xu): 通过 #include source 访问 static 函数
|
||||
# ============================================================
|
||||
|
||||
find_package(OpenSSL REQUIRED CONFIG)
|
||||
|
||||
add_executable(dstalk-network-plugin-test
|
||||
add_executable(dstalk_network_plugin_test
|
||||
network_plugin_test.cpp
|
||||
)
|
||||
|
||||
target_include_directories(dstalk-network-plugin-test
|
||||
target_include_directories(dstalk_network_plugin_test
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/include
|
||||
)
|
||||
|
||||
target_compile_definitions(dstalk-network-plugin-test
|
||||
target_compile_definitions(dstalk_network_plugin_test
|
||||
PRIVATE
|
||||
BOOST_ALL_NO_LIB
|
||||
)
|
||||
|
||||
target_link_libraries(dstalk-network-plugin-test
|
||||
target_link_libraries(dstalk_network_plugin_test
|
||||
PRIVATE
|
||||
dstalk
|
||||
boost::boost
|
||||
openssl::openssl
|
||||
)
|
||||
|
||||
add_test(NAME dstalk-network-plugin-test COMMAND dstalk-network-plugin-test)
|
||||
add_test(NAME dstalk_network_plugin_test COMMAND dstalk_network_plugin_test)
|
||||
|
||||
# ============================================================
|
||||
# coverage — gcovr 覆盖率报告 (HTML + 终端摘要)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define BOOST_JSON_HEADER_ONLY
|
||||
#define BOOST_ALL_NO_LIB
|
||||
#include "../plugins_upper/anthropic/src/anthropic_plugin.cpp"
|
||||
using namespace dstalk_ai;
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define BOOST_JSON_HEADER_ONLY
|
||||
#define BOOST_ALL_NO_LIB
|
||||
#include "../plugins_upper/openai/src/openai_plugin.cpp"
|
||||
using namespace dstalk_ai;
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
@@ -55,6 +55,7 @@ static void mock_log(int level, const char* fmt, ...) {
|
||||
// Stub host_api 函数:除 log 外所有操作均返回失败/默认值
|
||||
static int stub_reg(const char*, int, void*) { return -1; }
|
||||
static void* stub_query(const char*, int) { return nullptr; }
|
||||
static void stub_unreg(const char*) {}
|
||||
static int stub_sub(int, dstalk_event_handler_fn, void*) { return -1; }
|
||||
static int stub_emit(int, const void*) { return -1; }
|
||||
static void stub_unsub(int) {}
|
||||
@@ -67,7 +68,7 @@ static char* stub_strdup(const char*) { return nullptr; }
|
||||
// Mock host_api vtable: all stubs except mock_log for capturing error-path diagnostics
|
||||
// Mock host_api 虚表:除 mock_log 外全部 stub,用于捕获错误路径诊断
|
||||
static dstalk_host_api_t g_mock_host_api = {
|
||||
stub_reg, stub_query,
|
||||
stub_reg, stub_query, stub_unreg,
|
||||
stub_sub, stub_emit, stub_unsub,
|
||||
stub_cget, stub_cset,
|
||||
mock_log,
|
||||
@@ -148,8 +149,8 @@ int main()
|
||||
dstalk::PluginLoader loader;
|
||||
fs::path plugins_dir = get_plugins_dir();
|
||||
|
||||
fs::path dll_config = plugins_dir / "plugin-config.dll";
|
||||
fs::path dll_fileio = plugins_dir / "plugin-file_io.dll";
|
||||
fs::path dll_config = plugins_dir / "plugin_config.dll";
|
||||
fs::path dll_fileio = plugins_dir / "plugin_file_io.dll";
|
||||
|
||||
bool have_plugins = fs::exists(dll_config) && fs::exists(dll_fileio);
|
||||
|
||||
@@ -206,8 +207,8 @@ int main()
|
||||
fs::path plugins_dir = get_plugins_dir();
|
||||
|
||||
std::vector<fs::path> dlls;
|
||||
for (auto name : {"plugin-config.dll", "plugin-file_io.dll",
|
||||
"plugin-context.dll", "plugin-session.dll"}) {
|
||||
for (auto name : {"plugin_config.dll", "plugin_file_io.dll",
|
||||
"plugin_context.dll", "plugin_session.dll"}) {
|
||||
fs::path p = plugins_dir / name;
|
||||
if (fs::exists(p)) dlls.push_back(p);
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ int main()
|
||||
// 测试服务查询: ai(可能因为没有真实 API key 而失败,但服务应存在)
|
||||
// Test service query: ai (may fail without real API key, but service should exist)
|
||||
const char* ai_provider = dstalk_config_get("ai.provider");
|
||||
if (!ai_provider) ai_provider = "ai.openai";
|
||||
if (!ai_provider) ai_provider = "ai_openai";
|
||||
auto* ai = static_cast<const dstalk_ai_service_t*>(
|
||||
dstalk_service_query(ai_provider, 1));
|
||||
if (ai) {
|
||||
@@ -598,12 +598,12 @@ int main()
|
||||
std::cout << "[OK] R3: http error path, no response body (connection refused)\n";
|
||||
}
|
||||
} else {
|
||||
// 回退:测 AI 服务 (ai.openai) 错误路径
|
||||
// Fallback: test AI service (ai.openai) error path
|
||||
// 回退:测 AI 服务 (ai_openai) 错误路径
|
||||
// Fallback: test AI service (ai_openai) error path
|
||||
auto* ai_svc = static_cast<const dstalk_ai_service_t*>(
|
||||
dstalk_service_query("ai.openai", 1));
|
||||
dstalk_service_query("ai_openai", 1));
|
||||
if (ai_svc) {
|
||||
std::cout << "[OK] R3: ai.openai service found (http fallback)\n";
|
||||
std::cout << "[OK] R3: ai_openai service found (http fallback)\n";
|
||||
dstalk_message_t msg = {"user", "hi", nullptr, nullptr};
|
||||
dstalk_chat_result_t r = ai_svc->chat(&msg, 1, "", nullptr);
|
||||
// api_key="test-key" 为无效 key,应返回 error result 而非崩溃
|
||||
|
||||
Reference in New Issue
Block a user