2024-09-10 20:27:09 +02:00
|
|
|
|
// Copyright 2024 Google LLC
|
|
|
|
|
|
//
|
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
|
//
|
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
//
|
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
|
|
@testable import FirebaseFunctions
|
|
|
|
|
|
|
|
|
|
|
|
import XCTest
|
|
|
|
|
|
|
|
|
|
|
|
final class FunctionsErrorTests: XCTestCase {
|
|
|
|
|
|
func testInitWithCode() {
|
|
|
|
|
|
let error = FunctionsError(.permissionDenied)
|
|
|
|
|
|
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
XCTAssertEqual(nsError.domain, "com.firebase.functions")
|
|
|
|
|
|
XCTAssertEqual(nsError.code, 7)
|
|
|
|
|
|
XCTAssertEqual(nsError.localizedDescription, "PERMISSION DENIED")
|
|
|
|
|
|
XCTAssertEqual(nsError.userInfo.count, 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func testInitWithCodeAndUserInfo() {
|
|
|
|
|
|
let error = FunctionsError(.unimplemented, userInfo: ["TEST_Key": "TEST_Value"])
|
|
|
|
|
|
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
XCTAssertEqual(nsError.domain, "com.firebase.functions")
|
|
|
|
|
|
XCTAssertEqual(nsError.code, 12)
|
|
|
|
|
|
XCTAssertEqual(
|
|
|
|
|
|
nsError.localizedDescription,
|
|
|
|
|
|
"The operation couldn’t be completed. (com.firebase.functions error 12.)"
|
|
|
|
|
|
)
|
|
|
|
|
|
XCTAssertEqual(nsError.userInfo.count, 1)
|
|
|
|
|
|
XCTAssertEqual(nsError.userInfo["TEST_Key"] as? String, "TEST_Value")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func testInitWithOKStatusCodeAndNoErrorBody() {
|
|
|
|
|
|
// The error should be `nil`.
|
|
|
|
|
|
let error = FunctionsError(
|
|
|
|
|
|
httpStatusCode: 200,
|
2025-03-03 20:53:39 +04:00
|
|
|
|
region: "my-region",
|
|
|
|
|
|
url: URL(string: "https://example.com/fake_func")!,
|
2024-09-10 20:27:09 +02:00
|
|
|
|
body: nil,
|
|
|
|
|
|
serializer: FunctionsSerializer()
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
XCTAssertNil(error)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func testInitWithErrorStatusCodeAndNoErrorBody() {
|
|
|
|
|
|
// The error should be inferred from the HTTP status code.
|
|
|
|
|
|
let error = FunctionsError(
|
|
|
|
|
|
httpStatusCode: 429,
|
2025-03-03 20:53:39 +04:00
|
|
|
|
region: "my-region",
|
|
|
|
|
|
url: URL(string: "https://example.com/fake_func")!,
|
2024-09-10 20:27:09 +02:00
|
|
|
|
body: nil,
|
|
|
|
|
|
serializer: FunctionsSerializer()
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
guard let error else { return XCTFail("Unexpected `nil` value") }
|
|
|
|
|
|
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
XCTAssertEqual(nsError.domain, "com.firebase.functions")
|
|
|
|
|
|
XCTAssertEqual(nsError.code, 8)
|
|
|
|
|
|
XCTAssertEqual(nsError.localizedDescription, "RESOURCE EXHAUSTED")
|
2025-03-03 20:53:39 +04:00
|
|
|
|
XCTAssertEqual(nsError.userInfo.count, 3)
|
2024-09-10 20:27:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func testInitWithOKStatusCodeAndIncompleteErrorBody() {
|
|
|
|
|
|
// The status code in the error body takes precedence over the HTTP status code.
|
|
|
|
|
|
let responseData = #"{ "error": { "status": "OUT_OF_RANGE" } }"#.data(using: .utf8)!
|
|
|
|
|
|
|
|
|
|
|
|
let error = FunctionsError(
|
|
|
|
|
|
httpStatusCode: 200,
|
2025-03-03 20:53:39 +04:00
|
|
|
|
region: "my-region",
|
|
|
|
|
|
url: URL(string: "https://example.com/fake_func")!,
|
2024-09-10 20:27:09 +02:00
|
|
|
|
body: responseData,
|
|
|
|
|
|
serializer: FunctionsSerializer()
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
guard let error else { return XCTFail("Unexpected `nil` value") }
|
|
|
|
|
|
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
XCTAssertEqual(nsError.domain, "com.firebase.functions")
|
|
|
|
|
|
XCTAssertEqual(nsError.code, 11)
|
|
|
|
|
|
XCTAssertEqual(nsError.localizedDescription, "OUT OF RANGE")
|
2025-03-03 20:53:39 +04:00
|
|
|
|
XCTAssertEqual(nsError.userInfo.count, 3)
|
2024-09-10 20:27:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func testInitWithErrorStatusCodeAndErrorBody() {
|
|
|
|
|
|
// The status code in the error body takes precedence over the HTTP status code.
|
|
|
|
|
|
let responseData =
|
|
|
|
|
|
#"{ "error": { "status": "OUT_OF_RANGE", "message": "TEST_ErrorMessage", "details": 123 } }"#
|
|
|
|
|
|
.data(using: .utf8)!
|
|
|
|
|
|
|
|
|
|
|
|
let error = FunctionsError(
|
|
|
|
|
|
httpStatusCode: 499,
|
2025-03-03 20:53:39 +04:00
|
|
|
|
region: "my-region",
|
|
|
|
|
|
url: URL(string: "https://example.com/fake_func")!,
|
2024-09-10 20:27:09 +02:00
|
|
|
|
body: responseData,
|
|
|
|
|
|
serializer: FunctionsSerializer()
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
guard let error else { return XCTFail("Unexpected `nil` value") }
|
|
|
|
|
|
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
XCTAssertEqual(nsError.domain, "com.firebase.functions")
|
|
|
|
|
|
XCTAssertEqual(nsError.code, 11)
|
|
|
|
|
|
XCTAssertEqual(nsError.localizedDescription, "TEST_ErrorMessage")
|
2025-03-03 20:53:39 +04:00
|
|
|
|
XCTAssertEqual(nsError.userInfo.count, 4)
|
2024-09-10 20:27:09 +02:00
|
|
|
|
XCTAssertEqual(nsError.userInfo["details"] as? Int, 123)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func testInitWithErrorStatusCodeAndOKErrorBody() {
|
|
|
|
|
|
// When the status code in the error body is `OK`, error should be `nil` regardless of the HTTP
|
|
|
|
|
|
// status code.
|
|
|
|
|
|
let responseData =
|
|
|
|
|
|
#"{ "error": { "status": "OK", "message": "TEST_ErrorMessage", "details": 123 } }"#
|
|
|
|
|
|
.data(using: .utf8)!
|
|
|
|
|
|
|
|
|
|
|
|
let error = FunctionsError(
|
|
|
|
|
|
httpStatusCode: 401,
|
2025-03-03 20:53:39 +04:00
|
|
|
|
region: "my-region",
|
|
|
|
|
|
url: URL(string: "https://example.com/fake_func")!,
|
2024-09-10 20:27:09 +02:00
|
|
|
|
body: responseData,
|
|
|
|
|
|
serializer: FunctionsSerializer()
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
XCTAssertNil(error)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func testInitWithErrorStatusCodeAndIncompleteErrorBody() {
|
|
|
|
|
|
// The error name is not in the body; it should be inferred from the HTTP status code.
|
|
|
|
|
|
let responseData = #"{ "error": { "message": "TEST_ErrorMessage", "details": null } }"#
|
|
|
|
|
|
.data(using: .utf8)!
|
|
|
|
|
|
|
|
|
|
|
|
let error = FunctionsError(
|
|
|
|
|
|
httpStatusCode: 403,
|
2025-03-03 20:53:39 +04:00
|
|
|
|
region: "my-region",
|
|
|
|
|
|
url: URL(string: "https://example.com/fake_func")!,
|
2024-09-10 20:27:09 +02:00
|
|
|
|
body: responseData,
|
|
|
|
|
|
serializer: FunctionsSerializer()
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
guard let error else { return XCTFail("Unexpected `nil` value") }
|
|
|
|
|
|
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
XCTAssertEqual(nsError.domain, "com.firebase.functions")
|
|
|
|
|
|
XCTAssertEqual(nsError.code, 7) // `permissionDenied`, inferred from the HTTP status code
|
|
|
|
|
|
XCTAssertEqual(nsError.localizedDescription, "TEST_ErrorMessage")
|
2025-03-03 20:53:39 +04:00
|
|
|
|
XCTAssertEqual(nsError.userInfo.count, 4)
|
2024-09-10 20:27:09 +02:00
|
|
|
|
XCTAssertEqual(nsError.userInfo["details"] as? NSNull, NSNull())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func testInitWithErrorStatusCodeAndInvalidErrorBody() {
|
|
|
|
|
|
// An unsupported status code in the error body should result in the rest of the body ignored.
|
|
|
|
|
|
let responseData =
|
|
|
|
|
|
#"{ "error": { "status": "TEST_UNKNOWN_ERROR", "message": "TEST_ErrorMessage", "details": 123 } }"#
|
|
|
|
|
|
.data(using: .utf8)!
|
|
|
|
|
|
|
|
|
|
|
|
let error = FunctionsError(
|
|
|
|
|
|
httpStatusCode: 503,
|
2025-03-03 20:53:39 +04:00
|
|
|
|
region: "my-region",
|
|
|
|
|
|
url: URL(string: "https://example.com/fake_func")!,
|
2024-09-10 20:27:09 +02:00
|
|
|
|
body: responseData,
|
|
|
|
|
|
serializer: FunctionsSerializer()
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
guard let error else { return XCTFail("Unexpected `nil` value") }
|
|
|
|
|
|
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
XCTAssertEqual(nsError.domain, "com.firebase.functions")
|
|
|
|
|
|
// Currently, `internal` is used as the fallback error code. Is this correct?
|
|
|
|
|
|
// Seems like we could get more information from the HTTP status code in such cases.
|
|
|
|
|
|
XCTAssertEqual(nsError.code, 13)
|
|
|
|
|
|
XCTAssertEqual(nsError.localizedDescription, "INTERNAL")
|
|
|
|
|
|
XCTAssertEqual(nsError.userInfo.count, 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|