Skip to content

Commit

Permalink
Add clause to catch/handle bad config format (#151)
Browse files Browse the repository at this point in the history
* Add clause to catch/handle bad config format

Closes #150
Closes #136

* [ci-skip] Improve mock test template

* Since all mock tests are to be written using Bypass, removed mock file
as well as mention of `mock` library.
* Added setup and parse to the test template
  • Loading branch information
oyeb committed Jun 6, 2018
1 parent 9414bb4 commit f0dacc1
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 28 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,11 @@ We wanted to "supervise" our payments, and power utilities to process recurring
payments, subscriptions with it. But yes, as of now, it is a bottle neck and
unnecessary.

It's slated to be removed in [`v2.0.0`][milestone-2_0_0_alpha] and any supervised / async /
parallel work can be explicitly managed via native elixir constructs.
It's slated to be removed in [`v2.0.0`][milestone-2_0_0_alpha] and any
supervised/async/parallel work can be explicitly managed via native elixir
constructs.

**In fact, it's already been removed from our [dev](#) branch.**

[milestone-2_0_0_alpha]: https://github.com/aviabird/gringotts/milestone/3
[reason]: http://harrypotter.wikia.com/wiki/Gringotts
Expand Down
1 change: 0 additions & 1 deletion lib/gringotts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ defmodule Gringotts do
end

defp get_and_validate_config(gateway) do
# Keep the key name and adapter the same in the config in application
config = Application.get_env(:gringotts, gateway)
# The following call to validate_config might raise an error
gateway.validate_config(config)
Expand Down
8 changes: 7 additions & 1 deletion lib/gringotts/adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ defmodule Gringotts.Adapter do
Raises a run-time `ArgumentError` if any of the `required_config` values
is not available or missing from the Application config.
"""
def validate_config(config) do
def validate_config(config) when is_list(config) do
missing_keys =
Enum.reduce(@required_config, [], fn key, missing_keys ->
if config[key] in [nil, ""], do: [key | missing_keys], else: missing_keys
Expand All @@ -58,6 +58,12 @@ defmodule Gringotts.Adapter do
raise_on_missing_config(missing_keys, config)
end

def validate_config(config) when is_map(config) do
config
|> Enum.into([])
|> validate_config
end

defp raise_on_missing_config([], _config), do: :ok

defp raise_on_missing_config(key, config) do
Expand Down
4 changes: 1 addition & 3 deletions templates/gateway.eex
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ defmodule Gringotts.Gateways.<%= gateway_module %> do

## Following the examples

1. First, set up a sample application and configure it to work with MONEI.
1. First, set up a sample application and configure it to work with <%= gateway %>.
- You could do that from scratch by following our [Getting Started][gs] guide.
- To save you time, we recommend [cloning our example
repo][example] that gives you a pre-configured sample app ready-to-go.
Expand Down Expand Up @@ -258,15 +258,13 @@ defmodule Gringotts.Gateways.<%= gateway_module %> do
# For consistency with other gateway implementations, make your (final)
# network request in here, and parse it using another private method called
# `respond`.
@spec commit(_) :: {:ok | :error, Response}
defp commit(_) do
# resp = HTTPoison.request(args, ...)
# respond(resp, ...)
end

# Parses <%= gateway %>'s response and returns a `Gringotts.Response` struct
# in a `:ok`, `:error` tuple.
@spec respond(term) :: {:ok | :error, Response}
defp respond(<%= gateway_underscore %>_response)
defp respond({:ok, %{status_code: 200, body: body}}), do: "something"
defp respond({:ok, %{status_code: status_code, body: body}}), do: "something"
Expand Down
10 changes: 7 additions & 3 deletions templates/integration.eex
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
defmodule Gringotts.Integration.Gateways.<%= gateway_module <> "Test"%> do
# Integration tests for the <%= gateway_module%>
defmodule Gringotts.Integration.Gateways.<%= gateway_module <> "Test" %> do
# Integration tests for the <%= gateway_module %>
#
# Note that your tests SHOULD NOT directly call the <%= gateway_module %>, but
# all calls must be via Gringotts' public API as defined in `lib`gringotts.ex`

use ExUnit.Case, async: false
use ExUnit.Case, async: true
alias Gringotts.Gateways.<%= gateway_module%>

@moduletag :integration
Expand All @@ -15,6 +18,7 @@ defmodule Gringotts.Integration.Gateways.<%= gateway_module <> "Test"%> do
end

# Group the test cases by public api

describe "purchase" do
end

Expand Down
68 changes: 50 additions & 18 deletions templates/test.eex
Original file line number Diff line number Diff line change
@@ -1,32 +1,64 @@
defmodule Gringotts.Gateways.<%= gateway_module <> "Test" %> do
# The file contains mocked tests for <%= gateway_module%>
# The file contains mock tests for <%= gateway_module%>

# We recommend using [mock][1] for this, you can place the mock responses from
# the Gateway in `test/mocks/<%= mock_response_filename %>` file, which has also been
# generated for you.
#
# [1]: https://github.com/jjh42/mock
# We recommend using [`Bypass`][bypass] for this as it allows us to inspect
# the request body that is sent to the gateway.

# After all, the only thing Gringotts does, is building HTTPoison requests
# from arguments. Thus by validating that a request has been properly
# constructed from the given arguments we accurately cover the behaviour of
# the module.

# For inspiration and guidance to writing mock tests, please refer the mock
# tests of the MONEI gateway. Bypass has excellent documentation and there are
# numerous blog posts detailing good practices.

# Load the mock response file before running the tests.
Code.require_file "../mocks/<%= mock_response_filename %>", __DIR__
# [bypass]: https://github.com/pspdfkit-labs/bypass

use ExUnit.Case, async: false
use ExUnit.Case, async: true

import Bypass

alias Gringotts.Gateways.<%= gateway_module%>
import Mock
alias Plug.{Conn, Parsers}

# Group the test cases by public api
describe "purchase" do
# A new Bypass instance is needed per test, so that we can do parallel tests
setup do
bypass = Bypass.open()
{:ok, bypass: bypass}
end

describe "authorize" do
end
@doc """
Parses the body of the `Plug.Conn.t`.

describe "capture" do
end
This is very useful when testing with `Bypass` to parse body of the request
built in the test. This makes it dead-simple to write asserts on the request
body!

## Example
```
test "something", %{bypass: bypass} do
Bypass.expect(bypass, "POST", "some/endpoint/", fn conn ->
p_conn = parse(conn)
params = p_conn.body_params
assert params["amount"] == "42.00"
assert params["currency"] == "USD"
Conn.resp(conn, 200, "the_mocked_reponse_body")
end)

describe "void" do
{:ok, response} = Gateway.authorize(@amount42, @card, @opts)
assert "something about the mocked response if necessary"
end
```
"""
@spec parse(Plug.Conn.t(), keyword) :: Plug.Conn.t()
def parse(conn, opts \\ []) do
opts = Keyword.put_new(opts, :parsers, [Parsers.URLENCODED])

describe "refund" do
# if your gateway returns JSON instead of URL Encoded responses, use the
# JSON parser

# opts = Keyword.put_new(opts, :parsers, [Parsers.JSON])
Parsers.call(conn, Parsers.init(opts))
end
end

0 comments on commit f0dacc1

Please sign in to comment.