Packages
exvcr
0.10.3
0.17.1
0.17.0
0.16.0
0.15.2
0.15.1
0.15.0
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.7
0.1.6
0.1.5
HTTP request/response recording library for elixir, inspired by VCR.
Current section
Files
Jump to
Current section
Files
lib/exvcr/mock.ex
defmodule ExVCR.Mock do
@moduledoc """
Provides macro to record HTTP request/response.
"""
alias ExVCR.Recorder
defmacro __using__(opts) do
adapter = opts[:adapter] || ExVCR.Adapter.IBrowse
options = opts[:options]
quote do
import ExVCR.Mock
:application.start(unquote(adapter).module_name)
use unquote(adapter)
def adapter_method() do
unquote(adapter)
end
def options_method() do
unquote(options)
end
end
end
@doc """
Provides macro to mock response based on specified parameters.
"""
defmacro use_cassette(:stub, options, test) do
quote do
stub_fixture = "stub_fixture_#{ExVCR.Util.uniq_id}"
stub = prepare_stub_record(unquote(options), adapter_method())
recorder = Recorder.start([fixture: stub_fixture, stub: stub, adapter: adapter_method()])
try do
mock_methods(recorder, adapter_method())
[do: return_value] = unquote(test)
return_value
after
module_name = adapter_method().module_name
:meck.unload(module_name)
ExVCR.MockLock.release_lock()
end
end
end
@doc """
Provides macro to trigger recording/replaying http interactions.
## Options
- `:match_requests_on` A list of request properties to match on when
finding a matching response. Valid values include `:query`, `:headers`,
and `:request_body`
"""
defmacro use_cassette(fixture, options, test) do
quote do
recorder = Recorder.start(
unquote(options) ++ [fixture: normalize_fixture(unquote(fixture)), adapter: adapter_method()])
try do
mock_methods(recorder, adapter_method())
[do: return_value] = unquote(test)
return_value
after
recorder_result = Recorder.save(recorder)
module_name = adapter_method().module_name
:meck.unload(module_name)
ExVCR.MockLock.release_lock()
recorder_result
end
end
end
@doc """
Provides macro to trigger recording/replaying http interactions with default options.
"""
defmacro use_cassette(fixture, test) do
quote do
use_cassette(unquote(fixture), [], unquote(test))
end
end
@doc """
Mock methods pre-defined for the specified adapter.
"""
def mock_methods(recorder, adapter) do
target_methods = adapter.target_methods(recorder)
module_name = adapter.module_name
parent_pid = self()
Task.async(fn ->
ExVCR.MockLock.ensure_started
ExVCR.MockLock.request_lock(self(), parent_pid)
receive do
:lock_granted ->
Enum.each(target_methods, fn({function, callback}) ->
:meck.expect(module_name, function, callback)
end)
end
end)
|> Task.await(:infinity)
end
@doc """
Prepare stub record based on specified option parameters.
"""
def prepare_stub_record(options, adapter) do
method = (options[:method] || "get") |> to_string
url = (options[:url] || "~r/.+/") |> to_string
body = (options[:body] || "Hello World") |> to_string
# REVIEW: would be great to have "~r/.+/" as default request_body
request_body = (options[:request_body] || "") |> to_string
headers = options[:headers] || adapter.default_stub_params(:headers)
status_code = options[:status_code] || adapter.default_stub_params(:status_code)
record = %{ "request" => %{"method" => method, "url" => url, "request_body" => request_body},
"response" => %{"body" => body, "headers" => headers, "status_code" => status_code} }
[adapter.convert_from_string(record)]
end
@doc """
Normalize fixture name for using as json file names, which removes whitespaces and align case.
"""
def normalize_fixture(fixture) do
fixture |> String.replace(~r/\s/, "_") |> String.downcase
end
end