2024-01-11 16:52:55 +00:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Tests\Integration\Services;
|
|
|
|
|
|
|
|
|
|
use App\Exceptions\FailedToActivateLicenseException;
|
2024-03-22 20:34:32 +00:00
|
|
|
|
use App\Http\Integrations\LemonSqueezy\Requests\ActivateLicenseRequest;
|
|
|
|
|
use App\Http\Integrations\LemonSqueezy\Requests\DeactivateLicenseRequest;
|
|
|
|
|
use App\Http\Integrations\LemonSqueezy\Requests\ValidateLicenseRequest;
|
2024-01-11 16:52:55 +00:00
|
|
|
|
use App\Models\License;
|
|
|
|
|
use App\Services\LicenseService;
|
|
|
|
|
use App\Values\LicenseStatus;
|
|
|
|
|
use Illuminate\Http\Response;
|
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
|
use Illuminate\Support\Facades\File;
|
2024-10-24 10:45:45 +00:00
|
|
|
|
use PHPUnit\Framework\Attributes\Test;
|
2024-03-22 20:34:32 +00:00
|
|
|
|
use Saloon\Http\Faking\MockResponse;
|
|
|
|
|
use Saloon\Laravel\Facades\Saloon;
|
2024-01-11 16:52:55 +00:00
|
|
|
|
use Tests\TestCase;
|
|
|
|
|
|
|
|
|
|
use function Tests\test_path;
|
|
|
|
|
|
|
|
|
|
class LicenseServiceTest extends TestCase
|
|
|
|
|
{
|
|
|
|
|
private LicenseService $service;
|
|
|
|
|
|
|
|
|
|
public function setUp(): void
|
|
|
|
|
{
|
|
|
|
|
parent::setUp();
|
|
|
|
|
|
|
|
|
|
$this->service = app(LicenseService::class);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function activateLicense(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
|
|
|
|
config(['lemonsqueezy.store_id' => 42]);
|
|
|
|
|
$key = '38b1460a-5104-4067-a91d-77b872934d51';
|
|
|
|
|
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::fake([
|
|
|
|
|
ActivateLicenseRequest::class => MockResponse::make(
|
|
|
|
|
body: File::get(test_path('blobs/lemonsqueezy/license-activated-successful.json')),
|
|
|
|
|
),
|
|
|
|
|
]);
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
$license = $this->service->activate($key);
|
|
|
|
|
|
|
|
|
|
self::assertSame($key, $license->key);
|
|
|
|
|
self::assertNotNull($license->instance);
|
|
|
|
|
self::assertSame('Luke Skywalker', $license->meta->customerName);
|
|
|
|
|
self::assertSame('luke@skywalker.com', $license->meta->customerEmail);
|
|
|
|
|
|
|
|
|
|
/** @var LicenseStatus $cachedLicenseStatus */
|
|
|
|
|
$cachedLicenseStatus = Cache::get('license_status');
|
|
|
|
|
|
|
|
|
|
self::assertSame($license->key, $cachedLicenseStatus->license->key);
|
|
|
|
|
self::assertTrue($cachedLicenseStatus->isValid());
|
2024-03-22 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
Saloon::assertSent(static function (ActivateLicenseRequest $request) use ($key): bool {
|
|
|
|
|
self::assertSame([
|
|
|
|
|
'license_key' => $key,
|
|
|
|
|
'instance_name' => 'Koel Plus',
|
|
|
|
|
], $request->body()->all());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
2024-01-11 16:52:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function activateLicenseFailsBecauseOfIncorrectStoreId(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
2024-03-22 20:34:32 +00:00
|
|
|
|
$this->expectException(FailedToActivateLicenseException::class);
|
|
|
|
|
$this->expectExceptionMessage('This license key is not from Koel’s official store.');
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
config(['lemonsqueezy.store_id' => 43]);
|
|
|
|
|
$key = '38b1460a-5104-4067-a91d-77b872934d51';
|
|
|
|
|
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::fake([
|
|
|
|
|
ActivateLicenseRequest::class => MockResponse::make(
|
|
|
|
|
body: File::get(test_path('blobs/lemonsqueezy/license-activated-successful.json')),
|
|
|
|
|
),
|
|
|
|
|
]);
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
$this->service->activate($key);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function activateLicenseFailsForInvalidLicenseKey(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
2024-03-22 20:34:32 +00:00
|
|
|
|
$this->expectException(FailedToActivateLicenseException::class);
|
|
|
|
|
$this->expectExceptionMessage('license_key not found');
|
|
|
|
|
|
|
|
|
|
Saloon::fake([
|
|
|
|
|
ActivateLicenseRequest::class => MockResponse::make(
|
|
|
|
|
body: File::get(test_path('blobs/lemonsqueezy/license-invalid.json')),
|
|
|
|
|
status: Response::HTTP_NOT_FOUND,
|
|
|
|
|
),
|
2024-01-11 16:52:55 +00:00
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$this->service->activate('invalid-key');
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function deactivateLicense(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
|
|
|
|
/** @var License $license */
|
|
|
|
|
$license = License::factory()->create();
|
|
|
|
|
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::fake([
|
|
|
|
|
DeactivateLicenseRequest::class => MockResponse::make(
|
|
|
|
|
body: File::get(test_path('blobs/lemonsqueezy/license-deactivated-successful.json')),
|
|
|
|
|
status: Response::HTTP_NOT_FOUND,
|
|
|
|
|
),
|
|
|
|
|
]);
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
$this->service->deactivate($license);
|
|
|
|
|
|
|
|
|
|
self::assertModelMissing($license);
|
|
|
|
|
self::assertFalse(Cache::has('license_status'));
|
2024-03-22 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
Saloon::assertSent(static function (DeactivateLicenseRequest $request) use ($license): bool {
|
|
|
|
|
self::assertSame([
|
|
|
|
|
'license_key' => $license->key,
|
|
|
|
|
'instance_id' => $license->instance->id,
|
|
|
|
|
], $request->body()->all());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
2024-01-11 16:52:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function deactivateLicenseHandlesLeftoverRecords(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
|
|
|
|
/** @var License $license */
|
|
|
|
|
$license = License::factory()->create();
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::fake([DeactivateLicenseRequest::class => MockResponse::make(status: Response::HTTP_NOT_FOUND)]);
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
$this->service->deactivate($license);
|
|
|
|
|
|
|
|
|
|
self::assertModelMissing($license);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function deactivateLicenseFails(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
2024-03-22 20:34:32 +00:00
|
|
|
|
$this->expectExceptionMessage('Unprocessable Entity (422) Response: Something went horrible wrong');
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
/** @var License $license */
|
|
|
|
|
$license = License::factory()->create();
|
|
|
|
|
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::fake([
|
|
|
|
|
DeactivateLicenseRequest::class => MockResponse::make(
|
|
|
|
|
body: 'Something went horrible wrong',
|
|
|
|
|
status: Response::HTTP_UNPROCESSABLE_ENTITY
|
|
|
|
|
),
|
|
|
|
|
]);
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
$this->service->deactivate($license);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function getLicenseStatusFromCache(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::fake([]);
|
|
|
|
|
|
2024-01-11 16:52:55 +00:00
|
|
|
|
/** @var License $license */
|
|
|
|
|
$license = License::factory()->create();
|
|
|
|
|
|
|
|
|
|
Cache::put('license_status', LicenseStatus::valid($license));
|
|
|
|
|
|
|
|
|
|
self::assertTrue($this->service->getStatus()->license->is($license));
|
|
|
|
|
self::assertTrue($this->service->getStatus()->isValid());
|
2024-03-22 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
Saloon::assertNothingSent();
|
2024-01-11 16:52:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function getLicenseStatusWithNoLicenses(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::fake([]);
|
2024-01-11 16:52:55 +00:00
|
|
|
|
License::query()->delete();
|
|
|
|
|
|
|
|
|
|
self::assertTrue($this->service->getStatus()->hasNoLicense());
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::assertNothingSent();
|
2024-01-11 16:52:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function getLicenseStatusValidatesWithApi(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
|
|
|
|
/** @var License $license */
|
|
|
|
|
$license = License::factory()->create();
|
|
|
|
|
|
|
|
|
|
self::assertFalse(Cache::has('license_status'));
|
|
|
|
|
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::fake([
|
|
|
|
|
ValidateLicenseRequest::class => MockResponse::make(
|
|
|
|
|
body: File::get(test_path('blobs/lemonsqueezy/license-validated-successful.json')),
|
|
|
|
|
),
|
|
|
|
|
]);
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
self::assertTrue($this->service->getStatus()->isValid());
|
|
|
|
|
self::assertTrue(Cache::has('license_status'));
|
2024-03-22 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
Saloon::assertSent(static function (ValidateLicenseRequest $request) use ($license): bool {
|
|
|
|
|
self::assertSame([
|
|
|
|
|
'license_key' => $license->key,
|
|
|
|
|
'instance_id' => $license->instance->id,
|
|
|
|
|
], $request->body()->all());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
2024-01-11 16:52:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 10:45:45 +00:00
|
|
|
|
#[Test]
|
|
|
|
|
public function getLicenseStatusValidatesWithApiWithInvalidLicense(): void
|
2024-01-11 16:52:55 +00:00
|
|
|
|
{
|
2024-03-22 20:34:32 +00:00
|
|
|
|
License::factory()->create();
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
self::assertFalse(Cache::has('license_status'));
|
|
|
|
|
|
2024-03-22 20:34:32 +00:00
|
|
|
|
Saloon::fake([ValidateLicenseRequest::class => MockResponse::make(status: Response::HTTP_NOT_FOUND)]);
|
2024-01-11 16:52:55 +00:00
|
|
|
|
|
|
|
|
|
self::assertFalse($this->service->getStatus()->isValid());
|
|
|
|
|
self::assertTrue(Cache::has('license_status'));
|
|
|
|
|
}
|
|
|
|
|
}
|