Add ability to remove NTS clients

This commit is contained in:
Mike Cifelli 2024-04-14 17:23:13 -04:00
parent 3d03e4eb62
commit feff0b29cd
Signed by: mike
GPG Key ID: 6B08C6BE47D08E4C
7 changed files with 131 additions and 26 deletions

View File

@ -14,9 +14,43 @@ defmodule Chronoscope.NTS do
end
def list() do
call_all_clients(:list)
end
def clear() do
:terminate
|> call_all_clients()
|> Enum.map(&wait_for_termination/1)
end
defp wait_for_termination(pid) do
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, _, _, _} -> {:ok, pid}
after
1000 -> {:error, pid}
end
end
defp call_all_clients(message) do
NTS.DynamicSupervisor
|> DynamicSupervisor.which_children()
|> Enum.map(fn {_, pid, _, _} -> GenServer.call(pid, :list) end)
|> Enum.map(fn {_, pid, _, _} -> GenServer.call(pid, message) end)
end
def remove(host, port) do
name = "#{host}:#{port}"
case Registry.lookup(NTS.Registry, name) do
[{pid, _}] ->
pid
|> GenServer.call(:terminate)
|> wait_for_termination()
[] ->
{:error, :notfound}
end
end
@impl true

View File

@ -1,5 +1,5 @@
defmodule Chronoscope.NTS.Client do
use GenServer
use GenServer, restart: :transient
alias Chronoscope.NTS
alias Chronoscope.NTS.KeyEstablishmentClient
@ -23,6 +23,11 @@ defmodule Chronoscope.NTS.Client do
}}
end
@impl true
def handle_call(:terminate, _from, state) do
{:stop, :normal, self(), state}
end
@impl true
def handle_call(:list, _from, state) do
{:reply, state, state}

View File

@ -10,18 +10,6 @@ defmodule Chronoscope.NTS.ClientTest do
setup :verify_on_exit!
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
setup _tags do
DateTimeMock
|> stub(:utc_now, fn -> ~U[2024-03-31 01:23:45Z] end)

View File

@ -12,18 +12,6 @@ defmodule Chronoscope.NTS.KeyEstablishmentClientTest do
@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 "sends the correct TLS options" do
SSLMock

View File

@ -0,0 +1,72 @@
defmodule Chronoscope.NTSTest do
use Chronoscope.Case
alias Chronoscope.NTS.SSLMock
import Chronoscope.NTS
import Mox
setup :verify_on_exit!
setup :set_mox_global
defp expect_key_establishment(host, port) do
host_charlist = to_charlist(host)
SSLMock
|> expect(:connect, fn ^host_charlist, ^port, _, _ -> {:ok, :socket} end)
|> expect(:send, fn :socket, _ -> send_ssl_response([]) end)
|> expect(:peercert, fn :socket -> {:ok, peercert()} end)
|> expect(:close, fn :socket -> :ok end)
end
setup do
clear()
on_exit(fn -> clear() end)
end
describe "Chronoscope.NTS.healthy?()" do
test "is healthy" do
assert healthy?() == true
end
end
describe "Chronoscope.NTS.list()" do
test "shows empty client list" do
assert list() == []
end
test "shows all clients" do
expect_key_establishment("localhost", 4444)
key_establishment("localhost", 4444)
assert [%{host: "localhost", key_establishment_response: _, last_key_establishment: _, port: 4444}] = list()
end
end
describe "Chronoscope.NTS.remove()" do
test "removes a client" do
expect_key_establishment("localhost", 4444)
key_establishment("localhost", 4444)
assert {:ok, _} = remove("localhost", 4444)
assert list() == []
end
test "does nothing if the client doesn't exist" do
expect_key_establishment("localhost", 4444)
key_establishment("localhost", 4444)
assert remove("localhost", 1111) == {:error, :notfound}
assert [%{host: "localhost", key_establishment_response: _, last_key_establishment: _, port: 4444}] = list()
end
end
describe "Chronoscope.NTS.key_establishment()" do
test "creates and reuses a client" do
expect_key_establishment("localhost", 4444)
assert {:ok, %{cert_expiration: _}} = key_establishment("localhost", 4444)
assert {:ok, %{cert_expiration: _}} = key_establishment("localhost", 4444)
end
end
end

View File

@ -1,8 +1,26 @@
defmodule Chronoscope.Case do
use ExUnit.CaseTemplate
using do
quote do
import Chronoscope.Case
end
end
setup _tags do
Mox.stub_with(Chronoscope.NTS.DateTimeMock, Chronoscope.DateTime.Stub)
:ok
end
def 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
def send_ssl_response(response) do
send(self(), {:ssl, nil, response})
:ok
end
end

0
test/support/ssl.ex Normal file
View File