Testing FastAPI database with async connection - pytest

I have application on FastAPI. For sending queries to db I'm using SQLAlchemy. Connection in my app looks like `
import databases
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base
from settings import settings
SQLALCHEMY_DATABASE_URL = settings.DB_CONNECT
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
)
database = databases.Database(SQLALCHEMY_DATABASE_URL)
Base = declarative_base()
`
How can I test my app with this db connection? Now I'm tring `
#pytest_asyncio.fixture(autouse=True)
async def db():
await database.connect()
yield
await database.disconnect()
`
but this way I can only connect to current and working database. I need to create test database for testing. I will be glad for any help.

Related

Why Flask does not traceback when it recognizes bad DB connection?

Could not find any answer to this, I try to create two separated objects for different configurations to separate development environment from production.
So I came up with this config.py file
class BaseConfig:
SECRET_KEY = 'MYSECRET'
class DevConfig(BaseConfig):
SQLALCHEMY_DATABASE_URI = 'sqlite:///market.db'
DEBUG = True
class ProdConfig(BaseConfig):
DEBUG = False
pg_user = 'admin'
pg_password = 'admin'
pg_db = 'mytable'
pg_host = 'localhost'
pg_port = '5432'
SQLALCHEMY_DATABASE_URI = f"postgresql://{pg_user}:{pg_password}#{pg_host}:{pg_port}/{pg_db}"
Now I have this config file, I want to test out and see failure by purpose when I create a Flask instance and read from ProdConfig object (Note: I still don't have Postgres instance running on localhost), but I expect for a connection failure when I start my app. But why it lets me to even run the application?
Project has one package, so here is __init__.py of one of my packages:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from market.config import DevConfig, ProdConfig
app = Flask(__name__)
app.config.from_object(ProdConfig) # Note this one!
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = "login_page"
login_manager.login_message_category = "info"
And I have a run.py outside of the package that imports this package, so:
from market import app
#Checks if the run.py file has executed directly and not imported
if __name__ == '__main__':
app.run()
I would expect Flask to fail immediately when the connection could not be established against the DB.

How to create test Postgres db in flask-tesing

I am using flask-testing to do some unit tests on a Postgres application. According to doc , I have following code.
from flask_testing import TestCase
from src.game.models import db
from src import create_app
class BaseTest(TestCase):
SQLALCHEMY_DATABASE_URI = 'postgresql://demo:demo#postgres:5432/test_db'
TESTING = True
def create_app(self):
# pass in test configuration
return create_app(self)
def setUp(self):
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
Of course I got this error
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) FATAL:
database "test_db" does not exist
I do have a database postgresql://demo:demo#postgres:5432/demo which is my production database.
How can I create test_db in this BaseTest class? I am using Python 3.6 and latest flask and flask-sqlalchemy. Thank you very much.

Database 'height_collector' does not exist! Python flask

When i am trying to connect to my existing database(it is realy exist) i have an ERROR occur:
Here is my code and error:
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres510#localhost/height_collector'
db = SQLAlchemy(app)
class Data(db.Model):
__tablename__ = "data"
id = db.Column(db.Integer, primary_key=True)
email_ = db.Column(db.String(120), unique=True)
height_ = db.Column(db.Integer)
def __init__(self, email_, height_):
self.email_ = email_
self.heigth_ = height_
#app.route("/")
def index():
return render_template("index.html")
#app.route("/success", methods=['post'])
def success():
if request.method == 'POST':
email = request.form["email_name"]
height = request.form["height_name"]
print(email, height)
return render_template("success.html")
if __name__ == '__main__':
app.debug = True
app.run()
and then i have an error
Data base ".." doesn't exist!
Here is a picture of my database
It's hard to be sure, but this is probably related to either network names, postgres server config, or permissions.
You need to go through different possibilities step by step and eliminate them as the cause. You can connect and see the db in pgAdmin, and you can't connect in Flask. Somewhere between these two is a difference which stops it from working.
Double-check that in pgAdmin you can correctly open the database which you see pictured and look at the tables (if any). It could be that pgAdmin is showing this db open but it isn't connectable any more.
Can you make sure that in pgAdmin, you use localhost as the host name of your connection, and not the IP address of the machine or anything else. If this is the problem, you need to look at how postgres is configured, and in particular the listen key in the postgres config. If listen is set to localhost, you should be good.
I don't see where you mentioned that you are using Windows, but another answerer seems to have assumed this, is this the case? Does the command ping localhost in a shell succeed?
Connect in pgAdmin using the exact user and password that you use in your Flask code.
Try to connect in Python, not in Flask. Open a Python shell, import psycopg2 and call psycopg2.connect(host='localhost', user='postgres', ...)

Connect to MongoDb using X509 certificate

I am trying to connect to MongoDB using mongoX509. I am using mongo java driver 3.3.0 jar. In api reference I can see MongoCredential to pass subject name and authenticate but i am not able to import this in my code. When I decompile the jar I am not able to see MongoCredential as well.
Am I missing any dependencies. Is there any easy way to connect to Mongodb without using MongoCredential? The details i have is server, port and certificate subject name?
I can post the code I am trying if anyone wants to take a look at it as well
Thanks in Advance
Code - I am using SoapUI to run this code
import com.mongodb.MongoClient;
import com.mongodb.MongoClientURI;
import com.mongodb.MongoCredential;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
try{
def subjectName="CN=xx,OU=xx,O=xx,C=US,ST=CA,L=xx"
MongoCredential credential = MongoCredential.createMongoX509Credential(subjectName);
def URI = "mongodb://server1:27017,server2:27017,server3:27017/<<database>>?replicaSet=<<XYZ>>&authMechanism=MONGODB-X509&ssl=true"
MongoClientURI uri = new MongoClientURI(URI)
MongoClient client = new MongoClient(uri, Arrays.asList(credential));
DB database = client.getDB(<<database>>);
collection = database.isAuthenticated();
log.info collection
}
catch (Exception e){
log.info e
}
The issue was because of incorrect jar that I was using. I got the correct version and it worked.

Flask-sqlalchemy losing connection after restarting of DB server

I use flask-sqlalchemy in my application. DB is postgresql 9.3.
I have simple init of db, model and view:
from config import *
from flask import Flask, request, render_template
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://%s:%s#%s/%s' % (DB_USER, DB_PASSWORD, HOST, DB_NAME)
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
login = db.Column(db.String(255), unique=True, index=True, nullable=False)
db.create_all()
db.session.commit()
#app.route('/users/')
def users():
users = User.query.all()
return '1'
And all works fine. But when happens DB server restarting (sudo service postgresql restart), on first request to the /users/ I obtain sqlalchemy.exc.OperationalError:
OperationalError: (psycopg2.OperationalError) terminating connection due to administrator command
SSL connection has been closed unexpectedly
[SQL: ....
Is there any way to renew connection inside view, or setup flask-sqlalchemy in another way for renew connection automatically?
UPDATE.
I ended up with using clear SQLAlchemy, declaring engine, metadata and db_session for every view, where I critically need it.
It is not solution of question, just a 'hack'.
So question is open. I am sure, It will be nice to find solution for this :)
The SQLAlchemy documentation explains that the default behaviour is to handle disconnects optimistically. Did you try another request - the connection should have re-established itself ? I've just tested this with a Flask/Postgres/Windows project and it works.
In a typical web application using an ORM Session, the above condition would correspond to a single request failing with a 500 error, then the web application continuing normally beyond that. Hence the approach is “optimistic” in that frequent database restarts are not anticipated.
If you want the connection state to be checked prior to a connection attempt you need to write code that handles disconnects pessimistically. The following example code is provided at the documentation:
from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy.pool import Pool
#event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
cursor = dbapi_connection.cursor()
try:
cursor.execute("SELECT 1")
except:
# optional - dispose the whole pool
# instead of invalidating one at a time
# connection_proxy._pool.dispose()
# raise DisconnectionError - pool will try
# connecting again up to three times before raising.
raise exc.DisconnectionError()
cursor.close()
Here's some screenshots of the event being caught in PyCharm's debugger:
Windows 7 (Postgres 9.4, Flask 0.10.1, SQLAlchemy 1.0.11, Flask-SQLAlchemy 2.1 and psycopg 2.6.1)
On first db request
After db restart
Ubuntu 14.04 (Postgres 9.4, Flask 0.10.1, SQLAlchemy 1.0.8, Flask-SQLAlchemy 2.0 and psycopg 2.5.5)
On first db request
After db restart
In plain SQLAlchemy you can add the pool_pre_ping=True kwarg when calling the create_engine function to fix this issue.
When using Flask-SQLAlchemy you can use the same argument, but you need to pass it as a dict in the engine_options kwarg:
app.db = SQLAlchemy(app, engine_options={"pool_pre_ping": True})