Skip to content

Commit

Permalink
Improve test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
cichacz committed Dec 17, 2024
1 parent fe15097 commit a74b0b1
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 13 deletions.
7 changes: 4 additions & 3 deletions lib/neo4ex/bolt_protocol/structure.ex
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@ defmodule Neo4ex.BoltProtocol.Structure do
defp build_fields_list(block) do
block
|> Macro.prewalk([], fn
{:field, _, [name, opts]}, acc ->
{:field, _, [name | opts]}, acc ->
opts =
Keyword.update(
opts,
opts
|> List.flatten()
|> Keyword.update(
:version,
quote(do: Version.parse_requirement!(">= 0.0.0")),
fn requirement ->
Expand Down
6 changes: 3 additions & 3 deletions lib/neo4ex/bolt_protocol/structure/message/extra/hello.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ defmodule Neo4ex.BoltProtocol.Structure.Message.Extra.Hello do
field(:routing, default: %{}, version: ">= 4.1.0")

# prior to v5.1, authentication is handled inside HELLO message
field(:scheme, default: "", version: "< 5.1.0")
field(:principal, default: "", version: "< 5.1.0")
field(:credentials, default: "", version: "< 5.1.0")
field(:scheme, version: "< 5.1.0")
field(:principal, version: "< 5.1.0")
field(:credentials, version: "< 5.1.0")
end
end
6 changes: 3 additions & 3 deletions lib/neo4ex/bolt_protocol/structure/message/extra/logon.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ defmodule Neo4ex.BoltProtocol.Structure.Message.Extra.Logon do
# @predefined_schemes ~w(none basic bearer kerberos)

embeded_structure do
field(:scheme, default: "")
field(:principal, default: "")
field(:credentials, default: "")
field(:scheme)
field(:principal)
field(:credentials)
end
end
4 changes: 2 additions & 2 deletions test/neo4ex/bolt_protocol/encoder_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ defmodule Neo4ex.BoltProtocol.EncoderTest do
extra: %{
"user_agent" => "Neo4ex/#{@version}",
"scheme" => "none",
"credentials" => "",
"principal" => ""
"credentials" => nil,
"principal" => nil
}
}
end
Expand Down
72 changes: 72 additions & 0 deletions test/neo4ex/bolt_protocol_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ defmodule Neo4ex.BoltProtocolTest do
import Mox
import Neo4ex.Neo4jConnection

alias Neo4ex.BoltProtocol.Structure.Message.Extra
alias Neo4ex.BoltProtocol.Structure.Message.Request.Logon
alias Neo4ex.BoltProtocol.Structure.Message.Request.Hello
alias Neo4ex.BoltProtocol.Structure.Message.Request.Rollback
alias Neo4ex.BoltProtocol.Structure.Message.Request.Commit
alias Neo4ex.BoltProtocol.Structure.Message.Request.Begin
Expand All @@ -24,6 +27,75 @@ defmodule Neo4ex.BoltProtocolTest do
%{socket: %Socket{bolt_version: Version.parse!("4.3.0")}, query: query}
end

describe "connect/1" do
test "properly negotiates version" do
success_message = %Success{}
encoded_success_message = Encoder.encode(success_message, "4.0.0")

# two versions, 4.0.0 and 0.0.0 x 3 (client always sends 4 versions)
handshake =
<<0x60, 0x60, 0xB0, 0x17, 0::8, 0::8, 0::8, 4::8, 0::96>>

hello = generate_message_chunk(%Hello{extra: %Extra.Hello{scheme: "none"}}, "4.0.0")

SocketMock
|> expect(:connect, fn ~c"noop", 7687, [:binary, {:active, false}] -> {:ok, nil} end)
|> expect(:send, fn _, ^handshake -> :ok end)
|> expect(:recv, fn _, 4 -> {:ok, <<0::16, 0::8, 4::8>>} end)
|> expect(:send, fn _, ^hello -> :ok end)
|> expect_message(encoded_success_message)

assert {:ok, %Socket{bolt_version: %Version{major: 4, minor: 0, patch: 0}}} ==
BoltProtocol.connect(hostname: "noop", versions: ["4.0.0"])

encoded_success_message = Encoder.encode(success_message, "5.3.0")

# two versions, 5.3.0 and 0.0.0 x 3 (client always sends 4 versions)
handshake =
<<0x60, 0x60, 0xB0, 0x17, 0::8, 0::8, 3::8, 5::8, 0::96>>

hello = generate_message_chunk(%Hello{}, "5.3.0")

logon =
generate_message_chunk(
%Logon{auth: %Extra.Logon{scheme: "bearer", credentials: "abc"}},
"5.3.0"
)

SocketMock
|> expect(:connect, fn ~c"noop", 7687, [:binary, {:active, false}] -> {:ok, nil} end)
|> expect(:send, fn _, ^handshake -> :ok end)
|> expect(:recv, fn _, 4 -> {:ok, <<0::16, 3::8, 5::8>>} end)
|> expect(:send, fn _, ^hello -> :ok end)
|> expect_message(encoded_success_message)
|> expect(:send, fn _, ^logon -> :ok end)
|> expect_message(encoded_success_message)

assert {:ok, %Socket{bolt_version: %Version{major: 5, minor: 3, patch: 0}}} ==
BoltProtocol.connect(hostname: "noop", versions: ["5.3.0"], credentials: "abc")
end

test "gracefully handles failures" do
message = %Failure{metadata: %{"message" => "failure"}}
encoded_failure_message = Encoder.encode(message, "5.3.0")

# two versions, 5.3.0 and 0.0.0 x 3 (client always sends 4 versions)
handshake =
<<0x60, 0x60, 0xB0, 0x17, 0::8, 0::8, 3::8, 5::8, 0::96>>

hello = generate_message_chunk(%Hello{}, "5.3.0")

SocketMock
|> expect(:connect, fn ~c"noop", 7687, [:binary, {:active, false}] -> {:ok, nil} end)
|> expect(:send, fn _, ^handshake -> :ok end)
|> expect(:recv, fn _, 4 -> {:ok, <<0::16, 3::8, 5::8>>} end)
|> expect(:send, fn _, ^hello -> :ok end)
|> expect_message(encoded_failure_message)

assert {:error, "failure"} == BoltProtocol.connect(hostname: "noop", versions: ["5.3.0"])
end
end

describe "disconnect/2" do
test "sends Goodbye message", %{socket: socket} do
chunk = generate_message_chunk(%Goodbye{})
Expand Down
10 changes: 10 additions & 0 deletions test/neo4ex/connector_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule Neo4ex.ConnectorTest do

import Mox

require Neo4ex.Connector

alias Neo4ex.BoltProtocol.Structure.Message.Request.Run
alias Neo4ex.BoltProtocol.Encoder

Expand Down Expand Up @@ -71,4 +73,12 @@ defmodule Neo4ex.ConnectorTest do
assert {:error, DBConnection.ConnectionError.exception(":closed")} == Connector.read(socket)
end
end

describe "supported_versions/0" do
test "returns compile-time list of versions" do
assert Enum.map(20..0//-1, fn minor -> Version.parse!("5.#{minor}.0") end) ++
Enum.map(4..0//-1, fn minor -> Version.parse!("4.#{minor}.0") end) ==
Connector.supported_versions()
end
end
end
4 changes: 2 additions & 2 deletions test/support/neo4j_connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ defmodule Neo4ex.Neo4jConnection do

alias Neo4ex.BoltProtocol.Encoder

def generate_message_chunk(message) do
encoded_message = Encoder.encode(message, "4.0.0")
def generate_message_chunk(message, version \\ "4.0.0") do
encoded_message = Encoder.encode(message, version)
message_size = byte_size(encoded_message)
<<message_size::16, encoded_message::binary, 0::16>>
end
Expand Down

0 comments on commit a74b0b1

Please sign in to comment.