schemathesis 4.0.0a9__py3-none-any.whl → 4.0.0a11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- schemathesis/__init__.py +3 -7
- schemathesis/checks.py +17 -7
- schemathesis/cli/commands/__init__.py +51 -3
- schemathesis/cli/commands/data.py +10 -0
- schemathesis/cli/commands/run/__init__.py +147 -260
- schemathesis/cli/commands/run/context.py +2 -3
- schemathesis/cli/commands/run/events.py +4 -0
- schemathesis/cli/commands/run/executor.py +60 -73
- schemathesis/cli/commands/run/filters.py +15 -165
- schemathesis/cli/commands/run/handlers/cassettes.py +105 -104
- schemathesis/cli/commands/run/handlers/junitxml.py +6 -5
- schemathesis/cli/commands/run/handlers/output.py +26 -47
- schemathesis/cli/commands/run/loaders.py +35 -50
- schemathesis/cli/commands/run/validation.py +36 -161
- schemathesis/cli/core.py +5 -3
- schemathesis/cli/ext/fs.py +7 -5
- schemathesis/cli/ext/options.py +0 -21
- schemathesis/config/__init__.py +188 -0
- schemathesis/config/_auth.py +51 -0
- schemathesis/config/_checks.py +268 -0
- schemathesis/config/_diff_base.py +99 -0
- schemathesis/config/_env.py +21 -0
- schemathesis/config/_error.py +156 -0
- schemathesis/config/_generation.py +150 -0
- schemathesis/config/_health_check.py +24 -0
- schemathesis/config/_operations.py +313 -0
- schemathesis/config/_output.py +171 -0
- schemathesis/config/_parameters.py +19 -0
- schemathesis/config/_phases.py +151 -0
- schemathesis/config/_projects.py +495 -0
- schemathesis/config/_rate_limit.py +17 -0
- schemathesis/config/_report.py +116 -0
- schemathesis/config/_validator.py +9 -0
- schemathesis/config/schema.json +837 -0
- schemathesis/core/__init__.py +3 -0
- schemathesis/core/compat.py +16 -9
- schemathesis/core/errors.py +19 -2
- schemathesis/core/failures.py +6 -7
- schemathesis/core/hooks.py +20 -0
- schemathesis/core/output/__init__.py +14 -37
- schemathesis/core/output/sanitization.py +3 -146
- schemathesis/core/validation.py +16 -0
- schemathesis/engine/__init__.py +2 -4
- schemathesis/engine/context.py +41 -43
- schemathesis/engine/core.py +7 -5
- schemathesis/engine/phases/__init__.py +10 -0
- schemathesis/engine/phases/probes.py +8 -8
- schemathesis/engine/phases/stateful/_executor.py +68 -43
- schemathesis/engine/phases/unit/__init__.py +23 -15
- schemathesis/engine/phases/unit/_executor.py +77 -17
- schemathesis/engine/phases/unit/_pool.py +1 -1
- schemathesis/errors.py +2 -0
- schemathesis/filters.py +2 -3
- schemathesis/generation/__init__.py +6 -31
- schemathesis/generation/case.py +5 -3
- schemathesis/generation/coverage.py +174 -134
- schemathesis/generation/hypothesis/__init__.py +7 -1
- schemathesis/generation/hypothesis/builder.py +40 -14
- schemathesis/generation/meta.py +3 -3
- schemathesis/generation/overrides.py +37 -1
- schemathesis/generation/stateful/state_machine.py +8 -1
- schemathesis/graphql/loaders.py +21 -12
- schemathesis/openapi/checks.py +12 -8
- schemathesis/openapi/generation/filters.py +10 -8
- schemathesis/openapi/loaders.py +22 -13
- schemathesis/pytest/lazy.py +2 -5
- schemathesis/pytest/plugin.py +11 -2
- schemathesis/schemas.py +13 -61
- schemathesis/specs/graphql/schemas.py +11 -15
- schemathesis/specs/openapi/_hypothesis.py +12 -8
- schemathesis/specs/openapi/checks.py +16 -18
- schemathesis/specs/openapi/examples.py +4 -3
- schemathesis/specs/openapi/formats.py +2 -2
- schemathesis/specs/openapi/negative/__init__.py +2 -2
- schemathesis/specs/openapi/patterns.py +46 -16
- schemathesis/specs/openapi/references.py +2 -3
- schemathesis/specs/openapi/schemas.py +11 -20
- schemathesis/specs/openapi/stateful/__init__.py +10 -5
- schemathesis/transport/prepare.py +7 -6
- schemathesis/transport/requests.py +3 -1
- schemathesis/transport/wsgi.py +3 -4
- {schemathesis-4.0.0a9.dist-info → schemathesis-4.0.0a11.dist-info}/METADATA +7 -8
- schemathesis-4.0.0a11.dist-info/RECORD +166 -0
- schemathesis/cli/commands/run/checks.py +0 -79
- schemathesis/cli/commands/run/hypothesis.py +0 -78
- schemathesis/cli/commands/run/reports.py +0 -72
- schemathesis/cli/hooks.py +0 -36
- schemathesis/engine/config.py +0 -59
- schemathesis/experimental/__init__.py +0 -72
- schemathesis-4.0.0a9.dist-info/RECORD +0 -153
- {schemathesis-4.0.0a9.dist-info → schemathesis-4.0.0a11.dist-info}/WHEEL +0 -0
- {schemathesis-4.0.0a9.dist-info → schemathesis-4.0.0a11.dist-info}/entry_points.txt +0 -0
- {schemathesis-4.0.0a9.dist-info → schemathesis-4.0.0a11.dist-info}/licenses/LICENSE +0 -0
@@ -1,52 +1,43 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from pathlib import Path
|
4
|
-
from
|
5
|
-
from typing import Any, Sequence
|
4
|
+
from typing import Any, Callable
|
6
5
|
|
7
6
|
import click
|
8
7
|
from click.utils import LazyFile
|
9
8
|
|
10
|
-
from schemathesis import contrib
|
9
|
+
from schemathesis import contrib
|
11
10
|
from schemathesis.checks import CHECKS
|
12
11
|
from schemathesis.cli.commands.run import executor, validation
|
13
|
-
from schemathesis.cli.commands.run.
|
14
|
-
from schemathesis.cli.commands.run.filters import FilterArguments, with_filters
|
15
|
-
from schemathesis.cli.commands.run.hypothesis import (
|
16
|
-
HYPOTHESIS_IN_MEMORY_DATABASE_IDENTIFIER,
|
17
|
-
HealthCheck,
|
18
|
-
prepare_health_checks,
|
19
|
-
prepare_phases,
|
20
|
-
prepare_settings,
|
21
|
-
)
|
22
|
-
from schemathesis.cli.commands.run.reports import DEFAULT_REPORT_DIRECTORY, ReportConfig, ReportFormat
|
12
|
+
from schemathesis.cli.commands.run.filters import with_filters
|
23
13
|
from schemathesis.cli.constants import DEFAULT_WORKERS, MAX_WORKERS, MIN_WORKERS
|
24
14
|
from schemathesis.cli.core import ensure_color
|
25
15
|
from schemathesis.cli.ext.groups import group, grouped_option
|
26
16
|
from schemathesis.cli.ext.options import (
|
27
17
|
CsvChoice,
|
28
18
|
CsvEnumChoice,
|
29
|
-
CsvListChoice,
|
30
19
|
CustomHelpMessageChoice,
|
31
20
|
RegistryChoice,
|
32
21
|
)
|
33
|
-
from schemathesis.
|
22
|
+
from schemathesis.config import DEFAULT_REPORT_DIRECTORY, HealthCheck, ReportFormat, SchemathesisConfig
|
23
|
+
from schemathesis.core import HYPOTHESIS_IN_MEMORY_DATABASE_IDENTIFIER
|
34
24
|
from schemathesis.core.transport import DEFAULT_RESPONSE_TIMEOUT
|
35
|
-
from schemathesis.
|
36
|
-
from schemathesis.
|
37
|
-
from schemathesis.generation import DEFAULT_GENERATOR_MODES, GenerationConfig, GenerationMode
|
38
|
-
from schemathesis.generation.overrides import Override
|
39
|
-
from schemathesis.generation.targets import TARGETS
|
25
|
+
from schemathesis.generation import DEFAULT_GENERATOR_MODES, GenerationMode
|
26
|
+
from schemathesis.generation.targets import TARGETS, TargetFunction
|
40
27
|
|
41
28
|
# NOTE: Need to explicitly import all registered checks
|
42
29
|
from schemathesis.specs.openapi.checks import * # noqa: F401, F403
|
43
30
|
|
44
31
|
COLOR_OPTIONS_INVALID_USAGE_MESSAGE = "Can't use `--no-color` and `--force-color` simultaneously"
|
45
32
|
|
46
|
-
DEFAULT_PHASES =
|
33
|
+
DEFAULT_PHASES = ["examples", "coverage", "fuzzing", "stateful"]
|
47
34
|
|
48
35
|
|
49
|
-
@click.argument(
|
36
|
+
@click.argument( # type: ignore[misc]
|
37
|
+
"location",
|
38
|
+
type=str,
|
39
|
+
callback=validation.validate_schema_location,
|
40
|
+
)
|
50
41
|
@group("Options")
|
51
42
|
@grouped_option(
|
52
43
|
"--url",
|
@@ -61,7 +52,7 @@ DEFAULT_PHASES = ("examples", "coverage", "fuzzing", "stateful")
|
|
61
52
|
@grouped_option(
|
62
53
|
"--workers",
|
63
54
|
"-w",
|
64
|
-
"
|
55
|
+
"workers",
|
65
56
|
help="Number of concurrent workers for testing. Auto-adjusts if 'auto' is specified",
|
66
57
|
type=CustomHelpMessageChoice(
|
67
58
|
["auto", *list(map(str, range(MIN_WORKERS, MAX_WORKERS + 1)))],
|
@@ -100,7 +91,7 @@ DEFAULT_PHASES = ("examples", "coverage", "fuzzing", "stateful")
|
|
100
91
|
multiple=True,
|
101
92
|
help="Comma-separated list of checks to run against API responses",
|
102
93
|
type=RegistryChoice(CHECKS, with_all=True),
|
103
|
-
default=
|
94
|
+
default=None,
|
104
95
|
callback=validation.reduce_list,
|
105
96
|
show_default=True,
|
106
97
|
metavar="",
|
@@ -111,7 +102,7 @@ DEFAULT_PHASES = ("examples", "coverage", "fuzzing", "stateful")
|
|
111
102
|
multiple=True,
|
112
103
|
help="Comma-separated list of checks to skip during testing",
|
113
104
|
type=RegistryChoice(CHECKS, with_all=True),
|
114
|
-
default=
|
105
|
+
default=None,
|
115
106
|
callback=validation.reduce_list,
|
116
107
|
show_default=True,
|
117
108
|
metavar="",
|
@@ -153,12 +144,14 @@ DEFAULT_PHASES = ("examples", "coverage", "fuzzing", "stateful")
|
|
153
144
|
"include_by",
|
154
145
|
type=str,
|
155
146
|
metavar="EXPR",
|
147
|
+
callback=validation.validate_filter_expression,
|
156
148
|
help="Include using custom expression",
|
157
149
|
)
|
158
150
|
@grouped_option(
|
159
151
|
"--exclude-by",
|
160
152
|
"exclude_by",
|
161
153
|
type=str,
|
154
|
+
callback=validation.validate_filter_expression,
|
162
155
|
metavar="EXPR",
|
163
156
|
help="Exclude using custom expression",
|
164
157
|
)
|
@@ -246,6 +239,7 @@ DEFAULT_PHASES = ("examples", "coverage", "fuzzing", "stateful")
|
|
246
239
|
)
|
247
240
|
@grouped_option(
|
248
241
|
"--report-dir",
|
242
|
+
"report_directory",
|
249
243
|
help="Directory to store all report files",
|
250
244
|
type=click.Path(file_okay=False, dir_okay=True),
|
251
245
|
default=DEFAULT_REPORT_DIRECTORY,
|
@@ -295,53 +289,6 @@ DEFAULT_PHASES = ("examples", "coverage", "fuzzing", "stateful")
|
|
295
289
|
metavar="BOOLEAN",
|
296
290
|
callback=validation.convert_boolean_string,
|
297
291
|
)
|
298
|
-
@group("Experimental options")
|
299
|
-
@grouped_option(
|
300
|
-
"--experimental",
|
301
|
-
"experiments",
|
302
|
-
help="Enable experimental features",
|
303
|
-
type=click.Choice(sorted([experiment.label for experiment in experimental.GLOBAL_EXPERIMENTS.available])),
|
304
|
-
callback=validation.convert_experimental,
|
305
|
-
multiple=True,
|
306
|
-
metavar="FEATURES",
|
307
|
-
)
|
308
|
-
@grouped_option(
|
309
|
-
"--experimental-coverage-unexpected-methods",
|
310
|
-
"coverage_unexpected_methods",
|
311
|
-
help="HTTP methods to use when generating test cases with methods not specified in the API during the coverage phase.",
|
312
|
-
type=CsvChoice(["get", "put", "post", "delete", "options", "head", "patch", "trace"], case_sensitive=False),
|
313
|
-
callback=validation.convert_http_methods,
|
314
|
-
metavar="",
|
315
|
-
default=None,
|
316
|
-
envvar="SCHEMATHESIS_EXPERIMENTAL_COVERAGE_UNEXPECTED_METHODS",
|
317
|
-
)
|
318
|
-
@grouped_option(
|
319
|
-
"--experimental-missing-required-header-allowed-statuses",
|
320
|
-
"missing_required_header_allowed_statuses",
|
321
|
-
help="Comma-separated list of status codes expected for test cases with a missing required header",
|
322
|
-
type=CsvListChoice(),
|
323
|
-
callback=validation.convert_status_codes,
|
324
|
-
metavar="",
|
325
|
-
envvar="SCHEMATHESIS_EXPERIMENTAL_MISSING_REQUIRED_HEADER_ALLOWED_STATUSES",
|
326
|
-
)
|
327
|
-
@grouped_option(
|
328
|
-
"--experimental-positive-data-acceptance-allowed-statuses",
|
329
|
-
"positive_data_acceptance_allowed_statuses",
|
330
|
-
help="Comma-separated list of status codes considered as successful responses",
|
331
|
-
type=CsvListChoice(),
|
332
|
-
callback=validation.convert_status_codes,
|
333
|
-
metavar="",
|
334
|
-
envvar="SCHEMATHESIS_EXPERIMENTAL_POSITIVE_DATA_ACCEPTANCE_ALLOWED_STATUSES",
|
335
|
-
)
|
336
|
-
@grouped_option(
|
337
|
-
"--experimental-negative-data-rejection-allowed-statuses",
|
338
|
-
"negative_data_rejection_allowed_statuses",
|
339
|
-
help="Comma-separated list of status codes expected for rejected negative data",
|
340
|
-
type=CsvListChoice(),
|
341
|
-
callback=validation.convert_status_codes,
|
342
|
-
metavar="",
|
343
|
-
envvar="SCHEMATHESIS_EXPERIMENTAL_NEGATIVE_DATA_REJECTION_ALLOWED_STATUSES",
|
344
|
-
)
|
345
292
|
@group("Data generation options")
|
346
293
|
@grouped_option(
|
347
294
|
"--mode",
|
@@ -378,7 +325,7 @@ DEFAULT_PHASES = ("examples", "coverage", "fuzzing", "stateful")
|
|
378
325
|
help="Enables deterministic mode, which eliminates random variation between tests",
|
379
326
|
is_flag=True,
|
380
327
|
is_eager=True,
|
381
|
-
default=
|
328
|
+
default=False,
|
382
329
|
show_default=True,
|
383
330
|
)
|
384
331
|
@grouped_option(
|
@@ -404,7 +351,7 @@ DEFAULT_PHASES = ("examples", "coverage", "fuzzing", "stateful")
|
|
404
351
|
help="Guide input generation to values more likely to expose bugs via targeted property-based testing",
|
405
352
|
type=RegistryChoice(TARGETS),
|
406
353
|
default=None,
|
407
|
-
callback=validation.
|
354
|
+
callback=validation.convert_maximize,
|
408
355
|
show_default=True,
|
409
356
|
metavar="METRIC",
|
410
357
|
)
|
@@ -452,98 +399,57 @@ DEFAULT_PHASES = ("examples", "coverage", "fuzzing", "stateful")
|
|
452
399
|
show_default=True,
|
453
400
|
metavar="BOOLEAN",
|
454
401
|
)
|
455
|
-
@group("Open API options")
|
456
|
-
@grouped_option(
|
457
|
-
"--set-query",
|
458
|
-
"set_query",
|
459
|
-
help=r"OpenAPI: Override a specific query parameter by specifying 'parameter=value'",
|
460
|
-
multiple=True,
|
461
|
-
type=str,
|
462
|
-
callback=validation.validate_set_query,
|
463
|
-
)
|
464
|
-
@grouped_option(
|
465
|
-
"--set-header",
|
466
|
-
"set_header",
|
467
|
-
help=r"OpenAPI: Override a specific header parameter by specifying 'parameter=value'",
|
468
|
-
multiple=True,
|
469
|
-
type=str,
|
470
|
-
callback=validation.validate_set_header,
|
471
|
-
)
|
472
|
-
@grouped_option(
|
473
|
-
"--set-cookie",
|
474
|
-
"set_cookie",
|
475
|
-
help=r"OpenAPI: Override a specific cookie parameter by specifying 'parameter=value'",
|
476
|
-
multiple=True,
|
477
|
-
type=str,
|
478
|
-
callback=validation.validate_set_cookie,
|
479
|
-
)
|
480
|
-
@grouped_option(
|
481
|
-
"--set-path",
|
482
|
-
"set_path",
|
483
|
-
help=r"OpenAPI: Override a specific path parameter by specifying 'parameter=value'",
|
484
|
-
multiple=True,
|
485
|
-
type=str,
|
486
|
-
callback=validation.validate_set_path,
|
487
|
-
)
|
488
402
|
@group("Global options")
|
489
403
|
@grouped_option("--no-color", help="Disable ANSI color escape codes", type=bool, is_flag=True)
|
490
404
|
@grouped_option("--force-color", help="Explicitly tells to enable ANSI color escape codes", type=bool, is_flag=True)
|
491
405
|
@click.pass_context # type: ignore[misc]
|
492
406
|
def run(
|
493
407
|
ctx: click.Context,
|
494
|
-
|
408
|
+
*,
|
409
|
+
location: str,
|
495
410
|
auth: tuple[str, str] | None,
|
496
411
|
headers: dict[str, str],
|
497
|
-
|
498
|
-
|
499
|
-
set_cookie: dict[str, str],
|
500
|
-
set_path: dict[str, str],
|
501
|
-
experiments: list,
|
502
|
-
coverage_unexpected_methods: set[str] | None,
|
503
|
-
missing_required_header_allowed_statuses: list[str],
|
504
|
-
positive_data_acceptance_allowed_statuses: list[str],
|
505
|
-
negative_data_rejection_allowed_statuses: list[str],
|
506
|
-
included_check_names: Sequence[str],
|
507
|
-
excluded_check_names: Sequence[str],
|
412
|
+
included_check_names: list[str] | None,
|
413
|
+
excluded_check_names: list[str] | None,
|
508
414
|
max_response_time: float | None = None,
|
509
|
-
phases:
|
415
|
+
phases: list[str] = DEFAULT_PHASES,
|
510
416
|
max_failures: int | None = None,
|
511
|
-
continue_on_failure: bool =
|
512
|
-
include_path:
|
513
|
-
include_path_regex: str | None
|
514
|
-
include_method:
|
515
|
-
include_method_regex: str | None
|
516
|
-
include_name:
|
517
|
-
include_name_regex: str | None
|
518
|
-
include_tag:
|
519
|
-
include_tag_regex: str | None
|
520
|
-
include_operation_id:
|
521
|
-
include_operation_id_regex: str | None
|
522
|
-
exclude_path:
|
523
|
-
exclude_path_regex: str | None
|
524
|
-
exclude_method:
|
525
|
-
exclude_method_regex: str | None
|
526
|
-
exclude_name:
|
527
|
-
exclude_name_regex: str | None
|
528
|
-
exclude_tag:
|
529
|
-
exclude_tag_regex: str | None
|
530
|
-
exclude_operation_id:
|
531
|
-
exclude_operation_id_regex: str | None
|
532
|
-
include_by:
|
533
|
-
exclude_by:
|
417
|
+
continue_on_failure: bool | None = None,
|
418
|
+
include_path: tuple[str, ...],
|
419
|
+
include_path_regex: str | None,
|
420
|
+
include_method: tuple[str, ...],
|
421
|
+
include_method_regex: str | None,
|
422
|
+
include_name: tuple[str, ...],
|
423
|
+
include_name_regex: str | None,
|
424
|
+
include_tag: tuple[str, ...],
|
425
|
+
include_tag_regex: str | None,
|
426
|
+
include_operation_id: tuple[str, ...],
|
427
|
+
include_operation_id_regex: str | None,
|
428
|
+
exclude_path: tuple[str, ...],
|
429
|
+
exclude_path_regex: str | None,
|
430
|
+
exclude_method: tuple[str, ...],
|
431
|
+
exclude_method_regex: str | None,
|
432
|
+
exclude_name: tuple[str, ...],
|
433
|
+
exclude_name_regex: str | None,
|
434
|
+
exclude_tag: tuple[str, ...],
|
435
|
+
exclude_tag_regex: str | None,
|
436
|
+
exclude_operation_id: tuple[str, ...],
|
437
|
+
exclude_operation_id_regex: str | None,
|
438
|
+
include_by: Callable | None = None,
|
439
|
+
exclude_by: Callable | None = None,
|
534
440
|
exclude_deprecated: bool = False,
|
535
|
-
|
536
|
-
base_url: str | None
|
441
|
+
workers: int = DEFAULT_WORKERS,
|
442
|
+
base_url: str | None,
|
537
443
|
wait_for_schema: float | None = None,
|
444
|
+
suppress_health_check: list[HealthCheck] | None,
|
538
445
|
rate_limit: str | None = None,
|
539
|
-
suppress_health_check: list[HealthCheck] | None = None,
|
540
446
|
request_timeout: int | None = None,
|
541
447
|
request_tls_verify: bool = True,
|
542
448
|
request_cert: str | None = None,
|
543
449
|
request_cert_key: str | None = None,
|
544
450
|
request_proxy: str | None = None,
|
545
|
-
report_formats: list[ReportFormat] | None
|
546
|
-
|
451
|
+
report_formats: list[ReportFormat] | None,
|
452
|
+
report_directory: Path | str = DEFAULT_REPORT_DIRECTORY,
|
547
453
|
report_junit_path: LazyFile | None = None,
|
548
454
|
report_vcr_path: LazyFile | None = None,
|
549
455
|
report_har_path: LazyFile | None = None,
|
@@ -551,11 +457,11 @@ def run(
|
|
551
457
|
output_sanitize: bool = True,
|
552
458
|
output_truncate: bool = True,
|
553
459
|
contrib_openapi_fill_missing_examples: bool = False,
|
554
|
-
generation_modes:
|
460
|
+
generation_modes: list[GenerationMode] = DEFAULT_GENERATOR_MODES,
|
555
461
|
generation_seed: int | None = None,
|
556
462
|
generation_max_examples: int | None = None,
|
557
|
-
generation_maximize:
|
558
|
-
generation_deterministic: bool
|
463
|
+
generation_maximize: list[TargetFunction] | None,
|
464
|
+
generation_deterministic: bool = False,
|
559
465
|
generation_database: str | None = None,
|
560
466
|
generation_unique_inputs: bool = False,
|
561
467
|
generation_allow_x00: bool = True,
|
@@ -573,126 +479,107 @@ def run(
|
|
573
479
|
"""
|
574
480
|
if no_color and force_color:
|
575
481
|
raise click.UsageError(COLOR_OPTIONS_INVALID_USAGE_MESSAGE)
|
576
|
-
ensure_color(ctx, no_color, force_color)
|
577
482
|
|
578
|
-
|
483
|
+
config: SchemathesisConfig = ctx.obj.config
|
484
|
+
|
485
|
+
# First, set the right color
|
486
|
+
color: bool | None
|
487
|
+
if force_color:
|
488
|
+
color = True
|
489
|
+
elif no_color:
|
490
|
+
color = False
|
491
|
+
else:
|
492
|
+
color = config.color
|
493
|
+
ensure_color(ctx, color)
|
579
494
|
|
580
|
-
|
581
|
-
_hypothesis_suppress_health_check = prepare_health_checks(suppress_health_check)
|
495
|
+
validation.validate_auth_overlap(auth, headers)
|
582
496
|
|
583
|
-
for experiment in experiments:
|
584
|
-
experiment.enable()
|
585
497
|
if contrib_openapi_fill_missing_examples:
|
586
498
|
contrib.openapi.fill_missing_examples.install()
|
587
499
|
|
588
|
-
override
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
500
|
+
# Then override the global config from CLI options
|
501
|
+
config.update(
|
502
|
+
color=color,
|
503
|
+
suppress_health_check=suppress_health_check,
|
504
|
+
seed=generation_seed,
|
505
|
+
wait_for_schema=wait_for_schema,
|
506
|
+
max_failures=max_failures,
|
507
|
+
)
|
508
|
+
config.output.sanitization.update(enabled=output_sanitize)
|
509
|
+
config.output.truncation.update(enabled=output_truncate)
|
510
|
+
config.reports.update(
|
511
|
+
formats=report_formats,
|
512
|
+
junit_path=report_junit_path.name if report_junit_path else None,
|
513
|
+
vcr_path=report_vcr_path.name if report_vcr_path else None,
|
514
|
+
har_path=report_har_path.name if report_har_path else None,
|
515
|
+
directory=Path(report_directory),
|
516
|
+
preserve_bytes=report_preserve_bytes,
|
517
|
+
)
|
518
|
+
# Other CLI options work as an override for all defined projects
|
519
|
+
config.projects.override.update(
|
520
|
+
base_url=base_url,
|
521
|
+
headers=headers if headers else None,
|
522
|
+
basic_auth=auth,
|
523
|
+
workers=workers,
|
524
|
+
continue_on_failure=continue_on_failure,
|
525
|
+
rate_limit=rate_limit,
|
526
|
+
request_timeout=request_timeout,
|
527
|
+
tls_verify=request_tls_verify,
|
528
|
+
request_cert=request_cert,
|
529
|
+
request_cert_key=request_cert_key,
|
530
|
+
proxy=request_proxy,
|
531
|
+
)
|
532
|
+
# These are filters for what API operations should be tested
|
533
|
+
filter_set = {
|
534
|
+
"include_path": include_path,
|
535
|
+
"include_method": include_method,
|
536
|
+
"include_name": include_name,
|
537
|
+
"include_tag": include_tag,
|
538
|
+
"include_operation_id": include_operation_id,
|
539
|
+
"include_path_regex": include_path_regex,
|
540
|
+
"include_method_regex": include_method_regex,
|
541
|
+
"include_name_regex": include_name_regex,
|
542
|
+
"include_tag_regex": include_tag_regex,
|
543
|
+
"include_operation_id_regex": include_operation_id_regex,
|
544
|
+
"exclude_path": exclude_path,
|
545
|
+
"exclude_method": exclude_method,
|
546
|
+
"exclude_name": exclude_name,
|
547
|
+
"exclude_tag": exclude_tag,
|
548
|
+
"exclude_operation_id": exclude_operation_id,
|
549
|
+
"exclude_path_regex": exclude_path_regex,
|
550
|
+
"exclude_method_regex": exclude_method_regex,
|
551
|
+
"exclude_name_regex": exclude_name_regex,
|
552
|
+
"exclude_tag_regex": exclude_tag_regex,
|
553
|
+
"exclude_operation_id_regex": exclude_operation_id_regex,
|
554
|
+
"include_by": include_by,
|
555
|
+
"exclude_by": exclude_by,
|
556
|
+
"exclude_deprecated": exclude_deprecated,
|
557
|
+
}
|
558
|
+
config.projects.override.phases.update(phases=phases)
|
559
|
+
config.projects.override.checks.update(
|
619
560
|
included_check_names=included_check_names,
|
620
561
|
excluded_check_names=excluded_check_names,
|
621
|
-
positive_data_acceptance_allowed_statuses=positive_data_acceptance_allowed_statuses,
|
622
|
-
missing_required_header_allowed_statuses=missing_required_header_allowed_statuses,
|
623
|
-
negative_data_rejection_allowed_statuses=negative_data_rejection_allowed_statuses,
|
624
562
|
max_response_time=max_response_time,
|
625
|
-
)
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
# Use the same seed for all tests unless `derandomize=True` is used
|
640
|
-
seed: int | None
|
641
|
-
if generation_seed is None and not generation_deterministic:
|
642
|
-
seed = Random().getrandbits(128)
|
643
|
-
else:
|
644
|
-
seed = generation_seed
|
645
|
-
|
646
|
-
phases_ = [PhaseName.PROBING] + [PhaseName.from_str(phase) for phase in phases]
|
563
|
+
)
|
564
|
+
config.projects.override.generation.update(
|
565
|
+
modes=generation_modes,
|
566
|
+
max_examples=generation_max_examples,
|
567
|
+
no_shrink=generation_no_shrink,
|
568
|
+
maximize=generation_maximize,
|
569
|
+
deterministic=generation_deterministic,
|
570
|
+
database=generation_database,
|
571
|
+
unique_inputs=generation_unique_inputs,
|
572
|
+
allow_x00=generation_allow_x00,
|
573
|
+
graphql_allow_null=generation_graphql_allow_null,
|
574
|
+
with_security_parameters=generation_with_security_parameters,
|
575
|
+
codec=generation_codec,
|
576
|
+
)
|
647
577
|
|
648
|
-
|
649
|
-
location=
|
650
|
-
base_url=base_url,
|
651
|
-
engine=EngineConfig(
|
652
|
-
execution=ExecutionConfig(
|
653
|
-
phases=phases_,
|
654
|
-
checks=selected_checks,
|
655
|
-
targets=TARGETS.get_by_names(generation_maximize or []),
|
656
|
-
hypothesis_settings=prepare_settings(
|
657
|
-
database=generation_database,
|
658
|
-
derandomize=generation_deterministic,
|
659
|
-
max_examples=generation_max_examples,
|
660
|
-
phases=_hypothesis_phases,
|
661
|
-
suppress_health_check=_hypothesis_suppress_health_check,
|
662
|
-
),
|
663
|
-
generation=GenerationConfig(
|
664
|
-
modes=list(generation_modes),
|
665
|
-
allow_x00=generation_allow_x00,
|
666
|
-
graphql_allow_null=generation_graphql_allow_null,
|
667
|
-
codec=generation_codec,
|
668
|
-
with_security_parameters=generation_with_security_parameters,
|
669
|
-
unexpected_methods=coverage_unexpected_methods,
|
670
|
-
),
|
671
|
-
max_failures=max_failures,
|
672
|
-
continue_on_failure=continue_on_failure,
|
673
|
-
unique_inputs=generation_unique_inputs,
|
674
|
-
seed=seed,
|
675
|
-
workers_num=workers_num,
|
676
|
-
),
|
677
|
-
network=NetworkConfig(
|
678
|
-
auth=auth,
|
679
|
-
headers=headers,
|
680
|
-
timeout=request_timeout,
|
681
|
-
tls_verify=request_tls_verify,
|
682
|
-
proxy=request_proxy,
|
683
|
-
cert=(request_cert, request_cert_key)
|
684
|
-
if request_cert is not None and request_cert_key is not None
|
685
|
-
else request_cert,
|
686
|
-
),
|
687
|
-
override=override,
|
688
|
-
checks_config=checks_config,
|
689
|
-
),
|
578
|
+
executor.execute(
|
579
|
+
location=location,
|
690
580
|
filter_set=filter_set,
|
691
|
-
|
692
|
-
|
693
|
-
output=OutputConfig(sanitize=output_sanitize, truncate=output_truncate),
|
694
|
-
report=report_config,
|
581
|
+
# We don't the project yet, so pass the default config
|
582
|
+
config=config.projects.get_default(),
|
695
583
|
args=ctx.args,
|
696
584
|
params=ctx.params,
|
697
585
|
)
|
698
|
-
executor.execute(config)
|
@@ -3,8 +3,8 @@ from __future__ import annotations
|
|
3
3
|
from dataclasses import dataclass, field
|
4
4
|
from typing import TYPE_CHECKING, Generator
|
5
5
|
|
6
|
+
from schemathesis.config import ProjectConfig
|
6
7
|
from schemathesis.core.failures import Failure
|
7
|
-
from schemathesis.core.output import OutputConfig
|
8
8
|
from schemathesis.core.result import Err, Ok
|
9
9
|
from schemathesis.core.transforms import UNRESOLVABLE
|
10
10
|
from schemathesis.core.transport import Response
|
@@ -176,12 +176,11 @@ class GroupedFailures:
|
|
176
176
|
class ExecutionContext:
|
177
177
|
"""Storage for the current context of the execution."""
|
178
178
|
|
179
|
+
config: ProjectConfig
|
179
180
|
statistic: Statistic = field(default_factory=Statistic)
|
180
181
|
exit_code: int = 0
|
181
|
-
output_config: OutputConfig = field(default_factory=OutputConfig)
|
182
182
|
initialization_lines: list[str | Generator[str, None, None]] = field(default_factory=list)
|
183
183
|
summary_lines: list[str | Generator[str, None, None]] = field(default_factory=list)
|
184
|
-
seed: int | None = None
|
185
184
|
|
186
185
|
def add_initialization_line(self, line: str | Generator[str, None, None]) -> None:
|
187
186
|
self.initialization_lines.append(line)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import time
|
2
2
|
import uuid
|
3
3
|
|
4
|
+
from schemathesis.config import ProjectConfig
|
4
5
|
from schemathesis.core import Specification
|
5
6
|
from schemathesis.engine import events
|
6
7
|
from schemathesis.schemas import ApiStatistic
|
@@ -26,6 +27,7 @@ class LoadingFinished(events.EngineEvent):
|
|
26
27
|
"specification",
|
27
28
|
"statistic",
|
28
29
|
"schema",
|
30
|
+
"config",
|
29
31
|
)
|
30
32
|
|
31
33
|
def __init__(
|
@@ -38,6 +40,7 @@ class LoadingFinished(events.EngineEvent):
|
|
38
40
|
specification: Specification,
|
39
41
|
statistic: ApiStatistic,
|
40
42
|
schema: dict,
|
43
|
+
config: ProjectConfig,
|
41
44
|
) -> None:
|
42
45
|
self.id = uuid.uuid4()
|
43
46
|
self.timestamp = time.time()
|
@@ -48,3 +51,4 @@ class LoadingFinished(events.EngineEvent):
|
|
48
51
|
self.statistic = statistic
|
49
52
|
self.schema = schema
|
50
53
|
self.base_path = base_path
|
54
|
+
self.config = config
|