class PostgresTest(unittest.TestCase): """Test the public API provided by the `Postgres` class""" def setUp(self): """Set up a temporary database cluster for testing potentially destructive operations""" self.pg_test = PGTest() self.postgres = Postgres(port=self.pg_test.port, interactive=False, quiet=True) self.dbuser = '******' self.dbpass = '******' self.dbname = 'aiida_db' def _setup_postgres(self): self.postgres.dbinfo = self.pg_test.dsn self.postgres.determine_setup() def test_determine_setup_fail(self): self.postgres.set_port('11111') setup_success = self.postgres.determine_setup() self.assertFalse(setup_success) def test_determine_setup_success(self): self._setup_postgres() self.assertTrue(self.postgres.pg_execute) def test_setup_fail_callback(self): """Make sure `determine_setup` works despite wrong initial values in case of correct callback""" def correct_setup(interactive, dbinfo): # pylint: disable=unused-argument return self.pg_test.dsn self.postgres.set_port(11111) self.postgres.set_setup_fail_callback(correct_setup) self.postgres.determine_setup() self.assertTrue(self.postgres.pg_execute) @mock.patch('aiida.control.postgres._try_connect', new=_try_connect_always_fail) @mock.patch('aiida.control.postgres._try_subcmd') def test_fallback_on_subcmd(self, try_subcmd): """Ensure that accessing postgres via subcommand is tried if psychopg does not work.""" self._setup_postgres() self.assertTrue(try_subcmd.call_count >= 1) def test_create_drop_db_user(self): """Check creating and dropping a user works""" self._setup_postgres() self.postgres.create_dbuser(self.dbuser, self.dbpass) self.assertTrue(self.postgres.dbuser_exists(self.dbuser)) self.postgres.drop_dbuser(self.dbuser) self.assertFalse(self.postgres.dbuser_exists(self.dbuser)) def test_create_drop_db(self): """Check creating & destroying a database""" self._setup_postgres() self.postgres.create_dbuser(self.dbuser, self.dbpass) self.postgres.create_db(self.dbuser, self.dbname) self.assertTrue(self.postgres.db_exists(self.dbname)) self.postgres.drop_db(self.dbname) self.assertFalse(self.postgres.db_exists(self.dbname))
def profile_delete(self, *args): """ Deletes profile Asks whether to delete associated database and associated database user. Specify argument '--force' to skip any questions warning about loss of data. """ from aiida.common.setup import get_or_create_config, update_config import os.path from urlparse import urlparse args = list(args) if '--force' in args: force = True args.remove('--force') else: force = False confs = get_or_create_config() profiles = confs.get('profiles', {}) users = [ profiles[name].get('AIIDADB_USER', '') for name in profiles.keys() ] profiles_to_delete = args for profile_to_delete in profiles_to_delete: try: profile = profiles[profile_to_delete] except KeyError: print("Profile '{}' does not exist".format(profile_to_delete)) continue postgres = Postgres(port=profile.get('AIIDADB_PORT'), interactive=True, quiet=False) postgres.determine_setup() print postgres.dbinfo db_name = profile.get('AIIDADB_NAME', '') if not postgres.db_exists(db_name): print( "Associated database '{}' does not exist.".format(db_name)) elif force or click.confirm("Delete associated database '{}'?\n" \ "WARNING: All data will be lost.".format(db_name)): print("Deleting database '{}'.".format(db_name)) postgres.drop_db(db_name) user = profile.get('AIIDADB_USER', '') if not postgres.dbuser_exists(user): print("Associated database user '{}' does not exist.".format( user)) elif users.count(user) > 1: print("Associated database user '{}' is used by other profiles "\ "and will not be deleted.".format(user)) elif force or click.confirm( "Delete database user '{}'?".format(user)): print("Deleting user '{}'.".format(user)) postgres.drop_dbuser(user) repo_uri = profile.get('AIIDADB_REPOSITORY_URI', '') repo_path = urlparse(repo_uri).path repo_path = os.path.expanduser(repo_path) if not os.path.isabs(repo_path): print("Associated file repository '{}' does not exist."\ .format(repo_path)) elif not os.path.isdir(repo_path): print("Associated file repository '{}' is not a directory."\ .format(repo_path)) elif force or click.confirm("Delete associated file repository '{}'?\n" \ "WARNING: All data will be lost.".format(repo_path)): print("Deleting directory '{}'.".format(repo_path)) import shutil shutil.rmtree(repo_path) if force or click.confirm("Delete configuration for profile '{}'?\n" \ "WARNING: Permanently removes profile from the list of AiiDA profiles."\ .format(profile_to_delete)): print("Deleting configuration for profile '{}'.".format( profile_to_delete)) del profiles[profile_to_delete] update_config(confs)
def profile_delete(force, profiles): """ Delete PROFILES separated by space from aiida config file along with its associated database and repository. """ from aiida.common.setup import get_or_create_config, update_config import os.path from urlparse import urlparse echo.echo('profiles: {}'.format(', '.join(profiles))) confs = get_or_create_config() available_profiles = confs.get('profiles', {}) users = [ available_profiles[name].get('AIIDADB_USER', '') for name in available_profiles.keys() ] for profile_name in profiles: try: profile = available_profiles[profile_name] except KeyError: echo.echo_info("Profile '{}' does not exist".format(profile_name)) continue postgres = Postgres(port=profile.get('AIIDADB_PORT'), interactive=True, quiet=False) postgres.dbinfo["user"] = profile.get('AIIDADB_USER') postgres.dbinfo["host"] = profile.get('AIIDADB_HOST') postgres.determine_setup() import json echo.echo(json.dumps(postgres.dbinfo, indent=4)) db_name = profile.get('AIIDADB_NAME', '') if not postgres.db_exists(db_name): echo.echo_info( "Associated database '{}' does not exist.".format(db_name)) elif force or click.confirm("Delete associated database '{}'?\n" \ "WARNING: All data will be lost.".format(db_name)): echo.echo_info("Deleting database '{}'.".format(db_name)) postgres.drop_db(db_name) user = profile.get('AIIDADB_USER', '') if not postgres.dbuser_exists(user): echo.echo_info( "Associated database user '{}' does not exist.".format(user)) elif users.count(user) > 1: echo.echo_info("Associated database user '{}' is used by other profiles " \ "and will not be deleted.".format(user)) elif force or click.confirm("Delete database user '{}'?".format(user)): echo.echo_info("Deleting user '{}'.".format(user)) postgres.drop_dbuser(user) repo_uri = profile.get('AIIDADB_REPOSITORY_URI', '') repo_path = urlparse(repo_uri).path repo_path = os.path.expanduser(repo_path) if not os.path.isabs(repo_path): echo.echo_info("Associated file repository '{}' does not exist." \ .format(repo_path)) elif not os.path.isdir(repo_path): echo.echo_info("Associated file repository '{}' is not a directory." \ .format(repo_path)) elif force or click.confirm("Delete associated file repository '{}'?\n" \ "WARNING: All data will be lost.".format(repo_path)): echo.echo_info("Deleting directory '{}'.".format(repo_path)) import shutil shutil.rmtree(repo_path) if force or click.confirm("Delete configuration for profile '{}'?\n" \ "WARNING: Permanently removes profile from the list of AiiDA profiles." \ .format(profile_name)): echo.echo_info("Deleting configuration for profile '{}'.".format( profile_name)) del available_profiles[profile_name] update_config(confs)
class SetupTestCase(unittest.TestCase): """Test ``verdi setup``""" def setUp(self): self.runner = CliRunner() backend = os.environ.get('TEST_AIIDA_BACKEND', 'django') self.backend = 'django' if backend == 'django' else 'sqlalchemy' self.pg_test = PGTest() self.postgres = Postgres(port=self.pg_test.port, interactive=False, quiet=True) self.postgres.dbinfo = self.pg_test.dsn self.postgres.determine_setup() self.dbuser = '******' self.dbpass = '******' self.dbname = 'aiida_test_setup' self.postgres.create_dbuser(self.dbuser, self.dbpass) self.postgres.create_db(self.dbuser, self.dbname) self.repo = abspath('./aiida_radames') def tearDown(self): self.postgres.drop_db(self.dbname) self.postgres.drop_dbuser(self.dbuser) self.pg_test.close() def test_user_setup(self): backend_settings.AIIDADB_PROFILE = None result = self.runner.invoke( _setup_cmd, [ 'radames', '--non-interactive', '--backend={}'.format(self.backend), '[email protected]', '--first-name=Radames', '--last-name=Verdi', '--institution=Scala', '--repo={}'.format(self.repo), '--db_host=localhost', '--db_port={}'.format(self.pg_test.port), '--db_name={}'.format(self.dbname), '--db_user={}'.format(self.dbuser), '--db_pass={}'.format(self.dbpass), '--no-password']) self.assertFalse(result.exception, msg=get_debug_msg(result)) def test_user_configure(self): backend_settings.AIIDADB_PROFILE = None self.runner.invoke( _setup_cmd, [ 'radames2', '--non-interactive', '--backend={}'.format(self.backend), '[email protected]', '--first-name=Radames', '--last-name=Verdi', '--institution=Scala', '--repo={}'.format(self.repo), '--db_host=localhost', '--db_port={}'.format(self.pg_test.port), '--db_name={}'.format(self.dbname), '--db_user={}'.format(self.dbuser), '--db_pass={}'.format(self.dbpass), '--no-password']) backend_settings.AIIDADB_PROFILE = None result = self.runner.invoke( _setup_cmd, ['radames2', '--only-config'], input='yes\[email protected]\npostgresql_psycopg2\n\n\n\n\n\n{repo}\nRadames2\nVerdi2\nScala2\nyes\nno\n'.format( repo=self.repo ), catch_exceptions=False ) self.assertFalse(result.exception, msg=get_debug_msg(result))
class SetupTestCase(unittest.TestCase): """Test `verdi setup`.""" def setUp(self): self.runner = CliRunner() backend = os.environ.get('TEST_AIIDA_BACKEND', 'django') self.backend = 'django' if backend == 'django' else 'sqlalchemy' self.pg_test = PGTest() self.postgres = Postgres(port=self.pg_test.port, interactive=False, quiet=True) self.postgres.dbinfo = self.pg_test.dsn self.postgres.determine_setup() self.dbuser = '******' self.dbpass = '******' self.dbname = 'aiida_test_setup_{}'.format(self.backend) self.postgres.create_dbuser(self.dbuser, self.dbpass) self.postgres.create_db(self.dbuser, self.dbname) self.repository = abspath('./aiida_radames_{}'.format(self.backend)) def tearDown(self): self.postgres.drop_db(self.dbname) self.postgres.drop_dbuser(self.dbuser) self.pg_test.close() def test_user_setup(self): """ Test `verdi setup` non-interactively """ backend_settings.AIIDADB_PROFILE = None result = self.runner.invoke(setup, [ '--non-interactive', '--backend={}'.format( self.backend), '[email protected]', '--first-name=Radames', '--last-name=Verdi', '--institution=Scala', '--repository={}'.format(self.repository), '--db-host=localhost', '--db-port={}'.format(self.pg_test.port), '--db-name={}'.format( self.dbname), '--db-username={}'.format( self.dbuser), '--db-password={}'.format( self.dbpass), 'radames_{}'.format(self.backend) ]) self.assertFalse(result.exception, msg=get_debug_msg(result)) def test_user_configure(self): """ Test `verdi setup` configure user """ backend_settings.AIIDADB_PROFILE = None self.runner.invoke(setup, [ '--non-interactive', '--backend={}'.format( self.backend), '[email protected]', '--first-name=Radames', '--last-name=Verdi', '--institution=Scala', '--repository={}'.format(self.repository), '--db-host=localhost', '--db-port={}'.format(self.pg_test.port), '--db-name={}'.format( self.dbname), '--db-username={}'.format( self.dbuser), '--db-password={}'.format( self.dbpass), 'radames2_{}'.format(self.backend) ]) tpl = '{email}\n{first_name}\n{last_name}\n{institution}\nyes\n{email}\n{engine}\n\n\n\n\n\n{repo}\nno\n\n' backend_settings.AIIDADB_PROFILE = None result = self.runner.invoke( setup, ['radames2_{}'.format(self.backend), '--only-config'], input=tpl.format(email='*****@*****.**', first_name='Radames2', last_name='Verdi2', institution='Scala2', engine='postgresql_psycopg2', repo=self.repository), catch_exceptions=False) self.assertFalse(result.exception, msg=get_debug_msg(result))