Skip to content

Add tests for OpenAI helpers and retry logic#1547

Closed
aibrahim-oai wants to merge 16 commits intomainfrom
codex/implement-tests-for-json-payload-construction
Closed

Add tests for OpenAI helpers and retry logic#1547
aibrahim-oai wants to merge 16 commits intomainfrom
codex/implement-tests-for-json-payload-construction

Conversation

@aibrahim-oai
Copy link
Copy Markdown
Collaborator

Summary

  • add unit tests for tool JSON helpers
  • verify message assembly for chat completions
  • test retry and error handling paths of ModelClient

Testing

  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace --exclude codex-linux-sandbox

https://chatgpt.com/codex/tasks/task_i_68717e8603a48321b875080ed3b70d63

@aibrahim-oai aibrahim-oai added the codex Label used by connector to tag PRs that have been reviewed by Codex label Jul 11, 2025 — with ChatGPT Codex Connector
@aibrahim-oai aibrahim-oai requested review from bolinfest and gpeal July 11, 2025 22:25
@bolinfest bolinfest added the code-review Issues relating to code reviews performed by codex label Jul 12, 2025
@github-actions github-actions Bot added codex-review-in-progress and removed code-review Issues relating to code reviews performed by codex labels Jul 12, 2025
@github-actions
Copy link
Copy Markdown
Contributor

PR Summary

Adds a suite of unit tests (≈ 437 LoC) for Rust core:

  • verifies JSON tool payload construction (openai_tools.rs)
  • checks chat-completion message assembly (chat_completions.rs)
  • exercises retry / back-off logic and error handling in the model client (client.rs)

Review

Nice boost to test coverage and confidence in critical request paths!

  • ✅ Tests are well-scoped, use wiremock to avoid real calls, and guard against the sandbox flag.
  • 🔄 Consider resetting the env vars (OPENAI_REQUEST_MAX_RETRIES) after each test to avoid bleed-through.
  • 🔄 pretty_assertions appears in the code—ensure it is listed as a dev-dependency in Cargo.toml if not already.
  • 📝 Minor: a few unwrap()s could become expect() with context, but fine for tests.

Overall, looks solid—just the small cleanup above and good to merge.


View workflow run

Copy link
Copy Markdown
Collaborator

@bolinfest bolinfest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a lot of comments, but I think none of these is review blocking, so please address before submitting.


#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn assembles_messages_correctly() {
let server = MockServer::start().await;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also need to check CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR?

Comment thread codex-rs/core/src/chat_completions.rs Outdated

let body = capture.lock().unwrap().take().unwrap();
let messages = body.get("messages").unwrap().as_array().unwrap();
assert_eq!(messages[1]["role"], "user");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just do one assert_eq! on messages in its entirety? Or maybe &messages[1..]?

}
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a docstring explaining what is being tested.

tokio::spawn(process_sse(stream, tx_event));
Ok(ResponseStream { rx_event })
}
#[cfg(test)]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you need just fmt.

.unwrap();
cfg.model_provider = provider.clone();
cfg.model = "gpt-test".into();
Arc::new(cfg)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just FYI, codex_home will be deleted when this function exits, but that seems fine in this case.

}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn retries_once_on_server_error() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all of these tests would benefit from docstrings.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added them

Comment thread codex-rs/core/src/client.rs Outdated
Comment on lines +584 to +600
let provider = ModelProviderInfo {
name: "openai".into(),
base_url: format!("{}/v1", server.uri()),
env_key: Some("PATH".into()),
env_key_instructions: None,
wire_api: WireApi::Responses,
query_params: None,
http_headers: None,
env_http_headers: None,
};
let config = default_config(provider.clone());
let client = ModelClient::new(
config,
provider,
ReasoningEffortConfig::None,
ReasoningSummaryConfig::None,
);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use a helper function to dedupe common logic in tests?

Comment thread codex-rs/core/src/openai_tools.rs Outdated

let tools = create_tools_json_for_responses_api(&prompt, "gpt-4").unwrap();
assert_eq!(tools.len(), 2);
assert_eq!(tools[0]["type"], "function");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one assert_eq! for all of tools[0]?

Comment thread codex-rs/core/src/openai_tools.rs Outdated
assert!(
tools
.iter()
.any(|t| t.get("name") == Some(&name.clone().into()))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use find(|t| t.get("name").as_ref() == Some("srv.dummy") on tools.iter() or something like that and then do an assert_eq!() on the value returned from find()?

);
}

#[test]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For both of these tests, can we just assert the entire string/serde_json::Value that we get back? I realize this means that we will have to update this test if we change the default tools, but I think having a test that verifies everything (and effectively documents what we send on the wire) is worth that maintenance cost.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

dependabot Bot and others added 2 commits July 12, 2025 16:38
…b/actions/codex (#1507)

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/node&package-manager=bun&previous-version=22.15.21&new-version=24.0.12)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

chore(deps-dev): bump @types/bun from 1.2.13 to 1.2.18 in /.github/actions/codex (#1509)

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/bun&package-manager=bun&previous-version=1.2.13&new-version=1.2.18)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

Add paste summarization to Codex TUI (#1549)

- introduce `Paste` event to avoid per-character paste handling
- collapse large pasted blocks to `[Pasted Content X lines]`
- store the real text so submission still includes it
- wire paste handling through `App`, `ChatWidget`, `BottomPane`, and
`ChatComposer`

- `cargo test -p codex-tui`

------
https://chatgpt.com/codex/tasks/task_i_6871e24abf80832184d1f3ca0c61a5ee

https://github.com/user-attachments/assets/eda7412f-da30-4474-9f7c-96b49d48fbf8

addressing review

addressing review

addressing review

Fix clippy

docstring
@aibrahim-oai aibrahim-oai force-pushed the codex/implement-tests-for-json-payload-construction branch from 61f28bc to 3d85eab Compare July 12, 2025 23:40
@aibrahim-oai aibrahim-oai requested a review from bolinfest July 14, 2025 22:39
@aibrahim-oai aibrahim-oai marked this pull request as draft July 16, 2025 17:02
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 17, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

codex Label used by connector to tag PRs that have been reviewed by Codex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants