def test_dict2entity(self): # prepare data user_expected = UserEntity(name='user', password='******', salt='salt', status='status') record = user_expected.to_dict() record.pop('name', None) record['name_hashed'] = 'name_hashed' record['name_encrypted'] = 'name_encrypted' record['nonce'] = 'nonce' self.__mock_crypter.decrypt.return_value = user_expected.get_name() # execute user = self.__user_table._dict2entity(record) # check crypter_decrypt_call = self.__mock_crypter.decrypt.call_args_list self.assertEqual( self.__mock_crypter.decrypt.call_count, 1, 'Expected 1 call to crypter.decrypt(). Got {}.'.format( self.__mock_crypter.decrypt.call_count)) args, _ = crypter_decrypt_call[0] expected_args = (record['name_encrypted'], record['nonce']) self.assertSequenceEqual( args, expected_args, 'Expected crypter.decrypt() call with parameter {}. Got {}'.format( expected_args, args)) self.assertIsInstance( user, UserEntity, 'Expected result to be a UserEntity. Got {}'.format(type(user))) self.__assert_user_equal(user, user_expected)
def test_fetch_by_name(self): # prepare data user_expected = UserEntity(name='user', password='******', salt='salt', status='status') record = user_expected.to_dict() record.pop('name', None) record['name_hashed'] = 'name_hashed' record['name_encrypted'] = 'name_encrypted' record['nonce'] = 'nonce' mock_cursor = mock.patch('psycopg2.extras.DictCursor').start() self.__mock_db.cursor.return_value = mock_cursor mock_cursor.fetchone.return_value = record self.__mock_crypter.decrypt.return_value = user_expected.get_name() # execute user = self.__user_table.fetch_by_name(user_expected.get_name()) # check cursor_execute_calls = mock_cursor.execute.call_args_list expected_args = [ 'PREPARE select_user_by_name', 'EXECUTE select_user_by_name' ] self.assertEqual( mock_cursor.execute.call_count, 2, 'Expected 2 calls to cursor.execute(). Got {}'.format( mock_cursor.execute.call_count)) for call, expected_arg in zip(cursor_execute_calls, expected_args): args, _ = call self.assertTrue( args[0].startswith(expected_arg), 'Expected call to cursor.execute() with {}. Got {}'.format( expected_arg, args[0])) self.assertEqual( mock_cursor.fetchone.call_count, 1, 'Expected 1 call to cursor.fetchone(). Got {}'.format( mock_cursor.fetchall.call_count)) crypter_decrypt_call = self.__mock_crypter.decrypt.call_args_list self.assertEqual( self.__mock_crypter.decrypt.call_count, 1, 'Expected 1 calls to crypter.decrypt(). Got {}'.format( self.__mock_crypter.decrypt.call_count)) args, _ = crypter_decrypt_call[0] expected_args = (record['name_encrypted'], record['nonce']) self.assertSequenceEqual( args, expected_args, 'Expected crypter.decrypt() call with parameter {}. Got {}'.format( expected_args, args)) self.assertIsInstance( user, UserEntity, 'Expected result to be a UserEntity. Got {}'.format(type(user))) self.__assert_user_equal(user, user_expected) # clean mock_cursor.stop()
def _dict2entity(self, record): if record is None: return None name = self.__crypter.decrypt(record['name_encrypted'], record['nonce']) return UserEntity( user_id=record['id'], name=name, password=record['password'], salt=record['salt'], status=record['status'], created_at=record['created_at'], modified_at=record['modified_at'], )
def add_user(self, name, password): # verify account is new user = self.__user_table.fetch_by_name(name) if user is not None: raise ValueError( 'Cannot create {}, user already exists.'.format(name)) # create digest, salt = self.__hasher.hash(password) user = UserEntity(name=name, password=digest, salt=salt, status=UserEntity.STATUS_ENABLED, created_at=datetime.now(timezone.utc), modified_at=datetime.now(timezone.utc)) return self.__user_table.save(user)
def save(self, user: UserEntity): # no id: it's a new record if user.get_id() is None: name_encrypted, nonce = self.__crypter.encrypt(user.get_name()) name_hashed = self.__hasher.anonymize(user.get_name()) query = "INSERT INTO user_account (name_hashed, name_encrypted, salt, nonce, password, status, created_at, modified_at) " query += "VALUES ($1,$2,$3,$4,$5,$6,$7,$8)" params = [ name_hashed, name_encrypted, user.get_salt(), nonce, user.get_password() ] params += [ user.get_status(), user.get_created_at(), user.get_modified_at() ] self._prepare_statement('insert_user', query) self._execute('insert_user', tuple(params)) # id: it's an update else: query = "UPDATE user_account SET password=$1, salt=$2, status=$3, modified_at=$4 WHERE id=$5" params = [ user.get_password(), user.get_salt(), user.get_status(), user.get_modified_at(), user.get_id() ] self._prepare_statement('update_user', query) self._execute('update_user', tuple(params)) self._commit() return self.fetch_by_name(user.get_name())
def test_fetch_all(self): # prepare data users_expected = [ UserEntity(user_id=1, name='user1', password='******', salt='salt1', status='status1'), UserEntity(user_id=2, name='user2', password='******', salt='salt2', status='status2'), ] records = [] for user in users_expected: record = user.to_dict() record.pop('name', None) record['name_hashed'] = 'name_hashed' record['name_encrypted'] = 'name_encrypted' record['nonce'] = 'nonce' records.append(record) mock_cursor = mock.patch('psycopg2.extras.DictCursor').start() self.__mock_db.cursor.return_value = mock_cursor mock_cursor.fetchall.return_value = records self.__mock_crypter.decrypt.side_effect = [ user.get_name() for user in users_expected ] # execute users = self.__user_table.fetch_all() # check cursor_execute_calls = mock_cursor.execute.call_args_list expected_args = ['PREPARE select_user_all', 'EXECUTE select_user_all'] self.assertEqual( mock_cursor.execute.call_count, 2, 'Expected 2 calls to cursor.execute(). Got {}'.format( mock_cursor.execute.call_count)) for call, expected_arg in zip(cursor_execute_calls, expected_args): args, _ = call self.assertTrue( args[0].startswith(expected_arg), 'Expected call to cursor.execute() with {}. Got {}'.format( expected_arg, args[0])) self.assertEqual( mock_cursor.fetchall.call_count, 1, 'Expected 1 call to cursor.fetchall(). Got {}'.format( mock_cursor.fetchall.call_count)) crypter_decrypt_calls = self.__mock_crypter.decrypt.call_args_list self.assertEqual( self.__mock_crypter.decrypt.call_count, 2, 'Expected 2 calls to crypter.decrypt(). Got {}'.format( self.__mock_crypter.decrypt.call_count)) for call, record in zip(crypter_decrypt_calls, records): args, _ = call expected_args = (record['name_encrypted'], record['nonce']) self.assertSequenceEqual( args, expected_args, 'Expected crypter.decrypt() call with parameter {}. Got {}'. format(expected_args, args)) self.assertIsInstance( users, list, 'Expected result to be a list. Got {}'.format(type(users))) self.assertEqual( len(users), 2, 'Expected 2 users in result. Got {}'.format(len(users))) self.assertListEqual( [type(user) for user in users], [UserEntity, UserEntity], 'Expected 2 UserEntity in result. Got {}'.format(users)) for observed, expected in zip(users, users_expected): self.__assert_user_equal(observed, expected) # clean mock_cursor.stop()
def test_save_with_id(self): # prepare data user_expected = UserEntity(user_id=1, name='user', password='******', salt='salt', status='status') record_after = user_expected.to_dict() record_after.pop('name', None) record_after['name_hashed'] = 'name_hashed' record_after['name_encrypted'] = 'name_encrypted' record_after['nonce'] = 'nonce' self.__mock_crypter.decrypt.return_value = user_expected.get_name() self.__mock_hasher.anonymize.return_value = 'name_hashed' mock_cursor = mock.patch('psycopg2.extras.DictCursor').start() mock_connection = mock.patch('psycopg2.extensions.connection').start() self.__mock_db.cursor.return_value = mock_cursor self.__mock_db.connection.return_value = mock_connection mock_cursor.fetchone.return_value = record_after # execute user = self.__user_table.save(user_expected) # check self.assertFalse( self.__mock_crypter.encrypt.called, 'Crypter.encrypt() was called and should not have been.') hasher_anonymize_call = self.__mock_hasher.anonymize.call_args_list self.assertEqual( self.__mock_hasher.anonymize.call_count, 1, 'Expected 1 call to hasher.anonymize(). Got {}'.format( self.__mock_hasher.anonymize.call_count)) arg, _ = hasher_anonymize_call[0] expected_arg = (user_expected.get_name(), ) self.assertEqual( arg, expected_arg, 'Expected hasher.anonymize() call with parameter {}. Got {}'. format(expected_arg, arg)) cursor_execute_calls = mock_cursor.execute.call_args_list expected_args = [ 'PREPARE update_user', 'EXECUTE update_user', 'PREPARE select_user_by_name', 'EXECUTE select_user_by_name' ] self.assertEqual( mock_cursor.execute.call_count, 4, 'Expected 4 calls to cursor.execute(). Got {}'.format( mock_cursor.execute.call_count)) for call, expected_arg in zip(cursor_execute_calls, expected_args): args, _ = call self.assertTrue( args[0].startswith(expected_arg), 'Expected call to cursor.execute() with {}. Got {}'.format( expected_arg, args[0])) self.assertEqual( mock_connection.commit.call_count, 1, 'Expected 1 call to connection.commit(). Got {}'.format( mock_connection.commit.call_count)) self.assertEqual( mock_cursor.fetchone.call_count, 1, 'Expected 1 call to cursor.fetchone(). Got {}'.format( mock_cursor.fetchall.call_count)) crypter_decrypt_call = self.__mock_crypter.decrypt.call_args_list self.assertEqual( self.__mock_crypter.decrypt.call_count, 1, 'Expected 1 calls to crypter.decrypt(). Got {}'.format( self.__mock_crypter.decrypt.call_count)) args, _ = crypter_decrypt_call[0] expected_args = (record_after['name_encrypted'], record_after['nonce']) self.assertSequenceEqual( args, expected_args, 'Expected crypter.decrypt() call with parameter {}. Got {}'.format( expected_args, args)) self.assertIsInstance( user, UserEntity, 'Expected result to be a UserEntity. Got {}'.format(type(user))) self.__assert_user_equal(user, user_expected)
def __assert_user_equal(self, observed: UserEntity, expected: UserEntity, omit_id=False): if omit_id is False: self.assertEqual( observed.get_id(), expected.get_id(), 'Expected user id {}. Got {}'.format(expected.get_id(), observed.get_id())) self.assertEqual( observed.get_name(), expected.get_name(), 'Expected user name {}. Got {}'.format(expected.get_name(), observed.get_name())) self.assertEqual( observed.get_status(), expected.get_status(), 'Expected user status {}. Got {}'.format(expected.get_status(), observed.get_status())) self.assertEqual( observed.get_password(), expected.get_password(), 'Expected user password {}. Got {}'.format( expected.get_password(), observed.get_password())) self.assertEqual( observed.get_salt(), expected.get_salt(), 'Expected user salt {}. Got {}'.format(expected.get_salt(), observed.get_salt())) self.assertEqual( observed.get_created_at(), expected.get_created_at(), 'Expected user created_at {}. Got {}'.format( expected.get_created_at(), observed.get_created_at())) self.assertEqual( observed.get_modified_at(), expected.get_modified_at(), 'Expected user modified_at {}. Got {}'.format( expected.get_modified_at(), observed.get_modified_at()))