Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions lib/pigeon/fcm/error.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ defmodule Pigeon.FCM.Error do

@doc false
@spec parse(map) :: Notification.error_response()
def parse(%{"details" => [%{"errorCode" => error_code}]}),
def parse(%{"details" => details} = error), do: parse_details(details, error)
def parse(error), do: parse_status(error)

defp parse_details([%{"errorCode" => error_code} | _], _),
do: parse_response(error_code)

def parse(error) do
error
|> Map.get("status")
|> parse_response()
end
defp parse_details([_ | tail], error), do: parse_details(tail, error)
defp parse_details([], error), do: parse_status(error)

defp parse_status(%{"status" => status}), do: parse_response(status)
defp parse_status(_), do: :unknown_error

defp parse_response("INTERNAL"), do: :internal
defp parse_response("INVALID_ARGUMENT"), do: :invalid_argument
Expand Down
214 changes: 173 additions & 41 deletions test/pigeon/fcm/error_test.exs
Original file line number Diff line number Diff line change
@@ -1,51 +1,183 @@
defmodule Pigeon.FCM.ErrorTest do
use ExUnit.Case, async: true
alias Pigeon.FCM.Error

test "parse/1 handles error reasons via status" do
reasons = [
{"INTERNAL", :internal},
{"INVALID_ARGUMENT", :invalid_argument},
{"PERMISSION_DENIED", :permission_denied},
{"QUOTA_EXCEEDED", :quota_exceeded},
{"SENDER_ID_MISMATCH", :sender_id_mismatch},
{"THIRD_PARTY_AUTH_ERROR", :third_party_auth_error},
{"UNAVAILABLE", :unavailable},
{"UNREGISTERED", :unregistered},
{"UNSPECIFIED_ERROR", :unspecified_error}
]

for {actual, expected} <- reasons do
payload = %{"status" => actual}
assert Pigeon.FCM.Error.parse(payload) == expected
describe "parse/1" do
test "returns :unregistered when 'errorCode' is 'UNREGISTERED' in details" do
error = %{
"code" => 404,
"details" => [
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode" => "UNREGISTERED"
},
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.ApnsError",
"reason" => "Unregistered",
"statusCode" => 410
}
],
"message" => "Requested entity was not found.",
"status" => "NOT_FOUND"
}

assert Error.parse(error) == :unregistered
end
end

test "parse/1 handles error reasons via errorCode" do
reasons = [
{"INTERNAL", :internal},
{"INVALID_ARGUMENT", :invalid_argument},
{"PERMISSION_DENIED", :permission_denied},
{"QUOTA_EXCEEDED", :quota_exceeded},
{"SENDER_ID_MISMATCH", :sender_id_mismatch},
{"THIRD_PARTY_AUTH_ERROR", :third_party_auth_error},
{"UNAVAILABLE", :unavailable},
{"UNREGISTERED", :unregistered},
{"UNSPECIFIED_ERROR", :unspecified_error}
]

for {actual, expected} <- reasons do
payload = %{"details" => [%{"errorCode" => actual}]}
assert Pigeon.FCM.Error.parse(payload) == expected
test "returns :invalid_argument when 'errorCode' is 'INVALID_ARGUMENT' in details" do
error = %{
"code" => 400,
"details" => [
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode" => "INVALID_ARGUMENT"
}
],
"message" => "Bad request.",
"status" => "NOT_FOUND"
}

assert Error.parse(error) == :invalid_argument
end
end

test "parse/1 handles unknown error reasons via status" do
payload = %{"status" => "UNKNOWN_ERROR_CODE"}
assert Pigeon.FCM.Error.parse(payload) == :unknown_error
end
test "returns :unknown_error when 'errorCode' is not found in details and 'status' is missing" do
error = %{
"code" => 500,
"details" => [
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"reason" => "Unknown"
}
],
"message" => "Internal server error."
}

assert Error.parse(error) == :unknown_error
end

test "returns :quota_exceeded when 'errorCode' is 'QUOTA_EXCEEDED'" do
error = %{
"code" => 429,
"details" => [
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode" => "QUOTA_EXCEEDED"
}
],
"message" => "Quota exceeded.",
"status" => "NOT_FOUND"
}

assert Error.parse(error) == :quota_exceeded
end

test "returns :unavailable when 'errorCode' is 'UNAVAILABLE'" do
error = %{
"code" => 503,
"details" => [
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode" => "UNAVAILABLE"
}
],
"message" => "Service unavailable.",
"status" => "NOT_FOUND"
}

assert Error.parse(error) == :unavailable
end

test "returns :internal when 'errorCode' is 'INTERNAL'" do
error = %{
"code" => 500,
"details" => [
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode" => "INTERNAL"
}
],
"message" => "Internal server error.",
"status" => "NOT_FOUND"
}

assert Error.parse(error) == :internal
end

test "returns :third_party_auth_error when 'errorCode' is 'THIRD_PARTY_AUTH_ERROR'" do
error = %{
"code" => 401,
"details" => [
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode" => "THIRD_PARTY_AUTH_ERROR"
}
],
"message" => "Third-party authentication error.",
"status" => "NOT_FOUND"
}

test "parse/1 handles unknown error reasons via errorCode" do
payload = %{"details" => [%{"errorCode" => "UNKNOWN_ERROR_CODE"}]}
assert Pigeon.FCM.Error.parse(payload) == :unknown_error
assert Error.parse(error) == :third_party_auth_error
end

test "returns :permission_denied when 'errorCode' is 'PERMISSION_DENIED'" do
error = %{
"code" => 403,
"details" => [
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode" => "PERMISSION_DENIED"
}
],
"message" => "Permission denied.",
"status" => "NOT_FOUND"
}

assert Error.parse(error) == :permission_denied
end

test "returns :unknown_error when 'errorCode' is unknown in details" do
error = %{
"code" => 400,
"details" => [
%{
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
"errorCode" => "UNKNOWN_ERROR"
}
],
"message" => "Unknown error.",
"status" => "NOT_FOUND"
}

assert Error.parse(error) == :unknown_error
end

test "returns :invalid_argument when 'status' is 'INVALID_ARGUMENT'" do
error = %{
"code" => 400,
"status" => "INVALID_ARGUMENT",
"message" => "Bad request."
}

assert Error.parse(error) == :invalid_argument
end

test "returns :unknown_error when 'status' is not found" do
error = %{
"code" => 500,
"message" => "Unknown error."
}

assert Error.parse(error) == :unknown_error
end

test "returns :unknown_error when 'status' is unknown" do
error = %{
"code" => 500,
"status" => "UNKNOWN_STATUS",
"message" => "Unknown status error."
}

assert Error.parse(error) == :unknown_error
end
end
end
Loading