def test_init_persona__success(make_token, tmp_path, dummy_context, mocker):
    """
    Validate that the ``init_persona()`` function will load tokens from the cache, validate them,
    extract identity data, and return a new ``Persona`` instance with the tokens and identity data contained
    within it.
    """
    access_token = make_token(
        identity_data=dict(
            user_email="*****@*****.**",
            org_name="good_org",
        ),
        expires="2022-02-16 22:30:00",
    )
    access_token_path = tmp_path / "access.jwt"
    access_token_path.write_text(access_token)
    refresh_token = "dummy-refresh-token"
    refresh_token_path = tmp_path / "refresh.jwt"
    refresh_token_path.write_text(refresh_token)

    mocker.patch.object(settings,
                        "JOBBERGATE_API_ACCESS_TOKEN_PATH",
                        new=access_token_path)
    mocker.patch.object(settings,
                        "JOBBERGATE_API_REFRESH_TOKEN_PATH",
                        new=refresh_token_path)
    with plummet.frozen_time("2022-02-16 21:30:00"):
        persona = init_persona(dummy_context)

    assert persona.token_set.access_token == access_token
    assert persona.token_set.refresh_token == refresh_token
    assert persona.identity_data.user_email == "*****@*****.**"
    assert persona.identity_data.org_name == "good_org"
def login(ctx: typer.Context):
    """
    Log in to the jobbergate-cli by storing the supplied token argument in the cache.
    """
    token_set: TokenSet = fetch_auth_tokens(ctx.obj)
    persona: Persona = init_persona(ctx.obj, token_set)
    terminal_message(
        f"User was logged in with email '{persona.identity_data.user_email}'",
        subject="Logged in!",
    )
def main(
    ctx: typer.Context,
    verbose: bool = typer.Option(
        False, help="Enable verbose logging to the terminal"),
    full: bool = typer.Option(False,
                              help="Print all fields from CRUD commands"),
    raw: bool = typer.Option(
        False, help="Print output from CRUD commands as raw json"),
    version: bool = typer.Option(
        False, help="Print the version of jobbergate-cli and exit"),
):
    """
    Welcome to the Jobbergate CLI!

    More information can be shown for each command listed below by running it with the --help option.
    """
    if version:
        typer.echo(importlib_metadata.version("jobbergate-cli"))
        raise typer.Exit()

    if ctx.invoked_subcommand is None:
        terminal_message(
            conjoin(
                "No command provided. Please check the [bold magenta]usage[/bold magenta] and add a command",
                "",
                f"[yellow]{ctx.get_help()}[/yellow]",
            ),
            subject="Need a jobbergate command",
        )
        raise typer.Exit()

    init_logs(verbose=verbose)
    init_sentry()
    persona = None

    client = httpx.Client(
        base_url=f"https://{settings.AUTH0_LOGIN_DOMAIN}",
        headers={"content-type": "application/x-www-form-urlencoded"},
    )
    context = JobbergateContext(persona=None, client=client)

    if ctx.invoked_subcommand not in ("login", "logout"):
        persona = init_persona(context)
        context.client = httpx.Client(
            base_url=settings.JOBBERGATE_API_ENDPOINT,
            headers=dict(
                Authorization=f"Bearer {persona.token_set.access_token}"),
        )
        context.persona = persona
        context.full_output = full
        context.raw_output = raw

    ctx.obj = context
def test_init_persona__refreshes_access_token_if_it_is_expired(
        make_token, tmp_path, respx_mock, dummy_context, mocker):
    """
    Validate that the ``init_persona()`` function will refresh the access token if it is expired and, after
    validating it, save it to the cache.
    """
    access_token = make_token(
        identity_data=dict(
            user_email="*****@*****.**",
            org_name="good_org",
        ),
        expires="2022-02-16 22:30:00",
    )
    access_token_path = tmp_path / "access.jwt"
    access_token_path.write_text(access_token)
    refresh_token = "dummy-refresh-token"
    refresh_token_path = tmp_path / "refresh.jwt"
    refresh_token_path.write_text(refresh_token)

    refreshed_access_token = make_token(
        identity_data=dict(
            user_email="*****@*****.**",
            org_name="good_org",
        ),
        expires="2022-02-17 22:30:00",
    )

    respx_mock.post(f"{LOGIN_DOMAIN}/oauth/token").mock(
        return_value=httpx.Response(
            httpx.codes.OK,
            json=dict(access_token=refreshed_access_token),
        ), )

    mocker.patch.object(settings,
                        "JOBBERGATE_API_ACCESS_TOKEN_PATH",
                        new=access_token_path)
    mocker.patch.object(settings,
                        "JOBBERGATE_API_REFRESH_TOKEN_PATH",
                        new=refresh_token_path)
    with plummet.frozen_time("2022-02-16 23:30:00"):
        persona = init_persona(dummy_context)

    assert persona.token_set.access_token == refreshed_access_token
    assert persona.token_set.refresh_token == refresh_token
    assert persona.identity_data.user_email == "*****@*****.**"
    assert persona.identity_data.org_name == "good_org"

    assert access_token_path.exists()
    assert access_token_path.read_text() == refreshed_access_token
    assert refresh_token_path.exists()
    assert refresh_token_path.read_text() == refresh_token
def test_init_persona__uses_passed_token_set(make_token, tmp_path,
                                             dummy_context, mocker):
    """
    Validate that the ``init_persona()`` function will used the passed ``TokenSet`` instance instead of
    loading it from the cache and will write the tokens to the cache after validating them.
    """
    access_token = make_token(
        identity_data=dict(
            user_email="*****@*****.**",
            org_name="good_org",
        ),
        expires="2022-02-16 22:30:00",
    )
    access_token_path = tmp_path / "access.jwt"
    refresh_token = "dummy-refresh-token"
    refresh_token_path = tmp_path / "refresh.jwt"

    token_set = TokenSet(
        access_token=access_token,
        refresh_token=refresh_token,
    )

    assert not access_token_path.exists()
    assert not refresh_token_path.exists()

    mocker.patch.object(settings,
                        "JOBBERGATE_API_ACCESS_TOKEN_PATH",
                        new=access_token_path)
    mocker.patch.object(settings,
                        "JOBBERGATE_API_REFRESH_TOKEN_PATH",
                        new=refresh_token_path)
    with plummet.frozen_time("2022-02-16 21:30:00"):
        persona = init_persona(dummy_context, token_set)

    assert persona.token_set.access_token == access_token
    assert persona.token_set.refresh_token == refresh_token
    assert persona.identity_data.user_email == "*****@*****.**"
    assert persona.identity_data.org_name == "good_org"

    assert access_token_path.exists()
    assert access_token_path.read_text() == access_token
    assert refresh_token_path.exists()