From 749b6f0d74ac24a1447d1ab1ba2afde5adfe2a96 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Thu, 21 Jun 2018 16:57:49 -0700 Subject: [PATCH 1/6] Cache pip wheels between runs in Travis, refs #323 --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 91009165..17d46803 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,12 +9,17 @@ python: script: - python setup.py test +cache: + directories: + - $HOME/.cache/pip + # This defines further stages that execute after the tests jobs: include: - stage: deploy latest.datasette.io if: branch = master AND type = push script: + - pip install -U pip wheel - pip install . - npm install -g now - python tests/fixtures.py fixtures.db fixtures.json From b9046332c4ce498ab1c363cf579ebc5586f304ac Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Thu, 21 Jun 2018 19:51:10 -0700 Subject: [PATCH 2/6] Tell pip to use explicit download cache --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 17d46803..aec6d488 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,8 @@ python: # Executed for 3.5 AND 3.5 as the first "test" stage: script: + - pip install -U pip wheel + - pip install --download-cache /home/travis/.cache/pip . - python setup.py test cache: @@ -19,8 +21,7 @@ jobs: - stage: deploy latest.datasette.io if: branch = master AND type = push script: - - pip install -U pip wheel - - pip install . + - pip install --download-cache /home/travis/.cache/pip . - npm install -g now - python tests/fixtures.py fixtures.db fixtures.json - export ALIAS=`echo $TRAVIS_COMMIT | cut -c 1-7` From 22831a1ac82a2e34c06dd3f753e9928ad9c95725 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Thu, 21 Jun 2018 19:53:22 -0700 Subject: [PATCH 3/6] Don't use --download-cache argument --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index aec6d488..0a5375f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ python: # Executed for 3.5 AND 3.5 as the first "test" stage: script: - pip install -U pip wheel - - pip install --download-cache /home/travis/.cache/pip . + - pip install . - python setup.py test cache: @@ -21,7 +21,7 @@ jobs: - stage: deploy latest.datasette.io if: branch = master AND type = push script: - - pip install --download-cache /home/travis/.cache/pip . + - pip install . - npm install -g now - python tests/fixtures.py fixtures.db fixtures.json - export ALIAS=`echo $TRAVIS_COMMIT | cut -c 1-7` From 69b3a6c7ddf0e4e188a600ae50949c2b6ddc166a Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Thu, 21 Jun 2018 19:59:26 -0700 Subject: [PATCH 4/6] Run pytest manually python setup.py test appeared to still download a bunch of stuff https://travis-ci.org/simonw/datasette/jobs/395306188 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0a5375f0..f272ab38 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,8 @@ python: # Executed for 3.5 AND 3.5 as the first "test" stage: script: - pip install -U pip wheel - - pip install . - - python setup.py test + - pip install .[test] + - pytest cache: directories: From 7d7f5f61fd6dca3385386a657a13057680d8ddd7 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Thu, 21 Jun 2018 20:03:54 -0700 Subject: [PATCH 5/6] Use extras_require so pip can install test dependencies https://github.com/pypa/pip/issues/1197#issuecomment-228939212 --- setup.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 79b1a519..67253a7f 100644 --- a/setup.py +++ b/setup.py @@ -47,10 +47,15 @@ setup( datasette=datasette.cli:cli ''', setup_requires=['pytest-runner'], + extras_require={ + 'test': [ + 'pytest==3.6.0', + 'aiohttp==2.3.2', + 'beautifulsoup4==4.6.0', + ] + }, tests_require=[ - 'pytest==3.6.0', - 'aiohttp==2.3.2', - 'beautifulsoup4==4.6.0', + 'datasette[test]', ], classifiers=[ 'Development Status :: 4 - Beta', From be018ce47f428a4faede1ee0cb5b5a8cf9a97056 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sat, 23 Jun 2018 17:55:00 -0700 Subject: [PATCH 6/6] Trying to get pytest-dist working on multiple cores --- tests/fixtures.py | 41 ++++++++++++++++++++++++++++------------- tests/test_api.py | 18 ++++++++++-------- tests/test_csv.py | 1 + tests/test_html.py | 8 ++++---- 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/tests/fixtures.py b/tests/fixtures.py index 004a0b03..e69a837b 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -1,9 +1,11 @@ from datasette.app import Datasette +from sanic.testing import PORT as PORT_BASE, SanicTestClient import itertools import json import os import pytest import random +import re import sqlite3 import sys import string @@ -11,7 +13,7 @@ import tempfile import time -class TestClient: +class MyTestClient: def __init__(self, sanic_test_client): self.sanic_test_client = sanic_test_client @@ -24,7 +26,7 @@ class TestClient: @pytest.fixture(scope='session') -def app_client(sql_time_limit_ms=None, max_returned_rows=None, config=None, filename="fixtures.db"): +def app_client(worker_id, sql_time_limit_ms=None, max_returned_rows=None, config=None, filename="fixtures.db"): with tempfile.TemporaryDirectory() as tmpdir: filepath = os.path.join(tmpdir, filename) conn = sqlite3.connect(filepath) @@ -49,38 +51,51 @@ def app_client(sql_time_limit_ms=None, max_returned_rows=None, config=None, file ds.sqlite_functions.append( ('sleep', 1, lambda n: time.sleep(float(n))), ) - client = TestClient(ds.app().test_client) + m = re.search(r'[0-9]+', worker_id) + if m: + num_id = m.group(0) + else: + num_id = 0 + port = PORT_BASE + int(num_id) + client = MyTestClient(SanicTestClient(ds.app(), port)) client.ds = ds yield client @pytest.fixture(scope='session') -def app_client_shorter_time_limit(): - yield from app_client(20) +def app_client_factory(worker_id): + def factory(**kwargs): + yield from app_client(worker_id, **kwargs) + return factory @pytest.fixture(scope='session') -def app_client_returned_rows_matches_page_size(): - yield from app_client(max_returned_rows=50) +def app_client_shorter_time_limit(worker_id): + yield from app_client(worker_id, 20) @pytest.fixture(scope='session') -def app_client_larger_cache_size(): - yield from app_client(config={ +def app_client_returned_rows_matches_page_size(worker_id): + yield from app_client(worker_id, max_returned_rows=50) + + +@pytest.fixture(scope='session') +def app_client_larger_cache_size(worker_id): + yield from app_client(worker_id, config={ 'cache_size_kb': 2500, }) @pytest.fixture(scope='session') -def app_client_csv_max_mb_one(): - yield from app_client(config={ +def app_client_csv_max_mb_one(worker_id): + yield from app_client(worker_id, config={ 'max_csv_mb': 1, }) @pytest.fixture(scope="session") -def app_client_with_dot(): - yield from app_client(filename="fixtures.dot.db") +def app_client_with_dot(worker_id): + yield from app_client(worker_id, filename="fixtures.dot.db") def generate_compound_rows(num): diff --git a/tests/test_api.py b/tests/test_api.py index 61987f0a..418494a0 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,5 +1,6 @@ from .fixtures import ( # noqa app_client, + app_client_factory, app_client_shorter_time_limit, app_client_larger_cache_size, app_client_returned_rows_matches_page_size, @@ -424,8 +425,8 @@ def test_invalid_custom_sql(app_client): assert 'Statement must be a SELECT' == response.json['error'] -def test_allow_sql_off(): - for client in app_client(config={ +def test_allow_sql_off(worker_id): + for client in app_client(worker_id, config={ 'allow_sql': False, }): assert 400 == client.get( @@ -971,11 +972,12 @@ def test_config_json(app_client): } == response.json -def test_page_size_matching_max_returned_rows(app_client_returned_rows_matches_page_size): +def test_page_size_matching_max_returned_rows(app_client_factory): + app_client = app_client_factory(max_returned_rows=50) fetched = [] path = '/fixtures/no_primary_key.json' while path: - response = app_client_returned_rows_matches_page_size.get(path) + response = app_client.get(path) fetched.extend(response.json['rows']) assert len(response.json['rows']) in (1, 50) path = response.json['next_url'] @@ -1140,8 +1142,8 @@ def test_suggested_facets(app_client): ).json["suggested_facets"]) > 0 -def test_allow_facet_off(): - for client in app_client(config={ +def test_allow_facet_off(worker_id): + for client in app_client(worker_id, config={ 'allow_facet': False, }): assert 400 == client.get( @@ -1153,8 +1155,8 @@ def test_allow_facet_off(): ).json["suggested_facets"] -def test_suggest_facets_off(): - for client in app_client(config={ +def test_suggest_facets_off(worker_id): + for client in app_client(worker_id, config={ 'suggest_facets': False, }): # Now suggested_facets should be [] diff --git a/tests/test_csv.py b/tests/test_csv.py index 194de5b1..794cd9b3 100644 --- a/tests/test_csv.py +++ b/tests/test_csv.py @@ -30,6 +30,7 @@ pk,planet_int,on_earth,state,city_id,city_id_label,neighborhood 15,2,0,MC,4,Memnonia,Arcadia Planitia '''.lstrip().replace('\n', '\r\n') + def test_table_csv(app_client): response = app_client.get('/fixtures/simple_primary_key.csv') assert response.status == 200 diff --git a/tests/test_html.py b/tests/test_html.py index ee9d3c41..a7c58442 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -639,8 +639,8 @@ def test_allow_download_on(app_client): assert len(soup.findAll('a', {'href': re.compile('\.db$')})) -def test_allow_download_off(): - for client in app_client(config={ +def test_allow_download_off(worker_id): + for client in app_client(worker_id, config={ 'allow_download': False, }): response = client.get( @@ -665,8 +665,8 @@ def test_allow_sql_on(app_client): assert len(soup.findAll('textarea', {'name': 'sql'})) -def test_allow_sql_off(): - for client in app_client(config={ +def test_allow_sql_off(worker_id): + for client in app_client(worker_id, config={ 'allow_sql': False, }): response = client.get(