config_preview_deploy-1.0.0-alpha3/tests/src/Kernel/IncomingRequestTest.php

tests/src/Kernel/IncomingRequestTest.php
<?php

declare(strict_types=1);

namespace Drupal\Tests\config_preview_deploy\Kernel;

use Symfony\Component\HttpFoundation\Response;
use Drupal\consumers\Entity\Consumer;
use Drupal\Core\Url;
use Drupal\KernelTests\KernelTestBase;
use Drupal\user\Entity\User;
use Symfony\Component\HttpFoundation\Request;

/**
 * Tests incoming requests to production endpoints.
 *
 * @group config_preview_deploy
 */
class IncomingRequestTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'config_preview_deploy',
    'simple_oauth',
    'simple_oauth_static_scope',
    'consumers',
    'key',
    'system',
    'user',
    'serialization',
    'options',
    'file',
    'image',
  ];

  /**
   * Test user.
   */
  protected User $testUser;

  /**
   * OAuth consumer.
   */
  protected Consumer $consumer;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    // Set HTTP_HOST for environment detection.
    $_SERVER['HTTP_HOST'] = 'test.example.com';

    $this->installEntitySchema('user');
    $this->installEntitySchema('consumer');
    $this->installEntitySchema('oauth2_token');
    $this->installEntitySchema('oauth2_scope');
    $this->installEntitySchema('oauth2_token_type');
    $this->installEntitySchema('key');
    $this->installConfig([
      'system',
      'user',
      'simple_oauth',
      'consumers',
      'config_preview_deploy',
    ]);

    // Create temporary directory for OAuth keys.
    $keysDir = sys_get_temp_dir() . '/oauth_keys_' . uniqid();
    mkdir($keysDir, 0777, TRUE);

    // Generate test keys.
    $this->generateTestKeys($keysDir);

    // Configure simple_oauth to use our test keys.
    $this->config('simple_oauth.settings')
      ->set('public_key', $keysDir . '/public.key')
      ->set('private_key', $keysDir . '/private.key')
      ->save();

    // Create test user with deployment permissions.
    $this->testUser = User::create([
      'name' => 'deploy_user',
      'mail' => 'deploy@example.com',
      'status' => 1,
    ]);
    $this->testUser->save();

    // Grant the user the required permission.
    user_role_grant_permissions('authenticated', ['accept config deployments']);

    // Run module install to create OAuth consumer.
    \Drupal::moduleHandler()->loadInclude('config_preview_deploy', 'install');
    config_preview_deploy_install();

    // Load the created consumer.
    $consumers = \Drupal::entityTypeManager()
      ->getStorage('consumer')
      ->loadByProperties(['client_id' => 'config_preview_deploy']);
    $this->consumer = reset($consumers);

  }

  /**
   * Generate test RSA key pair for OAuth.
   */
  protected function generateTestKeys(string $keysDir): void {
    // Generate private key.
    $private_key = openssl_pkey_new([
      'digest_alg' => 'sha256',
      'private_key_bits' => 2048,
      'private_key_type' => OPENSSL_KEYTYPE_RSA,
    ]);

    // Export private key.
    openssl_pkey_export_to_file($private_key, $keysDir . '/private.key');

    // Export public key.
    $public_key_details = openssl_pkey_get_details($private_key);
    file_put_contents($keysDir . '/public.key', $public_key_details['key']);
  }

  /**
   * Helper to issue a request and return the response.
   */
  protected function request(string $path, string $method = 'GET', array $query = [], array $headers = [], string $content = ''): Response {
    $request = Request::create($path, $method, $query, [], [], [], $content);

    // Add headers.
    foreach ($headers as $name => $value) {
      $request->headers->set($name, $value);
    }

    return $this->container->get('http_kernel')->handle($request);
  }

  /**
   * Tests status endpoint with valid token.
   */
  public function testStatusEndpointWithValidToken(): void {
    // Create valid token parameters using HashVerification service.
    $timestamp = time();
    $hashVerification = $this->container->get('config_preview_deploy.hash_verification');
    // Get the host from Drupal's base URL to match verification logic.
    $currentUrl = Url::fromRoute('system.admin', [], ['absolute' => TRUE])->toString();
    $productionHost = parse_url($currentUrl, PHP_URL_HOST);
    $token = $hashVerification->generateVerificationHash($productionHost, $timestamp);

    $response = $this->request('/api/config-preview-deploy/status', 'GET', [
      'timestamp' => $timestamp,
      'token' => $token,
    ]);

    $this->assertEquals(200, $response->getStatusCode());

    $data = json_decode($response->getContent(), TRUE);
    $this->assertArrayHasKey('last_change', $data);
    $this->assertArrayHasKey('timestamp', $data);
  }

  /**
   * Tests status endpoint with invalid token.
   */
  public function testStatusEndpointWithInvalidToken(): void {
    $response = $this->request('/api/config-preview-deploy/status', 'GET', [
      'timestamp' => time(),
      'token' => 'invalid-token',
    ]);

    $this->assertEquals(403, $response->getStatusCode());

    $data = json_decode($response->getContent(), TRUE);
    $this->assertEquals('Invalid verification hash', $data['error']);
  }

  /**
   * Tests status endpoint with expired timestamp.
   */
  public function testStatusEndpointWithExpiredTimestamp(): void {
    // More than 5 minutes old.
    $timestamp = time() - 400;
    $hashVerification = $this->container->get('config_preview_deploy.hash_verification');
    $productionHost = 'test.example.com';
    $token = $hashVerification->generateVerificationHash($productionHost, $timestamp);

    $response = $this->request('/api/config-preview-deploy/status', 'GET', [
      'timestamp' => $timestamp,
      'token' => $token,
    ]);

    $this->assertEquals(403, $response->getStatusCode());

    $data = json_decode($response->getContent(), TRUE);
    $this->assertEquals('Invalid verification hash', $data['error']);
  }

  /**
   * Tests deploy endpoint requires OAuth authentication.
   */
  public function testDeployEndpointRequiresOauth(): void {
    // Create deployment request without OAuth token.
    $data = json_encode([
      'diff' => 'test diff',
      'environment' => 'test',
      'auth_hash' => 'test_hash',
      'timestamp' => time(),
    ]);

    $response = $this->request('/admin/config/development/config-preview-deploy/deploy-endpoint', 'POST', [], [
      'Content-Type' => 'application/json',
    ], $data);

    // Should return 403 due to missing OAuth authentication.
    $this->assertEquals(403, $response->getStatusCode());
  }

  /**
   * Tests deploy endpoint with invalid OAuth token.
   */
  public function testDeployEndpointWithInvalidOauth(): void {
    $data = json_encode([
      'diff' => 'test diff',
      'environment' => 'test',
      'auth_hash' => 'test_hash',
      'timestamp' => time(),
    ]);

    $response = $this->request('/admin/config/development/config-preview-deploy/deploy-endpoint', 'POST', [], [
      'Content-Type' => 'application/json',
      'Authorization' => 'Bearer invalid-oauth-token-12345',
    ], $data);

    // Should return 401 due to invalid OAuth token.
    $this->assertEquals(401, $response->getStatusCode());
  }

  /**
   * Tests deploy endpoint OAuth protection with malformed request.
   */
  public function testDeployEndpointOauthProtectionWithMalformedRequest(): void {
    $response = $this->request('/admin/config/development/config-preview-deploy/deploy-endpoint', 'POST', [], [
      'Content-Type' => 'application/json',
      'Authorization' => 'Bearer invalid-token',
    ], 'invalid json data');

    // OAuth protection should trigger before request parsing.
    $this->assertEquals(401, $response->getStatusCode());
  }

  /**
   * Tests that OAuth protection is enforced on deploy endpoint.
   */
  public function testOauthProtectionOnDeployEndpoint(): void {
    // Test deploy endpoint (POST) - the main OAuth-protected endpoint.
    $response = $this->request('/admin/config/development/config-preview-deploy/deploy-endpoint', 'POST', [], [
      'Content-Type' => 'application/json',
    ], '{}');
    $this->assertEquals(403, $response->getStatusCode(), "Deploy endpoint should require OAuth authentication");
  }

  /**
   * Tests deploy endpoint handles different request scenarios.
   */
  public function testDeployEndpointScenarios(): void {
    // Test with valid JSON structure but no OAuth.
    $data = json_encode([
      'diff' => 'test diff',
      'environment' => 'test',
      'auth_hash' => 'test_hash',
      'timestamp' => time(),
    ]);

    $response = $this->request('/admin/config/development/config-preview-deploy/deploy-endpoint', 'POST', [], [
      'Content-Type' => 'application/json',
    ], $data);

    // Should return 403 due to missing OAuth authentication.
    $this->assertEquals(403, $response->getStatusCode());
  }

  /**
   * Tests environment name extraction from services.
   */
  public function testEnvironmentNameExtraction(): void {
    $config_verifier = \Drupal::service('config_preview_deploy.config_verifier');
    $environment = $config_verifier->getEnvironmentName();

    $this->assertIsString($environment);
    $this->assertNotEmpty($environment);

    // In test environment, should be one of these values.
    $valid_environments = ['local', 'test', gethostname()];
    $this->assertTrue(in_array($environment, $valid_environments));
  }

}

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

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