diff --git a/Sources/App/Core/Dependencies/LoggerClient.swift b/Sources/App/Core/Dependencies/LoggerClient.swift index b5cd45b59..0ce0ddbcd 100644 --- a/Sources/App/Core/Dependencies/LoggerClient.swift +++ b/Sources/App/Core/Dependencies/LoggerClient.swift @@ -39,6 +39,18 @@ extension LoggerClient { } +#if DEBUG +extension LoggerClient { + func set(to handler: LogHandler?) { + if let handler { + let logger = Logger(label: "test", factory: { _ in handler }) + set(to: logger) + } + } +} +#endif + + extension LoggerClient: DependencyKey { static var liveValue: Self { .init( diff --git a/Tests/AppTests/AppTestCase.swift b/Tests/AppTests/AppTestCase.swift index 5d61b3b4f..c45b81222 100644 --- a/Tests/AppTests/AppTestCase.swift +++ b/Tests/AppTests/AppTestCase.swift @@ -30,7 +30,7 @@ class AppTestCase: XCTestCase { app = try await setup(.testing) @Dependency(\.logger) var logger - logger.set(to: .init(label: "test", factory: { _ in self.logger })) + logger.set(to: self.logger) } func setup(_ environment: Environment) async throws -> Application { diff --git a/Tests/AppTests/GithubTests.swift b/Tests/AppTests/GithubTests.swift index 3d91a21e6..0a17bf269 100644 --- a/Tests/AppTests/GithubTests.swift +++ b/Tests/AppTests/GithubTests.swift @@ -12,40 +12,40 @@ // See the License for the specific language governing permissions and // limitations under the License. -import XCTest - @testable import App import Dependencies +import Logging import S3Store import SwiftSoup +import Testing import Vapor -class GithubTests: AppTestCase { +@Suite struct GithubTests { - func test_parseOwnerName() throws { + @Test func parseOwnerName() throws { do { let res = try Github.parseOwnerName(url: "https://github.com/foo/bar") - XCTAssertEqual(res.owner, "foo") - XCTAssertEqual(res.name, "bar") + #expect(res.owner == "foo") + #expect(res.name == "bar") } do { let res = try Github.parseOwnerName(url: "https://github.com/foo/bar.git") - XCTAssertEqual(res.owner, "foo") - XCTAssertEqual(res.name, "bar") + #expect(res.owner == "foo") + #expect(res.name == "bar") } do { _ = try Github.parseOwnerName(url: "https://github.com/foo/bar/baz") - XCTFail("Expected error") + Issue.record("Expected error") } catch let Github.Error.invalidURL(url) { - XCTAssertEqual(url, "https://github.com/foo/bar/baz") + #expect(url == "https://github.com/foo/bar/baz") } catch { - XCTFail("Unexpected error: \(error)") + Issue.record("Unexpected error: \(error)") } } - func test_decode_Metadata_null() throws { + @Test func decode_Metadata_null() throws { // Ensure missing values don't trip up decoding struct Response: Decodable { var data: Github.Metadata @@ -102,7 +102,7 @@ class GithubTests: AppTestCase { } } - func test_fetchResource() async throws { + @Test func fetchResource() async throws { struct Response: Decodable, Equatable { var data: Data struct Data: Decodable, Equatable { @@ -121,11 +121,11 @@ class GithubTests: AppTestCase { } } operation: { let res = try await Github.fetchResource(Response.self, query: q) - XCTAssertEqual(res, Response(data: .init(viewer: .init(login: "finestructure")))) + #expect(res == Response(data: .init(viewer: .init(login: "finestructure")))) } } - func test_fetchMetadata() async throws { + @Test func fetchMetadata() async throws { let iso8601 = ISO8601DateFormatter() try await withDependencies { @@ -139,25 +139,22 @@ class GithubTests: AppTestCase { repository: "alamofire") // validation - XCTAssertEqual(res.repository?.closedIssues.nodes.first!.closedAt, - iso8601.date(from: "2020-07-17T16:27:10Z")) - XCTAssertEqual(res.repository?.closedPullRequests.nodes.first!.closedAt, - iso8601.date(from: "2021-05-28T15:50:17Z")) - XCTAssertEqual(res.repository?.forkCount, 6727) - XCTAssertEqual(res.repository?.fundingLinks, [ + #expect(res.repository?.closedIssues.nodes.first!.closedAt == iso8601.date(from: "2020-07-17T16:27:10Z")) + #expect(res.repository?.closedPullRequests.nodes.first!.closedAt == iso8601.date(from: "2021-05-28T15:50:17Z")) + #expect(res.repository?.forkCount == 6727) + #expect(res.repository?.fundingLinks == [ .init(platform: .gitHub, url: "https://github.com/Alamofire"), .init(platform: .lfxCrowdfunding, url: "https://crowdfunding.lfx.linuxfoundation.org/projects/alamofire"), ]) - XCTAssertEqual(res.repository?.mergedPullRequests.nodes.first!.closedAt, - iso8601.date(from: "2021-06-07T22:47:01Z")) - XCTAssertEqual(res.repository?.name, "Alamofire") - XCTAssertEqual(res.repository?.owner.name, "Alamofire") - XCTAssertEqual(res.repository?.owner.login, "Alamofire") - XCTAssertEqual(res.repository?.owner.avatarUrl, "https://avatars.githubusercontent.com/u/7774181?v=4") - XCTAssertEqual(res.repository?.openIssues.totalCount, 30) - XCTAssertEqual(res.repository?.openPullRequests.totalCount, 6) - XCTAssertEqual(res.repository?.releases.nodes.count, 20) - XCTAssertEqual(res.repository?.releases.nodes.first, .some( + #expect(res.repository?.mergedPullRequests.nodes.first!.closedAt == iso8601.date(from: "2021-06-07T22:47:01Z")) + #expect(res.repository?.name == "Alamofire") + #expect(res.repository?.owner.name == "Alamofire") + #expect(res.repository?.owner.login == "Alamofire") + #expect(res.repository?.owner.avatarUrl == "https://avatars.githubusercontent.com/u/7774181?v=4") + #expect(res.repository?.openIssues.totalCount == 30) + #expect(res.repository?.openPullRequests.totalCount == 6) + #expect(res.repository?.releases.nodes.count == 20) + #expect(res.repository?.releases.nodes.first == .some( .init(description: "Released on 2020-04-21. All issues associated with this milestone can be found using this [filter](https://github.com/Alamofire/Alamofire/milestone/77?closed=1).\r\n\r\n#### Fixed\r\n- Change in multipart upload creation order.\r\n - Fixed by [Christian Noon](https://github.com/cnoon) in Pull Request [#3438](https://github.com/Alamofire/Alamofire/pull/3438).\r\n- Typo in Alamofire 5 migration guide.\r\n - Fixed by [DevYeom](https://github.com/DevYeom) in Pull Request [#3431](https://github.com/Alamofire/Alamofire/pull/3431).", descriptionHTML: "
mock descriptionHTML>",
isDraft: false,
@@ -165,22 +162,19 @@ class GithubTests: AppTestCase {
tagName: "5.4.3",
url: "https://github.com/Alamofire/Alamofire/releases/tag/5.4.3")
))
- XCTAssertEqual(res.repository?.repositoryTopics.totalCount, 15)
- XCTAssertEqual(res.repository?.repositoryTopics.nodes.first?.topic.name,
- "networking")
- XCTAssertEqual(res.repository?.stargazerCount, 35831)
- XCTAssertEqual(res.repository?.isInOrganization, true)
- XCTAssertEqual(res.repository?.homepageUrl, "https://swiftpackageindex.com/Alamofire/Alamofire")
+ #expect(res.repository?.repositoryTopics.totalCount == 15)
+ #expect(res.repository?.repositoryTopics.nodes.first?.topic.name == "networking")
+ #expect(res.repository?.stargazerCount == 35831)
+ #expect(res.repository?.isInOrganization == true)
+ #expect(res.repository?.homepageUrl == "https://swiftpackageindex.com/Alamofire/Alamofire")
// derived properties
- XCTAssertEqual(res.repository?.lastIssueClosedAt,
- iso8601.date(from: "2021-06-09T00:59:39Z"))
+ #expect(res.repository?.lastIssueClosedAt == iso8601.date(from: "2021-06-09T00:59:39Z"))
// merged date is latest - expect that one to be reported back
- XCTAssertEqual(res.repository?.lastPullRequestClosedAt,
- iso8601.date(from: "2021-06-07T22:47:01Z"))
+ #expect(res.repository?.lastPullRequestClosedAt == iso8601.date(from: "2021-06-07T22:47:01Z"))
}
}
- func test_fetchMetadata_badRequest() async throws {
+ @Test func fetchMetadata_badRequest() async throws {
await withDependencies {
$0.github.token = { "secr3t" }
$0.httpClient.post = { @Sendable _, _, _ in .badRequest }
@@ -188,17 +182,17 @@ class GithubTests: AppTestCase {
do {
_ = try await Github.fetchMetadata(owner: "alamofire",
repository: "alamofire")
- XCTFail("expected error to be thrown")
+ Issue.record("expected error to be thrown")
} catch {
guard case Github.Error.requestFailed(.badRequest) = error else {
- XCTFail("unexpected error: \(error.localizedDescription)")
+ Issue.record("unexpected error: \(error.localizedDescription)")
return
}
}
}
}
- func test_fetchMetadata_badData() async throws {
+ @Test func fetchMetadata_badData() async throws {
await withDependencies {
$0.github.token = { "secr3t" }
$0.httpClient.post = { @Sendable _, _, _ in .ok(body: "bad data") }
@@ -206,21 +200,21 @@ class GithubTests: AppTestCase {
// MUT
do {
_ = try await Github.fetchMetadata(owner: "foo", repository: "bar")
- XCTFail("expected error to be thrown")
+ Issue.record("expected error to be thrown")
} catch let Github.Error.decodeContentFailed(uri, error) {
// validation
- XCTAssertEqual(uri, "https://api.github.com/graphql")
+ #expect(uri == "https://api.github.com/graphql")
guard case DecodingError.dataCorrupted = error else {
- XCTFail("unexpected error: \(error.localizedDescription)")
+ Issue.record("unexpected error: \(error.localizedDescription)")
return
}
} catch {
- XCTFail("Unexpected error: \(error)")
+ Issue.record("Unexpected error: \(error)")
}
}
}
- func test_fetchMetadata_rateLimiting_429() async throws {
+ @Test func fetchMetadata_rateLimiting_429() async throws {
// Github doesn't actually send a 429 when you hit the rate limit
await withDependencies {
$0.github.token = { "secr3t" }
@@ -229,83 +223,83 @@ class GithubTests: AppTestCase {
// MUT
do {
_ = try await Github.fetchMetadata(owner: "foo", repository: "bar")
- XCTFail("expected error to be thrown")
+ Issue.record("expected error to be thrown")
} catch {
// validation
guard case Github.Error.requestFailed(.tooManyRequests) = error else {
- XCTFail("unexpected error: \(error.localizedDescription)")
+ Issue.record("unexpected error: \(error.localizedDescription)")
return
}
}
}
}
- func test_isRateLimited() throws {
+ @Test func isRateLimited() throws {
do {
let res = HTTPClient.Response(status: .forbidden,
headers: .init([("X-RateLimit-Remaining", "0")]))
- XCTAssertTrue(Github.isRateLimited(res))
+ #expect(Github.isRateLimited(res))
}
do {
let res = HTTPClient.Response(status: .forbidden,
headers: .init([("x-ratelimit-remaining", "0")]))
- XCTAssertTrue(Github.isRateLimited(res))
+ #expect(Github.isRateLimited(res))
}
do {
let res = HTTPClient.Response(status: .forbidden,
headers: .init([("X-RateLimit-Remaining", "1")]))
- XCTAssertFalse(Github.isRateLimited(res))
+ #expect(!Github.isRateLimited(res))
}
do {
let res = HTTPClient.Response(status: .forbidden,
headers: .init([("unrelated", "0")]))
- XCTAssertFalse(Github.isRateLimited(res))
+ #expect(!Github.isRateLimited(res))
}
do {
let res = HTTPClient.Response(status: .ok,
headers: .init([("X-RateLimit-Remaining", "0")]))
- XCTAssertFalse(Github.isRateLimited(res))
+ #expect(!Github.isRateLimited(res))
}
}
- func test_fetchMetadata_rateLimiting_403() async throws {
+ @Test func fetchMetadata_rateLimiting_403() async throws {
// Github sends a 403 and a rate limit remaining header
// X-RateLimit-Limit: 60
// X-RateLimit-Remaining: 56
- // Ensure we record it as a rate limit error and raise a Rollbar item
+ // Ensure we record it as a rate limit error
+ let capturingLogger = CapturingLogger()
await withDependencies {
$0.github.token = { "secr3t" }
$0.httpClient.post = { @Sendable _, _, _ in
.init(status: .forbidden, headers: ["X-RateLimit-Remaining": "0"])
}
+ $0.logger.set(to: capturingLogger)
} operation: {
// MUT
do {
_ = try await Github.fetchMetadata(owner: "foo", repository: "bar")
- XCTFail("expected error to be thrown")
+ Issue.record("expected error to be thrown")
} catch {
// validation
- logger.logs.withValue { logs in
- XCTAssertEqual(logs, [
+ capturingLogger.logs.withValue { logs in
+ #expect(logs == [
.init(level: .critical, message: "rate limited while fetching resource Response