Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/main/java/com/swyp/picke/domain/ad/service/AdQueryService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.swyp.picke.domain.ad.dto.response.AdResponse;
import com.swyp.picke.domain.ad.entity.AdCreative;
import com.swyp.picke.domain.ad.enums.AdSlotCode;
import com.swyp.picke.domain.ad.enums.AdNetwork;
import com.swyp.picke.domain.ad.enums.AdSource;
import com.swyp.picke.domain.ad.enums.AdStatus;
import com.swyp.picke.domain.ad.enums.AdTargetOs;
import com.swyp.picke.domain.ad.repository.AdCreativeRepository;
Expand Down Expand Up @@ -46,6 +48,7 @@ public List<AdResponse> findServableAds(AdSlotCode slot, AdTargetOs os, int size

List<AdCreative> candidates = adCreativeRepository.findAllBySlotAndStatus(slot, AdStatus.ACTIVE).stream()
.filter(creative -> creative.isServable(now))
.filter(this::isShoppingOrManualAd)
.filter(creative -> creative.getTargetOs().matches(requested))
.toList();

Expand All @@ -64,6 +67,7 @@ public List<AdResponse> findLandingAds() {

return adCreativeRepository.findAllByStatusOrderByIdDesc(AdStatus.ACTIVE).stream()
.filter(creative -> creative.isServable(now))
.filter(this::isShoppingOrManualAd)
.map(creative -> AdResponse.of(creative, buildClickUrl(creative)))
.toList();
}
Expand Down Expand Up @@ -101,6 +105,14 @@ private void increaseImpression(ImpressionTarget target, LocalDate today) {
}
}

/** 동기화된 애드픽 설치·가입 캠페인은 제외한다. 쇼핑 식별자는 수집 시 생성한 sh + 해시다. */
private boolean isShoppingOrManualAd(AdCreative creative) {
if (creative.getNetwork() != AdNetwork.ADPICK || creative.getSource() != AdSource.ADPICK_API) {
return true;
}
return creative.getExternalId() != null && creative.getExternalId().matches("sh[0-9a-f]{10}");
}

private String buildClickUrl(AdCreative creative) {
return adBaseUrl + "/c/" + creative.getCode();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.swyp.picke.domain.ad.enums.AdNetwork;
import com.swyp.picke.domain.ad.enums.AdSlotCode;
import com.swyp.picke.domain.ad.enums.AdStatus;
import com.swyp.picke.domain.ad.enums.AdSource;
import com.swyp.picke.domain.ad.enums.AdTargetOs;
import com.swyp.picke.domain.ad.repository.AdCreativeRepository;
import java.time.LocalDate;
Expand Down Expand Up @@ -147,6 +148,44 @@ void findServableAds_filtersByTargetOs() {
assertThat(result).extracting(AdResponse::code).containsExactlyInAnyOrder("ios00001", "all00001");
}

private AdCreative syncedAdpick(String code, String externalId) {
AdCreative ad = creative(code, AdStatus.ACTIVE, 100, null, null);
ReflectionTestUtils.setField(ad, "network", AdNetwork.ADPICK);
ReflectionTestUtils.setField(ad, "source", AdSource.ADPICK_API);
ReflectionTestUtils.setField(ad, "externalId", externalId);
return ad;
}

@Test
void excludesInstallCampaignsEvenWhenShoppingCannotFillRequestedSize() {
var shopping = syncedAdpick("shop0001", "sh012345abcd");
var install = syncedAdpick("app00001", "ukjd9nru");
var signup = syncedAdpick("join0001", "hmvdx3t3");
var coupang = creative("coup0001", AdStatus.ACTIVE, 1, null, null);
when(adCreativeRepository.findAllBySlotAndStatus(AdSlotCode.HOME_FEED, AdStatus.ACTIVE))
.thenReturn(List.of(shopping, install, signup, coupang));

assertThat(adQueryService.findServableAds(AdSlotCode.HOME_FEED, AdTargetOs.ALL, 10))
.extracting(AdResponse::code).containsExactlyInAnyOrder("shop0001", "coup0001");
}

@Test
void doesNotFallbackToInstallAdsWhenThereAreNoShoppingProducts() {
when(adCreativeRepository.findAllBySlotAndStatus(AdSlotCode.HOME_FEED, AdStatus.ACTIVE))
.thenReturn(List.of(syncedAdpick("app00001", "ukjd9nru"),
syncedAdpick("bad00001", null)));
assertThat(adQueryService.findServableAds(AdSlotCode.HOME_FEED, AdTargetOs.ANDROID, 10)).isEmpty();
}

@Test
void landingAlsoExcludesInstallCampaigns() {
when(adCreativeRepository.findAllByStatusOrderByIdDesc(AdStatus.ACTIVE))
.thenReturn(List.of(syncedAdpick("shop0001", "sh012345abcd"),
syncedAdpick("app00001", "ukjd9nru")));
assertThat(adQueryService.findLandingAds()).extracting(AdResponse::code)
.containsExactly("shop0001");
}

@Test
@DisplayName("노출 집계는 같은 날 반복 호출하면 기존 행을 누적한다")
void recordImpressions_incrementsExistingRow() {
Expand Down
Loading