Skip to content
Merged
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public class ConfiantAdQualityModuleConfiguration {
ConfiantAdQualityModule confiantAdQualityModule(
@Value("${hooks.modules.confiant-ad-quality.api-key}") String apiKey,
@Value("${hooks.modules.confiant-ad-quality.scan-state-check-interval}") int scanStateCheckInterval,
@Value("${hooks.modules.confiant-ad-quality.bidders-to-exclude-from-scan}") List<String> biddersToExcludeFromScan,
@Value("${hooks.modules.confiant-ad-quality.bidders-to-exclude-from-scan}")
List<String> biddersToExcludeFromScan,
RedisConfig redisConfig,
RedisRetryConfig retryConfig,
Vertx vertx,
Expand All @@ -43,13 +44,24 @@ ConfiantAdQualityModule confiantAdQualityModule(

final RedisConnectionConfig writeNodeConfig = redisConfig.getWriteNode();
final RedisClient writeRedisNode = new RedisClient(
vertx, writeNodeConfig.getHost(), writeNodeConfig.getPort(), writeNodeConfig.getPassword(), retryConfig, "write node");
vertx,
writeNodeConfig.getHost(),
writeNodeConfig.getPort(),
writeNodeConfig.getPassword(),
retryConfig,
"write node");
final RedisConnectionConfig readNodeConfig = redisConfig.getReadNode();
final RedisClient readRedisNode = new RedisClient(
vertx, readNodeConfig.getHost(), readNodeConfig.getPort(), readNodeConfig.getPassword(), retryConfig, "read node");
vertx,
readNodeConfig.getHost(),
readNodeConfig.getPort(),
readNodeConfig.getPassword(),
retryConfig,
"read node");

final BidsScanner bidsScanner = new BidsScanner(writeRedisNode, readRedisNode, apiKey, objectMapper);
final RedisScanStateChecker redisScanStateChecker = new RedisScanStateChecker(bidsScanner, scanStateCheckInterval, vertx);
final RedisScanStateChecker redisScanStateChecker = new RedisScanStateChecker(
bidsScanner, scanStateCheckInterval, vertx);

final Promise<Void> scannerPromise = Promise.promise();
scannerPromise.future().onComplete(r -> redisScanStateChecker.run());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@ public class AnalyticsMapper {
private static final String INSPECTED_HAS_ISSUE = "inspected-has-issue";
private static final String INSPECTED_NO_ISSUES = "inspected-no-issues";

private AnalyticsMapper() {
}

public static Tags toAnalyticsTags(List<BidderResponse> bidderResponsesWithIssues,
List<BidderResponse> bidderResponsesWithoutIssues,
List<BidderResponse> bidderResponsesNotScanned) {

return TagsImpl.of(Collections.singletonList(ActivityImpl.of(
AD_QUALITY_SCAN,
SUCCESS_STATUS,
toActivityResults(bidderResponsesWithIssues, bidderResponsesWithoutIssues, bidderResponsesNotScanned))));
toActivityResults(
bidderResponsesWithIssues,
bidderResponsesWithoutIssues,
bidderResponsesNotScanned))));
}

private static List<Result> toActivityResults(List<BidderResponse> bidderResponsesWithIssues,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,32 @@

public class BidsMapper {

public static RedisBidsData toRedisBidsFromBidResponses(
BidRequest bidRequest,
List<BidderResponse> bidderResponses) {
private BidsMapper() {
}

public static RedisBidsData toRedisBidsFromBidResponses(BidRequest bidRequest,
List<BidderResponse> bidderResponses) {

final List<RedisBidResponseData> confiantBidResponses = bidderResponses
.stream().map(bidResponse -> RedisBidResponseData
final List<RedisBidResponseData> confiantBidResponses = bidderResponses.stream()
.map(bidResponse -> RedisBidResponseData
.builder()
.dspId(bidResponse.getBidder())
.bidresponse(toBidResponseFromBidderResponse(bidRequest, bidResponse))
.build()).toList();
.build())
.toList();

return RedisBidsData.builder()
.breq(bidRequest)
.bresps(confiantBidResponses)
.build();
}

private static BidResponse toBidResponseFromBidderResponse(
BidRequest bidRequest,
BidderResponse bidderResponse) {
private static BidResponse toBidResponseFromBidderResponse(BidRequest bidRequest,
BidderResponse bidderResponse) {

return BidResponse.builder()
.id(bidRequest.getId())
.cur(bidRequest.getCur().get(0))
.cur(bidRequest.getCur().getFirst())
.seatbid(Collections.singletonList(SeatBid.builder()
.bid(bidderResponse.getSeatBid().getBids().stream().map(BidderBid::getBid).toList())
.build()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,18 @@ public Future<BidsScanResult> submitBids(RedisBidsData bids) {

final RedisAPI readRedisNodeAPI = this.readRedisNode.getRedisAPI();
final boolean shouldSubmit = !isScanDisabled
&& readRedisNodeAPI != null && bids.getBresps().size() > 0;
&& readRedisNodeAPI != null && !bids.getBresps().isEmpty();

if (shouldSubmit) {
readRedisNodeAPI.get("function_submit_bids", submitHash -> {
final Object submitHashResult = submitHash.result();
if (submitHashResult != null) {
final List<String> readArgs = List.of(submitHashResult.toString(), "0", toBidsAsJson(bids), apiKey, "true");
final List<String> readArgs = List.of(
submitHashResult.toString(),
"0",
toBidsAsJson(bids),
apiKey,
"true");

readRedisNodeAPI.evalsha(readArgs, response -> {
if (response.result() != null) {
Expand Down Expand Up @@ -120,7 +125,7 @@ public Future<Boolean> isScanDisabledFlag() {
if (redisAPI != null) {
redisAPI.get("scan-disabled", scanDisabledValue -> {
final Response scanDisabled = scanDisabledValue.result();
isDisabled.complete(scanDisabled != null && scanDisabled.toString().equals("true"));
isDisabled.complete(scanDisabled != null && "true".equals(scanDisabled.toString()));
});

return isDisabled.future();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ private void attemptReconnect(int retry, Handler<AsyncResult<RedisConnection>> h
if (retry > (retryConfig.getShortIntervalAttempts() + retryConfig.getLongIntervalAttempts())) {
logger.info("Confiant Redis connection is not established");
} else {
long backoff = retry < retryConfig.getShortIntervalAttempts()
final long backoff = retry < retryConfig.getShortIntervalAttempts()
? retryConfig.getShortInterval()
: retryConfig.getLongInterval();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public BidsScanResult parseBidsScanResult(String redisResponse) {
} catch (JsonProcessingException resultParse) {
String message;
try {
RedisError errorResponse = objectMapper.readValue(redisResponse, RedisError.class);
final RedisError errorResponse = objectMapper.readValue(redisResponse, RedisError.class);
message = String.format("Redis error - %s: %s", errorResponse.getCode(), errorResponse.getMessage());
} catch (JsonProcessingException errorParse) {
message = String.format("Error during parse redis response: %s", redisResponse);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,26 @@
@Data
public class RedisRetryConfig {

/** Maximum attempts with short interval value to try to reconnect to Confiant's Redis server in case any connection error happens */
/**
* Maximum attempts with short interval value to try to reconnect to
* Confiant's Redis server in case any connection error happens
*/
int shortIntervalAttempts;

/** Short time interval in milliseconds after which another one attempt to connect to Redis will be executed */
/**
* Short time interval in milliseconds after which another one attempt to connect to Redis will be executed
*/
int shortInterval;

/** Maximum attempts with long interval value to try to reconnect to Confiant's Redis server in case any connection error happens. This attempts are used when short-attempts were not successful */
/**
* Maximum attempts with long interval value to try to reconnect to
* Confiant's Redis server in case any connection error happens.
* This attempts are used when short-attempts were not successful
*/
int longIntervalAttempts;

/** Long time interval in milliseconds after which another one attempt to connect to Redis will be executed */
/**
* Long time interval in milliseconds after which another one attempt to connect to Redis will be executed
*/
int longInterval;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.iab.openrtb.request.Device;
import com.iab.openrtb.request.User;
import io.vertx.core.Future;
import org.apache.commons.collections4.ListUtils;
import org.prebid.server.activity.Activity;
import org.prebid.server.activity.ComponentType;
import org.prebid.server.activity.infrastructure.payload.ActivityInvocationPayload;
Expand All @@ -12,6 +13,7 @@
import org.prebid.server.auction.model.AuctionContext;
import org.prebid.server.auction.model.BidderResponse;
import org.prebid.server.auction.privacy.enforcement.mask.UserFpdActivityMask;
import org.prebid.server.hooks.execution.v1.InvocationResultImpl;
import org.prebid.server.hooks.execution.v1.bidder.AllProcessedBidResponsesPayloadImpl;
import org.prebid.server.hooks.modules.com.confiant.adquality.core.AnalyticsMapper;
import org.prebid.server.hooks.modules.com.confiant.adquality.core.BidsMapper;
Expand All @@ -20,7 +22,6 @@
import org.prebid.server.hooks.modules.com.confiant.adquality.model.GroupByIssues;
import org.prebid.server.hooks.v1.InvocationAction;
import org.prebid.server.hooks.v1.InvocationResult;
import org.prebid.server.hooks.execution.v1.InvocationResultImpl;
import org.prebid.server.hooks.v1.InvocationStatus;
import org.prebid.server.hooks.v1.auction.AuctionInvocationContext;
import org.prebid.server.hooks.v1.bidder.AllProcessedBidResponsesHook;
Expand All @@ -31,7 +32,6 @@
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ConfiantAdQualityBidResponsesScanHook implements AllProcessedBidResponsesHook {

Expand Down Expand Up @@ -117,7 +117,7 @@ private InvocationResult<AllProcessedBidResponsesPayload> toInvocationResult(
.analyticsTags(AnalyticsMapper.toAnalyticsTags(
bidderResponsesWithIssues, bidderResponsesWithoutIssues, notScannedBidderResponses))
.payloadUpdate(payload -> AllProcessedBidResponsesPayloadImpl.of(
Stream.concat(bidderResponsesWithoutIssues.stream(), notScannedBidderResponses.stream()).toList()));
ListUtils.union(bidderResponsesWithoutIssues, notScannedBidderResponses)));

return resultBuilder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.prebid.server.hooks.modules.com.confiant.adquality.core.AnalyticsMapper.toAnalyticsTags;

public class AnalyticsMapperTest {

Expand All @@ -29,7 +30,10 @@ public void shouldMapBidsScanResultToAnalyticsTags() {
AdQualityModuleTestUtils.getBidderResponse("bidder_d", "imp_d", "bid_id_d"));

// when
final Tags tags = AnalyticsMapper.toAnalyticsTags(bidderResponsesWithIssues, bidderResponsesWithoutIssues, bidderResponsesNotScanned);
final Tags tags = toAnalyticsTags(
bidderResponsesWithIssues,
bidderResponsesWithoutIssues,
bidderResponsesNotScanned);

// then
assertThat(tags.activities()).isEqualTo(singletonList(ActivityImpl.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ public void shouldMapBidResponsesToRedisBids() {
assertThat(redisBidResponseData1.getBidresponse().getId()).isEqualTo(bidRequest.getId());
assertThat(redisBidResponseData1.getBidresponse().getCur()).isEqualTo(bidRequest.getCur().get(0));
assertThat(redisBidResponseData1.getBidresponse().getSeatbid()).hasSize(1);
SeatBid seatBid1 = redisBidResponseData1.getBidresponse().getSeatbid().get(0);
final SeatBid seatBid1 = redisBidResponseData1.getBidresponse().getSeatbid().get(0);
assertThat(seatBid1.getBid()).hasSize(1);
assertThat(seatBid1.getBid().get(0).getId()).isEqualTo(bidderResponse1.getSeatBid().getBids().get(0).getBid().getId());
assertThat(seatBid1.getBid().getFirst().getId())
.isEqualTo(bidderResponse1.getSeatBid().getBids().getFirst().getBid().getId());

final RedisBidResponseData redisBidResponseData2 = result.getBresps().get(1);
assertThat(redisBidResponseData2.getDspId()).isEqualTo(bidderResponse2.getBidder());
Expand All @@ -53,6 +54,7 @@ public void shouldMapBidResponsesToRedisBids() {

final SeatBid seatBid2 = redisBidResponseData2.getBidresponse().getSeatbid().get(0);
assertThat(seatBid2.getBid()).hasSize(1);
assertThat(seatBid2.getBid().get(0).getId()).isEqualTo(bidderResponse2.getSeatBid().getBids().get(0).getBid().getId());
assertThat(seatBid2.getBid().getFirst().getId())
.isEqualTo(bidderResponse2.getSeatBid().getBids().getFirst().getBid().getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
import org.junit.jupiter.api.Test;
import org.prebid.server.auction.model.BidderResponse;
import org.prebid.server.hooks.modules.com.confiant.adquality.model.GroupByIssues;
import org.prebid.server.hooks.modules.com.confiant.adquality.util.AdQualityModuleTestUtils;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.prebid.server.hooks.modules.com.confiant.adquality.util.AdQualityModuleTestUtils.getBidderResponse;

public class BidsScanResultTest {

Expand All @@ -17,15 +17,28 @@ public class BidsScanResultTest {
@Test
public void shouldProperlyGetIssuesMessage() {
// given
final String redisResponse = "[[[{\"tag_key\": \"key_a\", \"imp_id\": \"imp_a\", \"issues\": [{ \"value\": \"ads.deceivenetworks.net\", \"spec_name\": \"malicious_domain\", \"first_adinstance\": \"e91e8da982bb8b7f80100426\"}]}]]]";
final String redisResponse = """
[[[{
"tag_key": "key_a",
"imp_id": "imp_a",
"issues": [{
"value": "ads.deceivenetworks.net",
"spec_name": "malicious_domain",
"first_adinstance": "e91e8da982bb8b7f80100426"
}]
}]]]""";
final BidsScanResult bidsScanResult = redisParser.parseBidsScanResult(redisResponse);

// when
final List<String> issues = bidsScanResult.getIssuesMessages();

// then
assertThat(issues.size()).isEqualTo(1);
assertThat(issues.get(0)).isEqualTo("key_a: [Issue(specName=malicious_domain, value=ads.deceivenetworks.net, firstAdinstance=e91e8da982bb8b7f80100426)]");
assertThat(issues.getFirst()).isEqualTo("""
key_a: [\
Issue(specName=malicious_domain, \
value=ads.deceivenetworks.net, \
firstAdinstance=e91e8da982bb8b7f80100426)]""");
}

@Test
Expand All @@ -39,16 +52,31 @@ public void shouldProperlyGetDebugMessage() {

// then
assertThat(messages.size()).isEqualTo(1);
assertThat(messages.get(0)).isEqualTo("Error during parse redis response: invalid redis response");
assertThat(messages.getFirst()).isEqualTo("Error during parse redis response: invalid redis response");
}

@Test
public void shouldProperlyGroupBiddersByIssues() {
// given
final String redisResponse = "[[[{\"tag_key\": \"key_a\", \"imp_id\": \"imp_a\", \"issues\": [{ \"value\": \"ads.deceivenetworks.net\", \"spec_name\": \"malicious_domain\", \"first_adinstance\": \"e91e8da982bb8b7f80100426\"}]}],[{\"tag_key\": \"key_b\", \"imp_id\": \"imp_b\"}]]]";
final String redisResponse = """
[[
[{
"tag_key": "key_a",
"imp_id": "imp_a",
"issues": [{
"value": "ads.deceivenetworks.net",
"spec_name": "malicious_domain",
"first_adinstance": "e91e8da982bb8b7f80100426"
}]
}],
[{
"tag_key": "key_b",
"imp_id": "imp_b"
}]
]]""";
final BidsScanResult bidsScanResult = redisParser.parseBidsScanResult(redisResponse);
final BidderResponse br1 = AdQualityModuleTestUtils.getBidderResponse("critio1", "1", "11");
final BidderResponse br2 = AdQualityModuleTestUtils.getBidderResponse("critio2", "2", "12");
final BidderResponse br1 = getBidderResponse("critio1", "1", "11");
final BidderResponse br2 = getBidderResponse("critio2", "2", "12");

// when
final GroupByIssues<BidderResponse> groupByIssues = bidsScanResult.toGroupByIssues(List.of(br1, br2));
Expand All @@ -63,10 +91,20 @@ public void shouldProperlyGroupBiddersByIssues() {
@Test
public void shouldProperlyGroupBiddersByIssuesWithoutIssues() {
// given
final String redisResponse = "[[[{\"tag_key\": \"key_a\", \"imp_id\": \"imp_a\"}],[{\"tag_key\": \"key_b\", \"imp_id\": \"imp_b\"}]]]";
final String redisResponse = """
[[
[{
"tag_key": "key_a",
"imp_id": "imp_a"
}],
[{
"tag_key": "key_b",
"imp_id": "imp_b"
}]
]]""";
final BidsScanResult bidsScanResult = redisParser.parseBidsScanResult(redisResponse);
final BidderResponse br1 = AdQualityModuleTestUtils.getBidderResponse("critio1", "1", "11");
final BidderResponse br2 = AdQualityModuleTestUtils.getBidderResponse("critio2", "2", "12");
final BidderResponse br1 = getBidderResponse("critio1", "1", "11");
final BidderResponse br2 = getBidderResponse("critio2", "2", "12");

// when
final GroupByIssues<BidderResponse> groupByIssues = bidsScanResult.toGroupByIssues(List.of(br1, br2));
Expand Down
Loading
Loading