310 lines
9.8 KiB
Elixir
310 lines
9.8 KiB
Elixir
defmodule OAuth2TokenAgent.TokenAgentTest do
|
|
@moduledoc """
|
|
Tests for TokenAgent, which is used to track token state
|
|
"""
|
|
use ExUnit.Case, async: false
|
|
|
|
import Mock
|
|
|
|
alias OAuth2.{AccessToken, Client}
|
|
alias OAuth2TokenAgent.{TokenAgent, TokenRefreshStrategy}
|
|
|
|
defp test_client do
|
|
Client.new(
|
|
strategy: OAuth2.Strategy.ClientCredentials,
|
|
client_id: "test_client_id",
|
|
client_secret: "test_client_secret_abc123",
|
|
site: "http://localhost/"
|
|
)
|
|
end
|
|
|
|
describe "start_link/1" do
|
|
test "returns an agent storing the token if successful" do
|
|
with_mock Client, [:passthrough],
|
|
get_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "test_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 6000
|
|
}
|
|
}}
|
|
end do
|
|
{:ok, agent} = TokenAgent.start_link(initial_client: test_client())
|
|
|
|
assert TokenAgent.get_access_token(agent) == "test_access_token"
|
|
|
|
assert TokenAgent.get_current_client(agent).token.access_token == "test_access_token"
|
|
end
|
|
end
|
|
|
|
test "returns an error if the initial token retrieval did not succeed" do
|
|
sample_error = %OAuth2.Error{reason: :econnrefused}
|
|
|
|
with_mock Client, [:passthrough], get_token: fn _client -> {:error, sample_error} end do
|
|
{:error, error} = TokenAgent.start_link(initial_client: test_client())
|
|
|
|
assert error == sample_error
|
|
end
|
|
end
|
|
|
|
test "returns an error if no client is provided" do
|
|
{:error, ":initial_client required"} = TokenAgent.start_link(name: MyModule.TokenAgent)
|
|
end
|
|
|
|
test "can be provided with an name to refer to the agent" do
|
|
with_mock Client, [:passthrough],
|
|
get_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "test_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 6000
|
|
}
|
|
}}
|
|
end do
|
|
{:ok, _} =
|
|
TokenAgent.start_link(
|
|
initial_client: test_client(),
|
|
inline_refresh_strategy: %TokenRefreshStrategy{},
|
|
name: MyModule.TokenAgent
|
|
)
|
|
|
|
assert TokenAgent.get_access_token(MyModule.TokenAgent) == "test_access_token"
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "refresh_tokens/1" do
|
|
test "uses the refresh token if available" do
|
|
with_mock Client, [:passthrough],
|
|
get_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "test_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 600,
|
|
refresh_token: "test_refresh_token"
|
|
}
|
|
}}
|
|
end,
|
|
refresh_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "new_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 600,
|
|
refresh_token: "new_refresh_token"
|
|
}
|
|
}}
|
|
end do
|
|
{:ok, agent} = TokenAgent.start_link(initial_client: test_client())
|
|
TokenAgent.refresh(agent)
|
|
|
|
assert TokenAgent.get_access_token(agent) == "new_access_token"
|
|
end
|
|
end
|
|
|
|
test "uses the initial client to get a new token if the refresh token cannot be used" do
|
|
with_mock Client, [:passthrough],
|
|
get_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "test_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 600,
|
|
refresh_token: "test_refresh_token"
|
|
}
|
|
}}
|
|
end,
|
|
refresh_token: fn _client -> {:error, %OAuth2.Error{reason: :econnrefused}} end,
|
|
get_token!: fn client ->
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "new_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 600,
|
|
refresh_token: "new_refresh_token"
|
|
}
|
|
}
|
|
end do
|
|
{:ok, agent} = TokenAgent.start_link(initial_client: test_client())
|
|
TokenAgent.refresh(agent)
|
|
|
|
assert TokenAgent.get_access_token(agent) == "new_access_token"
|
|
|
|
assert_called(Client.refresh_token(:_))
|
|
end
|
|
end
|
|
|
|
test "uses the initial client to get a new token if no refresh token is available" do
|
|
with_mock Client, [:passthrough],
|
|
get_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "test_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 600
|
|
}
|
|
}}
|
|
end,
|
|
refresh_token: fn _client -> {:error, %OAuth2.Error{reason: :econnrefused}} end,
|
|
get_token!: fn client ->
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "new_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 600
|
|
}
|
|
}
|
|
end do
|
|
{:ok, agent} = TokenAgent.start_link(initial_client: test_client())
|
|
TokenAgent.refresh(agent)
|
|
|
|
assert TokenAgent.get_access_token(agent) == "new_access_token"
|
|
|
|
assert_not_called(Client.refresh_token(:_))
|
|
end
|
|
end
|
|
|
|
test "uses the initial client to get a new token if no token is available" do
|
|
with_mock Client, [:passthrough],
|
|
get_token: fn client ->
|
|
{:ok, client}
|
|
end,
|
|
refresh_token: fn _client -> {:error, %OAuth2.Error{reason: :econnrefused}} end,
|
|
get_token!: fn client ->
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "new_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 600
|
|
}
|
|
}
|
|
end do
|
|
{:ok, agent} = TokenAgent.start_link(initial_client: test_client())
|
|
TokenAgent.refresh(agent)
|
|
|
|
assert TokenAgent.get_access_token(agent) == "new_access_token"
|
|
|
|
assert_not_called(Client.refresh_token(:_))
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "inline refresh" do
|
|
test "triggers during get_access_token if the inline_refresh strategy requires it" do
|
|
with_mock Client, [:passthrough],
|
|
get_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "test_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 10,
|
|
refresh_token: "test_refresh_token"
|
|
}
|
|
}}
|
|
end,
|
|
refresh_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "new_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 6000,
|
|
refresh_token: "new_refresh_token"
|
|
}
|
|
}}
|
|
end do
|
|
{:ok, agent} =
|
|
TokenAgent.start_link(
|
|
initial_client: test_client(),
|
|
inline_refresh_strategy: %TokenRefreshStrategy{
|
|
seconds_before_expires: 30
|
|
}
|
|
)
|
|
|
|
assert TokenAgent.get_access_token(agent) == "new_access_token"
|
|
end
|
|
end
|
|
|
|
test "does not trigger during get_access_token if the inline_refresh strategy does not require it" do
|
|
with_mock Client, [:passthrough],
|
|
get_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "test_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 100,
|
|
refresh_token: "test_refresh_token"
|
|
}
|
|
}}
|
|
end,
|
|
refresh_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "new_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 6000,
|
|
refresh_token: "new_refresh_token"
|
|
}
|
|
}}
|
|
end do
|
|
{:ok, agent} =
|
|
TokenAgent.start_link(
|
|
initial_client: test_client(),
|
|
inline_refresh_strategy: %TokenRefreshStrategy{
|
|
seconds_before_expires: 30
|
|
}
|
|
)
|
|
|
|
assert TokenAgent.get_access_token(agent) == "test_access_token"
|
|
|
|
assert_not_called(Client.refresh_token(:_))
|
|
end
|
|
end
|
|
|
|
test "does not trigger during get_access_token if no inline_refresh strategy is set" do
|
|
with_mock Client, [:passthrough],
|
|
get_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "test_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 10,
|
|
refresh_token: "test_refresh_token"
|
|
}
|
|
}}
|
|
end,
|
|
refresh_token: fn client ->
|
|
{:ok,
|
|
%Client{
|
|
client
|
|
| token: %AccessToken{
|
|
access_token: "new_access_token",
|
|
expires_at: (DateTime.utc_now() |> DateTime.to_unix()) + 6000,
|
|
refresh_token: "new_refresh_token"
|
|
}
|
|
}}
|
|
end do
|
|
{:ok, agent} =
|
|
TokenAgent.start_link(initial_client: test_client(), inline_refresh_strategy: nil)
|
|
|
|
assert TokenAgent.get_access_token(agent) == "test_access_token"
|
|
|
|
assert_not_called(Client.refresh_token(:_))
|
|
end
|
|
end
|
|
end
|
|
end
|