def test_configure_live_does_not_leak_passwords(tmpdir, capsys, cursor,
                                                db_config):
    """
    We add a new user (NEW_USER) through pgbedrock and make sure that 1) this change isn't
    committed if we pass --check and 2) this change _is_ committed if we pass --live
    """
    # Assert that we start without the role we are trying to add
    cursor.execute(Q_GET_ROLE_ATTRIBUTE.format('rolname', NEW_USER))
    assert cursor.rowcount == 0

    new_password = '******'
    spec_path = tmpdir.join('spec.yml')
    spec_path.write("""
    postgres:
        is_superuser: yes
        owns:
            schemas:
                - information_schema
                - pg_catalog
                - public

    test_user:
        can_login: yes
        is_superuser: yes
        attributes:
            - PASSWORD "test_password"

    {new_user}:
        attributes:
            - PASSWORD "{new_password}"
    """.format(new_user=NEW_USER, new_password=new_password))

    params = copy.deepcopy(db_config)
    params.update(
        dict(
            spec=spec_path.strpath,
            prompt=False,
            attributes=True,
            memberships=True,
            ownerships=True,
            privileges=True,
            live=True,
            verbose=True,
        ))
    core_configure.configure(**params)

    # Verify that the password was changed
    new_md5_hash = attr.create_md5_hash(NEW_USER, new_password)
    cursor.execute(
        "SELECT rolpassword FROM pg_authid WHERE rolname = '{}';".format(
            NEW_USER))
    assert cursor.fetchone()[0] == new_md5_hash

    # Verify that the password isn't exposed in our output
    out, err = capsys.readouterr()
    assert 'supersecret' not in out
    assert 'supersecret' not in err

    # Verify that the sanitized record of the password change is in our output
    assert 'ALTER ROLE "foobar" WITH ENCRYPTED PASSWORD \'******\';' in out
def test_set_all_attributes_change_skips_same_password(mockdbcontext,
                                                       password):
    role_attributes = copy.deepcopy(attr.DEFAULT_ATTRIBUTES)
    role_attributes.update(
        dict(rolpassword=attr.create_md5_hash(ROLE1, 'supersecret')))
    mockdbcontext.get_role_attributes = lambda x: role_attributes

    attributes = ['PASSWORD {}'.format(password)]
    roleconf = attr.AttributeAnalyzer(ROLE1,
                                      spec_attributes=attributes,
                                      dbcontext=mockdbcontext)
    attributes = roleconf.coalesce_attributes()
    roleconf.set_all_attributes(attributes)
    assert roleconf.sql_to_run == []
    opt = 'rolvaliduntil'
    val = '2019-09-09'
    curr_val = 'infinity'

    assert roleconf.get_attribute_value(opt) != val

    roleconf.set_attribute_value(attribute=opt,
                                 desired_value=val,
                                 current_value=curr_val)

    expected = [attr.Q_ALTER_VALID_UNTIL.format(ROLE1, val, curr_val)]
    assert roleconf.sql_to_run == expected


@nondefault_attributes(
    dict(rolpassword=attr.create_md5_hash(ROLE1, 'supersecret'), ))
@pytest.mark.parametrize('desired_value, expected',
                         [('supersecret', True),
                          ('incorrect_password', False)])
def test_is_same_password(roleconf, desired_value, expected):
    assert roleconf.is_same_password(desired_value) == expected


def test_is_same_password_if_empty(roleconf):
    assert roleconf.is_same_password(None) is True


@nondefault_attributes(
    dict(rolpassword=attr.create_md5_hash(ROLE1, 'supersecret'), ))
def test_set_password_statements_generated(roleconf):
    desired_value = 'evenmoresecret'