diff --git a/lib/chainweb/client.ex b/lib/chainweb/client.ex index b1fd26f..fdcd588 100644 --- a/lib/chainweb/client.ex +++ b/lib/chainweb/client.ex @@ -7,8 +7,8 @@ defmodule Kadena.Chainweb.Client do @behaviour Client.Spec @impl true - def request(method, path, headers \\ [], body \\ "", opts \\ []), - do: impl().request(method, path, headers, body, opts) + def request(method, url, headers \\ [], body \\ "", opts \\ []), + do: impl().request(method, url, headers, body, opts) @spec impl() :: atom() defp impl do diff --git a/lib/chainweb/client/default.ex b/lib/chainweb/client/default.ex index d1e32af..1b85a26 100644 --- a/lib/chainweb/client/default.ex +++ b/lib/chainweb/client/default.ex @@ -26,17 +26,17 @@ defmodule Kadena.Chainweb.Client.Default do } @impl true - def request(method, path, headers \\ [], body \\ "", opts \\ []) do + def request(method, url, headers \\ [], body \\ "", opts \\ []) do options = http_options(opts) method - |> http_client().request(path, headers, body, options) + |> http_client().request(url, headers, body, options) |> handle_response() end @spec handle_response(response :: client_response()) :: parsed_response() defp handle_response({:ok, status, _headers, body}) when status in 200..299 do - decoded_body = json_library().decode!(body, keys: :atoms) + decoded_body = json_library().decode!(body, keys: &snake_case_atom/1) {:ok, decoded_body} end @@ -55,6 +55,13 @@ defmodule Kadena.Chainweb.Client.Default do defp handle_response({:error, reason}), do: {:error, Error.new({:network, reason})} + @spec snake_case_atom(string :: String.t()) :: atom() + defp snake_case_atom(string) do + string + |> Macro.underscore() + |> String.to_atom() + end + @spec http_client() :: atom() defp http_client, do: Application.get_env(:kadena, :http_client, :hackney) diff --git a/lib/chainweb/client/spec.ex b/lib/chainweb/client/spec.ex index ac7820c..e8dc09d 100644 --- a/lib/chainweb/client/spec.ex +++ b/lib/chainweb/client/spec.ex @@ -19,8 +19,8 @@ defmodule Kadena.Chainweb.Client.Spec do @callback request( method :: method(), url :: binary(), - body :: binary(), headers :: headers(), + body :: binary(), options :: options() ) :: response() | response_error() end diff --git a/lib/chainweb/mapping.ex b/lib/chainweb/mapping.ex deleted file mode 100644 index 46e7d01..0000000 --- a/lib/chainweb/mapping.ex +++ /dev/null @@ -1,67 +0,0 @@ -defmodule Kadena.Chainweb.Mapping do - @moduledoc """ - Takes a result map or list of maps from Chainweb response and returns a struct - (e.g. `%Chainweb.Types.LocalResponse{}`) or list of structs. - """ - - @type attr_value :: any() - @type attr_type :: - :atom - | {:map, Keyword.t()} - | {:struct, module()} - | {:list, atom(), Keyword.t() | module()} - - @spec build(module :: struct(), attrs :: map()) :: struct() - def build(module, attrs) do - module_attrs = - module - |> Map.from_struct() - |> Map.keys() - |> Enum.map(&Atom.to_string/1) - |> (&Map.take(attrs, &1)).() - |> map_to_keyword_list() - - struct!(module, module_attrs) - end - - @spec parse(module :: struct(), mapping :: Keyword.t()) :: struct() - def parse(module, []), do: module - - def parse(module, [{attr, type} | attrs]) do - value = Map.get(module, attr) - parsed_value = do_parse(type, value) - - module - |> Map.put(attr, parsed_value) - |> parse(attrs) - end - - @spec do_parse(type :: attr_type(), value :: attr_value()) :: attr_value() - defp do_parse(:atom, value) when is_binary(value), do: String.to_existing_atom(value) - - defp do_parse({:map, mapping}, value) when is_map(value) do - Enum.reduce(mapping, value, fn {key, type}, acc -> - acc - |> Map.get(key) - |> (&do_parse(type, &1)).() - |> (&Map.put(acc, key, &1)).() - end) - end - - defp do_parse({:struct, module}, value) when not is_nil(value), do: module.new(value) - - defp do_parse({:list, :map, mapping}, values) when is_list(values) do - Enum.map(values, &do_parse({:map, mapping}, &1)) - end - - defp do_parse({:list, :struct, module}, values) when is_list(values) do - Enum.map(values, &module.new(&1)) - end - - defp do_parse(_type, value), do: value - - @spec map_to_keyword_list(map :: map()) :: Keyword.t() - defp map_to_keyword_list(attrs) do - Enum.map(attrs, fn {k, v} -> {String.to_existing_atom(k), v} end) - end -end diff --git a/lib/chainweb/network.ex b/lib/chainweb/network.ex new file mode 100644 index 0000000..23eab9a --- /dev/null +++ b/lib/chainweb/network.ex @@ -0,0 +1,27 @@ +defmodule Kadena.Chainweb.Network do + @moduledoc """ + Utility that handles Chainweb network URL resolution. + """ + + alias Kadena.Chainweb.Request + + @type request :: Request.t() + + @base_urls [ + testnet04: "https://api.testnet.chainweb.com/chainweb/0.0/testnet04", + mainnet01: "https://api.chainweb.com/chainweb/0.0/mainnet01" + ] + + @spec base_url(request :: request()) :: String.t() | nil + def base_url(%Request{network_id: nil}), do: nil + def base_url(%Request{api_type: :pact, chain_id: nil}), do: nil + + def base_url(%Request{api_type: :p2p, network_id: network_id, chain_id: nil}), + do: @base_urls[network_id] + + def base_url(%Request{api_type: :p2p, network_id: network_id, chain_id: chain_id}), + do: "#{@base_urls[network_id]}/chain/#{chain_id}" + + def base_url(%Request{api_type: :pact, network_id: network_id, chain_id: chain_id}), + do: "#{@base_urls[network_id]}/chain/#{chain_id}/pact/api/v1" +end diff --git a/lib/chainweb/pact/command_result.ex b/lib/chainweb/pact/command_result.ex new file mode 100644 index 0000000..ddc34cb --- /dev/null +++ b/lib/chainweb/pact/command_result.ex @@ -0,0 +1,32 @@ +defmodule Kadena.Chainweb.Pact.CommandResult do + @moduledoc """ + `CommandResult` struct definition. + """ + + @behaviour Kadena.Chainweb.Pact.Resource + + @type req_key :: String.t() + @type tx_id :: number() | nil + @type result :: map() + @type gas :: number() + @type logs :: String.t() | nil + @type continuation :: map() | nil + @type meta_data :: map() | nil + @type events :: list(map()) | nil + + @type t :: %__MODULE__{ + req_key: req_key(), + tx_id: tx_id(), + result: result(), + gas: gas(), + logs: logs(), + continuation: continuation(), + meta_data: meta_data(), + events: events() + } + + defstruct [:req_key, :tx_id, :result, :gas, :logs, :continuation, :meta_data, :events] + + @impl true + def new(attrs), do: struct(%__MODULE__{}, attrs) +end diff --git a/lib/chainweb/pact/listen_response.ex b/lib/chainweb/pact/listen_response.ex new file mode 100644 index 0000000..fa2d2ec --- /dev/null +++ b/lib/chainweb/pact/listen_response.ex @@ -0,0 +1,32 @@ +defmodule Kadena.Chainweb.Pact.ListenResponse do + @moduledoc """ + `ListenResponse` struct definition. + """ + + @behaviour Kadena.Chainweb.Pact.Resource + + @type req_key :: String.t() + @type tx_id :: number() | nil + @type result :: map() + @type gas :: number() + @type logs :: String.t() | nil + @type continuation :: map() | nil + @type meta_data :: map() | nil + @type events :: list(map()) | nil + + @type t :: %__MODULE__{ + req_key: req_key(), + tx_id: tx_id(), + result: result(), + gas: gas(), + logs: logs(), + continuation: continuation(), + meta_data: meta_data(), + events: events() + } + + defstruct [:req_key, :tx_id, :result, :gas, :logs, :continuation, :meta_data, :events] + + @impl true + def new(attrs), do: struct(%__MODULE__{}, attrs) +end diff --git a/lib/chainweb/pact/local_response.ex b/lib/chainweb/pact/local_response.ex new file mode 100644 index 0000000..62ea87b --- /dev/null +++ b/lib/chainweb/pact/local_response.ex @@ -0,0 +1,32 @@ +defmodule Kadena.Chainweb.Pact.LocalResponse do + @moduledoc """ + `LocalResponse` struct definition. + """ + + @behaviour Kadena.Chainweb.Pact.Resource + + @type req_key :: String.t() + @type tx_id :: number() | nil + @type result :: map() + @type gas :: number() + @type logs :: String.t() | nil + @type continuation :: map() | nil + @type meta_data :: map() | nil + @type events :: list(map()) | nil + + @type t :: %__MODULE__{ + req_key: req_key(), + tx_id: tx_id(), + result: result(), + gas: gas(), + logs: logs(), + continuation: continuation(), + meta_data: meta_data(), + events: events() + } + + defstruct [:req_key, :tx_id, :result, :gas, :logs, :continuation, :meta_data, :events] + + @impl true + def new(attrs), do: struct(%__MODULE__{}, attrs) +end diff --git a/lib/chainweb/pact/poll_response.ex b/lib/chainweb/pact/poll_response.ex new file mode 100644 index 0000000..9230b9f --- /dev/null +++ b/lib/chainweb/pact/poll_response.ex @@ -0,0 +1,25 @@ +defmodule Kadena.Chainweb.Pact.PollResponse do + @moduledoc """ + `PollResponse` struct definition. + """ + + @behaviour Kadena.Chainweb.Pact.Resource + + alias Kadena.Chainweb.Pact.CommandResult + + @type results :: list(CommandResult.t()) + + @type t :: %__MODULE__{results: results()} + + defstruct [:results] + + @impl true + def new(attrs) do + results = + attrs + |> Map.values() + |> Enum.map(&CommandResult.new/1) + + struct(%__MODULE__{}, results: results) + end +end diff --git a/lib/chainweb/pact/request.ex b/lib/chainweb/pact/request.ex index 21257fd..25d0b5f 100644 --- a/lib/chainweb/pact/request.ex +++ b/lib/chainweb/pact/request.ex @@ -11,7 +11,7 @@ defmodule Kadena.Chainweb.Pact.Request do SPVRequestBody } - alias Kadena.Chainweb.Pact.Resources.{ + alias Kadena.Chainweb.Pact.{ ListenResponse, LocalResponse, PollResponse, diff --git a/lib/chainweb/pact/resource.ex b/lib/chainweb/pact/resource.ex new file mode 100644 index 0000000..d8f953e --- /dev/null +++ b/lib/chainweb/pact/resource.ex @@ -0,0 +1,10 @@ +defmodule Kadena.Chainweb.Pact.Resource do + @moduledoc """ + Specifies contracts to build Chainweb Pact resources. + """ + + @type attrs :: map() | String.t() + @type resource :: struct() + + @callback new(attrs()) :: resource() +end diff --git a/lib/chainweb/pact/resources/command_result.ex b/lib/chainweb/pact/resources/command_result.ex deleted file mode 100644 index 8a00c25..0000000 --- a/lib/chainweb/pact/resources/command_result.ex +++ /dev/null @@ -1,56 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.CommandResult do - @moduledoc """ - `CommandResult` struct definition. - """ - - alias Kadena.Chainweb.Mapping - - alias Kadena.Chainweb.Pact.Resources.{ - PactEventsList, - PactExec, - PactResult, - ResponseMetaData - } - - alias Kadena.Types.Base64Url - - @behaviour Kadena.Chainweb.Resource - - @type str :: String.t() - @type req_key :: Base64Url.t() - @type tx_id :: number() | nil - @type result :: PactResult.t() - @type gas :: number() - @type logs :: String.t() | nil - @type continuation :: PactExec.t() | nil - @type meta_data :: ResponseMetaData.t() | nil - @type events :: PactEventsList.t() | nil - - @type t :: %__MODULE__{ - req_key: req_key(), - tx_id: tx_id(), - result: result(), - gas: gas(), - logs: logs(), - continuation: continuation(), - meta_data: meta_data(), - events: events() - } - - defstruct [:req_key, :tx_id, :result, :gas, :logs, :continuation, :meta_data, :events] - - @mapping [ - req_key: {:struct, Base64Url}, - result: {:struct, PactResult}, - continuation: {:struct, PactExec}, - meta_data: {:struct, ResponseMetaData}, - events: {:struct, PactEventsList} - ] - - @impl true - def new(attrs) do - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/continuation.ex b/lib/chainweb/pact/resources/continuation.ex deleted file mode 100644 index 60f0a0a..0000000 --- a/lib/chainweb/pact/resources/continuation.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.Continuation do - @moduledoc """ - `Continuation` struct definition. - """ - - alias Kadena.Chainweb.Mapping - alias Kadena.Types.PactValue - - @behaviour Kadena.Chainweb.Resource - - @type continuation_def :: String.t() - @type args :: PactValue.t() - - @type t :: %__MODULE__{ - def: continuation_def(), - args: args() - } - - defstruct [:def, :args] - - @mapping [args: {:struct, PactValue}] - - @impl true - def new(attrs) do - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/listen_response.ex b/lib/chainweb/pact/resources/listen_response.ex deleted file mode 100644 index 004066f..0000000 --- a/lib/chainweb/pact/resources/listen_response.ex +++ /dev/null @@ -1,55 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.ListenResponse do - @moduledoc """ - `ListenResponse` struct definition. - """ - - alias Kadena.Types.Base64Url - - alias Kadena.Chainweb.Pact.Resources.{ - CommandResult, - PactEventsList, - PactExec, - PactResult, - ResponseMetaData - } - - @behaviour Kadena.Chainweb.Resource - - @type req_key :: Base64Url.t() - @type tx_id :: number() | nil - @type result :: PactResult.t() - @type gas :: number() - @type logs :: String.t() | nil - @type continuation :: PactExec.t() - @type meta_data :: ResponseMetaData.t() | nil - @type events :: PactEventsList.t() | nil - - @type command_result :: CommandResult.t() - @type validation :: t() | {:error, Keyword.t()} - - @type t :: %__MODULE__{ - req_key: req_key(), - tx_id: tx_id(), - result: result(), - gas: gas(), - logs: logs(), - continuation: continuation(), - meta_data: meta_data(), - events: events() - } - - defstruct [:req_key, :tx_id, :result, :gas, :logs, :continuation, :meta_data, :events] - - @impl true - def new(attrs) do - attrs - |> CommandResult.new() - |> build_listen_response() - end - - @spec build_listen_response(command_result :: command_result()) :: validation() - defp build_listen_response(%CommandResult{} = command_result) do - attrs = Map.from_struct(command_result) - struct(%__MODULE__{}, attrs) - end -end diff --git a/lib/chainweb/pact/resources/local_response.ex b/lib/chainweb/pact/resources/local_response.ex deleted file mode 100644 index cb70089..0000000 --- a/lib/chainweb/pact/resources/local_response.ex +++ /dev/null @@ -1,53 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.LocalResponse do - @moduledoc """ - `LocalResponse` struct definition. - """ - - alias Kadena.Types.Base64Url - - alias Kadena.Chainweb.Pact.Resources.{ - CommandResult, - PactEventsList, - PactExec, - PactResult, - ResponseMetaData - } - - @behaviour Kadena.Chainweb.Resource - - @type req_key :: Base64Url.t() - @type tx_id :: number() | nil - @type result :: PactResult.t() - @type gas :: number() - @type logs :: String.t() | nil - @type continuation :: PactExec.t() - @type meta_data :: ResponseMetaData.t() | nil - @type events :: PactEventsList.t() | nil - @type command_result :: CommandResult.t() - - @type t :: %__MODULE__{ - req_key: req_key(), - tx_id: tx_id(), - result: result(), - gas: gas(), - logs: logs(), - continuation: continuation(), - meta_data: meta_data(), - events: events() - } - - defstruct [:req_key, :tx_id, :result, :gas, :logs, :continuation, :meta_data, :events] - - @impl true - def new(attrs) do - attrs - |> CommandResult.new() - |> build_local_request_body() - end - - @spec build_local_request_body(command_result :: command_result()) :: t() - defp build_local_request_body(%CommandResult{} = command_result) do - attrs = Map.from_struct(command_result) - struct(%__MODULE__{}, attrs) - end -end diff --git a/lib/chainweb/pact/resources/meta_data_result.ex b/lib/chainweb/pact/resources/meta_data_result.ex deleted file mode 100644 index 527955d..0000000 --- a/lib/chainweb/pact/resources/meta_data_result.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.MetaDataResult do - @moduledoc """ - `MetaDataResult` struct definition. - """ - - alias Kadena.Chainweb.Mapping - alias Kadena.Types.ChainID - - @behaviour Kadena.Chainweb.Resource - - @type creation_time :: number() - @type ttl :: number() - @type gas_limit :: number() - @type gas_price :: number() - @type sender :: String.t() - @type chain_id :: ChainID.t() - - @type t :: %__MODULE__{ - creation_time: creation_time(), - ttl: ttl(), - gas_limit: gas_limit(), - gas_price: gas_price(), - sender: sender(), - chain_id: chain_id() - } - - defstruct [:creation_time, :ttl, :gas_limit, :gas_price, :sender, :chain_id] - - @mapping [chain_id: {:struct, ChainID}] - - @impl true - def new(attrs) do - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/pact_event.ex b/lib/chainweb/pact/resources/pact_event.ex deleted file mode 100644 index 169e8a1..0000000 --- a/lib/chainweb/pact/resources/pact_event.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactEvent do - @moduledoc """ - `PactEventModule` struct definition. - """ - - alias Kadena.Chainweb.Mapping - alias Kadena.Chainweb.Pact.Resources.PactEventModule - alias Kadena.Types.PactValuesList - - @behaviour Kadena.Chainweb.Resource - - @type name :: String.t() - @type pact_event_module :: PactEventModule.t() - @type params :: PactValuesList.t() - @type module_hash :: String.t() - - @type t :: %__MODULE__{ - name: name(), - module: pact_event_module(), - params: params(), - module_hash: module_hash() - } - - defstruct [:name, :module, :params, :module_hash] - - @mapping [ - module: {:struct, PactEventModule}, - params: {:struct, PactValuesList} - ] - - @impl true - def new(attrs) do - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/pact_event_module.ex b/lib/chainweb/pact/resources/pact_event_module.ex deleted file mode 100644 index 6a6c906..0000000 --- a/lib/chainweb/pact/resources/pact_event_module.ex +++ /dev/null @@ -1,19 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactEventModule do - @moduledoc """ - `PactEventModule` struct definition. - """ - - alias Kadena.Chainweb.Mapping - - @behaviour Kadena.Chainweb.Resource - - @type name :: String.t() - @type namespace :: String.t() | nil - - @type t :: %__MODULE__{name: name(), namespace: namespace()} - - defstruct [:name, :namespace] - - @impl true - def new(attrs), do: Mapping.build(%__MODULE__{}, attrs) -end diff --git a/lib/chainweb/pact/resources/pact_events_list.ex b/lib/chainweb/pact/resources/pact_events_list.ex deleted file mode 100644 index 77c3c26..0000000 --- a/lib/chainweb/pact/resources/pact_events_list.ex +++ /dev/null @@ -1,27 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactEventsList do - @moduledoc """ - `PactEventsList` struct definition. - """ - alias Kadena.Chainweb.Mapping - alias Kadena.Chainweb.Pact.Resources.PactEvent - - @behaviour Kadena.Chainweb.Resource - - @type pact_event :: PactEvent.t() - @type pact_events :: list(pact_event()) - - @type t :: %__MODULE__{pact_events: pact_events()} - - defstruct pact_events: [] - - @mapping [pact_events: {:list, :struct, PactEvent}] - - @impl true - def new(pact_events) do - attrs = %{"pact_events" => pact_events} - - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/pact_exec.ex b/lib/chainweb/pact/resources/pact_exec.ex deleted file mode 100644 index 7f0def7..0000000 --- a/lib/chainweb/pact/resources/pact_exec.ex +++ /dev/null @@ -1,50 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactExec do - @moduledoc """ - `PactExec` struct definition. - """ - - alias Kadena.Chainweb.Mapping - - alias Kadena.Chainweb.Pact.Resources.{ - Continuation, - Yield - } - - alias Kadena.Types.{PactTransactionHash, Step} - - @behaviour Kadena.Chainweb.Resource - - @type pact_id :: PactTransactionHash.t() - @type step :: Step.t() - @type step_count :: integer() - @type executed :: boolean() | nil - @type step_has_rollback :: boolean() - @type continuation :: Continuation.t() - @type yield :: Yield.t() | nil - - @type t :: %__MODULE__{ - pact_id: pact_id(), - step: step(), - step_count: step_count(), - executed: executed(), - step_has_rollback: step_has_rollback(), - continuation: continuation(), - yield: yield() - } - - defstruct [:pact_id, :step, :step_count, :executed, :step_has_rollback, :continuation, :yield] - - @mapping [ - pact_id: {:struct, PactTransactionHash}, - step: {:struct, Step}, - continuation: {:struct, Continuation}, - yield: {:struct, Yield} - ] - - @impl true - def new(attrs) do - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/pact_result.ex b/lib/chainweb/pact/resources/pact_result.ex deleted file mode 100644 index 33bed3f..0000000 --- a/lib/chainweb/pact/resources/pact_result.ex +++ /dev/null @@ -1,35 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactResult do - @moduledoc """ - `PactResult` struct definition. - """ - - alias Kadena.Types.PactValue - - @behaviour Kadena.Chainweb.Resource - - @type status :: :success | :failure - @type error :: map() - @type data :: PactValue.t() | error() - - @type t :: %__MODULE__{ - status: status(), - data: data() - } - - defstruct [:status, :data] - - @impl true - def new(%{"status" => "success", "data" => data}) do - %__MODULE__{ - status: :success, - data: PactValue.new(data) - } - end - - def new(%{"status" => "failure", "data" => data}) do - %__MODULE__{ - status: :failure, - data: data - } - end -end diff --git a/lib/chainweb/pact/resources/poll_response.ex b/lib/chainweb/pact/resources/poll_response.ex deleted file mode 100644 index b089a74..0000000 --- a/lib/chainweb/pact/resources/poll_response.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PollResponse do - @moduledoc """ - `PollResponse` struct definition. - """ - - alias Kadena.Chainweb.Mapping - alias Kadena.Chainweb.Pact.Resources.CommandResult - - @behaviour Kadena.Chainweb.Resource - - @type results :: list(CommandResult.t()) - - @type t :: %__MODULE__{results: results()} - - defstruct [:results] - - @mapping [results: {:list, :struct, CommandResult}] - - @impl true - def new(attrs) do - values = Map.values(attrs) - attrs = %{"results" => values} - - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/provenance.ex b/lib/chainweb/pact/resources/provenance.ex deleted file mode 100644 index cd6a919..0000000 --- a/lib/chainweb/pact/resources/provenance.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.Provenance do - @moduledoc """ - `Provenance` struct definition. - """ - - alias Kadena.Chainweb.Mapping - alias Kadena.Types.ChainID - - @behaviour Kadena.Chainweb.Resource - - @type target_chain_id :: ChainID.t() - @type module_hash :: String.t() - - @type t :: %__MODULE__{ - target_chain_id: target_chain_id(), - module_hash: module_hash() - } - - defstruct [:target_chain_id, :module_hash] - - @mapping [target_chain_id: {:struct, ChainID}] - - @impl true - def new(attrs) do - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/response_meta_data.ex b/lib/chainweb/pact/resources/response_meta_data.ex deleted file mode 100644 index edbd2c6..0000000 --- a/lib/chainweb/pact/resources/response_meta_data.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.ResponseMetaData do - @moduledoc """ - `ResponseMetaData` struct definition. - """ - - alias Kadena.Chainweb.Mapping - alias Kadena.Chainweb.Pact.Resources.MetaDataResult - - @behaviour Kadena.Chainweb.Resource - - @type hash :: String.t() - @type block_hash :: hash() - @type block_number :: number() - @type block_time :: block_number() - @type block_height :: block_number() - @type prev_block_hash :: hash() - @type public_meta :: MetaDataResult.t() | nil - - @type t :: %__MODULE__{ - block_hash: block_hash(), - block_time: block_time(), - block_height: block_height(), - prev_block_hash: prev_block_hash(), - public_meta: public_meta() - } - - defstruct [:block_hash, :block_time, :block_height, :prev_block_hash, :public_meta] - - @mapping [public_meta: {:struct, MetaDataResult}] - - @impl true - def new(attrs) do - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/send_response.ex b/lib/chainweb/pact/resources/send_response.ex deleted file mode 100644 index b238952..0000000 --- a/lib/chainweb/pact/resources/send_response.ex +++ /dev/null @@ -1,25 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.SendResponse do - @moduledoc """ - `SendResponse` struct definition. - """ - - alias Kadena.Chainweb.Mapping - alias Kadena.Types.Base64UrlsList - - @behaviour Kadena.Chainweb.Resource - - @type request_keys :: Base64UrlsList.t() - - @type t :: %__MODULE__{request_keys: request_keys()} - - defstruct request_keys: [] - - @mapping [request_keys: {:struct, Base64UrlsList}] - - @impl true - def new(attrs) do - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/resources/spv_response.ex b/lib/chainweb/pact/resources/spv_response.ex deleted file mode 100644 index e47ea28..0000000 --- a/lib/chainweb/pact/resources/spv_response.ex +++ /dev/null @@ -1,27 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.SPVResponse do - @moduledoc """ - `SPVResponse` struct definition. - """ - - alias Kadena.Types.SPVProof - - @behaviour Kadena.Chainweb.Resource - - @type response :: String.t() - @type spv_proof :: SPVProof.t() | {:error, Keyword.t()} - - @type t :: %__MODULE__{response: response()} - - defstruct [:response] - - @impl true - def new(response) do - response - |> SPVProof.new() - |> build_spv_response() - end - - @spec build_spv_response(spv_proof :: spv_proof()) :: t() - defp build_spv_response(%SPVProof{value: response}), do: %__MODULE__{response: response} - defp build_spv_response(_error), do: %__MODULE__{} -end diff --git a/lib/chainweb/pact/resources/yield.ex b/lib/chainweb/pact/resources/yield.ex deleted file mode 100644 index beeae8d..0000000 --- a/lib/chainweb/pact/resources/yield.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.Yield do - @moduledoc """ - `Yield` struct definition. - """ - - alias Kadena.Chainweb.Mapping - alias Kadena.Chainweb.Pact.Resources.Provenance - - @behaviour Kadena.Chainweb.Resource - - @type data :: map() - @type provenance :: Provenance.t() | nil - - @type t :: %__MODULE__{ - data: data(), - provenance: provenance() - } - - defstruct [:data, :provenance] - - @mapping [provenance: {:struct, Provenance}] - - @impl true - def new(attrs) do - %__MODULE__{} - |> Mapping.build(attrs) - |> Mapping.parse(@mapping) - end -end diff --git a/lib/chainweb/pact/send_response.ex b/lib/chainweb/pact/send_response.ex new file mode 100644 index 0000000..c1dfd99 --- /dev/null +++ b/lib/chainweb/pact/send_response.ex @@ -0,0 +1,16 @@ +defmodule Kadena.Chainweb.Pact.SendResponse do + @moduledoc """ + `SendResponse` struct definition. + """ + + @behaviour Kadena.Chainweb.Pact.Resource + + @type request_keys :: list(String.t()) + + @type t :: %__MODULE__{request_keys: request_keys()} + + defstruct request_keys: [] + + @impl true + def new(attrs), do: struct(%__MODULE__{}, attrs) +end diff --git a/lib/chainweb/pact/spv_response.ex b/lib/chainweb/pact/spv_response.ex new file mode 100644 index 0000000..2402fd8 --- /dev/null +++ b/lib/chainweb/pact/spv_response.ex @@ -0,0 +1,16 @@ +defmodule Kadena.Chainweb.Pact.SPVResponse do + @moduledoc """ + `SPVResponse` struct definition. + """ + + @behaviour Kadena.Chainweb.Pact.Resource + + @type response :: String.t() + + @type t :: %__MODULE__{response: response()} + + defstruct [:response] + + @impl true + def new(response) when is_binary(response), do: struct(%__MODULE__{}, response: response) +end diff --git a/lib/chainweb/request.ex b/lib/chainweb/request.ex new file mode 100644 index 0000000..21793c2 --- /dev/null +++ b/lib/chainweb/request.ex @@ -0,0 +1,142 @@ +defmodule Kadena.Chainweb.Request do + @moduledoc """ + A module to work with Chainweb requests. + Requests are composed in a functional manner. + The request does not happen until it is configured and passed to `perform/1`. + """ + + alias Kadena.Chainweb.{Client, Error, Network} + + @type api_type :: :pact | :p2p + @type network_id :: :testnet04 | :mainnet01 + @type chain_id :: String.t() | nil + @type method :: :get | :post | :put + @type headers :: [{binary(), binary()}] + @type body :: String.t() | nil + @type query :: Keyword.t() + @type encoded_query :: String.t() | nil + @type endpoint :: String.t() | nil + @type path :: String.t() | nil + @type segment :: String.t() | nil + @type opts :: Keyword.t() + @type params :: Keyword.t() + @type response :: {:ok, map()} | {:error, Error.t()} + @type parsed_response :: {:ok, struct()} | {:error, Error.t()} + + @type t :: %__MODULE__{ + method: method(), + api_type: api_type(), + network_id: network_id(), + chain_id: chain_id(), + endpoint: endpoint(), + path: path(), + segment: segment(), + segment_path: path(), + query: query(), + headers: headers(), + body: body(), + encoded_query: encoded_query() + } + + defstruct [ + :method, + :api_type, + :network_id, + :chain_id, + :endpoint, + :path, + :segment, + :segment_path, + :query, + :headers, + :body, + :encoded_query + ] + + @spec new(method :: method(), opts :: opts()) :: t() + def new(method, [{api_type, opts}]) when api_type in [:pact, :p2p] do + network_id = Keyword.get(opts, :network_id) + chain_id = Keyword.get(opts, :chain_id) + endpoint = Keyword.get(opts, :endpoint) + path = Keyword.get(opts, :path) + segment = Keyword.get(opts, :segment) + segment_path = Keyword.get(opts, :segment_path) + + %__MODULE__{ + method: method, + api_type: api_type, + network_id: network_id, + chain_id: chain_id, + endpoint: endpoint, + path: path, + segment: segment, + segment_path: segment_path, + query: [], + headers: [] + } + end + + @spec set_chain_id(t(), chain_id :: chain_id()) :: t() + def set_chain_id(%__MODULE__{} = request, chain_id), do: %{request | chain_id: chain_id} + + @spec set_network(t(), network :: network_id()) :: t() + def set_network(%__MODULE__{} = request, network), do: %{request | network_id: network} + + @spec add_body(request :: t(), body :: body()) :: t() + def add_body(%__MODULE__{} = request, body), do: %{request | body: body} + + @spec add_headers(request :: t(), headers :: headers()) :: t() + def add_headers(%__MODULE__{} = request, headers), do: %{request | headers: headers} + + @spec add_query(request :: t(), params :: params()) :: t() + def add_query(%__MODULE__{} = request, params), + do: %{request | query: params, encoded_query: build_query_string(params)} + + @spec perform(request :: t()) :: response() + def perform(%__MODULE__{method: method, headers: headers, body: body} = request) do + request + |> build_request_url() + |> (&Client.request(method, &1, headers, body)).() + end + + @spec results(response :: response(), opts :: opts()) :: parsed_response() + def results({:ok, results}, as: resource), do: {:ok, resource.new(results)} + def results({:error, error}, _resource), do: {:error, error} + + @spec build_request_url(request :: t()) :: binary() + defp build_request_url( + %__MODULE__{ + endpoint: endpoint, + path: path, + segment: segment, + segment_path: segment_path, + encoded_query: encoded_query + } = request + ) do + base_url = Network.base_url(request) + + IO.iodata_to_binary([ + if(base_url, do: base_url, else: []), + if(endpoint, do: ["/" | to_string(endpoint)], else: []), + if(path, do: ["/" | to_string(path)], else: []), + if(segment, do: ["/" | to_string(segment)], else: []), + if(segment_path, do: ["/" | to_string(segment_path)], else: []), + if(encoded_query, do: ["?" | encoded_query], else: []) + ]) + end + + @spec build_query_string(params :: params()) :: encoded_query() + defp build_query_string(params) do + params + |> Enum.reject(&is_empty_param/1) + |> encode_query() + end + + @spec encode_query(query :: query()) :: encoded_query() + defp encode_query([]), do: nil + defp encode_query(query), do: URI.encode_query(query) + + @spec is_empty_param(param :: {atom(), any()}) :: boolean() + defp is_empty_param({_key, nil}), do: true + defp is_empty_param({_key, value}), do: to_string(value) == "" +end diff --git a/lib/chainweb/resource.ex b/lib/chainweb/resource.ex deleted file mode 100644 index d90e8d5..0000000 --- a/lib/chainweb/resource.ex +++ /dev/null @@ -1,10 +0,0 @@ -defmodule Kadena.Chainweb.Resource do - @moduledoc """ - Specifies contracts to build Chainweb resources. - """ - - @type attrs :: map() - @type resource :: struct() - - @callback new(attrs()) :: resource() -end diff --git a/lib/types/spv_proof.ex b/lib/types/spv_proof.ex deleted file mode 100644 index c763edf..0000000 --- a/lib/types/spv_proof.ex +++ /dev/null @@ -1,16 +0,0 @@ -defmodule Kadena.Types.SPVProof do - @moduledoc """ - `SPVProof` struct definition. - """ - - @behaviour Kadena.Types.Spec - - @type str :: String.t() - @type t :: %__MODULE__{value: str()} - - defstruct [:value] - - @impl true - def new(value) when is_binary(value), do: %__MODULE__{value: value} - def new(_value), do: {:error, [value: :invalid]} -end diff --git a/mix.exs b/mix.exs index b7c02fd..142bae4 100644 --- a/mix.exs +++ b/mix.exs @@ -94,10 +94,10 @@ defmodule Kadena.MixProject do Kadena.Chainweb.Error, Kadena.Chainweb.Client.Default, Kadena.Chainweb.Client.Spec, - Kadena.Chainweb.Mapping, + Kadena.Chainweb.Network, Kadena.Chainweb.Pact.Request, Kadena.Chainweb.Pact.JSONPayload, - Kadena.Chainweb.Resource + Kadena.Chainweb.Request ], Cryptography: [ Kadena.Cryptography.Sign, @@ -156,7 +156,15 @@ defmodule Kadena.MixProject do Kadena.Types.SPVRequestBody, Kadena.Types.Step ], - "Chainweb Pact Resources": ~r/^Kadena\.Chainweb\.Pact\.Resources\./, + "Chainweb Pact Resources": [ + Kadena.Chainweb.Pact.Resource, + Kadena.Chainweb.Pact.CommandResult, + Kadena.Chainweb.Pact.ListenResponse, + Kadena.Chainweb.Pact.LocalResponse, + Kadena.Chainweb.Pact.PollResponse, + Kadena.Chainweb.Pact.SendResponse, + Kadena.Chainweb.Pact.SPVResponse + ], Utils: Kadena.Utils.MapCase ] end diff --git a/test/chainweb/default_client_test.exs b/test/chainweb/default_client_test.exs index 0151f3f..805e91b 100644 --- a/test/chainweb/default_client_test.exs +++ b/test/chainweb/default_client_test.exs @@ -22,7 +22,7 @@ defmodule Kadena.Chainweb.CannedHTTPClient do do: {:error, :timeout} def request(:post, _url, _headers, _body, _opt) do - json_body = Chainweb.fixture("200") + json_body = Chainweb.fixture("200", raw_data: true) {:ok, 200, [], json_body} end end diff --git a/test/chainweb/mapping_test.exs b/test/chainweb/mapping_test.exs deleted file mode 100644 index 24b59b5..0000000 --- a/test/chainweb/mapping_test.exs +++ /dev/null @@ -1,182 +0,0 @@ -defmodule Kadena.Chainweb.Resources.FakeResource do - @moduledoc false - - defstruct [:id, :status, :value, :extra_values] -end - -defmodule Kadena.Chainweb.Resources.FakeValue do - @moduledoc false - - defstruct [:literal] - - def new(literal) do - %__MODULE__{ - literal: literal - } - end -end - -defmodule Kadena.Chainweb.MappingTest do - use ExUnit.Case - - alias Kadena.Chainweb.Mapping - alias Kadena.Chainweb.Resources.{FakeResource, FakeValue} - - setup do - %{ - attrs: %{ - "id" => "123", - "status" => "success", - "value" => 1, - "extra_values" => [ - "extra1", - "extra2" - ] - }, - resource: %FakeResource{} - } - end - - test "build/2", %{ - resource: resource, - attrs: - %{ - "id" => id, - "status" => status, - "value" => value, - "extra_values" => extra_values - } = attrs - } do - %FakeResource{ - id: ^id, - status: ^status, - value: ^value, - extra_values: ^extra_values - } = Mapping.build(resource, attrs) - end - - test "build/2 empty_attrs", %{resource: resource} do - %FakeResource{ - id: nil, - status: nil, - value: nil, - extra_values: nil - } = Mapping.build(resource, %{}) - end - - test "build/2 extra_attrs", %{ - resource: resource, - attrs: - %{ - "id" => id, - "status" => status, - "value" => value, - "extra_values" => extra_values - } = attrs - } do - attrs = Map.put(attrs, "extra_key", "extra_value") - - %FakeResource{ - id: ^id, - status: ^status, - value: ^value, - extra_values: ^extra_values - } = Mapping.build(resource, attrs) - end - - test "parse/2", %{ - resource: resource, - attrs: - %{ - "id" => id - } = attrs - } do - %FakeResource{ - id: ^id, - status: :success, - value: %FakeValue{literal: 1}, - extra_values: [ - %FakeValue{literal: "extra1"}, - %FakeValue{literal: "extra2"} - ] - } = - resource - |> Mapping.build(attrs) - |> Mapping.parse( - status: :atom, - value: {:struct, FakeValue}, - extra_values: {:list, :struct, FakeValue} - ) - end - - test "parse/2 atom", %{resource: resource, attrs: attrs} do - %FakeResource{status: :success} = - resource - |> Mapping.build(attrs) - |> Mapping.parse(status: :atom) - end - - test "parse/2 map", %{resource: resource} do - attrs = %{ - "value" => %{ - "number" => 1, - "pact_value" => 1 - } - } - - %FakeResource{ - value: %{"number" => 1, "pact_value" => %FakeValue{literal: 1}} - } = - resource - |> Mapping.build(attrs) - |> Mapping.parse(value: {:map, [{"pact_value", {:struct, FakeValue}}]}) - end - - test "parse/2 struct", %{resource: resource, attrs: attrs} do - %FakeResource{value: %FakeValue{literal: 1}} = - resource - |> Mapping.build(attrs) - |> Mapping.parse(value: {:struct, FakeValue}) - end - - test "parse/2 struct_nil", %{resource: resource, attrs: attrs} do - attrs = Map.put(attrs, "value", nil) - - %FakeResource{value: nil} = - resource - |> Mapping.build(attrs) - |> Mapping.parse(value: {:struct, FakeValue}) - end - - test "parse/2 list_of_structs", %{resource: resource, attrs: attrs} do - %FakeResource{extra_values: [%FakeValue{literal: "extra1"}, %FakeValue{literal: "extra2"}]} = - resource - |> Mapping.build(attrs) - |> Mapping.parse(extra_values: {:list, :struct, FakeValue}) - end - - test "parse/2 list_of_maps", %{resource: resource} do - attrs = %{ - "extra_values" => [ - %{ - "number" => 1, - "pact_value" => 1 - }, - %{ - "number" => 2, - "pact_value" => 2 - } - ] - } - - %FakeResource{ - extra_values: [ - %{"number" => 1, "pact_value" => %FakeValue{literal: 1}}, - %{"number" => 2, "pact_value" => %FakeValue{literal: 2}} - ] - } = - resource - |> Mapping.build(attrs) - |> Mapping.parse(extra_values: {:list, :map, [{"pact_value", {:struct, FakeValue}}]}) - end -end diff --git a/test/chainweb/network_test.exs b/test/chainweb/network_test.exs new file mode 100644 index 0000000..c26ee73 --- /dev/null +++ b/test/chainweb/network_test.exs @@ -0,0 +1,49 @@ +defmodule Kadena.Chainweb.NetworkTest do + use ExUnit.Case + + alias Kadena.Chainweb.{Network, Request} + + test "base_url/1 with_nil_network_id" do + nil = Network.base_url(%Request{api_type: :pact, network_id: nil, chain_id: 0}) + end + + test "base_url/1 pact_with_nil_chain_id" do + nil = Network.base_url(%Request{api_type: :pact, network_id: :testnet04, chain_id: nil}) + end + + test "base_url/1 with_invalid_api_type" do + assert_raise FunctionClauseError, fn -> + Network.base_url(%Request{api_type: :invalid, network_id: :testnet04, chain_id: 0}) + end + end + + test "base_url/1 pact_testnet04_chain0" do + "https://api.testnet.chainweb.com/chainweb/0.0/testnet04/chain/0/pact/api/v1" = + Network.base_url(%Request{api_type: :pact, network_id: :testnet04, chain_id: 0}) + end + + test "base_url/1 pact_mainnet01_chain0" do + "https://api.chainweb.com/chainweb/0.0/mainnet01/chain/0/pact/api/v1" = + Network.base_url(%Request{api_type: :pact, network_id: :mainnet01, chain_id: 0}) + end + + test "base_url/1 p2p_testnet04" do + "https://api.testnet.chainweb.com/chainweb/0.0/testnet04" = + Network.base_url(%Request{api_type: :p2p, network_id: :testnet04}) + end + + test "base_url/1 p2p_mainnet01" do + "https://api.chainweb.com/chainweb/0.0/mainnet01" = + Network.base_url(%Request{api_type: :p2p, network_id: :mainnet01}) + end + + test "base_url/1 p2p_testnet04_chain0" do + "https://api.testnet.chainweb.com/chainweb/0.0/testnet04/chain/0" = + Network.base_url(%Request{api_type: :p2p, network_id: :testnet04, chain_id: 0}) + end + + test "base_url/1 p2p_mainnet01_chain0" do + "https://api.chainweb.com/chainweb/0.0/mainnet01/chain/0" = + Network.base_url(%Request{api_type: :p2p, network_id: :mainnet01, chain_id: 0}) + end +end diff --git a/test/chainweb/pact/command_result_test.exs b/test/chainweb/pact/command_result_test.exs new file mode 100644 index 0000000..40adfe6 --- /dev/null +++ b/test/chainweb/pact/command_result_test.exs @@ -0,0 +1,130 @@ +defmodule Kadena.Chainweb.Pact.CommandResultTest do + @moduledoc """ + `CommandResult` struct definition tests. + """ + + use ExUnit.Case + + alias Kadena.Test.Fixtures.Chainweb + + alias Kadena.Chainweb.Pact.CommandResult + + setup do + continuation = %{ + continuation: %{args: "pact_value", def: "coin"}, + executed: false, + pact_id: "yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4", + step: 1, + step_count: 5, + step_has_rollback: false, + yield: %{ + data: %{ + amount: 0.01, + receiver: "4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc", + receiver_guard: %{ + keys: ["4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc"], + pred: "keys-all" + }, + source_chain: 0 + }, + provenance: %{ + module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", + target_chain_id: "1" + } + } + } + + events = [ + %{ + module: %{name: "coin", namespace: nil}, + module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", + name: "TRANSFER", + params: ["account1", "account2", 5.0e-5] + } + ] + + gas = 5 + logs = "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8" + + meta_data = %{ + block_hash: "kZCKTbL3ubONngiGQsJh4fGtP1xrhAoUvcTsqi3uCGg", + block_height: 2708, + block_time: 1_656_709_048_955_370, + prev_block_hash: "LD_o60RB4xnMgLyzkedNV6v-hbCCnx6WXRQy9WDKTgs", + public_meta: %{ + chain_id: "", + creation_time: 0, + gas_limit: 10, + gas_price: 0, + sender: "", + ttl: 0 + } + } + + req_key = "uolsidh4DWN-D44FoElnosL8e5-cGCGn_0l2Nct5mq8" + result = %{data: 3, status: "success"} + tx_id = 123_456 + + %{ + attrs: Chainweb.fixture("command_result"), + continuation: continuation, + events: events, + gas: gas, + logs: logs, + meta_data: meta_data, + req_key: req_key, + result: result, + tx_id: tx_id + } + end + + test "new/1", %{ + attrs: attrs, + continuation: continuation, + events: events, + gas: gas, + logs: logs, + meta_data: meta_data, + req_key: req_key, + result: result, + tx_id: tx_id + } do + %CommandResult{ + continuation: ^continuation, + events: ^events, + gas: ^gas, + logs: ^logs, + meta_data: ^meta_data, + req_key: ^req_key, + result: ^result, + tx_id: ^tx_id + } = CommandResult.new(attrs) + end + + test "new/1 with nil tx_id, logs, continuation, meta_data and events", %{ + attrs: attrs, + gas: gas, + req_key: req_key, + result: result + } do + attrs = %{ + attrs + | tx_id: nil, + logs: nil, + continuation: nil, + meta_data: nil, + events: nil + } + + %CommandResult{ + continuation: nil, + events: nil, + gas: ^gas, + logs: nil, + meta_data: nil, + req_key: ^req_key, + result: ^result, + tx_id: nil + } = CommandResult.new(attrs) + end +end diff --git a/test/chainweb/pact/listen_response_test.exs b/test/chainweb/pact/listen_response_test.exs new file mode 100644 index 0000000..d8ccd95 --- /dev/null +++ b/test/chainweb/pact/listen_response_test.exs @@ -0,0 +1,130 @@ +defmodule Kadena.Chainweb.Pact.ListenResponseTest do + @moduledoc """ + `ListenResponse` struct definition tests. + """ + + use ExUnit.Case + + alias Kadena.Test.Fixtures.Chainweb + + alias Kadena.Chainweb.Pact.ListenResponse + + setup do + continuation = %{ + continuation: %{args: "pact_value", def: "coin"}, + executed: false, + pact_id: "yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4", + step: 1, + step_count: 5, + step_has_rollback: false, + yield: %{ + data: %{ + amount: 0.01, + receiver: "4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc", + receiver_guard: %{ + keys: ["4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc"], + pred: "keys-all" + }, + source_chain: 0 + }, + provenance: %{ + module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", + target_chain_id: "1" + } + } + } + + events = [ + %{ + module: %{name: "coin", namespace: nil}, + module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", + name: "TRANSFER", + params: ["account1", "account2", 5.0e-5] + } + ] + + gas = 5 + logs = "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8" + + meta_data = %{ + block_hash: "kZCKTbL3ubONngiGQsJh4fGtP1xrhAoUvcTsqi3uCGg", + block_height: 2708, + block_time: 1_656_709_048_955_370, + prev_block_hash: "LD_o60RB4xnMgLyzkedNV6v-hbCCnx6WXRQy9WDKTgs", + public_meta: %{ + chain_id: "", + creation_time: 0, + gas_limit: 10, + gas_price: 0, + sender: "", + ttl: 0 + } + } + + req_key = "uolsidh4DWN-D44FoElnosL8e5-cGCGn_0l2Nct5mq8" + result = %{data: 3, status: "success"} + tx_id = 123_456 + + %{ + attrs: Chainweb.fixture("command_result"), + continuation: continuation, + events: events, + gas: gas, + logs: logs, + meta_data: meta_data, + req_key: req_key, + result: result, + tx_id: tx_id + } + end + + test "new/1", %{ + attrs: attrs, + continuation: continuation, + events: events, + gas: gas, + logs: logs, + meta_data: meta_data, + req_key: req_key, + result: result, + tx_id: tx_id + } do + %ListenResponse{ + continuation: ^continuation, + events: ^events, + gas: ^gas, + logs: ^logs, + meta_data: ^meta_data, + req_key: ^req_key, + result: ^result, + tx_id: ^tx_id + } = ListenResponse.new(attrs) + end + + test "new/1 with nil tx_id, logs, continuation, meta_data and events", %{ + attrs: attrs, + gas: gas, + req_key: req_key, + result: result + } do + attrs = %{ + attrs + | tx_id: nil, + logs: nil, + continuation: nil, + meta_data: nil, + events: nil + } + + %ListenResponse{ + continuation: nil, + events: nil, + gas: ^gas, + logs: nil, + meta_data: nil, + req_key: ^req_key, + result: ^result, + tx_id: nil + } = ListenResponse.new(attrs) + end +end diff --git a/test/chainweb/pact/local_response_test.exs b/test/chainweb/pact/local_response_test.exs new file mode 100644 index 0000000..562589e --- /dev/null +++ b/test/chainweb/pact/local_response_test.exs @@ -0,0 +1,130 @@ +defmodule Kadena.Chainweb.Pact.LocalResponseTest do + @moduledoc """ + `LocalResponse` struct definition tests. + """ + + use ExUnit.Case + + alias Kadena.Test.Fixtures.Chainweb + + alias Kadena.Chainweb.Pact.LocalResponse + + setup do + continuation = %{ + continuation: %{args: "pact_value", def: "coin"}, + executed: false, + pact_id: "yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4", + step: 1, + step_count: 5, + step_has_rollback: false, + yield: %{ + data: %{ + amount: 0.01, + receiver: "4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc", + receiver_guard: %{ + keys: ["4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc"], + pred: "keys-all" + }, + source_chain: 0 + }, + provenance: %{ + module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", + target_chain_id: "1" + } + } + } + + events = [ + %{ + module: %{name: "coin", namespace: nil}, + module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", + name: "TRANSFER", + params: ["account1", "account2", 5.0e-5] + } + ] + + gas = 5 + logs = "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8" + + meta_data = %{ + block_hash: "kZCKTbL3ubONngiGQsJh4fGtP1xrhAoUvcTsqi3uCGg", + block_height: 2708, + block_time: 1_656_709_048_955_370, + prev_block_hash: "LD_o60RB4xnMgLyzkedNV6v-hbCCnx6WXRQy9WDKTgs", + public_meta: %{ + chain_id: "", + creation_time: 0, + gas_limit: 10, + gas_price: 0, + sender: "", + ttl: 0 + } + } + + req_key = "uolsidh4DWN-D44FoElnosL8e5-cGCGn_0l2Nct5mq8" + result = %{data: 3, status: "success"} + tx_id = 123_456 + + %{ + attrs: Chainweb.fixture("command_result"), + continuation: continuation, + events: events, + gas: gas, + logs: logs, + meta_data: meta_data, + req_key: req_key, + result: result, + tx_id: tx_id + } + end + + test "new/1", %{ + attrs: attrs, + continuation: continuation, + events: events, + gas: gas, + logs: logs, + meta_data: meta_data, + req_key: req_key, + result: result, + tx_id: tx_id + } do + %LocalResponse{ + continuation: ^continuation, + events: ^events, + gas: ^gas, + logs: ^logs, + meta_data: ^meta_data, + req_key: ^req_key, + result: ^result, + tx_id: ^tx_id + } = LocalResponse.new(attrs) + end + + test "new/1 with nil tx_id, logs, continuation, meta_data and events", %{ + attrs: attrs, + gas: gas, + req_key: req_key, + result: result + } do + attrs = %{ + attrs + | tx_id: nil, + logs: nil, + continuation: nil, + meta_data: nil, + events: nil + } + + %LocalResponse{ + continuation: nil, + events: nil, + gas: ^gas, + logs: nil, + meta_data: nil, + req_key: ^req_key, + result: ^result, + tx_id: nil + } = LocalResponse.new(attrs) + end +end diff --git a/test/chainweb/pact/poll_response_test.exs b/test/chainweb/pact/poll_response_test.exs new file mode 100644 index 0000000..cf8e05c --- /dev/null +++ b/test/chainweb/pact/poll_response_test.exs @@ -0,0 +1,86 @@ +defmodule Kadena.Chainweb.Pact.PollResponseTest do + @moduledoc """ + `PollResponse` struct definition tests. + """ + + use ExUnit.Case + + alias Kadena.Chainweb.Pact.{CommandResult, PollResponse} + + alias Kadena.Test.Fixtures.Chainweb + + setup do + command_result_1 = %CommandResult{ + continuation: nil, + events: [ + %{ + module: %{name: "coin", namespace: nil}, + module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", + name: "TRANSFER", + params: [ + "k:c891d6761ed2c4ccadbe6a1142803fd34fedfe9db110149cd1d8e2a7bc90dc2f", + "6d87fd6e5e47185cb421459d2888bddba7a6c0f2c4ae5246d5f38f993818bb89", + 6.07e-4 + ] + } + ], + gas: 607, + logs: "OQzCLMH0ycZ0HPoN1F-2Rcifc4RuR4RmcO6t2iJI6A8", + meta_data: %{ + block_hash: "eNpIVqyanLWY3sGszNfgYN8YXWXDXfUsWbE_vWcNDlY", + block_height: 3_281_769, + block_time: 1_670_883_254_243_347, + prev_block_hash: "Tw4Z1exNzIinUFe3Y-rrbqp-iMo6NvQJQggMSeVNayw" + }, + req_key: "bKT10kNSeAyE4LgfFInhorKpK_tNLcNjsaWgug4v82s", + result: %{data: "Write succeeded", status: "success"}, + tx_id: 20_160_180 + } + + command_result_2 = %CommandResult{ + continuation: nil, + events: [ + %{ + module: %{name: "coin", namespace: nil}, + module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", + name: "TRANSFER", + params: [ + "k:f99185285730c5414c0a1ec68924598b175827890fad20c18548a9b27d79ce2a", + "6d87fd6e5e47185cb421459d2888bddba7a6c0f2c4ae5246d5f38f993818bb89", + 5.09e-4 + ] + } + ], + gas: 509, + logs: "_sMtjYp5hzhZSUgY72XoamRC0MJRJ_FlZ4IV6FQBK7I", + meta_data: %{ + block_hash: "eNpIVqyanLWY3sGszNfgYN8YXWXDXfUsWbE_vWcNDlY", + block_height: 3_281_769, + block_time: 1_670_883_254_243_347, + prev_block_hash: "Tw4Z1exNzIinUFe3Y-rrbqp-iMo6NvQJQggMSeVNayw" + }, + req_key: "ysx7BoerE0QpflZKkFhSjDZmvMf4xtZ0OxSL1EOckz0", + result: %{data: "Write succeeded", status: "success"}, + tx_id: 20_160_174 + } + + %{ + attrs: Chainweb.fixture("poll"), + command_result_1: command_result_1, + command_result_2: command_result_2 + } + end + + test "new/1", %{ + attrs: attrs, + command_result_1: command_result_1, + command_result_2: command_result_2 + } do + %PollResponse{ + results: [ + ^command_result_1, + ^command_result_2 + ] + } = PollResponse.new(attrs) + end +end diff --git a/test/chainweb/pact/resources/command_result_test.exs b/test/chainweb/pact/resources/command_result_test.exs deleted file mode 100644 index 4b4abca..0000000 --- a/test/chainweb/pact/resources/command_result_test.exs +++ /dev/null @@ -1,157 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.CommandResultTest do - @moduledoc """ - `CommandResult` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Test.Fixtures.Chainweb - - alias Kadena.Types.{Base64Url, ChainID, PactValue, PactValuesList} - - alias Kadena.Chainweb.Pact.Resources.{ - CommandResult, - Continuation, - MetaDataResult, - PactEvent, - PactEventModule, - PactEventsList, - PactExec, - PactResult, - Provenance, - ResponseMetaData, - Yield - } - - setup do - continuation = %PactExec{ - continuation: %Continuation{ - args: %Kadena.Types.PactValue{literal: "pact_value"}, - def: "coin" - }, - executed: false, - pact_id: %Kadena.Types.PactTransactionHash{ - hash: "yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4" - }, - step: %Kadena.Types.Step{number: 1}, - step_count: 5, - step_has_rollback: false, - yield: %Yield{ - data: %{ - "amount" => 0.01, - "receiver" => "4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc", - "receiver_guard" => %{ - "keys" => ["4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc"], - "pred" => "keys-all" - }, - "source_chain" => 0 - }, - provenance: %Provenance{ - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - target_chain_id: %ChainID{id: "1"} - } - } - } - - events = %PactEventsList{ - pact_events: [ - %PactEvent{ - module: %PactEventModule{name: "coin", namespace: nil}, - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - name: "TRANSFER", - params: %PactValuesList{ - pact_values: [ - %PactValue{literal: "account1"}, - %PactValue{literal: "account2"}, - %PactValue{literal: Decimal.new("0.000050")} - ] - } - } - ] - } - - gas = 5 - logs = "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8" - - response_meta_data = %ResponseMetaData{ - block_hash: "kZCKTbL3ubONngiGQsJh4fGtP1xrhAoUvcTsqi3uCGg", - block_height: 2708, - block_time: 1_656_709_048_955_370, - prev_block_hash: "LD_o60RB4xnMgLyzkedNV6v-hbCCnx6WXRQy9WDKTgs", - public_meta: %MetaDataResult{ - chain_id: %ChainID{id: ""}, - creation_time: 0, - gas_limit: 10, - gas_price: 0, - sender: "", - ttl: 0 - } - } - - req_key = %Base64Url{url: "uolsidh4DWN-D44FoElnosL8e5-cGCGn_0l2Nct5mq8"} - result = %PactResult{data: %PactValue{literal: 3}, status: :success} - tx_id = 123_456 - - %{ - attrs: Chainweb.fixture("command_result", to_snake: true), - continuation: continuation, - events: events, - gas: gas, - logs: logs, - response_meta_data: response_meta_data, - req_key: req_key, - result: result, - tx_id: tx_id - } - end - - test "new/1", %{ - attrs: attrs, - continuation: continuation, - events: events, - gas: gas, - logs: logs, - response_meta_data: response_meta_data, - req_key: req_key, - result: result, - tx_id: tx_id - } do - %CommandResult{ - continuation: ^continuation, - events: ^events, - gas: ^gas, - logs: ^logs, - meta_data: ^response_meta_data, - req_key: ^req_key, - result: ^result, - tx_id: ^tx_id - } = CommandResult.new(attrs) - end - - test "new/1 with nil tx_id, logs, continuation, meta_data and events", %{ - attrs: attrs, - gas: gas, - req_key: req_key, - result: result - } do - attrs = %{ - attrs - | "tx_id" => nil, - "logs" => nil, - "continuation" => nil, - "meta_data" => nil, - "events" => nil - } - - %CommandResult{ - continuation: nil, - events: nil, - gas: ^gas, - logs: nil, - meta_data: nil, - req_key: ^req_key, - result: ^result, - tx_id: nil - } = CommandResult.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/continuation_test.exs b/test/chainweb/pact/resources/continuation_test.exs deleted file mode 100644 index dd135de..0000000 --- a/test/chainweb/pact/resources/continuation_test.exs +++ /dev/null @@ -1,106 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.ContinuationTest do - @moduledoc """ - `Continuation` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Chainweb.Pact.Resources.Continuation - - alias Kadena.Types.{ - PactDecimal, - PactInt, - PactValue, - PactValuesList - } - - setup do - %{ - attrs: %{ - "def" => "coin", - "args" => "pact_value" - } - } - end - - test "new/1 with args as string", %{attrs: attrs} do - %Continuation{ - args: %PactValue{literal: "pact_value"}, - def: "coin" - } = Continuation.new(attrs) - end - - test "new/1 with args as integer", %{attrs: attrs} do - attrs = Map.put(attrs, "args", 1) - - %Continuation{ - args: %PactValue{literal: 1}, - def: "coin" - } = Continuation.new(attrs) - end - - test "new/1 with args as integer not in range", %{attrs: attrs} do - attrs = Map.put(attrs, "args", 9_007_199_254_740_992) - - %Continuation{ - args: %PactValue{ - literal: %PactInt{ - raw_value: 9_007_199_254_740_992, - value: "9007199254740992" - } - }, - def: "coin" - } = Continuation.new(attrs) - end - - test "new/1 with args as float", %{attrs: attrs} do - attrs = Map.put(attrs, "args", 0.01) - decimal = Decimal.new("0.01") - - %Continuation{ - args: %PactValue{literal: ^decimal}, - def: "coin" - } = Continuation.new(attrs) - end - - test "new/1 with args as string decimal", %{attrs: attrs} do - attrs = Map.put(attrs, "args", "9007199254740992.553") - decimal = Decimal.new("9007199254740992.553") - - %Continuation{ - args: %PactValue{ - literal: %PactDecimal{ - raw_value: ^decimal, - value: "9007199254740992.553" - } - }, - def: "coin" - } = Continuation.new(attrs) - end - - test "new/1 with args as boolean", %{attrs: attrs} do - attrs = Map.put(attrs, "args", true) - - %Continuation{ - args: %PactValue{literal: true}, - def: "coin" - } = Continuation.new(attrs) - end - - test "new/1 with args as list", %{attrs: attrs} do - attrs = Map.put(attrs, "args", ["COIN.gas", 0.01]) - decimal = Decimal.new("0.01") - - %Continuation{ - args: %PactValue{ - literal: %PactValuesList{ - pact_values: [ - %PactValue{literal: "COIN.gas"}, - %PactValue{literal: ^decimal} - ] - } - }, - def: "coin" - } = Continuation.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/listen_response_test.exs b/test/chainweb/pact/resources/listen_response_test.exs deleted file mode 100644 index 00466e0..0000000 --- a/test/chainweb/pact/resources/listen_response_test.exs +++ /dev/null @@ -1,164 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.ListenResponseTest do - @moduledoc """ - `ListenResponse` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Test.Fixtures.Chainweb - - alias Kadena.Types.{ - Base64Url, - ChainID, - PactTransactionHash, - PactValue, - PactValuesList, - Step - } - - alias Kadena.Chainweb.Pact.Resources.{ - Continuation, - ListenResponse, - MetaDataResult, - PactEvent, - PactEventModule, - PactEventsList, - PactExec, - PactResult, - Provenance, - ResponseMetaData, - Yield - } - - setup do - continuation = %PactExec{ - continuation: %Continuation{ - args: %PactValue{literal: "pact_value"}, - def: "coin" - }, - executed: false, - pact_id: %PactTransactionHash{ - hash: "yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4" - }, - step: %Step{number: 1}, - step_count: 5, - step_has_rollback: false, - yield: %Yield{ - data: %{ - "amount" => 0.01, - "receiver" => "4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc", - "receiver_guard" => %{ - "keys" => ["4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc"], - "pred" => "keys-all" - }, - "source_chain" => 0 - }, - provenance: %Provenance{ - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - target_chain_id: %ChainID{id: "1"} - } - } - } - - events = %PactEventsList{ - pact_events: [ - %PactEvent{ - module: %PactEventModule{name: "coin", namespace: nil}, - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - name: "TRANSFER", - params: %PactValuesList{ - pact_values: [ - %PactValue{literal: "account1"}, - %PactValue{literal: "account2"}, - %PactValue{literal: Decimal.new("0.000050")} - ] - } - } - ] - } - - gas = 5 - logs = "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8" - - response_meta_data = %ResponseMetaData{ - block_hash: "kZCKTbL3ubONngiGQsJh4fGtP1xrhAoUvcTsqi3uCGg", - block_height: 2708, - block_time: 1_656_709_048_955_370, - prev_block_hash: "LD_o60RB4xnMgLyzkedNV6v-hbCCnx6WXRQy9WDKTgs", - public_meta: %MetaDataResult{ - chain_id: %ChainID{id: ""}, - creation_time: 0, - gas_limit: 10, - gas_price: 0, - sender: "", - ttl: 0 - } - } - - req_key = %Base64Url{url: "uolsidh4DWN-D44FoElnosL8e5-cGCGn_0l2Nct5mq8"} - result = %PactResult{data: %PactValue{literal: 3}, status: :success} - tx_id = 123_456 - - %{ - attrs: Chainweb.fixture("command_result", to_snake: true), - continuation: continuation, - events: events, - gas: gas, - logs: logs, - response_meta_data: response_meta_data, - req_key: req_key, - result: result, - tx_id: tx_id - } - end - - test "new/1", %{ - attrs: attrs, - continuation: continuation, - events: events, - gas: gas, - logs: logs, - response_meta_data: response_meta_data, - req_key: req_key, - result: result, - tx_id: tx_id - } do - %ListenResponse{ - continuation: ^continuation, - events: ^events, - gas: ^gas, - logs: ^logs, - meta_data: ^response_meta_data, - req_key: ^req_key, - result: ^result, - tx_id: ^tx_id - } = ListenResponse.new(attrs) - end - - test "new/1 with nil tx_id, logs, continuation, meta_data and events", %{ - attrs: attrs, - gas: gas, - req_key: req_key, - result: result - } do - attrs = %{ - attrs - | "tx_id" => nil, - "logs" => nil, - "continuation" => nil, - "meta_data" => nil, - "events" => nil - } - - %ListenResponse{ - continuation: nil, - events: nil, - gas: ^gas, - logs: nil, - meta_data: nil, - req_key: ^req_key, - result: ^result, - tx_id: nil - } = ListenResponse.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/local_response_test.exs b/test/chainweb/pact/resources/local_response_test.exs deleted file mode 100644 index 94cd113..0000000 --- a/test/chainweb/pact/resources/local_response_test.exs +++ /dev/null @@ -1,164 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.LocalResponseTest do - @moduledoc """ - `LocalResponse` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Chainweb.Pact.Resources.{ - Continuation, - LocalResponse, - MetaDataResult, - PactEvent, - PactEventModule, - PactEventsList, - PactExec, - PactResult, - Provenance, - ResponseMetaData, - Yield - } - - alias Kadena.Test.Fixtures.Chainweb - - alias Kadena.Types.{ - Base64Url, - ChainID, - PactTransactionHash, - PactValue, - PactValuesList, - Step - } - - setup do - continuation = %PactExec{ - continuation: %Continuation{ - args: %PactValue{literal: "pact_value"}, - def: "coin" - }, - executed: false, - pact_id: %PactTransactionHash{ - hash: "yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4" - }, - step: %Step{number: 1}, - step_count: 5, - step_has_rollback: false, - yield: %Yield{ - data: %{ - "amount" => 0.01, - "receiver" => "4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc", - "receiver_guard" => %{ - "keys" => ["4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc"], - "pred" => "keys-all" - }, - "source_chain" => 0 - }, - provenance: %Provenance{ - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - target_chain_id: %ChainID{id: "1"} - } - } - } - - events = %PactEventsList{ - pact_events: [ - %PactEvent{ - module: %PactEventModule{name: "coin", namespace: nil}, - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - name: "TRANSFER", - params: %PactValuesList{ - pact_values: [ - %PactValue{literal: "account1"}, - %PactValue{literal: "account2"}, - %PactValue{literal: Decimal.new("0.000050")} - ] - } - } - ] - } - - gas = 5 - logs = "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8" - - response_meta_data = %ResponseMetaData{ - block_hash: "kZCKTbL3ubONngiGQsJh4fGtP1xrhAoUvcTsqi3uCGg", - block_height: 2708, - block_time: 1_656_709_048_955_370, - prev_block_hash: "LD_o60RB4xnMgLyzkedNV6v-hbCCnx6WXRQy9WDKTgs", - public_meta: %MetaDataResult{ - chain_id: %ChainID{id: ""}, - creation_time: 0, - gas_limit: 10, - gas_price: 0, - sender: "", - ttl: 0 - } - } - - req_key = %Base64Url{url: "uolsidh4DWN-D44FoElnosL8e5-cGCGn_0l2Nct5mq8"} - result = %PactResult{data: %PactValue{literal: 3}, status: :success} - tx_id = 123_456 - - %{ - attrs: Chainweb.fixture("command_result", to_snake: true), - continuation: continuation, - events: events, - gas: gas, - logs: logs, - response_meta_data: response_meta_data, - req_key: req_key, - result: result, - tx_id: tx_id - } - end - - test "new/1", %{ - attrs: attrs, - continuation: continuation, - events: events, - gas: gas, - logs: logs, - response_meta_data: response_meta_data, - req_key: req_key, - result: result, - tx_id: tx_id - } do - %LocalResponse{ - continuation: ^continuation, - events: ^events, - gas: ^gas, - logs: ^logs, - meta_data: ^response_meta_data, - req_key: ^req_key, - result: ^result, - tx_id: ^tx_id - } = LocalResponse.new(attrs) - end - - test "new/1 with nil tx_id, logs, continuation, meta_data and events", %{ - attrs: attrs, - gas: gas, - req_key: req_key, - result: result - } do - attrs = %{ - attrs - | "tx_id" => nil, - "logs" => nil, - "continuation" => nil, - "meta_data" => nil, - "events" => nil - } - - %LocalResponse{ - continuation: nil, - events: nil, - gas: ^gas, - logs: nil, - meta_data: nil, - req_key: ^req_key, - result: ^result, - tx_id: nil - } = LocalResponse.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/meta_data_result_test.exs b/test/chainweb/pact/resources/meta_data_result_test.exs deleted file mode 100644 index 55a4e53..0000000 --- a/test/chainweb/pact/resources/meta_data_result_test.exs +++ /dev/null @@ -1,34 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.MetaDataResultTest do - @moduledoc """ - `MetaDataResultTest` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Chainweb.Pact.Resources.MetaDataResult - alias Kadena.Types.ChainID - - setup do - %{ - attrs: %{ - "chain_id" => "0", - "creation_time" => 0, - "gas_limit" => 10, - "gas_price" => 0, - "sender" => "", - "ttl" => 0 - } - } - end - - test "new/1", %{attrs: attrs} do - %MetaDataResult{ - chain_id: %ChainID{id: "0"}, - creation_time: 0, - gas_limit: 10, - gas_price: 0, - sender: "", - ttl: 0 - } = MetaDataResult.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/pact_event_module_test.exs b/test/chainweb/pact/resources/pact_event_module_test.exs deleted file mode 100644 index 6c92881..0000000 --- a/test/chainweb/pact/resources/pact_event_module_test.exs +++ /dev/null @@ -1,28 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactEventModuleTest do - @moduledoc """ - `PactEventModule` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Chainweb.Pact.Resources.PactEventModule - - setup do - %{ - attrs: %{ - "name" => "coin", - "namespace" => "free" - } - } - end - - test "new/1", %{attrs: attrs} do - %PactEventModule{name: "coin", namespace: "free"} = PactEventModule.new(attrs) - end - - test "new/1 with nil namespace", %{attrs: attrs} do - attrs = Map.put(attrs, "namespace", nil) - - %PactEventModule{name: "coin", namespace: nil} = PactEventModule.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/pact_event_test.exs b/test/chainweb/pact/resources/pact_event_test.exs deleted file mode 100644 index 30aec85..0000000 --- a/test/chainweb/pact/resources/pact_event_test.exs +++ /dev/null @@ -1,45 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactEventTest do - @moduledoc """ - `PactEvent` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Types.{PactValue, PactValuesList} - alias Kadena.Chainweb.Pact.Resources.{PactEvent, PactEventModule} - - setup do - %{ - attrs: %{ - "module" => %{ - "name" => "coin", - "namespace" => nil - }, - "module_hash" => "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - "name" => "TRANSFER", - "params" => [ - "account1", - "account2", - 0.00005 - ] - } - } - end - - test "new/1", %{attrs: attrs} do - decimal = Decimal.new("0.000050") - - %PactEvent{ - module: %PactEventModule{name: "coin", namespace: nil}, - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - name: "TRANSFER", - params: %PactValuesList{ - pact_values: [ - %PactValue{literal: "account1"}, - %PactValue{literal: "account2"}, - %PactValue{literal: ^decimal} - ] - } - } = PactEvent.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/pact_events_list_test.exs b/test/chainweb/pact/resources/pact_events_list_test.exs deleted file mode 100644 index fc61165..0000000 --- a/test/chainweb/pact/resources/pact_events_list_test.exs +++ /dev/null @@ -1,55 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactEventsListTest do - @moduledoc """ - `PactEventsList` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Chainweb.Pact.Resources.{PactEvent, PactEventsList} - - setup do - pact_event_1_attrs = %{ - "module" => %{ - "name" => "coin", - "namespace" => nil - }, - "module_hash" => "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - "name" => "TRANSFER", - "params" => [ - "account1", - "account2", - 0.00005 - ] - } - - pact_event_2_attrs = %{ - "module" => %{ - "name" => "coin", - "namespace" => nil - }, - "module_hash" => "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP5", - "name" => "TRANSFER", - "params" => [ - "account3", - "account4", - 0.00005 - ] - } - - %{ - pact_events: [pact_event_1_attrs, pact_event_2_attrs], - pact_event_1: PactEvent.new(pact_event_1_attrs), - pact_event_2: PactEvent.new(pact_event_2_attrs) - } - end - - test "new/1", %{ - pact_events: pact_events, - pact_event_1: pact_event_1, - pact_event_2: pact_event_2 - } do - %PactEventsList{ - pact_events: [^pact_event_1, ^pact_event_2] - } = PactEventsList.new(pact_events) - end -end diff --git a/test/chainweb/pact/resources/pact_exec_test.exs b/test/chainweb/pact/resources/pact_exec_test.exs deleted file mode 100644 index 0e8ce0b..0000000 --- a/test/chainweb/pact/resources/pact_exec_test.exs +++ /dev/null @@ -1,116 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactExecTest do - @moduledoc """ - `PactExec` struct definition tests. - """ - use ExUnit.Case - - alias Kadena.Types.{ChainID, PactTransactionHash, PactValue, Step} - alias Kadena.Chainweb.Pact.Resources.{Continuation, PactExec, Provenance, Yield} - - setup do - attrs = %{ - "continuation" => %{"args" => "pact_value", "def" => "coin"}, - "executed" => false, - "pact_id" => "yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4", - "step" => 1, - "step_count" => 5, - "step_has_rollback" => false, - "yield" => %{ - "data" => %{ - "amount" => 0.01, - "receiver" => "4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc", - "receiver_guard" => %{ - "keys" => ["4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc"], - "pred" => "keys-all" - }, - "source_chain" => 0 - }, - "provenance" => %{ - "module_hash" => "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - "target_chain_id" => "1" - } - } - } - - continuation = %Continuation{ - args: %PactValue{literal: "pact_value"}, - def: "coin" - } - - executed = false - pact_id = %PactTransactionHash{hash: "yxM0umrtdcvSUZDc_GSjwadH6ELYFCjOqI59Jzqapi4"} - step = %Step{number: 1} - step_count = 5 - step_has_rollback = false - - yield = %Yield{ - data: %{ - "amount" => 0.01, - "receiver" => "4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc", - "receiver_guard" => %{ - "keys" => ["4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc"], - "pred" => "keys-all" - }, - "source_chain" => 0 - }, - provenance: %Provenance{ - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - target_chain_id: %ChainID{id: "1"} - } - } - - %{ - attrs: attrs, - continuation: continuation, - executed: executed, - pact_id: pact_id, - step: step, - step_count: step_count, - step_has_rollback: step_has_rollback, - yield: yield - } - end - - test "new/1", %{ - attrs: attrs, - continuation: continuation, - executed: executed, - pact_id: pact_id, - step: step, - step_count: step_count, - step_has_rollback: step_has_rollback, - yield: yield - } do - %PactExec{ - continuation: ^continuation, - executed: ^executed, - pact_id: ^pact_id, - step: ^step, - step_count: ^step_count, - step_has_rollback: ^step_has_rollback, - yield: ^yield - } = PactExec.new(attrs) - end - - test "new/1 with nil executed and yield", %{ - attrs: attrs, - continuation: continuation, - pact_id: pact_id, - step: step, - step_count: step_count, - step_has_rollback: step_has_rollback - } do - attrs = Map.put(attrs, "executed", nil) - attrs = Map.put(attrs, "yield", nil) - - %PactExec{ - continuation: ^continuation, - executed: nil, - pact_id: ^pact_id, - step: ^step, - step_count: ^step_count, - step_has_rollback: ^step_has_rollback, - yield: nil - } = PactExec.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/pact_result_test.exs b/test/chainweb/pact/resources/pact_result_test.exs deleted file mode 100644 index dd7d44a..0000000 --- a/test/chainweb/pact/resources/pact_result_test.exs +++ /dev/null @@ -1,22 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PactResultTest do - @moduledoc """ - `PactResult` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Chainweb.Pact.Resources.PactResult - alias Kadena.Types.PactValue - - describe "new/1" do - test "with a valid success status" do - %PactResult{status: :success, data: %PactValue{literal: 3}} = - PactResult.new(%{"status" => "success", "data" => 3}) - end - - test "with a valid failure status" do - %PactResult{status: :failure, data: %{}} = - PactResult.new(%{"status" => "failure", "data" => %{}}) - end - end -end diff --git a/test/chainweb/pact/resources/poll_response_test.exs b/test/chainweb/pact/resources/poll_response_test.exs deleted file mode 100644 index e93d798..0000000 --- a/test/chainweb/pact/resources/poll_response_test.exs +++ /dev/null @@ -1,134 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.PollResponseTest do - @moduledoc """ - `PollResponse` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Chainweb.Pact.Resources.{ - CommandResult, - PactEvent, - PactEventModule, - PactEventsList, - PactResult, - PollResponse, - ResponseMetaData - } - - alias Kadena.Test.Fixtures.Chainweb - - alias Kadena.Types.{ - Base64Url, - PactValue, - PactValuesList - } - - setup do - command_result_1 = %CommandResult{ - continuation: nil, - events: %PactEventsList{ - pact_events: [ - %PactEvent{ - module: %PactEventModule{ - name: "coin", - namespace: nil - }, - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - name: "TRANSFER", - params: %PactValuesList{ - pact_values: [ - %PactValue{ - literal: "k:c891d6761ed2c4ccadbe6a1142803fd34fedfe9db110149cd1d8e2a7bc90dc2f" - }, - %PactValue{ - literal: "6d87fd6e5e47185cb421459d2888bddba7a6c0f2c4ae5246d5f38f993818bb89" - }, - %PactValue{literal: Decimal.new("0.000607")} - ] - } - } - ] - }, - gas: 607, - logs: "OQzCLMH0ycZ0HPoN1F-2Rcifc4RuR4RmcO6t2iJI6A8", - meta_data: %ResponseMetaData{ - block_hash: "eNpIVqyanLWY3sGszNfgYN8YXWXDXfUsWbE_vWcNDlY", - block_height: 3_281_769, - block_time: 1_670_883_254_243_347, - prev_block_hash: "Tw4Z1exNzIinUFe3Y-rrbqp-iMo6NvQJQggMSeVNayw", - public_meta: nil - }, - req_key: %Base64Url{ - url: "bKT10kNSeAyE4LgfFInhorKpK_tNLcNjsaWgug4v82s" - }, - result: %PactResult{ - data: %PactValue{literal: "Write succeeded"}, - status: :success - }, - tx_id: 20_160_180 - } - - command_result_2 = %CommandResult{ - continuation: nil, - events: %PactEventsList{ - pact_events: [ - %PactEvent{ - module: %PactEventModule{ - name: "coin", - namespace: nil - }, - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - name: "TRANSFER", - params: %PactValuesList{ - pact_values: [ - %PactValue{ - literal: "k:f99185285730c5414c0a1ec68924598b175827890fad20c18548a9b27d79ce2a" - }, - %PactValue{ - literal: "6d87fd6e5e47185cb421459d2888bddba7a6c0f2c4ae5246d5f38f993818bb89" - }, - %PactValue{literal: Decimal.new("0.000509")} - ] - } - } - ] - }, - gas: 509, - logs: "_sMtjYp5hzhZSUgY72XoamRC0MJRJ_FlZ4IV6FQBK7I", - meta_data: %ResponseMetaData{ - block_hash: "eNpIVqyanLWY3sGszNfgYN8YXWXDXfUsWbE_vWcNDlY", - block_height: 3_281_769, - block_time: 1_670_883_254_243_347, - prev_block_hash: "Tw4Z1exNzIinUFe3Y-rrbqp-iMo6NvQJQggMSeVNayw", - public_meta: nil - }, - req_key: %Base64Url{ - url: "ysx7BoerE0QpflZKkFhSjDZmvMf4xtZ0OxSL1EOckz0" - }, - result: %PactResult{ - data: %PactValue{literal: "Write succeeded"}, - status: :success - }, - tx_id: 20_160_174 - } - - %{ - attrs: Chainweb.fixture("poll", to_snake: true), - command_result_1: command_result_1, - command_result_2: command_result_2 - } - end - - test "new/1", %{ - attrs: attrs, - command_result_1: command_result_1, - command_result_2: command_result_2 - } do - %PollResponse{ - results: [ - ^command_result_1, - ^command_result_2 - ] - } = PollResponse.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/provenance_test.exs b/test/chainweb/pact/resources/provenance_test.exs deleted file mode 100644 index bdefee1..0000000 --- a/test/chainweb/pact/resources/provenance_test.exs +++ /dev/null @@ -1,26 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.ProvenanceTest do - @moduledoc """ - `Provenance` struct definition tests. - """ - - alias Kadena.Chainweb.Pact.Resources.Provenance - alias Kadena.Types.ChainID - - use ExUnit.Case - - setup do - %{ - attrs: %{ - "module_hash" => "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - "target_chain_id" => "1" - } - } - end - - test "new/1", %{attrs: attrs} do - %Provenance{ - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - target_chain_id: %ChainID{id: "1"} - } = Provenance.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/response_meta_data_test.exs b/test/chainweb/pact/resources/response_meta_data_test.exs deleted file mode 100644 index cada0b6..0000000 --- a/test/chainweb/pact/resources/response_meta_data_test.exs +++ /dev/null @@ -1,58 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.ResponseMetaDataTest do - @moduledoc """ - `ChainwebResponseMetaData` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Chainweb.Pact.Resources.{MetaDataResult, ResponseMetaData} - alias Kadena.Types.ChainID - - setup do - %{ - attrs: %{ - "block_hash" => "kZCKTbL3ubONngiGQsJh4fGtP1xrhAoUvcTsqi3uCGg", - "block_height" => 2708, - "block_time" => 1_656_709_048_955_370, - "prev_block_hash" => "LD_o60RB4xnMgLyzkedNV6v-hbCCnx6WXRQy9WDKTgs", - "public_meta" => %{ - "chain_id" => "0", - "creation_time" => 0, - "gas_limit" => 10, - "gas_price" => 0, - "sender" => "", - "ttl" => 0 - } - } - } - end - - test "new/1", %{attrs: attrs} do - %ResponseMetaData{ - block_hash: "kZCKTbL3ubONngiGQsJh4fGtP1xrhAoUvcTsqi3uCGg", - block_height: 2708, - block_time: 1_656_709_048_955_370, - prev_block_hash: "LD_o60RB4xnMgLyzkedNV6v-hbCCnx6WXRQy9WDKTgs", - public_meta: %MetaDataResult{ - chain_id: %ChainID{id: "0"}, - creation_time: 0, - gas_limit: 10, - gas_price: 0, - sender: "", - ttl: 0 - } - } = ResponseMetaData.new(attrs) - end - - test "new/1 with nil public_meta", %{attrs: attrs} do - attrs = Map.put(attrs, "public_meta", nil) - - %ResponseMetaData{ - block_hash: "kZCKTbL3ubONngiGQsJh4fGtP1xrhAoUvcTsqi3uCGg", - block_height: 2708, - block_time: 1_656_709_048_955_370, - prev_block_hash: "LD_o60RB4xnMgLyzkedNV6v-hbCCnx6WXRQy9WDKTgs", - public_meta: nil - } = ResponseMetaData.new(attrs) - end -end diff --git a/test/chainweb/pact/resources/send_response_test.exs b/test/chainweb/pact/resources/send_response_test.exs deleted file mode 100644 index ad145c5..0000000 --- a/test/chainweb/pact/resources/send_response_test.exs +++ /dev/null @@ -1,45 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.SendResponseTest do - @moduledoc """ - `SendResponse` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Chainweb.Pact.Resources.SendResponse - alias Kadena.Types.{Base64Url, Base64UrlsList} - - setup do - %{ - attrs: %{ - "request_keys" => [ - "ATGCYPMNzdGcFh9Iik73KfMkgURIxaF91Ze4sHFsH8Q", - "JHgnKe5Wd4hNIb7a6bIhm4ifxsYFzVGtAMyi_TEO-oM" - ] - } - } - end - - test "new/1", %{attrs: attrs} do - %SendResponse{ - request_keys: %Base64UrlsList{ - urls: [ - %Base64Url{ - url: "ATGCYPMNzdGcFh9Iik73KfMkgURIxaF91Ze4sHFsH8Q" - }, - %Base64Url{ - url: "JHgnKe5Wd4hNIb7a6bIhm4ifxsYFzVGtAMyi_TEO-oM" - } - ] - } - } = SendResponse.new(attrs) - end - - test "new/1 invalid_request_keys", %{attrs: attrs} do - attrs = Map.put(attrs, "request_keys", "invalid_request_keys") - %SendResponse{request_keys: {:error, [urls: :not_a_list]}} = SendResponse.new(attrs) - end - - test "new/1 empty_attrs" do - %SendResponse{request_keys: %Base64UrlsList{urls: []}} = SendResponse.new(%{}) - end -end diff --git a/test/chainweb/pact/resources/yield_test.exs b/test/chainweb/pact/resources/yield_test.exs deleted file mode 100644 index 6e87916..0000000 --- a/test/chainweb/pact/resources/yield_test.exs +++ /dev/null @@ -1,51 +0,0 @@ -defmodule Kadena.Chainweb.Pact.Resources.YieldTest do - @moduledoc """ - `Yield` struct definition tests. - """ - - alias Kadena.Chainweb.Pact.Resources.{Provenance, Yield} - alias Kadena.Types.ChainID - - use ExUnit.Case - - setup do - data = %{ - "amount" => 0.01, - "receiver" => "4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc", - "receiver_guard" => %{ - "keys" => ["4f9c46df2fe874d7c1b60f68f8440a444dd716e6b2efba8ee141afdd58c993dc"], - "pred" => "keys-all" - }, - "source_chain" => 0 - } - - provenance = %Provenance{ - module_hash: "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - target_chain_id: %ChainID{id: "1"} - } - - attrs = %{ - "data" => data, - "provenance" => %{ - "module_hash" => "rE7DU8jlQL9x_MPYuniZJf5ICBTAEHAIFQCB4blofP4", - "target_chain_id" => "1" - } - } - - %{ - attrs: attrs, - data: data, - provenance: provenance - } - end - - test "new/1", %{attrs: attrs, data: data, provenance: provenance} do - %Yield{data: ^data, provenance: ^provenance} = Yield.new(attrs) - end - - test "new/1 with nil provenance", %{attrs: attrs, data: data} do - attrs = Map.put(attrs, "provenance", nil) - - %Yield{data: ^data, provenance: nil} = Yield.new(attrs) - end -end diff --git a/test/chainweb/pact/send_response_test.exs b/test/chainweb/pact/send_response_test.exs new file mode 100644 index 0000000..db3e85c --- /dev/null +++ b/test/chainweb/pact/send_response_test.exs @@ -0,0 +1,29 @@ +defmodule Kadena.Chainweb.Pact.SendResponseTest do + @moduledoc """ + `SendResponse` struct definition tests. + """ + + use ExUnit.Case + + alias Kadena.Chainweb.Pact.SendResponse + alias Kadena.Test.Fixtures.Chainweb + + setup do + %{ + attrs: Chainweb.fixture("send") + } + end + + test "new/1", %{attrs: attrs} do + %SendResponse{ + request_keys: [ + "ATGCYPMNzdGcFh9Iik73KfMkgURIxaF91Ze4sHFsH8Q", + "JHgnKe5Wd4hNIb7a6bIhm4ifxsYFzVGtAMyi_TEO-oM" + ] + } = SendResponse.new(attrs) + end + + test "new/1 empty_attrs" do + %SendResponse{request_keys: []} = SendResponse.new(%{}) + end +end diff --git a/test/chainweb/pact/resources/spv_response_test.exs b/test/chainweb/pact/spv_response_test.exs similarity index 97% rename from test/chainweb/pact/resources/spv_response_test.exs rename to test/chainweb/pact/spv_response_test.exs index 9dcab30..3fac5ea 100644 --- a/test/chainweb/pact/resources/spv_response_test.exs +++ b/test/chainweb/pact/spv_response_test.exs @@ -1,11 +1,11 @@ -defmodule Kadena.Chainweb.Pact.Resources.SPVResponseTest do +defmodule Kadena.Chainweb.Pact.SPVResponseTest do @moduledoc """ `SPVResponse` struct definition tests. """ use ExUnit.Case - alias Kadena.Chainweb.Pact.Resources.SPVResponse + alias Kadena.Chainweb.Pact.SPVResponse test "new/1 with string param" do spv_response = @@ -15,6 +15,8 @@ defmodule Kadena.Chainweb.Pact.Resources.SPVResponseTest do end test "new/1 with non-string param" do - %SPVResponse{response: nil} = SPVResponse.new(1) + assert_raise FunctionClauseError, fn -> + SPVResponse.new(1) + end end end diff --git a/test/chainweb/request_test.exs b/test/chainweb/request_test.exs new file mode 100644 index 0000000..5624b13 --- /dev/null +++ b/test/chainweb/request_test.exs @@ -0,0 +1,168 @@ +defmodule Kadena.Chainweb.Client.CannedRequestImpl do + @moduledoc false + + @behaviour Kadena.Chainweb.Client.Spec + + @network_url_pact_testnet04_chain0 "https://api.testnet.chainweb.com/chainweb/0.0/testnet04/chain/0/pact/api/v1" + + @impl true + def request( + _method, + @network_url_pact_testnet04_chain0 <> "/local", + _body, + _headers, + _opts + ) do + send(self(), {:chainweb_requested, 200}) + {:ok, 200, [], nil} + end +end + +defmodule Kadena.Chainweb.RequestTest do + use ExUnit.Case + + alias Kadena.Chainweb.Client.CannedRequestImpl + alias Kadena.Chainweb.{Error, Request} + alias Kadena.Chainweb.Pact.LocalResponse + + alias Kadena.Test.Fixtures.Chainweb + + setup do + Application.put_env(:kadena, :http_client_impl, CannedRequestImpl) + + on_exit(fn -> + Application.delete_env(:kadena, :http_client_impl) + end) + + endpoint = "local" + network_id = :testnet04 + chain_id = "0" + + body = + "{\"cmd\":\"{\\\"meta\\\":{\\\"chainId\\\":\\\"0\\\",\\\"creationTime\\\":1667249173,\\\"gasLimit\\\":1000,\\\"gasPrice\\\":1.0e-6,\\\"sender\\\":\\\"k:554754f48b16df24b552f6832dda090642ed9658559fef9f3ee1bb4637ea7c94\\\",\\\"ttl\\\":28800},\\\"networkId\\\":\\\"testnet04\\\",\\\"nonce\\\":\\\"2023-06-13 17:45:18.211131 UTC\\\",\\\"payload\\\":{\\\"exec\\\":{\\\"code\\\":\\\"(+ 5 6)\\\",\\\"data\\\":{}}},\\\"signers\\\":[{\\\"addr\\\":\\\"85bef77ea3570387cac57da34938f246c7460dc533a67823f065823e327b2afd\\\",\\\"clist\\\":[{\\\"args\\\":[\\\"85bef77ea3570387cac57da34938f246c7460dc533a67823f065823e327b2afd\\\"],\\\"name\\\":\\\"coin.GAS\\\"}],\\\"pubKey\\\":\\\"85bef77ea3570387cac57da34938f246c7460dc533a67823f065823e327b2afd\\\",\\\"scheme\\\":\\\"ED25519\\\"}]}\",\"hash\":\"-1npoTU2Mi71pKE_oteJiJuHuXTXxoObJm8zzVRK2pk\",\"sigs\":[{\"sig\":\"8b234b83570359e52188cceb301036a2a7b255171e856fd550cac687a946f18fbfc0e769fd8393dda44d6d04c31b531eaf35efb3b78b5e40fd857a743133030d\"}]}" + + headers = [{"Content-Type", "application/json"}] + query = [query_param1: "value1", query_param2: "value2"] + + %{ + endpoint: endpoint, + network_id: network_id, + chain_id: chain_id, + body: body, + headers: headers, + query: query + } + end + + test "new/1", %{endpoint: endpoint, network_id: network_id, chain_id: chain_id} do + %Request{ + method: :post, + endpoint: ^endpoint, + network_id: ^network_id, + chain_id: ^chain_id, + body: nil, + headers: [], + query: [] + } = Request.new(:post, pact: [endpoint: endpoint, network_id: network_id, chain_id: chain_id]) + end + + test "set_network/2", %{endpoint: endpoint, network_id: network_id} do + %Request{network_id: ^network_id} = + :post + |> Request.new(pact: [endpoint: endpoint]) + |> Request.set_network(network_id) + end + + test "set_chain_id/2", %{endpoint: endpoint, chain_id: chain_id} do + %Request{chain_id: ^chain_id} = + :post + |> Request.new(pact: [endpoint: endpoint]) + |> Request.set_chain_id(chain_id) + end + + test "add_body/2", %{endpoint: endpoint, body: body} do + %Request{method: :post, endpoint: ^endpoint, body: ^body} = + :post + |> Request.new(pact: [endpoint: endpoint]) + |> Request.add_body(body) + end + + test "add_headers/2", %{endpoint: endpoint, headers: headers} do + %Request{method: :post, endpoint: ^endpoint, headers: ^headers} = + :post + |> Request.new(pact: [endpoint: endpoint]) + |> Request.add_headers(headers) + end + + test "add_query/3", %{endpoint: endpoint, query: query} do + %Request{ + method: :post, + endpoint: ^endpoint, + query: ^query, + encoded_query: "query_param1=value1&query_param2=value2" + } = + :post + |> Request.new(pact: [endpoint: endpoint]) + |> Request.add_query(query) + end + + test "add_query/3 with_empty_params", %{endpoint: endpoint} do + query = [query_param1: "", query_param2: ""] + + %Request{ + method: :post, + endpoint: ^endpoint, + query: ^query, + encoded_query: nil + } = + :post + |> Request.new(pact: [endpoint: endpoint]) + |> Request.add_query(query) + end + + test "add_query/3 with_nil_params", %{endpoint: endpoint} do + query = [query_param1: nil, query_param2: nil] + + %Request{ + method: :post, + endpoint: ^endpoint, + query: ^query, + encoded_query: nil + } = + :post + |> Request.new(pact: [endpoint: endpoint]) + |> Request.add_query(query) + end + + test "perform/2", %{ + endpoint: endpoint, + network_id: network_id, + chain_id: chain_id, + body: body, + headers: headers + } do + :post + |> Request.new(pact: [endpoint: endpoint]) + |> Request.set_chain_id(chain_id) + |> Request.set_network(network_id) + |> Request.add_body(body) + |> Request.add_headers(headers) + |> Request.perform() + + assert_receive({:chainweb_requested, 200}) + end + + test "results/2 success" do + local_response = Chainweb.fixture("local") + + {:ok, + %LocalResponse{ + result: %{data: 11, status: "success"} + }} = Request.results({:ok, local_response}, as: LocalResponse) + end + + test "results/2 error" do + error = %Error{status: 400, title: "not enough input"} + {:error, ^error} = Request.results({:error, error}, as: LocalResponse) + end +end diff --git a/test/support/fixtures/chainweb.ex b/test/support/fixtures/chainweb.ex index a4e4678..495bd1a 100644 --- a/test/support/fixtures/chainweb.ex +++ b/test/support/fixtures/chainweb.ex @@ -3,21 +3,20 @@ defmodule Kadena.Test.Fixtures.Chainweb do Mocks Chainweb API responses. """ - alias Kadena.Utils.MapCase - @type fixture :: String.t() | atom() - @type opts :: Keyword.t() @fixtures_path "./test/support/fixtures/chainweb/" - @spec fixture(fixture :: fixture(), opts :: opts()) :: binary() + @spec fixture(fixture :: fixture()) :: binary() def fixture(fixture_name, opts \\ []) do - to_snake = Keyword.get(opts, :to_snake, false) + raw = Keyword.get(opts, :raw_data, false) + + body = + fixture_name + |> to_string() + |> read_json_file() - fixture_name - |> to_string() - |> read_json_file() - |> parse_to_snake(to_snake) + if(raw, do: body, else: Jason.decode!(body, keys: &snake_case_atom/1)) end @spec read_json_file(filename :: String.t()) :: binary() @@ -26,7 +25,10 @@ defmodule Kadena.Test.Fixtures.Chainweb do with {:ok, body} <- File.read(file), do: body end - @spec parse_to_snake(body :: binary(), to_snake :: boolean()) :: map() | binary() - defp parse_to_snake(body, true), do: body |> Jason.decode!() |> MapCase.to_snake!() - defp parse_to_snake(body, false), do: body + @spec snake_case_atom(string :: String.t()) :: atom() + defp snake_case_atom(string) do + string + |> Macro.underscore() + |> String.to_atom() + end end diff --git a/test/support/fixtures/chainweb/local.json b/test/support/fixtures/chainweb/local.json new file mode 100644 index 0000000..e32ac0d --- /dev/null +++ b/test/support/fixtures/chainweb/local.json @@ -0,0 +1,24 @@ +{ + "continuation": null, + "gas": 7, + "logs": "wsATyGqckuIvlm89hhd2j4t6RMkCrcwJe_oeCYr7Th8", + "metaData": { + "blockHeight": 2815727, + "blockTime": 1671054330981668, + "prevBlockHash": "asisNr3nuU0t357i2bxMVUiIWDVHAMtncJHtmyENbio", + "publicMeta": { + "chainId": "0", + "creationTime": 1667249173, + "gasLimit": 1000, + "gasPrice": 1.0e-6, + "sender": "k:554754f48b16df24b552f6832dda090642ed9658559fef9f3ee1bb4637ea7c94", + "ttl": 28800 + } + }, + "reqKey": "-1npoTU2Mi71pKE_oteJiJuHuXTXxoObJm8zzVRK2pk", + "result": { + "data": 11, + "status": "success" + }, + "txId": null +} diff --git a/test/support/fixtures/chainweb/send.json b/test/support/fixtures/chainweb/send.json new file mode 100644 index 0000000..65f5592 --- /dev/null +++ b/test/support/fixtures/chainweb/send.json @@ -0,0 +1,6 @@ +{ + "requestKeys": [ + "ATGCYPMNzdGcFh9Iik73KfMkgURIxaF91Ze4sHFsH8Q", + "JHgnKe5Wd4hNIb7a6bIhm4ifxsYFzVGtAMyi_TEO-oM" + ] +} diff --git a/test/types/spv_proof_test.exs b/test/types/spv_proof_test.exs deleted file mode 100644 index eac83c4..0000000 --- a/test/types/spv_proof_test.exs +++ /dev/null @@ -1,22 +0,0 @@ -defmodule Kadena.Types.SPVProofTest do - @moduledoc """ - `SPVProof` struct definition tests. - """ - - use ExUnit.Case - - alias Kadena.Types.SPVProof - - describe "new/1" do - test "with a valid param" do - spv_proof = - "eyJjaGFpbiI6MSwib2JqZWN0IjoiQUFBQUVBQUFBQUFBQUFBQkFBY3UzZlNTWXJpRV9ndEFybzFRN1NPMEZ2RDNaeFhUeGNWdzhDMHdkYXJfQU94TjZPRjFIdVZhY3dHUGVBY3dJZkpHZWoyUnNNTkhEdmlrZ2NZUWVockVBZWhPUk94V0FyQmJ1emV2dktNR1BlMHVGVV9QTzJ6MzdULS1jS2F0NnV3ekFYMGs1N1diOGJrT1JCUGhERHI4eXFiWG9YU2dJLWdaaEFMYlBUYTU0WWVDQUg4Ukgtc1dZV0dRU2xLdkNoYWlLeGZ6SGo0RkhCZnRRNXpSdkU3VmlOUWlBWGlVSk02SzNSZ3VjRkp6dGRCbS1QRlFZb0lYTzdCVXEyUjY5ZFBjZTR2ZUFIWnJicnIwc24tbkp3N1E2ZGxfSDdRVW1aNXM5QjMwZlQtYkdjbzB0RmF2QVBMVGxwUmh0bmVTd1FMeU0zdmhUc0NmQU9sb01ndGN1ci1OMFl5d0NCcG9BVlVxZHpZQ2ladTVDTUhKYjBWRGFqZGUtaUNTNXI1OVIzZlM1QTdWcHhxeUFMblpWWTU4cllFdjd4WXphM0hRTXBjQlRmUjU0aHZGREZINS1CUXlsa25jQVluUzBvYUhMVlFqamRJTFZpZXMtOUJZZ1lHb0dTZk1VUTZoTW5mWlZVdlZBT21HYnVULUx3UkxhTHhxY3FxVWRhbFMzVXpUbW00bHZlcXY4a1V3Szl2NUFJZHRQU2ZkZG9fTVJGUmpURGlxeTdOb1dCaVliNWhNNFpDNEs0b1A5aWVMQWZzYmY0ZFJqeHdyS0Nudm95YW5aUHFzWnJGdXgxZFBadWlDOTNTbUZYZFBBQ1VsYjJwal9KUmdQdnpmbzdiQXlDTmlIUnEzOHBGUlktOG8yNGxtdzVZOUFBS0VTcmpKVzJYM2JCWnU4dkl0NGI2WGNSLURwbzIzSE54S1N3bjBWMVotIiwic3ViamVjdCI6eyJpbnB1dCI6IkFCUjdJbWRoY3lJNk5EUTBMQ0p5WlhOMWJIUWlPbnNpYzNSaGRIVnpJam9pYzNWalkyVnpjeUlzSW1SaGRHRWlPbnNpWVcxdmRXNTBJam94TGpCbExUSXNJbkpsWTJWcGRtVnlJam9pTkdZNVl6UTJaR1l5Wm1VNE56UmtOMk14WWpZd1pqWTRaamcwTkRCaE5EUTBaR1EzTVRabE5tSXlaV1ppWVRobFpURTBNV0ZtWkdRMU9HTTVPVE5rWXlJc0luTnZkWEpqWlMxamFHRnBiaUk2SWpBaUxDSnlaV05sYVhabGNpMW5kV0Z5WkNJNmV5SndjbVZrSWpvaWEyVjVjeTFoYkd3aUxDSnJaWGx6SWpwYklqUm1PV00wTm1SbU1tWmxPRGMwWkRkak1XSTJNR1kyT0dZNE5EUXdZVFEwTkdSa056RTJaVFppTW1WbVltRTRaV1V4TkRGaFptUmtOVGhqT1RrelpHTWlYWDE5ZlN3aWNtVnhTMlY1SWpvaWVtWnNRa2hTTmxGS1FsSTNPSEprYVU5MU5raHlMWHBEZDBSVVQwVlBaVUpoYlhOcWRGVllPVFJhYXlJc0lteHZaM01pT2lKYU9YVnFkbVJEVEVsMVlXbHNUSEl5ZVRsSE0wVlRZVjg1TlVWeU1XMVdOblYwVVZaMVYyaFZWWFl3SWl3aVpYWmxiblJ6SWpwYmV5SndZWEpoYlhNaU9sc2lOR1k1WXpRMlpHWXlabVU0TnpSa04yTXhZall3WmpZNFpqZzBOREJoTkRRMFpHUTNNVFpsTm1JeVpXWmlZVGhsWlRFME1XRm1aR1ExT0dNNU9UTmtZeUlzSW1zNlpqZzVaV1kwTmpreU4yWTFNRFpqTnpCaU5tRTFPR1prTXpJeU5EVXdZVGt6TmpNeE1XUmpObUZqT1RGbU5HVmpNMlE0WldZNU5EazJNRGhrWW1ZeFppSXNOQzQwTkdVdE0xMHNJbTVoYldVaU9pSlVVa0ZPVTBaRlVpSXNJbTF2WkhWc1pTSTZleUp1WVcxbGMzQmhZMlVpT201MWJHd3NJbTVoYldVaU9pSmpiMmx1SW4wc0ltMXZaSFZzWlVoaGMyZ2lPaUp5UlRkRVZUaHFiRkZNT1hoZlRWQlpkVzVwV2twbU5VbERRbFJCUlVoQlNVWlJRMEkwWW14dlpsQTBJbjBzZXlKd1lYSmhiWE1pT2xzaU5HWTVZelEyWkdZeVptVTROelJrTjJNeFlqWXdaalk0WmpnME5EQmhORFEwWkdRM01UWmxObUl5WldaaVlUaGxaVEUwTVdGbVpHUTFPR001T1ROa1l5SXNJalJtT1dNME5tUm1NbVpsT0RjMFpEZGpNV0kyTUdZMk9HWTRORFF3WVRRME5HUmtOekUyWlRaaU1tVm1ZbUU0WldVeE5ERmhabVJrTlRoak9Ua3paR01pTERFdU1HVXRNaXdpTVNKZExDSnVZVzFsSWpvaVZGSkJUbE5HUlZKZldFTklRVWxPSWl3aWJXOWtkV3hsSWpwN0ltNWhiV1Z6Y0dGalpTSTZiblZzYkN3aWJtRnRaU0k2SW1OdmFXNGlmU3dpYlc5a2RXeGxTR0Z6YUNJNkluSkZOMFJWT0dwc1VVdzVlRjlOVUZsMWJtbGFTbVkxU1VOQ1ZFRkZTRUZKUmxGRFFqUmliRzltVURRaWZTeDdJbkJoY21GdGN5STZXeUkwWmpsak5EWmtaakptWlRnM05HUTNZekZpTmpCbU5qaG1PRFEwTUdFME5EUmtaRGN4Tm1VMllqSmxabUpoT0dWbE1UUXhZV1prWkRVNFl6azVNMlJqSWl3aUlpd3hMakJsTFRKZExDSnVZVzFsSWpvaVZGSkJUbE5HUlZJaUxDSnRiMlIxYkdVaU9uc2libUZ0WlhOd1lXTmxJanB1ZFd4c0xDSnVZVzFsSWpvaVkyOXBiaUo5TENKdGIyUjFiR1ZJWVhOb0lqb2lja1UzUkZVNGFteFJURGw0WDAxUVdYVnVhVnBLWmpWSlEwSlVRVVZJUVVsR1VVTkNOR0pzYjJaUU5DSjlMSHNpY0dGeVlXMXpJanBiSWpFaUxDSmpiMmx1TG5SeVlXNXpabVZ5TFdOeWIzTnpZMmhoYVc0aUxGc2lOR1k1WXpRMlpHWXlabVU0TnpSa04yTXhZall3WmpZNFpqZzBOREJoTkRRMFpHUTNNVFpsTm1JeVpXWmlZVGhsWlRFME1XRm1aR1ExT0dNNU9UTmtZeUlzSWpSbU9XTTBObVJtTW1abE9EYzBaRGRqTVdJMk1HWTJPR1k0TkRRd1lUUTBOR1JrTnpFMlpUWmlNbVZtWW1FNFpXVXhOREZoWm1Sa05UaGpPVGt6WkdNaUxIc2ljSEpsWkNJNkltdGxlWE10WVd4c0lpd2lhMlY1Y3lJNld5STBaamxqTkRaa1pqSm1aVGczTkdRM1l6RmlOakJtTmpobU9EUTBNR0UwTkRSa1pEY3hObVUyWWpKbFptSmhPR1ZsTVRReFlXWmtaRFU0WXprNU0yUmpJbDE5TENJeElpd3hMakJsTFRKZFhTd2libUZ0WlNJNklsaGZXVWxGVEVRaUxDSnRiMlIxYkdVaU9uc2libUZ0WlhOd1lXTmxJanB1ZFd4c0xDSnVZVzFsSWpvaWNHRmpkQ0o5TENKdGIyUjFiR1ZJWVhOb0lqb2lja1UzUkZVNGFteFJURGw0WDAxUVdYVnVhVnBLWmpWSlEwSlVRVVZJUVVsR1VVTkNOR0pzYjJaUU5DSjlYU3dpYldWMFlVUmhkR0VpT201MWJHd3NJbU52Ym5ScGJuVmhkR2x2YmlJNmV5SmxlR1ZqZFhSbFpDSTZiblZzYkN3aWNHRmpkRWxrSWpvaWVtWnNRa2hTTmxGS1FsSTNPSEprYVU5MU5raHlMWHBEZDBSVVQwVlBaVUpoYlhOcWRGVllPVFJhYXlJc0luTjBaWEJJWVhOU2IyeHNZbUZqYXlJNlptRnNjMlVzSW5OMFpYQWlPakFzSW5scFpXeGtJanA3SW1SaGRHRWlPbnNpWVcxdmRXNTBJam94TGpCbExUSXNJbkpsWTJWcGRtVnlJam9pTkdZNVl6UTJaR1l5Wm1VNE56UmtOMk14WWpZd1pqWTRaamcwTkRCaE5EUTBaR1EzTVRabE5tSXlaV1ppWVRobFpURTBNV0ZtWkdRMU9HTTVPVE5rWXlJc0luTnZkWEpqWlMxamFHRnBiaUk2SWpBaUxDSnlaV05sYVhabGNpMW5kV0Z5WkNJNmV5SndjbVZrSWpvaWEyVjVjeTFoYkd3aUxDSnJaWGx6SWpwYklqUm1PV00wTm1SbU1tWmxPRGMwWkRkak1XSTJNR1kyT0dZNE5EUXdZVFEwTkdSa056RTJaVFppTW1WbVltRTRaV1V4TkRGaFptUmtOVGhqT1RrelpHTWlYWDE5TENKemIzVnlZMlVpT2lJd0lpd2ljSEp2ZG1WdVlXNWpaU0k2ZXlKMFlYSm5aWFJEYUdGcGJrbGtJam9pTVNJc0ltMXZaSFZzWlVoaGMyZ2lPaUp5UlRkRVZUaHFiRkZNT1hoZlRWQlpkVzVwV2twbU5VbERRbFJCUlVoQlNVWlJRMEkwWW14dlpsQTBJbjE5TENKamIyNTBhVzUxWVhScGIyNGlPbnNpWVhKbmN5STZXeUkwWmpsak5EWmtaakptWlRnM05HUTNZekZpTmpCbU5qaG1PRFEwTUdFME5EUmtaRGN4Tm1VMllqSmxabUpoT0dWbE1UUXhZV1prWkRVNFl6azVNMlJqSWl3aU5HWTVZelEyWkdZeVptVTROelJrTjJNeFlqWXdaalk0WmpnME5EQmhORFEwWkdRM01UWmxObUl5WldaaVlUaGxaVEUwTVdGbVpHUTFPR001T1ROa1l5SXNleUp3Y21Wa0lqb2lhMlY1Y3kxaGJHd2lMQ0pyWlhseklqcGJJalJtT1dNME5tUm1NbVpsT0RjMFpEZGpNV0kyTUdZMk9HWTRORFF3WVRRME5HUmtOekUyWlRaaU1tVm1ZbUU0WldVeE5ERmhabVJrTlRoak9Ua3paR01pWFgwc0lqRWlMREV1TUdVdE1sMHNJbVJsWmlJNkltTnZhVzR1ZEhKaGJuTm1aWEl0WTNKdmMzTmphR0ZwYmlKOUxDSnpkR1Z3UTI5MWJuUWlPako5TENKMGVFbGtJam96TWprd2ZRIn0sImFsZ29yaXRobSI6IlNIQTUxMnRfMjU2In0" - - %SPVProof{value: ^spv_proof} = SPVProof.new(spv_proof) - end - - test "with an valid nil param" do - {:error, [value: :invalid]} = SPVProof.new(nil) - end - end -end