diff --git a/Sources/App/Core/AppEnvironment.swift b/Sources/App/Core/AppEnvironment.swift index d414cd385..ddae1d52d 100644 --- a/Sources/App/Core/AppEnvironment.swift +++ b/Sources/App/Core/AppEnvironment.swift @@ -23,8 +23,6 @@ import FoundationNetworking struct AppEnvironment: Sendable { - var currentReferenceCache: @Sendable () -> CurrentReferenceCache? - var dbId: @Sendable () -> String? var fetchDocumentation: @Sendable (_ client: Client, _ url: URI) async throws -> ClientResponse var fetchHTTPStatusCode: @Sendable (_ url: String) async throws -> HTTPStatus var fetchLicense: @Sendable (_ client: Client, _ owner: String, _ repository: String) async -> Github.License? @@ -87,8 +85,6 @@ extension AppEnvironment { nonisolated(unsafe) static var logger: Logger! static let live = AppEnvironment( - currentReferenceCache: { .live }, - dbId: { Environment.get("DATABASE_ID") }, fetchDocumentation: { client, url in try await client.get(url) }, fetchHTTPStatusCode: { url in try await Networking.fetchHTTPStatusCode(url) }, fetchLicense: { client, owner, repo in await Github.fetchLicense(client:client, owner: owner, repository: repo) }, diff --git a/Sources/App/Core/Dependencies/EnvironmentClient.swift b/Sources/App/Core/Dependencies/EnvironmentClient.swift index 31bb9f9f2..b3da31ab7 100644 --- a/Sources/App/Core/Dependencies/EnvironmentClient.swift +++ b/Sources/App/Core/Dependencies/EnvironmentClient.swift @@ -39,6 +39,8 @@ struct EnvironmentClient { var collectionSigningCertificateChain: @Sendable () -> [URL] = { XCTFail("collectionSigningCertificateChain"); return [] } var collectionSigningPrivateKey: @Sendable () -> Data? var current: @Sendable () -> Environment = { XCTFail("current"); return .development } + var currentReferenceCache: @Sendable () -> CurrentReferenceCache? + var dbId: @Sendable () -> String? var mastodonCredentials: @Sendable () -> Mastodon.Credentials? var mastodonPost: @Sendable (_ client: Client, _ post: String) async throws -> Void var random: @Sendable (_ range: ClosedRange) -> Double = { XCTFail("random"); return Double.random(in: $0) } @@ -91,6 +93,8 @@ extension EnvironmentClient: DependencyKey { Environment.get("COLLECTION_SIGNING_PRIVATE_KEY").map { Data($0.utf8) } }, current: { (try? Environment.detect()) ?? .development }, + currentReferenceCache: { .live }, + dbId: { Environment.get("DATABASE_ID") }, mastodonCredentials: { Environment.get("MASTODON_ACCESS_TOKEN") .map(Mastodon.Credentials.init(accessToken:)) diff --git a/Sources/App/Views/PublicPage.swift b/Sources/App/Views/PublicPage.swift index b69c142ff..47d5a9a32 100644 --- a/Sources/App/Views/PublicPage.swift +++ b/Sources/App/Views/PublicPage.swift @@ -34,7 +34,7 @@ class PublicPage { return HTML( .lang(.english), .comment("Version: \(environment.appVersion())"), - .comment("DB Id: \(Current.dbId())"), + .comment("DB Id: \(environment.dbId())"), head(), body() ) diff --git a/Sources/App/routes+documentation.swift b/Sources/App/routes+documentation.swift index 1576957ad..58f571276 100644 --- a/Sources/App/routes+documentation.swift +++ b/Sources/App/routes+documentation.swift @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. - +import Dependencies import Vapor @@ -124,7 +124,7 @@ private extension Parameters { } } } - + struct DocRedirect { var owner: String @@ -152,7 +152,7 @@ extension Request { target = try await DocumentationTarget.query(on: db, owner: owner, repository: repository, docVersion: .reference(ref)) } - + case .none: target = try await DocumentationTarget.query(on: db, owner: owner, repository: repository) } @@ -160,7 +160,7 @@ extension Request { return .init(owner: owner, repository: repository, target: target, path: path) } - + func getDocRoute(fragment: DocRoute.Fragment) async throws -> DocRoute { guard let owner = parameters.get("owner"), let repository = parameters.get("repository"), @@ -170,16 +170,18 @@ extension Request { if fragment.requiresArchive && archive == nil { throw Abort(.badRequest) } let pathElements = parameters.pathElements(for: fragment, archive: archive) + @Dependency(\.environment) var environment + let docVersion = try await { () -> DocVersion in if reference == String.current { - if let ref = Current.currentReferenceCache()?[owner: owner, repository: repository] { + if let ref = environment.currentReferenceCache()?[owner: owner, repository: repository] { return .current(referencing: ref) } guard let params = try await DocumentationTarget.query(on: db, owner: owner, repository: repository)?.internal else { throw Abort(.notFound) } - Current.currentReferenceCache()?[owner: owner, repository: repository] = "\(params.docVersion)" + environment.currentReferenceCache()?[owner: owner, repository: repository] = "\(params.docVersion)" return .current(referencing: "\(params.docVersion)") } else { return .reference(reference) diff --git a/Tests/AppTests/ApiTests.swift b/Tests/AppTests/ApiTests.swift index 19d1c29a7..576c0f133 100644 --- a/Tests/AppTests/ApiTests.swift +++ b/Tests/AppTests/ApiTests.swift @@ -112,6 +112,7 @@ class ApiTests: AppTestCase { func test_search_unauthenticated() async throws { try await withDependencies { $0.environment.apiSigningKey = { "secret" } + $0.environment.dbId = { nil } } operation: { // MUT try await app.test(.GET, "api/search?query=test", @@ -344,6 +345,7 @@ class ApiTests: AppTestCase { // Ensure unauthenticated access raises a 401 try await withDependencies { $0.environment.builderToken = { "secr3t" } + $0.environment.dbId = { nil } } operation: { // setup let p = try await savePackage(on: app.db, "1") @@ -640,6 +642,7 @@ class ApiTests: AppTestCase { func test_post_docReport_non_existing_build() async throws { try await withDependencies { $0.environment.builderToken = { "secr3t" } + $0.environment.dbId = { nil } } operation: { // setup let nonExistingBuildId = UUID() @@ -665,6 +668,7 @@ class ApiTests: AppTestCase { func test_post_docReport_unauthenticated() async throws { try await withDependencies { $0.environment.builderToken = { "secr3t" } + $0.environment.dbId = { nil } } operation: { // setup let p = try await savePackage(on: app.db, "1") @@ -978,6 +982,7 @@ class ApiTests: AppTestCase { func test_package_collections_packageURLs_limit() throws { try withDependencies { $0.environment.apiSigningKey = { "secret" } + $0.environment.dbId = { nil } } operation: { let dto = API.PostPackageCollectionDTO( // request 21 urls - this should raise a 400 @@ -999,6 +1004,7 @@ class ApiTests: AppTestCase { func test_package_collections_unauthorized() throws { try withDependencies { $0.environment.apiSigningKey = { "secret" } + $0.environment.dbId = { nil } } operation: { // MUT - happy path let body: ByteBuffer = .init(string: """ @@ -1042,6 +1048,7 @@ class ApiTests: AppTestCase { func test_packages_get() async throws { try await withDependencies { $0.environment.apiSigningKey = { "secret" } + $0.environment.dbId = { nil } } operation: { let owner = "owner" let repo = "repo" diff --git a/Tests/AppTests/AuthorControllerTests.swift b/Tests/AppTests/AuthorControllerTests.swift index fa4499c79..8a77c7915 100644 --- a/Tests/AppTests/AuthorControllerTests.swift +++ b/Tests/AppTests/AuthorControllerTests.swift @@ -12,10 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +import XCTest + @testable import App +import Dependencies import Vapor -import XCTest + class AuthorControllerTests: AppTestCase { @@ -66,27 +69,33 @@ class AuthorControllerTests: AppTestCase { } func test_show_owner() async throws { - // setup - let p = try await savePackage(on: app.db, "1") - try await Repository(package: p, owner: "owner").save(on: app.db) - try await Version(package: p, latest: .defaultBranch).save(on: app.db) + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + let p = try await savePackage(on: app.db, "1") + try await Repository(package: p, owner: "owner").save(on: app.db) + try await Version(package: p, latest: .defaultBranch).save(on: app.db) - // MUT - try await app.test(.GET, "/owner", afterResponse: { response async in - XCTAssertEqual(response.status, .ok) - }) + // MUT + try await app.test(.GET, "/owner", afterResponse: { response async in + XCTAssertEqual(response.status, .ok) + }) + } } func test_show_owner_empty() async throws { - // setup - let p = try await savePackage(on: app.db, "1") - try await Repository(package: p, owner: "owner").save(on: app.db) - try await Version(package: p, latest: .defaultBranch).save(on: app.db) + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + let p = try await savePackage(on: app.db, "1") + try await Repository(package: p, owner: "owner").save(on: app.db) + try await Version(package: p, latest: .defaultBranch).save(on: app.db) - // MUT - try await app.test(.GET, "/fake-owner", afterResponse: { response async in - XCTAssertEqual(response.status, .notFound) - }) + // MUT + try await app.test(.GET, "/fake-owner", afterResponse: { response async in + XCTAssertEqual(response.status, .notFound) + }) + } } } diff --git a/Tests/AppTests/BuildMonitorControllerTests.swift b/Tests/AppTests/BuildMonitorControllerTests.swift index c80b99caa..8a6b6107f 100644 --- a/Tests/AppTests/BuildMonitorControllerTests.swift +++ b/Tests/AppTests/BuildMonitorControllerTests.swift @@ -25,6 +25,7 @@ class BuildMonitorControllerTests: AppTestCase { func test_show_owner() async throws { try await withDependencies { $0.date.now = .now + $0.environment.dbId = { nil } } operation: { let package = try await savePackage(on: app.db, "https://github.com/daveverwer/LeftPad") let version = try Version(package: package) diff --git a/Tests/AppTests/ErrorMiddlewareTests.swift b/Tests/AppTests/ErrorMiddlewareTests.swift index 896afebe6..53a628ed7 100644 --- a/Tests/AppTests/ErrorMiddlewareTests.swift +++ b/Tests/AppTests/ErrorMiddlewareTests.swift @@ -12,10 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +import XCTest + @testable import App +import Dependencies import Vapor -import XCTest class ErrorMiddlewareTests: AppTestCase { @@ -39,24 +41,32 @@ class ErrorMiddlewareTests: AppTestCase { func test_html_error() throws { // Test to ensure errors are converted to html error pages via the ErrorMiddleware - try app.test(.GET, "404", afterResponse: { response in - XCTAssertEqual(response.content.contentType, .html) - XCTAssert(response.body.asString().contains("404 - Not Found")) - }) + try withDependencies { + $0.environment.dbId = { nil } + } operation: { + try app.test(.GET, "404", afterResponse: { response in + XCTAssertEqual(response.content.contentType, .html) + XCTAssert(response.body.asString().contains("404 - Not Found")) + }) + } } func test_status_code() throws { // Ensure we're still reporting the actual status code even when serving html pages // (Status is important for Google ranking, see // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/323) - try app.test(.GET, "404", afterResponse: { response in - XCTAssertEqual(response.status, .notFound) - XCTAssertEqual(response.content.contentType, .html) - }) - try app.test(.GET, "500", afterResponse: { response in - XCTAssertEqual(response.status, .internalServerError) - XCTAssertEqual(response.content.contentType, .html) - }) + try withDependencies { + $0.environment.dbId = { nil } + } operation: { + try app.test(.GET, "404", afterResponse: { response in + XCTAssertEqual(response.status, .notFound) + XCTAssertEqual(response.content.contentType, .html) + }) + try app.test(.GET, "500", afterResponse: { response in + XCTAssertEqual(response.status, .internalServerError) + XCTAssertEqual(response.content.contentType, .html) + }) + } } } diff --git a/Tests/AppTests/KeywordControllerTests.swift b/Tests/AppTests/KeywordControllerTests.swift index 04986eadd..44a06a3e4 100644 --- a/Tests/AppTests/KeywordControllerTests.swift +++ b/Tests/AppTests/KeywordControllerTests.swift @@ -12,10 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +import XCTest + @testable import App +import Dependencies import Vapor -import XCTest + class KeywordControllerTests: AppTestCase { @@ -102,25 +105,32 @@ class KeywordControllerTests: AppTestCase { } func test_show_keyword() async throws { - // setup - do { - let p = try await savePackage(on: app.db, "1") - try await Repository(package: p, - keywords: ["foo"], - name: "1", - owner: "owner").save(on: app.db) - try await Version(package: p, latest: .defaultBranch).save(on: app.db) - } - // MUT - try await app.test(.GET, "/keywords/foo") { req async in - // validate - XCTAssertEqual(req.status, .ok) + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + do { + let p = try await savePackage(on: app.db, "1") + try await Repository(package: p, + keywords: ["foo"], + name: "1", + owner: "owner").save(on: app.db) + try await Version(package: p, latest: .defaultBranch).save(on: app.db) + } + // MUT + try await app.test(.GET, "/keywords/foo") { req async in + // validate + XCTAssertEqual(req.status, .ok) + } } } func test_not_found() throws { - try app.test(.GET, "/keywords/baz") { - XCTAssertEqual($0.status, .notFound) + try withDependencies { + $0.environment.dbId = { nil } + } operation: { + try app.test(.GET, "/keywords/baz") { + XCTAssertEqual($0.status, .notFound) + } } } diff --git a/Tests/AppTests/Mocks/AppEnvironment+mock.swift b/Tests/AppTests/Mocks/AppEnvironment+mock.swift index 7a745d061..d8964bde3 100644 --- a/Tests/AppTests/Mocks/AppEnvironment+mock.swift +++ b/Tests/AppTests/Mocks/AppEnvironment+mock.swift @@ -22,8 +22,6 @@ import Vapor extension AppEnvironment { static func mock(eventLoop: EventLoop) -> Self { .init( - currentReferenceCache: { nil }, - dbId: { "db-id" }, fetchDocumentation: { _, _ in .init(status: .ok) }, fetchHTTPStatusCode: { _ in .ok }, fetchLicense: { _, _, _ in .init(htmlUrl: "https://github.com/foo/bar/blob/main/LICENSE") }, diff --git a/Tests/AppTests/PackageCollectionControllerTests.swift b/Tests/AppTests/PackageCollectionControllerTests.swift index d1544c726..9f416e4c6 100644 --- a/Tests/AppTests/PackageCollectionControllerTests.swift +++ b/Tests/AppTests/PackageCollectionControllerTests.swift @@ -138,14 +138,18 @@ class PackageCollectionControllerTests: AppTestCase { func test_nonexisting_404() throws { // Ensure a request for a non-existing collection returns a 404 - // MUT - try app.test( - .GET, - "foo/collection.json", - afterResponse: { res in - // validation - XCTAssertEqual(res.status, .notFound) - }) + try withDependencies { + $0.environment.dbId = { nil } + } operation: { + // MUT + try app.test( + .GET, + "foo/collection.json", + afterResponse: { res in + // validation + XCTAssertEqual(res.status, .notFound) + }) + } } } diff --git a/Tests/AppTests/PackageController+routesTests.swift b/Tests/AppTests/PackageController+routesTests.swift index 7cda52d38..cf339fd4b 100644 --- a/Tests/AppTests/PackageController+routesTests.swift +++ b/Tests/AppTests/PackageController+routesTests.swift @@ -25,44 +25,60 @@ import Vapor class PackageController_routesTests: SnapshotTestCase { func test_show() async throws { - // setup - let pkg = try await savePackage(on: app.db, "1") - try await Repository(package: pkg, name: "package", owner: "owner") - .save(on: app.db) - try await Version(package: pkg, latest: .defaultBranch).save(on: app.db) + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + // setup + let pkg = try await savePackage(on: app.db, "1") + try await Repository(package: pkg, name: "package", owner: "owner") + .save(on: app.db) + try await Version(package: pkg, latest: .defaultBranch).save(on: app.db) - // MUT - try await app.test(.GET, "/owner/package") { res async in - XCTAssertEqual(res.status, .ok) + // MUT + try await app.test(.GET, "/owner/package") { res async in + XCTAssertEqual(res.status, .ok) + } } } func test_show_checkingGitHubRepository_notFound() throws { - Current.fetchHTTPStatusCode = { _ in .notFound } + try withDependencies { + $0.environment.dbId = { nil } + } operation: { + Current.fetchHTTPStatusCode = { _ in .notFound } - // MUT - try app.test(.GET, "/unknown/package") { - XCTAssertEqual($0.status, .notFound) + // MUT + try app.test(.GET, "/unknown/package") { + XCTAssertEqual($0.status, .notFound) + } } } func test_show_checkingGitHubRepository_found() throws { - Current.fetchHTTPStatusCode = { _ in .ok } + try withDependencies { + $0.environment.dbId = { nil } + } operation: { + Current.fetchHTTPStatusCode = { _ in .ok } - // MUT - try app.test(.GET, "/unknown/package") { - XCTAssertEqual($0.status, .notFound) + // MUT + try app.test(.GET, "/unknown/package") { + XCTAssertEqual($0.status, .notFound) + } } } func test_show_checkingGitHubRepository_error() throws { // Make sure we don't throw an internal server error in case // fetchHTTPStatusCode fails - Current.fetchHTTPStatusCode = { _ in throw FetchError() } + try withDependencies { + $0.environment.dbId = { nil } + } operation: { + Current.fetchHTTPStatusCode = { _ in throw FetchError() } - // MUT - try app.test(.GET, "/unknown/package") { - XCTAssertEqual($0.status, .notFound) + // MUT + try app.test(.GET, "/unknown/package") { + XCTAssertEqual($0.status, .notFound) + } } } @@ -246,44 +262,56 @@ class PackageController_routesTests: SnapshotTestCase { } func test_builds() async throws { - // setup - let pkg = try await savePackage(on: app.db, "1") - try await Repository(package: pkg, name: "package", owner: "owner") - .save(on: app.db) - try await Version(package: pkg, latest: .defaultBranch).save(on: app.db) + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + // setup + let pkg = try await savePackage(on: app.db, "1") + try await Repository(package: pkg, name: "package", owner: "owner") + .save(on: app.db) + try await Version(package: pkg, latest: .defaultBranch).save(on: app.db) - // MUT - try await app.test(.GET, "/owner/package/builds") { res async in - XCTAssertEqual(res.status, .ok) + // MUT + try await app.test(.GET, "/owner/package/builds") { res async in + XCTAssertEqual(res.status, .ok) + } } } func test_maintainerInfo() async throws { - // setup - let pkg = try await savePackage(on: app.db, "1") - try await Repository(package: pkg, name: "package", owner: "owner") - .save(on: app.db) - try await Version(package: pkg, latest: .defaultBranch, packageName: "pkg") - .save(on: app.db) + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + // setup + let pkg = try await savePackage(on: app.db, "1") + try await Repository(package: pkg, name: "package", owner: "owner") + .save(on: app.db) + try await Version(package: pkg, latest: .defaultBranch, packageName: "pkg") + .save(on: app.db) - // MUT - try await app.test(.GET, "/owner/package/information-for-package-maintainers") { res async in - XCTAssertEqual(res.status, .ok) + // MUT + try await app.test(.GET, "/owner/package/information-for-package-maintainers") { res async in + XCTAssertEqual(res.status, .ok) + } } } func test_maintainerInfo_no_packageName() async throws { // Ensure we display the page even if packageName is not set - // setup - let pkg = try await savePackage(on: app.db, "1") - try await Repository(package: pkg, name: "package", owner: "owner") - .save(on: app.db) - try await Version(package: pkg, latest: .defaultBranch, packageName: nil) - .save(on: app.db) + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + // setup + let pkg = try await savePackage(on: app.db, "1") + try await Repository(package: pkg, name: "package", owner: "owner") + .save(on: app.db) + try await Version(package: pkg, latest: .defaultBranch, packageName: nil) + .save(on: app.db) - // MUT - try await app.test(.GET, "/owner/package/information-for-package-maintainers") { res async in - XCTAssertEqual(res.status, .ok) + // MUT + try await app.test(.GET, "/owner/package/information-for-package-maintainers") { res async in + XCTAssertEqual(res.status, .ok) + } } } @@ -538,6 +566,7 @@ class PackageController_routesTests: SnapshotTestCase { // /owner/package/documentation/~ + various path elements try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.currentReferenceCache = { nil } } operation: { // setup let pkg = try await savePackage(on: app.db, "1") @@ -620,6 +649,7 @@ class PackageController_routesTests: SnapshotTestCase { // /owner/package/documentation/~ + various path elements try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.currentReferenceCache = { nil } } operation: { // setup let pkg = try await savePackage(on: app.db, "1") @@ -813,34 +843,38 @@ class PackageController_routesTests: SnapshotTestCase { } func test_documentationRoot_notFound() async throws { - // setup - Current.fetchDocumentation = { _, _ in .init(status: .notFound) } - let pkg = try await savePackage(on: app.db, "1") - try await Repository(package: pkg, name: "package", owner: "owner") + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + // setup + Current.fetchDocumentation = { _, _ in .init(status: .notFound) } + let pkg = try await savePackage(on: app.db, "1") + try await Repository(package: pkg, name: "package", owner: "owner") + .save(on: app.db) + try await Version(package: pkg, + commit: "0123456789", + commitDate: .t0, + docArchives: [], // No docArchives! + latest: .defaultBranch, + packageName: "pkg", + reference: .branch("main")) + .save(on: app.db) + try await Version(package: pkg, + commit: "9876543210", + commitDate: .t0, + docArchives: [], // No docArchives! + latest: .release, + packageName: "pkg", + reference: .tag(1, 0, 0)) .save(on: app.db) - try await Version(package: pkg, - commit: "0123456789", - commitDate: .t0, - docArchives: [], // No docArchives! - latest: .defaultBranch, - packageName: "pkg", - reference: .branch("main")) - .save(on: app.db) - try await Version(package: pkg, - commit: "9876543210", - commitDate: .t0, - docArchives: [], // No docArchives! - latest: .release, - packageName: "pkg", - reference: .tag(1, 0, 0)) - .save(on: app.db) - // MUT - try await app.test(.GET, "/owner/package/main/documentation") { res async in - XCTAssertEqual(res.status, .notFound) - } - try await app.test(.GET, "/owner/package/1.0.0/documentation") { res async in - XCTAssertEqual(res.status, .notFound) + // MUT + try await app.test(.GET, "/owner/package/main/documentation") { res async in + XCTAssertEqual(res.status, .notFound) + } + try await app.test(.GET, "/owner/package/1.0.0/documentation") { res async in + XCTAssertEqual(res.status, .notFound) + } } } @@ -848,6 +882,7 @@ class PackageController_routesTests: SnapshotTestCase { // Test conversion of any doc fetching errors into 404s. try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.dbId = { nil } } operation: { // setup Current.fetchDocumentation = { _, uri in .init(status: .badRequest) } @@ -874,6 +909,7 @@ class PackageController_routesTests: SnapshotTestCase { // Test behaviour when fetchDocumentation throws try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.dbId = { nil } } operation: { struct SomeError: Error { } Current.fetchDocumentation = { _, _ in throw SomeError() } @@ -905,6 +941,7 @@ class PackageController_routesTests: SnapshotTestCase { func test_documentation_current_css() async throws { try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.currentReferenceCache = { nil } } operation: { // setup Current.fetchDocumentation = { _, uri in @@ -967,6 +1004,7 @@ class PackageController_routesTests: SnapshotTestCase { func test_documentation_current_js() async throws { try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.currentReferenceCache = { nil } } operation: { // setup Current.fetchDocumentation = { _, uri in @@ -1029,6 +1067,7 @@ class PackageController_routesTests: SnapshotTestCase { func test_documentation_current_data() async throws { try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.currentReferenceCache = { nil } } operation: { // setup Current.fetchDocumentation = { _, uri in @@ -1146,6 +1185,7 @@ class PackageController_routesTests: SnapshotTestCase { // Ensure references are path encoded try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.currentReferenceCache = { nil } } operation: { // setup let pkg = try await savePackage(on: app.db, "1") @@ -1209,6 +1249,8 @@ class PackageController_routesTests: SnapshotTestCase { func test_documentation_routes_tutorials() async throws { try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.currentReferenceCache = { nil } + $0.environment.dbId = { nil } } operation: { // setup let pkg = try await savePackage(on: app.db, "1") @@ -1432,7 +1474,7 @@ class PackageController_routesTests: SnapshotTestCase { // because app.test is not affected by @Dependency overrides. let prodApp = try await setup(.production) - do { + try await App.run { // setup let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) try await package.save(on: app.db) @@ -1446,30 +1488,36 @@ class PackageController_routesTests: SnapshotTestCase { try await prodApp.test(.GET, "/owner/repo0/sitemap.xml") { res async in XCTAssertEqual(res.status, .ok) } - } catch { - try? await prodApp.asyncShutdown() - throw error + } defer: { + try await prodApp.asyncShutdown() } - try await prodApp.asyncShutdown() } } func test_siteMap_dev() async throws { // Ensure we don't serve sitemaps in dev - // app and Current.environment are configured for .development by default + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + let devApp = try await setup(.development) - // setup - let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) - try await package.save(on: app.db) - try await Repository(package: package, defaultBranch: "default", - lastCommitDate: Date.now, - name: "Repo0", owner: "Owner").save(on: app.db) - try await Version(package: package, latest: .defaultBranch, packageName: "SomePackage", - reference: .branch("default")).save(on: app.db) + try await App.run { + // setup + let package = Package(url: URL(stringLiteral: "https://example.com/owner/repo0")) + try await package.save(on: app.db) + try await Repository(package: package, defaultBranch: "default", + lastCommitDate: Date.now, + name: "Repo0", owner: "Owner").save(on: app.db) + try await Version(package: package, latest: .defaultBranch, packageName: "SomePackage", + reference: .branch("default")).save(on: app.db) - // MUT - try await app.test(.GET, "/owner/repo0/sitemap.xml") { res async in - XCTAssertEqual(res.status, .notFound) + // MUT + try await devApp.test(.GET, "/owner/repo0/sitemap.xml") { res async in + XCTAssertEqual(res.status, .notFound) + } + } defer: { + try await devApp.asyncShutdown() + } } } @@ -1478,6 +1526,7 @@ class PackageController_routesTests: SnapshotTestCase { // https://github.com/SwiftPackageIndex/SwiftPackageIndex-Server/issues/2288 try await withDependencies { $0.environment.awsDocsBucket = { "docs-bucket" } + $0.environment.currentReferenceCache = { .live } } operation: { // setup let pkg = try await savePackage(on: app.db, "https://github.com/foo/bar".url, processingStage: .ingestion) @@ -1555,28 +1604,31 @@ class PackageController_routesTests: SnapshotTestCase { func test_getDocRoute_documentation_current() async throws { nonisolated(unsafe) let cache = CurrentReferenceCache() - Current.currentReferenceCache = { cache } - // owner/repo/~/documentation/archive - let req = Request(application: app, url: "", on: app.eventLoopGroup.next()) - req.parameters.set("owner", to: "owner") - req.parameters.set("repository", to: "repo") - req.parameters.set("reference", to: "~") - req.parameters.set("archive", to: "archive") + try await withDependencies { + $0.environment.currentReferenceCache = { cache } + } operation: { + // owner/repo/~/documentation/archive + let req = Request(application: app, url: "", on: app.eventLoopGroup.next()) + req.parameters.set("owner", to: "owner") + req.parameters.set("repository", to: "repo") + req.parameters.set("reference", to: "~") + req.parameters.set("archive", to: "archive") - do { // No cache value available and we've not set up the db with a record to be found -> notFound must be raised - _ = try await req.getDocRoute(fragment: .documentation) - XCTFail("expected a .notFound error") - } catch let error as Abort where error.status == .notFound { - // expected error - } catch { - XCTFail("unexpected error: \(error)") - } + do { // No cache value available and we've not set up the db with a record to be found -> notFound must be raised + _ = try await req.getDocRoute(fragment: .documentation) + XCTFail("expected a .notFound error") + } catch let error as Abort where error.status == .notFound { + // expected error + } catch { + XCTFail("unexpected error: \(error)") + } - cache[owner: "owner", repository: "repo"] = "1.2.3" + cache[owner: "owner", repository: "repo"] = "1.2.3" - do { // Now with the cache in place this resolves - let route = try await req.getDocRoute(fragment: .documentation) - XCTAssertEqual(route, .init(owner: "owner", repository: "repo", docVersion: .current(referencing: "1.2.3"), fragment: .documentation, pathElements: ["archive"])) + do { // Now with the cache in place this resolves + let route = try await req.getDocRoute(fragment: .documentation) + XCTAssertEqual(route, .init(owner: "owner", repository: "repo", docVersion: .current(referencing: "1.2.3"), fragment: .documentation, pathElements: ["archive"])) + } } } diff --git a/Tests/AppTests/RoutesTests.swift b/Tests/AppTests/RoutesTests.swift index c17228840..2464b32b9 100644 --- a/Tests/AppTests/RoutesTests.swift +++ b/Tests/AppTests/RoutesTests.swift @@ -75,10 +75,14 @@ final class RoutesTests: AppTestCase { } func test_maintenanceMessage() throws { - Current.maintenanceMessage = { "MAINTENANCE_MESSAGE" } + try withDependencies { + $0.environment.dbId = { nil } + } operation: { + Current.maintenanceMessage = { "MAINTENANCE_MESSAGE" } - try app.test(.GET, "/") { res in - XCTAssertContains(res.body.string, "MAINTENANCE_MESSAGE") + try app.test(.GET, "/") { res in + XCTAssertContains(res.body.string, "MAINTENANCE_MESSAGE") + } } } diff --git a/Tests/AppTests/SearchShowModelAppTests.swift b/Tests/AppTests/SearchShowModelAppTests.swift index 9b3d54a20..f883146e9 100644 --- a/Tests/AppTests/SearchShowModelAppTests.swift +++ b/Tests/AppTests/SearchShowModelAppTests.swift @@ -14,22 +14,28 @@ @testable import App +import Dependencies import SwiftSoup import XCTVapor + class SearchShowModelAppTests: AppTestCase { - + func test_SearchShow_Model_canonicalURLAllowList() async throws { - let request = Vapor.Request(application: app, - url: "search?query=alamo&page=2&utm_campaign=test&utm_source=email", - on: app.eventLoopGroup.next()) - let html = try await SearchController.show(req: request).render() - let document = try SwiftSoup.parse(html) - let linkElements = try document.select("link[rel='canonical']") - XCTAssertEqual(linkElements.count, 1) - - let href = try linkElements.first()!.attr("href") - XCTAssertEqual(href, "http://localhost:8080/search?query=alamo&page=2") + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + let request = Vapor.Request(application: app, + url: "search?query=alamo&page=2&utm_campaign=test&utm_source=email", + on: app.eventLoopGroup.next()) + let html = try await SearchController.show(req: request).render() + let document = try SwiftSoup.parse(html) + let linkElements = try document.select("link[rel='canonical']") + XCTAssertEqual(linkElements.count, 1) + + let href = try linkElements.first()!.attr("href") + XCTAssertEqual(href, "http://localhost:8080/search?query=alamo&page=2") + } } - + } diff --git a/Tests/AppTests/SitemapTests.swift b/Tests/AppTests/SitemapTests.swift index 3052543f6..07d0b7475 100644 --- a/Tests/AppTests/SitemapTests.swift +++ b/Tests/AppTests/SitemapTests.swift @@ -67,12 +67,20 @@ class SitemapTests: SnapshotTestCase { func test_siteMapIndex_dev() async throws { // Ensure we don't serve sitemaps in dev - // app and Current.environment are configured for .development by default - - // MUT - try await app.test(.GET, "/sitemap.xml") { res async in - // Validation - XCTAssertEqual(res.status, .notFound) + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + let devApp = try await setup(.development) + + try await App.run { + // MUT + try await devApp.test(.GET, "/sitemap.xml") { res async in + // Validation + XCTAssertEqual(res.status, .notFound) + } + } defer: { + try await devApp.asyncShutdown() + } } } @@ -110,12 +118,20 @@ class SitemapTests: SnapshotTestCase { func test_siteMapStaticPages_dev() async throws { // Ensure we don't serve sitemaps in dev - // app and Current.environment are configured for .development by default + try await withDependencies { + $0.environment.dbId = { nil } + } operation: { + let devApp = try await setup(.development) - // MUT - try await app.test(.GET, "/sitemap-static-pages.xml") { res async in - // Validation - XCTAssertEqual(res.status, .notFound) + try await App.run { + // MUT + try await devApp.test(.GET, "/sitemap-static-pages.xml") { res async in + // Validation + XCTAssertEqual(res.status, .notFound) + } + } defer: { + try await devApp.asyncShutdown() + } } } diff --git a/Tests/AppTests/WebpageSnapshotTests.swift b/Tests/AppTests/WebpageSnapshotTests.swift index 1801325c3..6290fb7b8 100644 --- a/Tests/AppTests/WebpageSnapshotTests.swift +++ b/Tests/AppTests/WebpageSnapshotTests.swift @@ -33,6 +33,7 @@ class WebpageSnapshotTests: SnapshotTestCase { override func invokeTest() { withDependencies { $0.environment.current = { .production } + $0.environment.dbId = { "db-id" } } operation: { super.invokeTest() }