diff --git a/.github/workflows/run_tests_job.yml b/.github/workflows/run_tests_job.yml new file mode 100644 index 0000000..13fc508 --- /dev/null +++ b/.github/workflows/run_tests_job.yml @@ -0,0 +1,42 @@ +name: Run full Elixir workflow + +on: + pull_request: + types: [ opened, reopened, edited ] + branches: + - master + push: + branches: + - add_github_action + workflow_dispatch: +jobs: + elixir_workflow: + runs-on: ubuntu-latest + strategy: + matrix: + elixir-version: ['1.12'] + otp: ['22.0'] + steps: + - uses: actions/checkout@v2 + - name: Setup Elixir + uses: erlef/setup-beam@v1 + with: + otp-version: '22.0' + elixir-version: '1.12' + - name: Install Dependencies + run: mix deps.get + - name: Compile Repository + run: mix compile --warnings-as-errors + - name: Check Code Coverage & Upload to Coveralls.io + run: MIX_ENV=test mix coveralls.github --max-cases 1 + env: + API_KEY: ${{ secrets.API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Run Static Code Analysis for Elixir + run: mix credo + - name: Run Static Code Analysis for Erlang + run: mix dialyzer --halt-exit-status + - name: Run Elixir Tests + env: + API_KEY: ${{ secrets.API_KEY }} + run: mix deps.get && mix test \ No newline at end of file diff --git a/README.md b/README.md index 11accc2..042b68d 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ This library implements the Lob API. Please read through the official [API Docum The library requires a valid Lob API key to work properly. To acquire an API key, first create an account at [Lob.com](https://dashboard.lob.com/#/register). Once you have created an account, you can access your API Keys from the [Settings Panel](https://dashboard.lob.com/#/settings). ### API Key Configuration - The library will by default refer to the `:api_key` config when making authenticated requests. If that is not present, it will look for the `LOB_API_KEY` environment variable. + The library will by default refer to the `:api_key` config when making authenticated requests. If that is not present, it will look for the `API_KEY` environment variable. ```elixir # Configuring an API key with configs @@ -78,11 +78,11 @@ Tests are written using [ExUnit](https://hexdocs.pm/ex_unit/ExUnit.html), Elixir Here's how you can run the tests: - LOB_API_KEY=YOUR_TEST_API_KEY mix test + API_KEY=YOUR_TEST_API_KEY mix test To run tests with a coverage report: - LOB_API_KEY=YOUR_TEST_API_KEY mix coveralls.html + API_KEY=YOUR_TEST_API_KEY mix coveralls.html Then view the report at `cover/excoveralls.html`. diff --git a/config/config.exs b/config/config.exs index c9c59bb..9def7c2 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,3 +1,3 @@ -use Mix.Config +import Config import_config "#{Mix.env}.exs" diff --git a/config/test.exs b/config/test.exs index a8d657a..bf27bfa 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,4 +1,7 @@ -use Mix.Config +import Config config :lob_elixir, - api_key: System.get_env("LOB_API_KEY") + api_key: System.get_env("API_KEY") + +# config :pre_commit, +# commands: ["test", "credo", "dialyzer", "coveralls"] diff --git a/lib/lob/bulk_intl_verification.ex b/lib/lob/bulk_intl_verification.ex index d74160b..4834ba9 100644 --- a/lib/lob/bulk_intl_verification.ex +++ b/lib/lob/bulk_intl_verification.ex @@ -8,7 +8,7 @@ defmodule Lob.BulkIntlVerification do def verify(data, headers \\ %{"Content-type": "application/json"}) do with {:ok, encoded_data} <- Poison.encode(data) do - Client.post_request(base_url(), encoded_data, Util.build_headers(headers)) + Client.post_request_binary(base_url(), encoded_data, Util.build_headers(headers)) end end diff --git a/lib/lob/bulk_us_verification.ex b/lib/lob/bulk_us_verification.ex index 6578ca5..287349a 100644 --- a/lib/lob/bulk_us_verification.ex +++ b/lib/lob/bulk_us_verification.ex @@ -2,12 +2,19 @@ defmodule Lob.BulkUSVerification do @moduledoc """ Module implementing the Lob bulk US verifications API. """ - use Lob.ResourceBase, endpoint: "bulk/us_verifications", methods: [] - @spec verify(map, map) :: Client.client_response | no_return +# The @spec for the function does not match the success typing of the function. + +# Function: +# Lob.BulkUSVerification.verify/2 + +# Success typing: +# @spec verify(%{:addresses => [any()]}, map()) :: {:error, _} | {:ok, map(), [any()]} + + @spec verify(any, map()) :: {:error, any} | {:ok, map(), [any()]} def verify(data, headers \\ %{"Content-type": "application/json"}) do - Client.post_request(base_url(), Poison.encode!(data), Util.build_headers(headers)) + Client.post_request_binary(base_url(), Poison.encode!(data), Util.build_headers(headers)) end end diff --git a/lib/lob/client.ex b/lib/lob/client.ex index 4ea999e..08e9703 100644 --- a/lib/lob/client.ex +++ b/lib/lob/client.ex @@ -3,9 +3,8 @@ defmodule Lob.Client do Client responsible for making requests to Lob and handling the responses. """ - alias Poison.Parser alias HTTPoison.Error - alias HTTPoison.Response + alias Poison.Parser use HTTPoison.Base @@ -20,7 +19,7 @@ defmodule Lob.Client do defexception message: """ The api_key setting is required to make requests to Lob. - Please configure :api_key in config.exs or set the LOB_API_KEY + Please configure :api_key in config.exs or set the API_KEY environment variable. config :lob_elixir, api_key: API_KEY @@ -32,7 +31,7 @@ defmodule Lob.Client do @spec api_key(atom) :: String.t def api_key(env_key \\ :api_key) do - case Confex.get_env(:lob_elixir, env_key, System.get_env("LOB_API_KEY")) || :not_found do + case Confex.get_env(:lob_elixir, env_key, System.get_env("API_KEY")) || :not_found do :not_found -> raise MissingAPIKeyError value -> value end @@ -68,13 +67,20 @@ defmodule Lob.Client do |> handle_response end - @spec post_request(String.t, {:multipart, list}, HTTPoison.Base.headers) :: client_response + @spec post_request(<<_::64, _::_*8>>, {:multipart, [any()]}, [{binary(), binary()}]) :: client_response def post_request(url, body, headers \\ []) do url |> post(body, headers, build_options()) |> handle_response end + @spec post_request_binary(<<_::64, _::_*8>>, binary(), [{binary(), binary()}]) :: client_response + def post_request_binary(url, body, headers \\ []) do + url + |> post(body, headers, build_options()) + |> handle_response + end + @spec delete_request(String.t, HTTPoison.Base.headers) :: client_response def delete_request(url, headers \\ []) do url diff --git a/lib/lob/resource_base.ex b/lib/lob/resource_base.ex index 164701e..021c6c6 100644 --- a/lib/lob/resource_base.ex +++ b/lib/lob/resource_base.ex @@ -10,8 +10,8 @@ defmodule Lob.ResourceBase do quote do @default_api_host "https://api.lob.com/v1" - alias Lob.Util alias Lob.Client + alias Lob.Util if :list in unquote(methods) do @spec list(map, map) :: Client.client_response @@ -73,14 +73,20 @@ defmodule Lob.ResourceBase do end end - @spec base_url :: String.t - defp base_url, do: "#{api_host()}/#{unquote(endpoint)}" + @spec base_url :: <<_::64, _::_*8>> + defp base_url do + "#{api_host()}/#{unquote(endpoint)}" + end - @spec api_host :: String.t - defp api_host, do: Application.get_env(:lob_elixir, :api_host, @default_api_host) + @spec api_host :: <<_::64, _::_*8>> + defp api_host do + "#{Application.get_env(:lob_elixir, :api_host, @default_api_host)}" + end - @spec resource_url(String.t) :: String.t - defp resource_url(resource_id), do: "#{base_url()}/#{resource_id}" + @spec resource_url(String.t) :: <<_::64, _::_*8>> + defp resource_url(resource_id) do + "#{base_url()}/#{resource_id}" + end end end diff --git a/lib/lob/util.ex b/lib/lob/util.ex index add56e6..7d686b3 100644 --- a/lib/lob/util.ex +++ b/lib/lob/util.ex @@ -27,7 +27,8 @@ defmodule Lob.Util do """ @spec build_body(map) :: {:multipart, list} def build_body(body) when is_map(body) do - {:multipart, Enum.reduce(body, [], &(&2 ++ transform_argument(&1)))} + result = {:multipart, Enum.reduce(body, [], &(&2 ++ transform_argument(&1)))} + result end @doc """ diff --git a/mix.exs b/mix.exs index 0279221..adab746 100644 --- a/mix.exs +++ b/mix.exs @@ -21,6 +21,11 @@ defmodule Lob.Mixfile do :unknown ], ignore_warnings: ".dialyzer_ignore" + ], + xref: [ + exclude: [ + :crypto + ] ] ] end @@ -39,7 +44,9 @@ defmodule Lob.Mixfile do {:dialyxir, "~> 1.1", only: [:dev, :test], runtime: false}, {:excoveralls, "~> 0.14", only: :test}, {:httpoison, "~> 1.8"}, + {:json, "~> 1.4"}, {:poison, "~> 5.0"}, + {:pre_commit, "~> 0.3.4", only: :dev}, {:plug_cowboy, "~> 2.5"}, {:uuid, "~> 1.1", only: :test} ] diff --git a/mix.lock b/mix.lock index f4fe6ef..41acafc 100644 --- a/mix.lock +++ b/mix.lock @@ -16,6 +16,7 @@ "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, + "json": {:hex, :json, "1.4.1", "8648f04a9439765ad449bc56a3ff7d8b11dd44ff08ffcdefc4329f7c93843dfa", [:mix], [], "hexpm", "9abf218dbe4ea4fcb875e087d5f904ef263d012ee5ed21d46e9dbca63f053d16"}, "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"}, @@ -25,6 +26,7 @@ "plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"}, "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, "poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"}, + "pre_commit": {:hex, :pre_commit, "0.3.4", "e2850f80be8090d50ad8019ef2426039307ff5dfbe70c736ad0d4d401facf304", [:mix], [], "hexpm", "16f684ba4f1fed1cba6b19e082b0f8d696e6f1c679285fedf442296617ba5f4e"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"}, diff --git a/test/lob/address_test.exs b/test/lob/address_test.exs index 917b53d..f465625 100644 --- a/test/lob/address_test.exs +++ b/test/lob/address_test.exs @@ -13,7 +13,10 @@ defmodule Lob.AddressTest do address_city: "San Francisco", address_state: "CA", address_country: "US", - address_zip: "94107" + address_zip: "94107", + metadata: %{ + foo: "bar" + } } } end @@ -35,9 +38,15 @@ defmodule Lob.AddressTest do assert addresses.count == 2 end - test "filters by metadata" do + test "filters by metadata", %{sample_address: sample_address} do + {:ok, created_address, _headers} = + sample_address + |> Map.merge(%{metadata: %{foo: "bar"}}) + |> Address.create + {:ok, addresses, _headers} = Address.list(%{metadata: %{foo: "bar"}}) - assert addresses.count == 1 + assert addresses.count > 0 + Address.delete(created_address.id) end end diff --git a/test/lob/bank_account_test.exs b/test/lob/bank_account_test.exs index 0df0aa4..2fedccd 100644 --- a/test/lob/bank_account_test.exs +++ b/test/lob/bank_account_test.exs @@ -9,7 +9,8 @@ defmodule Lob.BankAccountTest do routing_number: "122100024", account_number: "123456789", account_type: "company", - signatory: "John Doe" + signatory: "John Doe", + metadata: %{foo: "bar"} } } end @@ -31,9 +32,12 @@ defmodule Lob.BankAccountTest do assert bank_accounts.count == 2 end - test "filters by metadata" do + test "filters by metadata", %{sample_bank_account: sample_bank_account} do + {:ok, created_bank_account, _headers} = BankAccount.create(sample_bank_account) + {:ok, bank_accounts, _headers} = BankAccount.list(%{metadata: %{foo: "bar"}}) - assert bank_accounts.count == 1 + assert bank_accounts.count > 0 + BankAccount.delete(created_bank_account.id) end end diff --git a/test/lob/check_test.exs b/test/lob/check_test.exs index 69bbe31..0ac514a 100644 --- a/test/lob/check_test.exs +++ b/test/lob/check_test.exs @@ -26,7 +26,7 @@ defmodule Lob.CheckTest do sample_check = %{ description: "Library Test Check #{DateTime.utc_now |> DateTime.to_string}", - amount: 100 + amount: 100, } %{ @@ -53,9 +53,22 @@ defmodule Lob.CheckTest do assert checks.count == 2 end - test "filters by metadata" do + test "filters by metadata", %{sample_address: sample_address, sample_bank_account: sample_bank_account, sample_check: sample_check} do + {:ok, created_address, _headers} = Address.create(sample_address) + {:ok, verified_bank_account, _headers} = create_and_verify_bank_account(sample_bank_account) + + {:ok, created_check, _headers} = + Check.create(%{ + description: sample_check.description, + to: created_address.id, + from: created_address.id, + bank_account: verified_bank_account.id, + amount: 1312, + metadata: %{foo: "bar"} + }) {:ok, checks, _headers} = Check.list(%{metadata: %{foo: "bar"}}) - assert checks.count == 1 + assert checks.count > 0 + Check.delete(created_check.id) end end diff --git a/test/lob/client_test.exs b/test/lob/client_test.exs index 1d6e5a5..2b98283 100644 --- a/test/lob/client_test.exs +++ b/test/lob/client_test.exs @@ -15,10 +15,10 @@ defmodule Lob.ClientTest do test "raises MissingAPIKeyError if no API key is found" do assert_raise(MissingAPIKeyError, fn -> - api_key = System.get_env("LOB_API_KEY") - System.delete_env("LOB_API_KEY") + api_key = System.get_env("API_KEY") + System.delete_env("API_KEY") Client.api_key(nil) - System.put_env("LOB_API_KEY", api_key) + System.put_env("API_KEY", api_key) end) end diff --git a/test/lob/letter_test.exs b/test/lob/letter_test.exs index c290929..058c87a 100644 --- a/test/lob/letter_test.exs +++ b/test/lob/letter_test.exs @@ -17,7 +17,7 @@ defmodule Lob.LetterTest do } sample_letter = %{ - description: "Library Test Letter #{DateTime.utc_now |> DateTime.to_string}" + description: "Library Test Letter #{DateTime.utc_now |> DateTime.to_string}", } %{ @@ -43,9 +43,26 @@ defmodule Lob.LetterTest do assert letters.count == 2 end - test "filters by metadata" do + test "filters by metadata", %{sample_address: sample_address} do + {:ok, created_address, _headers} = Address.create(sample_address) + + {:ok, created_letter, _headers} = + Letter.create(%{ + description: "Letter with metadata", + to: created_address.id, + from: created_address.id, + color: true, + file: "{{data.name}}", + metadata: %{foo: "bar"}, + merge_variables: %{ + data: %{ + name: "Donald" + } + } + }) {:ok, letters, _headers} = Letter.list(%{metadata: %{foo: "bar"}}) - assert letters.count == 1 + assert letters.count > 0 + Letter.delete(created_letter.id) end end diff --git a/test/lob/postcard_test.exs b/test/lob/postcard_test.exs index 26a8baf..db7ce7b 100644 --- a/test/lob/postcard_test.exs +++ b/test/lob/postcard_test.exs @@ -44,9 +44,18 @@ defmodule Lob.PostcardTest do assert postcards.count == 2 end - test "filters by metadata" do + test "filters by metadata", %{sample_address: sample_address} do + {:ok, created_postcard, _headers} = Postcard.create(%{ + to: sample_address, + from: sample_address, + description: "Library Test Postcard #{DateTime.utc_now |> DateTime.to_string}", + front: "

Sample postcard back

", + back: "

Sample postcard back

", + metadata: %{foo: "bar"} + }) {:ok, postcards, _headers} = Postcard.list(%{metadata: %{foo: "bar"}}) - assert postcards.count == 1 + assert postcards.count > 0 + Postcard.delete(created_postcard.id) end end