Add tests for OAuth client and webhook notification handling
- Implement tests for `EbayOAuthClient` to verify authorization URL generation with configured scopes and token reuse logic. - Add tests for `WebhookChallengeHandler` to ensure correct SHA256 response generation and for `WebhookSignatureParser` to validate extraction of known fields from signature strings.
This commit is contained in:
commit
389d72a136
519 changed files with 99006 additions and 0 deletions
134
scripts/generate_clients.py
Normal file
134
scripts/generate_clients.py
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
GENERATED_ROOT = ROOT / "ebay_client" / "generated"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ApiSpec:
|
||||
name: str
|
||||
spec_path: Path
|
||||
output_path: Path
|
||||
project_name: str
|
||||
package_name: str
|
||||
|
||||
|
||||
API_SPECS = {
|
||||
"notification": ApiSpec(
|
||||
name="notification",
|
||||
spec_path=ROOT / "commerce_notification_v1_oas3.yaml",
|
||||
output_path=GENERATED_ROOT / "notification",
|
||||
project_name="ebay-notification-generated",
|
||||
package_name="notification_generated",
|
||||
),
|
||||
"inventory": ApiSpec(
|
||||
name="inventory",
|
||||
spec_path=ROOT / "sell_inventory_v1_oas3.yaml",
|
||||
output_path=GENERATED_ROOT / "inventory",
|
||||
project_name="ebay-inventory-generated",
|
||||
package_name="inventory_generated",
|
||||
),
|
||||
"fulfillment": ApiSpec(
|
||||
name="fulfillment",
|
||||
spec_path=ROOT / "sell_fulfillment_v1_oas3.yaml",
|
||||
output_path=GENERATED_ROOT / "fulfillment",
|
||||
project_name="ebay-fulfillment-generated",
|
||||
package_name="fulfillment_generated",
|
||||
),
|
||||
"account": ApiSpec(
|
||||
name="account",
|
||||
spec_path=ROOT / "sell_account_v1_oas3.yaml",
|
||||
output_path=GENERATED_ROOT / "account",
|
||||
project_name="ebay-account-generated",
|
||||
package_name="account_generated",
|
||||
),
|
||||
"feed": ApiSpec(
|
||||
name="feed",
|
||||
spec_path=ROOT / "sell_feed_v1_oas3.yaml",
|
||||
output_path=GENERATED_ROOT / "feed",
|
||||
project_name="ebay-feed-generated",
|
||||
package_name="feed_generated",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Generate isolated low-level clients from the eBay OpenAPI contracts.")
|
||||
parser.add_argument("--api", choices=sorted(API_SPECS), help="Generate only one API package.")
|
||||
parser.add_argument("--fail-on-warning", action="store_true", help="Fail if the generator emits warnings.")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def build_config(spec: ApiSpec) -> dict[str, object]:
|
||||
return {
|
||||
"project_name_override": spec.project_name,
|
||||
"package_name_override": spec.package_name,
|
||||
"field_prefix": "field_",
|
||||
"generate_all_tags": False,
|
||||
"http_timeout": 30,
|
||||
"literal_enums": False,
|
||||
"post_hooks": [],
|
||||
"use_path_prefixes_for_title_model_names": False,
|
||||
}
|
||||
|
||||
|
||||
def run_generation(spec: ApiSpec, *, fail_on_warning: bool) -> None:
|
||||
if not spec.spec_path.exists():
|
||||
raise FileNotFoundError(f"OpenAPI spec not found: {spec.spec_path}")
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix=f"ebay_{spec.name}_") as temp_dir_name:
|
||||
temp_dir = Path(temp_dir_name)
|
||||
config_path = temp_dir / "config.yaml"
|
||||
temp_output = temp_dir / "output"
|
||||
config_path.write_text(yaml.safe_dump(build_config(spec), sort_keys=True), encoding="utf-8")
|
||||
|
||||
command = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"openapi_python_client",
|
||||
"generate",
|
||||
"--path",
|
||||
str(spec.spec_path),
|
||||
"--meta",
|
||||
"none",
|
||||
"--overwrite",
|
||||
"--config",
|
||||
str(config_path),
|
||||
"--output-path",
|
||||
str(temp_output),
|
||||
]
|
||||
if fail_on_warning:
|
||||
command.append("--fail-on-warning")
|
||||
|
||||
subprocess.run(command, check=True, cwd=str(ROOT))
|
||||
|
||||
generated_package = temp_output / spec.package_name
|
||||
if not generated_package.exists():
|
||||
generated_package = temp_output
|
||||
if spec.output_path.exists():
|
||||
shutil.rmtree(spec.output_path)
|
||||
shutil.copytree(generated_package, spec.output_path)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
specs = [API_SPECS[args.api]] if args.api else [API_SPECS[name] for name in sorted(API_SPECS)]
|
||||
for spec in specs:
|
||||
print(f"Generating {spec.name} from {spec.spec_path.name} -> {spec.output_path}")
|
||||
run_generation(spec, fail_on_warning=args.fail_on_warning)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue