Skip to content

Add StreamData tests to authtoken library #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ defmodule AuthToken.Mixfile do
]
end

def application do
[applications: [:logger, :plug],
def extra_application do
[applications: [:logger],
env: [
timeout: 86400,
refresh: 1800
Expand All @@ -47,6 +47,7 @@ defmodule AuthToken.Mixfile do
{:phoenix, "~> 1.3"},

{:dialyxir, "~> 0.5", only: [:dev, :test], runtime: false},
{:stream_data, "~> 0.1", only: [:dev, :test]},
{:ex_doc, "~> 0.18", only: :dev}
]
end
Expand Down
3 changes: 2 additions & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
"phoenix": {:hex, :phoenix, "1.3.0", "1c01124caa1b4a7af46f2050ff11b267baa3edb441b45dbf243e979cd4c5891b", [], [{:cowboy, "~> 1.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "1.0.2", "bfa7fd52788b5eaa09cb51ff9fcad1d9edfeb68251add458523f839392f034c1", [], [], "hexpm"},
"plug": {:hex, :plug, "1.4.3", "236d77ce7bf3e3a2668dc0d32a9b6f1f9b1f05361019946aae49874904be4aed", [], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [], [], "hexpm"}}
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [], [], "hexpm"},
"stream_data": {:hex, :stream_data, "0.4.0", "128c01bfd0fae0108d169eee1772aeed6958604f8782abc2d6e11da4e52468b0", [], [], "hexpm"}}
130 changes: 100 additions & 30 deletions test/authtoken_test.exs
Original file line number Diff line number Diff line change
@@ -1,57 +1,127 @@
defmodule AuthTokenTest do
use ConnCase
use ConnCase, async: true
import ExUnitProperties

@user %{id: 123}

setup do
defp gen_authtoken_key() do
gen_ticker = fn _ ->
StreamData.constant(AuthToken.generate_key())
end

StreamData.constant(:unused)
|> StreamData.bind(gen_ticker)
|> StreamData.unshrinkable()
end

defp gen_usermap() do
StreamData.fixed_map(%{ id: StreamData.integer() })
end

defp gen_authtoken_token(user) do
gen_ticker = fn user ->
StreamData.constant(AuthToken.generate_token(user))
end

StreamData.constant(user)
|> StreamData.bind(gen_ticker)
|> StreamData.unshrinkable()
end

defp gen_authtoken_stale_token(user) do
gen_ticker = fn user ->
StreamData.constant(AuthToken.generate_token(user))
end

StreamData.constant(user)
|> StreamData.bind(gen_ticker)
|> StreamData.unshrinkable()
end

defp reset_timeout_env() do
Application.put_env(:authtoken, :timeout, 86400)
Application.put_env(:authtoken, :refresh, 1800)
end

setup do
reset_timeout_env()
end

describe "keys" do
test "generate_key/0 returns a valid AES128 key" do
{:ok, key} = AuthToken.generate_key()
property "generate_key/0 returns a valid AES128 key" do
check all authtoken_key <- gen_authtoken_key() do
{:ok, key} = authtoken_key
assert byte_size(key) == 16
end
end
end

assert byte_size(key) == 16
describe "unique keys" do
property "generate_key/0 always returns a unique AES128 key" do
# n.b.: not using `check all` here, since that would require we we
# construct a StreamData list. but all we want to do is ensure a large list is unique
authtoken_keys = Enum.take(gen_authtoken_key(), 99_999)

assert authtoken_keys == Enum.uniq(authtoken_keys)
end
end

describe "tokens" do
test "token generation" do
{:ok, encrypted_token} = AuthToken.generate_token(@user)
describe "token properties (and life-cycle)" do
property "generate_token/1 and decrypt_token/1 are reversible" do
check all user <- gen_usermap(),
authtoken_token <- gen_authtoken_token(user) do

assert {:ok, token} = AuthToken.decrypt_token(encrypted_token)
assert token["id"] == @user.id
{:ok, encrypted_token} = authtoken_token
assert {:ok, token} = AuthToken.decrypt_token(encrypted_token)
assert token["id"] == user.id
end
end

refute AuthToken.is_timedout?(token)
refute AuthToken.needs_refresh?(token)
property "authtoken can timeout" do
check all user <- gen_usermap(),
authtoken_token <- gen_authtoken_token(user) do

Application.put_env(:authtoken, :timeout, -1)
Application.put_env(:authtoken, :refresh, -1)
reset_timeout_env()

assert AuthToken.is_timedout?(token)
assert AuthToken.needs_refresh?(token)
{:ok, encrypted_token} = authtoken_token
{:ok, token} = AuthToken.decrypt_token(encrypted_token)

refute AuthToken.is_timedout?(token)
refute AuthToken.needs_refresh?(token)

Application.put_env(:authtoken, :timeout, -1)
Application.put_env(:authtoken, :refresh, -1)

assert AuthToken.is_timedout?(token)
assert AuthToken.needs_refresh?(token)
end
end

test "token refresh" do
{:ok, encrypted_token} = AuthToken.generate_token(@user)
{:ok, token} = AuthToken.decrypt_token(encrypted_token)
# property "token refresh" do
# check all user <- gen_usermap(),
# authtoken_token <- gen_authtoken_token(user) do

assert AuthToken.refresh_token(token) == {:error, :stillfresh}
assert AuthToken.refresh_token(encrypted_token) == {:error, :stillfresh}
# reset_timeout_env()

:timer.sleep(1000)
# {:ok, encrypted_token} = authtoken_token
# {:ok, token} = AuthToken.decrypt_token(encrypted_token)

Application.put_env(:authtoken, :refresh, -1)
assert {:ok, fresh_token} = AuthToken.refresh_token(token)
assert {:ok, fresh_token} = AuthToken.refresh_token(encrypted_token)
# assert AuthToken.refresh_token(token) == {:error, :stillfresh}
# assert AuthToken.refresh_token(encrypted_token) == {:error, :stillfresh}

{:ok, token} = AuthToken.decrypt_token(fresh_token)
assert token["ct"] < token["rt"]
# :timer.sleep(1000)

Application.put_env(:authtoken, :timeout, -1)
assert AuthToken.refresh_token(token) == {:error, :timedout}
end
# Application.put_env(:authtoken, :refresh, -1)
# assert {:ok, fresh_token} = AuthToken.refresh_token(token)
# assert {:ok, fresh_token} = AuthToken.refresh_token(encrypted_token)

# {:ok, token} = AuthToken.decrypt_token(fresh_token)
# assert token["ct"] < token["rt"]

# Application.put_env(:authtoken, :timeout, -1)
# assert AuthToken.refresh_token(token) == {:error, :timedout}
# end
# end
end

describe "plug verifying and testing tokens" do
Expand Down