Skip to content

Commit

Permalink
Merge pull request #46 from alexanderjordanbaker/XcodeAppStoreServerA…
Browse files Browse the repository at this point in the history
…PIClient

Use placeholder URL when LOCAL_TESTING environment option is provided
  • Loading branch information
alexanderjordanbaker committed Apr 8, 2024
2 parents cb43658 + 1ef30ec commit 9d13ec2
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 14 deletions.
20 changes: 19 additions & 1 deletion Sources/AppStoreServerLibrary/AppStoreServerAPIClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ import NIOHTTP1
import NIOFoundationCompat

public class AppStoreServerAPIClient {

public enum ConfigurationError: Error {
/// Xcode is not a supported environment for an AppStoreServerAPIClient
case invalidEnvironment
}

private static let userAgent = "app-store-server-library/swift/2.0.0"
private static let productionUrl = "https://api.storekit.itunes.apple.com"
private static let sandboxUrl = "https://api.storekit-sandbox.itunes.apple.com"
private static let localTestingUrl = "https://local-testing-base-url"
private static let appStoreConnectAudience = "appstoreconnect-v1"

private let signingKey: P256.Signing.PrivateKey
Expand All @@ -31,7 +37,19 @@ public class AppStoreServerAPIClient {
self.keyId = keyId
self.issuerId = issuerId
self.bundleId = bundleId
self.url = environment == Environment.production ? AppStoreServerAPIClient.productionUrl : AppStoreServerAPIClient.sandboxUrl
switch(environment) {
case .xcode:
throw ConfigurationError.invalidEnvironment
case .production:
self.url = AppStoreServerAPIClient.productionUrl
break
case .localTesting:
self.url = AppStoreServerAPIClient.localTestingUrl
break
case .sandbox:
self.url = AppStoreServerAPIClient.sandboxUrl
break
}
self.client = .init()
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/AppStoreServerLibrary/Models/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ public enum Environment: String, Decodable, Encodable, Hashable {
case sandbox = "Sandbox"
case production = "Production"
case xcode = "Xcode"
case localTesting = "LocalTesting"
case localTesting = "LocalTesting" // Used for unit testing
}
39 changes: 27 additions & 12 deletions Tests/AppStoreServerLibraryTests/AppStoreServerAPIClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testExtendRenewalDateForAllActiveSubscribers() async throws {
let client = try getClientWithBody("resources/models/extendRenewalDateForAllActiveSubscribersResponse.json") { request, body in
XCTAssertEqual(.POST, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/subscriptions/extend/mass", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/subscriptions/extend/mass", request.url)
let decodedJson = try! JSONSerialization.jsonObject(with: body!) as! [String: Any]
XCTAssertEqual(45, decodedJson["extendByDays"] as! Int)
XCTAssertEqual(1, decodedJson["extendReasonCode"] as! Int)
Expand Down Expand Up @@ -44,7 +44,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testExtendSubscriptionRenewalDate() async throws {
let client = try getClientWithBody("resources/models/extendSubscriptionRenewalDateResponse.json") { request, body in
XCTAssertEqual(.PUT, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/subscriptions/extend/4124214", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/subscriptions/extend/4124214", request.url)
let decodedJson = try! JSONSerialization.jsonObject(with: body!) as! [String: Any]
XCTAssertEqual(45, decodedJson["extendByDays"] as! Int)
XCTAssertEqual(1, decodedJson["extendReasonCode"] as! Int)
Expand All @@ -71,7 +71,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testGetAllSubscriptionStatuses() async throws {
let client = try getClientWithBody("resources/models/getAllSubscriptionStatusesResponse.json") { request, body in
XCTAssertEqual(.GET, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/subscriptions/4321?status=2&status=1", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/subscriptions/4321?status=2&status=1", request.url)
XCTAssertNil(request.body)
}

Expand Down Expand Up @@ -116,7 +116,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testGetRefundHistory() async throws {
let client = try getClientWithBody("resources/models/getRefundHistoryResponse.json") { request, body in
XCTAssertEqual(.GET, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v2/refund/lookup/555555?revision=revision_input", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v2/refund/lookup/555555?revision=revision_input", request.url)
XCTAssertNil(request.body)
}

Expand All @@ -134,7 +134,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testGetStatusOfSubscriptionRenewalDateExtensions() async throws {
let client = try getClientWithBody("resources/models/getStatusOfSubscriptionRenewalDateExtensionsResponse.json") { request, body in
XCTAssertEqual(.GET, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/subscriptions/extend/mass/20fba8a0-2b80-4a7d-a17f-85c1854727f8/com.example.product", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/subscriptions/extend/mass/20fba8a0-2b80-4a7d-a17f-85c1854727f8/com.example.product", request.url)
XCTAssertNil(request.body)
}

Expand All @@ -154,7 +154,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testGetTestNotificationStatus() async throws {
let client = try getClientWithBody("resources/models/getTestNotificationStatusResponse.json") { request, body in
XCTAssertEqual(.GET, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/notifications/test/8cd2974c-f905-492a-bf9a-b2f47c791d19", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/notifications/test/8cd2974c-f905-492a-bf9a-b2f47c791d19", request.url)
XCTAssertNil(request.body)
}

Expand All @@ -180,7 +180,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testGetNotificationHistory() async throws {
let client = try getClientWithBody("resources/models/getNotificationHistoryResponse.json") { request, body in
XCTAssertEqual(.POST, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/notifications/history?paginationToken=a036bc0e-52b8-4bee-82fc-8c24cb6715d6", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/notifications/history?paginationToken=a036bc0e-52b8-4bee-82fc-8c24cb6715d6", request.url)

let decodedJson = try! JSONSerialization.jsonObject(with: body!) as! [String: Any]
XCTAssertEqual(1698148900000, decodedJson["startDate"] as! Int)
Expand Down Expand Up @@ -283,7 +283,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testGetTransactionInfo() async throws {
let client = try getClientWithBody("resources/models/transactionInfoResponse.json") { request, body in
XCTAssertEqual(.GET, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/1234", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/transactions/1234", request.url)
XCTAssertNil(request.body)
}

Expand All @@ -299,7 +299,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testLookUpOrderId() async throws {
let client = try getClientWithBody("resources/models/lookupOrderIdResponse.json") { request, body in
XCTAssertEqual(.GET, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/lookup/W002182", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/lookup/W002182", request.url)
XCTAssertNil(request.body)
}

Expand All @@ -317,7 +317,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testRequestTestNotification() async throws {
let client = try getClientWithBody("resources/models/requestTestNotificationResponse.json") { request, body in
XCTAssertEqual(.POST, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/notifications/test", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/notifications/test", request.url)
XCTAssertNil(request.body)
}

Expand All @@ -333,7 +333,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
public func testSendConsumptionData() async throws {
let client = try getAppStoreServerAPIClient("") { request, body in
XCTAssertEqual(.PUT, request.method)
XCTAssertEqual("https://api.storekit-sandbox.itunes.apple.com/inApps/v1/transactions/consumption/49571273", request.url)
XCTAssertEqual("https://local-testing-base-url/inApps/v1/transactions/consumption/49571273", request.url)
XCTAssertEqual(["application/json"], request.headers["Content-Type"])
let decodedJson = try! JSONSerialization.jsonObject(with: body!) as! [String: Any]
XCTAssertEqual(true, decodedJson["customerConsented"] as! Bool)
Expand Down Expand Up @@ -495,6 +495,17 @@ final class AppStoreServerAPIClientTests: XCTestCase {
XCTAssertNotNil(causedBy)
}

public func testXcodeEnvironmentForAppStoreServerAPIClient() async throws {
let key = getSigningKey()
do {
let client = try AppStoreServerAPIClient(signingKey: key, keyId: "keyId", issuerId: "issuerId", bundleId: "com.example", environment: Environment.xcode)
XCTAssertTrue(false)
return
} catch (let e) {
XCTAssertEqual(AppStoreServerAPIClient.ConfigurationError.invalidEnvironment, e as! AppStoreServerAPIClient.ConfigurationError)
}
}

public func getClientWithBody(_ path: String, _ requestVerifier: @escaping RequestVerifier) throws -> AppStoreServerAPIClient {
let body = TestingUtility.readFile(path)
return try getAppStoreServerAPIClient(body, requestVerifier)
Expand All @@ -505,7 +516,7 @@ final class AppStoreServerAPIClientTests: XCTestCase {
}

private func getAppStoreServerAPIClient(_ body: String, _ status: HTTPResponseStatus, _ requestVerifier: RequestVerifier?) throws -> AppStoreServerAPIClient {
let key = TestingUtility.readFile("resources/certs/testSigningKey.p8")
let key = getSigningKey()
let client = try AppStoreServerAPIClientTest(signingKey: key, keyId: "keyId", issuerId: "issuerId", bundleId: "com.example", environment: Environment.localTesting) { request, requestBody in
try requestVerifier.map { try $0(request, requestBody) }
let headers = [("Content-Type", "application/json")]
Expand All @@ -515,6 +526,10 @@ final class AppStoreServerAPIClientTests: XCTestCase {
return client;
}

private func getSigningKey() -> String {
return TestingUtility.readFile("resources/certs/testSigningKey.p8")
}

class AppStoreServerAPIClientTest: AppStoreServerAPIClient {

private var requestOverride: ((HTTPClientRequest, Foundation.Data?) throws -> HTTPClientResponse)?
Expand Down

0 comments on commit 9d13ec2

Please sign in to comment.