Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add writable flag to meta stores #256

Merged
merged 15 commits into from
Apr 1, 2022
49 changes: 10 additions & 39 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
import shapely.geometry # noqa: F401

import os
from pathlib import Path
import tempfile
import uuid
import multiprocessing
import time
from functools import partial
Expand All @@ -15,8 +12,6 @@
import numpy as np
import rasterio

boto3 = pytest.importorskip('boto3')


def pytest_configure(config):
os.environ['TC_TESTING'] = '1'
Expand Down Expand Up @@ -350,43 +345,19 @@ def use_testdb(testdb, monkeypatch):


@pytest.fixture()
def s3_db_factory(tmpdir):
bucketname = str(uuid.uuid4())

def _s3_db_factory(keys, datasets=None, skip_metadata=False):
from terracotta import get_driver

with tempfile.TemporaryDirectory() as tmpdir:
dbfile = Path(tmpdir) / 'tc.sqlite'
driver = get_driver(dbfile)
driver.create(keys)

if datasets:
for keys, path in datasets.items():
driver.insert(keys, path, skip_metadata=skip_metadata)

with open(dbfile, 'rb') as f:
db_bytes = f.read()

conn = boto3.resource('s3')
conn.create_bucket(Bucket=bucketname)

s3 = boto3.client('s3')
s3.put_object(Bucket=bucketname, Key='tc.sqlite', Body=db_bytes)

return f's3://{bucketname}/tc.sqlite'
def use_non_writable_testdb(testdb, monkeypatch, raster_file):
import terracotta
terracotta.update_settings(DRIVER_PATH=str(testdb))

return _s3_db_factory
driver = terracotta.get_driver(testdb)
with driver.connect():
driver.insert(('first', 'second', 'third'), str(raster_file), skip_metadata=True)

driver.meta_store._WRITABLE = False
yield
driver.meta_store._WRITABLE = True
kiksekage marked this conversation as resolved.
Show resolved Hide resolved

@pytest.fixture()
def mock_aws_env(monkeypatch):
with monkeypatch.context() as m:
m.setenv('AWS_DEFAULT_REGION', 'us-east-1')
m.setenv('AWS_ACCESS_KEY_ID', 'FakeKey')
m.setenv('AWS_SECRET_ACCESS_KEY', 'FakeSecretKey')
m.setenv('AWS_SESSION_TOKEN', 'FakeSessionToken')
yield
driver.delete(('first', 'second', 'third'))


def run_test_server(driver_path, port):
Expand Down
54 changes: 49 additions & 5 deletions tests/drivers/test_sqlite_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,29 @@
"""

import os
import tempfile
import time
import uuid
from pathlib import Path

import pytest

from terracotta import exceptions

boto3 = pytest.importorskip('boto3')
moto = pytest.importorskip('moto')


@pytest.fixture(autouse=True)
def mock_aws_env(monkeypatch):
with monkeypatch.context() as m:
m.setenv('AWS_DEFAULT_REGION', 'us-east-1')
m.setenv('AWS_ACCESS_KEY_ID', 'FakeKey')
m.setenv('AWS_SECRET_ACCESS_KEY', 'FakeSecretKey')
m.setenv('AWS_SESSION_TOKEN', 'FakeSessionToken')
yield


class Timer:
def __init__(self, auto=False):
self.auto = auto
Expand All @@ -27,8 +41,38 @@ def tick(self):
self.time += 1


@pytest.fixture()
def s3_db_factory(tmpdir):
bucketname = str(uuid.uuid4())

def _s3_db_factory(keys, datasets=None):
from terracotta import get_driver

with tempfile.TemporaryDirectory() as tmpdir:
dbfile = Path(tmpdir) / 'tc.sqlite'
driver = get_driver(dbfile)
driver.create(keys)

if datasets:
for keys, path in datasets.items():
driver.insert(keys, path)

with open(dbfile, 'rb') as f:
db_bytes = f.read()

conn = boto3.resource('s3')
conn.create_bucket(Bucket=bucketname)

s3 = boto3.client('s3')
s3.put_object(Bucket=bucketname, Key='tc.sqlite', Body=db_bytes)

return f's3://{bucketname}/tc.sqlite'

return _s3_db_factory


@moto.mock_s3
def test_remote_database(s3_db_factory, mock_aws_env):
def test_remote_database(s3_db_factory):
keys = ('some', 'keys')
dbpath = s3_db_factory(keys)

Expand All @@ -47,7 +91,7 @@ def test_invalid_url():


@moto.mock_s3
def test_nonexisting_url(mock_aws_env):
def test_nonexisting_url():
from terracotta import exceptions, get_driver
driver = get_driver('s3://foo/db.sqlite')
with pytest.raises(exceptions.InvalidDatabaseError):
Expand All @@ -56,7 +100,7 @@ def test_nonexisting_url(mock_aws_env):


@moto.mock_s3
def test_remote_database_cache(s3_db_factory, raster_file, mock_aws_env):
def test_remote_database_cache(s3_db_factory, raster_file, monkeypatch):
keys = ('some', 'keys')
dbpath = s3_db_factory(keys)

Expand Down Expand Up @@ -92,7 +136,7 @@ def test_remote_database_cache(s3_db_factory, raster_file, mock_aws_env):


@moto.mock_s3
def test_immutability(s3_db_factory, raster_file, mock_aws_env):
def test_immutability(s3_db_factory, raster_file):
keys = ('some', 'keys')
dbpath = s3_db_factory(keys, datasets={('some', 'value'): str(raster_file)})

Expand All @@ -111,7 +155,7 @@ def test_immutability(s3_db_factory, raster_file, mock_aws_env):


@moto.mock_s3
def test_destructor(s3_db_factory, raster_file, capsys, mock_aws_env):
def test_destructor(s3_db_factory, raster_file, capsys):
keys = ('some', 'keys')
dbpath = s3_db_factory(keys, datasets={('some', 'value'): str(raster_file)})

Expand Down
33 changes: 7 additions & 26 deletions tests/server/test_flask_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

import pytest

moto = pytest.importorskip('moto')


@pytest.fixture(scope='module')
def flask_app():
Expand Down Expand Up @@ -53,37 +51,20 @@ def test_get_metadata(client, use_testdb):
assert ['extra_data'] == json.loads(rv.data)['metadata']


@moto.mock_s3
def test_get_metadata_lazily_nonwritable_db(client, s3_db_factory, mock_aws_env, raster_file):
import terracotta

keys = ('some', 'keys')
dbpath = s3_db_factory(
keys, datasets={("some", "value"): str(raster_file)}, skip_metadata=True
)
terracotta.update_settings(DRIVER_PATH=str(dbpath), DRIVER_PROVIDER="sqlite-remote")

rv = client.get('/metadata/some/value')
def test_get_metadata_lazily_nonwritable_db(client, use_non_writable_testdb):
rv = client.get('/metadata/first/second/third')
assert rv.status_code == 403


@moto.mock_s3
def test_debug_errors(debug_client, s3_db_factory, mock_aws_env, raster_file, raster_file_xyz):
import terracotta
def test_debug_errors(debug_client, use_non_writable_testdb, raster_file_xyz):
from terracotta import exceptions
import marshmallow

keys = ('some', 'keys')
dbpath = s3_db_factory(
keys, datasets={("some", "value"): str(raster_file)}, skip_metadata=True
)
terracotta.update_settings(DRIVER_PATH=str(dbpath), DRIVER_PROVIDER="sqlite-remote")

with pytest.raises(exceptions.DatabaseNotWritableError):
debug_client.get('/metadata/some/value')
debug_client.get('/metadata/first/second/third')

with pytest.raises(exceptions.DatasetNotFoundError):
debug_client.get('/metadata/NONEXISTING/KEYS')
debug_client.get('/metadata/NONEXISTING/KEYS/YO')

with pytest.raises(exceptions.InvalidKeyError):
debug_client.get('/metadata/ONLYONEKEY')
Expand All @@ -92,14 +73,14 @@ def test_debug_errors(debug_client, s3_db_factory, mock_aws_env, raster_file, ra

with pytest.raises(exceptions.InvalidArgumentsError):
debug_client.get(
f'/compute/some/value/{z}/{x}/{y}.png'
f'/compute/first/second/third/{z}/{x}/{y}.png'
'?expression=v1*v2&v1=val22&v2=val23'
'&stretch_range=[10000,0]'
)

with pytest.raises(marshmallow.ValidationError):
debug_client.get(
f'/compute/some/value/{z}/{x}/{y}.png'
f'/compute/first/second/third/{z}/{x}/{y}.png'
'?stretch_range=[10000,0]'
)

Expand Down