Skip to content

Commit

Permalink
LoadShedderIntegrationTests: verify requests are actually handled b…
Browse files Browse the repository at this point in the history
…y load shedder (#2663)
  • Loading branch information
NachoSoto authored Jun 19, 2023
1 parent 5c35df2 commit f9660fb
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Sources/Logging/Strings/NetworkStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum NetworkStrings {
case blocked_network(url: URL, newHost: String?)
case api_request_redirect(from: URL, to: URL)
case operation_state(NetworkOperation.Type, state: String)
case request_handled_by_load_shedder(HTTPRequest.Path)

#if DEBUG
case api_request_forcing_server_error(HTTPRequest)
Expand Down Expand Up @@ -103,6 +104,9 @@ extension NetworkStrings: LogMessage {
case let .operation_state(operation, state):
return "\(operation): \(state)"

case let .request_handled_by_load_shedder(path):
return "Request was handled by load shedder: \(path.description)"

#if DEBUG
case let .api_request_forcing_server_error(request):
return "Returning fake HTTP 500 error for '\(request.description)'"
Expand Down
10 changes: 10 additions & 0 deletions Sources/Networking/HTTPClient/HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ extension HTTPClient {
case signature = "X-Signature"
case requestDate = "X-RevenueCat-Request-Time"
case contentType = "Content-Type"
case isLoadShedder = "X-RevenueCat-Fortress"

}

Expand Down Expand Up @@ -320,6 +321,11 @@ private extension HTTPClient {
// If that can't be extracted, get status code from the parsed response.
httpCode: urlResponse?.httpStatusCode ?? response.statusCode
))

if response.isLoadShedder {
Logger.debug(Strings.network.request_handled_by_load_shedder(request.httpRequest.path))
}

case let .failure(error):
Logger.debug(Strings.network.api_request_failed(request.httpRequest,
httpCode: urlResponse?.httpStatusCode,
Expand Down Expand Up @@ -531,6 +537,10 @@ private extension HTTPResponse {
}
}

var isLoadShedder: Bool {
return self.value(forHeaderField: HTTPClient.ResponseHeader.isLoadShedder.rawValue) == "true"
}

}

private extension HTTPResponse where Body == Data {
Expand Down
42 changes: 42 additions & 0 deletions Tests/BackendIntegrationTests/LoadShedderIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,45 @@ class LoadShedderStoreKit1IntegrationTests: BaseStoreKitIntegrationTests {
return Signing.enforcedVerificationMode()
}

// MARK: -

private var logger: TestLogHandler!

override func setUp() async throws {
self.logger = TestLogHandler(capacity: 500)

try await super.setUp()
}

override func tearDown() async throws {
self.logger = nil

try await super.tearDown()
}

func testCanGetOfferings() async throws {
let receivedOfferings = try await Purchases.shared.offerings()

expect(receivedOfferings.all).toNot(beEmpty())
assertSnapshot(matching: receivedOfferings.response, as: .formattedJson)
}

func testOfferingsComeFromLoadShedder() async throws {
self.logger.verifyMessageWasLogged(
Strings.network.request_handled_by_load_shedder(
.getOfferings(appUserID: try Purchases.shared.appUserID.escapedOrError())
),
level: .debug
)
}

func testCanPurchasePackage() async throws {
try await self.purchaseMonthlyOffering()

self.logger.verifyMessageWasLogged(
Strings.network.request_handled_by_load_shedder(.postReceiptData),
level: .debug
)
}

@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
Expand All @@ -57,4 +87,16 @@ class LoadShedderStoreKit1IntegrationTests: BaseStoreKitIntegrationTests {
expect(result.entitlementsByProduct["com.revenuecat.loadShedder.monthly"]) == ["premium"]
}

@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
func testProductEntitlementMappingComesFromLoadShedder() async throws {
try AvailabilityChecks.iOS15APIAvailableOrSkipTest()

try await self.logger.verifyMessageIsEventuallyLogged(
Strings.network.request_handled_by_load_shedder(.getProductEntitlementMapping).description,
level: .debug,
timeout: .seconds(5),
pollInterval: .milliseconds(100)
)
}

}
8 changes: 8 additions & 0 deletions Tests/BackendIntegrationTests/OtherIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ class OtherIntegrationTests: BaseBackendIntegrationTests {
try await Purchases.shared.healthRequest(signatureVerification: true)
}

func testHandledByProductionServer() async throws {
let logger = TestLogHandler()

try await Purchases.shared.healthRequest(signatureVerification: false)

logger.verifyMessageWasNotLogged(Strings.network.request_handled_by_load_shedder(.health))
}

@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
func testProductEntitlementMapping() async throws {
try AvailabilityChecks.iOS15APIAvailableOrSkipTest()
Expand Down
47 changes: 47 additions & 0 deletions Tests/UnitTests/Networking/HTTPClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,53 @@ final class HTTPClientTests: BaseHTTPClientTests {
)
}

func testNormalResponsesAreNotDetectedAsLoadSheddder() throws {
let path: HTTPRequest.Path = .logIn

stub(condition: isPath(path)) { _ in
return HTTPStubsResponse(
data: .init(),
statusCode: .success,
headers: [:]
)
}

let logger = TestLogHandler()

let response: HTTPResponse<Data>.Result? = waitUntilValue { completion in
self.client.perform(.init(method: .get, path: path), completionHandler: completion)
}
expect(response).to(beSuccess())

logger.verifyMessageWasNotLogged(Strings.network.request_handled_by_load_shedder(path))
}

func testLoadShedderResponsesAreLogged() throws {
let path: HTTPRequest.Path = .logIn

stub(condition: isPath(path)) { _ in
return HTTPStubsResponse(
data: .init(),
statusCode: .success,
headers: [
HTTPClient.ResponseHeader.isLoadShedder.rawValue: "true"
]
)
}

let logger = TestLogHandler()

let response: HTTPResponse<Data>.Result? = waitUntilValue { completion in
self.client.perform(.init(method: .get, path: path), completionHandler: completion)
}
expect(response).to(beSuccess())

logger.verifyMessageWasLogged(
Strings.network.request_handled_by_load_shedder(path),
level: .debug
)
}

}

func isPath(_ path: HTTPRequest.Path) -> HTTPStubsTestBlock {
Expand Down

0 comments on commit f9660fb

Please sign in to comment.