Skip to content

Commit c19f5b0

Browse files
committed
fix(FCM.Error): implement recursive parsing for handling multiple elements in "details"
Refactored the `parse/1` function to use recursion for correctly handling cases where the "details" list contains multiple elements, and falling back to the "status" field when necessary.
1 parent f4bd7a9 commit c19f5b0

2 files changed

Lines changed: 192 additions & 6 deletions

File tree

lib/pigeon/fcm/error.ex

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ defmodule Pigeon.FCM.Error do
55

66
@doc false
77
@spec parse(map) :: Notification.error_response()
8-
def parse(%{"details" => [%{"errorCode" => error_code}]}),
8+
def parse(%{"details" => details} = error), do: parse_details(details, error)
9+
def parse(error), do: parse_status(error)
10+
11+
defp parse_details([%{"errorCode" => error_code} | _], _),
912
do: parse_response(error_code)
1013

11-
def parse(error) do
12-
error
13-
|> Map.get("status")
14-
|> parse_response()
15-
end
14+
defp parse_details([_ | tail], error), do: parse_details(tail, error)
15+
defp parse_details([], error), do: parse_status(error)
16+
17+
defp parse_status(%{"status" => status}), do: parse_response(status)
18+
defp parse_status(_), do: :unknown_error
1619

1720
defp parse_response("UNSPECIFIED_ERROR"), do: :unspecified_error
1821
defp parse_response("INVALID_ARGUMENT"), do: :invalid_argument

test/pigeon/fcm/error_test.exs

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
defmodule Pigeon.FCM.ErrorTest do
2+
use ExUnit.Case, async: true
3+
alias Pigeon.FCM.Error
4+
5+
describe "parse/1" do
6+
test "returns :unregistered when 'errorCode' is 'UNREGISTERED' in details" do
7+
error = %{
8+
"code" => 404,
9+
"details" => [
10+
%{
11+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
12+
"errorCode" => "UNREGISTERED"
13+
},
14+
%{
15+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.ApnsError",
16+
"reason" => "Unregistered",
17+
"statusCode" => 410
18+
}
19+
],
20+
"message" => "Requested entity was not found.",
21+
"status" => "NOT_FOUND"
22+
}
23+
24+
assert Error.parse(error) == :unregistered
25+
end
26+
27+
test "returns :invalid_argument when 'errorCode' is 'INVALID_ARGUMENT' in details" do
28+
error = %{
29+
"code" => 400,
30+
"details" => [
31+
%{
32+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
33+
"errorCode" => "INVALID_ARGUMENT"
34+
}
35+
],
36+
"message" => "Bad request.",
37+
"status" => "NOT_FOUND"
38+
}
39+
40+
assert Error.parse(error) == :invalid_argument
41+
end
42+
43+
test "returns :unknown_error when 'errorCode' is not found in details and 'status' is missing" do
44+
error = %{
45+
"code" => 500,
46+
"details" => [
47+
%{
48+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
49+
"reason" => "Unknown"
50+
}
51+
],
52+
"message" => "Internal server error."
53+
}
54+
55+
assert Error.parse(error) == :unknown_error
56+
end
57+
58+
test "returns :quota_exceeded when 'errorCode' is 'QUOTA_EXCEEDED'" do
59+
error = %{
60+
"code" => 429,
61+
"details" => [
62+
%{
63+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
64+
"errorCode" => "QUOTA_EXCEEDED"
65+
}
66+
],
67+
"message" => "Quota exceeded.",
68+
"status" => "NOT_FOUND"
69+
}
70+
71+
assert Error.parse(error) == :quota_exceeded
72+
end
73+
74+
test "returns :unavailable when 'errorCode' is 'UNAVAILABLE'" do
75+
error = %{
76+
"code" => 503,
77+
"details" => [
78+
%{
79+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
80+
"errorCode" => "UNAVAILABLE"
81+
}
82+
],
83+
"message" => "Service unavailable.",
84+
"status" => "NOT_FOUND"
85+
}
86+
87+
assert Error.parse(error) == :unavailable
88+
end
89+
90+
test "returns :internal when 'errorCode' is 'INTERNAL'" do
91+
error = %{
92+
"code" => 500,
93+
"details" => [
94+
%{
95+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
96+
"errorCode" => "INTERNAL"
97+
}
98+
],
99+
"message" => "Internal server error.",
100+
"status" => "NOT_FOUND"
101+
}
102+
103+
assert Error.parse(error) == :internal
104+
end
105+
106+
test "returns :third_party_auth_error when 'errorCode' is 'THIRD_PARTY_AUTH_ERROR'" do
107+
error = %{
108+
"code" => 401,
109+
"details" => [
110+
%{
111+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
112+
"errorCode" => "THIRD_PARTY_AUTH_ERROR"
113+
}
114+
],
115+
"message" => "Third-party authentication error.",
116+
"status" => "NOT_FOUND"
117+
}
118+
119+
assert Error.parse(error) == :third_party_auth_error
120+
end
121+
122+
test "returns :permission_denied when 'errorCode' is 'PERMISSION_DENIED'" do
123+
error = %{
124+
"code" => 403,
125+
"details" => [
126+
%{
127+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
128+
"errorCode" => "PERMISSION_DENIED"
129+
}
130+
],
131+
"message" => "Permission denied.",
132+
"status" => "NOT_FOUND"
133+
}
134+
135+
assert Error.parse(error) == :permission_denied
136+
end
137+
138+
test "returns :unknown_error when 'errorCode' is unknown in details" do
139+
error = %{
140+
"code" => 400,
141+
"details" => [
142+
%{
143+
"@type" => "type.googleapis.com/google.firebase.fcm.v1.FcmError",
144+
"errorCode" => "UNKNOWN_ERROR"
145+
}
146+
],
147+
"message" => "Unknown error.",
148+
"status" => "NOT_FOUND"
149+
}
150+
151+
assert Error.parse(error) == :unknown_error
152+
end
153+
154+
test "returns :invalid_argument when 'status' is 'INVALID_ARGUMENT'" do
155+
error = %{
156+
"code" => 400,
157+
"status" => "INVALID_ARGUMENT",
158+
"message" => "Bad request."
159+
}
160+
161+
assert Error.parse(error) == :invalid_argument
162+
end
163+
164+
test "returns :unknown_error when 'status' is not found" do
165+
error = %{
166+
"code" => 500,
167+
"message" => "Unknown error."
168+
}
169+
170+
assert Error.parse(error) == :unknown_error
171+
end
172+
173+
test "returns :unknown_error when 'status' is unknown" do
174+
error = %{
175+
"code" => 500,
176+
"status" => "UNKNOWN_STATUS",
177+
"message" => "Unknown status error."
178+
}
179+
180+
assert Error.parse(error) == :unknown_error
181+
end
182+
end
183+
end

0 commit comments

Comments
 (0)