Skip to content

Commit 99e22b4

Browse files
committed
feat: add utility to check V2 and V3 compatibility
1 parent eeda50e commit 99e22b4

File tree

4 files changed

+138
-0
lines changed

4 files changed

+138
-0
lines changed

deepaas/api/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ def get_fastapi_app(
9999
response_model=responses.VersionsAndLinks,
100100
)
101101

102+
# Add a redirect from the old swagger.json to the new openapi.json
103+
APP.add_api_route(
104+
f"{base_path}/swagger.json",
105+
APP.openapi,
106+
methods=["GET"],
107+
summary="Get OpenAPI schema",
108+
tags=["version"],
109+
)
110+
102111
return APP
103112

104113

deepaas/cmd/deepaas_test_v2_v3.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
# Copyright 2018 Spanish National Research Council (CSIC)
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7+
# not use this file except in compliance with the License. You may obtain
8+
# a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15+
# License for the specific language governing permissions and limitations
16+
# under the License.
17+
18+
import argparse
19+
import requests
20+
21+
parser = argparse.ArgumentParser(
22+
description="DEEPaaS API v2 to v3 migration test script"
23+
)
24+
parser.add_argument(
25+
"--old-api-base-url",
26+
default="http://127.0.0.1:5000",
27+
help="Base URL of the old API",
28+
)
29+
parser.add_argument(
30+
"--new-api-base-url",
31+
default="http://127.0.0.1:5001",
32+
help="Base URL of the new API",
33+
)
34+
parser.add_argument(
35+
"--model-name",
36+
default="demo_app",
37+
help="Name of the model to test. To make testing easier, you should provide "
38+
"the name of the model you want to test.",
39+
)
40+
41+
args = parser.parse_args()
42+
43+
OLD_API_BASE_URL = args.old_api_base_url
44+
NEW_API_BASE_URL = args.new_api_base_url
45+
MODEL_NAME = args.model_name
46+
47+
48+
def get_openapi_spec(base_url):
49+
"""Retrieve the OpenAPI spec from the given base URL."""
50+
51+
response = requests.get(f"{base_url}/swagger.json", timeout=5)
52+
response.raise_for_status() # Raise an error for bad responses
53+
return response.json()
54+
55+
56+
def compare_endpoints(old_spec, new_spec):
57+
"""Compare endpoints in both OpenAPI specs.
58+
59+
This method ignoring methods that have been removed.
60+
"""
61+
old_paths = set(old_spec['paths'].keys())
62+
new_paths = set(new_spec['paths'].keys())
63+
64+
removed_paths = [f'/v2/models/{MODEL_NAME}/train']
65+
for path in removed_paths:
66+
old_paths.discard(path)
67+
68+
# Find paths that are in new but not in old
69+
missing_in_old = new_paths - old_paths
70+
71+
if missing_in_old:
72+
print("The following endpoints are missing in the old API:")
73+
for path in missing_in_old:
74+
print(f" - {path}")
75+
76+
# Check if all old paths (except removed) are in the new API
77+
missing_in_new = old_paths - new_paths
78+
79+
if missing_in_new:
80+
print("The following endpoints are missing in the new API:")
81+
for path in missing_in_new:
82+
print(f" - {path}")
83+
84+
return old_paths, new_paths
85+
86+
87+
def test_endpoint(old_url, new_url, method, endpoint):
88+
"""Test both endpoints and check if responses are equivalent."""
89+
90+
old_response = requests.request(method, old_url + endpoint)
91+
new_response = requests.request(method, new_url + endpoint)
92+
93+
assert old_response.status_code == new_response.status_code, ( # nosec
94+
f"Status code mismatch for {method} {endpoint}: "
95+
f"Old: {old_response.status_code}, New: {new_response.status_code}"
96+
)
97+
98+
old_data = old_response.json()
99+
new_data = new_response.json()
100+
101+
assert old_data == new_data, ( # nosec
102+
f"Response mismatch for {method} {endpoint}: Old: {old_data}, New: {new_data}"
103+
)
104+
105+
106+
def main():
107+
"""Main function to test the API endpoints."""
108+
109+
# Retrieve OpenAPI specifications
110+
old_openapi_spec = get_openapi_spec(OLD_API_BASE_URL)
111+
new_openapi_spec = get_openapi_spec(NEW_API_BASE_URL)
112+
113+
old_paths, new_paths = compare_endpoints(old_openapi_spec, new_openapi_spec)
114+
115+
# Testing the endpoints
116+
for endpoint in old_paths.intersection(new_paths):
117+
# We will loop through all HTTP methods available in the old API
118+
for method in ['GET', 'POST', 'PUT', 'DELETE']:
119+
try:
120+
test_endpoint(OLD_API_BASE_URL, NEW_API_BASE_URL, method, endpoint)
121+
print(f"Test passed for {method} {endpoint}")
122+
except Exception as e:
123+
print(f"Test failed for {method} {endpoint}: {e}")
124+
125+
126+
if __name__ == "__main__":
127+
main()

deepaas/model/v2/wrapper.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import contextlib
2020
import functools
2121
import io
22+
2223
# import os
2324
# import tempfile
2425

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ classifiers = [
4141
[tool.poetry.scripts]
4242
deepaas-run = "deepaas.cmd.run:main"
4343
deepaas-cli = "deepaas.cmd.cli:main"
44+
deepaas-test-v2-v3 = "deepaas.cmd.deepaas_test_v2_v3:main"
4445

4546
[tool.poetry.plugins] # Optional super table
4647

0 commit comments

Comments
 (0)