Skip to content

Commit b4c437d

Browse files
authored
ci: migration 09_http_handler to pytest (#18714)
1 parent 1cf3d94 commit b4c437d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+716
-404
lines changed

.github/actions/test_compat_client_cluster/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@ runs:
5454

5555
- name: Run test
5656
shell: bash
57-
run: nox -f tests/nox/noxfile.py
57+
run: nox -f tests/nox/noxfile.py -s python_client java_client
5858
env:
5959
JDBC_MAIN_VER: ${{env.JDBC_MAIN_VER}}

.github/actions/test_stateful_cluster_linux/action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ runs:
1313
shell: bash
1414
run: |
1515
./scripts/ci/ci-run-stateful-tests-cluster-minio.sh
16+
17+
- uses: wntrblm/[email protected]
18+
- name: Run nox test
19+
shell: bash
20+
run: nox -f tests/nox/noxfile.py -s test_suites -- suites/1_stateful

.github/actions/test_stateful_standalone_linux/action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ runs:
1313
shell: bash
1414
run: |
1515
./scripts/ci/ci-run-stateful-tests-standalone-minio.sh
16+
17+
- uses: wntrblm/[email protected]
18+
- name: Run nox test
19+
shell: bash
20+
run: nox -f tests/nox/noxfile.py -s test_suites -- suites/1_stateful

tests/nox/noxfile.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,10 @@ def run_jdbc_test(session, driver_version, main_version):
5555
external=True,
5656
env=env,
5757
)
58+
59+
60+
@nox.session
61+
def test_suites(session):
62+
session.install("pytest", "requests", "pytest-asyncio")
63+
# Usage: nox -s test_suites -- suites/1_stateful/09_http_handler/test_09_0007_session.py::test_session
64+
session.run("pytest", *session.posargs)

tests/nox/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[tool.pytest.ini_options]
22
addopts = "-s -vv"
3+
testpaths = ["suites"]

tests/suites/1_stateful/09_http_handler/09_0008_forward.result renamed to tests/nox/suites/1_stateful/09_http_handler/__init__.py

File renamed without changes.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import requests
2+
3+
# Define the URLs and credentials
4+
query_url = "http://localhost:8000/v1/query"
5+
auth = ("root", "")
6+
7+
8+
def execute_sql(sql):
9+
"""Execute SQL query via HTTP API"""
10+
payload = {"sql": sql, "pagination": {"wait_time_secs": 3}}
11+
response = requests.post(
12+
query_url, auth=auth, headers={"Content-Type": "application/json"}, json=payload
13+
)
14+
return response.json()
15+
16+
17+
def test_invalid_utf8():
18+
# Setup: create table and insert invalid UTF-8 data
19+
assert execute_sql("drop table if exists t1")["error"] == None
20+
assert execute_sql("create table t1(a varchar)")["error"] == None
21+
assert execute_sql("insert INTO t1 VALUES(FROM_BASE64('0Aw='))")["error"] == {
22+
"code": 1006,
23+
"message": "invalid utf8 sequence while evaluating function `to_string(D00C)` in expr `CAST(from_hex('D00C')::string AS String NULL)`",
24+
}
25+
26+
# Query the table
27+
assert execute_sql("select * from t1")["data"] == []
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import requests
2+
import json
3+
4+
5+
# Define the URLs and credentials
6+
query_url = "http://localhost:8000/v1/query"
7+
auth = ("root", "")
8+
9+
10+
def execute_query(payload_data):
11+
"""Execute query with custom payload data"""
12+
response = requests.post(
13+
query_url,
14+
auth=auth,
15+
headers={"Content-Type": "application/json"},
16+
data=payload_data,
17+
)
18+
return response.json()
19+
20+
21+
def test_json_response_errors():
22+
# Test 1: Invalid SQL query - select non-existent column
23+
result1 = execute_query('{"sql": "select a", "pagination": { "wait_time_secs": 5}}')
24+
assert result1.get("state", "Unknown") == "Failed"
25+
assert result1["error"] == json.loads(
26+
"""{"code": 1065, "message": "error: \\n --> SQL:1:8\\n |\\n1 | select a\\n | ^ column a doesn't exist\\n\\n"}"""
27+
)
28+
29+
# Test 2: Malformed JSON - missing quote before sql key
30+
result2 = execute_query(
31+
'{sql": "select * from tx", "pagination": { "wait_time_secs": 2}}'
32+
)
33+
assert result2 == json.loads(
34+
'{"error": {"code": 400, "message": "parse error: key must be a string at line 1 column 2"}}'
35+
)
36+
37+
# Test 3: Invalid endpoint URL
38+
response3 = requests.post(
39+
"http://localhost:8000/v1/querq/", # Note: wrong endpoint
40+
auth=auth,
41+
headers={"Content-Type": "application/json"},
42+
data='{"sql": "select * from tx", "pagination": { "wait_time_secs": 2}}',
43+
)
44+
assert response3.json() == json.loads(
45+
'{"error": {"code": 404, "message": "not found"}}'
46+
)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import requests
2+
import json
3+
from suites.utils import comparison_output
4+
5+
# Define the URLs and credentials
6+
query_url = "http://localhost:8000/v1/query"
7+
auth = ("root", "")
8+
9+
10+
def execute_query(sql):
11+
"""Execute SQL query via HTTP API"""
12+
payload = {"sql": sql, "pagination": {"wait_time_secs": 5}}
13+
response = requests.post(
14+
query_url, auth=auth, headers={"Content-Type": "application/json"}, json=payload
15+
)
16+
return response.json()
17+
18+
19+
@comparison_output(
20+
""">>>> create or replace table t_09_0002 (a int)
21+
<<<<
22+
"Succeeded"
23+
null
24+
"Succeeded"
25+
null
26+
"Succeeded"
27+
null
28+
"Succeeded"
29+
null"""
30+
)
31+
def test_sql_ends_with_semicolon():
32+
# Create table
33+
assert execute_query("create or replace table t_09_0002 (a int)")["error"] == None
34+
print(">>>> create or replace table t_09_0002 (a int)")
35+
print("<<<<")
36+
37+
# Test INSERT statements with semicolons
38+
queries = [
39+
"insert into t_09_0002 from @~/not_exist file_format=(type=csv);",
40+
"insert into t_09_0002 select 1;",
41+
"insert into t_09_0002 values (1);",
42+
"select 1;",
43+
]
44+
45+
for query in queries:
46+
result = execute_query(query)
47+
print(f'"{result.get("state", "Unknown")}"')
48+
print(json.dumps(result["error"]))
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import requests
2+
import os
3+
4+
5+
# Define the URLs and credentials
6+
query_url = "http://localhost:8000/v1/query"
7+
upload_url = "http://localhost:8000/v1/upload_to_stage"
8+
auth = ("root", "")
9+
10+
11+
def execute_sql(sql):
12+
"""Execute SQL query via HTTP API"""
13+
payload = {"sql": sql, "pagination": {"wait_time_secs": 6}}
14+
response = requests.post(
15+
query_url, auth=auth, headers={"Content-Type": "application/json"}, json=payload
16+
)
17+
return response.json()
18+
19+
20+
def upload_to_stage(stage_name, file_path):
21+
"""Upload file to stage"""
22+
with open(file_path, "rb") as f:
23+
files = {"upload": f}
24+
response = requests.put(
25+
upload_url,
26+
auth=auth,
27+
headers={"x-databend-stage-name": stage_name},
28+
files=files,
29+
)
30+
return response.json()
31+
32+
33+
def test_error_detail():
34+
# Setup: drop existing table and stage
35+
assert execute_sql("drop table if exists products")["error"] == None
36+
assert execute_sql("drop stage if exists s1")["error"] == None
37+
38+
# Create stage and table
39+
assert execute_sql("CREATE STAGE s1 FILE_FORMAT = (TYPE = CSV)")["error"] == None
40+
assert execute_sql("remove @s1")["error"] == None
41+
assert (
42+
execute_sql("create table products (id int, name string, description string)")[
43+
"error"
44+
]
45+
== None
46+
)
47+
48+
# Upload CSV file to stage (select.csv has 2 columns, table has 3 columns)
49+
csv_file_path = os.path.join(
50+
os.path.dirname(__file__), "../../../../data/csv/select.csv"
51+
)
52+
upload_result = upload_to_stage("s1", csv_file_path)
53+
assert not "data" in upload_result
54+
55+
# Try to copy from stage to table - should fail with column mismatch error
56+
copy_result = execute_sql(
57+
"copy /*+ set_var(enable_distributed_copy_into = 0) */ into products (id, name, description) from @s1/"
58+
)
59+
60+
assert copy_result["error"] == {
61+
"code": 1046,
62+
"message": "Number of columns in file (2) does not match that of the corresponding table (3)",
63+
"detail": "at file 'select.csv', line 1",
64+
}
65+
66+
# Cleanup
67+
assert execute_sql("drop table if exists products")["error"] == None
68+
assert execute_sql("drop stage if exists s1")["error"] == None

0 commit comments

Comments
 (0)