Skip to content

Commit 5f9d449

Browse files
committed
Some tests
1 parent 84a029d commit 5f9d449

File tree

6 files changed

+289
-0
lines changed

6 files changed

+289
-0
lines changed

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def get_long_description():
2323
license='Apache License, Version 2.0',
2424
packages=['datasette_connectors'],
2525
install_requires=['datasette==0.25'],
26+
tests_require=['pytest', 'aiohttp'],
2627
entry_points='''
2728
[console_scripts]
2829
datasette=datasette_connectors.cli:cli

tests/__init__.py

Whitespace-only changes.

tests/dummy.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
from datasette_connectors.row import Row
2+
3+
4+
_connector_type = 'dummy'
5+
6+
def inspect(path):
7+
tables = {}
8+
views = []
9+
10+
for table in ['table1', 'table2']:
11+
tables[table] = {
12+
'name': table,
13+
'columns': ['c1', 'c2', 'c3'],
14+
'primary_keys': [],
15+
'count': 2,
16+
'label_column': None,
17+
'hidden': False,
18+
'fts_table': None,
19+
'foreign_keys': {'incoming': [], 'outgoing': []},
20+
}
21+
22+
return tables, views, _connector_type
23+
24+
25+
class Connection:
26+
def __init__(self, path):
27+
self.path = path
28+
29+
def execute(self, sql, params=None, truncate=False, page_size=None, max_returned_rows=None):
30+
sql = sql.strip()
31+
32+
rows = []
33+
truncated = False
34+
description = []
35+
36+
if sql == 'select c1 from table1':
37+
rows = [
38+
Row({'c1': 10}),
39+
Row({'c1': 20})
40+
]
41+
description = (('c1',),)
42+
elif sql == 'select rowid, * from table2 order by rowid limit 51':
43+
rows = [
44+
Row({'rowid': 1, 'c1': 100, 'c2': 120, 'c3': 130}),
45+
Row({'rowid': 2, 'c1': 200, 'c2': 220, 'c3': 230})
46+
]
47+
description = (('rowid',), ('c1',), ('c2',), ('c3',))
48+
elif sql == 'select count(*) from table2':
49+
rows = [Row({'count(*)': 2})]
50+
description = (('count(*)',),)
51+
elif sql == """select distinct rowid from table2
52+
where rowid is not null
53+
limit 31""":
54+
rows = [
55+
Row({'rowid': 1}),
56+
Row({'rowid': 2})
57+
]
58+
description = (('rowid',),)
59+
elif sql == """select distinct c1 from table2
60+
where c1 is not null
61+
limit 31""":
62+
rows = [
63+
Row({'c1': 100}),
64+
Row({'c1': 200})
65+
]
66+
description = (('c1',),)
67+
elif sql == """select distinct c2 from table2
68+
where c2 is not null
69+
limit 31""":
70+
rows = [
71+
Row({'c2': 120}),
72+
Row({'c2': 220})
73+
]
74+
description = (('c2',),)
75+
elif sql == """select distinct c3 from table2
76+
where c3 is not null
77+
limit 31""":
78+
rows = [
79+
Row({'c3': 130}),
80+
Row({'c3': 230})
81+
]
82+
description = (('c3',),)
83+
elif sql == 'select sql from sqlite_master where name = :n and type=:t':
84+
if params['t'] != 'view':
85+
rows = [Row({'sql': 'CREATE TABLE ' + params['n'] + ' (c1, c2, c3)'})]
86+
description = (('sql',),)
87+
else:
88+
raise Exception("Unexpected query: %s" % sql)
89+
90+
return rows, truncated, description

tests/fixtures.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from datasette_connectors import monkey; monkey.patch_datasette()
2+
from datasette_connectors import connectors
3+
from . import dummy
4+
connectors.db_connectors['dummy'] = dummy
5+
6+
from datasette.app import Datasette
7+
import os
8+
import pytest
9+
import tempfile
10+
11+
@pytest.fixture(scope='session')
12+
def app_client(max_returned_rows=None):
13+
with tempfile.TemporaryDirectory() as tmpdir:
14+
filepath = os.path.join(tmpdir, 'dummy_tables.db')
15+
populate_file(filepath)
16+
ds = Datasette(
17+
[filepath],
18+
config={
19+
'default_page_size': 50,
20+
'max_returned_rows': max_returned_rows or 1000,
21+
}
22+
)
23+
client = ds.app().test_client
24+
client.ds = ds
25+
yield client
26+
27+
28+
def populate_file(filepath):
29+
dummyfile = open(filepath, "w")
30+
dummyfile.write("This is a dummy file. We need something to force a SQLite error")
31+
dummyfile.close()

tests/test_api.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
from .fixtures import app_client
2+
from urllib.parse import urlencode
3+
4+
def test_homepage(app_client):
5+
_, response = app_client.get('/.json')
6+
assert response.status == 200
7+
assert response.json.keys() == {'dummy_tables': 0}.keys()
8+
d = response.json['dummy_tables']
9+
assert d['name'] == 'dummy_tables'
10+
assert d['tables_count'] == 2
11+
12+
def test_database_page(app_client):
13+
response = app_client.get('/dummy_tables.json', gather_request=False)
14+
data = response.json
15+
assert 'dummy_tables' == data['database']
16+
assert [{
17+
'name': 'table1',
18+
'columns': ['c1', 'c2', 'c3'],
19+
'primary_keys': [],
20+
'count': 2,
21+
'label_column': None,
22+
'hidden': False,
23+
'fts_table': None,
24+
'foreign_keys': {'incoming': [], 'outgoing': []}
25+
}, {
26+
'name': 'table2',
27+
'columns': ['c1', 'c2', 'c3'],
28+
'primary_keys': [],
29+
'count': 2,
30+
'label_column': None,
31+
'hidden': False,
32+
'fts_table': None,
33+
'foreign_keys': {'incoming': [], 'outgoing': []}
34+
}] == data['tables']
35+
36+
def test_custom_sql(app_client):
37+
response = app_client.get(
38+
'/dummy_tables.json?' + urlencode({
39+
'sql': 'select c1 from table1',
40+
'_shape': 'objects'
41+
}),
42+
gather_request=False
43+
)
44+
data = response.json
45+
assert {
46+
'sql': 'select c1 from table1',
47+
'params': {}
48+
} == data['query']
49+
assert 2 == len(data['rows'])
50+
assert [
51+
{'c1': 10},
52+
{'c1': 20}
53+
] == data['rows']
54+
assert ['c1'] == data['columns']
55+
assert 'dummy_tables' == data['database']
56+
assert not data['truncated']
57+
58+
def test_invalid_custom_sql(app_client):
59+
response = app_client.get(
60+
'/dummy_tables.json?sql=.schema',
61+
gather_request=False
62+
)
63+
assert response.status == 400
64+
assert response.json['ok'] is False
65+
assert 'Statement must be a SELECT' == response.json['error']
66+
67+
def test_table_json(app_client):
68+
response = app_client.get(
69+
'/dummy_tables/table2.json?_shape=objects',
70+
gather_request=False
71+
)
72+
assert response.status == 200
73+
data = response.json
74+
assert data['query']['sql'] == 'select rowid, * from table2 order by rowid limit 51'
75+
assert data['rows'] == [{
76+
'rowid': 1,
77+
'c1': 100,
78+
'c2': 120,
79+
'c3': 130
80+
}, {
81+
'rowid': 2,
82+
'c1': 200,
83+
'c2': 220,
84+
'c3': 230
85+
}]
86+
87+
def test_table_not_exists_json(app_client):
88+
assert {
89+
'ok': False,
90+
'error': 'Table not found: blah',
91+
'status': 404,
92+
'title': None,
93+
} == app_client.get(
94+
'/dummy_tables/blah.json', gather_request=False
95+
).json
96+
97+
def test_table_shape_arrays(app_client):
98+
response = app_client.get(
99+
'/dummy_tables/table2.json?_shape=arrays',
100+
gather_request=False
101+
)
102+
assert [
103+
[1, 100, 120, 130],
104+
[2, 200, 220, 230],
105+
] == response.json['rows']
106+
107+
def test_table_shape_objects(app_client):
108+
response = app_client.get(
109+
'/dummy_tables/table2.json?_shape=objects',
110+
gather_request=False
111+
)
112+
assert [{
113+
'rowid': 1,
114+
'c1': 100,
115+
'c2': 120,
116+
'c3': 130,
117+
}, {
118+
'rowid': 2,
119+
'c1': 200,
120+
'c2': 220,
121+
'c3': 230,
122+
}] == response.json['rows']
123+
124+
def test_table_shape_array(app_client):
125+
response = app_client.get(
126+
'/dummy_tables/table2.json?_shape=array',
127+
gather_request=False
128+
)
129+
assert [{
130+
'rowid': 1,
131+
'c1': 100,
132+
'c2': 120,
133+
'c3': 130,
134+
}, {
135+
'rowid': 2,
136+
'c1': 200,
137+
'c2': 220,
138+
'c3': 230,
139+
}] == response.json
140+
141+
def test_table_shape_invalid(app_client):
142+
response = app_client.get(
143+
'/dummy_tables/table2.json?_shape=invalid',
144+
gather_request=False
145+
)
146+
assert {
147+
'ok': False,
148+
'error': 'Invalid _shape: invalid',
149+
'status': 400,
150+
'title': None,
151+
} == response.json

tests/test_html.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from .fixtures import app_client
2+
3+
def test_homepage(app_client):
4+
response = app_client.get('/', gather_request=False)
5+
assert response.status == 200
6+
assert 'dummy_tables' in response.text
7+
8+
def test_database_page(app_client):
9+
response = app_client.get('/dummy_tables', allow_redirects=False, gather_request=False)
10+
assert response.status == 302
11+
response = app_client.get('/dummy_tables', gather_request=False)
12+
assert 'dummy_tables' in response.text
13+
14+
def test_table(app_client):
15+
response = app_client.get('/dummy_tables/table2', gather_request=False)
16+
assert response.status == 200

0 commit comments

Comments
 (0)