Commit d5c1f84a authored by Luc Yriarte's avatar Luc Yriarte
Browse files

Merge branch 'basic-apis-v2' into 'master'

Basic apis v2

See merge request !199
parents 0933cca7 886d99eb
Pipeline #59039 passed with stages
in 36 minutes and 23 seconds
......@@ -164,10 +164,13 @@ basic_dependencies = [
]
wdms_app.include_router(probes.router)
wdms_app.include_router(about.router, prefix=DDMS_V2_PATH)
wdms_app.include_router(about.router, tags=["Wellbore DDMS"])
# hidden from swagger but maintained for backward compatibility with /ddms/v2 APIs
wdms_app.include_router(about.router, prefix=DDMS_V2_PATH, tags=["Wellbore DDMS"], include_in_schema=False)
wdms_app.include_router(ddms_v2.router, prefix=DDMS_V2_PATH, tags=["Wellbore DDMS"], include_in_schema=False)
ddms_v2_routes_groups = [
(ddms_v2, "Wellbore DDMS"),
(well_ddms_v2, "Well"),
(wellbore_ddms_v2, "Wellbore"),
(logset_ddms_v2, "Logset"),
......
......@@ -32,6 +32,7 @@ spec:
- operation:
notPaths:
- {{ include "os-wellbore-ddms.prefix" . }}/
- {{ include "os-wellbore-ddms.prefix" . }}/about
- {{ include "os-wellbore-ddms.prefix" . }}/ddms/v2/about
- {{ include "os-wellbore-ddms.prefix" . }}/docs
- {{ include "os-wellbore-ddms.prefix" . }}/openapi.json
......
......@@ -23,22 +23,6 @@
"title": "AboutResponse",
"type": "object"
},
"AboutResponseUser": {
"additionalProperties": false,
"description": "The base model forbids fields which are not declared initially in the pydantic model",
"properties": {
"email": {
"title": "Email",
"type": "string"
},
"tenant": {
"title": "Tenant",
"type": "string"
}
},
"title": "AboutResponseUser",
"type": "object"
},
"AbstractAccessControlList100": {
"additionalProperties": false,
"description": "The access control tags associated with this entity.",
......@@ -3406,35 +3390,6 @@
"title": "UpdateSessionStateValue",
"type": "string"
},
"V1AboutResponse": {
"additionalProperties": false,
"description": "The base model forbids fields which are not declared initially in the pydantic model",
"properties": {
"dmsInfo": {
"$ref": "#/components/schemas/V1DmsInfo"
},
"user": {
"$ref": "#/components/schemas/AboutResponseUser"
}
},
"title": "V1AboutResponse",
"type": "object"
},
"V1DmsInfo": {
"additionalProperties": false,
"description": "The base model forbids fields which are not declared initially in the pydantic model",
"properties": {
"kinds": {
"items": {
"type": "string"
},
"title": "Kinds",
"type": "array"
}
},
"title": "V1DmsInfo",
"type": "object"
},
"ValidationError": {
"properties": {
"loc": {
......@@ -8494,6 +8449,27 @@
},
"openapi": "3.0.2",
"paths": {
"/about": {
"get": {
"operationId": "get_about_about_get",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AboutResponse"
}
}
},
"description": "Successful Response"
}
},
"summary": "Get About",
"tags": [
"Wellbore DDMS"
]
}
},
"/alpha/ddms/v2/logs/{record_id}/data": {
"get": {
"description": "Returns the data according to the specified query parameters. Multiple media types response are available (\"application/json\", text/csv\", \"application/x-parquet\"). The desired format can be specify in \"Accept\" header. The default is Parquet. When bulk statistics are requested using \"describe\" parameter, the response is always provided in JSON.\n<p>Required roles: 'users.datalake.viewers' or 'users.datalake.editors' or 'users.datalake.admins'.\n\"In addition, users must be a member of data groups to access the data.</p>\n",
......@@ -11119,24 +11095,6 @@
]
}
},
"/ddms/v2/about": {
"get": {
"operationId": "get_about_ddms_v2_about_get",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AboutResponse"
}
}
},
"description": "Successful Response"
}
},
"summary": "Get About"
}
},
"/ddms/v2/dipsets": {
"post": {
"description": "<p>Required roles: 'users.datalake.editors' or 'users.datalake.admins'.</p>",
......@@ -13961,56 +13919,6 @@
]
}
},
"/ddms/v2/status": {
"get": {
"operationId": "about_ddms_v2_status_get",
"parameters": [
{
"description": "identifier of the data partition to query",
"in": "header",
"name": "data-partition-id",
"required": false,
"schema": {
"description": "identifier of the data partition to query",
"minLength": 1,
"title": "data partition id",
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V1AboutResponse"
}
}
},
"description": "Successful Response"
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
"description": "Validation Error"
}
},
"security": [
{
"HTTPBearer": []
}
],
"summary": "Get the status of the service",
"tags": [
"Wellbore DDMS"
]
}
},
"/ddms/v2/trajectories": {
"post": {
"description": "<p>Required roles: 'users.datalake.editors' or 'users.datalake.admins'.</p>",
......@@ -14805,29 +14713,6 @@
]
}
},
"/ddms/v2/version": {
"get": {
"operationId": "get_version_ddms_v2_version_get",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VersionDetailsResponse"
}
}
},
"description": "Successful Response"
}
},
"security": [
{
"HTTPBearer": []
}
],
"summary": "Get Version"
}
},
"/ddms/v2/wellbores": {
"post": {
"description": "<p>Required roles: 'users.datalake.editors' or 'users.datalake.admins'.</p>",
......@@ -19599,6 +19484,32 @@
"log-recognition"
]
}
},
"/version": {
"get": {
"operationId": "get_version_version_get",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VersionDetailsResponse"
}
}
},
"description": "Successful Response"
}
},
"security": [
{
"HTTPBearer": []
}
],
"summary": "Get Version",
"tags": [
"Wellbore DDMS"
]
}
}
}
}
\ No newline at end of file
......@@ -19,7 +19,7 @@ def build_request_about() -> RequestRunner:
rq_proto = Request(
name='about',
method='GET',
url='{{base_url}}/ddms/v2/about',
url='{{base_url}}/about',
headers={
'accept': 'application/json',
'Connection': '{{header_connection}}',
......
......@@ -19,7 +19,7 @@ def build_request_version() -> RequestRunner:
rq_proto = Request(
name='version',
method='GET',
url='{{base_url}}/ddms/v2/version',
url='{{base_url}}/version',
headers={
'accept': 'application/json',
'Connection': '{{header_connection}}',
......
......@@ -19,19 +19,13 @@ import jwt
payload = {}
wellbore_api_group_prefix = 'ddms/v2'
def build_url(base_url: str, path: str):
return f"{base_url}/{wellbore_api_group_prefix}{path}"
@pytest.fixture
def skip_if_gcp_environment(base_url):
"""
In GCP environment there is no AuthorizationPolicy set. Certain tests may fail on GCP
and this fixture aims to skip a test case when targeted environment is GCP.
"""
response = requests.request("GET", build_url(base_url, "/about"), verify=False)
response = requests.request("GET", f"{base_url}/about", verify=False)
assert response.status_code == 200
about_response = response.json()
......@@ -41,7 +35,7 @@ def skip_if_gcp_environment(base_url):
# Test for expired token
def test_expired_token_returns_40X(base_url, check_cert, token):
url = build_url(base_url, "/about")
url = f"{base_url}/about"
token_expired = jwt.encode({"email":"nobody@example.com", "exp":datetime.datetime.utcnow() - datetime.timedelta(seconds=300)}, key="secret", algorithm="HS256")
headers = {
'Authorization': f"Bearer {token_expired}"
......@@ -59,7 +53,7 @@ def test_notoken_paths_returns_20X_docs(base_url, check_cert, token):
assert 'content-security-policy' in response.headers
# Test for no token on some paths where JWT token is NOT required due to the AuthorizationPolicy
@pytest.mark.parametrize("path", ["docs", "openapi.json", f"{wellbore_api_group_prefix}/about"])
@pytest.mark.parametrize("path", ["docs", "openapi.json", "about"])
def test_notoken_paths_returns_20X(base_url, check_cert, token, path):
url = f"{base_url}/{path}"
......@@ -71,7 +65,7 @@ def test_notoken_paths_returns_20X(base_url, check_cert, token, path):
@pytest.mark.parametrize("path", ["version", "nonExistingPath"])
def test_notoken_returns_40X(base_url, check_cert, token, skip_if_gcp_environment, path):
url = build_url(base_url, f"/{path}")
url = f"{base_url}/{path}"
headers = {}
response = requests.request("GET", url, headers=headers, data=payload, verify=check_cert)
assert response.status_code == 403
......@@ -80,7 +74,7 @@ def test_notoken_returns_40X(base_url, check_cert, token, skip_if_gcp_environmen
# Test for invalid token
def test_invalid_token_returns_40X(base_url, check_cert, token):
url = build_url(base_url, "/about")
url = f"{base_url}/about"
blank = {}
token_invalid = token[0:len(token) - 10]
headers = {
......@@ -93,7 +87,7 @@ def test_invalid_token_returns_40X(base_url, check_cert, token):
# Test for unauthorized issuer
def test_invalid_issuer_token_returns_40X(base_url, check_cert, token):
url = build_url(base_url, "/about")
url = f"{base_url}/about"
blank = {}
token_no_iss = jwt.encode({"email": "nobody@example.com"}, key="secret", algorithm="HS256")
headers = {
......
......@@ -23,6 +23,8 @@ from tests.unit.test_utils import ctx_fixture
# Initialize traces exporter in app, like it is in app's startup decorator
wdms_app.trace_exporter = traces.CombinedExporter(service_name='tested-ddms')
# parametrized for backward compatibility with /ddms/v2 APIs
PathPrefixParams = [DDMS_V2_PATH, '']
@pytest.fixture
def client(ctx_fixture):
......@@ -42,13 +44,13 @@ def client_with_authenticated_user():
wdms_app.dependency_overrides = {}
def build_url(path: str):
return DDMS_V2_PATH + path
def build_url(prefix: str, path: str):
return prefix + path
@pytest.mark.parametrize("path_prefix", PathPrefixParams)
def test_about_contains_build_n_version(client, path_prefix):
def test_about_contains_build_n_version(client):
response = client.get(build_url("/about"))
response = client.get(build_url(path_prefix, "/about"))
assert response.status_code == 200
response_json = response.json()
......@@ -56,27 +58,30 @@ def test_about_contains_build_n_version(client):
assert response_json['version']
@pytest.mark.parametrize("path_prefix", PathPrefixParams)
@pytest.mark.parametrize("cloud_provider", ['Azure', 'gcp', 'unknown', 'aws', None])
def test_about_with_cloud_provider(client, cloud_provider):
def test_about_with_cloud_provider(client, cloud_provider, path_prefix):
Config.cloud_provider.value = cloud_provider
response = client.get(build_url("/about"))
response = client.get(build_url(path_prefix, "/about"))
assert response.status_code == 200
json_response = response.json()
assert json_response['cloudEnvironment'] == cloud_provider
def test_version_requires_authentication(client):
response = client.get(build_url("/version"))
@pytest.mark.parametrize("path_prefix", PathPrefixParams)
def test_version_requires_authentication(client, path_prefix):
response = client.get(build_url(path_prefix, "/version"))
assert response.status_code == 403
def test_version_properly_read_details(client_with_authenticated_user, monkeypatch):
@pytest.mark.parametrize("path_prefix", PathPrefixParams)
def test_version_properly_read_details(client_with_authenticated_user, monkeypatch, path_prefix):
# override value of build details
Config.build_details.value = 'key1=value1; key2=value2'
response = client_with_authenticated_user.get(build_url("/version"))
response = client_with_authenticated_user.get(build_url(path_prefix, "/version"))
assert response.status_code == 200
response_json = response.json()
assert response_json['details']['key1'] == 'value1'
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment