Add tests
This commit is contained in:
parent
684daf43cc
commit
fb5fb1b181
|
@ -21,4 +21,5 @@ config :phoenix, :plug_init_mode, :runtime
|
||||||
|
|
||||||
config :chronoscope, Chronoscope.NTS,
|
config :chronoscope, Chronoscope.NTS,
|
||||||
behaviour: Chronoscope.NTS.BehaviourMock,
|
behaviour: Chronoscope.NTS.BehaviourMock,
|
||||||
datetime: Chronoscope.NTS.DateTimeMock
|
datetime: Chronoscope.NTS.DateTimeMock,
|
||||||
|
ssl: Chronoscope.NTS.SSLMock
|
||||||
|
|
|
@ -21,20 +21,20 @@ defmodule Chronoscope.NTS do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def key_establishment(host, port) do
|
def key_establishment(host, port) do
|
||||||
|
GenServer.call(client_pid(host, port), :key_establishment)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp client_pid(host, port) do
|
||||||
name = "#{host}:#{port}"
|
name = "#{host}:#{port}"
|
||||||
|
|
||||||
case Registry.lookup(NTS.Registry, name) do
|
case Registry.lookup(NTS.Registry, name) do
|
||||||
[{pid, _}] ->
|
[{pid, _}] ->
|
||||||
GenServer.call(pid, :key_establishment)
|
pid
|
||||||
|
|
||||||
[] ->
|
[] ->
|
||||||
{:ok, pid} =
|
NTS.DynamicSupervisor
|
||||||
DynamicSupervisor.start_child(
|
|> DynamicSupervisor.start_child({NTS.Client, host: host, port: port, name: {:via, Registry, {NTS.Registry, name}}})
|
||||||
NTS.DynamicSupervisor,
|
|> then(fn {:ok, pid} -> pid end)
|
||||||
{NTS.Client, host: host, port: port, name: {:via, Registry, {NTS.Registry, name}}}
|
|
||||||
)
|
|
||||||
|
|
||||||
GenServer.call(pid, :key_establishment)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,7 +21,7 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do
|
||||||
defp ssl_connect(host, port) do
|
defp ssl_connect(host, port) do
|
||||||
host
|
host
|
||||||
|> String.to_charlist()
|
|> String.to_charlist()
|
||||||
|> :ssl.connect(port, tls_options(host), @timeout_in_milliseconds)
|
|> ssl().connect(port, tls_options(host), @timeout_in_milliseconds)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp tls_options(host) do
|
defp tls_options(host) do
|
||||||
|
@ -31,21 +31,21 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp perform_key_establishment(socket) do
|
defp perform_key_establishment(socket) do
|
||||||
:ok = :ssl.send(socket, KeyEstablishmentRequest.create())
|
:ok = ssl().send(socket, KeyEstablishmentRequest.create())
|
||||||
{:ok, peercert} = :ssl.peercert(socket)
|
{:ok, peercert} = ssl().peercert(socket)
|
||||||
|
|
||||||
receive do
|
receive do
|
||||||
{:ssl, _socket, response} ->
|
{:ssl, _socket, response} ->
|
||||||
:ssl.close(socket)
|
ssl().close(socket)
|
||||||
parse_response(response, peercert)
|
parse_response(response, peercert)
|
||||||
|
|
||||||
msg ->
|
msg ->
|
||||||
:ssl.close(socket)
|
ssl().close(socket)
|
||||||
Logger.error("received unexpected message: #{inspect(msg)}")
|
Logger.error("received unexpected message: #{inspect(msg)}")
|
||||||
{:error, :no_response}
|
{:error, :no_response}
|
||||||
after
|
after
|
||||||
@timeout_in_milliseconds ->
|
@timeout_in_milliseconds ->
|
||||||
:ssl.close(socket)
|
ssl().close(socket)
|
||||||
Logger.error("timed out waiting for response")
|
Logger.error("timed out waiting for response")
|
||||||
{:error, :timeout}
|
{:error, :timeout}
|
||||||
end
|
end
|
||||||
|
@ -67,4 +67,8 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do
|
||||||
{:error, String.trim(error)}
|
{:error, String.trim(error)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp ssl() do
|
||||||
|
Application.get_env(:chronoscope, Chronoscope.NTS)[:ssl] || :ssl
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
defmodule Chronoscope.NTS.KeyEstablishmentClientTest do
|
||||||
|
use Chronoscope.Case
|
||||||
|
|
||||||
|
alias Chronoscope.NTS.SSLMock
|
||||||
|
alias Chronoscope.NTS.KeyEstablishmentRequest
|
||||||
|
|
||||||
|
import Chronoscope.NTS.KeyEstablishmentClient
|
||||||
|
import Mox
|
||||||
|
|
||||||
|
setup :verify_on_exit!
|
||||||
|
|
||||||
|
@timeout 3000
|
||||||
|
|
||||||
|
defp peercert() do
|
||||||
|
:secp256r1
|
||||||
|
|> X509.PrivateKey.new_ec()
|
||||||
|
|> X509.Certificate.self_signed("/C=US/ST=CA/L=San Francisco/O=Acme/CN=Test")
|
||||||
|
|> X509.Certificate.to_der()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp send_ssl_response(response) do
|
||||||
|
send(self(), {:ssl, nil, response})
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "Chronoscope.NTS.KeyEstablishmentClient.key_establishment()" do
|
||||||
|
test "handles an empty response" do
|
||||||
|
request = KeyEstablishmentRequest.create()
|
||||||
|
|
||||||
|
SSLMock
|
||||||
|
|> expect(:connect, fn ~c"localhost", 2222, _tls_options, @timeout -> {:ok, :socket} end)
|
||||||
|
|> expect(:send, fn :socket, ^request -> send_ssl_response([]) end)
|
||||||
|
|> expect(:peercert, fn :socket -> {:ok, peercert()} end)
|
||||||
|
|> expect(:close, fn :socket -> :ok end)
|
||||||
|
|
||||||
|
assert {:ok, %{cert_expiration: _expiration}} = key_establishment(%{host: "localhost", port: 2222})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "sends the correct TLS options" do
|
||||||
|
SSLMock
|
||||||
|
|> expect(:connect, fn ~c"localhost", 2222, tls_options, @timeout ->
|
||||||
|
assert tls_options[:alpn_advertised_protocols] == ["ntske/1"]
|
||||||
|
{:ok, :socket}
|
||||||
|
end)
|
||||||
|
|> expect(:send, fn :socket, _request -> send_ssl_response([]) end)
|
||||||
|
|> expect(:peercert, fn :socket -> {:ok, peercert()} end)
|
||||||
|
|> expect(:close, fn :socket -> :ok end)
|
||||||
|
|
||||||
|
key_establishment(%{host: "localhost", port: 2222})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,5 @@
|
||||||
defmodule Chronoscope.NTS.KeyEstablishmentRequestTest do
|
defmodule Chronoscope.NTS.KeyEstablishmentRequestTest do
|
||||||
use ExUnit.Case
|
use Chronoscope.Case
|
||||||
|
|
||||||
import Chronoscope.NTS.KeyEstablishmentRequest
|
import Chronoscope.NTS.KeyEstablishmentRequest
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
defmodule Chronoscope.NTS.KeyEstablishmentResponseTest do
|
defmodule Chronoscope.NTS.KeyEstablishmentResponseTest do
|
||||||
use ExUnit.Case
|
use Chronoscope.Case
|
||||||
|
|
||||||
import Chronoscope.NTS.KeyEstablishmentResponse
|
import Chronoscope.NTS.KeyEstablishmentResponse
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,13 @@ defmodule Chronoscope.DateTime.Stub do
|
||||||
def utc_now(), do: DateTime.utc_now()
|
def utc_now(), do: DateTime.utc_now()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defmodule Chronoscope.SSL.Behaviour do
|
||||||
|
@callback connect(any(), any(), any(), any()) :: {:ok, any()} | {:error, any()}
|
||||||
|
@callback send(any(), any()) :: :ok | {:error, any()}
|
||||||
|
@callback peercert(any()) :: {:ok, any()} | {:error, any()}
|
||||||
|
@callback close(any()) :: :ok | {:error, any()}
|
||||||
|
end
|
||||||
|
|
||||||
Mox.defmock(Chronoscope.NTS.BehaviourMock, for: Chronoscope.NTS.Behaviour)
|
Mox.defmock(Chronoscope.NTS.BehaviourMock, for: Chronoscope.NTS.Behaviour)
|
||||||
Mox.defmock(Chronoscope.NTS.DateTimeMock, for: Chronoscope.DateTime.Behaviour)
|
Mox.defmock(Chronoscope.NTS.DateTimeMock, for: Chronoscope.DateTime.Behaviour)
|
||||||
|
Mox.defmock(Chronoscope.NTS.SSLMock, for: Chronoscope.SSL.Behaviour)
|
||||||
|
|
Loading…
Reference in New Issue