From 41c0039e985863a431080346156296867e24697c Mon Sep 17 00:00:00 2001 From: sanchayata-jain-cko <146939622+sanchayata-jain-cko@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:17:11 +0000 Subject: [PATCH 1/5] enable telemetry --- .vscode/launch.json | 20 ++ lib/Checkout/AbstractCheckoutSdkBuilder.php | 14 +- lib/Checkout/ApiClient.php | 243 +++++++++++++++--- lib/Checkout/CheckoutConfiguration.php | 15 +- lib/Checkout/CheckoutOAuthSdkBuilder.php | 4 +- lib/Checkout/CheckoutStaticKeysSdkBuilder.php | 4 +- lib/Checkout/Common/RequestMetrics.php | 17 ++ lib/Checkout/Common/TelemetryQueue.php | 48 ++++ lib/Checkout/OAuthSdkCredentials.php | 7 + test/Checkout/Tests/TelemetryTest.php | 0 10 files changed, 327 insertions(+), 45 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 lib/Checkout/Common/RequestMetrics.php create mode 100644 lib/Checkout/Common/TelemetryQueue.php create mode 100644 test/Checkout/Tests/TelemetryTest.php diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..c726ebb5 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003, + "pathMappings": { + "/var/www/html": "${workspaceFolder}" + }, + "log": true, + "xdebugSettings": { + "max_children": 128, + "max_data": 512, + "max_depth": 3 + } + } + ] +} diff --git a/lib/Checkout/AbstractCheckoutSdkBuilder.php b/lib/Checkout/AbstractCheckoutSdkBuilder.php index 2769b4fb..738bfbda 100644 --- a/lib/Checkout/AbstractCheckoutSdkBuilder.php +++ b/lib/Checkout/AbstractCheckoutSdkBuilder.php @@ -13,12 +13,14 @@ abstract class AbstractCheckoutSdkBuilder protected $environmentSubdomain; protected $httpClientBuilder; protected $logger; + protected $enableTelemetry; public function __construct() { $this->environment = Environment::sandbox(); $this->httpClientBuilder = new DefaultHttpClientBuilder([]); $this->setDefaultLogger(); + $this->enableTelemetry = true; } /** @@ -50,6 +52,15 @@ public function httpClientBuilder(HttpClientBuilderInterface $httpClientBuilder) $this->httpClientBuilder = $httpClientBuilder; return $this; } + /** + * @param bool $enableTelemetry + * @return $this + */ + public function enableTelemetry($enableTelemetry) + { + $this->enableTelemetry = $enableTelemetry; + return $this; + } /** * @param LoggerInterface $logger @@ -70,7 +81,8 @@ protected function getCheckoutConfiguration() $this->getSdkCredentials(), $this->environment, $this->httpClientBuilder, - $this->logger + $this->logger, + $this->enableTelemetry ); } diff --git a/lib/Checkout/ApiClient.php b/lib/Checkout/ApiClient.php index b4762793..9a9ba972 100644 --- a/lib/Checkout/ApiClient.php +++ b/lib/Checkout/ApiClient.php @@ -4,6 +4,7 @@ use Checkout\Common\AbstractQueryFilter; use Checkout\Files\FileRequest; +use Common\TelemetryQueue; use Exception; use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Psr7\Response; @@ -21,6 +22,10 @@ class ApiClient private $baseUri; + private $enableTelemetry; + + private $requestMetricsQueue; + public function __construct(CheckoutConfiguration $configuration, $baseUri = null) { $this->configuration = $configuration; @@ -28,6 +33,8 @@ public function __construct(CheckoutConfiguration $configuration, $baseUri = nul $this->jsonSerializer = new JsonSerializer(); $this->logger = $this->configuration->getLogger(); $this->baseUri = $baseUri != null ? $baseUri : $this->configuration->getEnvironment()->getBaseUri(); + $this->enableTelemetry = $this->configuration->isEnableTelemetry(); + $this->requestMetricsQueue = new TelemetryQueue(); } /** @@ -132,32 +139,39 @@ public function submitFileFilesApi($path, FileRequest $fileRequest, SdkAuthoriza return $this->submit($path, $fileRequest, $authorization, "path"); } - /** - * @param $path - * @param FileRequest $fileRequest - * @param SdkAuthorization $authorization - * @param $multipart - * @return array - * @throws CheckoutApiException - */ - private function submit($path, FileRequest $fileRequest, SdkAuthorization $authorization, $multipart) + private function handleRequest($method, $path, SdkAuthorization $authorization, array $requestOptions) { try { - $this->logger->info("POST " . $path . " file: " . $fileRequest->file); - $headers = $this->getHeaders($authorization, null, null); - $response = $this->client->request("POST", $this->getRequestUrl($path), [ - "verify" => false, - "headers" => $headers, - "multipart" => [ - [ - "name" => $multipart, - "contents" => fopen($fileRequest->file, "r") - ], - [ - "name" => "purpose", - "contents" => $fileRequest->purpose - ] - ]]); + $headers = $requestOptions['headers']; + + if ($this->enableTelemetry) { + $currentRequestId = uniqid(); + $lastRequestMetric = $this->requestMetricsQueue->dequeue(); + + if ($lastRequestMetric !== null) { + $lastRequestMetric->requestId = $currentRequestId; + $headers["Cko-Sdk-Telemetry"] = base64_encode(json_encode([ + 'prev-request-id' => $lastRequestMetric->prevRequestId, + 'prev-request-duration' => $lastRequestMetric->prevRequestDuration + ])); + } + + $startTime = microtime(true); + $response = $this->client->request($method, $this->getRequestUrl($path), array_merge( + $requestOptions, + ['headers' => $headers] + )); + $duration = (int)((microtime(true) - $startTime) * 1000); + + $lastRequestMetric->prevRequestDuration = $duration; + $lastRequestMetric->prevRequestId = $currentRequestId; + $this->requestMetricsQueue->enqueue($lastRequestMetric); + } else { + $response = $this->client->request($method, $this->getRequestUrl($path), array_merge( + $requestOptions, + ['headers' => $headers] + )); + } return $this->getResponseContents($response); } catch (Exception $e) { $this->logger->error($path . " error: " . $e->getMessage()); @@ -168,6 +182,38 @@ private function submit($path, FileRequest $fileRequest, SdkAuthorization $autho } } + /** + * @param $path + * @param FileRequest $fileRequest + * @param SdkAuthorization $authorization + * @param $multipart + * @return array + * @throws CheckoutApiException + */ + private function submit($path, FileRequest $fileRequest, SdkAuthorization $authorization, $multipart) + { + // Keep specific logging in submit + $this->logger->info("POST " . $path . " file: " . $fileRequest->file); + + $headers = $this->getHeaders($authorization, null, null, null); + $requestOptions = [ + "verify" => false, + "headers" => $headers, + "multipart" => [ + [ + "name" => $multipart, + "contents" => fopen($fileRequest->file, "r") + ], + [ + "name" => "purpose", + "contents" => $fileRequest->purpose + ] + ] + ]; + + return $this->handleRequest("POST", $path, $authorization, $requestOptions); + } + /** * @param string $method * @param string $path @@ -179,24 +225,135 @@ private function submit($path, FileRequest $fileRequest, SdkAuthorization $autho */ private function invoke($method, $path, $body, SdkAuthorization $authorization, $idempotencyKey = null) { - try { - $this->logger->info($method . " " . $path); - $headers = $this->getHeaders($authorization, "application/json", $idempotencyKey); - $response = $this->client->request($method, $this->getRequestUrl($path), [ - "verify" => false, - "body" => $body, - "headers" => $headers - ]); - return $this->getResponseContents($response); - } catch (Exception $e) { - $this->logger->error($path . " error: " . $e->getMessage()); - if ($e instanceof RequestException) { - throw CheckoutApiException::from($e); - } - throw new CheckoutApiException($e); - } + // Keep specific logging in invoke + $this->logger->info($method . " " . $path); + + $headers = $this->getHeaders($authorization, "application/json", $idempotencyKey, null); + $requestOptions = [ + "verify" => false, + "body" => $body, + "headers" => $headers + ]; + + return $this->handleRequest($method, $path, $authorization, $requestOptions); } + // /** + // * @param $path + // * @param FileRequest $fileRequest + // * @param SdkAuthorization $authorization + // * @param $multipart + // * @return array + // * @throws CheckoutApiException + // */ + // private function submit($path, FileRequest $fileRequest, SdkAuthorization $authorization, $multipart) + // { + // try { + // $this->logger->info("POST " . $path . " file: " . $fileRequest->file); + // $headers = $this->getHeaders($authorization, null, null); + // if ($this->enableTelemetry) { + // $currentRequestId = uniqid(); //TODO: look at how uuid is made in go and copy + // $lastRequestMetric = $this->requestMetricsQueue->dequeue(); + + // if ($lastRequestMetric !== null) { + // $lastRequestMetric->requestId = $currentRequestId; + // $headers[self::CKO_TELEMETRY_HEADER] = base64_encode(json_encode([ + // 'prev-request-id' => $lastRequestMetric->prevRequestId, + // 'prev-request-duration' => $lastRequestMetric->prevRequestDuration + // ])); + // } + + // $startTime = microtime(true); + // $response = $this->client->request("POST", $this->getRequestUrl($path), [ + // "verify" => false, + // "headers" => $headers, + // "multipart" => [ + // [ + // "name" => $multipart, + // "contents" => fopen($fileRequest->file, "r") + // ], + // [ + // "name" => "purpose", + // "contents" => $fileRequest->purpose + // ] + // ]]); + + // $duration = (int)((microtime(true) - $startTime) * 1000); + + // $lastRequestMetric->prevRequestDuration = $duration; + // $lastRequestMetric->prevRequestId = $currentRequestId; + // $this->requestMetricsQueue->enqueue($lastRequestMetric); + // } else { + // $response = $this->client->request("POST", $this->getRequestUrl($path), [ + // "verify" => false, + // "headers" => $headers, + // "multipart" => [ + // [ + // "name" => $multipart, + // "contents" => fopen($fileRequest->file, "r") + // ], + // [ + // "name" => "purpose", + // "contents" => $fileRequest->purpose + // ] + // ]]); + // } + // return $this->getResponseContents($response); + // } catch (Exception $e) { + // $this->logger->error($path . " error: " . $e->getMessage()); + // if ($e instanceof RequestException) { + // throw CheckoutApiException::from($e); + // } + // throw new CheckoutApiException($e); + // } + // } + + // private function invoke($method, $path, $body, SdkAuthorization $authorization, $idempotencyKey = null) + // { + // try { + // $this->logger->info($method . " " . $path); + // $headers = $this->getHeaders($authorization, "application/json", $idempotencyKey); + // if ($this->enableTelemetry) { + // // Generate current request ID and handle telemetry only if enabled + // $currentRequestId = uniqid(); + // $lastRequestMetric = $this->requestMetricsQueue->dequeue(); + + // if ($lastRequestMetric !== null) { + // $lastRequestMetric->requestId = $currentRequestId; + // $headers[self::CKO_TELEMETRY_HEADER] = base64_encode(json_encode([ + // 'prev-request-id' => $lastRequestMetric->prevRequestId, + // 'prev-request-duration' => $lastRequestMetric->prevRequestDuration + // ])); + // } + + // $startTime = microtime(true); + // $response = $this->client->request($method, $this->getRequestUrl($path), [ + // "verify" => false, + // "body" => $body, + // "headers" => $headers + // ]); + // $duration = (int)((microtime(true) - $startTime) * 1000); + + // $lastRequestMetric->prevRequestDuration = $duration; + // $lastRequestMetric->prevRequestId = $currentRequestId; + // $this->requestMetricsQueue->enqueue($lastRequestMetric); + // } else { + // $response = $this->client->request($method, $this->getRequestUrl($path), [ + // "verify" => false, + // "body" => $body, + // "headers" => $headers + // ]); + // } + // return $this->getResponseContents($response); + // } catch (Exception $e) { + // $this->logger->error($path . " error: " . $e->getMessage()); + // if ($e instanceof RequestException) { + // throw CheckoutApiException::from($e); + // } + // throw new CheckoutApiException($e); + // } + // } + /** * @param string $path * @return string @@ -210,10 +367,11 @@ private function getRequestUrl($path) * @param SdkAuthorization $authorization * @param string|null $contentType * @param string|null $idempotencyKey + * @param string|null $telemetryData * @return array * @throws CheckoutAuthorizationException */ - private function getHeaders(SdkAuthorization $authorization, $contentType, $idempotencyKey) + private function getHeaders(SdkAuthorization $authorization, $contentType, $idempotencyKey, $telemetryData) { $headers = [ "User-agent" => CheckoutUtils::PROJECT_NAME . "/" . CheckoutUtils::PROJECT_VERSION, @@ -226,6 +384,9 @@ private function getHeaders(SdkAuthorization $authorization, $contentType, $idem if (!empty($idempotencyKey)) { $headers["Cko-Idempotency-Key"] = $idempotencyKey; } + if (!empty($telemetryData)) { + $headers["Cko-Sdk-Telemetry"] = base64_encode(json_encode($telemetryData)); + } return $headers; } diff --git a/lib/Checkout/CheckoutConfiguration.php b/lib/Checkout/CheckoutConfiguration.php index 20cc0e31..b44f5e6d 100644 --- a/lib/Checkout/CheckoutConfiguration.php +++ b/lib/Checkout/CheckoutConfiguration.php @@ -15,24 +15,29 @@ final class CheckoutConfiguration private $httpClientBuilder; private $logger; + + private $enableTelemetry; /** * @param SdkCredentialsInterface $sdkCredentials * @param Environment $environment * @param HttpClientBuilderInterface $httpClientBuilder * @param LoggerInterface $logger + * @param bool $enableTelemetry */ public function __construct( SdkCredentialsInterface $sdkCredentials, Environment $environment, HttpClientBuilderInterface $httpClientBuilder, - LoggerInterface $logger + LoggerInterface $logger, + $enableTelemetry = true ) { $this->sdkCredentials = $sdkCredentials; $this->environment = $environment; $this->httpClientBuilder = $httpClientBuilder; $this->logger = $logger; $this->environmentSubdomain = null; + $this ->enableTelemetry = $enableTelemetry; } /** @@ -79,4 +84,12 @@ public function getLogger() { return $this->logger; } + + /** + * @return bool + */ + public function isEnableTelemetry() + { + return $this->enableTelemetry; + } } diff --git a/lib/Checkout/CheckoutOAuthSdkBuilder.php b/lib/Checkout/CheckoutOAuthSdkBuilder.php index a180816f..4bc01915 100644 --- a/lib/Checkout/CheckoutOAuthSdkBuilder.php +++ b/lib/Checkout/CheckoutOAuthSdkBuilder.php @@ -84,8 +84,10 @@ public function build() $this->getSdkCredentials(), $this->environment, $this->httpClientBuilder, - $this->logger + $this->logger, + $this->enableTelemetry ); + // $configuration = $this->getCheckoutConfiguration(); if ($this->environmentSubdomain !== null) { $configuration->setEnvironmentSubdomain($this->environmentSubdomain); } diff --git a/lib/Checkout/CheckoutStaticKeysSdkBuilder.php b/lib/Checkout/CheckoutStaticKeysSdkBuilder.php index ec8b6aa4..d0dc639a 100644 --- a/lib/Checkout/CheckoutStaticKeysSdkBuilder.php +++ b/lib/Checkout/CheckoutStaticKeysSdkBuilder.php @@ -48,8 +48,10 @@ public function build() $this->getSdkCredentials(), $this->environment, $this->httpClientBuilder, - $this->logger + $this->logger, + $this->enableTelemetry ); + // $configuration = $this->getCheckoutConfiguration(); if ($this->environmentSubdomain !== null) { $configuration->setEnvironmentSubdomain($this->environmentSubdomain); } diff --git a/lib/Checkout/Common/RequestMetrics.php b/lib/Checkout/Common/RequestMetrics.php new file mode 100644 index 00000000..1c8ca314 --- /dev/null +++ b/lib/Checkout/Common/RequestMetrics.php @@ -0,0 +1,17 @@ +prevRequestId = $prevRequestId; + $this->requestId = $requestId; + $this->prevRequestDuration = $prevRequestDuration; + } +} diff --git a/lib/Checkout/Common/TelemetryQueue.php b/lib/Checkout/Common/TelemetryQueue.php new file mode 100644 index 00000000..4468315b --- /dev/null +++ b/lib/Checkout/Common/TelemetryQueue.php @@ -0,0 +1,48 @@ +queue = []; + $this->mutex = fopen(sys_get_temp_dir() . '/telemetry_queue.lock', 'w+'); + } + + public function __destruct() + { + if ($this->mutex) { + fclose($this->mutex); + } + } + + public function enqueue($metrics) + { + flock($this->mutex, LOCK_EX); + try { + if (count($this->queue) < self::MAX_COUNT_IN_TELEMETRY_QUEUE) { + $this->queue[] = $metrics; + } + } finally { + flock($this->mutex, LOCK_UN); + } + } + + public function dequeue() + { + flock($this->mutex, LOCK_EX); + try { + if (empty($this->queue)) { + return null; + } + return array_shift($this->queue); + } finally { + flock($this->mutex, LOCK_UN); + } + } +} diff --git a/lib/Checkout/OAuthSdkCredentials.php b/lib/Checkout/OAuthSdkCredentials.php index 85e2147d..9b188726 100644 --- a/lib/Checkout/OAuthSdkCredentials.php +++ b/lib/Checkout/OAuthSdkCredentials.php @@ -85,10 +85,14 @@ public function getAuthorization($authorizationType) */ private function getAccessToken() { + printf("ClientId: %s\n", $this->clientId); + printf("ClientSecret: %s\n", $this->clientSecret); + if (!is_null($this->accessToken) && $this->accessToken->isValid()) { return $this->accessToken; } try { + printf("Scope string: %s\n", implode(" ", $this->scopes)); $response = $this->client->request("POST", $this->authorizationUri, [ "verify" => false, "headers" => [ @@ -101,7 +105,10 @@ private function getAccessToken() "scope" => implode(" ", $this->scopes) ] ]); + printf($response); $body = json_decode($response->getBody(), true); + printf("This is a body!"); + print_r($body); $expirationDate = new DateTime(); $expirationDate->add(new DateInterval("PT" . $body["expires_in"] . "S")); $this->accessToken = new OAuthAccessToken($body["access_token"], $expirationDate); diff --git a/test/Checkout/Tests/TelemetryTest.php b/test/Checkout/Tests/TelemetryTest.php new file mode 100644 index 00000000..e69de29b From c836f80d925b753cf40d889eda67b4a02b96e8db Mon Sep 17 00:00:00 2001 From: sanchayata-jain-cko <146939622+sanchayata-jain-cko@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:39:42 +0000 Subject: [PATCH 2/5] added test for enable telemetry --- lib/Checkout/ApiClient.php | 10 +- lib/Checkout/Common/RequestMetrics.php | 4 +- lib/Checkout/Common/TelemetryQueue.php | 2 +- .../CheckoutStaticKeysPreviousSdkBuilder.php | 3 +- test/Checkout/Tests/TelemetryTest.php | 158 ++++++++++++++++++ 5 files changed, 170 insertions(+), 7 deletions(-) diff --git a/lib/Checkout/ApiClient.php b/lib/Checkout/ApiClient.php index 9a9ba972..a4baa896 100644 --- a/lib/Checkout/ApiClient.php +++ b/lib/Checkout/ApiClient.php @@ -3,8 +3,9 @@ namespace Checkout; use Checkout\Common\AbstractQueryFilter; +use Checkout\Common\RequestMetrics; use Checkout\Files\FileRequest; -use Common\TelemetryQueue; +use Checkout\Common\TelemetryQueue; use Exception; use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Psr7\Response; @@ -146,9 +147,11 @@ private function handleRequest($method, $path, SdkAuthorization $authorization, if ($this->enableTelemetry) { $currentRequestId = uniqid(); - $lastRequestMetric = $this->requestMetricsQueue->dequeue(); + $lastRequestMetric = new RequestMetrics(); + $dequeuedMetric = $this->requestMetricsQueue->dequeue(); + - if ($lastRequestMetric !== null) { + if ($dequeuedMetric !== null) { $lastRequestMetric->requestId = $currentRequestId; $headers["Cko-Sdk-Telemetry"] = base64_encode(json_encode([ 'prev-request-id' => $lastRequestMetric->prevRequestId, @@ -238,6 +241,7 @@ private function invoke($method, $path, $body, SdkAuthorization $authorization, return $this->handleRequest($method, $path, $authorization, $requestOptions); } + // /** // * @param $path // * @param FileRequest $fileRequest diff --git a/lib/Checkout/Common/RequestMetrics.php b/lib/Checkout/Common/RequestMetrics.php index 1c8ca314..8d95ccf8 100644 --- a/lib/Checkout/Common/RequestMetrics.php +++ b/lib/Checkout/Common/RequestMetrics.php @@ -1,6 +1,6 @@ prevRequestId = $prevRequestId; $this->requestId = $requestId; diff --git a/lib/Checkout/Common/TelemetryQueue.php b/lib/Checkout/Common/TelemetryQueue.php index 4468315b..a20f6a2e 100644 --- a/lib/Checkout/Common/TelemetryQueue.php +++ b/lib/Checkout/Common/TelemetryQueue.php @@ -1,6 +1,6 @@ getSdkCredentials(), $this->environment, $this->httpClientBuilder, - $this->logger + $this->logger, + $this->enableTelemetry ); if ($this->environmentSubdomain !== null) { $configuration->setEnvironmentSubdomain($this->environmentSubdomain); diff --git a/test/Checkout/Tests/TelemetryTest.php b/test/Checkout/Tests/TelemetryTest.php index e69de29b..7a678512 100644 --- a/test/Checkout/Tests/TelemetryTest.php +++ b/test/Checkout/Tests/TelemetryTest.php @@ -0,0 +1,158 @@ +container = []; + + $this->mockHandler = new MockHandler(); + + $handlerStack = HandlerStack::create($this->mockHandler); + + $history = Middleware::history($this->container); + $handlerStack->push($history); + } + + /** + * Counts requests that contain a specific header + */ + private function countRequestsWithHeader($header) + { + $count = 0; + foreach ($this->container as $transaction) { + if ($transaction['request']->hasHeader($header)) { + $count++; + } + } + return $count; + } + + /** + * Creates a CheckoutApi instance with the specified telemetry setting + */ + private function createCheckoutApi($enableTelemetry) + { + $handlerStack = HandlerStack::create($this->mockHandler); + $history = Middleware::history($this->container); + $handlerStack->push($history); + + $client = new Client(['handler' => $handlerStack]); + + // Set up the mock builder to return this client + $httpBuilder = $this->createMock(HttpClientBuilderInterface::class); + $httpBuilder->expects($this->once()) + ->method("getClient") + ->willReturn($client); + $builder = CheckoutSdk::builder() + ->previous() + ->staticKeys() + ->publicKey(parent::$validPreviousPk) + ->secretKey(parent::$validPreviousSk) + ->httpClientBuilder($httpBuilder) + ->environment(Environment::sandbox()); + + if (!$enableTelemetry) { + $builder = $builder->enableTelemetry(false); + } else { + $builder = $builder->enableTelemetry(true); + } + + // Add mock responses to the handler for the number of requests we expect + for ($i = 0; $i < 3; $i++) { + $this->mockHandler->append(new Response(200, [], '{"data": []}')); + } + + return $builder->build(); + } + + /** + * @test + */ + public function shouldSendTelemetryByDefault() + { + $checkoutApi = $this->createCheckoutApi(true); + + for ($i = 0; $i < 3; $i++) { + $checkoutApi->getEventsClient()->retrieveAllEventTypes(); + } + + // Telemetry headers should be present in all requests except the first + $expectedTelemetryHeaderCount = 2; + $telemetryHeaderCount = $this->countRequestsWithHeader('cko-sdk-telemetry'); + + $this->assertEquals( + $expectedTelemetryHeaderCount, + $telemetryHeaderCount, + "Expected exactly {$expectedTelemetryHeaderCount} requests to contain the telemetry header" + ); + } + + /** + * @test + */ + public function shouldNotSendTelemetryWhenOptedOut() + { + $checkoutApi = $this->createCheckoutApi(false); + + for ($i = 0; $i < 3; $i++) { + $checkoutApi->getEventsClient()->retrieveAllEventTypes(); + } + + // No requests should contain telemetry headers + $telemetryHeaderCount = $this->countRequestsWithHeader('cko-sdk-telemetry'); + + $this->assertEquals( + 0, + $telemetryHeaderCount, + 'Expected no requests to contain the telemetry header' + ); + } + + /** + * @test + */ + public function shouldHandleTelemetryQueueAndBottleneck() + { + $checkoutApi = $this->createCheckoutApi(true); + + // Add more mock responses for the additional requests + for ($i = 0; $i < 7; $i++) { // 7 more to make total of 10 + $this->mockHandler->append(new Response(200, [], '{"data": []}')); + } + + $numRequests = 10; + + for ($i = 0; $i < $numRequests; $i++) { + $checkoutApi->getEventsClient()->retrieveAllEventTypes(); + } + + // Since telemetry starts being sent from the second request, + // we expect (numRequests - 1) telemetry headers + $expectedTelemetryHeaderCount = $numRequests - 1; + $telemetryHeaderCount = $this->countRequestsWithHeader('cko-sdk-telemetry'); + + $this->assertEquals( + $expectedTelemetryHeaderCount, + $telemetryHeaderCount, + "Expected {$expectedTelemetryHeaderCount} requests to contain the telemetry header" + ); + } +} From 2687839297dafcc536c1c35665f7a876beea17d1 Mon Sep 17 00:00:00 2001 From: sanchayata-jain-cko <146939622+sanchayata-jain-cko@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:50:46 +0000 Subject: [PATCH 3/5] remove commented out code --- lib/Checkout/ApiClient.php | 117 ------------------------------------- 1 file changed, 117 deletions(-) diff --git a/lib/Checkout/ApiClient.php b/lib/Checkout/ApiClient.php index a4baa896..97a61892 100644 --- a/lib/Checkout/ApiClient.php +++ b/lib/Checkout/ApiClient.php @@ -241,123 +241,6 @@ private function invoke($method, $path, $body, SdkAuthorization $authorization, return $this->handleRequest($method, $path, $authorization, $requestOptions); } - - // /** - // * @param $path - // * @param FileRequest $fileRequest - // * @param SdkAuthorization $authorization - // * @param $multipart - // * @return array - // * @throws CheckoutApiException - // */ - // private function submit($path, FileRequest $fileRequest, SdkAuthorization $authorization, $multipart) - // { - // try { - // $this->logger->info("POST " . $path . " file: " . $fileRequest->file); - // $headers = $this->getHeaders($authorization, null, null); - // if ($this->enableTelemetry) { - // $currentRequestId = uniqid(); //TODO: look at how uuid is made in go and copy - // $lastRequestMetric = $this->requestMetricsQueue->dequeue(); - - // if ($lastRequestMetric !== null) { - // $lastRequestMetric->requestId = $currentRequestId; - // $headers[self::CKO_TELEMETRY_HEADER] = base64_encode(json_encode([ - // 'prev-request-id' => $lastRequestMetric->prevRequestId, - // 'prev-request-duration' => $lastRequestMetric->prevRequestDuration - // ])); - // } - - // $startTime = microtime(true); - // $response = $this->client->request("POST", $this->getRequestUrl($path), [ - // "verify" => false, - // "headers" => $headers, - // "multipart" => [ - // [ - // "name" => $multipart, - // "contents" => fopen($fileRequest->file, "r") - // ], - // [ - // "name" => "purpose", - // "contents" => $fileRequest->purpose - // ] - // ]]); - - // $duration = (int)((microtime(true) - $startTime) * 1000); - - // $lastRequestMetric->prevRequestDuration = $duration; - // $lastRequestMetric->prevRequestId = $currentRequestId; - // $this->requestMetricsQueue->enqueue($lastRequestMetric); - // } else { - // $response = $this->client->request("POST", $this->getRequestUrl($path), [ - // "verify" => false, - // "headers" => $headers, - // "multipart" => [ - // [ - // "name" => $multipart, - // "contents" => fopen($fileRequest->file, "r") - // ], - // [ - // "name" => "purpose", - // "contents" => $fileRequest->purpose - // ] - // ]]); - // } - // return $this->getResponseContents($response); - // } catch (Exception $e) { - // $this->logger->error($path . " error: " . $e->getMessage()); - // if ($e instanceof RequestException) { - // throw CheckoutApiException::from($e); - // } - // throw new CheckoutApiException($e); - // } - // } - - // private function invoke($method, $path, $body, SdkAuthorization $authorization, $idempotencyKey = null) - // { - // try { - // $this->logger->info($method . " " . $path); - // $headers = $this->getHeaders($authorization, "application/json", $idempotencyKey); - // if ($this->enableTelemetry) { - // // Generate current request ID and handle telemetry only if enabled - // $currentRequestId = uniqid(); - // $lastRequestMetric = $this->requestMetricsQueue->dequeue(); - - // if ($lastRequestMetric !== null) { - // $lastRequestMetric->requestId = $currentRequestId; - // $headers[self::CKO_TELEMETRY_HEADER] = base64_encode(json_encode([ - // 'prev-request-id' => $lastRequestMetric->prevRequestId, - // 'prev-request-duration' => $lastRequestMetric->prevRequestDuration - // ])); - // } - - // $startTime = microtime(true); - // $response = $this->client->request($method, $this->getRequestUrl($path), [ - // "verify" => false, - // "body" => $body, - // "headers" => $headers - // ]); - // $duration = (int)((microtime(true) - $startTime) * 1000); - - // $lastRequestMetric->prevRequestDuration = $duration; - // $lastRequestMetric->prevRequestId = $currentRequestId; - // $this->requestMetricsQueue->enqueue($lastRequestMetric); - // } else { - // $response = $this->client->request($method, $this->getRequestUrl($path), [ - // "verify" => false, - // "body" => $body, - // "headers" => $headers - // ]); - // } - // return $this->getResponseContents($response); - // } catch (Exception $e) { - // $this->logger->error($path . " error: " . $e->getMessage()); - // if ($e instanceof RequestException) { - // throw CheckoutApiException::from($e); - // } - // throw new CheckoutApiException($e); - // } - // } - /** * @param string $path * @return string From 9f34f59f7c23521721e6d7efaf0f668aa1d99221 Mon Sep 17 00:00:00 2001 From: sanchayata-jain-cko <146939622+sanchayata-jain-cko@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:52:11 +0000 Subject: [PATCH 4/5] added comment --- lib/Checkout/ApiClient.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/Checkout/ApiClient.php b/lib/Checkout/ApiClient.php index 97a61892..18e3ddf0 100644 --- a/lib/Checkout/ApiClient.php +++ b/lib/Checkout/ApiClient.php @@ -140,6 +140,15 @@ public function submitFileFilesApi($path, FileRequest $fileRequest, SdkAuthoriza return $this->submit($path, $fileRequest, $authorization, "path"); } + /** + * Summary of handleRequest + * @param $method + * @param $path + * @param \Checkout\SdkAuthorization $authorization + * @param array $requestOptions + * @throws \Checkout\CheckoutApiException + * @return array + */ private function handleRequest($method, $path, SdkAuthorization $authorization, array $requestOptions) { try { From a39e3e20725214c5530e14ffe4b0b97615ab4801 Mon Sep 17 00:00:00 2001 From: sanchayata-jain-cko <146939622+sanchayata-jain-cko@users.noreply.github.com> Date: Fri, 6 Dec 2024 16:33:07 +0000 Subject: [PATCH 5/5] remove json --- .vscode/launch.json | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index c726ebb5..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Listen for Xdebug", - "type": "php", - "request": "launch", - "port": 9003, - "pathMappings": { - "/var/www/html": "${workspaceFolder}" - }, - "log": true, - "xdebugSettings": { - "max_children": 128, - "max_data": 512, - "max_depth": 3 - } - } - ] -}