'How to fix a SQL Integrity error while trying to build a Flask application?
I am currently following Miguel Grinberg's Flask Web Development tutorial. I am trying to code unittests for testing a "Change Email" functionality as described in commit 8h in his GitHub repo :(https://github.com/miguelgrinberg/flasky/commit/d5b2e68ba717b1f1bce2930d43c2099cab6998a5)
class UserModelTestCase(unittest.TestCase):
def test_password_setter(self):
#...
def test_no_password_getter(self):
#...
def test_password_verification(self):
#...
def test_password_salts_are_random(self):
#...
def test_valid_confirmation_token(self):
u = User(password='cat')
db.session.add(u)
db.session.commit()
token = u.generate_confirmation_token()
self.assertTrue(u.confirm(token))
def test_invalid_confirmation_token(self):
u1 = User(password='cat')
u2 = User(password='dog')
db.session.add(u1)
db.session.add(u2)
db.session.commit()
token = u1.generate_confirmation_token()
self.assertFalse(u2.confirm(token))
def test_expired_confirmation_token(self):
u = User(password='cat')
db.session.add(u)
db.session.commit()
token = u.generate_confirmation_token(1)
time.sleep(2)
self.assertFalse(u.confirm(token))
def test_valid_reset_token(self):
u = User(password='cat')
db.session.add(u)
db.session.commit()
token = u.generate_reset_token()
self.assertTrue(User.reset_password(token, 'dog'))
self.assertTrue(u.verify_password('dog'))
def test_invalid_reset_token(self):
u = User(password='cat')
db.session.add(u)
db.session.commit()
token = u.generate_reset_token()
self.assertFalse(User.reset_password(token + 'a', 'horse'))
self.assertTrue(u.verify_password('cat'))
def test_valid_email_change_token(self):
u = User(email='[email protected]', password='cat')
db.session.add(u)
db.session.commit()
token = u.generate_email_change_token('[email protected]')
self.assertTrue(u.change_email(token))
self.assertTrue(u.email == '[email protected]')
def test_invalid_email_change_token(self):
u1 = User(email='[email protected]', password='cat')
u2 = User(email='[email protected]', password='dog')
db.session.add(u1)
db.session.add(u2)
db.session.commit()
token = u1.generate_email_change_token('[email protected]')
self.assertFalse(u2.change_email(token))
self.assertTrue(u2.email == '[email protected]')
def test_duplicate_email_change_token(self):
u1 = User(email='[email protected]', password='cat')
u2 = User(email='[email protected]', password='dog')
db.session.add(u1)
db.session.add(u2)
db.session.commit()
token = u2.generate_email_change_token('[email protected]')
self.assertFalse(u2.change_email(token))
self.assertTrue(u2.email == '[email protected]')
However, I keep getting an Integrity Error while running the test.
flask test
test_duplicate_email_change_token (test_user_model.UserModelTestCase)... ok
test_expired_confirmation_token(test_user_model.UserModelTestCase) ... ok
test_invalid_confirmation_token (test_user_model.UserModelTestCase) ... ok
test_invalid_email_change_token(test_user_model.UserModelTestCase) ... ERROR
test_invalid_reset_token(test_user_model.UserModelTestCase) ... ERROR
test_no_password_getter(test_user_model.UserModelTestCase) ... ok
test_password_salts_are_random (test_user_model.UserModelTestCase) ...ok
test_password_setter (test_user_model.UserModelTestCase) ... ok
test_password_verification (test_user_model.UserModelTestCase) ... ok
test_valid_confirmation_token (test_user_model.UserModelTestCase) ... ERROR
test_valid_email_change_token(test_user_model.UserModelTestCase) ... ERROR
test_valid_reset_token(test_user_model.UserModelTestCase) ... ERROR====================================================================== ERROR: test_invalid_email_change_token(test_user_model.UserModelTestCase)
Traceback (most recent call last): File "c:\users\rishi\pycharmprojects\flasky\lib\site-> packages\sqlalchemy\engine\base.py", line 1802, in _execute_context
self.dialect.do_execute( File "c:\users\rishi\pycharmprojects\flasky\lib\sitepackages\sqlalchemy\engine\default.py", line 732, in do_executecursor.execute(statement, parameters)
sqlite3.IntegrityError: UNIQUE constraint failed: users.email
For reference, please see database model User saved in models.py
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
password_hash = db.Column(db.String(128))
confirmed = db.Column(db.Boolean, default=False)
@property
def password(self):
raise AttributeError('password is not a readable attribute')
@password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
def verify_password(self, password):
return check_password_hash(self.password_hash, password)
def generate_confirmation_token(self, expiration=3600):
s = Serializer(current_app.config['SECRET_KEY'], expiration)
return s.dumps({'confirm':self.id}).decode('UTF-8')
def confirm(self, token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token.encode('UTF-8'))
except:
return False
if data.get('confirm') != self.id:
return False
self.confirmed = True
db.session.add(self)
return True
def generate_reset_token(self, expiration=3600):
s = Serializer(current_app.config['SECRET_KEY'], expiration)
return s.dumps({'reset': self.id}).decode('utf-8')
@staticmethod
def reset_password(token, new_password):
s = Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token.encode('utf-8'))
except:
return False
user = User.query.get(data.get('reset'))
if user is None:
return False
user.password = new_password
db.session.add(user)
return True
def generate_email_change_token(self, new_email, expiration=3600):
s = Serializer(current_app.config['SECRET_KEY'], expiration)
return s.dumps({'change_email':self.id, 'new_email': new_email}).decode('utf-8')
def change_email(self, token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token.encode('utf-8'))
except:
return False
if data.get('change_email') != self.id:
return False
new_email = data.get('new_email')
if new_email is None:
return False
if self.query.filter_by(email=new_email).first() is not None:
return False
self.email = new_email
db.session.add(self)
return True
def __repr__(self):
return '<User %r>' % self.username
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
