예제 #1
0
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))
예제 #2
0
    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)
예제 #3
0
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)
예제 #4
0
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))
예제 #5
0
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))