test_helpers-1.0.0-alpha6/tests/src/Unit/Stub/HttpClientFactoryStubTest.php

tests/src/Unit/Stub/HttpClientFactoryStubTest.php
<?php

declare(strict_types=1);

namespace Drupal\Tests\test_helpers\Unit\Stub;

use Drupal\Component\Serialization\Yaml;
use Drupal\Core\Http\ClientFactory;
use Drupal\Tests\UnitTestCase;
use Drupal\test_helpers\Stub\HttpClientFactoryStub;
use Drupal\test_helpers\TestHelpers;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use donatj\MockWebServer\MockWebServer;
use donatj\MockWebServer\Response as MockWebServerResponse;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\CoversMethod;
use PHPUnit\Framework\Attributes\Group;

/**
 * Tests HttpClientFactoryStub class.
 */
#[CoversClass(HttpClientFactoryStub::class)]
#[Group('test_helpers')]
#[Group('test_helpers_http_client')]
#[CoversMethod(HttpClientFactoryStub::class, '__construct')]
#[CoversMethod(HttpClientFactoryStub::class, 'fromOptions')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubGetStoredResponse')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubStoreResponse')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubGetRequestHash')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubAddCustomResponseToStack')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubSetCustomHandler')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubGetTestName')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubSetTestName')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubGetRequestMetadata')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubDeleteStoredResponseByHash')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubLogResponseUsage')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubRemoveResponseUsageLog')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubGetResponseUsageLog')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubGetHandledRequests')]
#[CoversMethod(HttpClientFactoryStub::class, 'stubGetLastResponse')]
class HttpClientFactoryStubTest extends UnitTestCase {

  const RESPONSES_STORAGE_DIRECTORY = __DIR__ . '/../../../assets';

  /**
   * Tests the constructor of HttpClientFactoryStub.
   */
  public function testConstructor() {
    $stack = HandlerStack::create();
    $customTestName = 'customNameOne';
    $factoryDefault1 = TestHelpers::service('http_client_factory');
    $this->assertEquals(__CLASS__ . '::' . __FUNCTION__, $factoryDefault1->stubGetTestName());

    $factoryStore = TestHelpers::service(
      'http_client_factory',
      customArguments: [
        $stack,
        HttpClientFactoryStub::HTTP_CLIENT_MODE_STORE,
        self::RESPONSES_STORAGE_DIRECTORY,
        $customTestName,
      ],
      forceOverride: TRUE,
    );
    $this->assertEquals($customTestName, $factoryStore->stubGetTestName());

    $factoryMock = TestHelpers::service(
      'http_client_factory',
      customArguments: [
        $stack,
        HttpClientFactoryStub::HTTP_CLIENT_MODE_MOCK,
        self::RESPONSES_STORAGE_DIRECTORY,
      ],
      forceOverride: TRUE,
    );
    $this->assertEquals(__CLASS__ . '::' . __FUNCTION__, $factoryMock->stubGetTestName());

    $factoryDefault2 = TestHelpers::service(
      'http_client_factory',
      forceOverride: TRUE);
    $this->assertEquals(__CLASS__ . '::' . __FUNCTION__, $factoryDefault2->stubGetTestName());
  }

  /**
   * Tests storing and mocking requests with different modes.
   */
  public function testStoringAndMockingRequests() {
    $server = new MockWebServer();
    $server->start();
    $requestPath = '/endpoint?get=foobar';
    $baseUri = $server->getServerRoot();
    $url = $baseUri . $requestPath;

    $request = new Request('GET', $url);

    $httpClientFactoryStubNone = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: NULL,
    );
    $clientFactoryNone = TestHelpers::service('http_client_factory', $httpClientFactoryStubNone, forceOverride: TRUE);
    $httpCallerNone = new HttpCaller($clientFactoryNone, $baseUri);

    $httpClientFactoryStubStore = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_STORE,
    );
    $clientFactoryStore = TestHelpers::service('http_client_factory', $httpClientFactoryStubStore, forceOverride: TRUE);
    $httpCallerStore = new HttpCaller($clientFactoryStore, $baseUri);

    $httpClientFactoryStubMock = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_MOCK,
    );
    $clientFactoryMock = TestHelpers::service('http_client_factory', $httpClientFactoryStubMock, forceOverride: TRUE);
    $httpCallerMock = new HttpCaller($clientFactoryMock, $baseUri);

    $httpClientFactoryStubAppend = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_APPEND,
    );
    $clientFactoryAppend = TestHelpers::service('http_client_factory', $httpClientFactoryStubAppend, forceOverride: TRUE);
    $httpCallerAppend = new HttpCaller($clientFactoryAppend, $baseUri);

    // Test a real response.
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerStore, $requestPath)->_GET->get);

    // Test a stored response.
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerStore, $requestPath)->_GET->get);

    // Store the modified stored response.
    $storedResponseHash = $httpClientFactoryStubMock->stubGetRequestHash($request);
    $storedResponseFile = self::RESPONSES_STORAGE_DIRECTORY . '/' . $storedResponseHash . '.txt';
    $storedResponseContents = file_get_contents($storedResponseFile);
    $modifiedResponse = json_decode($storedResponseContents);
    $modifiedResponse->_GET->get = 'baz';
    file_put_contents($storedResponseFile, json_encode($modifiedResponse));

    // Check that the stored response has the modified value.
    $this->assertEquals('baz', $this->makeRequestGetJsonResponse($httpCallerMock, $requestPath)->_GET->get);
    // Check that the none mode returns the original value.
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerNone, $requestPath)->_GET->get);
    // Check that the append mode has the modified value.
    $this->assertEquals('baz', $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath)->_GET->get);
    // Check that the store mode provides the original value and restores the
    // file for the append mode.
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerStore, $requestPath)->_GET->get);
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath)->_GET->get);

    // Test the stubAddCustomResponseToStack().
    // And the stubSetCustomHandler().
    $clientFactoryAppend->stubAddCustomResponseToStack(
      new Response(404, [], '{"value":"AppendTest1"}'),
    );
    $clientFactoryAppend->stubAddCustomResponseToStack(
      new Response(404, [], '{"value":"AppendTest2"}'),
    );
    $clientFactoryStore->stubAddCustomResponseToStack(
      new Response(404, [], '{"value":"StoreTest1"}'),
    );
    $this->assertEquals('AppendTest1', $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath)->value);
    $this->assertEquals('AppendTest2', $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath)->value);
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath)->_GET->get);
    $this->assertEquals('StoreTest1', $this->makeRequestGetJsonResponse($httpCallerStore, $requestPath)->value);
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerStore, $requestPath)->_GET->get);

    // Check that the append mode started to return the modified value after
    // storing the actual request.
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath)->_GET->get);

    // Check the exception with the mock mode if the stored response is missing.
    $httpClientFactoryStubMock->stubDeleteStoredResponseByHash($storedResponseHash);
    try {
      $httpCallerMock->get($requestPath);
      $this->fail('The call in the mock mode with the deleted response should throw an exception.');
    }
    catch (\Exception $e) {
      $this->assertStringContainsString('Missing the stored response file', $e->getMessage());
      $this->assertStringContainsString($storedResponseHash, $e->getMessage());
    }

    // Check that the append more recreates the file if missing.
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath)->_GET->get);
    $this->assertEquals('foobar', $this->makeRequestGetJsonResponse($httpCallerMock, $requestPath)->_GET->get);

    // Restore the stored file contents.
    \Drupal::service('http_client_factory')->stubDeleteStoredResponseByHash($storedResponseHash);
    $server->stop();
  }

  /**
   * Tests storing responses with exceptions.
   */
  public function testStoringResponsesWithExceptions() {
    $responses = [
      '/error-401' => [
        'body' => '{"value":"error 401"}',
        'status' => 401,
      ],
      '/error-500' => [
        'body' => '{"value":"error 500"}',
        'status' => 500,
      ],
    ];

    $server = new MockWebServer();
    $server->start();
    $baseUri = $server->getServerRoot();
    $handlerResponse = NULL;
    $throwExceptionHandler = function (callable $handler) use (&$handlerResponse) {
      return function ($request, array $options) use ($handler, &$handlerResponse) {
        /** @var \Psr\Http\Message\ResponseInterface $handlerResponse */
        throw new BadResponseException('Test1', $request, $handlerResponse);
      };
    };

    $handlerStack = HandlerStack::create();
    $handlerStack->unshift($throwExceptionHandler, 'throwExceptionHandler');

    $httpClientFactoryStubStore = new HttpClientFactoryStub(
      stack: $handlerStack,
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_STORE,
    );
    $clientFactoryStore = TestHelpers::service('http_client_factory', $httpClientFactoryStubStore, forceOverride: TRUE);

    foreach ($responses as $path => $data) {
      $mockedResponse = new MockWebServerResponse($data['body'], [], $data['status']);
      $handlerResponse = new Response($data['status'], [], $data['body']);
      $server->setResponseOfPath($path, $mockedResponse);
      $requestPath = $baseUri . $path;
      $httpCallerStore = new HttpCaller($clientFactoryStore, $requestPath);
      $request = new Request('GET', $requestPath);
      $storedResponseHash = $httpClientFactoryStubStore->stubGetRequestHash($request);
      // $httpClientFactoryStubStore->stubSetCustomHandler();
      try {
        // This call should throw a Guzzle exception because the response
        // contains an error status code.
        $this->makeRequestGetJsonResponse($httpCallerStore, $requestPath);
      }
      catch (\Exception) {
        $asset = $httpClientFactoryStubStore->stubGetStoredResponseByHash($storedResponseHash);
        $this->assertEquals($data['status'], $asset->getStatusCode());
        $this->assertEquals($data['body'], $asset->getBody());
        $httpClientFactoryStubStore->stubDeleteStoredResponseByHash($storedResponseHash);
      }
    }
  }

  /**
   * Tests storing the same request with context.
   */
  public function testStoringSameRequestWithContext() {
    $server = new MockWebServer();
    $server->start();
    $requestPath = '/testStoringSameRequestWithContext-endpoint';
    $baseUri = $server->getServerRoot();
    $url = $baseUri . $requestPath;

    $httpClientFactoryStubStore = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_STORE,
    );
    $clientFactoryStore = TestHelpers::service('http_client_factory', $httpClientFactoryStubStore, forceOverride: TRUE);
    $httpCallerStore = new HttpCaller($clientFactoryStore, $baseUri);

    $httpClientFactoryStubMock = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_MOCK,
    );
    $clientFactoryMock = TestHelpers::service('http_client_factory', $httpClientFactoryStubMock, forceOverride: TRUE);
    $httpCallerMock = new HttpCaller($clientFactoryMock, $baseUri);

    $httpClientFactoryStubAppend = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_APPEND,
    );
    $clientFactoryAppend = TestHelpers::service('http_client_factory', $httpClientFactoryStubAppend, forceOverride: TRUE);
    $httpCallerAppend = new HttpCaller($clientFactoryAppend, $baseUri);

    $responseMocked1 = new MockWebServerResponse('{"value":"r1"}');
    $responseMocked2 = new MockWebServerResponse('{"value":"r2"}');
    $responseMocked3 = new MockWebServerResponse('{"value":"r3"}');

    $server->setResponseOfPath($requestPath, $responseMocked1);
    $response = $this->makeRequestGetJsonResponse($httpCallerStore, $requestPath);
    $this->assertEquals('r1', $response->value);

    $server->setResponseOfPath($requestPath, $responseMocked2);
    $response = $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath);
    $this->assertEquals('r1', $response->value);
    $response = $this->makeRequestGetJsonResponse($httpCallerMock, $requestPath);
    $this->assertEquals('r1', $response->value);
    $response = $this->makeRequestGetJsonResponse($httpCallerStore, $requestPath);
    $this->assertEquals('r2', $response->value);
    $response = $this->makeRequestGetJsonResponse($httpCallerMock, $requestPath);
    $this->assertEquals('r2', $response->value);

    $server->setResponseOfPath($requestPath, $responseMocked3);
    $clientFactoryAppend->stubSetContext('context1');
    $response = $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath);
    $this->assertEquals('r3', $response->value);
    $clientFactoryAppend->stubSetContext();
    $response = $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath);
    $this->assertEquals('r2', $response->value);

    $response = $this->makeRequestGetJsonResponse($httpCallerAppend, $requestPath);
    $this->assertEquals('r2', $response->value);

    $storedRequestHashes = array_unique([
      ...$clientFactoryStore->stubGetHandledRequests(),
      ...$clientFactoryAppend->stubGetHandledRequests(),
    ]);
    foreach ($storedRequestHashes as $hash) {
      $clientFactoryStore->stubDeleteStoredResponseByHash($hash);
    }

  }

  /**
   * Tests the stubSetCustomHandler method.
   */
  public function testStubSetCustomHandler() {
    $server = new MockWebServer();
    $server->start();
    $requestPath = '/endpoint?get=foobar';
    $baseUri = $server->getServerRoot();

    $httpClientFactory = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_MOCK,
    );

    $clientFactory = TestHelpers::service('http_client_factory', $httpClientFactory, forceOverride: TRUE);
    $customHandler1 = function (callable $handler) {
      return function ($request, array $options) {
        $response = new Response(200, [], 'CustomHandler1');
        return new FulfilledPromise($response);
      };
    };
    $customHandler2 = function (callable $handler) {
      return function ($request, array $options) {
        $response = new Response(200, [], 'CustomHandler2');
        return new FulfilledPromise($response);
      };
    };
    $clientFactory->stubSetCustomHandler($customHandler1);

    $httpCaller = new HttpCaller($clientFactory, $baseUri);
    $this->assertEquals('CustomHandler1', $httpCaller->get($requestPath)->getBody()->getContents());
    $this->assertEquals('CustomHandler1', $httpCaller->get($requestPath)->getBody()->getContents());
    $clientFactory->stubAddCustomResponseToStack(new Response(404, [], 'Cr1'));
    $clientFactory->stubAddCustomResponseToStack(new Response(301, [], 'Cr2'));
    $this->assertEquals('Cr1', $httpCaller->get($requestPath)->getBody()->getContents());
    $this->assertEquals('Cr2', $httpCaller->get($requestPath)->getBody()->getContents());
    $this->assertEquals('CustomHandler1', $httpCaller->get($requestPath)->getBody()->getContents());
    $clientFactory->stubSetCustomHandler($customHandler2);
    $this->assertEquals('CustomHandler2', $httpCaller->get($requestPath)->getBody()->getContents());
    $clientFactory->stubSetCustomHandler(NULL);
    // This call should throw an exception because in the HTTP_CLIENT_MODE_MOCK
    // the file is missing.
    TestHelpers::assertException(
      function () use ($httpCaller, $requestPath) {
        $this->assertEquals('CustomHandler', $httpCaller->get($requestPath)->getBody()->getContents());
      }
    );
    $clientFactory->stubAddCustomResponseToStack(new Response(404, [], 'Cr1'));
    $this->assertEquals('Cr1', $httpCaller->get($requestPath)->getBody()->getContents());
    // This call should throw an exception because in the HTTP_CLIENT_MODE_MOCK
    // the file is missing.
    TestHelpers::assertException(
      function () use ($httpCaller, $requestPath) {
        $this->assertEquals('CustomHandler', $httpCaller->get($requestPath)->getBody()->getContents());
      }
    );
  }

  /**
   * Tests the test name sorting in the stored responses.
   */
  public function testTestName() {
    $server = new MockWebServer();
    $server->start();
    $requestPath = '/endpoint?get=foobar';
    $baseUri = $server->getServerRoot();
    $url = $baseUri . $requestPath;

    $testName = __CLASS__ . '::' . __FUNCTION__;
    $testNameCustom2 = __CLASS__ . '::' . __FUNCTION__ . '_42';
    $testNameCustom3 = __CLASS__ . '::' . __FUNCTION__ . '_32';

    $httpClientFactoryStub = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_STORE,
    );
    $httpCaller1 = new HttpCaller($httpClientFactoryStub, $baseUri);

    $httpClientFactoryStubCustomName2 = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_STORE,
      testName: $testNameCustom2,
    );
    $httpCaller2 = new HttpCaller($httpClientFactoryStubCustomName2, $baseUri);

    $httpClientFactoryStubCustomName3 = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_STORE,
      testName: $testNameCustom3,
    );
    $httpCaller3 = new HttpCaller($httpClientFactoryStubCustomName3, $baseUri);

    $request = new Request('GET', $url);
    $httpCaller1->get($requestPath);
    $httpCaller2->get($requestPath);
    $httpCaller3->get($requestPath);

    $storedResponseMetadataFile = $httpClientFactoryStub->stubGetRequestFilenameFromRequest($request, TRUE);
    $storedResponseMetadata = Yaml::decode(file_get_contents($storedResponseMetadataFile));
    // Check the sorted order of tests.
    $this->assertEquals($testName, $storedResponseMetadata['tests'][0]);
    $this->assertEquals($testNameCustom2, $storedResponseMetadata['tests'][2]);
    $this->assertEquals($testNameCustom3, $storedResponseMetadata['tests'][1]);

    $httpClientFactoryStub->stubDeleteStoredResponseByHash($httpClientFactoryStub->stubGetRequestHash($request));
    $server->stop();
  }

  /**
   * Tests the stubGetRequestMetadata method.
   */
  public function testGetRequestMetadata() {
    $server = new MockWebServer();
    $server->start();
    $requestPath = '/endpoint?get=foobar';
    $baseUri = $server->getServerRoot();
    $url = $baseUri . $requestPath;

    $httpClientFactoryStub = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_STORE,
    );

    $httpCaller = new HttpCaller($httpClientFactoryStub, $baseUri);

    $body = json_encode(['foo' => 'bar']);
    $request = new Request('POST', $url, [], $body);
    $httpCaller->post($requestPath, $body);

    $storedResponseFile = $httpClientFactoryStub->stubGetRequestFilenameFromRequest($request);
    $storedResponseMetadataFile = $httpClientFactoryStub->stubGetRequestFilenameFromRequest($request, TRUE);
    $storedResponseMetadata = Yaml::decode(file_get_contents($storedResponseMetadataFile));
    $this->assertEquals('POST', $storedResponseMetadata['request']['method']);
    $this->assertEquals($url, $storedResponseMetadata['request']['uri']);
    $this->assertEquals($body, $storedResponseMetadata['request']['body']);
    $this->assertTrue(file_exists($storedResponseFile));
    $httpClientFactoryStub->stubDeleteStoredResponseByHash($httpClientFactoryStub->stubGetRequestHash($request));
    $this->assertFalse(file_exists($storedResponseFile));
    $this->assertFalse(file_exists($storedResponseMetadataFile));
    $server->stop();
  }

  /**
   * Tests the stubGetResponseUsageLog method.
   */
  public function testResponsesUsageLog() {
    $server = new MockWebServer();
    $server->start();

    $logFile = tempnam(sys_get_temp_dir(), 'test_helpers_http_client_log_');

    $httpClientFactoryLog = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_APPEND,
      options: [
        HttpClientFactoryStub::OPTION_LOG_STORED_RESPONSES_USAGE_FILE => $logFile,
      ],
    );

    $httpClientFactoryNoLog = new HttpClientFactoryStub(
      responsesStorageDirectory: self::RESPONSES_STORAGE_DIRECTORY,
      requestMockMode: HttpClientFactoryStub::HTTP_CLIENT_MODE_APPEND,
      options: [
        HttpClientFactoryStub::OPTION_LOG_STORED_RESPONSES_USAGE_FILE => NULL,
      ],
    );

    // Make several requests without log mode enabled.
    TestHelpers::service('http_client_factory', $httpClientFactoryNoLog, forceOverride: TRUE);
    $hash1 = $this->makeRequestGetHash($server, '/endpoint?get=test1');
    $hash2 = $this->makeRequestGetHash($server, '/endpoint?get=test2');
    $this->assertEmpty($httpClientFactoryNoLog->stubGetResponseUsageLog());
    $this->assertEmpty($httpClientFactoryLog->stubGetResponseUsageLog());

    // Modify the first request stored response.
    $responseFake = new Response(202, [], 'fake response');
    $httpClientFactoryNoLog->stubStoreResponse($responseFake, NULL, $hash1);

    TestHelpers::service('http_client_factory', $httpClientFactoryLog, forceOverride: TRUE);
    \Drupal::service('http_client_factory')->stubSetRequestMockMode(HttpClientFactoryStub::HTTP_CLIENT_MODE_STORE);
    $hash1 = $this->makeRequestGetHash($server, '/endpoint?get=test1');
    $hash2 = $this->testResponsesUsageLogSubFunction($httpClientFactoryLog, $server, '/endpoint?get=test2');
    \Drupal::service('http_client_factory')->stubSetTestName();
    \Drupal::service('http_client_factory')->stubSetRequestMockMode(HttpClientFactoryStub::HTTP_CLIENT_MODE_APPEND);
    // Calling the no-logging service.
    TestHelpers::service('http_client_factory', $httpClientFactoryNoLog, forceOverride: TRUE);
    $this->makeRequestGetHash($server, '/endpoint?get=test2');
    // Reverting to the logging service.
    TestHelpers::service('http_client_factory', $httpClientFactoryLog, forceOverride: TRUE);
    $this->makeRequestGetHash($server, '/endpoint?get=test2');
    $hash3 = $this->makeRequestGetHash($server, '/endpoint?get=test3');

    // Expect tat the no-log log is empty.
    $this->assertEmpty($httpClientFactoryNoLog->stubGetResponseUsageLog());

    // Tests the responses container.
    $responsesContainer = $httpClientFactoryLog->stubGetHandledRequests();
    $this->assertEquals([
      $hash1,
      $hash2,
      $hash2,
      $hash3,
    ], $responsesContainer);

    $lastResponse0 = json_decode($httpClientFactoryLog->stubGetLastResponse());
    $this->assertEquals('test3', $lastResponse0->_GET->get);
    $lastResponse1 = json_decode($httpClientFactoryLog->stubGetLastResponse(1));
    $this->assertEquals('test2', $lastResponse1->_GET->get);

    $httpClientFactoryLog->stubDeleteStoredResponseByHash($hash1);
    $httpClientFactoryLog->stubDeleteStoredResponseByHash($hash2);
    $httpClientFactoryLog->stubDeleteStoredResponseByHash($hash3);

    $log = $httpClientFactoryLog->stubGetResponseUsageLog();
    $logExpected = [
      [
        'hash' => $hash1,
        'operation' => 'update',
        'test' => self::class . '::testResponsesUsageLog',
      ],
      [
        'hash' => $hash2,
        'operation' => 'check',
        'test' => self::class . '::testResponsesUsageLogSubFunction',
      ],
      [
        'hash' => $hash2,
        'operation' => 'read',
        'test' => self::class . '::testResponsesUsageLog',
      ],
      [
        'hash' => $hash3,
        'operation' => 'create',
        'test' => self::class . '::testResponsesUsageLog',
      ],
    ];
    $this->assertTrue(TestHelpers::isNestedArraySubsetOf($log, $logExpected));
  }

  /**
   * Makes a request and returns the hash of the request.
   *
   * @param \donatj\MockWebServer\MockWebServer $server
   *   A mock web server.
   * @param string $path
   *   A path.
   * @param string $type
   *   A type of the request.
   * @param mixed $body
   *   A body of the request.
   *
   * @return string
   *   A hash of the request.
   */
  private function makeRequestGetHash(MockWebServer $server, string $path, $type = 'GET', $body = NULL): string {
    $baseUri = $server->getServerRoot();
    $url = $baseUri . $path;
    $request = new Request($type, $url, body: $body);
    $service = \Drupal::service('http_client_factory');
    $client = $service->fromOptions([
      'base_uri' => $baseUri,
    ]);
    $client->send($request);
    $hash = $service->stubGetRequestHash($request);
    return $hash;
  }

  /**
   * A sub-function to test the responses usage log.
   *
   * @param \Drupal\test_helpers\Stub\HttpClientFactoryStub $httpClientFactory
   *   An HTTP client factory.
   * @param \donatj\MockWebServer\MockWebServer $server
   *   A mock web server.
   * @param string $path
   *   A path.
   *
   * @return string
   *   A hash of the request.
   */
  private function testResponsesUsageLogSubFunction($httpClientFactory, $server, $path) {
    $httpClientFactory->stubSetTestName();
    return $this->makeRequestGetHash($server, $path);
  }

  /**
   * Makes a request and returns the JSON response.
   *
   * @param \Drupal\Tests\test_helpers\Unit\Stub\HttpCaller $httpCaller
   *   An HTTP caller.
   * @param string $requestPath
   *   A request path.
   *
   * @return mixed
   *   A JSON response.
   */
  private function makeRequestGetJsonResponse($httpCaller, $requestPath) {
    $response = $httpCaller->get($requestPath);
    $result = json_decode($response->getBody()->getContents());
    return $result;
  }

}

/**
 * A helper class to test the functionality.
 */
class HttpCaller {

  /**
   * An HTTP client.
   *
   * @var \GuzzleHttp\Client
   */
  public Client $client;

  /**
   * Constructs the HttpCaller class.
   *
   * @param \Drupal\Core\Http\ClientFactory $httpClientFactory
   *   An HTTP Client factory.
   * @param string $baseUri
   *   A base uri.
   */
  public function __construct(
    protected ClientFactory $httpClientFactory,
    protected $baseUri,
  ) {
    $this->client = $this->httpClientFactory->fromOptions([
      'base_uri' => $baseUri,
    ]);
  }

  /**
   * Gets the contents from an url.
   *
   * @param string $url
   *   An url.
   *
   * @return \Psr\Http\Message\ResponseInterface
   *   The response of the url.
   */
  public function get(string $url) {
    return $this->client->get($url);
  }

  /**
   * Makes a post requests  an url.
   *
   * @param string $url
   *   An url.
   * @param string $body
   *   The body contents.
   *
   * @return \Psr\Http\Message\ResponseInterface
   *   The response of the url.
   */
  public function post(string $url, string $body) {
    return $this->client->post($url, ['body' => $body]);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc