Add tests

This commit is contained in:
Mike Cifelli 2024-04-13 11:42:15 -04:00
parent 684daf43cc
commit fb5fb1b181
Signed by: mike
GPG Key ID: 6B08C6BE47D08E4C
7 changed files with 82 additions and 17 deletions

View File

@ -21,4 +21,5 @@ config :phoenix, :plug_init_mode, :runtime
config :chronoscope, Chronoscope.NTS,
behaviour: Chronoscope.NTS.BehaviourMock,
datetime: Chronoscope.NTS.DateTimeMock
datetime: Chronoscope.NTS.DateTimeMock,
ssl: Chronoscope.NTS.SSLMock

View File

@ -21,20 +21,20 @@ defmodule Chronoscope.NTS do
@impl true
def key_establishment(host, port) do
GenServer.call(client_pid(host, port), :key_establishment)
end
defp client_pid(host, port) do
name = "#{host}:#{port}"
case Registry.lookup(NTS.Registry, name) do
[{pid, _}] ->
GenServer.call(pid, :key_establishment)
pid
[] ->
{:ok, pid} =
DynamicSupervisor.start_child(
NTS.DynamicSupervisor,
{NTS.Client, host: host, port: port, name: {:via, Registry, {NTS.Registry, name}}}
)
GenServer.call(pid, :key_establishment)
NTS.DynamicSupervisor
|> DynamicSupervisor.start_child({NTS.Client, host: host, port: port, name: {:via, Registry, {NTS.Registry, name}}})
|> then(fn {:ok, pid} -> pid end)
end
end
end

View File

@ -21,7 +21,7 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do
defp ssl_connect(host, port) do
host
|> String.to_charlist()
|> :ssl.connect(port, tls_options(host), @timeout_in_milliseconds)
|> ssl().connect(port, tls_options(host), @timeout_in_milliseconds)
end
defp tls_options(host) do
@ -31,21 +31,21 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do
end
defp perform_key_establishment(socket) do
:ok = :ssl.send(socket, KeyEstablishmentRequest.create())
{:ok, peercert} = :ssl.peercert(socket)
:ok = ssl().send(socket, KeyEstablishmentRequest.create())
{:ok, peercert} = ssl().peercert(socket)
receive do
{:ssl, _socket, response} ->
:ssl.close(socket)
ssl().close(socket)
parse_response(response, peercert)
msg ->
:ssl.close(socket)
ssl().close(socket)
Logger.error("received unexpected message: #{inspect(msg)}")
{:error, :no_response}
after
@timeout_in_milliseconds ->
:ssl.close(socket)
ssl().close(socket)
Logger.error("timed out waiting for response")
{:error, :timeout}
end
@ -67,4 +67,8 @@ defmodule Chronoscope.NTS.KeyEstablishmentClient do
{:error, String.trim(error)}
end
end
defp ssl() do
Application.get_env(:chronoscope, Chronoscope.NTS)[:ssl] || :ssl
end
end

View File

@ -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

View File

@ -1,5 +1,5 @@
defmodule Chronoscope.NTS.KeyEstablishmentRequestTest do
use ExUnit.Case
use Chronoscope.Case
import Chronoscope.NTS.KeyEstablishmentRequest

View File

@ -1,5 +1,5 @@
defmodule Chronoscope.NTS.KeyEstablishmentResponseTest do
use ExUnit.Case
use Chronoscope.Case
import Chronoscope.NTS.KeyEstablishmentResponse

View File

@ -7,5 +7,13 @@ defmodule Chronoscope.DateTime.Stub do
def utc_now(), do: DateTime.utc_now()
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.DateTimeMock, for: Chronoscope.DateTime.Behaviour)
Mox.defmock(Chronoscope.NTS.SSLMock, for: Chronoscope.SSL.Behaviour)