Skip to content

Commit 0036a22

Browse files
committed
More tests
1 parent 2e05f2f commit 0036a22

File tree

11 files changed

+183
-9
lines changed

11 files changed

+183
-9
lines changed

src/engines.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def __init__(self, database, table, num_layers=16,
140140
min_time=10, max_time=100, min_rows=10000, max_rows=1000000,
141141
min_bytes=10000000, max_bytes=100000000):
142142
self.database = database
143-
self.table = table
143+
self.table_name = table
144144
self.num_layers = num_layers
145145
self.min_time = min_time
146146
self.max_time = max_time
@@ -153,7 +153,7 @@ def __init__(self, database, table, num_layers=16,
153153
def get_params(self):
154154
return [
155155
self.database,
156-
self.table.name,
156+
self.table_name,
157157
self.num_layers,
158158
self.min_time,
159159
self.max_time,

tests/drivers/native/__init__.py

Whitespace-only changes.

tests/drivers/native/test_select.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from sqlalchemy import Column
2+
3+
from src import engines, types, Table
4+
from tests.session import native_session, mocked_engine
5+
from tests.testcase import BaseTestCase
6+
7+
8+
class SanityTestCase(BaseTestCase):
9+
session = native_session
10+
11+
def test_sanity(self):
12+
table = Table(
13+
't1', self.metadata(),
14+
Column('x', types.Int32, primary_key=True),
15+
engines.Memory()
16+
)
17+
18+
with mocked_engine(self.session) as engine:
19+
table.drop(if_exists=True)
20+
engine.assert_sql(['DROP TABLE IF EXISTS t1'])

tests/drivers/test_escaping.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
from decimal import Decimal
2+
from datetime import date
3+
14
from six import text_type
25
from sqlalchemy import literal
36

7+
from src.drivers.escaper import Escaper
48
from tests.session import session
59
from tests.testcase import BaseTestCase
610

@@ -14,4 +18,22 @@ def test_select_escaping(self):
1418
self.compile(session.query(literal('\t')), literal_binds=True),
1519
"SELECT '\t' AS param_1"
1620
)
17-
# TODO: test escaping \t, etc.
21+
22+
def test_escaper(self):
23+
e = Escaper()
24+
self.assertEqual(e.escape([None]), ['NULL'])
25+
self.assertEqual(e.escape([[123]]), [[123]])
26+
self.assertEqual(e.escape({'x': 'str'}), {'x': "'str'"})
27+
self.assertEqual(e.escape([Decimal('10')]), [10.0])
28+
self.assertEqual(e.escape([10.0]), [10.0])
29+
self.assertEqual(e.escape([date(2017, 1, 2)]), ["'2017-01-02'"])
30+
31+
with self.assertRaises(Exception) as ex:
32+
e.escape([object()])
33+
34+
self.assertIn('Unsupported object', text_type(ex.exception))
35+
36+
with self.assertRaises(Exception) as ex:
37+
e.escape('str')
38+
39+
self.assertIn('Unsupported param format', text_type(ex.exception))

tests/functions/test_extract.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@ def test_extract_day(self):
3434
self.compile(extract('day', get_date_column('x'))),
3535
'toDayOfMonth(x)'
3636
)
37+
38+
def test_extract_unknown(self):
39+
self.assertEqual(
40+
self.compile(extract('test', get_date_column('x'))),
41+
'x'
42+
)

tests/functions/test_if.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from sqlalchemy import literal, func, text
2+
3+
from tests.testcase import BaseTestCase
4+
5+
6+
class IfTestCase(BaseTestCase):
7+
def test_if(self):
8+
expression = func.if_(
9+
literal(1) > literal(2),
10+
text('a'),
11+
text('b'),
12+
)
13+
14+
self.assertEqual(
15+
self.compile(expression, literal_binds=True),
16+
'if(1 > 2, a, b)'
17+
)

tests/session.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,50 @@
1+
import re
2+
13
from sqlalchemy import create_engine
24
from sqlalchemy.dialects import registry
35

46
from src import make_session
57

68

79
registry.register("clickhouse", "src.drivers.http.base", "dialect")
10+
registry.register("clickhouse.native", "src.drivers.native.base", "dialect")
811

912
uri = 'clickhouse://default:@localhost:8123/default'
10-
1113
session = make_session(create_engine(uri))
14+
15+
native_uri = 'clickhouse+native://default:@localhost/default'
16+
native_session = make_session(create_engine(native_uri))
17+
18+
19+
class MockedEngine(object):
20+
def __init__(self, engine_session=None):
21+
self.buffer = buffer = []
22+
23+
engine_session = engine_session or session
24+
25+
self.dialect_cls = engine_session.bind.dialect
26+
self.prev_do_execute = self.dialect_cls.do_execute
27+
self.prev_do_executemany = self.dialect_cls.do_executemany
28+
29+
def do_executemany(cursor, statement, parameters, context=None):
30+
buffer.append(statement)
31+
32+
def do_execute(cursor, statement, parameters, context=None):
33+
buffer.append(statement)
34+
35+
self.dialect_cls.do_execute = do_execute
36+
self.dialect_cls.do_executemany = do_executemany
37+
38+
def assert_sql(self, stmts):
39+
recv = [re.sub(r'[\n\t]', '', str(s)) for s in self.buffer]
40+
assert recv == stmts, recv
41+
42+
def __enter__(self):
43+
return self
44+
45+
def __exit__(self, *exc_info):
46+
self.dialect_cls.do_execute = self.prev_do_execute
47+
self.dialect_cls.do_executemany = self.prev_do_executemany
48+
49+
50+
mocked_engine = MockedEngine

tests/test_compiler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ class MyEnum(enum.Enum):
4141
MyEnum = enum.Enum('MyEnum', data)
4242

4343
self.assertEqual(
44-
self.compile(types.Enum16(MyEnum)),
45-
"Enum16(' \\' t = ' = 1, 'test' = 2)"
44+
self.compile(types.Enum8(MyEnum)),
45+
"Enum8(' \\' t = ' = 1, 'test' = 2)"
4646
)

tests/test_ddl.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from src import types, engines, Table
55
from src.sql.ddl import DropTable
66
from tests.testcase import BaseTestCase
7+
from tests.session import mocked_engine
78

89

910
class DDLTestCase(BaseTestCase):
@@ -114,7 +115,7 @@ def test_create_table_nullable_nested_nullable(self):
114115
'ENGINE = Memory'
115116
)
116117

117-
def test_drop_table(self):
118+
def test_drop_table_clause(self):
118119
table = Table(
119120
't1', self.metadata(),
120121
Column('x', types.Int32, primary_key=True)
@@ -128,3 +129,13 @@ def test_drop_table(self):
128129
self.compile(DropTable(table, if_exists=True)),
129130
'DROP TABLE IF EXISTS t1'
130131
)
132+
133+
def test_table_drop(self):
134+
table = Table(
135+
't1', self.metadata(),
136+
Column('x', types.Int32, primary_key=True)
137+
)
138+
139+
with mocked_engine() as engine:
140+
table.drop(if_exists=True)
141+
engine.assert_sql(['DROP TABLE IF EXISTS t1'])

tests/test_engines.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class TestTable(base):
6161
')'
6262
)
6363

64-
def test_index_granularity(self):
64+
def test_merge_tree_index_granularity(self):
6565
base = get_declarative_base()
6666

6767
class TestTable(base):
@@ -90,3 +90,61 @@ def test_create_table_without_engine(self):
9090
self.compile(CreateTable(no_engine_table))
9191

9292
self.assertEqual(text_type(ex.exception), "No engine for table 't1'")
93+
94+
def test_collapsing_merge_tree(self):
95+
base = get_declarative_base()
96+
97+
class TestTable(base):
98+
date = Column(types.Date, primary_key=True)
99+
x = Column(types.Int32)
100+
y = Column(types.String)
101+
sign = Column(types.Int8)
102+
103+
__table_args__ = (
104+
engines.CollapsingMergeTree(date, (date, x), sign),
105+
)
106+
107+
self.assertEqual(
108+
self.compile(CreateTable(TestTable.__table__)),
109+
'CREATE TABLE test_table '
110+
'(date Date, x Int32, y String, sign Int8) '
111+
'ENGINE = CollapsingMergeTree(date, (date, x), 8192, sign)'
112+
)
113+
114+
def test_summing_merge_tree(self):
115+
base = get_declarative_base()
116+
117+
class TestTable(base):
118+
date = Column(types.Date, primary_key=True)
119+
x = Column(types.Int32)
120+
y = Column(types.Int32)
121+
122+
__table_args__ = (
123+
engines.SummingMergeTree(date, (date, x), (y, )),
124+
)
125+
126+
self.assertEqual(
127+
self.compile(CreateTable(TestTable.__table__)),
128+
'CREATE TABLE test_table (date Date, x Int32, y Int32) '
129+
'ENGINE = SummingMergeTree(date, (date, x), 8192, (y))'
130+
)
131+
132+
def test_buffer(self):
133+
base = get_declarative_base()
134+
135+
class TestTable(base):
136+
date = Column(types.Date, primary_key=True)
137+
x = Column(types.Int32)
138+
y = Column(types.String)
139+
140+
__table_args__ = (
141+
engines.Buffer('db', 'table'),
142+
)
143+
144+
self.assertEqual(
145+
self.compile(CreateTable(TestTable.__table__)),
146+
"CREATE TABLE test_table (date Date, x Int32, y String) "
147+
"ENGINE = Buffer("
148+
"db, table, 16, 10, 100, 10000, 1000000, 10000000, 100000000"
149+
")"
150+
)

0 commit comments

Comments
 (0)