시청 검증 콜백이 없는 테스트 광고 단위에서 광고 추가 기여 POP 지급

This commit is contained in:
Sn-Kinos
2026-10-08 18:51:18 +09:00
parent f7075f0e6f
commit a74edaef6b
2 changed files with 36 additions and 3 deletions
+15 -3
View File
@@ -491,9 +491,21 @@ export const fnAdReward = onCall(async (req) => {
// 시청 증거 — Google 이 서버로 보낸 SSV 콜백(서명 검증 통과분)만 인정한다. // 시청 증거 — Google 이 서버로 보낸 SSV 콜백(서명 검증 통과분)만 인정한다.
const ssv = await db.collection('adSsv') const ssv = await db.collection('adSsv')
.where('uid', '==', uid).where('baseTxId', '==', baseTxId).limit(1).get(); .where('uid', '==', uid).where('baseTxId', '==', baseTxId).limit(1).get();
if (ssv.empty) fail(ERR.adNotVerified, '광고 시청이 아직 확인되지 않았습니다.'); let impressionId: string;
const impressionId = ssv.docs[0]!.id; let network: string;
const network = (ssv.docs[0]!.get('adNetwork') as string | undefined) || 'admob'; if (!ssv.empty) {
impressionId = ssv.docs[0]!.id;
network = (ssv.docs[0]!.get('adNetwork') as string | undefined) || 'admob';
} else if (process.env.AD_REWARD_TEST_UNIT === 'true') {
// Google 공개 **테스트 광고 단위**에는 우리 SSV URL 을 걸 수 없어 콜백이 오지 않는다(r11 3-6 —
// fn-ad-ssv 호출 0건). 앱은 끝까지 본 광고(onUserEarnedReward)에만 이 함수를 부르므로, 테스트 단위를
// 쓰는 서버에서만 그 호출을 시청 완료로 받는다. 서버 .env(개발 서버만)로 켜며 앱이 바꿀 수 없다.
// ponytail: 발주사 AdMob 실 광고 단위 + SSV URL 등록 뒤 이 값을 끄면 SSV 만 인정한다.
impressionId = `test-${baseTxId}`;
network = 'admob-test';
} else {
fail(ERR.adNotVerified, '광고 시청이 아직 확인되지 않았습니다.');
}
const logRef = db.doc(`adRewardLogs/${impressionId}`); const logRef = db.doc(`adRewardLogs/${impressionId}`);
const quest = (await db.doc(`quests/${questId}`).get()).data() ?? {}; const quest = (await db.doc(`quests/${questId}`).get()).data() ?? {};
@@ -370,6 +370,27 @@ describe('클라이언트가 고른 ID 로 한도를 다시 열 수 없다 (리
expect((await ad(baseTxId)).rewarded).toBe(10); expect((await ad(baseTxId)).rewarded).toBe(10);
}); });
it('광고: 테스트 광고 단위(샌드박스)는 SSV 콜백이 오지 않으므로 끝까지 본 호출에 증분을 준다 (r11 3-6)', async () => {
// Google 공개 테스트 광고 단위에는 우리 SSV URL 을 걸 수 없어 fn-ad-ssv 가 한 번도 불리지 않는다.
// 개발 서버(.env.fanuzu-dev-b020d)만 켜는 값이다 — 꺼져 있으면 위 시험대로 E-AD-03.
process.env.AD_REWARD_TEST_UNIT = 'true';
try {
const baseTxId = await baseReward();
const reply = await ad(baseTxId);
expect(reply.rewarded).toBe(10);
const row = only(await adRows());
expect(row.get('popType')).toBe('support');
const log = await db().doc(`adRewardLogs/test-${baseTxId}`).get();
expect(log.get('network')).toBe('admob-test');
expect((await db().doc(`users/${UID}/questProgress/ad`).get()).get('count')).toBe(1);
// 같은 기본 보상에 두 번은 없다.
expect((await ad(baseTxId)).duplicate).toBe(true);
expect((await adRows()).length).toBe(1);
} finally {
delete process.env.AD_REWARD_TEST_UNIT;
}
});
it('광고: 동시에 불러도 한 번만 지급하고, 재전송은 첫 결과를 돌려준다', async () => { it('광고: 동시에 불러도 한 번만 지급하고, 재전송은 첫 결과를 돌려준다', async () => {
const baseTxId = await baseReward(); const baseTxId = await baseReward();
await ssv(baseTxId, 'ssv-a'); await ssv(baseTxId, 'ssv-a');