sessionless-1.x-dev/tests/src/Unit/WebTokenServiceUnitTest.php

tests/src/Unit/WebTokenServiceUnitTest.php
<?php

declare(strict_types=1);
namespace Drupal\Tests\sessionless\Unit;

use Drupal\Core\Cache\MemoryCache\MemoryCacheFactory;
use Drupal\Core\Cache\NullBackend;
use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
use Drupal\Core\Lock\NullLockBackend;
use Drupal\Core\State\State;
use Drupal\sessionless\KeyStorage\KeyStorage;
use Drupal\sessionless\KeyStorage\KeyStorageInterface;
use Drupal\sessionless\Serialization\JsonSafeCompressedPhpSerialization;
use Drupal\sessionless\SessionlessEncryptAndSign;
use Drupal\sessionless\SessionlessOnlySign;
use Drupal\sessionless\SessionlessInterface;
use Drupal\Tests\sessionless\Traits\ClassWithPrivateProperty;
use Drupal\Tests\sessionless\Traits\SessionlessServices;
use Drupal\Tests\sessionless\Unit\Double\FakeTime;
use Drupal\Tests\UnitTestCase;
use Drupal\TestTools\Random;
use Symfony\Component\Stopwatch\Stopwatch;

/**
 * @group sessionless
 */
final class WebTokenServiceUnitTest extends UnitTestCase {

  protected function setUp(): void {
    parent::setUp();
  }

  /**
   * @dataProvider provideWebTokenService
   */
  public function testWebTokenService(SessionlessInterface $tokenService): void {
    // Class with private property contains nul bytes when serialized.
    $data = [
      'randomObject' => Random::object(10),
      'classWithPrivateString' => new ClassWithPrivateProperty(Random::string(500)),
    ];
    $token = $tokenService->encode($data);
    $this->assertIsString($token);
    // $this->assertSame('', $token);
    $this->assertMatchesRegularExpression('~^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$~', $token);
    $recoveredData = $tokenService->decode($token);
    // The recreated object is equal, but not same.
    $this->assertEquals($data, $recoveredData);
    $this->assertNotSame($data, $recoveredData);
  }

  /**
   * @dataProvider provideWebTokenServiceAndKeyStorage
   */
  public function testKeyChange(SessionlessInterface $tokenService, KeyStorageInterface $keyStorage): void {
    $data = random_bytes(100000);

    $token1a = $tokenService->encode($data);
    $token1b = $tokenService->encode($data);

    $keyVersion1 = $keyStorage->getKeyVersion();
    $keyStorage->dropSecretKeys();
    $keyVersion2 = $keyStorage->getKeyVersion();

    $token2a = $tokenService->encode($data);
    $token2b = $tokenService->encode($data);

    // Key version changed.
    $this->assertNotSame($keyVersion1, $keyVersion2);

    // Same key, same token.
    // Note: For encrypted tokens, this is ONLY the case when cached, because
    // the session encryption key is random.
    $this->assertSame($token1a, $token1b);
    $this->assertSame($token2a, $token2b);

    // Different key, different token.
    $this->assertNotSame($token1a, $token2a);
  }

  /**
   * @dataProvider provideWebTokenService
   */
  public function testAlgorithmsCaching(SessionlessInterface $tokenService): void {
    $data = random_bytes(100000);
    $stopwatch = new Stopwatch(true);

    $stopwatch->start('1a');
    $tokenService->encode($data);
    $stopwatch->stop('1a');

    $stopwatch->start('1b');
    $tokenService->encode($data);
    $stopwatch->stop('1b');

    // Every second run was significantly faster (but still needs packing).
    $this->assertLessThan($stopwatch->getEvent('1a')->getDuration() / 2, $stopwatch->getEvent('1b')->getDuration());
  }

  public static function provideWebTokenService() {
    yield 'onlySigned' => [self::createWebTokenService(false)->webTokenService];
    yield 'encryptedSigned' => [self::createWebTokenService(true)->webTokenService];
  }

  public static function provideWebTokenServiceAndKeyStorage() {
    $services = self::createWebTokenService(FALSE);
    yield 'onlySigned' => [$services->webTokenService, $services->keyStorage];
    $services = self::createWebTokenService(TRUE);
    yield 'encryptedSigned' => [$services->webTokenService, $services->keyStorage];
  }

  public static function createWebTokenService(bool $encrypt): SessionlessServices {
    $state = new State(new KeyValueMemoryFactory(), new NullBackend(''), new NullLockBackend());
    $keyStorage = new KeyStorage($state);
    $serializer = new JsonSafeCompressedPhpSerialization();
    $time = new FakeTime();
    $cacheFactory = new MemoryCacheFactory($time);
    $cache = $cacheFactory->get('sessionless');
    if ($encrypt) {
      $tokenService = new SessionlessEncryptAndSign($keyStorage, $serializer, $cache);
    }
    else {
      $tokenService = new SessionlessOnlySign($keyStorage, $serializer, $cache);
    }
    return new SessionlessServices($tokenService, $keyStorage);
  }

}

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

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