Packages
exvcr
0.14.2
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 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(: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
unload(module_name)
ExVCR.MockLock.release_lock()
end
end
end
defmacro use_cassette(fixture, options, test) do
quote do
recorder = start_cassette(unquote(fixture), unquote(options))
try do
[do: return_value] = unquote(test)
return_value
after
stop_cassette(recorder)
end
end
end
defmacro use_cassette(fixture, test) do
quote do
use_cassette(unquote(fixture), [], unquote(test))
end
end
defmacro start_cassette(fixture, options) when fixture != :stub do
quote do
recorder =
Recorder.start(
unquote(options) ++
[fixture: normalize_fixture(unquote(fixture)), adapter: adapter_method()]
)
mock_methods(recorder, adapter_method())
recorder
end
end
defmacro stop_cassette(recorder) do
quote do
recorder_result = Recorder.save(unquote(recorder))
module_name = adapter_method().module_name
unload(module_name)
ExVCR.MockLock.release_lock()
recorder_result
end
end
@doc false
defp load(adapter, recorder) do
if ExVCR.Application.global_mock_enabled?() do
ExVCR.Actor.CurrentRecorder.set(recorder)
else
module_name = adapter.module_name
target_methods = adapter.target_methods(recorder)
Enum.each(target_methods, fn({function, callback}) ->
:meck.expect(module_name, function, callback)
end)
end
end
@doc false
def unload(module_name) do
if ExVCR.Application.global_mock_enabled?() do
ExVCR.Actor.CurrentRecorder.default_state()
|> ExVCR.Actor.CurrentRecorder.set()
else
:meck.unload(module_name)
end
end
@doc """
Mock methods pre-defined for the specified adapter.
"""
def mock_methods(recorder, adapter) do
parent_pid = self()
Task.async(fn ->
ExVCR.MockLock.ensure_started
ExVCR.MockLock.request_lock(self(), parent_pid)
receive do
:lock_granted ->
load(adapter, recorder)
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