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)