diff --git a/toardb/auth_user/models.py b/toardb/auth_user/models.py index 5f644ed4c381c523e00a4352bd14c9e94dd2ece2..9284dd15d552b0e9932e39167e3d049a05da65d4 100644 --- a/toardb/auth_user/models.py +++ b/toardb/auth_user/models.py @@ -1,15 +1,17 @@ # coding: utf-8 -from sqlalchemy import ARRAY, BigInteger, Boolean, CheckConstraint, Column, DateTime, Float, ForeignKey, Index, Integer, SmallInteger, String, Table, Text, UniqueConstraint, text +from sqlalchemy import ARRAY, BigInteger, Boolean, CheckConstraint, Column, DateTime, Float, ForeignKey, \ + Index, Integer, SmallInteger, String, Table, Text, UniqueConstraint, text, Sequence from sqlalchemy.orm import relationship from geoalchemy2.types import Geometry from sqlalchemy.dialects.postgresql import JSONB from toardb.base import Base +AUTH_USER_ID_SEQ = Sequence('auth_user_id_seq') # define sequence explicitly class AuthUser(Base): __tablename__ = 'auth_user' - id = Column(Integer, primary_key=True, server_default=text("nextval('auth_user_id_seq'::regclass)")) + id = Column(Integer, AUTH_USER_ID_SEQ, primary_key=True, server_default=AUTH_USER_ID_SEQ.next_value()) password = Column(String(128), nullable=False) last_login = Column(DateTime(True)) is_superuser = Column(Boolean, nullable=False) diff --git a/toardb/contacts/contacts.py b/toardb/contacts/contacts.py index 9f578a8f459c003fd55dfb088fe2b18973fa515c..171a54914889ad444b8c909e366ef0d6fa187f30 100644 --- a/toardb/contacts/contacts.py +++ b/toardb/contacts/contacts.py @@ -6,19 +6,10 @@ from typing import List from fastapi import APIRouter, Depends, HTTPException, Body from sqlalchemy.orm import Session from . import crud, schemas -from toardb.utils.database import ToarDbSession +from toardb.utils.database import ToarDbSession, get_db router = APIRouter() -# Dependency -def get_db(): - try: - db = ToarDbSession() - yield db - finally: - db.close() - - # plain views to post and get contacts #get all entries of table persons diff --git a/toardb/contacts/models_organisation.py b/toardb/contacts/models_organisation.py index dcf8f9c7502b77a28149d72880b91481e889f18d..3befad731e35acd1bd3334a6668211ca1795595b 100644 --- a/toardb/contacts/models_organisation.py +++ b/toardb/contacts/models_organisation.py @@ -3,10 +3,10 @@ class Organisation (Base) ========================= """ -from sqlalchemy import CheckConstraint, Column, Integer, String, text +from sqlalchemy import CheckConstraint, Column, Integer, String, Sequence from toardb.base import Base - +ORGANISATIONS_ID_SEQ = Sequence('organisations_id_seq') # define sequence explicitly class Organisation(Base): """ Table "public.organisations" @@ -41,7 +41,7 @@ class Organisation(Base): CheckConstraint('kind >= 0'), ) - id = Column(Integer, primary_key=True, server_default=text("nextval('organisations_id_seq'::regclass)")) + id = Column(Integer, ORGANISATIONS_ID_SEQ, primary_key=True, server_default=ORGANISATIONS_ID_SEQ.next_value()) name = Column(String(32), nullable=False) longname = Column(String(128), nullable=False) kind = Column(Integer, nullable=False) diff --git a/toardb/contacts/models_person.py b/toardb/contacts/models_person.py index aa31af4c9c1658cc968c552eb3352ee262c2ca7e..54ce047ee190fe3dc8526e47d354860af961a0bb 100644 --- a/toardb/contacts/models_person.py +++ b/toardb/contacts/models_person.py @@ -3,9 +3,10 @@ class Person (Base) =================== """ -from sqlalchemy import Boolean, Column, Integer, String, text +from sqlalchemy import Boolean, Column, Integer, String, Sequence from toardb.base import Base +PERSONS_ID_SEQ = Sequence('persons_id_seq') # define sequence explicitly class Person(Base): """ Table "public.persons" @@ -30,7 +31,7 @@ class Person(Base): """ __tablename__ = 'persons' - id = Column(Integer, primary_key=True, server_default=text("nextval('persons_id_seq'::regclass)")) + id = Column(Integer, PERSONS_ID_SEQ, primary_key=True, server_default=PERSONS_ID_SEQ.next_value()) name = Column(String(64), nullable=False) email = Column(String(128), nullable=False) phone = Column(String(32), nullable=False) diff --git a/toardb/contacts/test_base.py b/toardb/contacts/test_base.py deleted file mode 100644 index 70113f71186ca3e4a4b90b1a25e40878fcb77e3f..0000000000000000000000000000000000000000 --- a/toardb/contacts/test_base.py +++ /dev/null @@ -1,78 +0,0 @@ -#taken from: https://github.com/tiangolo/fastapi/issues/831 -import pytest -from starlette.testclient import TestClient -from typing import Optional, AsyncIterable -from sqlalchemy import create_engine -from sqlalchemy.engine import Engine as Database -from sqlalchemy.orm import Session -from sqlalchemy_utils import database_exists, create_database, drop_database - -from toardb.utils.database import DATABASE_URL -from .models import Base -from toardb.toardb import app -from toardb.contacts.contacts import get_db - -url = str(DATABASE_URL+ "_test") -_db_conn = create_engine(url) - -def get_test_db_conn() -> Database: - assert _db_conn is not None - return _db_conn - - -def get_test_db() -> AsyncIterable[Session]: - sess = Session(bind=_db_conn) - - try: - yield sess - finally: - sess.close() - - -@pytest.fixture(scope="session", autouse=True) -def create_test_database(): - """ - Create a clean database on every test case. - We use the `sqlalchemy_utils` package here for a few helpers in consistently - creating and dropping the database. - """ - if database_exists(url): - drop_database(url) - create_database(url) # Create the test database. - #'create_all' does not work (because of undefined id_seq table)! - # I also need the id_seq tables: - fake_conn = _db_conn.raw_connection() - fake_cur = fake_conn.cursor() - fake_cur.execute("CREATE SEQUENCE public.persons_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.organisations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - Base.metadata.create_all(_db_conn) # Create the tables. - #try with the basics - app.dependency_overrides[get_db] = get_test_db # Mock the Database Dependency - yield # Run the tests. - drop_database(url) # Drop the test database. - - -@pytest.yield_fixture -def test_db_session(): - """Returns an sqlalchemy session, and after the test tears down everything properly.""" - - session = Session(bind=_db_conn) - - yield session - # Drop all data after each test - for tbl in reversed(Base.metadata.sorted_tables): - _db_conn.execute(tbl.delete()) - # put back the connection to the connection pool - session.close() - - -@pytest.fixture() -def client(): - """ - When using the 'client' fixture in test cases, we'll get full database - rollbacks between test cases: - """ - with TestClient(app) as client: - yield client diff --git a/toardb/contacts/test_contacts.py b/toardb/contacts/test_contacts.py index 162883b20e596170a97f5857d66dd9c5e3c35290..06b3e9861b46c40a897560a461442804f265cea5 100644 --- a/toardb/contacts/test_contacts.py +++ b/toardb/contacts/test_contacts.py @@ -2,14 +2,14 @@ import pytest import json from .models import Person, Organisation # Required imports 'create_test_database' -from .test_base import ( +from toardb.test_base import ( client, get_test_db, create_test_database, url, + get_test_engine, test_db_session as db, ) -from .test_base import _db_conn class TestApps: def setup(self): @@ -23,6 +23,7 @@ class TestApps: @pytest.fixture(autouse=True) def setup_db_data(self, db): # id_seq will not be reset automatically between tests! + _db_conn = get_test_engine() fake_conn = _db_conn.raw_connection() fake_cur = fake_conn.cursor() fake_cur.execute("ALTER SEQUENCE persons_id_seq RESTART WITH 1") diff --git a/toardb/data/data.py b/toardb/data/data.py index c8a76b03b518dbb9cda1a2e80ef8a5048666034b..f61b31f7eb225dbf675ee437f347146a1c5fbb29 100644 --- a/toardb/data/data.py +++ b/toardb/data/data.py @@ -9,24 +9,10 @@ from fastapi import APIRouter, Depends, HTTPException, \ from sqlalchemy.orm import Session from sqlalchemy.engine import Engine from . import crud, schemas -from toardb.utils.database import ToarDbSession, engine +from toardb.utils.database import ToarDbSession, engine, get_engine, get_db router = APIRouter() -# Dependency -def get_engine(): - assert engine is not None - return engine - -# Dependency -def get_db(): - try: - db = ToarDbSession() - yield db - finally: - db.close() - - # plain views to post and get data #get all data of table data diff --git a/toardb/data/test_base.py b/toardb/data/test_base.py deleted file mode 100644 index d85318992098d439453904db993fdffe77981668..0000000000000000000000000000000000000000 --- a/toardb/data/test_base.py +++ /dev/null @@ -1,124 +0,0 @@ -#taken from: https://github.com/tiangolo/fastapi/issues/831 -import pytest -from starlette.testclient import TestClient -from typing import Optional, AsyncIterable -from sqlalchemy import create_engine -from sqlalchemy.engine import Engine -from sqlalchemy.orm import Session -from sqlalchemy.orm import sessionmaker -from sqlalchemy_utils import database_exists, create_database, drop_database - -from toardb.utils.database import DATABASE_URL -from .models import Base -from toardb.auth_user.models import Base as AuthUserBase -from toardb.contacts.models import Base as ContactBase -from toardb.variables.models import Base as VariableBase -from toardb.stationmeta.models import Base as StationmetaBase -from toardb.timeseries.models import Base as TimeseriesBase -from toardb.toardb import app -from toardb.data.data import get_db, get_engine - -url = str(DATABASE_URL+ "_test") -_db_conn = create_engine(url) - -def get_test_engine() -> Engine: - assert _db_conn is not None - return _db_conn - - -def get_test_db(): - sess = sessionmaker(bind=_db_conn,autoflush=False,autocommit=False)() - try: - yield sess - finally: - sess.close() - - -@pytest.fixture(scope="session", autouse=True) -def create_test_database(): - """ - Create a clean database on every test case. - We use the `sqlalchemy_utils` package here for a few helpers in consistently - creating and dropping the database. - """ - if database_exists(url): - drop_database(url) - create_database(url) # Create the test database. - #'create_all' does not work (because of undefined 'Geometry')! - #declare PostGIS extension! - fake_conn = _db_conn.raw_connection() - fake_cur = fake_conn.cursor() - fake_cur.execute("CREATE EXTENSION postgis") - fake_conn.commit() - # I also need the id_seq tables: - fake_cur.execute("CREATE SEQUENCE public.auth_user_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.variables_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_core_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_global_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_global_services_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_roles_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_annotations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_aux_docs_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_aux_images_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_aux_urls_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.persons_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.organisations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.timeseries_annotations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.timeseries_roles_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.timeseries_programmes_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.timeseries_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - AuthUserBase.metadata.create_all(_db_conn) # Create the tables. - ContactBase.metadata.create_all(_db_conn) # Create the tables. - VariableBase.metadata.create_all(_db_conn) # Create the tables. - StationmetaBase.metadata.create_all(_db_conn) # Create the tables. - TimeseriesBase.metadata.create_all(_db_conn) # Create the tables. - Base.metadata.create_all(_db_conn) # Create the tables. - #try with the basics - app.dependency_overrides[get_db] = get_test_db # Mock the Database Dependency - app.dependency_overrides[get_engine] = get_test_engine # Mock the Database Dependency - yield # Run the tests. - drop_database(url) # Drop the test database. - - -@pytest.yield_fixture -def test_db_session(): - """Returns an sqlalchemy session, and after the test tears down everything properly.""" - - session = sessionmaker(bind=_db_conn,autoflush=False,autocommit=False)() - yield session - # Drop all data after each test - for tbl in reversed(AuthUserBase.metadata.sorted_tables + - ContactBase.metadata.sorted_tables + - VariableBase.metadata.sorted_tables + - StationmetaBase.metadata.sorted_tables + - TimeseriesBase.metadata.sorted_tables + - Base.metadata.sorted_tables): - _db_conn.execute(tbl.delete()) - # put back the connection to the connection pool - session.close() - - -@pytest.fixture() -def client(): - """ - When using the 'client' fixture in test cases, we'll get full database - rollbacks between test cases: - """ - with TestClient(app) as client: - yield client diff --git a/toardb/data/test_data.py b/toardb/data/test_data.py index 30915342376035c6f070ef03cd470be53f17f332..b3354a77addaaf362c75b67448386330c440c94d 100644 --- a/toardb/data/test_data.py +++ b/toardb/data/test_data.py @@ -7,15 +7,14 @@ from toardb.stationmeta.schemas import get_geom_from_coordinates, Coordinates from toardb.variables.models import Variable from toardb.contacts.models import Person, Organisation from toardb.auth_user.models import AuthUser -# Required imports 'create_test_database' -from .test_base import ( +from toardb.test_base import ( client, get_test_db, create_test_database, url, + get_test_engine, test_db_session as db, ) -from .test_base import _db_conn class TestApps: def setup(self): @@ -28,6 +27,7 @@ class TestApps: """ @pytest.fixture(autouse=True) def setup_db_data(self, db): + _db_conn = get_test_engine() fake_conn = _db_conn.raw_connection() fake_cur = fake_conn.cursor() # id_seq will not be reset automatically between tests! @@ -45,11 +45,11 @@ class TestApps: fake_conn.commit() fake_cur.execute("ALTER SEQUENCE stationmeta_annotations_id_seq RESTART WITH 1") fake_conn.commit() - fake_cur.execute("ALTER SEQUENCE stationmeta_aux_docs_id_seq RESTART WITH 1") + fake_cur.execute("ALTER SEQUENCE stationmeta_aux_doc_id_seq RESTART WITH 1") fake_conn.commit() - fake_cur.execute("ALTER SEQUENCE stationmeta_aux_images_id_seq RESTART WITH 1") + fake_cur.execute("ALTER SEQUENCE stationmeta_aux_image_id_seq RESTART WITH 1") fake_conn.commit() - fake_cur.execute("ALTER SEQUENCE stationmeta_aux_urls_id_seq RESTART WITH 1") + fake_cur.execute("ALTER SEQUENCE stationmeta_aux_url_id_seq RESTART WITH 1") fake_conn.commit() fake_cur.execute("ALTER SEQUENCE persons_id_seq RESTART WITH 1") fake_conn.commit() diff --git a/toardb/stationmeta/models_annotation.py b/toardb/stationmeta/models_annotation.py index fd31faf860b1d78bc16fb4bc327d1d440b88764b..c7f91b67ab8e9a1a6fccbe0ce962e801c6e1e4f7 100644 --- a/toardb/stationmeta/models_annotation.py +++ b/toardb/stationmeta/models_annotation.py @@ -3,8 +3,8 @@ class StationmetaAnnotation (Base) ================================== """ -from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, text, String, \ - Text, Boolean, CheckConstraint, Table +from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, String, \ + Text, Boolean, CheckConstraint, Table, Sequence from sqlalchemy.orm import relationship from toardb.auth_user.models import AuthUser from toardb.base import Base @@ -17,24 +17,25 @@ stationmeta_core_stationmeta_annotations_table = Table('stationmeta_core_station ) +STATIONMETA_ANNOTATIONS_ID_SEQ = Sequence('stationmeta_annotations_id_seq') # define sequence explicitly class StationmetaAnnotation(Base): """ Table "public.stationmeta_annotations" - +----------------+--------------------------+-----------+----------+----------------------------------------------------+ - | Column | Type | Collation | Nullable | Default | - +================+==========================+===========+==========+====================================================+ - | id | integer | | not null | nextval('station_annotations_id_seq'::regclass) | - +----------------+--------------------------+-----------+----------+----------------------------------------------------+ - | kind | integer | | not null | | - +----------------+--------------------------+-----------+----------+----------------------------------------------------+ - | text | text | | not null | | - +----------------+--------------------------+-----------+----------+----------------------------------------------------+ - | date_added | timestamp with time zone | | not null | | - +----------------+--------------------------+-----------+----------+----------------------------------------------------+ - | approved | boolean | | not null | | - +----------------+--------------------------+-----------+----------+----------------------------------------------------+ - | contributor_id | integer | | not null | | - +----------------+--------------------------+-----------+----------+----------------------------------------------------+ + +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ + | Column | Type | Collation | Nullable | Default | + +================+==========================+===========+==========+========================================================+ + | id | integer | | not null | nextval('stationmeta_annotations_id_seq'::regclass) | + +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ + | kind | integer | | not null | | + +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ + | text | text | | not null | | + +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ + | date_added | timestamp with time zone | | not null | | + +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ + | approved | boolean | | not null | | + +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ + | contributor_id | integer | | not null | | + +----------------+--------------------------+-----------+----------+--------------------------------------------------------+ Indexes: "stationmeta_annotations_pkey" PRIMARY KEY, btree (id) "stationmeta_annotations_contributor_id_a5009820" btree (contributor_id) @@ -48,7 +49,7 @@ class StationmetaAnnotation(Base): CheckConstraint('kind >= 0'), ) - id = Column(Integer, primary_key=True, server_default=text("nextval('stationmeta_annotations_id_seq'::regclass)")) + id = Column(Integer, STATIONMETA_ANNOTATIONS_ID_SEQ, primary_key=True, server_default=STATIONMETA_ANNOTATIONS_ID_SEQ.next_value()) kind = Column(Integer, nullable=False) text = Column(Text, nullable=False) date_added = Column(DateTime(True), nullable=False) diff --git a/toardb/stationmeta/models_aux.py b/toardb/stationmeta/models_aux.py index 3f754c7e413bcb83515b07c6da4af46540a349c6..eb42b8675e94fe0bb2b242641ec2f4b2c27b7556 100644 --- a/toardb/stationmeta/models_aux.py +++ b/toardb/stationmeta/models_aux.py @@ -12,12 +12,13 @@ class StationMetaAuxDoc (Base) class StationMetaAuxImage (Base) -------------------------------- """ -from sqlalchemy import CheckConstraint, Column, DateTime, ForeignKey, Integer, String, Text, text +from sqlalchemy import CheckConstraint, Column, DateTime, ForeignKey, Integer, String, Text, Sequence #from sqlalchemy.orm import relationship from .models_core import StationmetaCore from toardb.base import Base +STATIONMETA_AUX_DOC_ID_SEQ = Sequence('stationmeta_aux_doc_id_seq') #define sequence explicitly class StationmetaAuxDoc(Base): """ Table "public.stationmeta_aux_doc" @@ -43,7 +44,7 @@ class StationmetaAuxDoc(Base): __tablename__ = 'stationmeta_aux_doc' - id = Column(Integer, primary_key=True, server_default=text("nextval('stationmeta_aux_docs_id_seq'::regclass)")) + id = Column(Integer, STATIONMETA_AUX_DOC_ID_SEQ, primary_key=True, server_default=STATIONMETA_AUX_DOC_ID_SEQ.next_value()) resource_description = Column(Text, nullable=False) date_added = Column(DateTime(True), nullable=False) resource = Column(String(100), nullable=False) @@ -52,6 +53,7 @@ class StationmetaAuxDoc(Base): # station = relationship('StationmetaCore') +STATIONMETA_AUX_IMAGE_ID_SEQ = Sequence('stationmeta_aux_image_id_seq') #define sequence explicitly class StationmetaAuxImage(Base): """ Table "public.stationmeta_aux_image" @@ -88,7 +90,7 @@ class StationmetaAuxImage(Base): CheckConstraint('image_width >= 0') ) - id = Column(Integer, primary_key=True, server_default=text("nextval('stationmeta_aux_images_id_seq'::regclass)")) + id = Column(Integer, STATIONMETA_AUX_IMAGE_ID_SEQ, primary_key=True, server_default=STATIONMETA_AUX_IMAGE_ID_SEQ.next_value()) resource_description = Column(Text, nullable=False) date_added = Column(DateTime(True), nullable=False) resource = Column(String(100), nullable=False) @@ -99,6 +101,7 @@ class StationmetaAuxImage(Base): # station = relationship('StationmetaCore') +STATIONMETA_AUX_URL_ID_SEQ = Sequence('stationmeta_aux_url_id_seq') #define sequence explicitly class StationmetaAuxUrl(Base): """ Table "public.stationmeta_aux_url" @@ -124,7 +127,7 @@ class StationmetaAuxUrl(Base): __tablename__ = 'stationmeta_aux_url' - id = Column(Integer, primary_key=True, server_default=text("nextval('stationmeta_aux_urls_id_seq'::regclass)")) + id = Column(Integer, STATIONMETA_AUX_URL_ID_SEQ, primary_key=True, server_default=STATIONMETA_AUX_URL_ID_SEQ.next_value()) resource_description = Column(Text, nullable=False) date_added = Column(DateTime(True), nullable=False) resource = Column(String(200), nullable=False) diff --git a/toardb/stationmeta/models_core.py b/toardb/stationmeta/models_core.py index e4498c74d968ccd7035cdea8b7427b02b0cb25d3..7b4d23c67cf541e17157297416a633da16da236a 100644 --- a/toardb/stationmeta/models_core.py +++ b/toardb/stationmeta/models_core.py @@ -3,8 +3,8 @@ class StationmetaCore (Base) ============================ """ -from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, text, String, \ - Text, CheckConstraint +from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, String, \ + Text, CheckConstraint, Sequence from geoalchemy2.types import Geometry from sqlalchemy.orm import relationship from sqlalchemy.dialects.postgresql import JSONB, ARRAY @@ -12,7 +12,7 @@ from shapely import wkt from toardb.auth_user.models import AuthUser from toardb.base import Base - +STATIONMETA_CORE_ID_SEQ = Sequence('stationmeta_core_id_seq') # define sequence explicitly class StationmetaCore(Base): """ Table "public.stationmeta_core" @@ -78,7 +78,7 @@ class StationmetaCore(Base): CheckConstraint('type_of_environment >= 0') ) - id = Column(Integer, primary_key=True, server_default=text("nextval('stationmeta_core_id_seq'::regclass)")) + id = Column(Integer, STATIONMETA_CORE_ID_SEQ, primary_key=True, server_default=STATIONMETA_CORE_ID_SEQ.next_value()) codes = Column(ARRAY(String(16))) name = Column(String(128), nullable=False) coordinates = Column(Geometry('POINTZ', 4326)) diff --git a/toardb/stationmeta/models_global.py b/toardb/stationmeta/models_global.py index a4960507b6eb70f0cab0700edbb2ecd9d9d017ba..f9cea75e62769dcba3eb36516631d36edda66b6a 100644 --- a/toardb/stationmeta/models_global.py +++ b/toardb/stationmeta/models_global.py @@ -3,15 +3,15 @@ class StationmetaGlobal (Base) ============================== """ -from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, text, String, \ - Text, CheckConstraint +from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, String, \ + Text, CheckConstraint, Sequence from geoalchemy2.types import Geometry from sqlalchemy.orm import relationship from sqlalchemy.dialects.postgresql import JSONB, ARRAY from .models_core import StationmetaCore from toardb.base import Base - +STATIONMETA_GLOBAL_ID_SEQ = Sequence('stationmeta_global_id_seq') # define sequence explicitly class StationmetaGlobal(Base): """ Table "public.stationmeta_global" @@ -73,7 +73,7 @@ class StationmetaGlobal(Base): CheckConstraint('toar1_category >= 0') ) - id = Column(Integer, primary_key=True, server_default=text("nextval('stationmeta_global_id_seq'::regclass)")) + id = Column(Integer, STATIONMETA_GLOBAL_ID_SEQ, primary_key=True, server_default=STATIONMETA_GLOBAL_ID_SEQ.next_value()) population_density_year2010 = Column(Float(53), nullable=False) max_population_density_25km_year2010 = Column(Float(53), nullable=False) climatic_zone = Column(Integer, nullable=False) diff --git a/toardb/stationmeta/models_global_services.py b/toardb/stationmeta/models_global_services.py index a0c99b7c661c4c3ec5a82d9e9a578da684e1ffc1..5f8f7daf0f9688e52c3aaefe25c3caa387965a2c 100644 --- a/toardb/stationmeta/models_global_services.py +++ b/toardb/stationmeta/models_global_services.py @@ -3,9 +3,10 @@ class StationmetaGlobalService (Base) ===================================== """ -from sqlalchemy import CheckConstraint, Column, Integer, String, text +from sqlalchemy import CheckConstraint, Column, Integer, String, Sequence from toardb.base import Base +STATIONMETA_GLOBAL_SERVICES_ID_SEQ = Sequence('stationmeta_global_services_id_seq') # define sequence explicitly class StationmetaGlobalService(Base): """ Table "public.stationmeta_global_services" @@ -41,7 +42,7 @@ class StationmetaGlobalService(Base): CheckConstraint('service_valid_year >= 0') ) - id = Column(Integer, primary_key=True, server_default=text("nextval('stationmeta_global_services_id_seq'::regclass)")) + id = Column(Integer, STATIONMETA_GLOBAL_SERVICES_ID_SEQ, primary_key=True, server_default=STATIONMETA_GLOBAL_SERVICES_ID_SEQ.next_value()) variable_name = Column(String(64), nullable=False) result_type = Column(Integer, nullable=False) result_nvalues = Column(Integer, nullable=False) diff --git a/toardb/stationmeta/models_role.py b/toardb/stationmeta/models_role.py index 4d6b6602ef54d7324ee6c4a4fb166b4426eabe11..01fd6d3d751fa4ade7c9daba983d0c35938ec819 100644 --- a/toardb/stationmeta/models_role.py +++ b/toardb/stationmeta/models_role.py @@ -3,8 +3,8 @@ class StationmetaRole (Base) ============================ """ -from sqlalchemy import Column, ForeignKey, Integer, text, \ - CheckConstraint, UniqueConstraint, Table +from sqlalchemy import Column, ForeignKey, Integer, \ + CheckConstraint, UniqueConstraint, Table, Sequence from sqlalchemy.orm import relationship from toardb.contacts.models import Person from toardb.base import Base @@ -17,20 +17,21 @@ stationmeta_core_stationmeta_roles_table = Table('stationmeta_core_timeseries_ro ) +STATIONMETA_ROLES_ID_SEQ = Sequence('stationmeta_roles_id_seq') # define sequence explicitly class StationmetaRole(Base): """ Table "public.stationmeta_roles" - +------------+---------+-----------+----------+-------------------------------------------+ - | Column | Type | Collation | Nullable | Default | - +============+=========+===========+==========+===========================================+ - | id | integer | | not null | nextval('station_roles_id_seq'::regclass) | - +------------+---------+-----------+----------+-------------------------------------------+ - | role | integer | | not null | | - +------------+---------+-----------+----------+-------------------------------------------+ - | status | integer | | not null | | - +------------+---------+-----------+----------+-------------------------------------------+ - | person_id | integer | | not null | | - +------------+---------+-----------+----------+-------------------------------------------+ + +------------+---------+-----------+----------+-----------------------------------------------+ + | Column | Type | Collation | Nullable | Default | + +============+=========+===========+==========+===============================================+ + | id | integer | | not null | nextval('stationmeta_roles_id_seq'::regclass) | + +------------+---------+-----------+----------+-----------------------------------------------+ + | role | integer | | not null | | + +------------+---------+-----------+----------+-----------------------------------------------+ + | status | integer | | not null | | + +------------+---------+-----------+----------+-----------------------------------------------+ + | person_id | integer | | not null | | + +------------+---------+-----------+----------+-----------------------------------------------+ Indexes: "stationmeta_roles_pkey" PRIMARY KEY, btree (id) "stationmeta_roles_person_id_3bd9c160" btree (person_id) @@ -47,7 +48,7 @@ class StationmetaRole(Base): CheckConstraint('status >= 0') ) - id = Column(Integer, primary_key=True, server_default=text("nextval('stationmeta_roles_id_seq'::regclass)")) + id = Column(Integer, STATIONMETA_ROLES_ID_SEQ, primary_key=True, server_default=STATIONMETA_ROLES_ID_SEQ.next_value()) role = Column(Integer, nullable=False) status = Column(Integer, nullable=False) # do not use string declaration here (not working for pytest) diff --git a/toardb/stationmeta/stationmeta.py b/toardb/stationmeta/stationmeta.py index 6367f09d1902bb18937c54b353cff30fcb68a32a..a3c100336d13ee89d2df9fa6e598e321178ca0a4 100644 --- a/toardb/stationmeta/stationmeta.py +++ b/toardb/stationmeta/stationmeta.py @@ -7,34 +7,10 @@ from fastapi import APIRouter, Depends, HTTPException, Body from sqlalchemy.orm import Session, sessionmaker from . import crud, schemas from sqlalchemy import create_engine -from toardb.utils.database import DATABASE_URL +from toardb.utils.database import DATABASE_URL, get_db router = APIRouter() -# Dependency -#def get_db(): -# try: -# db = ToarDbSession() -# yield db -# finally: -# db.close() - -# the following to be able to test! -# will later go to utils.database again! -# Dependency -async def get_db(): - engine = create_engine( - DATABASE_URL, #connect_args={"check_same_thread": False} - ) - SessionLocal = sessionmaker(bind=engine) - - try: - db = SessionLocal() - yield db - finally: - db.close() - - # plain views to post and get stationmeta #get all entries of table stationmeta diff --git a/toardb/stationmeta/test_base.py b/toardb/stationmeta/test_base.py deleted file mode 100644 index 55575696b5b2021a36e1776537329e6dfb80ad59..0000000000000000000000000000000000000000 --- a/toardb/stationmeta/test_base.py +++ /dev/null @@ -1,99 +0,0 @@ -#taken from: https://github.com/tiangolo/fastapi/issues/831 -import pytest -from starlette.testclient import TestClient -from typing import Optional, AsyncIterable -from sqlalchemy import create_engine -from sqlalchemy.engine import Engine as Database -from sqlalchemy.orm import Session -from sqlalchemy_utils import database_exists, create_database, drop_database - -from toardb.utils.database import DATABASE_URL -from .models import Base -from toardb.toardb import app -from toardb.stationmeta.stationmeta import get_db - -url = str(DATABASE_URL+ "_test") -_db_conn = create_engine(url) - -def get_test_db_conn() -> Database: - assert _db_conn is not None - return _db_conn - - -def get_test_db() -> AsyncIterable[Session]: - sess = Session(bind=_db_conn) - - try: - yield sess - finally: - sess.close() - - -@pytest.fixture(scope="session", autouse=True) -def create_test_database(): - """ - Create a clean database on every test case. - We use the `sqlalchemy_utils` package here for a few helpers in consistently - creating and dropping the database. - """ - if database_exists(url): - drop_database(url) - create_database(url) # Create the test database. - #'create_all' does not work (because of undefined 'Geometry')! - #declare PostGIS extension! - fake_conn = _db_conn.raw_connection() - fake_cur = fake_conn.cursor() - fake_cur.execute("CREATE EXTENSION postgis") - fake_conn.commit() - # I also need the id_seq tables: - fake_cur.execute("CREATE SEQUENCE public.auth_user_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_core_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_global_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_global_services_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_annotations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_roles_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_aux_docs_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_aux_images_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_aux_urls_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.persons_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.organisations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - Base.metadata.create_all(_db_conn) # Create the tables. - #try with the basics - app.dependency_overrides[get_db] = get_test_db # Mock the Database Dependency - yield # Run the tests. - drop_database(url) # Drop the test database. - - -@pytest.yield_fixture -def test_db_session(): - """Returns an sqlalchemy session, and after the test tears down everything properly.""" - - session = Session(bind=_db_conn) - - yield session - # Drop all data after each test - for tbl in reversed(Base.metadata.sorted_tables): - _db_conn.execute(tbl.delete()) - # put back the connection to the connection pool - session.close() - - -@pytest.fixture() -def client(): - """ - When using the 'client' fixture in test cases, we'll get full database - rollbacks between test cases: - """ - with TestClient(app) as client: - yield client diff --git a/toardb/stationmeta/test_stationmeta.py b/toardb/stationmeta/test_stationmeta.py index b7b9a184fcc1af1801ca5417c014b57bacece194..792815418c373aa28b78b409b693dc144c700b98 100644 --- a/toardb/stationmeta/test_stationmeta.py +++ b/toardb/stationmeta/test_stationmeta.py @@ -4,15 +4,14 @@ from .models import StationmetaCore from toardb.auth_user.models import AuthUser from toardb.contacts.models import Person, Organisation from .schemas import get_geom_from_coordinates, Coordinates -# Required imports 'create_test_database' -from .test_base import ( +from toardb.test_base import ( client, get_test_db, create_test_database, url, + get_test_engine, test_db_session as db, ) -from .test_base import _db_conn class TestApps: def setup(self): @@ -26,6 +25,7 @@ class TestApps: @pytest.fixture(autouse=True) def setup_db_data(self, db): # id_seq will not be reset automatically between tests! + _db_conn = get_test_engine() fake_conn = _db_conn.raw_connection() fake_cur = fake_conn.cursor() fake_cur.execute("ALTER SEQUENCE auth_user_id_seq RESTART WITH 1") @@ -40,11 +40,11 @@ class TestApps: fake_conn.commit() fake_cur.execute("ALTER SEQUENCE stationmeta_roles_id_seq RESTART WITH 1") fake_conn.commit() - fake_cur.execute("ALTER SEQUENCE stationmeta_aux_docs_id_seq RESTART WITH 1") + fake_cur.execute("ALTER SEQUENCE stationmeta_aux_doc_id_seq RESTART WITH 1") fake_conn.commit() - fake_cur.execute("ALTER SEQUENCE stationmeta_aux_images_id_seq RESTART WITH 1") + fake_cur.execute("ALTER SEQUENCE stationmeta_aux_image_id_seq RESTART WITH 1") fake_conn.commit() - fake_cur.execute("ALTER SEQUENCE stationmeta_aux_urls_id_seq RESTART WITH 1") + fake_cur.execute("ALTER SEQUENCE stationmeta_aux_url_id_seq RESTART WITH 1") fake_conn.commit() fake_cur.execute("ALTER SEQUENCE persons_id_seq RESTART WITH 1") fake_conn.commit() diff --git a/toardb/variables/test_base.py b/toardb/test_base.py similarity index 73% rename from toardb/variables/test_base.py rename to toardb/test_base.py index a8b05f14a0129f3f2f12a3802f091833c16b9063..ff85b1aae866c86493552fd7b6897a91c126c2e7 100644 --- a/toardb/variables/test_base.py +++ b/toardb/test_base.py @@ -1,28 +1,25 @@ #taken from: https://github.com/tiangolo/fastapi/issues/831 import pytest from starlette.testclient import TestClient -from typing import Optional, AsyncIterable from sqlalchemy import create_engine -from sqlalchemy.engine import Engine as Database -from sqlalchemy.orm import Session +from sqlalchemy.engine import Engine +from sqlalchemy.orm import sessionmaker from sqlalchemy_utils import database_exists, create_database, drop_database -from toardb.utils.database import DATABASE_URL -from .models import Base +from toardb.base import Base from toardb.toardb import app -from toardb.variables.variables import get_db +from toardb.utils.database import DATABASE_URL, get_db, get_engine url = str(DATABASE_URL+ "_test") _db_conn = create_engine(url) -def get_test_db_conn() -> Database: +def get_test_engine() -> Engine: assert _db_conn is not None return _db_conn -def get_test_db() -> AsyncIterable[Session]: - sess = Session(bind=_db_conn) - +def get_test_db(): + sess = sessionmaker(bind=_db_conn,autoflush=False,autocommit=False)() try: yield sess finally: @@ -40,17 +37,17 @@ def create_test_database(): drop_database(url) create_database(url) # Create the test database. #'create_all' does not work (because of undefined 'Geometry')! - #declare PostGIS extension! + #declare PostGIS extension! (and toar_controlled_vocabulary) fake_conn = _db_conn.raw_connection() fake_cur = fake_conn.cursor() - fake_cur.execute("CREATE EXTENSION postgis") + fake_cur.execute("CREATE EXTENSION IF NOT EXISTS postgis") fake_conn.commit() - # I also need the id_seq tables: - fake_cur.execute("CREATE SEQUENCE public.variables_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") + fake_cur.execute("CREATE EXTENSION IF NOT EXISTS toar_controlled_vocabulary") fake_conn.commit() Base.metadata.create_all(_db_conn) # Create the tables. #try with the basics app.dependency_overrides[get_db] = get_test_db # Mock the Database Dependency + app.dependency_overrides[get_engine] = get_test_engine # Mock the Database Dependency yield # Run the tests. drop_database(url) # Drop the test database. @@ -59,8 +56,7 @@ def create_test_database(): def test_db_session(): """Returns an sqlalchemy session, and after the test tears down everything properly.""" - session = Session(bind=_db_conn) - + session = sessionmaker(bind=_db_conn,autoflush=False,autocommit=False)() yield session # Drop all data after each test for tbl in reversed(Base.metadata.sorted_tables): diff --git a/toardb/timeseries/models_annotation.py b/toardb/timeseries/models_annotation.py index 43b0c3ef5c72985afa130af42e378fded4276383..e24a9624a8e0209b50349c26e610fd07bfe047c3 100644 --- a/toardb/timeseries/models_annotation.py +++ b/toardb/timeseries/models_annotation.py @@ -4,7 +4,7 @@ class TimeseriesAnnotation(Base) ================================ """ from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, text, String, \ - Text, Boolean, CheckConstraint, Table + Text, Boolean, CheckConstraint, Table, Sequence from sqlalchemy.orm import relationship from toardb.auth_user.models import AuthUser from toardb.base import Base @@ -16,6 +16,7 @@ timeseries_timeseries_annotations_table = Table('timeseries_timeseries_annotatio ) +TIMESERIES_ANNOTATIONS_ID_SEQ = Sequence('timeseries_annotations_id_seq') # define sequence explicitly class TimeseriesAnnotation(Base): """ Table "public.timeseries_annotations" @@ -47,7 +48,7 @@ class TimeseriesAnnotation(Base): CheckConstraint('kind >= 0'), ) - id = Column(Integer, primary_key=True, server_default=text("nextval('timeseries_annotations_id_seq'::regclass)")) + id = Column(Integer, TIMESERIES_ANNOTATIONS_ID_SEQ, primary_key=True, server_default=TIMESERIES_ANNOTATIONS_ID_SEQ.next_value()) kind = Column(Integer, nullable=False) text = Column(Text, nullable=False) date_added = Column(DateTime(True), nullable=False) diff --git a/toardb/timeseries/models_core.py b/toardb/timeseries/models_core.py index 81df7e15fe71d574410cfae85ad235550dd6b35a..b69d0e0627b573e347a84d582ba8d6a7a7e9e22b 100644 --- a/toardb/timeseries/models_core.py +++ b/toardb/timeseries/models_core.py @@ -4,13 +4,15 @@ class Timeseries (Base) ======================= """ from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, text, String, \ - Text, CheckConstraint, UniqueConstraint, PrimaryKeyConstraint + Text, CheckConstraint, UniqueConstraint, PrimaryKeyConstraint, \ + Sequence from sqlalchemy.dialects.postgresql import JSONB from toardb.stationmeta.models import StationmetaCore from toardb.variables.models import Variable from toardb.base import Base +TIMESERIES_ID_SEQ = Sequence('timeseries_id_seq') # define sequence explicitly class Timeseries(Base): """ Table "public.timeseries" @@ -76,7 +78,7 @@ class Timeseries(Base): UniqueConstraint('station_id', 'variable_id', 'label'), ) - id = Column(Integer, primary_key=True, server_default=text("nextval('timeseries_id_seq'::regclass)")) + id = Column(Integer, TIMESERIES_ID_SEQ, primary_key=True, server_default=TIMESERIES_ID_SEQ.next_value()) label = Column(String(128), nullable=False) order = Column(Integer, nullable=False) access_rights = Column(Integer, nullable=False) diff --git a/toardb/timeseries/models_programme.py b/toardb/timeseries/models_programme.py index d293905a436ba0a54d97c900137c24cd359672c1..fc44d596527dbecfb18b7deda4d4de62aa1544ee 100644 --- a/toardb/timeseries/models_programme.py +++ b/toardb/timeseries/models_programme.py @@ -3,7 +3,7 @@ class TimeseriesProgramme (Base) ================================ """ -from sqlalchemy import Column, Integer, text, String, Text, ForeignKey, Table +from sqlalchemy import Column, Integer, text, String, Text, ForeignKey, Table, Sequence from sqlalchemy.orm import relationship from toardb.base import Base @@ -13,7 +13,8 @@ timeseries_timeseries_programmes_table = Table('timeseries_timeseries_programmes Column('programme_id', Integer, ForeignKey('timeseries_programmes.id')) ) -# this has at the moment no relation to anything!!! + +TIMESERIES_PROGRAMMES_ID_SEQ = Sequence('timeseries_programmes_id_seq') # define sequence explicitly class TimeseriesProgramme(Base): """ Table "public.timeseries_programmes" @@ -35,7 +36,7 @@ class TimeseriesProgramme(Base): """ __tablename__ = 'timeseries_programmes' - id = Column(Integer, primary_key=True, server_default=text("nextval('timeseries_programmes_id_seq'::regclass)")) + id = Column(Integer, TIMESERIES_PROGRAMMES_ID_SEQ, primary_key=True, server_default=TIMESERIES_PROGRAMMES_ID_SEQ.next_value()) name = Column(String(32), nullable=False) longname = Column(String(128), nullable=False) homepage = Column(String(200), nullable=False) diff --git a/toardb/timeseries/models_role.py b/toardb/timeseries/models_role.py index fbfa87981337cba805b1d0ab18f85d4b786ca6c5..eca3f3e376a0ba16b1f9cce159e1e1cece422daa 100644 --- a/toardb/timeseries/models_role.py +++ b/toardb/timeseries/models_role.py @@ -5,7 +5,7 @@ class TimeseriesRole (Base) """ from sqlalchemy import Column, ForeignKey, Integer, text, \ CheckConstraint, UniqueConstraint, \ - Table + Table, Sequence from sqlalchemy.orm import relationship from toardb.contacts.models import Person from toardb.base import Base @@ -17,7 +17,7 @@ timeseries_timeseries_roles_table = Table('timeseries_timeseries_roles', Base.me Column('role_id', Integer, ForeignKey('timeseries_roles.id')) ) - +TIMESERIES_ROLES_ID_SEQ = Sequence('timeseries_roles_id_seq') # define sequence explicitly class TimeseriesRole(Base): """ Table "public.timeseries_roles" @@ -50,7 +50,7 @@ class TimeseriesRole(Base): UniqueConstraint('role', 'person_id') ) - id = Column(Integer, primary_key=True, server_default=text("nextval('timeseries_roles_id_seq'::regclass)")) + id = Column(Integer, TIMESERIES_ROLES_ID_SEQ, primary_key=True, server_default=TIMESERIES_ROLES_ID_SEQ.next_value()) role = Column(Integer, nullable=False) status = Column(Integer, nullable=False) # do not use string declaration here (not working for pytest) diff --git a/toardb/timeseries/test_base.py b/toardb/timeseries/test_base.py deleted file mode 100644 index 0906f4b5e617430be4ec3d332ba897506af947cd..0000000000000000000000000000000000000000 --- a/toardb/timeseries/test_base.py +++ /dev/null @@ -1,114 +0,0 @@ -#taken from: https://github.com/tiangolo/fastapi/issues/831 -import pytest -from starlette.testclient import TestClient -from typing import Optional, AsyncIterable -from sqlalchemy import create_engine -from sqlalchemy.engine import Engine as Database -from sqlalchemy.orm import Session -from sqlalchemy_utils import database_exists, create_database, drop_database - -from toardb.utils.database import DATABASE_URL -from .models import Base -from toardb.toardb import app -from toardb.timeseries.timeseries import get_db - -url = str(DATABASE_URL+ "_test") -_db_conn = create_engine(url) - -def get_test_db_conn() -> Database: - assert _db_conn is not None - return _db_conn - - -def get_test_db() -> AsyncIterable[Session]: - sess = Session(bind=_db_conn) - - try: - yield sess - finally: - sess.close() - - -@pytest.fixture(scope="session", autouse=True) -def create_test_database(): - """ - Create a clean database on every test case. - We use the `sqlalchemy_utils` package here for a few helpers in consistently - creating and dropping the database. - """ - if database_exists(url): - drop_database(url) - create_database(url) # Create the test database. - #'create_all' does not work (because of undefined 'Geometry')! - #declare PostGIS extension! - fake_conn = _db_conn.raw_connection() - fake_cur = fake_conn.cursor() - fake_cur.execute("CREATE EXTENSION postgis") - fake_conn.commit() - # I also need the id_seq tables: - fake_cur.execute("CREATE SEQUENCE public.auth_user_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.variables_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_core_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_global_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_global_services_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_roles_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_annotations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_aux_docs_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_aux_images_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.stationmeta_aux_urls_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.persons_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.organisations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.timeseries_annotations_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.timeseries_roles_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.timeseries_programmes_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - fake_cur.execute("CREATE SEQUENCE public.timeseries_id_seq AS integer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1") - fake_conn.commit() - # just to show that tables are available now: -# fake_cur.execute("SELECT * FROM pg_catalog.pg_tables WHERE schemaname != 'pg_catalog' AND schemaname != 'information_schema'") -# rows = fake_cur.fetchall() -# for row in rows: -# print(row) - Base.metadata.create_all(_db_conn) # Create the tables. - #try with the basics - app.dependency_overrides[get_db] = get_test_db # Mock the Database Dependency - yield # Run the tests. - drop_database(url) # Drop the test database. - - -@pytest.yield_fixture -def test_db_session(): - """Returns an sqlalchemy session, and after the test tears down everything properly.""" - - session = Session(bind=_db_conn) - - yield session - # Drop all data after each test - for tbl in reversed(Base.metadata.sorted_tables): - _db_conn.execute(tbl.delete()) - # put back the connection to the connection pool - session.close() - - -@pytest.fixture() -def client(): - """ - When using the 'client' fixture in test cases, we'll get full database - rollbacks between test cases: - """ - with TestClient(app) as client: - yield client diff --git a/toardb/timeseries/test_timeseries.py b/toardb/timeseries/test_timeseries.py index 37f74fe46203162bdff0120099593e36c9802ebf..de006943d659ee6f24a99b2a667f0d5809908889 100644 --- a/toardb/timeseries/test_timeseries.py +++ b/toardb/timeseries/test_timeseries.py @@ -7,14 +7,14 @@ from toardb.variables.models import Variable from toardb.contacts.models import Person, Organisation from toardb.auth_user.models import AuthUser # Required imports 'create_test_database' -from .test_base import ( +from toardb.test_base import ( client, get_test_db, create_test_database, url, + get_test_engine, test_db_session as db, ) -from .test_base import _db_conn class TestApps: def setup(self): @@ -27,6 +27,8 @@ class TestApps: """ @pytest.fixture(autouse=True) def setup_db_data(self, db): + _db_conn = get_test_engine() + print(_db_conn) # id_seq will not be reset automatically between tests! fake_conn = _db_conn.raw_connection() fake_cur = fake_conn.cursor() @@ -44,11 +46,11 @@ class TestApps: fake_conn.commit() fake_cur.execute("ALTER SEQUENCE stationmeta_annotations_id_seq RESTART WITH 1") fake_conn.commit() - fake_cur.execute("ALTER SEQUENCE stationmeta_aux_docs_id_seq RESTART WITH 1") + fake_cur.execute("ALTER SEQUENCE stationmeta_aux_doc_id_seq RESTART WITH 1") fake_conn.commit() - fake_cur.execute("ALTER SEQUENCE stationmeta_aux_images_id_seq RESTART WITH 1") + fake_cur.execute("ALTER SEQUENCE stationmeta_aux_image_id_seq RESTART WITH 1") fake_conn.commit() - fake_cur.execute("ALTER SEQUENCE stationmeta_aux_urls_id_seq RESTART WITH 1") + fake_cur.execute("ALTER SEQUENCE stationmeta_aux_url_id_seq RESTART WITH 1") fake_conn.commit() fake_cur.execute("ALTER SEQUENCE persons_id_seq RESTART WITH 1") fake_conn.commit() @@ -119,9 +121,11 @@ class TestApps: def test_get_timeseries(self, client, db): + print("==============Client: ================", client.base_url) response = client.get("/timeseries/") expected_status_code = 200 assert response.status_code == expected_status_code + print("I got: ", response.json()) expected_resp = [{'id': 1, 'label': 'CMA', 'order': 1, 'access_rights': 0, 'sampling_frequency': 0, 'aggregation': 0, 'data_start_date': '2003-09-07T15:30:00+02:00', 'data_end_date': '2016-12-31T14:30:00+01:00', diff --git a/toardb/timeseries/timeseries.py b/toardb/timeseries/timeseries.py index de1819b099dfee8c05097e3993f96031626813ff..617bd82da0dd98fecb239410c7bedc32f45b8199 100644 --- a/toardb/timeseries/timeseries.py +++ b/toardb/timeseries/timeseries.py @@ -6,20 +6,10 @@ from typing import List from fastapi import APIRouter, Depends, HTTPException, Body from sqlalchemy.orm import Session from . import crud, schemas -from toardb.utils.database import ToarDbSession +from toardb.utils.database import ToarDbSession, get_db router = APIRouter() -# Dependency -def get_db(): - try: - db = ToarDbSession() - yield db - finally: - db.close() - - - # plain views to post and get timeseries #get all entries of table timeseries diff --git a/toardb/utils/database.py b/toardb/utils/database.py index b31d57dcd7e499c4695528c859a6599315b2c75b..d31e48577dfc7b55a8adfd2dd9ccd04c590fb1a2 100644 --- a/toardb/utils/database.py +++ b/toardb/utils/database.py @@ -9,3 +9,16 @@ DATABASE_URL = "postgresql://toaradmin:toar2@localhost:5432/toardb" engine = create_engine(DATABASE_URL) ToarDbSession = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +# Dependency +def get_engine(): + assert engine is not None + return engine + +# Dependency +def get_db(): + try: + db = ToarDbSession() + yield db + finally: + db.close() diff --git a/toardb/variables/models.py b/toardb/variables/models.py index 06a6511c165a7e825a05fade2d81cde7387746ba..22315aac47a6e519bf9c0b52c003f63d52b6ff37 100644 --- a/toardb/variables/models.py +++ b/toardb/variables/models.py @@ -1,11 +1,12 @@ # coding: utf-8 -from sqlalchemy import ARRAY, BigInteger, Boolean, CheckConstraint, Column, DateTime, Float, ForeignKey, Index, Integer, SmallInteger, String, Text, UniqueConstraint, text +from sqlalchemy import Column, Integer, String, Sequence from sqlalchemy.orm import relationship from sqlalchemy.sql.sqltypes import NullType from sqlalchemy.dialects.postgresql import JSONB from toardb.base import Base +VARIABLES_ID_SEQ = Sequence('variables_id_seq') # define sequence explicitly class Variable(Base): """ Table "public.variables" @@ -35,7 +36,7 @@ class Variable(Base): """ __tablename__ = 'variables' - id = Column(Integer, primary_key=True, server_default=text("nextval('variables_id_seq'::regclass)")) + id = Column(Integer, VARIABLES_ID_SEQ, primary_key=True, server_default=VARIABLES_ID_SEQ.next_value()) name = Column(String(32), nullable=False, unique=True) longname = Column(String(128), nullable=False) displayname = Column(String(128), nullable=False) diff --git a/toardb/variables/test_variables.py b/toardb/variables/test_variables.py index c58b2d03aa46c9cd082109a82708536fa1973839..538428d52c6ee24ebce023aee32aee98ee49269b 100644 --- a/toardb/variables/test_variables.py +++ b/toardb/variables/test_variables.py @@ -2,14 +2,14 @@ import pytest import json from .models import Variable # Required imports 'create_test_database' -from .test_base import ( +from toardb.test_base import ( client, get_test_db, create_test_database, url, + get_test_engine, test_db_session as db, ) -from .test_base import _db_conn class TestApps: def setup(self): @@ -23,6 +23,7 @@ class TestApps: @pytest.fixture(autouse=True) def setup_db_data(self, db): # id_seq will not be reset automatically between tests! + _db_conn = get_test_engine() fake_conn = _db_conn.raw_connection() fake_cur = fake_conn.cursor() fake_cur.execute("ALTER SEQUENCE variables_id_seq RESTART WITH 1") diff --git a/toardb/variables/variables.py b/toardb/variables/variables.py index dbc633c6a5db77dfc12ded2044edd5f260149c1a..55ddc2bc7d2cf760a2b585fb787bc46cce9b1a0e 100644 --- a/toardb/variables/variables.py +++ b/toardb/variables/variables.py @@ -6,19 +6,10 @@ from typing import List from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from toardb.variables import crud, schemas -from toardb.utils.database import ToarDbSession +from toardb.utils.database import ToarDbSession, get_db router= APIRouter() -# Dependency -def get_db(): - try: - db = ToarDbSession() - yield db - finally: - db.close() - - # plain views to post and get variables @router.post('/variables/', response_model=schemas.Variable) def create_variable(variable: schemas.VariableCreate, db: Session = Depends(get_db)):