diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index e7a4f6eb0..7737d9314 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -22,7 +22,7 @@ jobs: name: Run unit tests (macOS) - runs-on: macos-14 + runs-on: macos-15 timeout-minutes: 30 outputs: @@ -67,12 +67,13 @@ jobs: run: set -o pipefail && swift test | tee -a build-log.txt | xcbeautify --report junit --report-path . --junit-report-filename tests.xml - name: Publish Unit Tests Report - uses: mikepenz/action-junit-report@v3 + uses: mikepenz/action-junit-report@v4 if: always() with: check_name: Test Report (macOS) report_paths: tests.xml require_tests: true + check_retries: true - name: Update Asana with failed unit tests if: always() # always run even if the previous step fails @@ -108,7 +109,7 @@ jobs: name: Run unit tests (iOS) - runs-on: macos-14 + runs-on: macos-15 timeout-minutes: 30 steps: @@ -143,7 +144,7 @@ jobs: run: | while xcodebuild -resolvePackageDependencies \ -scheme BrowserServicesKit-Package \ - -destination 'platform=iOS Simulator,name=iPhone 15,OS=17' \ + -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.1' \ -derivedDataPath DerivedData \ 2>&1 | grep Error; do :; done @@ -156,16 +157,18 @@ jobs: run: | set -o pipefail && xcodebuild test \ -scheme BrowserServicesKit \ - -destination 'platform=iOS Simulator,name=iPhone 15,OS=17' \ + -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.1' \ -derivedDataPath DerivedData \ -skipPackagePluginValidation \ -skipMacroValidation \ + -test-iterations 3 \ + -retry-tests-on-failure \ CODE_SIGNING_ALLOWED=NO \ | tee -a ios-build-log.txt \ | xcbeautify --report junit --report-path . --junit-report-filename ios-unittests.xml - name: Publish Unit Tests Report - uses: mikepenz/action-junit-report@v3 + uses: mikepenz/action-junit-report@v4 if: always() with: check_name: Test Report (iOS) diff --git a/.xcode-version b/.xcode-version index 232a7fc1a..c32b0ec5a 100644 --- a/.xcode-version +++ b/.xcode-version @@ -1 +1 @@ -15.4 +16.1 diff --git a/Package.resolved b/Package.resolved index ff26e86c7..056cb5a08 100644 --- a/Package.resolved +++ b/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/GRDB.swift.git", "state" : { - "revision" : "4225b85c9a0c50544e413a1ea1e502c802b44b35", - "version" : "2.4.0" + "revision" : "5b2f6a81099d26ae0f9e38788f51490cd6a4b202", + "version" : "2.4.2" } }, { diff --git a/Package.swift b/Package.swift index 709e31ad4..fd1be0840 100644 --- a/Package.swift +++ b/Package.swift @@ -49,7 +49,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/duckduckgo/duckduckgo-autofill.git", exact: "15.1.0"), - .package(url: "https://github.com/duckduckgo/GRDB.swift.git", exact: "2.4.0"), + .package(url: "https://github.com/duckduckgo/GRDB.swift.git", exact: "2.4.2"), .package(url: "https://github.com/duckduckgo/TrackerRadarKit", exact: "3.0.0"), .package(url: "https://github.com/duckduckgo/sync_crypto", exact: "0.3.0"), .package(url: "https://github.com/gumob/PunycodeSwift.git", exact: "3.0.0"), @@ -411,10 +411,6 @@ let package = Package( dependencies: [ "Common" ], - resources: [ - .copy("hashPrefixes.json"), - .copy("filterSet.json") - ], swiftSettings: [ .define("DEBUG", .when(configuration: .debug)) ] @@ -655,8 +651,8 @@ let package = Package( "PixelKit" ], resources: [ - .copy("hashPrefixes.json"), - .copy("filterSet.json") + .copy("Resources/hashPrefixes.json"), + .copy("Resources/filterSet.json") ] ), .testTarget( diff --git a/Sources/Configuration/DefaultConfigurationManager.swift b/Sources/Configuration/DefaultConfigurationManager.swift index 89eddea27..76996cd0b 100644 --- a/Sources/Configuration/DefaultConfigurationManager.swift +++ b/Sources/Configuration/DefaultConfigurationManager.swift @@ -96,7 +96,7 @@ open class DefaultConfigurationManager: NSObject { public func start() { Logger.config.debug("Starting configuration refresh timer") - refreshTask = Task.periodic(interval: Constants.refreshCheckIntervalSeconds) { + refreshTask = Task.periodic(interval: Constants.refreshCheckIntervalSeconds) { [weak self] in Self.queue.async { [weak self] in self?.lastRefreshCheckTime = Date() self?.refreshIfNeeded() diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/AdClickAttribution/AdClickAttributionRulesProviderTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/AdClickAttribution/AdClickAttributionRulesProviderTests.swift index 42223ea2c..feb6fbcf5 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/AdClickAttribution/AdClickAttributionRulesProviderTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/AdClickAttribution/AdClickAttributionRulesProviderTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import XCTest import BrowserServicesKit import os @@ -217,3 +220,5 @@ class AdClickAttributionRulesProviderTests: XCTestCase { } } + +#endif diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/ClickToLoadBlockingTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/ClickToLoadBlockingTests.swift index 7002154c0..bb577fdc2 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/ClickToLoadBlockingTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/ClickToLoadBlockingTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import XCTest import os.log import WebKit @@ -368,3 +371,5 @@ class ClickToLoadBlockingTests: XCTestCase { } } } + +#endif diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerReferenceTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerReferenceTests.swift index ef8478910..b922378e9 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerReferenceTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerReferenceTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import XCTest import os.log import WebKit @@ -203,3 +206,5 @@ class ContentBlockerReferenceTests: XCTestCase { } } } + +#endif diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerInitialCompilationTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerInitialCompilationTests.swift index 004d373e4..f6082a7b2 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerInitialCompilationTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerInitialCompilationTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import Foundation import TrackerRadarKit import BrowserServicesKit @@ -294,3 +297,5 @@ final class ContentBlockerRulesManagerInitialCompilationTests: XCTestCase { } } + +#endif diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerMultipleRulesTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerMultipleRulesTests.swift index d02b47599..969ccba83 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerMultipleRulesTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerMultipleRulesTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import XCTest import TrackerRadarKit import BrowserServicesKit @@ -352,3 +355,5 @@ class ContentBlockerRulesManagerMultipleRulesTests: ContentBlockerRulesManagerTe } } + +#endif diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerTests.swift index dc1e188ce..60df0f3a1 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesManagerTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import XCTest import TrackerRadarKit import BrowserServicesKit @@ -1243,3 +1246,5 @@ extension ContentBlockerRulesManager { } } + +#endif diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesUserScriptsTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesUserScriptsTests.swift index 8d48a1ff4..faa5cbce6 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesUserScriptsTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/ContentBlockerRulesUserScriptsTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import BrowserServicesKit import Common import TrackerRadarKit @@ -569,3 +572,5 @@ class ContentBlockerRulesUserScriptsTests: XCTestCase { self.wait(for: [websiteLoaded], timeout: 30) } } + +#endif diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/SurrogatesReferenceTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/SurrogatesReferenceTests.swift index b1d77303b..153f37690 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/SurrogatesReferenceTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/SurrogatesReferenceTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import XCTest @testable import TrackerRadarKit import os.log @@ -226,3 +229,5 @@ final class SurrogatesReferenceTests: XCTestCase { } } } + +#endif diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/SurrogatesUserScriptTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/SurrogatesUserScriptTests.swift index 5a33b0eb8..3a77d1ece 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/SurrogatesUserScriptTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/SurrogatesUserScriptTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import BrowserServicesKit import Common import TrackerRadarKit @@ -685,3 +688,5 @@ class SurrogatesUserScriptsTests: XCTestCase { self.wait(for: [websiteLoaded, surrogateValidated], timeout: 15) } } + +#endif diff --git a/Tests/BrowserServicesKitTests/ContentBlocker/TrackerAllowlistReferenceTests.swift b/Tests/BrowserServicesKitTests/ContentBlocker/TrackerAllowlistReferenceTests.swift index 9bfc87066..d20123ea0 100644 --- a/Tests/BrowserServicesKitTests/ContentBlocker/TrackerAllowlistReferenceTests.swift +++ b/Tests/BrowserServicesKitTests/ContentBlocker/TrackerAllowlistReferenceTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import XCTest import os.log import WebKit @@ -209,3 +212,5 @@ class TrackerAllowlistReferenceTests: XCTestCase { } } } + +#endif diff --git a/Tests/BrowserServicesKitTests/Fingerprinting/FingerprintingReferenceTests.swift b/Tests/BrowserServicesKitTests/Fingerprinting/FingerprintingReferenceTests.swift index d04ce66cb..68ce6e903 100644 --- a/Tests/BrowserServicesKitTests/Fingerprinting/FingerprintingReferenceTests.swift +++ b/Tests/BrowserServicesKitTests/Fingerprinting/FingerprintingReferenceTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import XCTest @testable import TrackerRadarKit @testable import BrowserServicesKit @@ -260,3 +263,5 @@ private struct Test: Codable { let property, expectPropertyValue: String let exceptPlatforms: [String] } + +#endif diff --git a/Tests/BrowserServicesKitTests/GPC/GPCReferenceTests.swift b/Tests/BrowserServicesKitTests/GPC/GPCReferenceTests.swift index 8fe83c91f..afc346069 100644 --- a/Tests/BrowserServicesKitTests/GPC/GPCReferenceTests.swift +++ b/Tests/BrowserServicesKitTests/GPC/GPCReferenceTests.swift @@ -16,6 +16,9 @@ // limitations under the License. // +// Tests are disabled on iOS due to WKWebView stability issues on the iOS 17.5+ simulator. +#if os(macOS) + import XCTest import BrowserServicesKit import os.log @@ -235,3 +238,5 @@ struct GpcJavaScriptAPITest: Codable { let exceptPlatforms: [String] let frameURL: String? } + +#endif diff --git a/Tests/ConfigurationTests/ConfigurationManagerTests.swift b/Tests/ConfigurationTests/ConfigurationManagerTests.swift index 97cd49569..5e931a07d 100644 --- a/Tests/ConfigurationTests/ConfigurationManagerTests.swift +++ b/Tests/ConfigurationTests/ConfigurationManagerTests.swift @@ -65,7 +65,7 @@ final class MockConfigurationManager: DefaultConfigurationManager { } } -struct MockDependencyProvider { +final class MockDependencyProvider { var privacyConfigEtag: String? var privacyConfigData: Data? } @@ -132,16 +132,15 @@ final class ConfigurationManagerTests: XCTestCase { let managerA = makeConfigurationManager(name: "A") let managerB = makeConfigurationManager(name: "B") - var e: XCTestExpectation? = expectation(description: "ConfigManager B updated") + let e = XCTestExpectation(description: "ConfigManager B updated") managerB.onDependenciesUpdated = { - e?.fulfill() - e = nil + e.fulfill() } let configData = Data("Privacy Config".utf8) MockURLProtocol.requestHandler = { _ in (HTTPURLResponse.ok, configData) } await managerA.refreshNow() - await fulfillment(of: [e!], timeout: 2) + await fulfillment(of: [e], timeout: 2) XCTAssertNotNil(MockURLProtocol.lastRequest) XCTAssertEqual(managerB.dependencyProvider.privacyConfigData, configData) @@ -152,37 +151,43 @@ final class ConfigurationManagerTests: XCTestCase { let managerA = makeConfigurationManager() let managerB = makeConfigurationManager() - var e: XCTestExpectation? = expectation(description: "ConfigManager B updated") + var e = XCTestExpectation(description: "ConfigManager B updated") managerB.onDependenciesUpdated = { - e?.fulfill() - e = nil + e.fulfill() } var configData = Data("Privacy Config".utf8) MockURLProtocol.requestHandler = { _ in (HTTPURLResponse.ok, configData) } await managerA.refreshNow() - await fulfillment(of: [e!], timeout: 2) + await fulfillment(of: [e], timeout: 2) XCTAssertNotNil(MockURLProtocol.lastRequest) XCTAssertEqual(managerB.dependencyProvider.privacyConfigData, configData) XCTAssertEqual(managerB.dependencyProvider.privacyConfigEtag, HTTPURLResponse.testEtag) MockURLProtocol.lastRequest = nil - e = expectation(description: "ConfigManager A updated") + e = XCTestExpectation(description: "ConfigManager A updated") managerB.onDependenciesUpdated = nil managerA.onDependenciesUpdated = { - e?.fulfill() - e = nil + e.fulfill() } configData = Data("Privacy Config 2".utf8) MockURLProtocol.requestHandler = { _ in (HTTPURLResponse.ok, configData) } await managerB.refreshNow() - await fulfillment(of: [e!], timeout: 2) + await fulfillment(of: [e], timeout: 2) XCTAssertNotNil(MockURLProtocol.lastRequest) - XCTAssertEqual(managerA.dependencyProvider.privacyConfigData, configData) - XCTAssertEqual(managerA.dependencyProvider.privacyConfigEtag, HTTPURLResponse.testEtag) + + let configDataExpectation = XCTNSPredicateExpectation(predicate: NSPredicate { _, _ in + return managerA.dependencyProvider.privacyConfigData == configData + }, object: .none) + + let configEtagExpectation = XCTNSPredicateExpectation(predicate: NSPredicate { _, _ in + return managerA.dependencyProvider.privacyConfigEtag == HTTPURLResponse.testEtag + }, object: .none) + + await fulfillment(of: [configDataExpectation, configEtagExpectation], timeout: 5) MockURLProtocol.lastRequest = nil MockURLProtocol.requestHandler = { _ in (HTTPURLResponse.notModified, nil) } @@ -197,16 +202,15 @@ final class ConfigurationManagerTests: XCTestCase { let managerA = makeConfigurationManager() let managerB = makeConfigurationManager() - var e: XCTestExpectation? = expectation(description: "ConfigManager B updated") + let e = XCTestExpectation(description: "ConfigManager B updated") managerB.onDependenciesUpdated = { - e?.fulfill() - e = nil + e.fulfill() } let configData = Data("Privacy Config".utf8) MockURLProtocol.requestHandler = { _ in (HTTPURLResponse.ok, configData) } await managerA.refreshNow() - await fulfillment(of: [e!], timeout: 2) + await fulfillment(of: [e], timeout: 2) XCTAssertNotNil(MockURLProtocol.lastRequest) XCTAssertEqual(managerB.dependencyProvider.privacyConfigData, configData) diff --git a/Tests/PhishingDetectionTests/filterSet.json b/Tests/PhishingDetectionTests/Resources/filterSet.json similarity index 100% rename from Tests/PhishingDetectionTests/filterSet.json rename to Tests/PhishingDetectionTests/Resources/filterSet.json diff --git a/Tests/PhishingDetectionTests/hashPrefixes.json b/Tests/PhishingDetectionTests/Resources/hashPrefixes.json similarity index 100% rename from Tests/PhishingDetectionTests/hashPrefixes.json rename to Tests/PhishingDetectionTests/Resources/hashPrefixes.json