Skip to content

Commit

Permalink
fix: match request body json otp26 (#213)
Browse files Browse the repository at this point in the history
* handle request body differently if it is json

* Revert "handle request body differently if it is json"

This reverts commit 02cf526.

* only add the code without formatting

* revert formatting change

* remove jason

* add a test with a map
  • Loading branch information
barnabasJ authored Dec 9, 2023
1 parent 8c942fe commit 0af120a
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 15 deletions.
27 changes: 27 additions & 0 deletions fixture/vcr_cassettes/finch_post_map.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[
{
"request": {
"body": "{\"address\":{\"city\":\"Los Angeles\",\"state\":\"CA\",\"street\":\"123 Main St\",\"zip\":\"90001\"},\"age\":30,\"city\":\"New York\",\"country\":\"USA\",\"favoriteColor\":\"blue\",\"hobbies\":[\"reading\",\"traveling\",\"swimming\"],\"isMarried\":true,\"name\":\"John\",\"phoneNumbers\":[{\"number\":\"555-555-1234\",\"type\":\"home\"},{\"number\":\"555-555-5678\",\"type\":\"work\"}]}",
"headers": [],
"method": "post",
"options": [],
"request_body": "",
"url": "http://httpbin.org/post"
},
"response": {
"binary": false,
"body": "{\n \"args\": {}, \n \"data\": \"{\\\"address\\\":{\\\"city\\\":\\\"Los Angeles\\\",\\\"state\\\":\\\"CA\\\",\\\"street\\\":\\\"123 Main St\\\",\\\"zip\\\":\\\"90001\\\"},\\\"age\\\":30,\\\"city\\\":\\\"New York\\\",\\\"country\\\":\\\"USA\\\",\\\"favoriteColor\\\":\\\"blue\\\",\\\"hobbies\\\":[\\\"reading\\\",\\\"traveling\\\",\\\"swimming\\\"],\\\"isMarried\\\":true,\\\"name\\\":\\\"John\\\",\\\"phoneNumbers\\\":[{\\\"number\\\":\\\"555-555-1234\\\",\\\"type\\\":\\\"home\\\"},{\\\"number\\\":\\\"555-555-5678\\\",\\\"type\\\":\\\"work\\\"}]}\", \n \"files\": {}, \n \"form\": {}, \n \"headers\": {\n \"Content-Length\": \"323\", \n \"Host\": \"httpbin.org\", \n \"User-Agent\": \"mint/1.5.1\", \n \"X-Amzn-Trace-Id\": \"Root=1-6502b298-152ed17e42e07eca56f829aa\"\n }, \n \"json\": {\n \"address\": {\n \"city\": \"Los Angeles\", \n \"state\": \"CA\", \n \"street\": \"123 Main St\", \n \"zip\": \"90001\"\n }, \n \"age\": 30, \n \"city\": \"New York\", \n \"country\": \"USA\", \n \"favoriteColor\": \"blue\", \n \"hobbies\": [\n \"reading\", \n \"traveling\", \n \"swimming\"\n ], \n \"isMarried\": true, \n \"name\": \"John\", \n \"phoneNumbers\": [\n {\n \"number\": \"555-555-1234\", \n \"type\": \"home\"\n }, \n {\n \"number\": \"555-555-5678\", \n \"type\": \"work\"\n }\n ]\n }, \n \"origin\": \"62.178.80.139\", \n \"url\": \"http://httpbin.org/post\"\n}\n",
"headers": {
"date": "Thu, 14 Sep 2023 07:13:28 GMT",
"content-type": "application/json",
"content-length": "1240",
"connection": "keep-alive",
"server": "gunicorn/19.9.0",
"access-control-allow-origin": "*",
"access-control-allow-credentials": "true"
},
"status_code": 200,
"type": "ok"
}
}
]
37 changes: 32 additions & 5 deletions lib/exvcr/handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,44 @@ defmodule ExVCR.Handler do

defp normalize_url(url) do
original_url = URI.parse(url)

original_url
|> Map.put(:query, normalize_query(original_url.query))
|> URI.to_string()
end

defp normalize_request_body(request_body) do
normalize_query(request_body)
defp normalize_request_body(request_body) when is_binary(request_body) do
case JSX.decode(request_body) do
{:ok, decoded} ->
normalize_request_body(decoded)

{:error, _} ->
normalize_query(request_body)
end
end

defp normalize_request_body(request_body) when is_map(request_body) do
request_body
|> Map.to_list()
|> Enum.sort_by(fn {key, _val} -> key end)
|> Enum.map(fn
{key, val} when is_map(val) -> {key, normalize_request_body(val)}
{key, val} when is_list(val) -> {key, normalize_request_body(val)}
{key, val} -> {key, val}
end)
|> URI.encode_query()
end

defp normalize_request_body(request_body) when is_list(request_body) do
request_body
|> Enum.map(fn
val when is_map(val) -> normalize_request_body(val)
val when is_list(val) -> normalize_request_body(val)
val -> val
end)
|> Enum.map_join(&to_string/1)
end
defp normalize_query(nil), do: nil

defp normalize_query(nil), do: nil

defp normalize_query(query) do
query
Expand Down
84 changes: 74 additions & 10 deletions test/adapter_finch_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ defmodule ExVCR.Adapter.FinchTest do

setup_all do
HttpServer.start(path: "/server", port: @port, response: "test_response")
on_exit fn ->

on_exit(fn ->
HttpServer.stop(@port)
end
end)

:ok
end

Expand All @@ -17,17 +19,20 @@ defmodule ExVCR.Adapter.FinchTest do
ExVCR.Actor.CurrentRecorder.default_state()
|> ExVCR.Actor.CurrentRecorder.set()
end

url = "http://localhost:#{@port}/server"
{:ok, response} = Finch.build(:get, url) |> Finch.request(ExVCRFinch)
assert response.status == 200
end

test "passthrough works after cassette has been used" do
url = "http://localhost:#{@port}/server"

use_cassette "finch_get_localhost" do
{:ok, response} = Finch.build(:get, url) |> Finch.request(ExVCRFinch)
assert response.status == 200
end

{:ok, response} = Finch.build(:get, url) |> Finch.request(ExVCRFinch)
assert response.status == 200
end
Expand Down Expand Up @@ -63,7 +68,11 @@ defmodule ExVCR.Adapter.FinchTest do
test "request with HTTPError" do
use_cassette "finch_httperror", custom: true do
{:error, response} = Finch.build(:get, "http://example.com/") |> Finch.request(ExVCRFinch)
assert response == %Mint.HTTPError{module: Mint.HTTP2, reason: :too_many_concurrent_requests}

assert response == %Mint.HTTPError{
module: Mint.HTTP2,
reason: :too_many_concurrent_requests
}
end
end

Expand All @@ -90,31 +99,84 @@ defmodule ExVCR.Adapter.FinchTest do

test "post method" do
use_cassette "finch_post" do
assert_response Finch.build(:post, "http://httpbin.org/post", [], "test") |> Finch.request(ExVCRFinch)
assert_response(
Finch.build(:post, "http://httpbin.org/post", [], "test")
|> Finch.request(ExVCRFinch)
)
end
end

@tag :wip
test "post method with json body" do
use_cassette "finch_post_map" do
assert_response(
Finch.build(
:post,
"http://httpbin.org/post",
[],
JSX.encode!(%{
name: "John",
age: 30,
city: "New York",
country: "USA",
isMarried: true,
hobbies: ["reading", "traveling", "swimming"],
address: %{
street: "123 Main St",
city: "Los Angeles",
state: "CA",
zip: "90001"
},
phoneNumbers: [
%{
type: "home",
number: "555-555-1234"
},
%{
type: "work",
number: "555-555-5678"
}
],
favoriteColor: "blue"
})
)
|> Finch.request(ExVCRFinch)
)
end
end

test "put method" do
use_cassette "finch_put" do
assert_response Finch.build(:put, "http://httpbin.org/put", [], "test") |> Finch.request(ExVCRFinch, receive_timeout: 10_000)
assert_response(
Finch.build(:put, "http://httpbin.org/put", [], "test")
|> Finch.request(ExVCRFinch, receive_timeout: 10_000)
)
end
end

test "patch method" do
use_cassette "finch_patch" do
assert_response Finch.build(:patch, "http://httpbin.org/patch", [], "test") |> Finch.request(ExVCRFinch)
assert_response(
Finch.build(:patch, "http://httpbin.org/patch", [], "test")
|> Finch.request(ExVCRFinch)
)
end
end

test "delete method" do
use_cassette "finch_delete" do
assert_response Finch.build(:delete, "http://httpbin.org/delete") |> Finch.request(ExVCRFinch, receive_timeout: 10_000)
assert_response(
Finch.build(:delete, "http://httpbin.org/delete")
|> Finch.request(ExVCRFinch, receive_timeout: 10_000)
)
end
end

test "get fails with timeout" do
use_cassette "finch_get_timeout" do
{:error, error} = Finch.build(:get, "http://example.com") |> Finch.request(ExVCRFinch, receive_timeout: 1)
{:error, error} =
Finch.build(:get, "http://example.com") |> Finch.request(ExVCRFinch, receive_timeout: 1)

assert error == %Mint.TransportError{reason: :timeout}
end
end
Expand All @@ -128,13 +190,15 @@ defmodule ExVCR.Adapter.FinchTest do

use_cassette "example_finch_different" do
assert_raise ExVCR.RequestNotMatchError, ~r/different_from_original/, fn ->
{:ok, _response} = Finch.build(:get, "http://example.com/different_from_original") |> Finch.request(ExVCRFinch)
{:ok, _response} =
Finch.build(:get, "http://example.com/different_from_original")
|> Finch.request(ExVCRFinch)
end
end
end

test "stub request works for Finch" do
use_cassette :stub, [url: "http://example.com/", body: "Stub Response", status_code: 200] do
use_cassette :stub, url: "http://example.com/", body: "Stub Response", status_code: 200 do
{:ok, response} = Finch.build(:get, "http://example.com") |> Finch.request(ExVCRFinch)
assert response.body =~ ~r/Stub Response/
assert Map.new(response.headers)["content-type"] == "text/html"
Expand Down

0 comments on commit 0af120a

Please sign in to comment.