diff --git a/phpmon/Common/Http/RealWebApi.swift b/phpmon/Common/Http/RealWebApi.swift index 0491c676..d0a3aaf5 100644 --- a/phpmon/Common/Http/RealWebApi.swift +++ b/phpmon/Common/Http/RealWebApi.swift @@ -53,7 +53,7 @@ class RealWebApi: WebApiProtocol { func get( _ url: URL, - withHeaders headers: HttpHeaders, + withHeaders headers: HttpHeaders = [:], withTimeout timeout: TimeInterval = URLSession.shared.configuration.timeoutIntervalForRequest ) async throws -> WebApiResponse { try await self.request( @@ -67,7 +67,7 @@ class RealWebApi: WebApiProtocol { func post( _ url: URL, - withHeaders headers: HttpHeaders, + withHeaders headers: HttpHeaders = [:], withData data: String, withTimeout timeout: TimeInterval ) async throws -> WebApiResponse { diff --git a/phpmon/Common/Http/TestableWebApi.swift b/phpmon/Common/Http/TestableWebApi.swift index cf774924..1e74289e 100644 --- a/phpmon/Common/Http/TestableWebApi.swift +++ b/phpmon/Common/Http/TestableWebApi.swift @@ -100,7 +100,7 @@ class TestableWebApi: WebApiProtocol { } } -struct FakeWebApiResponse { +struct FakeWebApiResponse: Codable { let statusCode: Int let headers: [String: String] let data: Data? diff --git a/phpmon/Common/Testables/TestableConfiguration.swift b/phpmon/Common/Testables/TestableConfiguration.swift index cbcaa88f..70ab6e41 100644 --- a/phpmon/Common/Testables/TestableConfiguration.swift +++ b/phpmon/Common/Testables/TestableConfiguration.swift @@ -14,6 +14,8 @@ public struct TestableConfiguration: Codable { var shellOutput: [String: BatchFakeShellOutput] var commandOutput: [String: String] var preferenceOverrides: [PreferenceName: Bool] + var apiGetResponses: [URL: FakeWebApiResponse] + var apiPostResponses: [URL: FakeWebApiResponse] init( architecture: String, @@ -21,13 +23,17 @@ public struct TestableConfiguration: Codable { shellOutput: [String: BatchFakeShellOutput], commandOutput: [String: String], preferenceOverrides: [PreferenceName: Bool], - phpVersions: [VersionNumber] + phpVersions: [VersionNumber], + apiGetResponses: [URL: FakeWebApiResponse], + apiPostResponses: [URL: FakeWebApiResponse] ) { self.architecture = architecture self.filesystem = filesystem self.shellOutput = shellOutput self.commandOutput = commandOutput self.preferenceOverrides = preferenceOverrides + self.apiGetResponses = apiGetResponses + self.apiPostResponses = apiPostResponses phpVersions.enumerated().forEach { (index, version) in self.addPhpVersion(version, primary: index == 0) @@ -35,7 +41,13 @@ public struct TestableConfiguration: Codable { } private enum CodingKeys: String, CodingKey { - case architecture, filesystem, shellOutput, commandOutput, preferenceOverrides + case architecture, + filesystem, + shellOutput, + commandOutput, + preferenceOverrides, + apiGetResponses, + apiPostResponses } // MARK: Add PHP versions diff --git a/phpmon/Container/Container.swift b/phpmon/Container/Container.swift index 75b57a51..9f20e40b 100644 --- a/phpmon/Container/Container.swift +++ b/phpmon/Container/Container.swift @@ -107,7 +107,9 @@ class Container { self.overrideFake( shellExpectations: config.shellOutput, fileSystemFiles: config.filesystem, - commands: config.commandOutput + commands: config.commandOutput, + webApiGetResponses: config.apiGetResponses, + webApiPostResponses: config.apiPostResponses ) } } diff --git a/phpmon/Domain/Integrations/Homebrew/CaskFile+API.swift b/phpmon/Domain/Integrations/Homebrew/CaskFile+API.swift index da86a981..f9b043cb 100644 --- a/phpmon/Domain/Integrations/Homebrew/CaskFile+API.swift +++ b/phpmon/Domain/Integrations/Homebrew/CaskFile+API.swift @@ -28,25 +28,19 @@ extension CaskFile { } } - // If it's a URL via the network we need to know if to use the complex API or not - if isRunningTests || App.hasLoadedTestableConfiguration || url.absoluteString.contains("https://raw.githubusercontent.com") { - // For testing simplicity, we will use curl, since we need no complex rules or headers - return CaskFile.from(await container.shell.pipe("curl -s --max-time 10 '\(url.absoluteString)'").out) - } else { - // However, for the real deal, we will use the Web API - guard let response = try? await container.webApi.get( - url, - withHeaders: container.webApi.defaultHeaders, - withTimeout: .seconds(10) - ) else { - throw CaskFileError.requestFailed - } - - guard let text = response.plainText else { - throw CaskFileError.invalidData - } - - return CaskFile.from(text) + // However, for the real deal, we will use the Web API + guard let response = try? await container.webApi.get( + url, + withHeaders: container.webApi.defaultHeaders, + withTimeout: .seconds(10) + ) else { + throw CaskFileError.requestFailed } + + guard let text = response.plainText else { + throw CaskFileError.invalidData + } + + return CaskFile.from(text) } } diff --git a/tests/PHP Monitor.xctestplan b/tests/PHP Monitor.xctestplan index bc734b7e..c1c464cb 100644 --- a/tests/PHP Monitor.xctestplan +++ b/tests/PHP Monitor.xctestplan @@ -13,6 +13,7 @@ }, "testTargets" : [ { + "enabled" : false, "parallelizable" : true, "target" : { "containerPath" : "container:PHP Monitor.xcodeproj", @@ -30,7 +31,6 @@ } }, { - "enabled" : false, "target" : { "containerPath" : "container:PHP Monitor.xcodeproj", "identifier" : "C471E7BB28F9B90F0021E251", diff --git a/tests/Shared/TestableConfigurations.swift b/tests/Shared/TestableConfigurations.swift index 65f5ed7e..2988f885 100644 --- a/tests/Shared/TestableConfigurations.swift +++ b/tests/Shared/TestableConfigurations.swift @@ -138,36 +138,6 @@ class TestableConfigurations { : .instant(ShellStrings.shared.brewServicesAsRoot), "/opt/homebrew/bin/brew services info --all --json" : .instant(ShellStrings.shared.brewServicesAsUser), - "curl -s --max-time 10 '\(Constants.Urls.UpdateCheckEndpoint.absoluteString)'" - : .delayed(0.5, """ - cask 'phpmon-dev' do - depends_on formula: 'gnu-sed' - - version '25.08.0_1000' - sha256 '1cb147bd1b1fbd52971d90dff577465b644aee7c878f15ede57f46e8f217067a' - - url 'https://github.com/nicoverbruggen/phpmon/releases/download/v6.0/phpmon-dev.zip' - name 'PHP Monitor DEV' - homepage 'https://phpmon.app' - - app 'PHP Monitor DEV.app', target: "PHP Monitor DEV.app" - end - """), - "curl -s --max-time 10 'https://raw.githubusercontent.com/nicoverbruggen/homebrew-cask/master/Casks/phpmon.rb''" : - .delayed(0.5, """ - cask 'phpmon-dev' do - depends_on formula: 'gnu-sed' - - version '25.08.0_1000' - sha256 '1cb147bd1b1fbd52971d90dff577465b644aee7c878f15ede57f46e8f217067a' - - url 'https://github.com/nicoverbruggen/phpmon/releases/download/v6.0/phpmon-dev.zip' - name 'PHP Monitor DEV' - homepage 'https://phpmon.app' - - app 'PHP Monitor DEV.app', target: "PHP Monitor DEV.app" - end - """), "/opt/homebrew/bin/brew unlink php" : .delayed(0.2, "OK"), "/opt/homebrew/bin/brew unlink php@8.2" @@ -222,7 +192,29 @@ class TestableConfigurations { VersionNumber(major: 8, minor: 1, patch: 0), VersionNumber(major: 8, minor: 0, patch: 0), VersionNumber(major: 7, minor: 4, patch: 33) - ] + ], + apiGetResponses: [ + url("\(Constants.Urls.UpdateCheckEndpoint.absoluteString)"): FakeWebApiResponse( + statusCode: 200, + headers: [:], + text: """ + cask 'phpmon-dev' do + depends_on formula: 'gnu-sed' + + version '25.08.0_1000' + sha256 '1cb147bd1b1fbd52971d90dff577465b644aee7c878f15ede57f46e8f217067a' + + url 'https://github.com/nicoverbruggen/phpmon/releases/download/v6.0/phpmon-dev.zip' + name 'PHP Monitor DEV' + homepage 'https://phpmon.app' + + app 'PHP Monitor DEV.app', target: "PHP Monitor DEV.app" + end + """, + duration: 0.5 + ) + ], + apiPostResponses: [:] ) } diff --git a/tests/ui/UpdateCheckTest.swift b/tests/ui/UpdateCheckTest.swift index 07c8ccaa..ec5ce0c3 100644 --- a/tests/ui/UpdateCheckTest.swift +++ b/tests/ui/UpdateCheckTest.swift @@ -31,9 +31,10 @@ final class UpdateCheckTest: UITestCase { configuration.preferenceOverrides[.automaticBackgroundUpdateCheck] = true // Ensure an update is available - configuration.shellOutput[ - "curl -s --max-time 10 '\(Constants.Urls.UpdateCheckEndpoint.absoluteString)'" - ] = .delayed(0.5, """ + configuration.apiGetResponses[url("\(Constants.Urls.UpdateCheckEndpoint.absoluteString)")] = FakeWebApiResponse( + statusCode: 200, + headers: [:], + text: """ cask 'phpmon-dev' do depends_on formula: 'gnu-sed' @@ -46,7 +47,9 @@ final class UpdateCheckTest: UITestCase { app 'PHP Monitor DEV.app', target: "PHP Monitor DEV.app" end - """) + """, + duration: 0.5 + ) let app = launch(openMenu: false, with: configuration) @@ -64,7 +67,10 @@ final class UpdateCheckTest: UITestCase { configuration.preferenceOverrides[.automaticBackgroundUpdateCheck] = false // Ensure an update is available - configuration.shellOutput["curl -s --max-time 10 '\(Constants.Urls.UpdateCheckEndpoint.absoluteString)'"] = .delayed(0.5, """ + configuration.apiGetResponses[url("\(Constants.Urls.UpdateCheckEndpoint.absoluteString)")] = FakeWebApiResponse( + statusCode: 200, + headers: [:], + text: """ cask 'phpmon-dev' do depends_on formula: 'gnu-sed' @@ -77,7 +83,9 @@ final class UpdateCheckTest: UITestCase { app 'PHP Monitor DEV.app', target: "PHP Monitor DEV.app" end - """) + """, + duration: 0.5 + ) // Wait for the menu to open and search for updates let app = launch(openMenu: false, with: configuration) @@ -93,7 +101,10 @@ final class UpdateCheckTest: UITestCase { configuration.preferenceOverrides[.automaticBackgroundUpdateCheck] = false // Ensure an update is available - configuration.shellOutput["curl -s --max-time 10 '\(Constants.Urls.UpdateCheckEndpoint.absoluteString)'"] = .delayed(0.5, """ + configuration.apiGetResponses[url("\(Constants.Urls.UpdateCheckEndpoint.absoluteString)")] = FakeWebApiResponse( + statusCode: 200, + headers: [:], + text: """ cask 'phpmon-dev' do depends_on formula: 'gnu-sed' @@ -106,7 +117,9 @@ final class UpdateCheckTest: UITestCase { app 'PHP Monitor DEV.app', target: "PHP Monitor DEV.app" end - """) + """, + duration: 0.5 + ) // Wait for the menu to open and search for updates let app = launch(openMenu: true, with: configuration) @@ -125,7 +138,14 @@ final class UpdateCheckTest: UITestCase { configuration.preferenceOverrides[.automaticBackgroundUpdateCheck] = false // Ensure an update is available - configuration.shellOutput["curl -s --max-time 10 '\(Constants.Urls.UpdateCheckEndpoint.absoluteString)'"] = .delayed(0.5, "404 PAGE NOT FOUND") + configuration.apiGetResponses[url("\(Constants.Urls.UpdateCheckEndpoint.absoluteString)")] = FakeWebApiResponse( + statusCode: 500, + headers: [:], + text: """ + OOPS, SERVER DOWN + """, + duration: 0.5 + ) // Wait for the menu to open and search for updates let app = launch(openMenu: true, with: configuration)