Included creation and dropping of test db for the tests

This commit is contained in:
Peter Yefi 2022-11-25 18:21:09 -05:00
parent 4d01eeba50
commit c50b202e5d
10 changed files with 115 additions and 64 deletions

View File

@ -38,3 +38,13 @@ TEST_DB_PASSWORD=postgres-database-password
TEST_DB_HOST=database-host TEST_DB_HOST=database-host
TEST_DB_PORT=database-port TEST_DB_PORT=database-port
``` ```
### Database Related Unit Test
Unit tests that involve database operations require a Postgres database to be set up.
The tests connect to the database server using the default postgres user (*postgres*).
NB: You can provide any credentials for the test to connect to postgres, just make sure
the credentials are set in your .env file as explained above in *Database Configuration Parameters* section
When the tests are run, a **test_db** database is created and then the required tables for
the test. Before the tests run, the *test_db* is deleted to ensure that each test starts
on a clean slate

View File

@ -13,10 +13,9 @@ from sqlalchemy.orm import Session
class BaseRepo: class BaseRepo:
def __init__(self, db_name, app_env='TEST'): def __init__(self, db_name, app_env='TEST'):
config = BaseConfiguration(db_name, app_env) self.config = BaseConfiguration(db_name, app_env)
engine = create_engine(config.conn_string()) self.engine = create_engine(self.config.conn_string())
self.config = config self.session = Session(self.engine)
self.session = Session(engine)
def __del__(self): def __del__(self):
""" """
@ -28,3 +27,4 @@ class BaseRepo:

View File

@ -39,4 +39,7 @@ class BaseConfiguration(object):
""" """
if self._db_pass: if self._db_pass:
return f'postgresql://{self._db_user}:{self._db_pass}@{self._db_host}:{self._db_port}/{self._db_name}' return f'postgresql://{self._db_user}:{self._db_pass}@{self._db_host}:{self._db_port}/{self._db_name}'
return f'postgresql://{self._db_user}@{self._db_host}:{self._db_port}/{self._db_name}' return f'postgresql://{self._db_user}@{self._db_host}:{self._db_port}/{self._db_name}'
def get_db_user(self):
return self._db_user

View File

@ -31,3 +31,12 @@ class City(Base):
city_version = Column(Integer, nullable=False) city_version = Column(Integer, nullable=False)
created = Column(DateTime, default=datetime.datetime.utcnow) created = Column(DateTime, default=datetime.datetime.utcnow)
def __init__(self, city, name, srs_name, country_code, l_corner, u_corner):
self.city = city
self.name = name
self.srs_name = srs_name
self.country_code = country_code
self.lower_corner = l_corner.tolist()
self.upper_corner = u_corner.tolist()

View File

@ -74,3 +74,13 @@ class HeatPumpSimulation(Base):
hp_supply_temp = Column(Float, nullable=False) hp_supply_temp = Column(Float, nullable=False)
created = Column(DateTime, default=datetime.datetime.utcnow) created = Column(DateTime, default=datetime.datetime.utcnow)
def __init__(self, city_id, hourly_elec_demand, daily_elec_demand, monthly_elec_demand, daily_fossil, monthly_fossil):
self.city_id = city_id
self.hourly_electricity_demand = hourly_elec_demand
self.daily_electricity_demand = daily_elec_demand
self.monthly_electricity_demand = monthly_elec_demand
self.daily_fossil_fuel_consumption = daily_fossil
self.monthly_fossil_fuel_consumption = monthly_fossil

View File

@ -9,7 +9,6 @@ from city_model_structure.city import City
from persistence import BaseRepo from persistence import BaseRepo
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy import select from sqlalchemy import select
from helpers.city_util import CityUtil
from persistence.models import City as DBCity from persistence.models import City as DBCity
import pickle import pickle
import requests import requests
@ -22,7 +21,6 @@ class CityRepo(BaseRepo):
def __init__(self, db_name, app_env): def __init__(self, db_name, app_env):
super().__init__(db_name, app_env) super().__init__(db_name, app_env)
self._city_util = CityUtil()
def __new__(cls, db_name, app_env): def __new__(cls, db_name, app_env):
""" """
@ -33,17 +31,12 @@ class CityRepo(BaseRepo):
return cls._instance return cls._instance
def insert(self, city: City) -> Union[City, Dict]: def insert(self, city: City) -> Union[City, Dict]:
db_city = DBCity() db_city = DBCity(pickle.dumps(city), city.name, city.srs_name, city.country_code, city.lower_corner,
db_city.name = city.name city.upper_corner)
db_city.climate_reference_city = city.climate_reference_city db_city.climate_reference_city = city.climate_reference_city
db_city.srs_name = city.srs_name
db_city.longitude = city.longitude db_city.longitude = city.longitude
db_city.latitude = city.latitude db_city.latitude = city.latitude
db_city.country_code = city.country_code
db_city.time_zone = city.time_zone db_city.time_zone = city.time_zone
db_city.lower_corner = city.lower_corner.tolist()
db_city.upper_corner = city.upper_corner.tolist()
db_city.city = pickle.dumps(city)
try: try:
# Retrieve hub project latest release # Retrieve hub project latest release
@ -137,8 +130,7 @@ class CityRepo(BaseRepo):
:return: a city :return: a city
""" """
try: try:
self.session.query(DBCity).filter(DBCity.id == city_id).delete() self.session.query(DBCity).filter(DBCity.id == city_id).delete()
self.session.commit() self.session.commit()
except SQLAlchemyError as err: except SQLAlchemyError as err:
print(f'Error while fetching city: {err}') print(f'Error while fetching city: {err}')

View File

@ -27,10 +27,10 @@ class HeatPumpSimulationRepo(BaseRepo):
cls._instance = super(HeatPumpSimulationRepo, cls).__new__(cls) cls._instance = super(HeatPumpSimulationRepo, cls).__new__(cls)
return cls._instance return cls._instance
def insert(self, hp_simulation_data: Dict, city_id: int) -> Union[HeatPumpSimulation, Dict]: def insert(self, hp_sim_data: Dict, city_id: int) -> Union[HeatPumpSimulation, Dict]:
""" """
Inserts the results of heat pump simulation Inserts the results of heat pump simulation
:param hp_simulation_data: dictionary with heatpump the simulation inputs and output :param hp_sim_data: dictionary with heatpump the simulation inputs and output
:param city_id: the city that was used in running the simulation :param city_id: the city that was used in running the simulation
:return: HeatPumpSimulation :return: HeatPumpSimulation
""" """
@ -40,27 +40,25 @@ class HeatPumpSimulationRepo(BaseRepo):
return {'message': 'city not found in database'} return {'message': 'city not found in database'}
try: try:
hp_simulation = HeatPumpSimulation() hp_simulation = HeatPumpSimulation(city_id, hp_sim_data["HourlyElectricityDemand"],
hp_sim_data["DailyElectricityDemand"], hp_sim_data["MonthlyElectricityDemand"],
hp_sim_data["DailyFossilFuelConsumption"],
hp_sim_data["MonthlyFossilFuelConsumption"])
hp_simulation.city_id = city_id hp_simulation.city_id = city_id
hp_simulation.end_year = hp_simulation_data["EndYear"] hp_simulation.end_year = hp_sim_data["EndYear"]
hp_simulation.start_year = hp_simulation_data["StartYear"] hp_simulation.start_year = hp_sim_data["StartYear"]
hp_simulation.max_demand_storage_hour = hp_simulation_data["HoursOfStorageAtMaxDemand"] hp_simulation.max_demand_storage_hour = hp_sim_data["HoursOfStorageAtMaxDemand"]
hp_simulation.max_hp_energy_input = hp_simulation_data["MaximumHPEnergyInput"] hp_simulation.max_hp_energy_input = hp_sim_data["MaximumHPEnergyInput"]
hp_simulation.building_supply_temp = hp_simulation_data["BuildingSuppTemp"] hp_simulation.building_supply_temp = hp_sim_data["BuildingSuppTemp"]
hp_simulation.temp_difference = hp_simulation_data["TemperatureDifference"] hp_simulation.temp_difference = hp_sim_data["TemperatureDifference"]
hp_simulation.fuel_lhv = hp_simulation_data["FuelLHV"] hp_simulation.fuel_lhv = hp_sim_data["FuelLHV"]
hp_simulation.fuel_price = hp_simulation_data["FuelPrice"] hp_simulation.fuel_price = hp_sim_data["FuelPrice"]
hp_simulation.fuel_efficiency = hp_simulation_data["FuelEF"] hp_simulation.fuel_efficiency = hp_sim_data["FuelEF"]
hp_simulation.fuel_density = hp_simulation_data["FuelDensity"] hp_simulation.fuel_density = hp_sim_data["FuelDensity"]
hp_simulation.hp_supply_temp = hp_simulation_data["HPSupTemp"] hp_simulation.hp_supply_temp = hp_sim_data["HPSupTemp"]
hp_simulation.daily_electricity_demand = hp_simulation_data["DailyElectricityDemand"] hp_simulation.simulation_type = hp_sim_data["SimulationType"]
hp_simulation.hourly_electricity_demand = hp_simulation_data["HourlyElectricityDemand"] hp_simulation.heat_pump_model = hp_sim_data["HeatPumpModel"]
hp_simulation.monthly_electricity_demand = hp_simulation_data["MonthlyElectricityDemand"] hp_simulation.heat_pump_type = hp_sim_data["HeatPumpType"]
hp_simulation.daily_fossil_fuel_consumption = hp_simulation_data["DailyFossilFuelConsumption"]
hp_simulation.monthly_fossil_fuel_consumption = hp_simulation_data["MonthlyFossilFuelConsumption"]
hp_simulation.simulation_type = hp_simulation_data["SimulationType"]
hp_simulation.heat_pump_model = hp_simulation_data["HeatPumpModel"]
hp_simulation.heat_pump_type = hp_simulation_data["HeatPumpType"]
# Persist heat pump simulation data # Persist heat pump simulation data
self.session.add(hp_simulation) self.session.add(hp_simulation)

View File

@ -17,4 +17,4 @@ scipy
PyYAML PyYAML
pyecore==0.12.2 pyecore==0.12.2
python-dotenv python-dotenv
SQLAlchemy SQLAlchemy

View File

@ -8,10 +8,11 @@ from unittest import TestCase
from imports.geometry_factory import GeometryFactory from imports.geometry_factory import GeometryFactory
from imports.db_factory import DBFactory from imports.db_factory import DBFactory
from exports.db_factory import DBFactory as ExportDBFactory from exports.db_factory import DBFactory as ExportDBFactory
from persistence.db_config import BaseConfiguration from persistence.base_repo import BaseRepo
from sqlalchemy import create_engine from sqlalchemy import create_engine
from persistence.models import City from persistence.models import City
from pickle import loads from pickle import loads
from sqlalchemy.exc import ProgrammingError
class TestDBFactory(TestCase): class TestDBFactory(TestCase):
@ -19,20 +20,36 @@ class TestDBFactory(TestCase):
TestDBFactory TestDBFactory
""" """
def setUp(self) -> None: @classmethod
def setUpClass(cls) -> None:
""" """
Test setup Test setup
:return: None :return: None
""" """
# Create test tables if they do not exit # Create test database
config = BaseConfiguration(db_name='hub_test', app_env='TEST') repo = BaseRepo(db_name='test_db', app_env='TEST')
engine = create_engine(config.conn_string()) eng = create_engine(f'postgresql://{repo.config.get_db_user()}@/{repo.config.get_db_user()}')
City.__table__.create(bind=engine, checkfirst=True)
try:
# delete test database if it exists
conn = eng.connect()
conn.execute('commit')
conn.execute('DROP DATABASE test_db')
conn.close()
except ProgrammingError as err:
print(f'Database does not exist. Nothing to delete')
cnn = eng.connect()
cnn.execute('commit')
cnn.execute("CREATE DATABASE test_db")
cnn.close()
City.__table__.create(bind=repo.engine, checkfirst=True)
city_file = "../unittests/tests_data/C40_Final.gml" city_file = "../unittests/tests_data/C40_Final.gml"
self.city = GeometryFactory('citygml', city_file).city cls.city = GeometryFactory('citygml', city_file).city
self._db_factory = DBFactory(city=self.city, db_name='hub_test', app_env='TEST') cls._db_factory = DBFactory(city=cls.city, db_name='test_db', app_env='TEST')
self._export_db_factory = ExportDBFactory(city=self.city, db_name='hub_test', app_env='TEST') cls._export_db_factory = ExportDBFactory(city=cls.city, db_name='test_db', app_env='TEST')
def test_save_city(self): def test_save_city(self):
saved_city = self._db_factory.persist_city() saved_city = self._db_factory.persist_city()
@ -71,6 +88,3 @@ class TestDBFactory(TestCase):
self.assertEqual(updated_city.longitude, 1.43589) self.assertEqual(updated_city.longitude, 1.43589)
self.assertEqual(updated_city.latitude, -9.38928339) self.assertEqual(updated_city.latitude, -9.38928339)
self._db_factory.delete_city(city.id) self._db_factory.delete_city(city.id)

View File

@ -10,12 +10,13 @@ from imports.energy_systems_factory import EnergySystemsFactory
from exports.energy_systems_factory import EnergySystemsExportFactory from exports.energy_systems_factory import EnergySystemsExportFactory
from imports.db_factory import DBFactory from imports.db_factory import DBFactory
from exports.db_factory import DBFactory as ExportDBFactory from exports.db_factory import DBFactory as ExportDBFactory
from persistence.db_config import BaseConfiguration from persistence.base_repo import BaseRepo
from sqlalchemy import create_engine from sqlalchemy import create_engine
from persistence.models import City from persistence.models import City
from persistence.models import SimulationTypes from persistence.models import SimulationTypes
from persistence.models import HeatPumpTypes from persistence.models import HeatPumpTypes
from persistence.models import HeatPumpSimulation from persistence.models import HeatPumpSimulation
from sqlalchemy.exc import ProgrammingError
# User defined paramenters # User defined paramenters
hp_sim_data = { hp_sim_data = {
@ -37,24 +38,38 @@ class TestHeatPumpSimulation(TestCase):
""" """
Heat pump simulation test cases Heat pump simulation test cases
""" """
@classmethod
def setUp(self) -> None: def setUpClass(cls) -> None:
""" """
Test setup Test setup
:return: None :return: None
""" """
repo = BaseRepo(db_name='test_db', app_env='TEST')
eng = create_engine(f'postgresql://{repo.config.get_db_user()}@/{repo.config.get_db_user()}')
try:
conn = eng.connect()
conn.execute('commit')
conn.execute('DROP DATABASE test_db')
conn.close()
except ProgrammingError as err:
print(f'Database does not exist. Nothing to delete')
cnn = eng.connect()
cnn.execute('commit')
cnn.execute("CREATE DATABASE test_db")
cnn.close()
# Create test tables if they do not exit # Create test tables if they do not exit
config = BaseConfiguration(db_name='hub_test', app_env='TEST') City.__table__.create(bind=repo.engine, checkfirst=True)
engine = create_engine(config.conn_string()) HeatPumpSimulation.__table__.create(bind=repo.engine, checkfirst=True)
City.__table__.create(bind=engine, checkfirst=True)
HeatPumpSimulation.__table__.create(bind=engine, checkfirst=True)
city_file = "../unittests/tests_data/C40_Final.gml" city_file = "../unittests/tests_data/C40_Final.gml"
self._city = GeometryFactory('citygml', city_file).city cls._city = GeometryFactory('citygml', city_file).city
EnergySystemsFactory('air source hp', self._city).enrich() EnergySystemsFactory('air source hp', cls._city).enrich()
self._db_factory = DBFactory(city=self._city, db_name='hub_test', app_env='TEST') cls._db_factory = DBFactory(city=cls._city, db_name='test_db', app_env='TEST')
self._export_db_factory = ExportDBFactory(city=self._city, db_name='hub_test', app_env='TEST') cls._export_db_factory = ExportDBFactory(city=cls._city, db_name='test_db', app_env='TEST')
def test_heat_pump_simulation_persistence(self): def test_heat_pump_simulation_persistence(self):
output = EnergySystemsExportFactory(city=self._city, user_input=hp_sim_data, hp_model='018', output = EnergySystemsExportFactory(city=self._city, user_input=hp_sim_data, hp_model='018',
@ -98,6 +113,6 @@ class TestHeatPumpSimulation(TestCase):
self.assertEqual(hp_sim[0].simulation_type, SimulationTypes.Series) self.assertEqual(hp_sim[0].simulation_type, SimulationTypes.Series)
self.assertEqual(hp_sim[0].fuel_price, hp_sim_data["FuelPrice"]) self.assertEqual(hp_sim[0].fuel_price, hp_sim_data["FuelPrice"])
self.assertEqual(hp_sim[0].hourly_electricity_demand, output["hourly_electricity_demand"]) self.assertEqual(hp_sim[0].hourly_electricity_demand, output["hourly_electricity_demand"])
self._db_factory.delete_hp_simulation(hp_sim[0].id) self._db_factory.delete_hp_simulation(hp_sim[0].id)
self._db_factory.delete_city(saved_city.id) self._db_factory.delete_city(saved_city.id)