import pytest
import tempfile
import shutil
from pathlib import Path
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'apexbase', 'python'))
try:
from apexbase import ApexClient
except ImportError as e:
pytest.skip(f"ApexBase not available: {e}", allow_module_level=True)
try:
import pandas as pd
PANDAS_AVAILABLE = True
except ImportError:
PANDAS_AVAILABLE = False
@pytest.fixture
def olap_client():
tmp = tempfile.mkdtemp()
client = ApexClient(os.path.join(tmp, "olap_test"))
client.create_table("default")
cities = ["Beijing", "Shanghai", "Shenzhen", "Guangzhou", "Hangzhou",
"Chengdu", "Wuhan", "Nanjing", "Tianjin", "Xian"]
depts = ["Engineering", "Sales", "Marketing", "HR", "Finance"]
rows = []
for i in range(5000):
rows.append({
"emp_id": i + 1,
"age": 22 + (i % 40),
"years": i % 20,
"salary": 50000.0 + (i % 100) * 1000.0,
"city": cities[i % 10],
"dept": depts[i % 5],
"is_manager": i % 10 == 0,
})
client.store(rows)
yield client
shutil.rmtree(tmp, ignore_errors=True)
class TestOlapFullScan:
def test_select_star(self, olap_client):
result = olap_client.execute("SELECT * FROM default")
assert len(result) == 5000
def test_schema_columns(self, olap_client):
result = olap_client.execute("SELECT * FROM default LIMIT 1")
assert len(result) == 1
row = result[0]
assert "emp_id" in row
assert "salary" in row
assert "city" in row
assert "dept" in row
def test_row_count(self, olap_client):
result = olap_client.execute("SELECT COUNT(*) as cnt FROM default")
assert result[0]["cnt"] == 5000
class TestOlapAggregation:
def test_count_star(self, olap_client):
result = olap_client.execute("SELECT COUNT(*) as cnt FROM default")
assert result[0]["cnt"] == 5000
def test_sum(self, olap_client):
result = olap_client.execute("SELECT SUM(salary) as total FROM default")
expected = 50 * 9950000.0
assert abs(result[0]["total"] - expected) < 1.0
def test_avg(self, olap_client):
result = olap_client.execute("SELECT AVG(salary) as avg_sal FROM default")
assert abs(result[0]["avg_sal"] - 99500.0) < 1.0
def test_min(self, olap_client):
result = olap_client.execute("SELECT MIN(salary) as min_sal FROM default")
assert abs(result[0]["min_sal"] - 50000.0) < 1.0
def test_max(self, olap_client):
result = olap_client.execute("SELECT MAX(salary) as max_sal FROM default")
assert abs(result[0]["max_sal"] - 149000.0) < 1.0
def test_count_distinct(self, olap_client):
result = olap_client.execute("SELECT COUNT(DISTINCT city) as n FROM default")
assert result[0]["n"] == 10
def test_count_distinct_dept(self, olap_client):
result = olap_client.execute("SELECT COUNT(DISTINCT dept) as n FROM default")
assert result[0]["n"] == 5
class TestOlapGroupBy:
def test_group_by_single_col(self, olap_client):
result = olap_client.execute(
"SELECT dept, COUNT(*) as cnt FROM default GROUP BY dept"
)
assert len(result) == 5
for row in result:
assert row["cnt"] == 1000
def test_group_by_with_avg(self, olap_client):
result = olap_client.execute(
"SELECT city, AVG(salary) as avg_sal FROM default GROUP BY city"
)
assert len(result) == 10
for row in result:
assert row["avg_sal"] > 0
def test_group_by_two_cols(self, olap_client):
result = olap_client.execute(
"SELECT city, dept, COUNT(*) as cnt FROM default GROUP BY city, dept"
)
total = sum(r["cnt"] for r in result)
assert total == 5000
def test_group_by_with_sum(self, olap_client):
result = olap_client.execute(
"SELECT dept, SUM(salary) as total FROM default GROUP BY dept ORDER BY total DESC"
)
assert len(result) == 5
totals = [r["total"] for r in result]
for i in range(1, len(totals)):
assert totals[i - 1] >= totals[i]
class TestOlapHaving:
def test_having_avg(self, olap_client):
result = olap_client.execute(
"SELECT city, AVG(salary) as avg_sal FROM default GROUP BY city "
"HAVING AVG(salary) > 99000"
)
assert len(result) > 0
for row in result:
assert row["avg_sal"] > 99000
def test_having_count(self, olap_client):
result = olap_client.execute(
"SELECT dept, COUNT(*) as cnt FROM default GROUP BY dept HAVING COUNT(*) >= 1000"
)
assert len(result) == 5
class TestOlapOrderBy:
def test_order_by_desc_limit(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default ORDER BY salary DESC LIMIT 10"
)
assert len(result) == 10
salaries = [r["salary"] for r in result]
for i in range(1, len(salaries)):
assert salaries[i - 1] >= salaries[i]
assert abs(salaries[0] - 149000.0) < 1.0
def test_order_by_asc_limit(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default ORDER BY age ASC LIMIT 5"
)
assert len(result) == 5
for row in result:
assert row["age"] == 22
class TestOlapWhereFilter:
def test_between(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default WHERE age BETWEEN 30 AND 35 LIMIT 100"
)
assert 0 < len(result) <= 100
for row in result:
assert 30 <= row["age"] <= 35
def test_in_list(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default WHERE city IN ('Beijing', 'Shanghai')"
)
assert len(result) == 1000 for row in result:
assert row["city"] in ("Beijing", "Shanghai")
def test_like_pattern(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default WHERE city LIKE 'Sh%'"
)
assert len(result) == 1000 for row in result:
assert row["city"].startswith("Sh")
def test_string_eq(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default WHERE city = 'Beijing'"
)
assert len(result) == 500
def test_string_eq_with_limit(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default WHERE city = 'Beijing' LIMIT 10"
)
assert len(result) == 10
for row in result:
assert row["city"] == "Beijing"
def test_boolean_filter_true(self, olap_client):
result = olap_client.execute(
"SELECT COUNT(*) as cnt FROM default WHERE is_manager = true"
)
assert result[0]["cnt"] == 500
def test_boolean_filter_false(self, olap_client):
result = olap_client.execute(
"SELECT COUNT(*) as cnt FROM default WHERE is_manager = false"
)
assert result[0]["cnt"] == 4500
class TestOlapMultiCondition:
def test_and_condition(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default WHERE city = 'Beijing' AND age > 50"
)
assert len(result) > 0
for row in result:
assert row["city"] == "Beijing"
assert row["age"] > 50
def test_or_condition(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default WHERE age < 23 OR age > 60"
)
assert len(result) > 0
for row in result:
assert row["age"] < 23 or row["age"] > 60
class TestOlapProjection:
def test_select_specific_columns(self, olap_client):
result = olap_client.execute(
"SELECT emp_id, salary FROM default LIMIT 10"
)
assert len(result) == 10
for row in result:
assert "emp_id" in row
assert "salary" in row
@pytest.mark.skipif(not PANDAS_AVAILABLE, reason="pandas not available")
def test_to_pandas(self, olap_client):
result = olap_client.execute("SELECT * FROM default")
df = result.to_pandas()
assert len(df) == 5000
assert "salary" in df.columns
assert "city" in df.columns
@pytest.mark.skipif(not PANDAS_AVAILABLE, reason="pandas not available")
def test_to_pandas_with_filter(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default WHERE city = 'Shanghai'"
)
df = result.to_pandas()
assert len(df) == 500
assert all(df["city"] == "Shanghai")
class TestOlapComplexQuery:
def test_filter_group_order(self, olap_client):
result = olap_client.execute(
"SELECT dept, COUNT(*) as cnt, AVG(salary) as avg_sal FROM default "
"WHERE city = 'Beijing' GROUP BY dept ORDER BY avg_sal DESC"
)
assert len(result) >= 1
total = sum(r["cnt"] for r in result)
assert total == 500
def test_group_by_order_by_limit(self, olap_client):
result = olap_client.execute(
"SELECT dept, SUM(salary) as total FROM default "
"GROUP BY dept ORDER BY total DESC"
)
assert len(result) == 5
totals = [r["total"] for r in result]
for i in range(1, len(totals)):
assert totals[i - 1] >= totals[i]
class TestOlapEdgeCases:
def test_empty_result(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default WHERE city = 'NonExistent'"
)
assert len(result) == 0
def test_count_empty_result(self, olap_client):
result = olap_client.execute(
"SELECT COUNT(*) as cnt FROM default WHERE city = 'NonExistent'"
)
assert result[0]["cnt"] == 0
def test_limit_larger_than_data(self, olap_client):
result = olap_client.execute(
"SELECT * FROM default LIMIT 99999"
)
assert len(result) == 5000
def test_retrieve_all(self, olap_client):
all_rows = olap_client.retrieve_all()
assert len(all_rows) == 5000