|
6 | 6 |
|
7 | 7 | import pytest |
8 | 8 |
|
9 | | -from runloop_api_client.sdk import AsyncSnapshot, AsyncBlueprint, AsyncScenarioBuilder |
| 9 | +from runloop_api_client.sdk import AsyncSnapshot, AsyncBlueprint, ScenarioPreview, AsyncScenarioBuilder |
10 | 10 | from runloop_api_client.types.scoring_function_param import ScorerTestBasedScoringFunctionTestFile |
11 | 11 |
|
12 | 12 |
|
@@ -230,3 +230,65 @@ def test_fluent_chaining(self, mock_builder: AsyncScenarioBuilder, mock_blueprin |
230 | 230 | assert mock_builder._working_directory == "/app" |
231 | 231 | assert mock_builder._problem_statement == "Fix the bug" |
232 | 232 | assert len(mock_builder._scorers) == 1 |
| 233 | + |
| 234 | + def test_preview_with_no_config(self, mock_builder: AsyncScenarioBuilder) -> None: |
| 235 | + """Test preview() works with no configuration (only name from constructor).""" |
| 236 | + preview = mock_builder.preview() |
| 237 | + |
| 238 | + assert isinstance(preview, ScenarioPreview) |
| 239 | + assert preview.name == "test-scenario" |
| 240 | + assert preview.input_context is not None |
| 241 | + assert preview.input_context.problem_statement is None |
| 242 | + assert preview.input_context.additional_context is None |
| 243 | + assert preview.scoring_contract is not None |
| 244 | + assert len(preview.scoring_contract.scoring_function_parameters) == 0 |
| 245 | + assert preview.environment is None |
| 246 | + assert len(preview.metadata) == 0 |
| 247 | + assert preview.reference_output is None |
| 248 | + assert preview.required_environment_variables is None |
| 249 | + assert preview.required_secret_names is None |
| 250 | + assert preview.validation_type is None |
| 251 | + |
| 252 | + def test_preview_with_full_config(self, mock_builder: AsyncScenarioBuilder, mock_blueprint: AsyncBlueprint) -> None: |
| 253 | + """Test preview() with all fields configured, including weight normalization.""" |
| 254 | + mock_builder.with_problem_statement("Fix the bug") |
| 255 | + mock_builder.with_additional_context({"hint": "line 42"}) |
| 256 | + mock_builder.from_blueprint(mock_blueprint) |
| 257 | + mock_builder.with_working_directory("/app") |
| 258 | + mock_builder.with_metadata({"team": "infra"}) |
| 259 | + mock_builder.with_reference_output("diff content") |
| 260 | + mock_builder.with_required_env_vars(["API_KEY"]) |
| 261 | + mock_builder.with_required_secrets(["db_pass"]) |
| 262 | + mock_builder.with_validation_type("FORWARD") |
| 263 | + # Add multiple scorers with different weights to test normalization |
| 264 | + mock_builder.add_bash_script_scorer("scorer1", bash_script="echo 1", weight=1.0) |
| 265 | + mock_builder.add_bash_script_scorer("scorer2", bash_script="echo 2", weight=2.0) |
| 266 | + mock_builder.add_bash_script_scorer("scorer3", bash_script="echo 3", weight=3.0) |
| 267 | + |
| 268 | + preview = mock_builder.preview() |
| 269 | + |
| 270 | + # Verify it returns ScenarioPreview |
| 271 | + assert isinstance(preview, ScenarioPreview) |
| 272 | + |
| 273 | + # Verify all fields are populated |
| 274 | + assert preview.name == "test-scenario" |
| 275 | + assert preview.input_context is not None |
| 276 | + assert preview.input_context.problem_statement == "Fix the bug" |
| 277 | + assert preview.input_context.additional_context == {"hint": "line 42"} |
| 278 | + assert preview.environment is not None |
| 279 | + assert preview.environment.blueprint_id == "bp-123" |
| 280 | + assert preview.environment.working_directory == "/app" |
| 281 | + assert preview.metadata == {"team": "infra"} |
| 282 | + assert preview.reference_output == "diff content" |
| 283 | + assert preview.required_environment_variables == ["API_KEY"] |
| 284 | + assert preview.required_secret_names == ["db_pass"] |
| 285 | + assert preview.validation_type == "FORWARD" |
| 286 | + |
| 287 | + # Verify weights are normalized (1, 2, 3 -> 1/6, 2/6, 3/6) |
| 288 | + assert preview.scoring_contract is not None |
| 289 | + scorers = preview.scoring_contract.scoring_function_parameters |
| 290 | + assert len(scorers) == 3 |
| 291 | + assert abs(scorers[0].weight - 1 / 6) < 0.0001 |
| 292 | + assert abs(scorers[1].weight - 2 / 6) < 0.0001 |
| 293 | + assert abs(scorers[2].weight - 3 / 6) < 0.0001 |
| 294 | + assert abs(sum(s.weight for s in scorers) - 1.0) < 0.0001 |
0 commit comments