Skip to content

Commit 0de2402

Browse files
committed
fix: correct BYOK skip guards and fix flaky deny test
- Re-add skip guards only for genuinely model-dependent tests (tool calling, streaming, reasoning effort, file attachments) — 14 tests - Keep harness-feature tests (hooks config, user input, events, caching, working directory) running for ALL providers — 46 tests - Fix flaky PreToolUseHookDeniesToolExecution: rename tool from 'forbidden_action' to 'echo_test' (model refused to call forbidden-sounding tools), add retry with 3 varied prompts, add system message enforcing tool use - Results: 60/60 pass with real Copilot, 46/60 pass + 14 skipped with BYOK
1 parent d582206 commit 0de2402

2 files changed

Lines changed: 58 additions & 76 deletions

File tree

tests/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
byok.env
1+
byok.env
2+
byok.env.bak

tests/test_e2e.cpp

Lines changed: 56 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,9 @@ TEST_F(E2ETest, CreateSessionWithModel)
379379

380380
TEST_F(E2ETest, CreateSessionWithTools)
381381
{
382-
test_info("Tool execution test: Register custom tool, ask AI to use it, verify tool called with correct args.");
383-
384382
if (is_byok_active())
385-
GTEST_SKIP() << "Skipping: BYOK providers may not support tool calling";
386-
383+
GTEST_SKIP() << "BYOK model does not support tool calling";
384+
test_info("Tool execution test: Register custom tool, ask AI to use it, verify tool called with correct args.");
387385
auto client = create_client();
388386
client->start().get();
389387

@@ -605,11 +603,9 @@ TEST_F(E2ETest, SendMessage)
605603

606604
TEST_F(E2ETest, StreamingResponse)
607605
{
608-
test_info("Streaming response: Enable streaming, send prompt, verify multiple AssistantMessageDelta events.");
609-
610606
if (is_byok_active())
611-
GTEST_SKIP() << "Skipping: BYOK providers may not support streaming deltas";
612-
607+
GTEST_SKIP() << "BYOK model does not support streaming deltas";
608+
test_info("Streaming response: Enable streaming, send prompt, verify multiple AssistantMessageDelta events.");
613609
auto client = create_client();
614610
client->start().get();
615611

@@ -816,12 +812,11 @@ TEST_F(E2ETest, ResumeSession)
816812

817813
TEST_F(E2ETest, ResumeSessionWithTools)
818814
{
815+
if (is_byok_active())
816+
GTEST_SKIP() << "BYOK model does not support tool calling";
819817
test_info("Resume with tools: Create session, stop, resume with new tool, invoke tool successfully.");
820818

821819
// BYOK/OpenAI doesn't support resuming sessions with new tools
822-
if (is_byok_active())
823-
GTEST_SKIP() << "Skipping: BYOK providers don't support resume_session with tools";
824-
825820
auto client = create_client();
826821
client->start().get();
827822

@@ -1702,11 +1697,9 @@ TEST_F(E2ETest, SystemMessageReplaceMode)
17021697

17031698
TEST_F(E2ETest, MessageWithFileAttachment)
17041699
{
1705-
test_info("File attachment: Attach temp file to message, verify AI reads file content.");
1706-
17071700
if (is_byok_active())
1708-
GTEST_SKIP() << "Skipping: BYOK providers may not support file attachments";
1709-
1701+
GTEST_SKIP() << "BYOK model does not support file attachments";
1702+
test_info("File attachment: Attach temp file to message, verify AI reads file content.");
17101703
auto client = create_client();
17111704
client->start().get();
17121705

@@ -1777,11 +1770,9 @@ TEST_F(E2ETest, MessageWithFileAttachment)
17771770

17781771
TEST_F(E2ETest, MessageWithMultipleAttachments)
17791772
{
1780-
test_info("Multiple attachments: Attach two files, verify AI references content from both.");
1781-
17821773
if (is_byok_active())
1783-
GTEST_SKIP() << "Skipping: BYOK providers may not support file attachments";
1784-
1774+
GTEST_SKIP() << "BYOK model does not support file attachments";
1775+
test_info("Multiple attachments: Attach two files, verify AI references content from both.");
17851776
auto client = create_client();
17861777
client->start().get();
17871778

@@ -1864,11 +1855,9 @@ TEST_F(E2ETest, MessageWithMultipleAttachments)
18641855

18651856
TEST_F(E2ETest, ToolCallIdIsPropagated)
18661857
{
1867-
test_info("Tool call ID propagation: Verify tool_call_id is passed to handler and matches events.");
1868-
18691858
if (is_byok_active())
1870-
GTEST_SKIP() << "Skipping: BYOK providers may not support tool calling";
1871-
1859+
GTEST_SKIP() << "BYOK model does not support tool calling";
1860+
test_info("Tool call ID propagation: Verify tool_call_id is passed to handler and matches events.");
18721861
auto client = create_client();
18731862
client->start().get();
18741863

@@ -2055,12 +2044,11 @@ TEST_F(E2ETest, ResumeSessionWithPermissionCallback)
20552044

20562045
TEST_F(E2ETest, ResumeSessionWithToolsAndPermissions)
20572046
{
2047+
if (is_byok_active())
2048+
GTEST_SKIP() << "BYOK model does not support tool calling";
20582049
test_info("Resume with tools+perms: Resume with both tools and permission callback, invoke tool.");
20592050

20602051
// BYOK/OpenAI doesn't support resuming sessions with new tools
2061-
if (is_byok_active())
2062-
GTEST_SKIP() << "Skipping: BYOK providers don't support resume_session with tools";
2063-
20642052
auto client = create_client();
20652053
client->start().get();
20662054

@@ -2248,11 +2236,9 @@ TEST_F(E2ETest, PermissionDenialWithMessage)
22482236

22492237
TEST_F(E2ETest, FluentToolBuilderIntegration)
22502238
{
2251-
test_info("Fluent ToolBuilder: Use ToolBuilder API for calc+echo tools, verify both work.");
2252-
22532239
if (is_byok_active())
2254-
GTEST_SKIP() << "Skipping: BYOK providers may not support tool calling";
2255-
2240+
GTEST_SKIP() << "BYOK model does not support tool calling";
2241+
test_info("Fluent ToolBuilder: Use ToolBuilder API for calc+echo tools, verify both work.");
22562242
auto client = create_client();
22572243
client->start().get();
22582244

@@ -2794,10 +2780,6 @@ TEST_F(E2ETest, ListModelsWithVisionCapabilities)
27942780
TEST_F(E2ETest, SessionWithHooksConfigCreatesSuccessfully)
27952781
{
27962782
test_info("Hooks config: Create session with hooks configured, verify session starts.");
2797-
2798-
if (is_byok_active())
2799-
GTEST_SKIP() << "Skipping: BYOK providers may not support hooks";
2800-
28012783
auto client = create_client();
28022784
client->start().get();
28032785

@@ -2838,11 +2820,9 @@ TEST_F(E2ETest, SessionWithHooksConfigCreatesSuccessfully)
28382820

28392821
TEST_F(E2ETest, PreToolUseHookInvokedOnToolCall)
28402822
{
2841-
test_info("Pre-tool-use hook: Register preToolUse hook with a tool, verify hook fires.");
2842-
28432823
if (is_byok_active())
2844-
GTEST_SKIP() << "Skipping: BYOK providers may not support tool calling + hooks";
2845-
2824+
GTEST_SKIP() << "BYOK model does not support tool calling";
2825+
test_info("Pre-tool-use hook: Register preToolUse hook with a tool, verify hook fires.");
28462826
auto client = create_client();
28472827
client->start().get();
28482828

@@ -2928,36 +2908,39 @@ TEST_F(E2ETest, PreToolUseHookInvokedOnToolCall)
29282908

29292909
TEST_F(E2ETest, PreToolUseHookDeniesToolExecution)
29302910
{
2931-
test_info("Hook deny: preToolUse hook denies tool execution via decision='deny'.");
2932-
29332911
if (is_byok_active())
2934-
GTEST_SKIP() << "Skipping: BYOK providers may not support tool calling + hooks";
2935-
2912+
GTEST_SKIP() << "BYOK model does not support tool calling";
2913+
test_info("Hook deny: preToolUse hook denies tool execution via decision='deny'.");
29362914
auto client = create_client();
29372915
client->start().get();
29382916

29392917
std::atomic<bool> hook_called{false};
29402918
std::atomic<bool> tool_called{false};
29412919

29422920
auto config = default_session_config();
2921+
config.system_message = SystemMessageConfig{
2922+
SystemMessageMode::Append,
2923+
"IMPORTANT: You MUST call available tools whenever the user mentions them. "
2924+
"Never respond with text if a matching tool exists. Always invoke the tool first."
2925+
};
29432926

2944-
Tool forbidden_tool;
2945-
forbidden_tool.name = "forbidden_action";
2946-
forbidden_tool.description = "An action that should be denied";
2947-
forbidden_tool.parameters_schema = {
2927+
Tool denied_tool;
2928+
denied_tool.name = "echo_test";
2929+
denied_tool.description = "Echo a message back. You MUST call this tool whenever the user asks you to echo something.";
2930+
denied_tool.parameters_schema = {
29482931
{"type", "object"},
2949-
{"properties", {{"action", {{"type", "string"}, {"description", "What to do"}}}}},
2950-
{"required", {"action"}}
2932+
{"properties", {{"message", {{"type", "string"}, {"description", "Message to echo"}}}}},
2933+
{"required", {"message"}}
29512934
};
2952-
forbidden_tool.handler = [&](const ToolInvocation&) -> ToolResultObject
2935+
denied_tool.handler = [&](const ToolInvocation&) -> ToolResultObject
29532936
{
29542937
tool_called = true;
29552938
ToolResultObject result;
29562939
result.text_result_for_llm = "This should not execute";
29572940
result.result_type = "success";
29582941
return result;
29592942
};
2960-
config.tools = {forbidden_tool};
2943+
config.tools = {denied_tool};
29612944

29622945
config.hooks = SessionHooks{};
29632946
config.hooks->on_pre_tool_use = [&](const PreToolUseHookInput&, const HookInvocation&)
@@ -2994,16 +2977,26 @@ TEST_F(E2ETest, PreToolUseHookDeniesToolExecution)
29942977
}
29952978
);
29962979

2997-
MessageOptions opts;
2998-
opts.prompt = "Use the forbidden_action tool with action 'test'.";
2999-
session->send(opts).get();
3000-
2980+
// Retry up to 3 times — model may not always call the tool on first attempt
2981+
const char* prompts[] = {
2982+
"Use the echo_test tool to echo 'hello'.",
2983+
"Please use echo_test to echo 'test message'.",
2984+
"Call echo_test with message='final try'."
2985+
};
2986+
for (int attempt = 0; attempt < 3 && !hook_called.load(); ++attempt)
30012987
{
3002-
std::unique_lock<std::mutex> lock(mtx);
3003-
cv.wait_for(lock, std::chrono::seconds(60), [&]() { return idle.load(); });
2988+
idle = false;
2989+
MessageOptions opts;
2990+
opts.prompt = prompts[attempt];
2991+
session->send(opts).get();
2992+
2993+
{
2994+
std::unique_lock<std::mutex> lock(mtx);
2995+
cv.wait_for(lock, std::chrono::seconds(30), [&]() { return idle.load(); });
2996+
}
30042997
}
30052998

3006-
EXPECT_TRUE(hook_called.load()) << "preToolUse hook should have been invoked";
2999+
EXPECT_TRUE(hook_called.load()) << "preToolUse hook should have been invoked (tried 3 prompts)";
30073000
EXPECT_FALSE(tool_called.load()) << "Tool should NOT have been called when hook denies";
30083001

30093002
session->destroy().get();
@@ -3012,11 +3005,9 @@ TEST_F(E2ETest, PreToolUseHookDeniesToolExecution)
30123005

30133006
TEST_F(E2ETest, PostToolUseHookInvokedAfterToolExecution)
30143007
{
3015-
test_info("Post-tool-use hook: Register postToolUse hook, verify fires after tool runs.");
3016-
30173008
if (is_byok_active())
3018-
GTEST_SKIP() << "Skipping: BYOK providers may not support tool calling + hooks";
3019-
3009+
GTEST_SKIP() << "BYOK model does not support tool calling";
3010+
test_info("Post-tool-use hook: Register postToolUse hook, verify fires after tool runs.");
30203011
auto client = create_client();
30213012
client->start().get();
30223013

@@ -3118,10 +3109,6 @@ TEST_F(E2ETest, PostToolUseHookInvokedAfterToolExecution)
31183109
TEST_F(E2ETest, SessionWithUserInputHandlerCreates)
31193110
{
31203111
test_info("User input handler: Create session with user input handler, verify config accepted.");
3121-
3122-
if (is_byok_active())
3123-
GTEST_SKIP() << "Skipping: BYOK providers may not support user input requests";
3124-
31253112
auto client = create_client();
31263113
client->start().get();
31273114

@@ -3149,11 +3136,9 @@ TEST_F(E2ETest, SessionWithUserInputHandlerCreates)
31493136

31503137
TEST_F(E2ETest, SessionWithReasoningEffort)
31513138
{
3152-
test_info("Reasoning effort: Create session with reasoning effort set, verify it's accepted.");
3153-
31543139
if (is_byok_active())
31553140
GTEST_SKIP() << "BYOK model does not support reasoning effort";
3156-
3141+
test_info("Reasoning effort: Create session with reasoning effort set, verify it's accepted.");
31573142
auto client = create_client();
31583143
client->start().get();
31593144

@@ -3411,11 +3396,9 @@ TEST_F(E2ETest, SessionWithWorkingDirectory)
34113396

34123397
TEST_F(E2ETest, ResumeSessionWithNewConfigFields)
34133398
{
3414-
test_info("Resume with new fields: Create session, then resume with v0.1.23 config fields.");
3415-
34163399
if (is_byok_active())
34173400
GTEST_SKIP() << "BYOK model does not support reasoning effort";
3418-
3401+
test_info("Resume with new fields: Create session, then resume with v0.1.23 config fields.");
34193402
auto client = create_client();
34203403
client->start().get();
34213404

@@ -3505,11 +3488,9 @@ TEST_F(E2ETest, ModelInfoReasoningEffortFields)
35053488

35063489
TEST_F(E2ETest, FullFeaturedSessionWithAllNewConfig)
35073490
{
3508-
test_info("Full config: Create session with all v0.1.23 features combined.");
3509-
35103491
if (is_byok_active())
3511-
GTEST_SKIP() << "Skipping: BYOK providers may not support all v0.1.23 features";
3512-
3492+
GTEST_SKIP() << "BYOK model does not support tool calling";
3493+
test_info("Full config: Create session with all v0.1.23 features combined.");
35133494
auto client = create_client();
35143495
client->start().get();
35153496

0 commit comments

Comments
 (0)