|
14 | 14 |
|
15 | 15 | from .utils import ( |
16 | 16 | build_ref, |
| 17 | + get_callbacks, |
17 | 18 | get_examples, |
18 | 19 | get_headers, |
19 | 20 | get_links, |
|
22 | 23 | get_responses, |
23 | 24 | get_schemas, |
24 | 25 | get_security_schemes, |
| 26 | + validate_spec, |
25 | 27 | ) |
26 | 28 |
|
27 | 29 | description = "This is a sample Petstore server. You can find out more " |
@@ -359,6 +361,40 @@ def test_links_duplicate_name(self, spec): |
359 | 361 | with pytest.raises(APISpecError, match='Another link with name "GetUser"'): |
360 | 362 | spec.components.link("GetUser", link) |
361 | 363 |
|
| 364 | + @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) |
| 365 | + def test_callbacks(self, spec): |
| 366 | + callback = { |
| 367 | + "{$request.query.callbackUrl}": { |
| 368 | + "post": { |
| 369 | + "requestBody": { |
| 370 | + "content": {"application/json": {"schema": {"type": "string"}}} |
| 371 | + }, |
| 372 | + "responses": {"200": {"description": "callback received"}}, |
| 373 | + } |
| 374 | + } |
| 375 | + } |
| 376 | + spec.components.callback("myCallback", callback) |
| 377 | + callbacks = get_callbacks(spec) |
| 378 | + assert "myCallback" in callbacks |
| 379 | + assert callbacks["myCallback"] == callback |
| 380 | + assert validate_spec(spec) |
| 381 | + |
| 382 | + @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) |
| 383 | + def test_callback_is_chainable(self, spec): |
| 384 | + spec.components.callback("cb1", {}).callback("cb2", {}) |
| 385 | + callbacks = get_callbacks(spec) |
| 386 | + assert "cb1" in callbacks |
| 387 | + assert "cb2" in callbacks |
| 388 | + |
| 389 | + @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) |
| 390 | + def test_callback_duplicate_name(self, spec): |
| 391 | + spec.components.callback("myCallback", {}) |
| 392 | + with pytest.raises( |
| 393 | + DuplicateComponentNameError, |
| 394 | + match='Another callback with name "myCallback" is already registered.', |
| 395 | + ): |
| 396 | + spec.components.callback("myCallback", {}) |
| 397 | + |
362 | 398 | def test_security_scheme(self, spec): |
363 | 399 | sec_scheme = {"type": "apiKey", "in": "header", "name": "X-API-Key"} |
364 | 400 | spec.components.security_scheme("ApiKeyAuth", sec_scheme) |
@@ -642,6 +678,62 @@ def test_links_lazy(self, spec): |
642 | 678 | assert "GetUser" in links |
643 | 679 | assert links["GetUser"] == link |
644 | 680 |
|
| 681 | + # "callbacks" components section only exists in OAS 3 |
| 682 | + @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) |
| 683 | + def test_components_resolve_refs_in_callback(self, spec): |
| 684 | + callback = { |
| 685 | + "{$request.query.callbackUrl}": { |
| 686 | + "post": { |
| 687 | + "parameters": [ |
| 688 | + {"name": "param", "in": "query", "schema": "ParamSchema"} |
| 689 | + ], |
| 690 | + "requestBody": { |
| 691 | + "content": {"application/json": {"schema": "BodySchema"}} |
| 692 | + }, |
| 693 | + "responses": {"200": {"description": "OK"}}, |
| 694 | + } |
| 695 | + } |
| 696 | + } |
| 697 | + spec.components.callback("myCallback", callback) |
| 698 | + resolved_cb = get_callbacks(spec)["myCallback"] |
| 699 | + op = resolved_cb["{$request.query.callbackUrl}"]["post"] |
| 700 | + assert op["parameters"][0]["schema"] == build_ref(spec, "schema", "ParamSchema") |
| 701 | + assert op["requestBody"]["content"]["application/json"]["schema"] == build_ref( |
| 702 | + spec, "schema", "BodySchema" |
| 703 | + ) |
| 704 | + |
| 705 | + # Referenced callbacks are only supported in OAS 3.x |
| 706 | + @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) |
| 707 | + def test_callbacks_lazy(self, spec): |
| 708 | + callback = { |
| 709 | + "{$request.query.callbackUrl}": { |
| 710 | + "post": { |
| 711 | + "responses": {"200": {"description": "OK"}}, |
| 712 | + } |
| 713 | + } |
| 714 | + } |
| 715 | + spec.components.callback("Callback_1", callback, lazy=False) |
| 716 | + spec.components.callback("Callback_2", callback, lazy=True) |
| 717 | + callbacks = get_callbacks(spec) |
| 718 | + assert "Callback_1" in callbacks |
| 719 | + assert "Callback_2" not in callbacks |
| 720 | + spec.path( |
| 721 | + "/path", |
| 722 | + operations={ |
| 723 | + "post": { |
| 724 | + "callbacks": {"myCallback": "Callback_2"}, |
| 725 | + "responses": {"200": {"description": "OK"}}, |
| 726 | + } |
| 727 | + }, |
| 728 | + ) |
| 729 | + callbacks = get_callbacks(spec) |
| 730 | + assert "Callback_2" in callbacks |
| 731 | + post_op = spec.to_dict()["paths"]["/path"]["post"] |
| 732 | + assert post_op["callbacks"]["myCallback"] == build_ref( |
| 733 | + spec, "callback", "Callback_2" |
| 734 | + ) |
| 735 | + assert validate_spec(spec) |
| 736 | + |
645 | 737 |
|
646 | 738 | class TestPath(RefsSchemaTestMixin): |
647 | 739 | paths = { |
@@ -987,6 +1079,23 @@ def test_path_resolve_callbacks(self, spec): |
987 | 1079 | == schema_ref |
988 | 1080 | ) |
989 | 1081 |
|
| 1082 | + # callbacks only exists in OAS 3 |
| 1083 | + @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) |
| 1084 | + def test_path_resolve_callback_ref(self, spec): |
| 1085 | + spec.path( |
| 1086 | + "/pet/{petId}", |
| 1087 | + operations={ |
| 1088 | + "get": { |
| 1089 | + "callbacks": { |
| 1090 | + "onEvent": "EventCallback", |
| 1091 | + } |
| 1092 | + } |
| 1093 | + }, |
| 1094 | + ) |
| 1095 | + assert get_paths(spec)["/pet/{petId}"]["get"]["callbacks"][ |
| 1096 | + "onEvent" |
| 1097 | + ] == build_ref(spec, "callback", "EventCallback") |
| 1098 | + |
990 | 1099 | # requestBody only exists in OAS 3 |
991 | 1100 | @pytest.mark.parametrize("spec", ("3.0.0",), indirect=True) |
992 | 1101 | def test_path_resolve_request_body(self, spec): |
@@ -1139,6 +1248,11 @@ def header_helper(self, header, **kwargs): |
1139 | 1248 | if not return_none: |
1140 | 1249 | return {"description": "some header"} |
1141 | 1250 |
|
| 1251 | + def callback_helper(self, callback, **kwargs): |
| 1252 | + callback.pop("dummy", None) |
| 1253 | + if not return_none: |
| 1254 | + return {"description": "some callback"} |
| 1255 | + |
1142 | 1256 | def path_helper(self, path, operations, parameters, **kwargs): |
1143 | 1257 | if not return_none: |
1144 | 1258 | if path == "/path_1": |
@@ -1234,6 +1348,27 @@ def test_plugin_header_helper_is_used(self, openapi_version, return_none): |
1234 | 1348 | # Check original header is not modified |
1235 | 1349 | assert header == {"dummy": "dummy"} |
1236 | 1350 |
|
| 1351 | + @pytest.mark.parametrize("openapi_version", ("3.0.0",)) |
| 1352 | + @pytest.mark.parametrize("return_none", (True, False)) |
| 1353 | + def test_plugin_callback_helper_is_used(self, openapi_version, return_none): |
| 1354 | + spec = APISpec( |
| 1355 | + title="Swagger Petstore", |
| 1356 | + version="1.0.0", |
| 1357 | + openapi_version=openapi_version, |
| 1358 | + plugins=(self.make_test_plugin(return_none),), |
| 1359 | + ) |
| 1360 | + callback = {"dummy": "dummy"} |
| 1361 | + spec.components.callback("myCallback", callback) |
| 1362 | + callbacks = get_callbacks(spec) |
| 1363 | + if return_none: |
| 1364 | + assert callbacks["myCallback"] == {} |
| 1365 | + else: |
| 1366 | + assert callbacks["myCallback"] == { |
| 1367 | + "description": "some callback", |
| 1368 | + } |
| 1369 | + # Check original callback is not modified |
| 1370 | + assert callback == {"dummy": "dummy"} |
| 1371 | + |
1237 | 1372 | @pytest.mark.parametrize("openapi_version", ("2.0", "3.0.0")) |
1238 | 1373 | @pytest.mark.parametrize("return_none", (True, False)) |
1239 | 1374 | def test_plugin_path_helper_is_used(self, openapi_version, return_none): |
|
0 commit comments