fix(test): stabilize e2e gate failures (#3447)

This commit is contained in:
Steven Enamakel's Droid
2026-06-06 17:15:16 -04:00
committed by GitHub
parent 1a01426eff
commit e1a1aa9271
6 changed files with 36 additions and 25 deletions
@@ -171,7 +171,7 @@ test.describe('Harness - Composio tool-call prompt flow', () => {
await sendMessage(page, 'check my email');
await expect(page.getByText(CANARY).first()).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(/Q3 Budget Review/i)).toBeVisible();
await expect(page.getByText(/Q3 Budget Review/i).first()).toBeVisible();
const log = await requests();
const llmHits = log.filter(
@@ -142,7 +142,7 @@ test.describe('Harness - Cron prompt-flow', () => {
await setMockBehavior('llmStreamChunkDelayMs', '10');
await sendMessage(page, 'remind me every morning at 9am');
await expect(page.getByText(CANARY)).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(CANARY).first()).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(/Done! I have set up a daily 9am morning reminder/i)).toBeVisible();
const log = await requests();
const llmHits = log.filter(
@@ -165,7 +165,7 @@ test.describe('Harness - Cron prompt-flow', () => {
await setMockBehavior('llmStreamChunkDelayMs', '10');
await sendMessage(page, 'what are my scheduled tasks');
await expect(page.getByText(CANARY)).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(CANARY).first()).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(/You have 2 scheduled tasks/i)).toBeVisible();
});
@@ -193,7 +193,7 @@ test.describe('Harness - Cron prompt-flow', () => {
await setMockBehavior('llmStreamChunkDelayMs', '10');
await sendMessage(page, 'change my morning reminder to 8am');
await expect(page.getByText(CANARY)).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(CANARY).first()).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(/changed your morning reminder to 8am/i)).toBeVisible();
});
@@ -218,7 +218,7 @@ test.describe('Harness - Cron prompt-flow', () => {
await setMockBehavior('llmStreamChunkDelayMs', '10');
await sendMessage(page, 'delete the morning reminder');
await expect(page.getByText(CANARY)).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(/deleted the morning reminder/i)).toBeVisible();
await expect(page.getByText(CANARY).first()).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(/deleted the morning reminder/i).first()).toBeVisible();
});
});
@@ -220,7 +220,7 @@ test.describe('Harness - Search tool-flow', () => {
await sendMessage(page, 'read the README');
await expect(page.getByText(CANARY).first()).toBeVisible({ timeout: 60_000 });
await expect(page.getByText(/OpenHuman is an AI assistant/i)).toBeVisible();
await expect(page.getByText(/OpenHuman is an AI assistant/i).first()).toBeVisible();
const log = await requests();
const llmHits = log.filter(
+12 -18
View File
@@ -26,10 +26,10 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# The full set of `tests/*_e2e.rs` files. Each gets a `--test <name>` flag
# in the single `cargo test` invocation so cargo compiles them in one
# unit and only the test binaries that exist get run. Tests guarded by
# `#[ignore]` stay skipped unless the caller passes `-- --ignored`.
# The full set of `tests/*_e2e.rs` files. The default runner executes them
# serially so CI does not link several large integration binaries at once.
# Tests guarded by `#[ignore]` stay skipped unless the caller passes
# `-- --ignored`.
ALL_E2E_SUITES=(
agent_retrieval_e2e
autocomplete_memory_e2e
@@ -128,19 +128,13 @@ export VITE_BACKEND_URL="$MOCK_API_URL"
cd "$REPO_ROOT"
source "$HOME/.cargo/env" 2>/dev/null || true
# Assemble the `--test <name>` flags so a single `cargo test` invocation
# compiles + runs every suite. Cargo will fail fast if any --test binary
# doesn't exist, which is the signal you want when a suite gets renamed.
CARGO_FLAGS=()
echo "[rust-e2e] Running ${#SUITES[@]} suite(s) serially."
for suite in "${SUITES[@]}"; do
CARGO_FLAGS+=(--test "$suite")
if [ "${#EXTRA_ARGS[@]}" -gt 0 ]; then
echo "[rust-e2e] cargo test --manifest-path Cargo.toml --test $suite -- ${EXTRA_ARGS[*]}"
cargo test --manifest-path Cargo.toml --test "$suite" -- "${EXTRA_ARGS[@]}"
else
echo "[rust-e2e] cargo test --manifest-path Cargo.toml --test $suite"
cargo test --manifest-path Cargo.toml --test "$suite"
fi
done
echo "[rust-e2e] Running:"
if [ "${#EXTRA_ARGS[@]}" -gt 0 ]; then
echo "[rust-e2e] cargo test --manifest-path Cargo.toml ${CARGO_FLAGS[*]} -- ${EXTRA_ARGS[*]}"
cargo test --manifest-path Cargo.toml "${CARGO_FLAGS[@]}" -- "${EXTRA_ARGS[@]}"
else
echo "[rust-e2e] cargo test --manifest-path Cargo.toml ${CARGO_FLAGS[*]}"
cargo test --manifest-path Cargo.toml "${CARGO_FLAGS[@]}"
fi
@@ -140,6 +140,7 @@ fn apply_caps_defaults_to_entries(sources: &mut [MemorySourceEntry]) -> u32 {
/// re-run it exactly once). Entries the user has already customised (non-None caps)
/// are left untouched.
pub async fn apply_composio_source_caps_migration() -> Result<(), String> {
let _guard = registry::memory_sources_write_guard().await;
let mut config = config_rpc::load_config_with_timeout().await?;
if config.composio_source_caps_migration_version >= CURRENT_CAPS_MIGRATION_VERSION {
+16
View File
@@ -6,6 +6,16 @@
use crate::openhuman::config::rpc as config_rpc;
use crate::openhuman::memory_sources::types::{MemorySourceEntry, SourceKind};
use std::sync::OnceLock;
static MEMORY_SOURCES_WRITE_LOCK: OnceLock<tokio::sync::Mutex<()>> = OnceLock::new();
pub(crate) async fn memory_sources_write_guard() -> tokio::sync::MutexGuard<'static, ()> {
MEMORY_SOURCES_WRITE_LOCK
.get_or_init(|| tokio::sync::Mutex::new(()))
.lock()
.await
}
/// Conservative default sync caps for a Composio toolkit, keyed by toolkit slug.
///
@@ -50,6 +60,7 @@ pub async fn get_source(id: &str) -> Result<Option<MemorySourceEntry>, String> {
pub async fn add_source(entry: MemorySourceEntry) -> Result<MemorySourceEntry, String> {
entry.validate()?;
let _guard = memory_sources_write_guard().await;
let mut config = config_rpc::load_config_with_timeout().await?;
if config.memory_sources.iter().any(|s| s.id == entry.id) {
@@ -75,6 +86,7 @@ pub async fn update_source(
id: &str,
patch: MemorySourcePatch,
) -> Result<MemorySourceEntry, String> {
let _guard = memory_sources_write_guard().await;
let mut config = config_rpc::load_config_with_timeout().await?;
let entry = config
@@ -159,6 +171,7 @@ pub async fn update_source(
}
pub async fn remove_source(id: &str) -> Result<bool, String> {
let _guard = memory_sources_write_guard().await;
let mut config = config_rpc::load_config_with_timeout().await?;
let before = config.memory_sources.len();
config.memory_sources.retain(|s| s.id != id);
@@ -182,6 +195,7 @@ pub async fn remove_source(id: &str) -> Result<bool, String> {
/// connection-delete flow doesn't have, so this is the connection-keyed
/// counterpart. Returns the number of entries removed (0 if none matched).
pub async fn remove_composio_source_by_connection_id(connection_id: &str) -> Result<usize, String> {
let _guard = memory_sources_write_guard().await;
let mut config = config_rpc::load_config_with_timeout().await?;
let before = config.memory_sources.len();
config.memory_sources.retain(|s| {
@@ -212,6 +226,7 @@ pub async fn upsert_composio_source(
connection_id: &str,
label: &str,
) -> Result<MemorySourceEntry, String> {
let _guard = memory_sources_write_guard().await;
let mut config = config_rpc::load_config_with_timeout().await?;
if let Some(existing) = config.memory_sources.iter_mut().find(|s| {
@@ -332,6 +347,7 @@ pub struct MemorySourcePatch {
///
/// Saves config once after all mutations and returns the updated entries.
pub async fn apply_all_in() -> Result<Vec<MemorySourceEntry>, String> {
let _guard = memory_sources_write_guard().await;
let mut config = config_rpc::load_config_with_timeout().await?;
tracing::info!(