Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass Mutation Name as Endpoint for GraphQL #1349

Merged
merged 7 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Braintree.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
428F976626727333001042E1 /* BTMockOpenURLContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 428F976526727333001042E1 /* BTMockOpenURLContext.m */; };
42FC218B25CDE0290047C49A /* BTPayPalRequest_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42FC218A25CDE0290047C49A /* BTPayPalRequest_Tests.swift */; };
42FC237125CE0E110047C49A /* BTPayPalCheckoutRequest_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42FC237025CE0E110047C49A /* BTPayPalCheckoutRequest_Tests.swift */; };
45227FC52C330FDE00A15018 /* MockURLSessionTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45227FC32C330FDE00A15018 /* MockURLSessionTask.swift */; };
45227FC72C33104100A15018 /* MockBTHTTPNetworkTiming.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45227FC62C33104100A15018 /* MockBTHTTPNetworkTiming.swift */; };
460C0C220F594AE8EE205E57 /* Pods_Tests_BraintreeCoreTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9239C9FE850C3587DE61A3A2 /* Pods_Tests_BraintreeCoreTests.framework */; };
5708E0A628809AD9007946B9 /* BTJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5708E0A528809AD9007946B9 /* BTJSON.swift */; };
5708E0A828809BC6007946B9 /* BTJSONError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5708E0A728809BC6007946B9 /* BTJSONError.swift */; };
Expand Down Expand Up @@ -772,6 +774,8 @@
42F75E5A24D48138007DC5E7 /* BTThreeDSecureClient_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureClient_Tests.swift; sourceTree = "<group>"; };
42FC218A25CDE0290047C49A /* BTPayPalRequest_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTPayPalRequest_Tests.swift; sourceTree = "<group>"; };
42FC237025CE0E110047C49A /* BTPayPalCheckoutRequest_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTPayPalCheckoutRequest_Tests.swift; sourceTree = "<group>"; };
45227FC32C330FDE00A15018 /* MockURLSessionTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockURLSessionTask.swift; sourceTree = "<group>"; };
45227FC62C33104100A15018 /* MockBTHTTPNetworkTiming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockBTHTTPNetworkTiming.swift; sourceTree = "<group>"; };
463DED22C0F426A474E6D7E2 /* Pods-Tests-BraintreeCoreTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests-BraintreeCoreTests.release.xcconfig"; path = "Target Support Files/Pods-Tests-BraintreeCoreTests/Pods-Tests-BraintreeCoreTests.release.xcconfig"; sourceTree = "<group>"; };
541AEE40A1F01913E0638CC9 /* Pods-Tests-BraintreeCoreTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests-BraintreeCoreTests.debug.xcconfig"; path = "Target Support Files/Pods-Tests-BraintreeCoreTests/Pods-Tests-BraintreeCoreTests.debug.xcconfig"; sourceTree = "<group>"; };
5708E0A528809AD9007946B9 /* BTJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTJSON.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1964,6 +1968,8 @@
8053F05629FAD4790076F988 /* Encodable+Dictionary_Tests.swift */,
A908436924FD88C3004134CA /* Helpers */,
A9E5C22824FD6D0800EE691F /* Info.plist */,
45227FC32C330FDE00A15018 /* MockURLSessionTask.swift */,
45227FC62C33104100A15018 /* MockBTHTTPNetworkTiming.swift */,
);
path = BraintreeCoreTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -3556,6 +3562,7 @@
BEBC6F3229380B82004E25A0 /* BTExceptionCatcher.m in Sources */,
8053F05429FAB6B00076F988 /* FPTIBatchData_Tests.swift in Sources */,
A908436D24FD8A59004134CA /* BTPaymentMethodNonceParser_Tests.swift in Sources */,
45227FC52C330FDE00A15018 /* MockURLSessionTask.swift in Sources */,
A908436B24FD89DA004134CA /* BTJSON_Tests.swift in Sources */,
BEBC6F262937A510004E25A0 /* BTClientMetadata_Tests.swift in Sources */,
A908436624FD8791004134CA /* BTConfiguration_Tests.swift in Sources */,
Expand All @@ -3571,6 +3578,7 @@
BE54C0352912B6BC009C6CEE /* BTHTTPTestProtocol.swift in Sources */,
80C10F832BE090AA00BFA2EE /* ConfigurationCache_Tests.swift in Sources */,
8087C10F2BFBACCA0020FC2E /* TokenizationKey_Tests.swift in Sources */,
45227FC72C33104100A15018 /* MockBTHTTPNetworkTiming.swift in Sources */,
BEDA91A028EDDE64007441D9 /* FakeAnalyticsService.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
18 changes: 17 additions & 1 deletion Sources/BraintreeCore/BTHTTP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,14 @@ class BTHTTP: NSObject, URLSessionTaskDelegate {
metrics.transactionMetrics.forEach { transaction in
if let startDate = transaction.fetchStartDate,
let endDate = transaction.responseEndDate,
let path = transaction.request.url?.path {
var path = transaction.request.url?.path {

if path.contains("graphql"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we able to add a unit test for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, added: df95e39

let data = task.originalRequest?.httpBody,
let mutationName = getGraphQLMutationName(data) {
path = mutationName
}

networkTimingDelegate?.fetchAPITiming(
path: path,
connectionStartTime: transaction.connectStartDate?.utcTimestampMilliseconds,
Expand All @@ -401,4 +408,13 @@ class BTHTTP: NSObject, URLSessionTaskDelegate {
}
}
}

private func getGraphQLMutationName(_ data: Data) -> String? {
let json = try? JSONSerialization.jsonObject(with: data)
let body = BTJSON(value: json)

guard let mutationName = body["operationName"].asString() else { return nil }

return "mutation \(mutationName)"
}
}
30 changes: 30 additions & 0 deletions UnitTests/BraintreeCoreTests/BTHTTP_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,36 @@ final class BTHTTP_Tests: XCTestCase {
}
}
}

func testURLSessionTaskDidFinishCollectingMetrics() {
let mockDelegate = MockNetworkTimingDelegate()
http?.networkTimingDelegate = mockDelegate

var originalRequest = URLRequest(url: URL(string: "https://example.com/graphql")!)
originalRequest.httpBody = """
{
"operationName": "TestMutation"
}
""".data(using: .utf8)
let task = testURLSession.dataTask(with: originalRequest)

let transactionMetrics = MockURLSessionTaskTransactionMetrics()
transactionMetrics.mockConnectStartDate = Date()
transactionMetrics.mockFetchStartDate = Date()
Comment on lines +766 to +767
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just curious, how are these two values different? 👀

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FetchStartDate: The time when the task started fetching the resource, from the server or locally.
ConnectStartDate: The time immediately before the task started establishing a TCP connection to the server.

Apple has an amazing graphic in their documentation that would explain it better. Apple doc reference

transactionMetrics.mockResponseEndDate = Date().addingTimeInterval(1)
transactionMetrics.mockRequest = URLRequest(url: URL(string: "https://example.com/graphql")!)

let metrics = MockURLSessionTaskMetrics(transactionMetrics: [transactionMetrics])

http?.urlSession(testURLSession, task: task, didFinishCollecting: metrics)

XCTAssertTrue(mockDelegate.didCallFetchAPITiming)
XCTAssertEqual(mockDelegate.receivedPath, "mutation TestMutation")
XCTAssertNotNil(mockDelegate.receivedConnectionStartTime)
XCTAssertNotNil(mockDelegate.receivedRequestStartTime)
XCTAssertNotNil(mockDelegate.receivedStartTime)
XCTAssertNotNil(mockDelegate.receivedEndTime)
}

// MARK: - Helper Methods

Expand Down
20 changes: 20 additions & 0 deletions UnitTests/BraintreeCoreTests/MockBTHTTPNetworkTiming.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@testable import BraintreeCore
import Foundation

class MockNetworkTimingDelegate: BTHTTPNetworkTiming {
var didCallFetchAPITiming = false
var receivedPath: String?
var receivedConnectionStartTime: Int?
var receivedRequestStartTime: Int?
var receivedStartTime: Int?
var receivedEndTime: Int?

func fetchAPITiming(path: String, connectionStartTime: Int?, requestStartTime: Int?, startTime: Int, endTime: Int) {
didCallFetchAPITiming = true
receivedPath = path
receivedConnectionStartTime = connectionStartTime
receivedRequestStartTime = requestStartTime
receivedStartTime = startTime
receivedEndTime = endTime
}
}
38 changes: 38 additions & 0 deletions UnitTests/BraintreeCoreTests/MockURLSessionTask.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Foundation

class MockURLSessionTaskTransactionMetrics: URLSessionTaskTransactionMetrics {

var mockConnectStartDate: Date?
var mockFetchStartDate: Date?
var mockResponseEndDate: Date?
var mockRequest: URLRequest?

override var connectStartDate: Date? {
mockConnectStartDate
}

override var fetchStartDate: Date? {
mockFetchStartDate
}

override var responseEndDate: Date? {
mockResponseEndDate
}

override var request: URLRequest {
mockRequest ?? URLRequest(url: URL(string: "https://example.com")!)
}
}

class MockURLSessionTaskMetrics: URLSessionTaskMetrics {
var mockTransactionMetrics: [URLSessionTaskTransactionMetrics]

/// For testing only
init(transactionMetrics: [URLSessionTaskTransactionMetrics]) {
self.mockTransactionMetrics = transactionMetrics
}

override var transactionMetrics: [URLSessionTaskTransactionMetrics] {
mockTransactionMetrics
}
}
Loading