import json import pathlib import pytest from datasette.app import Datasette from datasette.utils.sqlite import sqlite3 from datasette.utils import StartupError from .fixtures import TestClient as _TestClient PLUGIN = """ from datasette import hookimpl @hookimpl def extra_template_vars(): return { "from_plugin": "hooray" } """ METADATA = {"title": "This is from metadata"} CONFIG = { "settings": { "default_cache_ttl": 60, } } CSS = """ body { margin-top: 3em} """ @pytest.fixture(scope="session") def config_dir(tmp_path_factory): config_dir = tmp_path_factory.mktemp("config-dir") plugins_dir = config_dir / "plugins" plugins_dir.mkdir() (plugins_dir / "hooray.py").write_text(PLUGIN, "utf-8") (plugins_dir / "non_py_file.txt").write_text(PLUGIN, "utf-8") (plugins_dir / ".mypy_cache").mkdir() templates_dir = config_dir / "templates" templates_dir.mkdir() (templates_dir / "row.html").write_text( "Show row here. Plugin says {{ from_plugin }}", "utf-8" ) static_dir = config_dir / "static" static_dir.mkdir() (static_dir / "hello.css").write_text(CSS, "utf-8") (config_dir / "metadata.json").write_text(json.dumps(METADATA), "utf-8") (config_dir / "datasette.json").write_text(json.dumps(CONFIG), "utf-8") for dbname in ("demo.db", "immutable.db", "j.sqlite3", "k.sqlite"): db = sqlite3.connect(str(config_dir / dbname)) db.executescript( """ CREATE TABLE cities ( id integer primary key, name text ); INSERT INTO cities (id, name) VALUES (1, 'San Francisco') ; """ ) # Mark "immutable.db" as immutable (config_dir / "inspect-data.json").write_text( json.dumps( { "immutable": { "hash": "hash", "size": 8192, "file": "immutable.db", "tables": {"cities": {"count": 1}}, } } ), "utf-8", ) return config_dir def test_invalid_settings(config_dir): previous = (config_dir / "datasette.json").read_text("utf-8") (config_dir / "datasette.json").write_text( json.dumps({"settings": {"invalid": "invalid-setting"}}), "utf-8" ) try: with pytest.raises(StartupError) as ex: ds = Datasette([], config_dir=config_dir) assert ex.value.args[0] == "Invalid setting 'invalid' in datasette.json" finally: (config_dir / "datasette.json").write_text(previous, "utf-8") @pytest.fixture(scope="session") def config_dir_client(config_dir): ds = Datasette([], config_dir=config_dir) yield _TestClient(ds) def test_metadata(config_dir_client): response = config_dir_client.get("/-/metadata.json") assert 200 == response.status assert METADATA == response.json def test_settings(config_dir_client): response = config_dir_client.get("/-/settings.json") assert 200 == response.status assert 60 == response.json["default_cache_ttl"] def test_plugins(config_dir_client): response = config_dir_client.get("/-/plugins.json") assert 200 == response.status assert "hooray.py" in {p["name"] for p in response.json} assert "non_py_file.txt" not in {p["name"] for p in response.json} assert "mypy_cache" not in {p["name"] for p in response.json} def test_templates_and_plugin(config_dir_client): response = config_dir_client.get("/demo/cities/1") assert 200 == response.status assert "Show row here. Plugin says hooray" == response.text def test_static(config_dir_client): response = config_dir_client.get("/static/hello.css") assert 200 == response.status assert CSS == response.text assert "text/css" == response.headers["content-type"] def test_static_directory_browsing_not_allowed(config_dir_client): response = config_dir_client.get("/static/") assert 403 == response.status assert "403: Directory listing is not allowed" == response.text def test_databases(config_dir_client): response = config_dir_client.get("/-/databases.json") assert 200 == response.status databases = response.json assert 4 == len(databases) databases.sort(key=lambda d: d["name"]) for db, expected_name in zip(databases, ("demo", "immutable", "j", "k")): assert expected_name == db["name"] assert db["is_mutable"] == (expected_name != "immutable") @pytest.mark.parametrize("filename", ("metadata.yml", "metadata.yaml")) def test_metadata_yaml(tmp_path_factory, filename): config_dir = tmp_path_factory.mktemp("yaml-config-dir") (config_dir / filename).write_text("title: Title from metadata", "utf-8") ds = Datasette([], config_dir=config_dir) client = _TestClient(ds) response = client.get("/-/metadata.json") assert 200 == response.status assert {"title": "Title from metadata"} == response.json def test_store_config_dir(config_dir_client): ds = config_dir_client.ds assert hasattr(ds, "config_dir") assert ds.config_dir is not None assert isinstance(ds.config_dir, pathlib.Path)