231 lines
7.5 KiB
PHP
231 lines
7.5 KiB
PHP
<?php
|
|
|
|
use App\Enums\GenerationCreditTransactionType;
|
|
use App\Enums\RewardedAdSessionStatus;
|
|
use App\Models\GenerationCreditBalance;
|
|
use App\Models\GenerationCreditTransaction;
|
|
use App\Models\RewardedAdSession;
|
|
use App\Models\User;
|
|
use App\Services\AdMobServerSideVerificationVerifier;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\Request;
|
|
use Laravel\Sanctum\Sanctum;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function (): void {
|
|
config()->set('admob.rewarded.android_ad_unit_id', 'ca-app-pub-test/android-rewarded');
|
|
config()->set('admob.rewarded.ios_ad_unit_id', 'ca-app-pub-test/ios-rewarded');
|
|
config()->set('admob.rewarded.reward_amount', 1);
|
|
config()->set('admob.rewarded.reward_item', 'generation_credit');
|
|
|
|
$this->app->instance(
|
|
AdMobServerSideVerificationVerifier::class,
|
|
new class extends AdMobServerSideVerificationVerifier
|
|
{
|
|
public function verify(Request $request): void
|
|
{
|
|
//
|
|
}
|
|
},
|
|
);
|
|
});
|
|
|
|
it('returns the generation credit status', function () {
|
|
$user = User::factory()->create();
|
|
|
|
GenerationCreditBalance::factory()->create([
|
|
'user_id' => $user->id,
|
|
'balance' => 2,
|
|
]);
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$this
|
|
->getJson('/api/me/generation-credits')
|
|
->assertOk()
|
|
->assertJsonPath('data.balance', 2)
|
|
->assertJsonPath('data.canWatchRewardedAd', true)
|
|
->assertJsonPath('data.rewardedAdConfigured', true);
|
|
});
|
|
|
|
it('creates a rewarded ad session for the current day', function () {
|
|
$user = User::factory()->create();
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$response = $this
|
|
->postJson('/api/me/rewarded-ad-sessions', [
|
|
'platform' => 'android',
|
|
])
|
|
->assertCreated()
|
|
->assertJsonPath('data.adUnitId', 'ca-app-pub-test/android-rewarded')
|
|
->assertJsonPath('data.userId', $user->id);
|
|
|
|
$session = RewardedAdSession::query()->sole();
|
|
|
|
expect($session->custom_data)->toBe($response->json('data.customData'))
|
|
->and($session->status)->toBe(RewardedAdSessionStatus::CREATED)
|
|
->and($session->reward_date->toDateString())->toBe(now('UTC')->toDateString());
|
|
});
|
|
|
|
it('reuses an active rewarded ad session', function () {
|
|
$user = User::factory()->create();
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$firstSessionId = $this
|
|
->postJson('/api/me/rewarded-ad-sessions', [
|
|
'platform' => 'ios',
|
|
])
|
|
->assertCreated()
|
|
->json('data.id');
|
|
|
|
$this
|
|
->postJson('/api/me/rewarded-ad-sessions', [
|
|
'platform' => 'ios',
|
|
])
|
|
->assertOk()
|
|
->assertJsonPath('data.id', $firstSessionId);
|
|
|
|
expect(RewardedAdSession::query()->count())->toBe(1);
|
|
});
|
|
|
|
it('grants one generation credit from a verified rewarded ad callback', function () {
|
|
$user = User::factory()->create();
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$sessionPayload = $this
|
|
->postJson('/api/me/rewarded-ad-sessions', [
|
|
'platform' => 'android',
|
|
])
|
|
->assertCreated()
|
|
->json('data');
|
|
|
|
$this
|
|
->get('/api/admob/rewarded-ads/callback?'.http_build_query([
|
|
'ad_network' => '5450213213286189855',
|
|
'ad_unit' => 'ca-app-pub-test/android-rewarded',
|
|
'custom_data' => $sessionPayload['customData'],
|
|
'reward_amount' => 1,
|
|
'reward_item' => 'generation_credit',
|
|
'timestamp' => now()->getTimestampMs(),
|
|
'transaction_id' => 'reward-transaction-1',
|
|
'user_id' => $user->id,
|
|
]))
|
|
->assertOk()
|
|
->assertSee('ok');
|
|
|
|
$transaction = GenerationCreditTransaction::query()->sole();
|
|
$session = RewardedAdSession::query()->sole();
|
|
|
|
expect($transaction->type)->toBe(GenerationCreditTransactionType::AD_REWARD)
|
|
->and($transaction->amount)->toBe(1)
|
|
->and($transaction->daily_reward_key)->toBe('ad:'.$session->reward_date->toDateString())
|
|
->and($session->status)->toBe(RewardedAdSessionStatus::REWARDED)
|
|
->and(GenerationCreditBalance::query()->whereKey($user->id)->value('balance'))->toBe(1);
|
|
});
|
|
|
|
it('accepts the numeric ad unit id returned by admob callbacks', function () {
|
|
$user = User::factory()->create();
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$sessionPayload = $this
|
|
->postJson('/api/me/rewarded-ad-sessions', [
|
|
'platform' => 'android',
|
|
])
|
|
->assertCreated()
|
|
->json('data');
|
|
|
|
$this
|
|
->get('/api/admob/rewarded-ads/callback?'.http_build_query([
|
|
'ad_unit' => 'android-rewarded',
|
|
'custom_data' => $sessionPayload['customData'],
|
|
'reward_amount' => 1,
|
|
'reward_item' => 'generation_credit',
|
|
'transaction_id' => 'reward-transaction-numeric-ad-unit',
|
|
'user_id' => $user->id,
|
|
]))
|
|
->assertOk();
|
|
|
|
expect(GenerationCreditBalance::query()->whereKey($user->id)->value('balance'))->toBe(1);
|
|
});
|
|
|
|
it('rejects unexpected rewarded ad units', function () {
|
|
$user = User::factory()->create();
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$sessionPayload = $this
|
|
->postJson('/api/me/rewarded-ad-sessions', [
|
|
'platform' => 'android',
|
|
])
|
|
->assertCreated()
|
|
->json('data');
|
|
|
|
$this
|
|
->get('/api/admob/rewarded-ads/callback?'.http_build_query([
|
|
'ad_unit' => 'unexpected-ad-unit',
|
|
'custom_data' => $sessionPayload['customData'],
|
|
'reward_amount' => 1,
|
|
'reward_item' => 'generation_credit',
|
|
'transaction_id' => 'reward-transaction-unexpected-ad-unit',
|
|
'user_id' => $user->id,
|
|
]))
|
|
->assertBadRequest();
|
|
|
|
expect(GenerationCreditBalance::query()->whereKey($user->id)->value('balance'))->toBeNull();
|
|
});
|
|
|
|
it('does not grant more than one rewarded ad credit per day', function () {
|
|
$user = User::factory()->create();
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$firstSession = RewardedAdSession::factory()->create([
|
|
'user_id' => $user->id,
|
|
'reward_date' => now('UTC')->toDateString(),
|
|
]);
|
|
$secondSession = RewardedAdSession::factory()->create([
|
|
'user_id' => $user->id,
|
|
'reward_date' => now('UTC')->toDateString(),
|
|
]);
|
|
|
|
foreach ([$firstSession, $secondSession] as $index => $session) {
|
|
$this
|
|
->get('/api/admob/rewarded-ads/callback?'.http_build_query([
|
|
'ad_unit' => 'ca-app-pub-test/android-rewarded',
|
|
'custom_data' => $session->custom_data,
|
|
'reward_amount' => 1,
|
|
'reward_item' => 'generation_credit',
|
|
'transaction_id' => 'reward-transaction-'.$index,
|
|
'user_id' => $user->id,
|
|
]))
|
|
->assertOk();
|
|
}
|
|
|
|
expect(GenerationCreditTransaction::query()->where('type', GenerationCreditTransactionType::AD_REWARD)->count())->toBe(1)
|
|
->and(GenerationCreditBalance::query()->whereKey($user->id)->value('balance'))->toBe(1)
|
|
->and($secondSession->refresh()->status)->toBe(RewardedAdSessionStatus::REJECTED);
|
|
});
|
|
|
|
it('prevents new rewarded ad sessions after today reward is claimed', function () {
|
|
$user = User::factory()->create();
|
|
|
|
GenerationCreditTransaction::factory()->create([
|
|
'user_id' => $user->id,
|
|
'daily_reward_key' => 'ad:'.now('UTC')->toDateString(),
|
|
]);
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$this
|
|
->postJson('/api/me/rewarded-ad-sessions', [
|
|
'platform' => 'android',
|
|
])
|
|
->assertUnprocessable()
|
|
->assertJsonPath('message', __('api.generation_credits.rewarded_ad_unavailable'));
|
|
});
|