commerce_license-8.x-2.x-dev/tests/src/Kernel/LicenseCronExpiryTest.php
tests/src/Kernel/LicenseCronExpiryTest.php
<?php namespace Drupal\Tests\commerce_license\Kernel\System; use Drupal\advancedqueue\Entity\Queue; use Drupal\advancedqueue\Job; use Drupal\commerce_license\Cron; use Drupal\Core\Test\AssertMailTrait; use Drupal\Tests\commerce_order\Kernel\OrderKernelTestBase; /** * Tests that cron expires a license. * * @group commerce_license */ class LicenseCronExpiryTest extends OrderKernelTestBase { use AssertMailTrait; /** * The number of seconds in one day. */ public const TIME_ONE_DAY = 60 * 60 * 24; /** * The modules to enable. * * @var array */ protected static $modules = [ 'advancedqueue', 'commerce_license', 'commerce_license_test', 'commerce_license_set_expiry_test', ]; /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * The cron service. * * @var \Drupal\Core\Cron */ protected $cron; /** * {@inheritdoc} */ protected function setUp(): void { parent::setUp(); $this->installSchema('advancedqueue', 'advancedqueue'); $this->installEntitySchema('commerce_license'); // This is just duplicates of the queues in the real module, as we don't // want to have to install the admin view in this test. $this->installConfig('commerce_license_set_expiry_test'); $this->cron = \Drupal::service('cron'); $this->entityTypeManager = \Drupal::service('entity_type.manager'); } /** * Returns the current time. * * @return int * The time. */ protected static function today(): int { return time(); } /** * Returns the time a day ago. * * @return int * Yesterday's time. */ protected static function yesterday() { return self::today() - self::TIME_ONE_DAY; } /** * Returns the time a day from now. * * @return int * Tomorrow's time. */ protected static function tomorrow() { return self::today() + self::TIME_ONE_DAY; } /** * Gets a protected method for testing. * * @param string $class * Name of the class. * @param string $name * Name of the method. * * @return \ReflectionMethod * The method. * * @throws \ReflectionException */ protected static function getMethod(string $class, string $name): \ReflectionMethod { $class = new \ReflectionClass($class); $method = $class->getMethod($name); $method->setAccessible(TRUE); return $method; } /** * License hasn't expired. * * Tests that getLicenseIdsToExpire doesn't return a license that hasn't * expired yet. */ public function testGetLicenseIdsToExpireTomorrow(): void { $license_storage = $this->entityTypeManager->getStorage('commerce_license'); $license_owner = $this->createUser(); // Create a license in the 'active' state. $license = $license_storage->create([ 'type' => 'simple', 'state' => 'active', 'product' => 1, 'uid' => $license_owner->id(), // Use the unlimited expiry plugin as it's simple. 'expiration_type' => [ 'target_plugin_id' => 'unlimited', 'target_plugin_configuration' => [], ], ]); $license->save(); // Force the expiration timestamp. // As the state is not being changed, the expiration plugin won't be called. $license->expires = self::tomorrow(); $license->save(); // Test getLicensesToExpire() method. $cron = \Drupal::service('commerce_license.cron'); $getLicenseIdsToExpire = self::getMethod(Cron::class, 'getLicensesToExpire'); $expire_ids = $getLicenseIdsToExpire->invokeArgs($cron, [self::today()]); $this->assertEquals([], $expire_ids, 'The license ID is not returned by the expiration query.'); } /** * License has expired. * * Tests that getLicenseIdsToExpire doesn't return a license that hasn't * expired yet. */ public function testGetLicenseIdsToExpireYesterday(): void { $license_storage = $this->entityTypeManager->getStorage('commerce_license'); $license_owner = $this->createUser(); // Create a license in the 'active' state. $license = $license_storage->create([ 'type' => 'simple', 'state' => 'active', 'product' => 1, 'uid' => $license_owner->id(), // Use the unlimited expiry plugin as it's simple. 'expiration_type' => [ 'target_plugin_id' => 'unlimited', 'target_plugin_configuration' => [], ], ]); $license->save(); // Force the expiration timestamp. // As the state is not being changed, the expiration plugin won't be called. $license->expires = self::yesterday(); $license->save(); // Test getLicensesToExpire() method. $cron = \Drupal::service('commerce_license.cron'); $getLicenseIdsToExpire = self::getMethod(Cron::class, 'getLicensesToExpire'); $expire_ids = $getLicenseIdsToExpire->invokeArgs($cron, [self::today()]); $this->assertEquals([$license->id() => $license->id()], $expire_ids, 'The license ID is returned by the expiration query.'); } /** * Tests that a cron run won't expire a current license. */ public function testLicenseCronExpiryCurrent(): void { $license_storage = $this->entityTypeManager->getStorage('commerce_license'); $license_owner = $this->createUser(); // Create a license in the 'active' state. $license = $license_storage->create([ 'type' => 'simple', 'state' => 'active', 'product' => 1, 'uid' => $license_owner->id(), // Use the unlimited expiry plugin as it's simple. 'expiration_type' => [ 'target_plugin_id' => 'unlimited', 'target_plugin_configuration' => [], ], ]); $license->save(); // Force the expiration timestamp. // As the state is not being changed, the expiration plugin won't be called. $license->expires = self::tomorrow(); $license->save(); $this->cron->run(); // Check the license has not been changed. $this->assertEquals('active', $license->getState()->getId(), 'The license has not been changed and is still active.'); $queue = $this->container->get('queue')->get('commerce_license_expire'); $this->assertEquals(0, $queue->numberOfItems(), 'The license item was not added to the queue.'); } /** * Tests that a cron run expires an expired license. */ public function testLicenseCronExpiryExpired(): void { $license_storage = $this->entityTypeManager->getStorage('commerce_license'); $license_owner = $this->createUser(); // Create a license in the 'active' state. $license = $license_storage->create([ 'type' => 'simple', 'state' => 'active', 'product' => 1, 'uid' => $license_owner->id(), // Use the unlimited expiry plugin as it's simple. 'expiration_type' => [ 'target_plugin_id' => 'unlimited', 'target_plugin_configuration' => [], ], ]); $license->save(); // Force the expiration timestamp. // As the state is not being changed, the expiration plugin won't be called. $license->expires = self::yesterday(); $license->save(); // This cron run sets up the queued jobs. $this->cron->run(); $license = $this->reloadEntity($license); /** @var \Drupal\advancedqueue\Entity\QueueInterface $queue */ $queue = Queue::load('commerce_license'); $counts = array_filter($queue->getBackend()->countJobs()); $this->assertEquals([Job::STATE_QUEUED => 1], $counts); $job1 = $queue->getBackend()->claimJob(); $this->assertEquals([ 'license_id' => $license->id(), ], $job1->getPayload()); $this->assertEquals('commerce_license_expire', $job1->getType()); } /** * Tests that the LicenseExpire job expires the license. */ public function testLicenseExpireJob(): void { $license_storage = $this->entityTypeManager->getStorage('commerce_license'); $license_owner = $this->createUser(); // Create a license in the 'active' state. $license = $license_storage->create([ 'type' => 'simple', 'state' => 'active', 'product' => 1, 'uid' => $license_owner->id(), // Use the unlimited expiry plugin as it's simple. 'expiration_type' => [ 'target_plugin_id' => 'unlimited', 'target_plugin_configuration' => [], ], ]); $license->save(); // Force the expiration timestamp. // As the state is not being changed, the expiration plugin won't be called. $license->expires = self::yesterday(); $license->save(); $license = $this->reloadEntity($license); $this->assertEquals('active', $license->getState()->getId(), 'The license is currently active.'); /** @var \Drupal\advancedqueue\Entity\QueueInterface $queue */ $queue = Queue::load('commerce_license'); $job = Job::create('commerce_license_expire', ['license_id' => $license->id()]); $queue->enqueueJob($job); $processor = $this->container->get('advancedqueue.processor'); $num_processed = $processor->processQueue($queue); $this->assertEquals(1, $num_processed); $counts = array_filter($queue->getBackend()->countJobs()); $this->assertEquals([Job::STATE_SUCCESS => 1], $counts); $license = $this->reloadEntity($license); $this->assertEquals('expired', $license->getState()->getId(), 'The license is now expired.'); // Note that we don't need to check that the expiry did something, as that // is covered by LicenseStateChangeTest. // Check the notification email is now queued. /** @var \Drupal\advancedqueue\Entity\QueueInterface $queue */ $notification_queue = Queue::load('commerce_license_notify'); $counts = array_filter($notification_queue->getBackend()->countJobs()); $this->assertEquals([Job::STATE_QUEUED => 1], $counts); // Run the notification queue. $num_processed = $processor->processQueue($notification_queue); $this->assertEquals(1, $num_processed); $counts = array_filter($notification_queue->getBackend()->countJobs()); $this->assertEquals([Job::STATE_SUCCESS => 1], $counts); $mails = $this->getMails(); $this->assertCount(1, $mails); $expiry_email = reset($mails); $this->assertEquals('text/html; charset=UTF-8;', $expiry_email['headers']['Content-Type']); $this->assertEquals('8Bit', $expiry_email['headers']['Content-Transfer-Encoding']); $this->assertMailString('subject', 'Your purchase of test license #1 has now expired', 1); $this->assertMailString('body', 'License Expiry', 1); $this->assertMailString('body', 'Your purchase of test license #1 has now expired', 1); // @todo add a product to test the product text. } }