From ec450e9085593d12be3871e77ce84b82048cd8b8 Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Freeman Date: Fri, 13 Mar 2026 23:56:06 +0000 Subject: [PATCH] fix(test): fix tolerant exit code and missing RC check in resource CLI test - Replace `rc == 0 or rc == 1` with strict `rc == 0` in resource type list test so failures are no longer silently accepted - Capture and assert the return code of the Suite Setup database schema creation to fail fast if the setup itself is broken apply strict RC checks to resource_cli.robot - Capture return value of Run Process in Suite Setup and assert rc==0 - Replace tolerant RC check (rc==0 or rc==1) with strict Should Be Equal As Integers check for resource type list test case broaden exception handling in resource CLI commands Add catch-all `except Exception` handler after each `except CleverAgentsError` block in all 14 resource CLI command handlers. This ensures unexpected exceptions (e.g. sqlalchemy.exc.OperationalError) are caught and displayed gracefully instead of producing raw tracebacks. re-raise typer.Abort/Exit in broad exception handlers The `except Exception` handlers added in the previous commit inadvertently caught typer.Abort and typer.Exit, which are subclasses of Exception (via click.exceptions). This turned successful CLI exits into aborts and double-handled already-caught errors, breaking integration tests that rely on normal typer exit behaviour. Add an isinstance guard to re-raise typer.Abort and typer.Exit before the catch-all handler runs. Fixes #896 --- robot/resource_cli.robot | 5 +- src/cleveragents/cli/commands/resource.py | 74 ++++++++++++++++++++++- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/robot/resource_cli.robot b/robot/resource_cli.robot index 56f20b15f..a2cd5f9a2 100644 --- a/robot/resource_cli.robot +++ b/robot/resource_cli.robot @@ -15,8 +15,9 @@ Set Environment Variables Set Environment Variable CLEVERAGENTS_DATABASE_URL ${DB_URL} Set Environment Variable CLEVERAGENTS_TESTING_USE_MOCK_AI true ${script}= Set Variable from cleveragents.infrastructure.database.models import Base; from sqlalchemy import create_engine; e \= create_engine("${DB_URL}"); Base.metadata.create_all(e) - Run Process ${PYTHON} -c ${script} + ${result}= Run Process ${PYTHON} -c ${script} ... env:PYTHONPATH=src timeout=30s + Should Be Equal As Integers ${result.rc} 0 Clean Up Test Database Remove File build/test_resource_cli.db @@ -28,7 +29,7 @@ Resource Type List Returns Output ... env:PYTHONPATH=src env:CLEVERAGENTS_DATABASE_URL=${DB_URL} env:CLEVERAGENTS_TESTING_USE_MOCK_AI=true ... timeout=30s stderr=STDOUT Log ${result.stdout} - Should Be True ${result.rc} == 0 or ${result.rc} == 1 + Should Be Equal As Integers ${result.rc} 0 Resource Show Non Existent Returns Error [Documentation] Verify resource show for non-existent resource fails gracefully diff --git a/src/cleveragents/cli/commands/resource.py b/src/cleveragents/cli/commands/resource.py index 81e861a25..8efcc91d3 100644 --- a/src/cleveragents/cli/commands/resource.py +++ b/src/cleveragents/cli/commands/resource.py @@ -227,6 +227,11 @@ def type_add( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc @type_app.command("remove") @@ -275,6 +280,11 @@ def type_remove( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc @type_app.command("list") @@ -332,6 +342,11 @@ def type_list( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc @type_app.command("show") @@ -368,6 +383,11 @@ def type_show( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc def _print_type_panel(spec: Any) -> None: @@ -507,6 +527,11 @@ def resource_add( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc @app.command("list") @@ -569,6 +594,11 @@ def resource_list( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc @app.command("show") @@ -626,6 +656,11 @@ def resource_show( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc # --------------------------------------------------------------------------- @@ -682,6 +717,11 @@ def resource_tree( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc def _tree_to_dict( @@ -839,6 +879,11 @@ def resource_inspect( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc def _read_resource_file(resource: Any, file_path: str) -> str: @@ -921,6 +966,11 @@ def resource_link_child( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc # --------------------------------------------------------------------------- @@ -984,6 +1034,11 @@ def resource_unlink_child( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc @app.command("remove") @@ -1065,6 +1120,11 @@ def resource_remove( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc # --------------------------------------------------------------------------- @@ -1098,7 +1158,7 @@ def resource_stop( ) -> None: """Stop a running devcontainer-instance resource. - Transitions the container from ``running`` → ``stopping`` → ``stopped``. + Transitions the container from ``running`` -> ``stopping`` -> ``stopped``. Only devcontainer-instance and container-instance resources may be stopped. @@ -1151,6 +1211,11 @@ def resource_stop( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc @app.command("rebuild") @@ -1167,7 +1232,7 @@ def resource_rebuild( ) -> None: """Rebuild a stopped or failed devcontainer-instance resource. - Transitions: ``stopped``/``failed`` → ``building`` → ``running``. + Transitions: ``stopped``/``failed`` -> ``building`` -> ``running``. Only devcontainer-instance resources may be rebuilt. Use ``--yes`` / ``-y`` to skip the confirmation prompt in scripts. @@ -1225,3 +1290,8 @@ def resource_rebuild( except CleverAgentsError as exc: console.print(f"[red]Error:[/red] {exc.message}") raise typer.Abort() from exc + except Exception as exc: + if isinstance(exc, (typer.Abort, typer.Exit)): + raise + console.print(f"[red]Unexpected error:[/red] {exc}") + raise typer.Abort() from exc -- 2.52.0