diff --git a/components/brave_ads/test/BUILD.gn b/components/brave_ads/test/BUILD.gn index e7f48b75ca71..0dae5ba71f8c 100644 --- a/components/brave_ads/test/BUILD.gn +++ b/components/brave_ads/test/BUILD.gn @@ -21,6 +21,9 @@ source_set("brave_ads_unit_tests") { "//brave/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/payments/payments_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/account/statement/statement_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/ad_diagnostics/ad_diagnostics_test.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_unittest_util.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_unittest_util.h", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/ad_pacing/ad_pacing_test.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/ad_priority/ad_priority_test.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving_test.cc", @@ -46,6 +49,10 @@ source_set("brave_ads_unit_tests") { "//brave/vendor/bat-native-ads/src/bat/ads/internal/ads_history/sorts/ads_history_sort_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/base64_util_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/browser_manager/browser_manager_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_unittest_util.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_unittest_util.h", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_unittest_util.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_unittest_util.h", "//brave/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_util_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/container_util_unittest.cc", @@ -74,7 +81,12 @@ source_set("brave_ads_unit_tests") { "//brave/vendor/bat-native-ads/src/bat/ads/internal/database/tables/segments_database_table_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_issue_17199_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_predictor_util_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_util_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads_unittest.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/sample_ads_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/features/ad_rewards/ad_rewards_features_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/features/anti_targeting/anti_targeting_features_unittest.cc", @@ -189,6 +201,12 @@ source_set("brave_ads_unit_tests") { "//brave/vendor/bat-native-ads/src/bat/ads/internal/tokens/refill_unblinded_tokens/request_signed_tokens_url_request_builder_unittest.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_base.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_base.h", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_file_util.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_file_util.h", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_tag_parser_util.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_tag_parser_util.h", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_time_util.cc", + "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_time_util.h", "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.cc", "//brave/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.h", "//brave/vendor/bat-native-ads/src/bat/ads/internal/url_util_unittest.cc", diff --git a/vendor/bat-native-ads/BUILD.gn b/vendor/bat-native-ads/BUILD.gn index d7d79d6a1e3e..d8e36ffb163e 100644 --- a/vendor/bat-native-ads/BUILD.gn +++ b/vendor/bat-native-ads/BUILD.gn @@ -343,6 +343,7 @@ source_set("ads") { "src/bat/ads/internal/bundle/creative_ad_notification_info.cc", "src/bat/ads/internal/bundle/creative_ad_notification_info.h", "src/bat/ads/internal/bundle/creative_ad_notification_info_aliases.h", + "src/bat/ads/internal/bundle/creative_daypart_info.cc", "src/bat/ads/internal/bundle/creative_daypart_info.h", "src/bat/ads/internal/bundle/creative_daypart_info_aliases.h", "src/bat/ads/internal/bundle/creative_inline_content_ad_info.cc", @@ -491,12 +492,22 @@ source_set("ads") { "src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.cc", "src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.h", "src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_aliases.h", + "src/bat/ads/internal/eligible_ads/ad_predictor_info.cc", + "src/bat/ads/internal/eligible_ads/ad_predictor_info.h", + "src/bat/ads/internal/eligible_ads/eligible_ads_aliases.h", "src/bat/ads/internal/eligible_ads/eligible_ads_constants.h", + "src/bat/ads/internal/eligible_ads/eligible_ads_features.cc", + "src/bat/ads/internal/eligible_ads/eligible_ads_features.h", + "src/bat/ads/internal/eligible_ads/eligible_ads_features_util.cc", + "src/bat/ads/internal/eligible_ads/eligible_ads_features_util.h", + "src/bat/ads/internal/eligible_ads/eligible_ads_predictor_util.h", + "src/bat/ads/internal/eligible_ads/eligible_ads_util.h", "src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.cc", "src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.h", "src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads_aliases.h", "src/bat/ads/internal/eligible_ads/round_robin_ads.h", "src/bat/ads/internal/eligible_ads/round_robin_advertisers.h", + "src/bat/ads/internal/eligible_ads/sample_ads.h", "src/bat/ads/internal/eligible_ads/seen_ads.h", "src/bat/ads/internal/eligible_ads/seen_advertisers.h", "src/bat/ads/internal/features/ad_rewards/ad_rewards_features.cc", diff --git a/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_issue_17412_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_issue_17412_test.cc index 9fe38a866bd4..638a0391f9e7 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_issue_17412_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_issue_17412_test.cc @@ -6,6 +6,7 @@ #include "bat/ads/internal/account/ad_rewards/ad_rewards.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" #include "bat/ads/statement_info.h" #include "net/http/http_status_code.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_test.cc index 577468edf4ef..f2a70884d6f5 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/ad_rewards_test.cc @@ -6,6 +6,7 @@ #include "bat/ads/internal/account/ad_rewards/ad_rewards.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" #include "bat/ads/statement_info.h" #include "net/http/http_status_code.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/payments/payments_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/payments/payments_unittest.cc index 5c520f307ed3..3f553fed5d7a 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/payments/payments_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/account/ad_rewards/payments/payments_unittest.cc @@ -8,6 +8,7 @@ #include #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/account/statement/statement_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/account/statement/statement_unittest.cc index 2be7c44a8293..78b6be3dcdf4 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/account/statement/statement_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/account/statement/statement_unittest.cc @@ -12,6 +12,7 @@ #include "bat/ads/internal/account/wallet/wallet.h" #include "bat/ads/internal/account/wallet/wallet_info.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" #include "bat/ads/statement_info.h" #include "net/http/http_status_code.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_unittest_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_unittest_util.cc new file mode 100644 index 000000000000..9a28e88201b5 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_unittest_util.cc @@ -0,0 +1,30 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/ad_events/ad_event_unittest_util.h" + +#include + +#include "base/guid.h" +#include "bat/ads/confirmation_type.h" +#include "bat/ads/internal/ad_events/ad_event_info.h" +#include "bat/ads/internal/bundle/creative_ad_info.h" + +namespace ads { + +AdEventInfo GetAdEvent(const CreativeAdInfo& creative_ad, + const ConfirmationType confirmation_type, + const base::Time& time) { + AdEventInfo ad_event; + ad_event.uuid = base::GenerateGUID(); + ad_event.confirmation_type = confirmation_type; + ad_event.creative_instance_id = creative_ad.creative_instance_id; + ad_event.advertiser_id = creative_ad.advertiser_id; + ad_event.timestamp = static_cast(time.ToDoubleT()); + + return ad_event; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_unittest_util.h b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_unittest_util.h new file mode 100644 index 000000000000..578822082843 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_unittest_util.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_AD_EVENTS_AD_EVENT_UNITTEST_UTIL_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_AD_EVENTS_AD_EVENT_UNITTEST_UTIL_H_ + +#include "base/time/time.h" + +namespace ads { + +struct AdEventInfo; +class ConfirmationType; +struct CreativeAdInfo; + +AdEventInfo GetAdEvent(const CreativeAdInfo& creative_ad, + const ConfirmationType confirmation_type, + const base::Time& time); + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_AD_EVENTS_AD_EVENT_UNITTEST_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util.cc index 06ed05d984d2..ff3124844cba 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util.cc @@ -5,7 +5,9 @@ #include "bat/ads/internal/ad_events/ad_event_util.h" +#include "base/time/time.h" #include "bat/ads/ad_info.h" +#include "bat/ads/internal/bundle/creative_ad_info.h" namespace ads { @@ -23,4 +25,39 @@ bool HasFiredAdViewedEvent(const AdInfo& ad, const AdEventList& ad_events) { return true; } +absl::optional GetLastSeenAdTime( + const AdEventList& ad_events, + const CreativeAdInfo& creative_ad) { + const auto iter = std::find_if( + ad_events.begin(), ad_events.end(), + [&creative_ad](const AdEventInfo& ad_event) -> bool { + return (ad_event.creative_instance_id == + creative_ad.creative_instance_id && + ad_event.confirmation_type == ConfirmationType::kViewed); + }); + + if (iter == ad_events.end()) { + return absl::nullopt; + } + + return base::Time::FromDoubleT(static_cast(iter->timestamp)); +} + +absl::optional GetLastSeenAdvertiserTime( + const AdEventList& ad_events, + const CreativeAdInfo& creative_ad) { + const auto iter = std::find_if( + ad_events.begin(), ad_events.end(), + [&creative_ad](const AdEventInfo& ad_event) -> bool { + return (ad_event.advertiser_id == creative_ad.advertiser_id && + ad_event.confirmation_type == ConfirmationType::kViewed); + }); + + if (iter == ad_events.end()) { + return absl::nullopt; + } + + return base::Time::FromDoubleT(static_cast(iter->timestamp)); +} + } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util.h b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util.h index 4b12779660d1..b48e745ba4c0 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util.h @@ -6,14 +6,28 @@ #ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_AD_EVENTS_AD_EVENT_UTIL_H_ #define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_AD_EVENTS_AD_EVENT_UTIL_H_ +#include "bat/ads/internal/ad_events/ad_event_info.h" #include "bat/ads/internal/ad_events/ad_event_info_aliases.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace base { +class Time; +} namespace ads { struct AdInfo; +struct CreativeAdInfo; bool HasFiredAdViewedEvent(const AdInfo& ad, const AdEventList& ad_events); +absl::optional GetLastSeenAdTime(const AdEventList& ad_events, + const CreativeAdInfo& creative_ad); + +absl::optional GetLastSeenAdvertiserTime( + const AdEventList& ad_events, + const CreativeAdInfo& creative_ad); + } // namespace ads #endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_AD_EVENTS_AD_EVENT_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util_unittest.cc new file mode 100644 index 000000000000..5796411ce1f4 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_events/ad_event_util_unittest.cc @@ -0,0 +1,189 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/ad_events/ad_event_util.h" + +#include + +#include "base/guid.h" +#include "bat/ads/internal/ad_events/ad_event_unittest_util.h" +#include "bat/ads/internal/bundle/creative_ad_notification_info.h" +#include "bat/ads/internal/bundle/creative_ad_notification_unittest_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +TEST(BatAdsAdEventUtilTest, GetLastSeenAdTimeForEmptyAdEvents) { + // Arrange + AdEventList ad_events; + + const CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(); + + // Act + const absl::optional ad_last_seen = + GetLastSeenAdTime(ad_events, creative_ad_notification); + + // Assert + EXPECT_EQ(absl::nullopt, ad_last_seen); +} + +TEST(BatAdsAdEventUtilTest, GetLastSeenAdTimeForUnseenAd) { + // Arrange + AdEventList ad_events; + + const CreativeAdNotificationInfo creative_ad_notification_1 = + GetCreativeAdNotification(); + + const base::Time event_time = + base::Time::Now() - base::TimeDelta::FromHours(12); + const AdEventInfo ad_event = GetAdEvent( + creative_ad_notification_1, ConfirmationType::kViewed, event_time); + ad_events.push_back(ad_event); + + // Act + const CreativeAdNotificationInfo creative_ad_notification_2 = + GetCreativeAdNotification(); + const absl::optional ad_last_seen = + GetLastSeenAdTime(ad_events, creative_ad_notification_2); + + // Assert + EXPECT_EQ(absl::nullopt, ad_last_seen); +} + +TEST(BatAdsAdEventUtilTest, GetLastSeenAdTime) { + // Arrange + AdEventList ad_events; + + const base::Time now = base::Time::Now(); + + const CreativeAdNotificationInfo creative_ad_notification_1 = + GetCreativeAdNotification(); + + const CreativeAdNotificationInfo creative_ad_notification_2 = + GetCreativeAdNotification(); + + const AdEventInfo ad_event_4 = + GetAdEvent(creative_ad_notification_1, ConfirmationType::kConversion, + now - base::TimeDelta::FromHours(3)); + ad_events.push_back(ad_event_4); + + const AdEventInfo ad_event_3 = + GetAdEvent(creative_ad_notification_1, ConfirmationType::kViewed, + now - base::TimeDelta::FromHours(6)); + ad_events.push_back(ad_event_3); + + const AdEventInfo ad_event_2 = + GetAdEvent(creative_ad_notification_2, ConfirmationType::kViewed, + now - base::TimeDelta::FromHours(11)); + ad_events.push_back(ad_event_2); + + const AdEventInfo ad_event_1 = + GetAdEvent(creative_ad_notification_1, ConfirmationType::kViewed, + now - base::TimeDelta::FromHours(12)); + ad_events.push_back(ad_event_1); + + // Act + const absl::optional ad_last_seen = + GetLastSeenAdTime(ad_events, creative_ad_notification_1); + + // Assert + const base::Time expected_timestamp = now - base::TimeDelta::FromHours(6); + const base::Time expected_ad_last_seen = base::Time::FromDoubleT( + static_cast(expected_timestamp.ToDoubleT())); + EXPECT_EQ(expected_ad_last_seen, ad_last_seen.value()); +} + +TEST(BatAdsAdEventUtilTest, GetLastSeenAdvertiserTimeForEmptyAdEvents) { + // Arrange + AdEventList ad_events; + + const CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(); + + // Act + const absl::optional advertiser_last_seen = + GetLastSeenAdvertiserTime(ad_events, creative_ad_notification); + + // Assert + EXPECT_EQ(absl::nullopt, advertiser_last_seen); +} + +TEST(BatAdsAdEventUtilTest, GetLastSeenAdvertiserTimeForUnseenAdvertiser) { + // Arrange + AdEventList ad_events; + + const CreativeAdNotificationInfo creative_ad_notification_1 = + GetCreativeAdNotification(); + + const base::Time event_time = + base::Time::Now() - base::TimeDelta::FromHours(12); + const AdEventInfo ad_event = GetAdEvent( + creative_ad_notification_1, ConfirmationType::kViewed, event_time); + ad_events.push_back(ad_event); + + // Act + const CreativeAdNotificationInfo creative_ad_notification_2 = + GetCreativeAdNotification(); + const absl::optional advertiser_last_seen = + GetLastSeenAdvertiserTime(ad_events, creative_ad_notification_2); + + // Assert + EXPECT_EQ(absl::nullopt, advertiser_last_seen); +} + +TEST(BatAdsAdEventUtilTest, GetLastSeenAdvertiserTime) { + // Arrange + AdEventList ad_events; + + const base::Time now = base::Time::Now(); + + const std::string advertiser_id_1 = base::GenerateGUID(); + const CreativeAdNotificationInfo creative_ad_notification_1 = + GetCreativeAdNotificationForAdvertiser(advertiser_id_1); + + const std::string advertiser_id_2 = base::GenerateGUID(); + const CreativeAdNotificationInfo creative_ad_notification_2 = + GetCreativeAdNotificationForAdvertiser(advertiser_id_2); + + const CreativeAdNotificationInfo creative_ad_notification_3 = + GetCreativeAdNotificationForAdvertiser(advertiser_id_1); + + // Ad events are ordered by date DESC in |AdEvents::GetAll()| + const AdEventInfo ad_event_4 = + GetAdEvent(creative_ad_notification_1, ConfirmationType::kViewed, + now - base::TimeDelta::FromHours(3)); + ad_events.push_back(ad_event_4); + + const AdEventInfo ad_event_3 = + GetAdEvent(creative_ad_notification_3, ConfirmationType::kViewed, + now - base::TimeDelta::FromHours(6)); + ad_events.push_back(ad_event_3); + + const AdEventInfo ad_event_2 = + GetAdEvent(creative_ad_notification_2, ConfirmationType::kViewed, + now - base::TimeDelta::FromHours(11)); + ad_events.push_back(ad_event_2); + + const AdEventInfo ad_event_1 = + GetAdEvent(creative_ad_notification_1, ConfirmationType::kViewed, + now - base::TimeDelta::FromHours(12)); + ad_events.push_back(ad_event_1); + + // Act + const absl::optional advertiser_last_seen = + GetLastSeenAdvertiserTime(ad_events, creative_ad_notification_3); + + // Assert + const base::Time expected_timestamp = now - base::TimeDelta::FromHours(3); + const absl::optional expected_advertiser_last_seen = + base::Time::FromDoubleT( + static_cast(expected_timestamp.ToDoubleT())); + EXPECT_EQ(expected_advertiser_last_seen, advertiser_last_seen.value()); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_pacing/ad_pacing_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_pacing/ad_pacing_test.cc index 4810757c5f76..8563713290f2 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_pacing/ad_pacing_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_pacing/ad_pacing_test.cc @@ -9,6 +9,7 @@ #include "bat/ads/internal/frequency_capping/frequency_capping_unittest_util.h" #include "bat/ads/internal/resources/frequency_capping/anti_targeting_resource.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" #include "bat/ads/internal/user_activity/user_activity.h" #include "net/http/http_status_code.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_priority/ad_priority_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_priority/ad_priority_test.cc index 6aaa4bb2979e..cfaaf1fcc25f 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_priority/ad_priority_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_priority/ad_priority_test.cc @@ -10,6 +10,7 @@ #include "bat/ads/internal/frequency_capping/frequency_capping_unittest_util.h" #include "bat/ads/internal/resources/frequency_capping/anti_targeting_resource.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" #include "bat/ads/internal/user_activity/user_activity.h" #include "net/http/http_status_code.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving.cc index 12f9bb60f5f5..1a5b46ae9977 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving.cc @@ -22,6 +22,7 @@ #include "bat/ads/internal/bundle/creative_ad_notification_info.h" #include "bat/ads/internal/client/client.h" #include "bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.h" +#include "bat/ads/internal/features/ad_serving/ad_serving_features.h" #include "bat/ads/internal/logging.h" #include "bat/ads/internal/p2a/p2a_ad_opportunities/p2a_ad_opportunity.h" #include "bat/ads/internal/platform/platform_helper.h" @@ -30,6 +31,7 @@ #include "bat/ads/internal/segments/segments_util.h" #include "bat/ads/internal/settings/settings.h" #include "bat/ads/internal/time_formatting_util.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace ads { namespace ad_notifications { @@ -103,6 +105,30 @@ void AdServing::MaybeServeAd() { return; } + // TODO(https://github.com/brave/brave-browser/issues/17542): Refactor Brave + // ads serving + const int ad_serving_version = features::GetAdServingVersion(); + BLOG(1, "Ad serving version " << ad_serving_version); + + switch (ad_serving_version) { + case 1: { + MaybeServeAdV1(); + break; + } + + case 2: { + MaybeServeAdV2(); + break; + } + + default: { + NOTREACHED() << "Ad serving version is not supported"; + break; + } + } +} + +void AdServing::MaybeServeAdV1() { const ad_targeting::UserModelInfo user_model = ad_targeting::BuildUserModel(); eligible_ads_->Get(user_model, [=](const bool was_allowed, @@ -135,6 +161,34 @@ void AdServing::MaybeServeAd() { }); } +void AdServing::MaybeServeAdV2() { + const ad_targeting::UserModelInfo user_model = ad_targeting::BuildUserModel(); + + eligible_ads_->GetV2( + user_model, [=](const bool was_allowed, + const absl::optional ad) { + if (was_allowed) { + p2a::RecordAdOpportunityForSegments(AdType::kAdNotification, + user_model.interest_segments); + } + + if (!ad) { + BLOG(1, "Ad notification not served: No eligible ads found"); + FailedToServeAd(); + return; + } + + if (!ServeAd(ad.value())) { + BLOG(1, "Failed to serve ad notification"); + FailedToServeAd(); + return; + } + + BLOG(1, "Served ad notification"); + ServedAd(ad.value()); + }); +} + void AdServing::OnAdsPerHourChanged() { const int64_t ads_per_hour = settings::GetAdsPerHour(); BLOG(1, "Maximum ads per hour changed to " << ads_per_hour); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving.h b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving.h index 10d353bdf5cc..2f8268ec1525 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving.h @@ -50,6 +50,8 @@ class AdServing final { void StopServingAdsAtRegularIntervals(); void MaybeServeAd(); + void MaybeServeAdV1(); + void MaybeServeAdV2(); void OnAdsPerHourChanged(); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving_test.cc index 5efdb7e8d807..a6dfd964b1b6 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving_test.cc @@ -5,11 +5,15 @@ #include "bat/ads/internal/ad_serving/ad_notifications/ad_notification_serving.h" +#include #include #include "base/guid.h" +#include "base/test/scoped_feature_list.h" #include "bat/ads/internal/ad_serving/ad_targeting/geographic/subdivision/subdivision_targeting.h" +#include "bat/ads/internal/bundle/creative_ad_notification_unittest_util.h" #include "bat/ads/internal/database/tables/creative_ad_notifications_database_table.h" +#include "bat/ads/internal/features/ad_serving/ad_serving_features.h" #include "bat/ads/internal/resources/frequency_capping/anti_targeting_resource.h" #include "bat/ads/internal/unittest_base.h" #include "bat/ads/internal/unittest_util.h" @@ -63,34 +67,6 @@ class BatAdsAdNotificationServingTest : public UnitTestBase { UserActivity::Get()->RecordEvent(UserActivityEventType::kClosedTab); } - CreativeAdNotificationInfo GetCreativeAdNotification() { - CreativeAdNotificationInfo creative_ad_notification; - - creative_ad_notification.creative_instance_id = base::GenerateGUID(); - creative_ad_notification.creative_set_id = base::GenerateGUID(); - creative_ad_notification.campaign_id = base::GenerateGUID(); - creative_ad_notification.start_at_timestamp = DistantPastAsTimestamp(); - creative_ad_notification.end_at_timestamp = DistantFutureAsTimestamp(); - creative_ad_notification.daily_cap = 1; - creative_ad_notification.advertiser_id = base::GenerateGUID(); - creative_ad_notification.priority = 1; - creative_ad_notification.ptr = 1.0; - creative_ad_notification.per_day = 1; - creative_ad_notification.per_week = 1; - creative_ad_notification.per_month = 1; - creative_ad_notification.total_max = 1; - creative_ad_notification.value = 1.0; - creative_ad_notification.segment = "untargeted"; - creative_ad_notification.geo_targets = {"US"}; - creative_ad_notification.target_url = "https://brave.com"; - CreativeDaypartInfo daypart; - creative_ad_notification.dayparts = {daypart}; - creative_ad_notification.title = "Test Ad Title"; - creative_ad_notification.body = "Test Ad Body"; - - return creative_ad_notification; - } - void ServeAd() { ad_targeting::geographic::SubdivisionTargeting subdivision_targeting; resource::AntiTargeting anti_targeting_resource; @@ -170,4 +146,37 @@ TEST_F(BatAdsAdNotificationServingTest, // Assert } +TEST_F(BatAdsAdNotificationServingTest, ServeAdWithAdServingVersion2) { + // Arrange + RecordUserActivityEvents(); + + CreativeAdNotificationList creative_ad_notifications; + const CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(); + creative_ad_notifications.push_back(creative_ad_notification); + Save(creative_ad_notifications); + + ad_targeting::geographic::SubdivisionTargeting subdivision_targeting; + resource::AntiTargeting anti_targeting_resource; + ad_notifications::AdServing ad_serving(&subdivision_targeting, + &anti_targeting_resource); + + std::map ad_serving_parameters; + ad_serving_parameters["ad_serving_version"] = 2; + + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeaturesAndParameters( + {{features::kAdServing, ad_serving_parameters}}, {}); + + // Act + EXPECT_CALL(*ads_client_mock_, + ShowNotification(DoesMatchCreativeInstanceId( + creative_ad_notification.creative_instance_id))) + .Times(1); + + ServeAd(); + + // Assert +} + } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving.cc index 667ec344c3d0..897e0d33a5e7 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving.cc @@ -16,10 +16,12 @@ #include "bat/ads/internal/ads/inline_content_ads/inline_content_ad_permission_rules.h" #include "bat/ads/internal/bundle/creative_inline_content_ad_info.h" #include "bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.h" +#include "bat/ads/internal/features/ad_serving/ad_serving_features.h" #include "bat/ads/internal/features/inline_content_ads/inline_content_ads_features.h" #include "bat/ads/internal/logging.h" #include "bat/ads/internal/resources/frequency_capping/anti_targeting_resource.h" #include "bat/ads/internal/segments/segments_aliases.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace ads { namespace inline_content_ads { @@ -60,11 +62,38 @@ void AdServing::MaybeServeAd(const std::string& dimensions, return; } + // TODO(https://github.com/brave/brave-browser/issues/17542): Refactor Brave + // Ads serving + const int ad_serving_version = features::GetAdServingVersion(); + BLOG(1, "Ad serving version " << ad_serving_version); + + switch (ad_serving_version) { + case 1: { + MaybeServeAdV1(dimensions, callback); + break; + } + + case 2: { + MaybeServeAdV2(dimensions, callback); + break; + } + + default: { + NOTREACHED() << "Ad serving version is not supported"; + break; + } + } +} + +void AdServing::MaybeServeAdV1(const std::string& dimensions, + GetInlineContentAdCallback callback) { const ad_targeting::UserModelInfo user_model = ad_targeting::BuildUserModel(); eligible_ads_->Get( user_model, dimensions, [=](const bool was_allowed, const CreativeInlineContentAdList& ads) { + InlineContentAdInfo inline_content_ad; + if (ads.empty()) { BLOG(1, "Inline content ad not served: No eligible ads found"); NotifyFailedToServeInlineContentAd(); @@ -79,7 +108,54 @@ void AdServing::MaybeServeAd(const std::string& dimensions, eligible_ads_->SetLastServedAd(ad); - InlineContentAdInfo inline_content_ad = BuildInlineContentAd(ad); + inline_content_ad = BuildInlineContentAd(ad); + + BLOG(1, "Serving inline content ad:\n" + << " uuid: " << inline_content_ad.uuid << "\n" + << " creativeInstanceId: " + << inline_content_ad.creative_instance_id << "\n" + << " creativeSetId: " << inline_content_ad.creative_set_id + << "\n" + << " campaignId: " << inline_content_ad.campaign_id << "\n" + << " advertiserId: " << inline_content_ad.advertiser_id + << "\n" + << " segment: " << inline_content_ad.segment << "\n" + << " title: " << inline_content_ad.title << "\n" + << " description: " << inline_content_ad.description + << "\n" + << " imageUrl: " << inline_content_ad.image_url << "\n" + << " dimensions: " << inline_content_ad.dimensions << "\n" + << " ctaText: " << inline_content_ad.cta_text << "\n" + << " targetUrl: " << inline_content_ad.target_url); + + NotifyDidServeInlineContentAd(inline_content_ad); + + callback(/* success */ true, dimensions, inline_content_ad); + }); +} + +void AdServing::MaybeServeAdV2(const std::string& dimensions, + GetInlineContentAdCallback callback) { + InlineContentAdInfo inline_content_ad; + + const ad_targeting::UserModelInfo user_model = ad_targeting::BuildUserModel(); + + eligible_ads_->GetV2( + user_model, dimensions, + [=](const bool was_allowed, + const absl::optional& ad) { + InlineContentAdInfo inline_content_ad; + + if (!ad) { + BLOG(1, "Inline content ad not served: No eligible ads found"); + NotifyFailedToServeInlineContentAd(); + callback(/* success */ false, dimensions, inline_content_ad); + return; + } + + eligible_ads_->SetLastServedAd(ad.value()); + + inline_content_ad = BuildInlineContentAd(ad.value()); BLOG(1, "Serving inline content ad:\n" << " uuid: " << inline_content_ad.uuid << "\n" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving.h b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving.h index ef8663bc8fab..31805419e1ec 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving.h @@ -43,6 +43,10 @@ class AdServing final { void MaybeServeAd(const std::string& dimensions, GetInlineContentAdCallback callback); + void MaybeServeAdV1(const std::string& dimensions, + GetInlineContentAdCallback callback); + void MaybeServeAdV2(const std::string& dimensions, + GetInlineContentAdCallback callback); private: std::unique_ptr eligible_ads_; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving_test.cc index a9648ef43ac8..c55354ef9066 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_serving/inline_content_ads/inline_content_ad_serving_test.cc @@ -12,6 +12,7 @@ #include "bat/ads/internal/database/tables/creative_inline_content_ads_database_table.h" #include "bat/ads/internal/resources/frequency_capping/anti_targeting_resource.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" #include "net/http/http_status_code.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting.cc index dcdf1c116358..f7004ebe454b 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting.cc @@ -85,5 +85,42 @@ SegmentList GetTopParentSegments(const UserModelInfo& user_model) { return GetTopSegments(user_model, /* parent_only */ true); } +SegmentList GetTopParentChildInterestSegments(const UserModelInfo& user_model) { + return GetTopSegments(user_model.interest_segments, kTopInterestSegmentsCount, + /* parent_only */ false); +} + +SegmentList GetTopParentInterestSegments(const UserModelInfo& user_model) { + return GetTopSegments(user_model.interest_segments, kTopInterestSegmentsCount, + /* parent_only */ true); +} + +SegmentList GetTopParentChildLatentInterestSegments( + const UserModelInfo& user_model) { + return GetTopSegments(user_model.latent_interest_segments, + kTopLatentInterestSegmentsCount, + /* parent_only */ false); +} + +SegmentList GetTopParentLatentInterestSegments( + const UserModelInfo& user_model) { + return GetTopSegments(user_model.latent_interest_segments, + kTopLatentInterestSegmentsCount, + /* parent_only */ true); +} + +SegmentList GetTopParentChildPurchaseIntenSegments( + const UserModelInfo& user_model) { + return GetTopSegments(user_model.purchase_intent_segments, + kTopPurchaseIntentSegmentsCount, + /* parent_only */ false); +} + +SegmentList GetTopParentPurchaseIntenSegments(const UserModelInfo& user_model) { + return GetTopSegments(user_model.purchase_intent_segments, + kTopPurchaseIntentSegmentsCount, + /* parent_only */ true); +} + } // namespace ad_targeting } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting.h b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting.h index 46c6ffbb1dad..3a9d922a8a11 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting.h @@ -17,6 +17,20 @@ SegmentList GetTopParentChildSegments(const UserModelInfo& user_model); SegmentList GetTopParentSegments(const UserModelInfo& user_model); +SegmentList GetTopParentChildInterestSegments(const UserModelInfo& user_model); + +SegmentList GetTopParentInterestSegments(const UserModelInfo& user_model); + +SegmentList GetTopParentChildLatentInterestSegments( + const UserModelInfo& user_model); + +SegmentList GetTopParentLatentInterestSegments(const UserModelInfo& user_model); + +SegmentList GetTopParentChildPurchaseIntenSegments( + const UserModelInfo& user_model); + +SegmentList GetTopParentPurchaseIntenSegments(const UserModelInfo& user_model); + } // namespace ad_targeting } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting_user_model_builder_unittest_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting_user_model_builder_unittest_util.cc index 6b2c4f083b17..d2dbd042d304 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting_user_model_builder_unittest_util.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting_user_model_builder_unittest_util.cc @@ -16,5 +16,13 @@ UserModelInfo BuildUserModel(const SegmentList& segments) { return user_model; } +UserModelInfo BuildUserModel(const SegmentList& interest_segments, + const SegmentList& purchase_intent_segments) { + UserModelInfo user_model; + user_model.interest_segments = interest_segments; + user_model.purchase_intent_segments = purchase_intent_segments; + return user_model; +} + } // namespace ad_targeting } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting_user_model_builder_unittest_util.h b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting_user_model_builder_unittest_util.h index 164afb38192f..8a8d28fd174d 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting_user_model_builder_unittest_util.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/ad_targeting_user_model_builder_unittest_util.h @@ -14,6 +14,8 @@ namespace ad_targeting { struct UserModelInfo; UserModelInfo BuildUserModel(const SegmentList& segments); +UserModelInfo BuildUserModel(const SegmentList& interest_segments, + const SegmentList& purchase_intent_segments); } // namespace ad_targeting } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/processors/behavioral/purchase_intent/purchase_intent_processor_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/processors/behavioral/purchase_intent/purchase_intent_processor_unittest.cc index 7cee56b7ccd5..1e7d69ebfead 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/processors/behavioral/purchase_intent/purchase_intent_processor_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ad_targeting/processors/behavioral/purchase_intent/purchase_intent_processor_unittest.cc @@ -13,6 +13,7 @@ #include "bat/ads/internal/container_util.h" #include "bat/ads/internal/resources/behavioral/purchase_intent/purchase_intent_resource.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.cc b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.cc index c8917c78664b..d651751d1d49 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.cc @@ -4,6 +4,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "bat/ads/internal/bundle/creative_ad_info.h" +#include "bat/ads/internal/container_util.h" namespace ads { @@ -13,4 +14,24 @@ CreativeAdInfo::CreativeAdInfo(const CreativeAdInfo& info) = default; CreativeAdInfo::~CreativeAdInfo() = default; +bool CreativeAdInfo::operator==(const CreativeAdInfo& rhs) const { + return creative_instance_id == rhs.creative_instance_id && + creative_set_id == rhs.creative_set_id && + campaign_id == rhs.campaign_id && + start_at_timestamp == rhs.start_at_timestamp && + end_at_timestamp == rhs.end_at_timestamp && + daily_cap == rhs.daily_cap && advertiser_id == rhs.advertiser_id && + priority == rhs.priority && ptr == rhs.ptr && + conversion == rhs.conversion && per_day == rhs.per_day && + per_week == rhs.per_week && per_month == rhs.per_month && + total_max == rhs.total_max && + split_test_group == rhs.split_test_group && segment == rhs.segment && + CompareAsSets(geo_targets, rhs.geo_targets) && + target_url == rhs.target_url && CompareAsSets(dayparts, rhs.dayparts); +} + +bool CreativeAdInfo::operator!=(const CreativeAdInfo& rhs) const { + return !(*this == rhs); +} + } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.h index 9fd5d38dd793..f883c9e16bc6 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_info.h @@ -19,6 +19,10 @@ struct CreativeAdInfo { CreativeAdInfo(const CreativeAdInfo& info); ~CreativeAdInfo(); + bool operator==(const CreativeAdInfo& rhs) const; + + bool operator!=(const CreativeAdInfo& rhs) const; + std::string creative_instance_id; std::string creative_set_id; std::string campaign_id; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_info.cc b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_info.cc index 98f1aa4c45eb..359e424ca01a 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_info.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_info.cc @@ -10,7 +10,8 @@ namespace ads { CreativeAdNotificationInfo::CreativeAdNotificationInfo() = default; CreativeAdNotificationInfo::CreativeAdNotificationInfo( - const CreativeAdNotificationInfo& info) = default; + const CreativeAdInfo& creative_ad) + : CreativeAdInfo(creative_ad) {} CreativeAdNotificationInfo::~CreativeAdNotificationInfo() = default; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_info.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_info.h index 499fdfbbb05f..530495886d42 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_info.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_info.h @@ -14,7 +14,7 @@ namespace ads { struct CreativeAdNotificationInfo final : CreativeAdInfo { CreativeAdNotificationInfo(); - CreativeAdNotificationInfo(const CreativeAdNotificationInfo& info); + explicit CreativeAdNotificationInfo(const CreativeAdInfo& creative_ad); ~CreativeAdNotificationInfo(); bool operator==(const CreativeAdNotificationInfo& rhs) const; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_unittest_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_unittest_util.cc new file mode 100644 index 000000000000..6e2cc310eaaa --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_unittest_util.cc @@ -0,0 +1,68 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/bundle/creative_ad_notification_unittest_util.h" + +#include "bat/ads/internal/bundle/creative_ad_info.h" +#include "bat/ads/internal/bundle/creative_ad_notification_info.h" +#include "bat/ads/internal/bundle/creative_ad_unittest_util.h" + +namespace ads { + +CreativeAdNotificationInfo GetCreativeAdNotification() { + const CreativeAdInfo creative_ad = GetCreativeAd(); + CreativeAdNotificationInfo creative_ad_notification(creative_ad); + + creative_ad_notification.title = "Test Ad Title"; + creative_ad_notification.body = "Test Ad Body"; + + return creative_ad_notification; +} + +CreativeAdNotificationInfo GetCreativeAdNotification(const std::string& segment, + const double ptr, + const int priority) { + CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(); + creative_ad_notification.priority = priority; + creative_ad_notification.ptr = ptr; + creative_ad_notification.segment = segment; + + return creative_ad_notification; +} + +CreativeAdNotificationInfo GetCreativeAdNotification( + const std::string& creative_instance_id, + const std::string& segment) { + CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(); + + creative_ad_notification.creative_instance_id = creative_instance_id; + creative_ad_notification.segment = segment; + + return creative_ad_notification; +} + +CreativeAdNotificationInfo GetCreativeAdNotificationForAdvertiser( + const std::string& advertiser_id) { + CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(); + + creative_ad_notification.advertiser_id = advertiser_id; + + return creative_ad_notification; +} + +CreativeAdNotificationInfo GetCreativeAdNotificationForSegment( + const std::string& segment) { + CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(); + + creative_ad_notification.segment = segment; + + return creative_ad_notification; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_unittest_util.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_unittest_util.h new file mode 100644 index 000000000000..8938dee55457 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_notification_unittest_util.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_BUNDLE_CREATIVE_AD_NOTIFICATION_UNITTEST_UTIL_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_BUNDLE_CREATIVE_AD_NOTIFICATION_UNITTEST_UTIL_H_ + +#include + +namespace ads { + +struct CreativeAdNotificationInfo; + +CreativeAdNotificationInfo GetCreativeAdNotification(); + +CreativeAdNotificationInfo GetCreativeAdNotification(const std::string& segment, + const double ptr, + const int priority); + +CreativeAdNotificationInfo GetCreativeAdNotification( + const std::string& creative_instance_id, + const std::string& segment); + +CreativeAdNotificationInfo GetCreativeAdNotificationForAdvertiser( + const std::string& advertiser_id); + +CreativeAdNotificationInfo GetCreativeAdNotificationForSegment( + const std::string& segment); + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_BUNDLE_CREATIVE_AD_NOTIFICATION_UNITTEST_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_unittest_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_unittest_util.cc new file mode 100644 index 000000000000..91ba25356f7c --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_unittest_util.cc @@ -0,0 +1,38 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/bundle/creative_ad_unittest_util.h" + +#include "base/guid.h" +#include "bat/ads/internal/unittest_time_util.h" + +namespace ads { + +CreativeAdInfo GetCreativeAd() { + CreativeAdInfo creative_ad; + + creative_ad.creative_instance_id = base::GenerateGUID(); + creative_ad.creative_set_id = base::GenerateGUID(); + creative_ad.campaign_id = base::GenerateGUID(); + creative_ad.start_at_timestamp = DistantPastAsTimestamp(); + creative_ad.end_at_timestamp = DistantFutureAsTimestamp(); + creative_ad.daily_cap = 1; + creative_ad.advertiser_id = base::GenerateGUID(); + creative_ad.priority = 1; + creative_ad.ptr = 1.0; + creative_ad.per_day = 1; + creative_ad.per_week = 1; + creative_ad.per_month = 1; + creative_ad.total_max = 1; + creative_ad.segment = "untargeted"; + creative_ad.geo_targets = {"US"}; + creative_ad.target_url = "https://brave.com"; + CreativeDaypartInfo daypart; + creative_ad.dayparts = {daypart}; + + return creative_ad; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_unittest_util.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_unittest_util.h new file mode 100644 index 000000000000..32416144463d --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_ad_unittest_util.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_BUNDLE_CREATIVE_AD_UNITTEST_UTIL_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_BUNDLE_CREATIVE_AD_UNITTEST_UTIL_H_ + +#include + +#include "bat/ads/internal/bundle/creative_ad_info.h" + +namespace ads { + +CreativeAdInfo GetCreativeAd(); + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_BUNDLE_CREATIVE_AD_UNITTEST_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.cc b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.cc new file mode 100644 index 000000000000..8d0bb40bf099 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.cc @@ -0,0 +1,23 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/bundle/creative_daypart_info.h" + +namespace ads { + +CreativeDaypartInfo::CreativeDaypartInfo() = default; + +CreativeDaypartInfo::~CreativeDaypartInfo() = default; + +bool CreativeDaypartInfo::operator==(const CreativeDaypartInfo& rhs) const { + return dow == rhs.dow && start_minute == rhs.start_minute && + end_minute == rhs.end_minute; +} + +bool CreativeDaypartInfo::operator!=(const CreativeDaypartInfo& rhs) const { + return !(*this == rhs); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.h b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.h index 52f11885830d..ed31f53e5722 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/bundle/creative_daypart_info.h @@ -13,6 +13,13 @@ namespace ads { struct CreativeDaypartInfo final { + CreativeDaypartInfo(); + ~CreativeDaypartInfo(); + + bool operator==(const CreativeDaypartInfo& rhs) const; + + bool operator!=(const CreativeDaypartInfo& rhs) const; + std::string dow = "0123456"; int start_minute = 0; int end_minute = (base::Time::kMinutesPerHour * base::Time::kHoursPerDay) - 1; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_unittest.cc index a81d506d497d..6fe8696f1830 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_unittest.cc @@ -8,6 +8,8 @@ #include #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_file_util.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_util_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_util_unittest.cc index 3cee65aa3926..e5359d6f4a71 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_util_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/catalog/catalog_util_unittest.cc @@ -8,6 +8,7 @@ #include "bat/ads/ads_client.h" #include "bat/ads/internal/ads_client_helper.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" #include "bat/ads/pref_names.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/container_util.h b/vendor/bat-native-ads/src/bat/ads/internal/container_util.h index a420847160b2..df5d3c72c0f2 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/container_util.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/container_util.h @@ -6,6 +6,7 @@ #ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_CONTAINER_UTIL_H_ #define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_CONTAINER_UTIL_H_ +#include #include #include @@ -77,6 +78,18 @@ bool CompareAsSets(const T& c1, const T& c2) { return true; } +template +std::vector SetIntersection(std::vector lhs, std::vector rhs) { + std::sort(lhs.begin(), lhs.end()); + std::sort(rhs.begin(), rhs.end()); + + std::vector intersection; + std::set_intersection(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), + std::back_inserter(intersection)); + + return intersection; +} + } // namespace ads #endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_CONTAINER_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/container_util_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/container_util_unittest.cc index 62a90b2e7c02..909d848b89de 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/container_util_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/container_util_unittest.cc @@ -217,4 +217,44 @@ TEST(BatAdsContainerUtilTest, CompareEmptySets) { EXPECT_TRUE(does_equal); } +TEST(BatAdsContainerUtilTest, DoesNotMatchEmptySegments) { + // Arrange + const std::vector lhs; + const std::vector rhs; + + // Act + const std::vector set_intersection = SetIntersection(lhs, rhs); + + // Assert + const std::vector expected_set_intersection; + EXPECT_EQ(expected_set_intersection, set_intersection); +} + +TEST(BatAdsContainerUtilTest, DoesNotMatchSegments) { + // Arrange + const std::vector lhs = {"element 1", "element 2"}; + const std::vector rhs = {"element 3"}; + + // Act + const std::vector set_intersection = SetIntersection(lhs, rhs); + + // Assert + const std::vector expected_set_intersection; + EXPECT_EQ(expected_set_intersection, set_intersection); +} + +TEST(BatAdsContainerUtilTest, SetIntersectionForUnsortedList) { + // Arrange + const std::vector lhs = {"element 1", "element 3", "element 2"}; + const std::vector rhs = {"element 2", "element 1"}; + + // Act + const std::vector set_intersection = SetIntersection(lhs, rhs); + + // Assert + const std::vector expected_set_intersection = {"element 1", + "element 2"}; + EXPECT_EQ(expected_set_intersection, set_intersection); +} + } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/conversions/conversions_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/conversions/conversions_unittest.cc index 2eaa039035f5..42d5607842da 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/conversions/conversions_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/conversions/conversions_unittest.cc @@ -15,6 +15,7 @@ #include "bat/ads/internal/database/tables/conversions_database_table.h" #include "bat/ads/internal/resources/conversions/conversions_resource.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" #include "bat/ads/pref_names.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration_issue_17231_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration_issue_17231_unittest.cc index 3fbd2dfe18bb..03d411cdf9db 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration_issue_17231_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration_issue_17231_unittest.cc @@ -11,6 +11,7 @@ #include "bat/ads/internal/database/tables/conversion_queue_database_table.h" #include "bat/ads/internal/database/tables/conversions_database_table.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration_unittest.cc index bddb42a73446..5f05085a1d38 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/database_migration_unittest.cc @@ -8,6 +8,7 @@ #include "bat/ads/internal/ad_events/ad_events.h" #include "bat/ads/internal/database/database_version.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/conversion_queue_database_table_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/conversion_queue_database_table_unittest.cc index 419b6fb61c5b..63485a153ec8 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/conversion_queue_database_table_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/conversion_queue_database_table_unittest.cc @@ -8,6 +8,7 @@ #include #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_unittest.cc index d1ef46ad8f6f..0318da81fdad 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_ad_notifications_database_table_unittest.cc @@ -5,8 +5,11 @@ #include "bat/ads/internal/database/tables/creative_ad_notifications_database_table.h" +#include + #include "bat/ads/internal/container_util.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table.cc index b5bacc605cf3..3ed46bf4e8e6 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table.cc @@ -189,7 +189,7 @@ void CreativeInlineContentAds::GetForCreativeInstanceId( std::placeholders::_1, creative_instance_id, callback)); } -void CreativeInlineContentAds::GetForSegments( +void CreativeInlineContentAds::GetForSegmentsAndDimensions( const SegmentList& segments, const std::string& dimensions, GetCreativeInlineContentAdsCallback callback) { @@ -290,10 +290,106 @@ void CreativeInlineContentAds::GetForSegments( AdsClientHelper::Get()->RunDBTransaction( std::move(transaction), - std::bind(&CreativeInlineContentAds::OnGetForSegments, this, + std::bind(&CreativeInlineContentAds::OnGetForSegmentsAndDimensions, this, std::placeholders::_1, segments, callback)); } +void CreativeInlineContentAds::GetForDimensions( + const std::string& dimensions, + GetCreativeInlineContentAdsForDimensionsCallback callback) { + if (dimensions.empty()) { + callback(/* success */ true, {}); + return; + } + + const std::string query = base::StringPrintf( + "SELECT " + "cbna.creative_instance_id, " + "cbna.creative_set_id, " + "cbna.campaign_id, " + "cam.start_at_timestamp, " + "cam.end_at_timestamp, " + "cam.daily_cap, " + "cam.advertiser_id, " + "cam.priority, " + "ca.conversion, " + "ca.per_day, " + "ca.per_week, " + "ca.per_month, " + "ca.total_max, " + "ca.value, " + "ca.split_test_group, " + "s.segment, " + "gt.geo_target, " + "ca.target_url, " + "cbna.title, " + "cbna.description, " + "cbna.image_url, " + "cbna.dimensions, " + "cbna.cta_text, " + "cam.ptr, " + "dp.dow, " + "dp.start_minute, " + "dp.end_minute " + "FROM %s AS cbna " + "INNER JOIN campaigns AS cam " + "ON cam.campaign_id = cbna.campaign_id " + "INNER JOIN segments AS s " + "ON s.creative_set_id = cbna.creative_set_id " + "INNER JOIN creative_ads AS ca " + "ON ca.creative_instance_id = cbna.creative_instance_id " + "INNER JOIN geo_targets AS gt " + "ON gt.campaign_id = cbna.campaign_id " + "INNER JOIN dayparts AS dp " + "ON dp.campaign_id = cbna.campaign_id " + "AND cbna.dimensions = '%s' " + "AND %s BETWEEN cam.start_at_timestamp AND cam.end_at_timestamp", + GetTableName().c_str(), dimensions.c_str(), + TimeAsTimestampString(base::Time::Now()).c_str()); + + mojom::DBCommandPtr command = mojom::DBCommand::New(); + command->type = mojom::DBCommand::Type::READ; + command->command = query; + + command->record_bindings = { + mojom::DBCommand::RecordBindingType::STRING_TYPE, // creative_instance_id + mojom::DBCommand::RecordBindingType::STRING_TYPE, // creative_set_id + mojom::DBCommand::RecordBindingType::STRING_TYPE, // campaign_id + mojom::DBCommand::RecordBindingType::INT64_TYPE, // start_at_timestamp + mojom::DBCommand::RecordBindingType::INT64_TYPE, // end_at_timestamp + mojom::DBCommand::RecordBindingType::INT_TYPE, // daily_cap + mojom::DBCommand::RecordBindingType::STRING_TYPE, // advertiser_id + mojom::DBCommand::RecordBindingType::INT_TYPE, // priority + mojom::DBCommand::RecordBindingType::BOOL_TYPE, // conversion + mojom::DBCommand::RecordBindingType::INT_TYPE, // per_day + mojom::DBCommand::RecordBindingType::INT_TYPE, // per_week + mojom::DBCommand::RecordBindingType::INT_TYPE, // per_month + mojom::DBCommand::RecordBindingType::INT_TYPE, // total_max + mojom::DBCommand::RecordBindingType::DOUBLE_TYPE, // value + mojom::DBCommand::RecordBindingType::STRING_TYPE, // split_test_group + mojom::DBCommand::RecordBindingType::STRING_TYPE, // segment + mojom::DBCommand::RecordBindingType::STRING_TYPE, // geo_target + mojom::DBCommand::RecordBindingType::STRING_TYPE, // target_url + mojom::DBCommand::RecordBindingType::STRING_TYPE, // title + mojom::DBCommand::RecordBindingType::STRING_TYPE, // description + mojom::DBCommand::RecordBindingType::STRING_TYPE, // image_url + mojom::DBCommand::RecordBindingType::STRING_TYPE, // dimensions + mojom::DBCommand::RecordBindingType::STRING_TYPE, // cta_text + mojom::DBCommand::RecordBindingType::DOUBLE_TYPE, // ptr + mojom::DBCommand::RecordBindingType::STRING_TYPE, // dayparts->dow + mojom::DBCommand::RecordBindingType::INT_TYPE, // dayparts->start_minute + mojom::DBCommand::RecordBindingType::INT_TYPE // dayparts->end_minute + }; + + mojom::DBTransactionPtr transaction = mojom::DBTransaction::New(); + transaction->commands.push_back(std::move(command)); + + AdsClientHelper::Get()->RunDBTransaction( + std::move(transaction), + std::bind(&CreativeInlineContentAds::OnGetForDimensions, this, + std::placeholders::_1, callback)); +} + void CreativeInlineContentAds::GetAll( GetCreativeInlineContentAdsCallback callback) { const std::string query = base::StringPrintf( @@ -490,7 +586,7 @@ void CreativeInlineContentAds::OnGetForCreativeInstanceId( creative_inline_content_ad); } -void CreativeInlineContentAds::OnGetForSegments( +void CreativeInlineContentAds::OnGetForSegmentsAndDimensions( mojom::DBCommandResponsePtr response, const SegmentList& segments, GetCreativeInlineContentAdsCallback callback) { @@ -513,6 +609,28 @@ void CreativeInlineContentAds::OnGetForSegments( callback(/* success */ true, segments, creative_inline_content_ads); } +void CreativeInlineContentAds::OnGetForDimensions( + mojom::DBCommandResponsePtr response, + GetCreativeInlineContentAdsForDimensionsCallback callback) { + if (!response || + response->status != mojom::DBCommandResponse::Status::RESPONSE_OK) { + BLOG(0, "Failed to get creative inline content ads"); + callback(/* success */ false, {}); + return; + } + + CreativeInlineContentAdList creative_inline_content_ads; + + for (const auto& record : response->result->get_records()) { + const CreativeInlineContentAdInfo creative_inline_content_ad = + GetFromRecord(record.get()); + + creative_inline_content_ads.push_back(creative_inline_content_ad); + } + + callback(/* success */ true, creative_inline_content_ads); +} + void CreativeInlineContentAds::OnGetAll( mojom::DBCommandResponsePtr response, GetCreativeInlineContentAdsCallback callback) { diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table.h b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table.h index fea25c0894e0..21df0810994b 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table.h @@ -21,6 +21,10 @@ namespace ads { struct CreativeInlineContentAdInfo; +using GetCreativeInlineContentAdsForDimensionsCallback = + std::function; + namespace database { namespace table { @@ -43,9 +47,14 @@ class CreativeInlineContentAds final : public Table { void GetForCreativeInstanceId(const std::string& creative_instance_id, GetCreativeInlineContentAdCallback callback); - void GetForSegments(const SegmentList& segments, - const std::string& dimensions, - GetCreativeInlineContentAdsCallback callback); + void GetForSegmentsAndDimensions( + const SegmentList& segments, + const std::string& dimensions, + GetCreativeInlineContentAdsCallback callback); + + void GetForDimensions( + const std::string& dimensions, + GetCreativeInlineContentAdsForDimensionsCallback callback); void GetAll(GetCreativeInlineContentAdsCallback callback); @@ -77,9 +86,14 @@ class CreativeInlineContentAds final : public Table { const std::string& creative_instance_id, GetCreativeInlineContentAdCallback callback); - void OnGetForSegments(mojom::DBCommandResponsePtr response, - const SegmentList& segments, - GetCreativeInlineContentAdsCallback callback); + void OnGetForSegmentsAndDimensions( + mojom::DBCommandResponsePtr response, + const SegmentList& segments, + GetCreativeInlineContentAdsCallback callback); + + void OnGetForDimensions( + mojom::DBCommandResponsePtr response, + GetCreativeInlineContentAdsForDimensionsCallback callback); void OnGetAll(mojom::DBCommandResponsePtr response, GetCreativeInlineContentAdsCallback callback); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table_test.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table_test.cc index 06cedca2c781..b65bc466967b 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table_test.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table_test.cc @@ -5,6 +5,8 @@ #include "bat/ads/internal/database/tables/creative_inline_content_ads_database_table.h" +#include + #include "bat/ads/internal/unittest_base.h" #include "bat/ads/internal/unittest_util.h" #include "net/http/http_status_code.h" @@ -27,7 +29,7 @@ class BatAdsCreativeInlineContentAdsDatabaseTableIntegrationTest }; TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableIntegrationTest, - GetCreativeInlineContentAdsFromCatalogEndpoint) { + GetCreativeInlineContentAdsForSegmentsAndDimensionsFromCatalogEndpoint) { // Arrange const URLEndpoints endpoints = { {"/v8/catalog", {{net::HTTP_OK, "/catalog.json"}}}}; @@ -42,7 +44,7 @@ TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableIntegrationTest, const std::vector segments = {"technology & computing"}; database::table::CreativeInlineContentAds creative_inline_content_ads; - creative_inline_content_ads.GetForSegments( + creative_inline_content_ads.GetForSegmentsAndDimensions( segments, "200x100", [](const bool success, const SegmentList& segments, const CreativeInlineContentAdList& creative_inline_content_ads) { @@ -51,4 +53,27 @@ TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableIntegrationTest, }); } +TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableIntegrationTest, + GetCreativeInlineContentAdsForDimensionsFromCatalogEndpoint) { + // Arrange + const URLEndpoints endpoints = { + {"/v8/catalog", {{net::HTTP_OK, "/catalog.json"}}}}; + + MockUrlRequest(ads_client_mock_, endpoints); + + InitializeAds(); + + // Act + + // Assert + database::table::CreativeInlineContentAds creative_inline_content_ads; + creative_inline_content_ads.GetForDimensions( + "200x100", + [](const bool success, + const CreativeInlineContentAdList& creative_inline_content_ads) { + EXPECT_TRUE(success); + EXPECT_EQ(1UL, creative_inline_content_ads.size()); + }); +} + } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table_unittest.cc index 44fb0d7ee4a6..2ce75b560459 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_inline_content_ads_database_table_unittest.cc @@ -7,6 +7,7 @@ #include "bat/ads/internal/container_util.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* @@ -257,7 +258,8 @@ TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableTest, }); } -TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableTest, GetForSegments) { +TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableTest, + GetForSegmentsAndDimensions) { // Arrange CreativeInlineContentAdList creative_inline_content_ads; @@ -465,7 +467,7 @@ TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableTest, const SegmentList segments = {}; - database_table_->GetForSegments( + database_table_->GetForSegmentsAndDimensions( segments, "200x100", [&expected_creative_inline_content_ads]( const bool success, const SegmentList& segments, @@ -515,7 +517,7 @@ TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableTest, const SegmentList segments = {"technology & computing"}; - database_table_->GetForSegments( + database_table_->GetForSegmentsAndDimensions( segments, "200x100", [&expected_creative_inline_content_ads]( const bool success, const SegmentList& segments, @@ -616,7 +618,7 @@ TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableTest, const SegmentList segments = {"technology & computing-software", "food & drink"}; - database_table_->GetForSegments( + database_table_->GetForSegmentsAndDimensions( segments, "200x100", [&expected_creative_inline_content_ads]( const bool success, const SegmentList& segments, @@ -692,7 +694,7 @@ TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableTest, const SegmentList segments = {"food & drink"}; - database_table_->GetForSegments( + database_table_->GetForSegmentsAndDimensions( segments, "200x100", [&expected_creative_inline_content_ads]( const bool success, const SegmentList& segments, @@ -767,7 +769,7 @@ TEST_F(BatAdsCreativeInlineContentAdsDatabaseTableTest, const SegmentList segments = {"FoOd & DrInK"}; - database_table_->GetForSegments( + database_table_->GetForSegmentsAndDimensions( segments, "200x100", [&expected_creative_inline_content_ads]( const bool success, const SegmentList& segments, diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_unittest.cc index 1986778feafc..f2a3d92d46f7 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_new_tab_page_ads_database_table_unittest.cc @@ -7,6 +7,7 @@ #include "bat/ads/internal/container_util.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_unittest.cc index 9e3adffe6463..6d5c1bf94563 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/database/tables/creative_promoted_content_ads_database_table_unittest.cc @@ -7,6 +7,7 @@ #include "bat/ads/internal/container_util.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.cc index a00659d98141..9e1c9566fc7f 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.cc @@ -18,6 +18,9 @@ #include "bat/ads/internal/database/tables/ad_events_database_table.h" #include "bat/ads/internal/database/tables/creative_ad_notifications_database_table.h" #include "bat/ads/internal/eligible_ads/eligible_ads_constants.h" +#include "bat/ads/internal/eligible_ads/eligible_ads_predictor_util.h" +#include "bat/ads/internal/eligible_ads/eligible_ads_util.h" +#include "bat/ads/internal/eligible_ads/sample_ads.h" #include "bat/ads/internal/eligible_ads/seen_ads.h" #include "bat/ads/internal/eligible_ads/seen_advertisers.h" #include "bat/ads/internal/features/ad_serving/ad_serving_features.h" @@ -52,7 +55,7 @@ void EligibleAds::SetLastServedAd(const CreativeAdInfo& creative_ad) { } void EligibleAds::Get(const ad_targeting::UserModelInfo& user_model, - GetEligibleAdsCallback callback) { + GetCallback callback) { database::table::AdEvents database_table; database_table.GetAll([=](const bool success, const AdEventList& ad_events) { if (!success) { @@ -71,13 +74,87 @@ void EligibleAds::Get(const ad_targeting::UserModelInfo& user_model, }); } +void EligibleAds::GetV2(const ad_targeting::UserModelInfo& user_model, + GetV2Callback callback) { + database::table::AdEvents database_table; + database_table.GetAll([=](const bool success, const AdEventList& ad_events) { + if (!success) { + BLOG(1, "Failed to get ad events"); + callback(/* was_allowed */ false, absl::nullopt); + return; + } + + const int max_count = features::GetBrowsingHistoryMaxCount(); + const int days_ago = features::GetBrowsingHistoryDaysAgo(); + AdsClientHelper::Get()->GetBrowsingHistory( + max_count, days_ago, [=](const BrowsingHistoryList& history) { + GetEligibleAds(user_model, ad_events, history, callback); + }); + }); +} + /////////////////////////////////////////////////////////////////////////////// +void EligibleAds::GetEligibleAds(const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events, + const BrowsingHistoryList& browsing_history, + GetV2Callback callback) const { + BLOG(1, "Get eligible ads"); + + database::table::CreativeAdNotifications database_table; + database_table.GetAll([=](const bool success, const SegmentList& segments, + const CreativeAdNotificationList& ads) { + if (!success) { + BLOG(1, "Failed to get ads"); + callback(/* was_allowed */ false, absl::nullopt); + return; + } + + if (ads.empty()) { + BLOG(1, "No ads"); + callback(/* was_allowed */ true, absl::nullopt); + return; + } + + CreativeAdNotificationList eligible_ads = ApplyFrequencyCapping( + ads, + ShouldCapLastServedAd(ads) ? last_served_creative_ad_ + : CreativeAdInfo(), + ad_events, browsing_history); + + if (eligible_ads.empty()) { + BLOG(1, "No eligible ads"); + callback(/* was_allowed */ true, absl::nullopt); + return; + } + + ChooseAd(user_model, ad_events, eligible_ads, callback); + }); +} + +void EligibleAds::ChooseAd(const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events, + const CreativeAdNotificationList& eligible_ads, + GetV2Callback callback) const { + DCHECK(!eligible_ads.empty()); + + const CreativeAdNotificationPredictorMap ads = + GroupEligibleAdsByCreativeInstanceId(eligible_ads); + + const CreativeAdNotificationPredictorMap ads_with_features_and_scores = + ComputePredictorFeaturesAndScores(ads, user_model, ad_events); + + const absl::optional ad = + SampleFromAds(ads_with_features_and_scores); + + callback(/* was_allowed */ true, ad); +} + void EligibleAds::GetForParentChildSegments( const ad_targeting::UserModelInfo& user_model, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const { + GetCallback callback) const { const SegmentList segments = ad_targeting::GetTopParentChildSegments(user_model); if (segments.empty()) { @@ -112,7 +189,7 @@ void EligibleAds::GetForParentSegments( const ad_targeting::UserModelInfo& user_model, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const { + GetCallback callback) const { const SegmentList segments = ad_targeting::GetTopParentSegments(user_model); if (segments.empty()) { GetForUntargeted(ad_events, browsing_history, callback); @@ -143,7 +220,7 @@ void EligibleAds::GetForParentSegments( void EligibleAds::GetForUntargeted(const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const { + GetCallback callback) const { BLOG(1, "Get eligible ads for untargeted segment"); database::table::CreativeAdNotifications database_table; diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.h b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.h index e216a0c6f23a..4df660842544 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications.h @@ -10,6 +10,7 @@ #include "bat/ads/internal/bundle/creative_ad_notification_info_aliases.h" #include "bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_aliases.h" #include "bat/ads/internal/frequency_capping/frequency_capping_aliases.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace ads { @@ -26,6 +27,13 @@ class AntiTargeting; namespace ad_notifications { +using GetCallback = + std::function; + +using GetV2Callback = + std::function)>; + class EligibleAds final { public: EligibleAds( @@ -35,8 +43,10 @@ class EligibleAds final { void SetLastServedAd(const CreativeAdInfo& creative_ad); - void Get(const ad_targeting::UserModelInfo& user_model, - GetEligibleAdsCallback callback); + void Get(const ad_targeting::UserModelInfo& user_model, GetCallback callback); + + void GetV2(const ad_targeting::UserModelInfo& user_model, + GetV2Callback callback); private: ad_targeting::geographic::SubdivisionTargeting* @@ -46,19 +56,29 @@ class EligibleAds final { CreativeAdInfo last_served_creative_ad_; + void GetEligibleAds(const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events, + const BrowsingHistoryList& browsing_history, + GetV2Callback callback) const; + + void ChooseAd(const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events, + const CreativeAdNotificationList& eligible_ads, + GetV2Callback callback) const; + void GetForParentChildSegments(const ad_targeting::UserModelInfo& user_model, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const; + GetCallback callback) const; void GetForParentSegments(const ad_targeting::UserModelInfo& user_model, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const; + GetCallback callback) const; void GetForUntargeted(const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const; + GetCallback callback) const; CreativeAdNotificationList FilterIneligibleAds( const CreativeAdNotificationList& ads, diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_issue_17199_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_issue_17199_unittest.cc index 9916d16d4373..871cd42e26c3 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_issue_17199_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_issue_17199_unittest.cc @@ -10,6 +10,7 @@ #include "bat/ads/internal/ad_targeting/ad_targeting_user_model_info.h" #include "bat/ads/internal/resources/frequency_capping/anti_targeting_resource.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_unittest.cc index d29524ef97c9..e51aa070e926 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_notifications/eligible_ad_notifications_unittest.cc @@ -9,13 +9,17 @@ #include #include "base/guid.h" +#include "bat/ads/internal/ad_events/ad_events.h" #include "bat/ads/internal/ad_serving/ad_targeting/geographic/subdivision/subdivision_targeting.h" #include "bat/ads/internal/ad_targeting/ad_targeting_user_model_builder_unittest_util.h" #include "bat/ads/internal/ad_targeting/ad_targeting_user_model_info.h" +#include "bat/ads/internal/bundle/creative_ad_notification_unittest_util.h" #include "bat/ads/internal/database/tables/creative_ad_notifications_database_table.h" #include "bat/ads/internal/resources/frequency_capping/anti_targeting_resource.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" +#include "third_party/abseil-cpp/absl/types/optional.h" // npm run test -- brave_unit_tests --filter=BatAds* @@ -24,7 +28,7 @@ namespace ads { class BatAdsEligibleAdNotificationsTest : public UnitTestBase { protected: BatAdsEligibleAdNotificationsTest() - : database_table_( + : creative_ad_notifications_table_( std::make_unique()) {} ~BatAdsEligibleAdNotificationsTest() override = default; @@ -34,41 +38,14 @@ class BatAdsEligibleAdNotificationsTest : public UnitTestBase { UserActivity::Get()->RecordEvent(UserActivityEventType::kClosedTab); } - CreativeAdNotificationInfo GetCreativeAdNotificationForSegment( - const std::string& segment) { - CreativeAdNotificationInfo creative_ad_notification; - - creative_ad_notification.creative_instance_id = base::GenerateGUID(); - creative_ad_notification.creative_set_id = base::GenerateGUID(); - creative_ad_notification.campaign_id = base::GenerateGUID(); - creative_ad_notification.start_at_timestamp = DistantPastAsTimestamp(); - creative_ad_notification.end_at_timestamp = DistantFutureAsTimestamp(); - creative_ad_notification.daily_cap = 1; - creative_ad_notification.advertiser_id = base::GenerateGUID(); - creative_ad_notification.priority = 1; - creative_ad_notification.ptr = 1.0; - creative_ad_notification.per_day = 1; - creative_ad_notification.per_week = 1; - creative_ad_notification.per_month = 1; - creative_ad_notification.total_max = 1; - creative_ad_notification.value = 1.0; - creative_ad_notification.segment = segment; - creative_ad_notification.geo_targets = {"US"}; - creative_ad_notification.target_url = "https://brave.com"; - CreativeDaypartInfo daypart; - creative_ad_notification.dayparts = {daypart}; - creative_ad_notification.title = "Test Ad Title"; - creative_ad_notification.body = "Test Ad Body"; - - return creative_ad_notification; - } - void Save(const CreativeAdNotificationList& creative_ad_notifications) { - database_table_->Save(creative_ad_notifications, - [](const bool success) { ASSERT_TRUE(success); }); + creative_ad_notifications_table_->Save( + creative_ad_notifications, + [](const bool success) { ASSERT_TRUE(success); }); } - std::unique_ptr database_table_; + std::unique_ptr + creative_ad_notifications_table_; }; TEST_F(BatAdsEligibleAdNotificationsTest, GetAdsForParentChildSegment) { @@ -267,4 +244,98 @@ TEST_F(BatAdsEligibleAdNotificationsTest, GetAdsForUnmatchedSegments) { // Assert } +TEST_F(BatAdsEligibleAdNotificationsTest, GetV2WithoutAds) { + // Arrange + const SegmentList interest_segments = {"interest-foo", "interest-bar"}; + const SegmentList purchase_intent_segments = {"intent-foo", "intent-bar"}; + const ad_targeting::UserModelInfo user_model = + ad_targeting::BuildUserModel(interest_segments, purchase_intent_segments); + + // Act + ad_targeting::geographic::SubdivisionTargeting subdivision_targeting; + resource::AntiTargeting anti_targeting_resource; + ad_notifications::EligibleAds eligible_ads(&subdivision_targeting, + &anti_targeting_resource); + + eligible_ads.GetV2(user_model, + [=](const bool was_allowed, + const absl::optional ad) { + EXPECT_EQ(absl::nullopt, ad); + }); + + // Assert +} + +TEST_F(BatAdsEligibleAdNotificationsTest, GetV2WithEmptySegments) { + // Arrange + CreativeAdNotificationList creative_ad_notifications; + + const CreativeAdNotificationInfo creative_ad_notification_1 = + GetCreativeAdNotificationForSegment("foo"); + creative_ad_notifications.push_back(creative_ad_notification_1); + + const CreativeAdNotificationInfo creative_ad_notification_2 = + GetCreativeAdNotificationForSegment("foo-bar"); + creative_ad_notifications.push_back(creative_ad_notification_2); + + Save(creative_ad_notifications); + + const SegmentList interest_segments = {}; + const SegmentList purchase_intent_segments = {}; + const ad_targeting::UserModelInfo user_model = + ad_targeting::BuildUserModel(interest_segments, purchase_intent_segments); + + // Act + ad_targeting::geographic::SubdivisionTargeting subdivision_targeting; + resource::AntiTargeting anti_targeting_resource; + ad_notifications::EligibleAds eligible_ads(&subdivision_targeting, + &anti_targeting_resource); + + const CreativeAdNotificationInfo expected_ad = creative_ad_notification_2; + + eligible_ads.GetV2(user_model, + [=](const bool was_allowed, + const absl::optional ad) { + EXPECT_TRUE(ad); + }); + + // Assert +} + +TEST_F(BatAdsEligibleAdNotificationsTest, GetV2) { + // Arrange + CreativeAdNotificationList creative_ad_notifications; + + const CreativeAdNotificationInfo creative_ad_notification_1 = + GetCreativeAdNotificationForSegment("foo-bar1"); + creative_ad_notifications.push_back(creative_ad_notification_1); + + const CreativeAdNotificationInfo creative_ad_notification_2 = + GetCreativeAdNotificationForSegment("foo-bar3"); + creative_ad_notifications.push_back(creative_ad_notification_2); + + Save(creative_ad_notifications); + + const SegmentList interest_segments = {"foo-bar3"}; + const SegmentList purchase_intent_segments = {"foo-bar1", "foo-bar2"}; + const ad_targeting::UserModelInfo user_model = + ad_targeting::BuildUserModel(interest_segments, purchase_intent_segments); + + // Act + ad_targeting::geographic::SubdivisionTargeting subdivision_targeting; + resource::AntiTargeting anti_targeting_resource; + ad_notifications::EligibleAds eligible_ads(&subdivision_targeting, + &anti_targeting_resource); + + const CreativeAdNotificationInfo expected_ad = creative_ad_notification_2; + + eligible_ads.GetV2(user_model, + [=](const bool was_allowed, + const absl::optional ad) { + EXPECT_TRUE(ad); + }); + + // Assert +} + } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_predictor_info.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_predictor_info.cc new file mode 100644 index 000000000000..0711b1409acc --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_predictor_info.cc @@ -0,0 +1,25 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/eligible_ads/ad_predictor_info.h" + +#include "bat/ads/internal/bundle/creative_ad_notification_info.h" +#include "bat/ads/internal/bundle/creative_inline_content_ad_info.h" + +namespace ads { + +template +AdPredictorInfo::AdPredictorInfo() = default; + +template +AdPredictorInfo::AdPredictorInfo(const AdPredictorInfo& info) = default; + +template +AdPredictorInfo::~AdPredictorInfo() = default; + +template struct AdPredictorInfo; +template struct AdPredictorInfo; + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_predictor_info.h b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_predictor_info.h new file mode 100644 index 000000000000..635636fa5fcf --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/ad_predictor_info.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_AD_PREDICTOR_INFO_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_AD_PREDICTOR_INFO_H_ + +#include "bat/ads/internal/segments/segments_aliases.h" + +namespace ads { + +template +struct AdPredictorInfo { + AdPredictorInfo(); + AdPredictorInfo(const AdPredictorInfo& info); + ~AdPredictorInfo(); + + T creative_ad; + SegmentList segments; + bool does_match_intent_child_segments; + bool does_match_intent_parent_segments; + bool does_match_interest_child_segments; + bool does_match_interest_parent_segments; + int ad_last_seen_hours_ago = 0; + int advertiser_last_seen_hours_ago = 0; + double score = 0.0; +}; + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_AD_PREDICTOR_INFO_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_aliases.h b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_aliases.h new file mode 100644 index 000000000000..d9c104130292 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_aliases.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_ALIASES_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_ALIASES_H_ + +#include +#include + +namespace ads { + +using AdPredictorWeights = std::vector; + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_ALIASES_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features.cc new file mode 100644 index 000000000000..6729054b914a --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features.cc @@ -0,0 +1,44 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/eligible_ads/eligible_ads_features.h" + +#include + +#include "base/metrics/field_trial_params.h" +#include "bat/ads/internal/eligible_ads/eligible_ads_features_util.h" + +namespace ads { +namespace features { + +namespace { + +const char kFeatureName[] = "EligibleAds"; +const char kFieldTrialParameterAdPredictorWeights[] = "ad_predictor_weights"; +const AdPredictorWeights kDefaultWeights = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + +} // namespace + +const base::Feature kEligibleAds{kFeatureName, + base::FEATURE_ENABLED_BY_DEFAULT}; + +bool IsEligibleAdsEnabled() { + return base::FeatureList::IsEnabled(kEligibleAds); +} + +AdPredictorWeights GetAdPredictorWeights() { + const std::string param_value = GetFieldTrialParamValueByFeature( + kEligibleAds, kFieldTrialParameterAdPredictorWeights); + + AdPredictorWeights weights = ToAdPredictorWeights(param_value); + if (weights.empty()) { + weights = kDefaultWeights; + } + + return weights; +} + +} // namespace features +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features.h b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features.h new file mode 100644 index 000000000000..7a96d8abbf81 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_FEATURES_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_FEATURES_H_ + +#include "base/feature_list.h" +#include "bat/ads/internal/eligible_ads/eligible_ads_aliases.h" + +namespace ads { +namespace features { + +extern const base::Feature kEligibleAds; + +bool IsEligibleAdsEnabled(); + +AdPredictorWeights GetAdPredictorWeights(); + +} // namespace features +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_FEATURES_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_unittest.cc new file mode 100644 index 000000000000..22d64cb5ab4a --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_unittest.cc @@ -0,0 +1,49 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/eligible_ads/eligible_ads_features.h" + +#include "testing/gtest/include/gtest/gtest.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +namespace { +const unsigned int kNumberOfAdServingFeatures = 7u; +} // namespace + +TEST(BatAdsEligibleAdsFeaturesTest, EligibleAdsEnabled) { + // Arrange + + // Act + const bool is_enabled = features::IsEligibleAdsEnabled(); + + // Assert + EXPECT_TRUE(is_enabled); +} + +TEST(BatAdsEligibleAdsFeaturesTest, AdFeatureWeightLength) { + // Arrange + + // Act + AdPredictorWeights weights = features::GetAdPredictorWeights(); + + // Assert + EXPECT_EQ(kNumberOfAdServingFeatures, weights.size()); +} + +TEST(BatAdsEligibleAdsFeaturesTest, DefaultAdFeatureWeights) { + // Arrange + + // Act + AdPredictorWeights weights = features::GetAdPredictorWeights(); + + // Assert + AdPredictorWeights expected_weights = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}; + EXPECT_EQ(expected_weights, weights); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util.cc new file mode 100644 index 000000000000..086463e586ce --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util.cc @@ -0,0 +1,43 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/eligible_ads/eligible_ads_features_util.h" + +#include + +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" + +namespace ads { + +AdPredictorWeights ToAdPredictorWeights(const std::string& param_value) { + const std::vector components = base::SplitString( + param_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + AdPredictorWeights weights; + for (const auto& component : components) { + double value_as_double; + if (!base::StringToDouble(component, &value_as_double)) { + return {}; + } + + if (value_as_double < 0) { + return {}; + } + + weights.push_back(value_as_double); + } + + const double sum = std::accumulate(weights.begin(), weights.end(), + decltype(weights)::value_type(0)); + if (sum <= 0) { + return {}; + } + + return weights; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util.h b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util.h new file mode 100644 index 000000000000..f13181f273c2 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_FEATURES_UTIL_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_FEATURES_UTIL_H_ + +#include +#include + +#include "bat/ads/internal/eligible_ads/eligible_ads_aliases.h" + +namespace ads { + +AdPredictorWeights ToAdPredictorWeights(const std::string& param_value); + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_FEATURES_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util_unittest.cc new file mode 100644 index 000000000000..d0df539a32cd --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_features_util_unittest.cc @@ -0,0 +1,109 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/eligible_ads/eligible_ads_features_util.h" + +#include "testing/gtest/include/gtest/gtest.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +TEST(BatAdsEligibleAdsFeaturesUtilTest, + ToAdPredictorWeightsForEmptyParamValue) { + // Arrange + + // Act + const AdPredictorWeights weights = ToAdPredictorWeights(""); + + // Assert + const AdPredictorWeights expected_weights = {}; + EXPECT_EQ(expected_weights, weights); +} + +TEST(BatAdsEligibleAdsFeaturesUtilTest, + ToAdPredictorWeightsForNonNumericParamValue) { + // Arrange + + // Act + const AdPredictorWeights weights = ToAdPredictorWeights("1.0, foobar, 2.2"); + + // Assert + const AdPredictorWeights expected_weights = {}; + EXPECT_EQ(expected_weights, weights); +} + +TEST(BatAdsEligibleAdsFeaturesUtilTest, + ToAdPredictorWeightsForAllZeroParamValue) { + // Arrange + + // Act + const AdPredictorWeights weights = ToAdPredictorWeights("0.0, 0.0, 0.0"); + + // Assert + const AdPredictorWeights expected_weights = {}; + EXPECT_EQ(expected_weights, weights); +} + +TEST(BatAdsEligibleAdsFeaturesUtilTest, + ToAdPredictorWeightsForSomeZeroParamValue) { + // Arrange + + // Act + const AdPredictorWeights weights = ToAdPredictorWeights("0.0, 0.1, 0.0"); + + // Assert + const AdPredictorWeights expected_weights = {0.0, 0.1, 0.0}; + EXPECT_EQ(expected_weights, weights); +} + +TEST(BatAdsEligibleAdsFeaturesUtilTest, + ToAdPredictorWeightsForNegativeParamValue) { + // Arrange + + // Act + const AdPredictorWeights weights = ToAdPredictorWeights("1.0, 3.0, -2.0"); + + // Assert + const AdPredictorWeights expected_weights = {}; + EXPECT_EQ(expected_weights, weights); +} + +TEST(BatAdsEligibleAdsFeaturesUtilTest, + ToAdPredictorWeightsForSingleParamValue) { + // Arrange + + // Act + const AdPredictorWeights weights = ToAdPredictorWeights("1.0"); + + // Assert + const AdPredictorWeights expected_weights = {1.0}; + EXPECT_EQ(expected_weights, weights); +} + +TEST(BatAdsEligibleAdsFeaturesUtilTest, ToAdPredictorWeightsForParamValue) { + // Arrange + + // Act + const AdPredictorWeights weights = ToAdPredictorWeights("1.1, 3.3, 2.2"); + + // Assert + const AdPredictorWeights expected_weights = {1.1, 3.3, 2.2}; + EXPECT_EQ(expected_weights, weights); +} + +TEST(BatAdsEligibleAdsFeaturesUtilTest, + ToAdPredictorWeightsForParamValueWithMixedTypes) { + // Arrange + + // Act + const AdPredictorWeights weights = ToAdPredictorWeights("1, 3, 2.2"); + + // Assert + const AdPredictorWeights expected_weights = {1.0, 3.0, 2.2}; + EXPECT_EQ(expected_weights, weights); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_predictor_util.h b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_predictor_util.h new file mode 100644 index 000000000000..42209c0c09bb --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_predictor_util.h @@ -0,0 +1,139 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_PREDICTOR_UTIL_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_PREDICTOR_UTIL_H_ + +#include +#include + +#include "bat/ads/internal/ad_events/ad_event_util.h" +#include "bat/ads/internal/ad_targeting/ad_targeting.h" +#include "bat/ads/internal/ad_targeting/ad_targeting_user_model_info.h" +#include "bat/ads/internal/container_util.h" +#include "bat/ads/internal/eligible_ads/ad_predictor_info.h" +#include "bat/ads/internal/eligible_ads/eligible_ads_features.h" +#include "bat/ads/internal/segments/segments_aliases.h" + +namespace ads { + +enum AdPredictorWeightIndex { + kMatchesIntentChildSegment = 0, + kMatchesIntentParentSegment, + kMatchesInterestChildSegment, + kMatchesInterestParentSegment, + kAdLastSeenInHours, + kAdvertiserLastSeenInHours, + kPriority +}; + +template +AdPredictorInfo ComputePredictorFeatures( + const AdPredictorInfo& ad_predictor, + const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events) { + AdPredictorInfo mutable_ad_predictor = ad_predictor; + + const SegmentList intent_child_segments_intersection = SetIntersection( + ad_targeting::GetTopParentChildPurchaseIntenSegments(user_model), + ad_predictor.segments); + mutable_ad_predictor.does_match_intent_child_segments = + intent_child_segments_intersection.empty() ? false : true; + + const SegmentList intent_parent_segments_intersection = SetIntersection( + ad_targeting::GetTopParentPurchaseIntenSegments(user_model), + ad_predictor.segments); + mutable_ad_predictor.does_match_intent_parent_segments = + intent_parent_segments_intersection.empty() ? false : true; + + const SegmentList interest_child_segments_intersection = SetIntersection( + ad_targeting::GetTopParentChildInterestSegments(user_model), + ad_predictor.segments); + mutable_ad_predictor.does_match_interest_child_segments = + interest_child_segments_intersection.empty() ? false : true; + + const SegmentList interest_parent_segments_intersection = + SetIntersection(ad_targeting::GetTopParentInterestSegments(user_model), + ad_predictor.segments); + mutable_ad_predictor.does_match_interest_parent_segments = + interest_parent_segments_intersection.empty() ? false : true; + + const base::Time now = base::Time::Now(); + + const absl::optional last_seen_ad = + GetLastSeenAdTime(ad_events, ad_predictor.creative_ad); + mutable_ad_predictor.ad_last_seen_hours_ago = + last_seen_ad ? (now - last_seen_ad.value()).InHours() : 0; + + const absl::optional last_seen_advertiser = + GetLastSeenAdvertiserTime(ad_events, ad_predictor.creative_ad); + mutable_ad_predictor.advertiser_last_seen_hours_ago = + last_seen_advertiser ? (now - last_seen_advertiser.value()).InHours() : 0; + + return mutable_ad_predictor; +} + +template +double ComputePredictorScore(const AdPredictorInfo& ad_predictor) { + const AdPredictorWeights weights = features::GetAdPredictorWeights(); + double score = 0.0; + + if (ad_predictor.does_match_intent_child_segments) { + score += weights.at(AdPredictorWeightIndex::kMatchesIntentChildSegment); + } else if (ad_predictor.does_match_intent_parent_segments) { + score += weights.at(AdPredictorWeightIndex::kMatchesIntentParentSegment); + } + + if (ad_predictor.does_match_interest_child_segments) { + score += weights.at(AdPredictorWeightIndex::kMatchesInterestChildSegment); + } else if (ad_predictor.does_match_interest_parent_segments) { + score += weights.at(AdPredictorWeightIndex::kMatchesInterestParentSegment); + } + + if (ad_predictor.ad_last_seen_hours_ago <= base::Time::kHoursPerDay) { + score += weights.at(AdPredictorWeightIndex::kAdLastSeenInHours) * + ad_predictor.ad_last_seen_hours_ago / + static_cast(base::Time::kHoursPerDay); + } + + if (ad_predictor.advertiser_last_seen_hours_ago <= base::Time::kHoursPerDay) { + score += weights.at(AdPredictorWeightIndex::kAdvertiserLastSeenInHours) * + ad_predictor.advertiser_last_seen_hours_ago / + static_cast(base::Time::kHoursPerDay); + } + + if (ad_predictor.creative_ad.priority > 0) { + score += weights.at(AdPredictorWeightIndex::kPriority) / + ad_predictor.creative_ad.priority; + } + + score *= ad_predictor.creative_ad.ptr; + + return score; +} + +template +std::map> ComputePredictorFeaturesAndScores( + const std::map>& ads, + const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events) { + std::map> ads_with_features; + + for (auto& ad : ads) { + const AdPredictorInfo ad_predictor = ad.second; + AdPredictorInfo mutable_ad_predictor = + ComputePredictorFeatures(ad_predictor, user_model, ad_events); + mutable_ad_predictor.score = ComputePredictorScore(mutable_ad_predictor); + ads_with_features.insert( + {mutable_ad_predictor.creative_ad.creative_instance_id, + mutable_ad_predictor}); + } + + return ads_with_features; +} + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_PREDICTOR_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_predictor_util_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_predictor_util_unittest.cc new file mode 100644 index 000000000000..821965556317 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_predictor_util_unittest.cc @@ -0,0 +1,98 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/eligible_ads/eligible_ads_predictor_util.h" + +#include "base/guid.h" +#include "base/test/scoped_feature_list.h" +#include "bat/ads/internal/bundle/creative_ad_notification_info.h" +#include "bat/ads/internal/bundle/creative_ad_notification_unittest_util.h" +#include "bat/ads/internal/eligible_ads/eligible_ads_features.h" +#include "bat/ads/internal/unittest_util.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +TEST(BatAdsEligibleAdsUtilTest, + ComputePredictorScoreWithZeroWeightsNotAllowedByGriffin) { + // Arrange + const char kAdFeatureWeights[] = "ad_predictor_weights"; + std::map kEligibleAdsParameters; + kEligibleAdsParameters[kAdFeatureWeights] = + "0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0"; + + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeaturesAndParameters( + {{features::kEligibleAds, kEligibleAdsParameters}}, {}); + + const std::string segment = "foo-bar"; + const double ptr = 1.0; + const double priority = 1; + const CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(segment, ptr, priority); + + AdPredictorInfo ad_predictor; + ad_predictor.creative_ad = creative_ad_notification; + ad_predictor.segments = {segment}; + ad_predictor.does_match_intent_child_segments = 1; + ad_predictor.does_match_intent_parent_segments = 0; + ad_predictor.does_match_interest_child_segments = 0; + ad_predictor.does_match_interest_parent_segments = 0; + ad_predictor.ad_last_seen_hours_ago = 15; + ad_predictor.advertiser_last_seen_hours_ago = 48; + + // Act + ad_predictor.score = ComputePredictorScore(ad_predictor); + + // Assert + EXPECT_LT(0, ad_predictor.score); +} + +TEST(BatAdsEligibleAdsUtilTest, ComputePredictorScoreWithDefaultWeights) { + // Arrange + const std::string segment = "foo-bar"; + const double ptr = 1.0; + const double priority = 1; + const CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(segment, ptr, priority); + + AdPredictorInfo ad_predictor; + ad_predictor.creative_ad = creative_ad_notification; + ad_predictor.segments = {segment}; + ad_predictor.does_match_intent_child_segments = 1; + ad_predictor.does_match_intent_parent_segments = 0; + ad_predictor.does_match_interest_child_segments = 0; + ad_predictor.does_match_interest_parent_segments = 0; + ad_predictor.ad_last_seen_hours_ago = 15; + ad_predictor.advertiser_last_seen_hours_ago = 48; + + // Act + ad_predictor.score = ComputePredictorScore(ad_predictor); + + // Assert + const double expected_score = 0.0 + 1.0 + 1.0 * (15 / 24.0) + 1.0 * 1.0; + EXPECT_EQ(expected_score, ad_predictor.score); +} + +TEST(BatAdsEligibleAdsUtilTest, ComputePredictorScoreWithEmptyAdFeatures) { + // Arrange + const std::string segment = "foo-bar"; + const double ptr = 1.0; + const double priority = 1; + const CreativeAdNotificationInfo creative_ad_notification = + GetCreativeAdNotification(segment, ptr, priority); + + AdPredictorInfo ad_predictor; + + // Act + ad_predictor.score = ComputePredictorScore(ad_predictor); + + // Assert + const double expected_score = 0; + EXPECT_EQ(expected_score, ad_predictor.score); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_util.h b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_util.h new file mode 100644 index 000000000000..63569df76dd8 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_util.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_UTIL_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_UTIL_H_ + +#include +#include +#include +#include + +#include "bat/ads/internal/eligible_ads/ad_predictor_info.h" + +namespace ads { + +struct CreativeAdNotificationInfo; +struct CreativeInlineContentAdInfo; + +template +std::map> GroupEligibleAdsByCreativeInstanceId( + const std::vector& eligible_ads) { + std::map> ads; + for (const auto& eligible_ad : eligible_ads) { + const auto iter = ads.find(eligible_ad.creative_instance_id); + if (iter != ads.end()) { + iter->second.segments.push_back(eligible_ad.segment); + continue; + } + + AdPredictorInfo ad_predictor; + ad_predictor.segments = {eligible_ad.segment}; + ad_predictor.creative_ad = eligible_ad; + ads.insert({eligible_ad.creative_instance_id, ad_predictor}); + } + + return ads; +} + +using CreativeAdNotificationPredictorMap = + std::map>; + +using CreativeInlineContentAdPredictorMap = + std::map>; + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_ELIGIBLE_ADS_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_util_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_util_unittest.cc new file mode 100644 index 000000000000..23c8255ee7f7 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/eligible_ads_util_unittest.cc @@ -0,0 +1,66 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/eligible_ads/eligible_ads_util.h" + +#include + +#include "base/guid.h" +#include "bat/ads/internal/bundle/creative_ad_notification_info.h" +#include "bat/ads/internal/bundle/creative_ad_notification_unittest_util.h" +#include "bat/ads/internal/unittest_util.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +TEST(BatAdsEligibleAdsUtilTest, + GroupEligibleAdsByCreativeInstanceIdForEmptyAds) { + // Arrange + std::vector eligible_ads; + + // Act + const CreativeAdNotificationPredictorMap ads = + GroupEligibleAdsByCreativeInstanceId(eligible_ads); + + // Assert + EXPECT_TRUE(ads.empty()); +} + +TEST(BatAdsEligibleAdsUtilTest, GroupEligibleAdsByCreativeInstanceId) { + // Arrange + std::vector eligible_ads; + + const CreativeAdNotificationInfo creative_ad_notification_1 = + GetCreativeAdNotification(base::GenerateGUID(), "foo-bar1"); + eligible_ads.push_back(creative_ad_notification_1); + + const CreativeAdNotificationInfo creative_ad_notification_2 = + GetCreativeAdNotification(base::GenerateGUID(), "foo-bar2"); + eligible_ads.push_back(creative_ad_notification_2); + + const CreativeAdNotificationInfo creative_ad_notification_3 = + GetCreativeAdNotification(base::GenerateGUID(), "foo-bar3"); + eligible_ads.push_back(creative_ad_notification_3); + + const CreativeAdNotificationInfo creative_ad_notification_4 = + GetCreativeAdNotification(creative_ad_notification_2.creative_instance_id, + "foo-bar4"); + eligible_ads.push_back(creative_ad_notification_4); + + // Act + const CreativeAdNotificationPredictorMap ads = + GroupEligibleAdsByCreativeInstanceId(eligible_ads); + + // Assert + ASSERT_EQ(3u, ads.size()); + + AdPredictorInfo ad = + ads.at(creative_ad_notification_2.creative_instance_id); + const SegmentList& expected_segments = {"foo-bar2", "foo-bar4"}; + EXPECT_EQ(expected_segments, ad.segments); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.cc index f15ebf513df1..3a2a7096480d 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.cc @@ -18,6 +18,9 @@ #include "bat/ads/internal/database/tables/ad_events_database_table.h" #include "bat/ads/internal/database/tables/creative_inline_content_ads_database_table.h" #include "bat/ads/internal/eligible_ads/eligible_ads_constants.h" +#include "bat/ads/internal/eligible_ads/eligible_ads_predictor_util.h" +#include "bat/ads/internal/eligible_ads/eligible_ads_util.h" +#include "bat/ads/internal/eligible_ads/sample_ads.h" #include "bat/ads/internal/eligible_ads/seen_ads.h" #include "bat/ads/internal/eligible_ads/seen_advertisers.h" #include "bat/ads/internal/features/ad_serving/ad_serving_features.h" @@ -53,7 +56,7 @@ void EligibleAds::SetLastServedAd(const CreativeAdInfo& creative_ad) { void EligibleAds::Get(const ad_targeting::UserModelInfo& user_model, const std::string& dimensions, - GetEligibleAdsCallback callback) { + GetCallback callback) { database::table::AdEvents database_table; database_table.GetAll([=](const bool success, const AdEventList& ad_events) { if (!success) { @@ -72,14 +75,91 @@ void EligibleAds::Get(const ad_targeting::UserModelInfo& user_model, }); } +void EligibleAds::GetV2(const ad_targeting::UserModelInfo& user_model, + const std::string& dimensions, + GetV2Callback callback) { + database::table::AdEvents database_table; + database_table.GetAll([=](const bool success, const AdEventList& ad_events) { + if (!success) { + BLOG(1, "Failed to get ad events"); + callback(/* was_allowed */ false, absl::nullopt); + return; + } + + const int max_count = features::GetBrowsingHistoryMaxCount(); + const int days_ago = features::GetBrowsingHistoryDaysAgo(); + AdsClientHelper::Get()->GetBrowsingHistory( + max_count, days_ago, [=](const BrowsingHistoryList& history) { + GetEligibleAds(user_model, ad_events, history, dimensions, callback); + }); + }); +} + /////////////////////////////////////////////////////////////////////////////// +void EligibleAds::GetEligibleAds(const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events, + const BrowsingHistoryList& browsing_history, + const std::string& dimensions, + GetV2Callback callback) const { + BLOG(1, "Get eligible ads"); + + database::table::CreativeInlineContentAds database_table; + database_table.GetForDimensions( + dimensions, + [=](const bool success, const CreativeInlineContentAdList& ads) { + if (!success) { + BLOG(1, "Failed to get inline content ads"); + callback(/* was_allowed */ false, absl::nullopt); + return; + } + + if (ads.empty()) { + BLOG(1, "No inline content ads"); + callback(/* was_allowed */ true, absl::nullopt); + return; + } + + CreativeInlineContentAdList eligible_ads = ApplyFrequencyCapping( + ads, + ShouldCapLastServedAd(ads) ? last_served_creative_ad_ + : CreativeAdInfo(), + ad_events, browsing_history); + + if (eligible_ads.empty()) { + BLOG(1, "No eligible ads"); + callback(/* was_allowed */ true, absl::nullopt); + return; + } + + ChooseAd(user_model, ad_events, eligible_ads, callback); + }); +} + +void EligibleAds::ChooseAd(const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events, + const CreativeInlineContentAdList& eligible_ads, + GetV2Callback callback) const { + DCHECK(!eligible_ads.empty()); + + const CreativeInlineContentAdPredictorMap ads = + GroupEligibleAdsByCreativeInstanceId(eligible_ads); + + const CreativeInlineContentAdPredictorMap ads_with_features = + ComputePredictorFeaturesAndScores(ads, user_model, ad_events); + + const absl::optional ad = + SampleFromAds(ads_with_features); + + callback(/* was_allowed */ true, ad); +} + void EligibleAds::GetForParentChildSegments( const ad_targeting::UserModelInfo& user_model, const std::string& dimensions, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const { + GetCallback callback) const { const SegmentList segments = ad_targeting::GetTopParentChildSegments(user_model); if (segments.empty()) { @@ -94,7 +174,7 @@ void EligibleAds::GetForParentChildSegments( } database::table::CreativeInlineContentAds database_table; - database_table.GetForSegments( + database_table.GetForSegmentsAndDimensions( segments, dimensions, [=](const bool success, const SegmentList& segments, const CreativeInlineContentAdList& ads) { @@ -117,7 +197,7 @@ void EligibleAds::GetForParentSegments( const std::string& dimensions, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const { + GetCallback callback) const { const SegmentList segments = ad_targeting::GetTopParentSegments(user_model); if (segments.empty()) { GetForUntargeted(dimensions, ad_events, browsing_history, callback); @@ -130,7 +210,7 @@ void EligibleAds::GetForParentSegments( } database::table::CreativeInlineContentAds database_table; - database_table.GetForSegments( + database_table.GetForSegmentsAndDimensions( segments, dimensions, [=](const bool success, const SegmentList& segments, const CreativeInlineContentAdList& ads) { @@ -150,11 +230,11 @@ void EligibleAds::GetForParentSegments( void EligibleAds::GetForUntargeted(const std::string& dimensions, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const { + GetCallback callback) const { BLOG(1, "Get eligible ads for untargeted segment"); database::table::CreativeInlineContentAds database_table; - database_table.GetForSegments( + database_table.GetForSegmentsAndDimensions( {kUntargeted}, dimensions, [=](const bool success, const SegmentList& segments, const CreativeInlineContentAdList& ads) { diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.h b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.h index ede524bbcc9f..f599b8b212fd 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads.h @@ -12,6 +12,7 @@ #include "bat/ads/internal/bundle/creative_inline_content_ad_info_aliases.h" #include "bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads_aliases.h" #include "bat/ads/internal/frequency_capping/frequency_capping_aliases.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace ads { @@ -28,6 +29,13 @@ class AntiTargeting; namespace inline_content_ads { +using GetCallback = + std::function; + +using GetV2Callback = + std::function&)>; + class EligibleAds final { public: EligibleAds( @@ -39,7 +47,11 @@ class EligibleAds final { void Get(const ad_targeting::UserModelInfo& user_model, const std::string& dimensions, - GetEligibleAdsCallback callback); + GetCallback callback); + + void GetV2(const ad_targeting::UserModelInfo& user_model, + const std::string& dimensions, + GetV2Callback callback); private: ad_targeting::geographic::SubdivisionTargeting* @@ -49,22 +61,33 @@ class EligibleAds final { CreativeAdInfo last_served_creative_ad_; + void GetEligibleAds(const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events, + const BrowsingHistoryList& browsing_history, + const std::string& dimensions, + GetV2Callback callback) const; + + void ChooseAd(const ad_targeting::UserModelInfo& user_model, + const AdEventList& ad_events, + const CreativeInlineContentAdList& eligible_ads, + GetV2Callback callback) const; + void GetForParentChildSegments(const ad_targeting::UserModelInfo& user_model, const std::string& dimensions, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const; + GetCallback callback) const; void GetForParentSegments(const ad_targeting::UserModelInfo& user_model, const std::string& dimensions, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const; + GetCallback callback) const; void GetForUntargeted(const std::string& dimensions, const AdEventList& ad_events, const BrowsingHistoryList& browsing_history, - GetEligibleAdsCallback callback) const; + GetCallback callback) const; CreativeInlineContentAdList FilterIneligibleAds( const CreativeInlineContentAdList& ads, diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads_unittest.cc index f157f3a97e0f..c7031d11f1ed 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/inline_content_ads/eligible_inline_content_ads_unittest.cc @@ -14,6 +14,7 @@ #include "bat/ads/internal/database/tables/creative_inline_content_ads_database_table.h" #include "bat/ads/internal/resources/frequency_capping/anti_targeting_resource.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* @@ -303,4 +304,101 @@ TEST_F(BatAdsEligibleInlineContentAdsTest, GetAdsForUnmatchedDimensions) { // Assert } +TEST_F(BatAdsEligibleInlineContentAdsTest, GetV2WithoutAds) { + // Arrange + const SegmentList interest_segments = {"interest-foo", "interest-bar"}; + const SegmentList purchase_intent_segments = {"intent-foo", "intent-bar"}; + const ad_targeting::UserModelInfo user_model = + ad_targeting::BuildUserModel(interest_segments, purchase_intent_segments); + + // Act + ad_targeting::geographic::SubdivisionTargeting subdivision_targeting; + resource::AntiTargeting anti_targeting_resource; + inline_content_ads::EligibleAds eligible_ads(&subdivision_targeting, + &anti_targeting_resource); + + eligible_ads.GetV2( + user_model, "200x100", + [=](const bool was_allowed, + const absl::optional& ad) { + EXPECT_EQ(absl::nullopt, ad); + }); + + // Assert +} + +TEST_F(BatAdsEligibleInlineContentAdsTest, GetV2WithEmptySegments) { + // Arrange + CreativeInlineContentAdList creative_inline_content_ads; + + const CreativeInlineContentAdInfo creative_inline_content_ad_1 = + GetCreativeInlineContentAdForSegment("foo"); + creative_inline_content_ads.push_back(creative_inline_content_ad_1); + + const CreativeInlineContentAdInfo creative_inline_content_ad_2 = + GetCreativeInlineContentAdForSegment("foo-bar"); + creative_inline_content_ads.push_back(creative_inline_content_ad_2); + + Save(creative_inline_content_ads); + + const SegmentList interest_segments = {}; + const SegmentList purchase_intent_segments = {}; + const ad_targeting::UserModelInfo user_model = + ad_targeting::BuildUserModel(interest_segments, purchase_intent_segments); + + // Act + ad_targeting::geographic::SubdivisionTargeting subdivision_targeting; + resource::AntiTargeting anti_targeting_resource; + inline_content_ads::EligibleAds eligible_ads(&subdivision_targeting, + &anti_targeting_resource); + + const CreativeInlineContentAdInfo expected_ad = creative_inline_content_ad_2; + + eligible_ads.GetV2( + user_model, "200x100", + [=](const bool was_allowed, + const absl::optional& ad) { + EXPECT_TRUE(ad); + }); + + // Assert +} + +TEST_F(BatAdsEligibleInlineContentAdsTest, GetV2) { + // Arrange + CreativeInlineContentAdList creative_inline_content_ads; + + const CreativeInlineContentAdInfo creative_inline_content_ad_1 = + GetCreativeInlineContentAdForSegment("foo-bar1"); + creative_inline_content_ads.push_back(creative_inline_content_ad_1); + + const CreativeInlineContentAdInfo creative_inline_content_ad_2 = + GetCreativeInlineContentAdForSegment("foo-bar3"); + creative_inline_content_ads.push_back(creative_inline_content_ad_2); + + Save(creative_inline_content_ads); + + const SegmentList interest_segments = {"foo-bar3"}; + const SegmentList purchase_intent_segments = {"foo-bar1", "foo-bar2"}; + const ad_targeting::UserModelInfo user_model = + ad_targeting::BuildUserModel(interest_segments, purchase_intent_segments); + + // Act + ad_targeting::geographic::SubdivisionTargeting subdivision_targeting; + resource::AntiTargeting anti_targeting_resource; + inline_content_ads::EligibleAds eligible_ads(&subdivision_targeting, + &anti_targeting_resource); + + const CreativeInlineContentAdInfo expected_ad = creative_inline_content_ad_2; + + eligible_ads.GetV2( + user_model, "200x100", + [=](const bool was_allowed, + const absl::optional& ad) { + EXPECT_TRUE(ad); + }); + + // Assert +} + } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/sample_ads.h b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/sample_ads.h new file mode 100644 index 000000000000..d9921efd84e2 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/sample_ads.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_SAMPLE_ADS_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_SAMPLE_ADS_H_ + +#include +#include +#include + +#include "base/notreached.h" +#include "base/rand_util.h" +#include "bat/ads/internal/eligible_ads/ad_predictor_info.h" +#include "bat/ads/internal/number_util.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace ads { + +template +double CalculateNormalisingConstant( + const std::map>& ads) { + double normalising_constant = 0.0; + for (const auto& ad : ads) { + normalising_constant += ad.second.score; + } + + return normalising_constant; +} + +template +absl::optional SampleFromAds( + const std::map>& ads) { + const double normalising_constant = CalculateNormalisingConstant(ads); + if (DoubleIsLessEqual(normalising_constant, 0.0)) { + return absl::nullopt; + } + + const double rand = base::RandDouble(); + double sum = 0; + T selected_ad; + + for (const auto& ad : ads) { + const double probability = ad.second.score / normalising_constant; + sum += probability; + if (DoubleIsLess(rand, sum)) { + return ad.second.creative_ad; + } + } + + NOTREACHED() << "Sum should always be strictly less than probability"; + return absl::nullopt; +} + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_ELIGIBLE_ADS_SAMPLE_ADS_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/sample_ads_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/sample_ads_unittest.cc new file mode 100644 index 000000000000..17f17b4d674a --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/eligible_ads/sample_ads_unittest.cc @@ -0,0 +1,153 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/eligible_ads/sample_ads.h" + +#include "base/guid.h" +#include "bat/ads/internal/bundle/creative_ad_notification_info.h" +#include "bat/ads/internal/bundle/creative_ad_notification_unittest_util.h" +#include "bat/ads/internal/eligible_ads/eligible_ads_util.h" +#include "bat/ads/internal/unittest_util.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace ads { + +TEST(BatAdsSampleAdsTest, CalculateNormalisingConstantWithEmptyAds) { + // Arrange + CreativeAdNotificationPredictorMap ads; + + // Act + const double normalising_constant = CalculateNormalisingConstant(ads); + + // Assert + const double expected_normalising_constant = 0.0; + EXPECT_TRUE( + DoubleEquals(expected_normalising_constant, normalising_constant)); +} + +TEST(BatAdsSampleAdsTest, CalculateNormalisingConstant) { + // Arrange + CreativeAdNotificationPredictorMap ads; + AdPredictorInfo ad_predictor_1; + ad_predictor_1.score = 1.1; + ads[base::GenerateGUID()] = ad_predictor_1; + + AdPredictorInfo ad_predictor_2; + ad_predictor_2.score = 2.2; + ads[base::GenerateGUID()] = ad_predictor_2; + + AdPredictorInfo ad_predictor_3; + ad_predictor_3.score = 3.3; + ads[base::GenerateGUID()] = ad_predictor_3; + + // Act + const double normalising_constant = CalculateNormalisingConstant(ads); + + // Assert + const double expected_normalising_constant = 6.6; + EXPECT_TRUE( + DoubleEquals(expected_normalising_constant, normalising_constant)); +} + +TEST(BatAdsSampleAdsTest, SampleFromAdsWithZeroScores) { + // Arrange + CreativeAdNotificationPredictorMap ads; + AdPredictorInfo ad_predictor_1; + ad_predictor_1.score = 0; + ads[base::GenerateGUID()] = ad_predictor_1; + + AdPredictorInfo ad_predictor_2; + ad_predictor_2.score = 0; + ads[base::GenerateGUID()] = ad_predictor_2; + + AdPredictorInfo ad_predictor_3; + ad_predictor_3.score = 0; + ads[base::GenerateGUID()] = ad_predictor_3; + + // Act + const absl::optional ad = SampleFromAds(ads); + + // Assert + const absl::optional expected_ad = absl::nullopt; + EXPECT_EQ(expected_ad, ad); +} + +TEST(BatAdsSampleAdsTest, DeterministicallySampleFromAdsWithOneNonZeroScore) { + // Arrange + CreativeAdNotificationPredictorMap ads; + + CreativeAdNotificationInfo creative_ad_notification_1 = + GetCreativeAdNotification("foo-bar", 1.0, 1); + AdPredictorInfo ad_predictor_1; + ad_predictor_1.score = 0; + ad_predictor_1.creative_ad = creative_ad_notification_1; + ads[creative_ad_notification_1.creative_instance_id] = ad_predictor_1; + + CreativeAdNotificationInfo creative_ad_notification_2 = + GetCreativeAdNotification("foo-bar", 1.0, 1); + AdPredictorInfo ad_predictor_2; + ad_predictor_2.score = 0.1; + ad_predictor_2.creative_ad = creative_ad_notification_2; + ads[creative_ad_notification_2.creative_instance_id] = ad_predictor_2; + + CreativeAdNotificationInfo creative_ad_notification_3 = + GetCreativeAdNotification("foo-bar", 1.0, 1); + AdPredictorInfo ad_predictor_3; + ad_predictor_3.score = 0; + ad_predictor_3.creative_ad = creative_ad_notification_3; + ads[creative_ad_notification_3.creative_instance_id] = ad_predictor_3; + + // Act + for (int i = 0; i < 10; i++) { + CreativeAdNotificationInfo expected_ad = creative_ad_notification_2; + const absl::optional ad = SampleFromAds(ads); + EXPECT_EQ(expected_ad, ad.value()); + } + + // Assert +} + +TEST(BatAdsSampleAdsTest, ProbabilisticallySampleFromAds) { + // Arrange + CreativeAdNotificationPredictorMap ads; + + CreativeAdNotificationInfo creative_ad_notification_1 = + GetCreativeAdNotification("foo-bar", 1.0, 1); + AdPredictorInfo ad_predictor_1; + ad_predictor_1.creative_ad = creative_ad_notification_1; + ad_predictor_1.score = 3; + ads[creative_ad_notification_1.creative_instance_id] = ad_predictor_1; + + CreativeAdNotificationInfo creative_ad_notification_2 = + GetCreativeAdNotification("foo-bar", 1.0, 1); + AdPredictorInfo ad_predictor_2; + ad_predictor_2.creative_ad = creative_ad_notification_2; + ad_predictor_2.score = 3; + ads[creative_ad_notification_2.creative_instance_id] = ad_predictor_2; + + // Act + int ads_1_count = 0; + int ads_2_count = 0; + + // P(X>1) > 0.99999999 with X~Bin(n=25, p=0.5), i.e. less than 1 in 100M tests + // are expected to fail + for (int i = 0; i < 25; i++) { + const absl::optional ad = SampleFromAds(ads); + + if (ad.value().creative_instance_id == + creative_ad_notification_1.creative_instance_id) { + ads_1_count += 1; + } else if (ad.value().creative_instance_id == + creative_ad_notification_2.creative_instance_id) { + ads_2_count += 1; + } + } + + // Assert + EXPECT_FALSE(ads_1_count == 0 || ads_2_count == 0); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features.cc b/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features.cc index a349ad8a8a52..5913fdf7efda 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features.cc @@ -51,6 +51,9 @@ const char kFieldTrialParameterBrowsingHistoryDaysAgo[] = "browsing_history_days_ago"; const int kDefaultBrowsingHistoryDaysAgo = 180; +const char kFieldTrialParameterAdServingVersion[] = "ad_serving_version"; +const int kDefaultAdServingVersion = 1; + } // namespace const base::Feature kAdServing{kFeatureName, base::FEATURE_ENABLED_BY_DEFAULT}; @@ -119,5 +122,11 @@ int GetBrowsingHistoryDaysAgo() { kDefaultBrowsingHistoryDaysAgo); } +int GetAdServingVersion() { + return GetFieldTrialParamByFeatureAsInt(kAdServing, + kFieldTrialParameterAdServingVersion, + kDefaultAdServingVersion); +} + } // namespace features } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features.h b/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features.h index 4b8623fd70b0..06ab6f180c60 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features.h @@ -14,6 +14,7 @@ namespace features { extern const base::Feature kAdServing; bool IsAdServingEnabled(); +int GetAdServingVersion(); int GetDefaultAdNotificationsPerHour(); int GetMaximumAdNotificationsPerDay(); diff --git a/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features_unittest.cc index cad894835c78..fab414a23638 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/features/ad_serving/ad_serving_features_unittest.cc @@ -564,4 +564,15 @@ TEST(BatAdsAdServingFeaturesTest, DisabledMaximumPromotedContentAdsPerDay) { maximum_promoted_content_ads_per_day); } +TEST(BatAdsAdServingFeaturesTest, DefaultAdServingVersion) { + // Arrange + + // Act + const int ad_serving_version = features::GetAdServingVersion(); + + // Assert + const int expected_ad_serving_version = 1; + EXPECT_EQ(expected_ad_serving_version, ad_serving_version); +} + } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ml/pipeline/pipeline_util_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/ml/pipeline/pipeline_util_unittest.cc index 2b32bece1fa2..ee38759728b3 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ml/pipeline/pipeline_util_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ml/pipeline/pipeline_util_unittest.cc @@ -9,6 +9,7 @@ #include "bat/ads/internal/ml/pipeline/pipeline_info.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_file_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ml/pipeline/text_processing/text_processing_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/ml/pipeline/text_processing/text_processing_unittest.cc index 2213f1d85c2a..2e27c921beb0 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ml/pipeline/text_processing/text_processing_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ml/pipeline/text_processing/text_processing_unittest.cc @@ -17,6 +17,7 @@ #include "bat/ads/internal/ml/transformation/lowercase_transformation.h" #include "bat/ads/internal/ml/transformation/transformation.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_file_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/ml/transformation/hash_vectorizer_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/ml/transformation/hash_vectorizer_unittest.cc index e87edd42b05f..802c902971bb 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/ml/transformation/hash_vectorizer_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/ml/transformation/hash_vectorizer_unittest.cc @@ -7,6 +7,7 @@ #include "base/json/json_reader.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_file_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/resources/behavioral/bandits/epsilon_greedy_bandit_resource_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/resources/behavioral/bandits/epsilon_greedy_bandit_resource_unittest.cc index 80ce0b2cfd03..b543d4881628 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/resources/behavioral/bandits/epsilon_greedy_bandit_resource_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/resources/behavioral/bandits/epsilon_greedy_bandit_resource_unittest.cc @@ -9,6 +9,7 @@ #include "bat/ads/internal/catalog/catalog.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_file_util.h" #include "bat/ads/internal/unittest_util.h" #include "third_party/abseil-cpp/absl/types/optional.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/segments/segments_util_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/segments/segments_util_unittest.cc index c5890e0e46c1..232b82c55888 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/segments/segments_util_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/segments/segments_util_unittest.cc @@ -10,6 +10,7 @@ #include "bat/ads/internal/catalog/catalog.h" #include "bat/ads/internal/client/client.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_file_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/tokens/redeem_unblinded_token/user_data/confirmation_conversion_dto_user_data_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/tokens/redeem_unblinded_token/user_data/confirmation_conversion_dto_user_data_unittest.cc index d72a756a4c5a..07a58cf50b57 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/tokens/redeem_unblinded_token/user_data/confirmation_conversion_dto_user_data_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/tokens/redeem_unblinded_token/user_data/confirmation_conversion_dto_user_data_unittest.cc @@ -9,6 +9,7 @@ #include "bat/ads/internal/conversions/conversion_queue_item_info.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/tokens/redeem_unblinded_token/user_data/confirmation_dto_user_data_builder_unittest.cc b/vendor/bat-native-ads/src/bat/ads/internal/tokens/redeem_unblinded_token/user_data/confirmation_dto_user_data_builder_unittest.cc index d769674ef700..b7fc5451cf64 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/tokens/redeem_unblinded_token/user_data/confirmation_dto_user_data_builder_unittest.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/tokens/redeem_unblinded_token/user_data/confirmation_dto_user_data_builder_unittest.cc @@ -5,10 +5,12 @@ #include "bat/ads/internal/tokens/redeem_unblinded_token/user_data/confirmation_dto_user_data_builder.h" +#include #include #include "bat/ads/internal/database/tables/conversion_queue_database_table.h" #include "bat/ads/internal/unittest_base.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/internal/unittest_util.h" // npm run test -- brave_unit_tests --filter=BatAds* diff --git a/vendor/bat-native-ads/src/bat/ads/internal/unittest_base.cc b/vendor/bat-native-ads/src/bat/ads/internal/unittest_base.cc index 321bd5a97237..40f7f36aec1f 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/unittest_base.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/unittest_base.cc @@ -12,6 +12,7 @@ #include "bat/ads/ads_client.h" #include "bat/ads/internal/ads_client_helper.h" #include "bat/ads/internal/client/client.h" +#include "bat/ads/internal/unittest_file_util.h" #include "bat/ads/internal/unittest_util.h" #include "bat/ads/public/interfaces/ads.mojom.h" diff --git a/vendor/bat-native-ads/src/bat/ads/internal/unittest_file_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/unittest_file_util.cc new file mode 100644 index 000000000000..0becc604cba7 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/unittest_file_util.cc @@ -0,0 +1,69 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/unittest_file_util.h" + +#include "base/base_paths.h" +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "bat/ads/internal/unittest_tag_parser_util.h" + +namespace ads { + +namespace { + +base::FilePath GetDataPath() { + base::FilePath path; + base::PathService::Get(base::DIR_SOURCE_ROOT, &path); + path = path.AppendASCII("brave"); + path = path.AppendASCII("vendor"); + path = path.AppendASCII("bat-native-ads"); + path = path.AppendASCII("data"); + return path; +} + +} // namespace + +base::FilePath GetTestPath() { + base::FilePath path = GetDataPath(); + path = path.AppendASCII("test"); + return path; +} + +absl::optional ReadFileFromTestPathToString( + const std::string& name) { + base::FilePath path = GetTestPath(); + path = path.AppendASCII(name); + + std::string value; + if (!base::ReadFileToString(path, &value)) { + return absl::nullopt; + } + + ParseAndReplaceTagsForText(&value); + + return value; +} + +base::FilePath GetResourcesPath() { + base::FilePath path = GetDataPath(); + path = path.AppendASCII("resources"); + return path; +} + +absl::optional ReadFileFromResourcePathToString( + const std::string& name) { + base::FilePath path = GetResourcesPath(); + path = path.AppendASCII(name); + + std::string value; + if (!base::ReadFileToString(path, &value)) { + return absl::nullopt; + } + + return value; +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/unittest_file_util.h b/vendor/bat-native-ads/src/bat/ads/internal/unittest_file_util.h new file mode 100644 index 000000000000..4a12be3e377d --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/unittest_file_util.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_FILE_UTIL_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_FILE_UTIL_H_ + +#include + +#include "base/files/file_path.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace ads { + +base::FilePath GetTestPath(); + +absl::optional ReadFileFromTestPathToString( + const std::string& name); + +base::FilePath GetResourcesPath(); + +absl::optional ReadFileFromResourcePathToString( + const std::string& name); + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_FILE_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/unittest_tag_parser_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/unittest_tag_parser_util.cc new file mode 100644 index 000000000000..7c8e0a7ac424 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/unittest_tag_parser_util.cc @@ -0,0 +1,149 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/unittest_tag_parser_util.h" + +#include +#include + +#include "base/check.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "base/time/time_to_iso8601.h" +#include "bat/ads/internal/unittest_time_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/re2/src/re2/re2.h" + +namespace ads { + +namespace { + +const char kNowTagValue[] = "now"; +const char kDistantPastTagValue[] = "distant_past"; +const char kDistantFutureTagValue[] = "distant_future"; +const char kFromSecondsTagValue[] = "seconds"; +const char kFromMinutesTagValue[] = "minutes"; +const char kFromHoursTagValue[] = "hours"; +const char kFromDaysTagValue[] = "days"; + +bool ParseTimeDelta(const std::string& value, base::TimeDelta* time_delta) { + DCHECK(time_delta); + + const std::vector components = base::SplitString( + value, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + + int offset; + if (!base::StringToInt(components.at(0), &offset)) { + return false; + } + + const std::string period = components.at(1); + if (period == kFromSecondsTagValue) { + *time_delta = base::TimeDelta::FromSeconds(offset); + } else if (period == kFromMinutesTagValue) { + *time_delta = base::TimeDelta::FromMinutes(offset); + } else if (period == kFromHoursTagValue) { + *time_delta = base::TimeDelta::FromHours(offset); + } else if (period == kFromDaysTagValue) { + *time_delta = base::TimeDelta::FromDays(offset); + } else { + return false; + } + + return true; +} + +std::vector ParseTagsForText(std::string* text) { + DCHECK(text); + + re2::StringPiece text_string_piece(*text); + RE2 r("<(.*)>"); + + std::vector tags; + + std::string tag; + while (RE2::FindAndConsume(&text_string_piece, r, &tag)) { + tag = base::ToLowerASCII(tag); + tags.push_back(tag); + } + + return tags; +} + +bool ParseTimeTag(std::string* value) { + DCHECK(value); + + base::Time time; + + if (*value == kNowTagValue) { + time = Now(); + } else if (*value == kDistantPastTagValue) { + time = DistantPast(); + } else if (*value == kDistantFutureTagValue) { + time = DistantFuture(); + } else if (re2::RE2::FullMatch(*value, + "[-+]?[0-9]*.*(seconds|minutes|hours|days)")) { + base::TimeDelta time_delta; + + if (!ParseTimeDelta(*value, &time_delta)) { + return false; + } + + time = Now() + time_delta; + } else { + return false; + } + + *value = base::TimeToISO8601(time); + + return true; +} + +void ReplaceTagsForText(std::string* text, + const std::vector& tags) { + DCHECK(text); + + for (const auto& tag : tags) { + const std::vector components = base::SplitString( + tag, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + + if (components.size() != 2) { + FAIL() << "Invalid tag: " << tag; + return; + } + + const std::string key = components.at(0); + std::string value = components.at(1); + + if (key == "time") { + if (!ParseTimeTag(&value)) { + FAIL() << "Invalid tag: " << tag; + return; + } + } else { + FAIL() << "Unknown tag: " << tag; + return; + } + + const std::string enclosed_tag = base::StringPrintf("<%s>", tag.c_str()); + const std::string escaped_enclosed_tag = RE2::QuoteMeta(enclosed_tag); + + RE2::Replace(text, escaped_enclosed_tag, value); + } +} + +} // namespace + +void ParseAndReplaceTagsForText(std::string* text) { + DCHECK(text); + + const std::vector tags = ParseTagsForText(text); + ReplaceTagsForText(text, tags); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/unittest_tag_parser_util.h b/vendor/bat-native-ads/src/bat/ads/internal/unittest_tag_parser_util.h new file mode 100644 index 000000000000..392e6f9220f8 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/unittest_tag_parser_util.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_TAG_PARSER_UTIL_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_TAG_PARSER_UTIL_H_ + +#include + +namespace ads { + +void ParseAndReplaceTagsForText(std::string* text); + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_TAG_PARSER_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/unittest_time_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/unittest_time_util.cc new file mode 100644 index 000000000000..accc3b31ff20 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/unittest_time_util.cc @@ -0,0 +1,62 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "bat/ads/internal/unittest_time_util.h" + +#include "base/time/time_to_iso8601.h" + +namespace ads { + +int64_t TimestampFromDateString(const std::string& date) { + return TimeFromDateString(date).ToDoubleT(); +} + +base::Time TimeFromDateString(const std::string& date) { + base::Time time; + if (!base::Time::FromUTCString(date.c_str(), &time)) { + return time; + } + + return time.UTCMidnight() + base::TimeDelta::FromDays(1) - + base::TimeDelta::FromMilliseconds(1); +} + +int64_t DistantPastAsTimestamp() { + return 0; // Thursday, 1 January 1970 00:00:00 +} + +base::Time DistantPast() { + return base::Time::FromDoubleT(DistantPastAsTimestamp()); +} + +std::string DistantPastAsISO8601() { + return base::TimeToISO8601(DistantPast()); +} + +int64_t NowAsTimestamp() { + return static_cast(Now().ToDoubleT()); +} + +base::Time Now() { + return base::Time::Now(); +} + +std::string NowAsISO8601() { + return base::TimeToISO8601(Now()); +} + +int64_t DistantFutureAsTimestamp() { + return 4102444799; // Thursday, 31 December 2099 23:59:59 +} + +base::Time DistantFuture() { + return base::Time::FromDoubleT(DistantFutureAsTimestamp()); +} + +std::string DistantFutureAsISO8601() { + return base::TimeToISO8601(DistantFuture()); +} + +} // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/unittest_time_util.h b/vendor/bat-native-ads/src/bat/ads/internal/unittest_time_util.h new file mode 100644 index 000000000000..f283d63851a6 --- /dev/null +++ b/vendor/bat-native-ads/src/bat/ads/internal/unittest_time_util.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2021 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_TIME_UTIL_H_ +#define BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_TIME_UTIL_H_ + +#include +#include + +#include "base/time/time.h" + +namespace ads { + +int64_t TimestampFromDateString(const std::string& date); +base::Time TimeFromDateString(const std::string& date); + +int64_t DistantPastAsTimestamp(); +base::Time DistantPast(); +std::string DistantPastAsISO8601(); + +int64_t NowAsTimestamp(); +base::Time Now(); +std::string NowAsISO8601(); + +int64_t DistantFutureAsTimestamp(); +base::Time DistantFuture(); +std::string DistantFutureAsISO8601(); + +} // namespace ads + +#endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_TIME_UTIL_H_ diff --git a/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.cc b/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.cc index 22711614919b..2f37bd8c2eac 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.cc +++ b/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.cc @@ -5,29 +5,22 @@ #include "bat/ads/internal/unittest_util.h" -#include "base/base_paths.h" #include "base/check_op.h" #include "base/containers/flat_map.h" #include "base/files/file_util.h" #include "base/notreached.h" -#include "base/path_service.h" -#include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" -#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" -#include "base/time/time.h" -#include "base/time/time_to_iso8601.h" #include "bat/ads/ads.h" +#include "bat/ads/database.h" #include "bat/ads/internal/ads_client_mock.h" -#include "bat/ads/internal/time_formatting_util.h" -#include "bat/ads/internal/url_util.h" +#include "bat/ads/internal/unittest_file_util.h" +#include "bat/ads/internal/unittest_tag_parser_util.h" +#include "bat/ads/internal/unittest_time_util.h" #include "bat/ads/pref_names.h" -#include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "brave/components/l10n/browser/locale_helper_mock.h" #include "testing/gmock/include/gmock/gmock.h" -#include "third_party/abseil-cpp/absl/types/optional.h" -#include "third_party/re2/src/re2/re2.h" #include "url/gurl.h" -#include "url/url_constants.h" using ::testing::_; using ::testing::Invoke; @@ -43,127 +36,6 @@ static std::map> g_ad_events; static std::map g_prefs; -const char kNowTagValue[] = "now"; -const char kDistantPastTagValue[] = "distant_past"; -const char kDistantFutureTagValue[] = "distant_future"; -const char kFromSecondsTagValue[] = "seconds"; -const char kFromMinutesTagValue[] = "minutes"; -const char kFromHoursTagValue[] = "hours"; -const char kFromDaysTagValue[] = "days"; - -bool ParseTimeDelta(const std::string& value, base::TimeDelta* time_delta) { - DCHECK(time_delta); - - const std::vector components = base::SplitString( - value, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - - int offset; - if (!base::StringToInt(components.at(0), &offset)) { - return false; - } - - const std::string period = components.at(1); - if (period == kFromSecondsTagValue) { - *time_delta = base::TimeDelta::FromSeconds(offset); - } else if (period == kFromMinutesTagValue) { - *time_delta = base::TimeDelta::FromMinutes(offset); - } else if (period == kFromHoursTagValue) { - *time_delta = base::TimeDelta::FromHours(offset); - } else if (period == kFromDaysTagValue) { - *time_delta = base::TimeDelta::FromDays(offset); - } else { - return false; - } - - return true; -} - -bool ParseTimeTag(std::string* value) { - DCHECK(value); - - base::Time time; - - if (*value == kNowTagValue) { - time = Now(); - } else if (*value == kDistantPastTagValue) { - time = DistantPast(); - } else if (*value == kDistantFutureTagValue) { - time = DistantFuture(); - } else if (re2::RE2::FullMatch(*value, - "[-+]?[0-9]*.*(seconds|minutes|hours|days)")) { - base::TimeDelta time_delta; - - if (!ParseTimeDelta(*value, &time_delta)) { - return false; - } - - time = Now() + time_delta; - } else { - return false; - } - - *value = base::TimeToISO8601(time); - - return true; -} - -std::vector ParseTagsForText(std::string* text) { - DCHECK(text); - - re2::StringPiece text_string_piece(*text); - RE2 r("<(.*)>"); - - std::vector tags; - - std::string tag; - while (RE2::FindAndConsume(&text_string_piece, r, &tag)) { - tag = base::ToLowerASCII(tag); - tags.push_back(tag); - } - - return tags; -} - -void ReplaceTagsForText(std::string* text, - const std::vector& tags) { - DCHECK(text); - - for (const auto& tag : tags) { - const std::vector components = base::SplitString( - tag, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - - if (components.size() != 2) { - FAIL() << "Invalid tag: " << tag; - return; - } - - const std::string key = components.at(0); - std::string value = components.at(1); - - if (key == "time") { - if (!ParseTimeTag(&value)) { - FAIL() << "Invalid tag: " << tag; - return; - } - } else { - FAIL() << "Unknown tag: " << tag; - return; - } - - const std::string enclosed_tag = base::StringPrintf("<%s>", tag.c_str()); - const std::string escaped_enclosed_tag = RE2::QuoteMeta(enclosed_tag); - - RE2::Replace(text, escaped_enclosed_tag, value); - } -} - -void ParseAndReplaceTagsForText(std::string* text) { - DCHECK(text); - - const std::vector tags = ParseTagsForText(text); - ReplaceTagsForText(text, tags); -} - std::string GetUuid(const std::string& name) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); @@ -405,56 +277,6 @@ void MockDefaultPrefs(const std::unique_ptr& mock) { } // namespace -base::FilePath GetDataPath() { - base::FilePath path; - base::PathService::Get(base::DIR_SOURCE_ROOT, &path); - path = path.AppendASCII("brave"); - path = path.AppendASCII("vendor"); - path = path.AppendASCII("bat-native-ads"); - path = path.AppendASCII("data"); - return path; -} - -base::FilePath GetTestPath() { - base::FilePath path = GetDataPath(); - path = path.AppendASCII("test"); - return path; -} - -absl::optional ReadFileFromTestPathToString( - const std::string& name) { - base::FilePath path = GetTestPath(); - path = path.AppendASCII(name); - - std::string value; - if (!base::ReadFileToString(path, &value)) { - return absl::nullopt; - } - - ParseAndReplaceTagsForText(&value); - - return value; -} - -base::FilePath GetResourcesPath() { - base::FilePath path = GetDataPath(); - path = path.AppendASCII("resources"); - return path; -} - -absl::optional ReadFileFromResourcePathToString( - const std::string& name) { - base::FilePath path = GetResourcesPath(); - path = path.AppendASCII(name); - - std::string value; - if (!base::ReadFileToString(path, &value)) { - return absl::nullopt; - } - - return value; -} - void SetEnvironment(const mojom::Environment environment) { g_environment = environment; } @@ -758,54 +580,4 @@ void MockPrefs(const std::unique_ptr& mock) { MockDefaultPrefs(mock); } -int64_t TimestampFromDateString(const std::string& date) { - return TimeFromDateString(date).ToDoubleT(); -} - -base::Time TimeFromDateString(const std::string& date) { - base::Time time; - if (!base::Time::FromUTCString(date.c_str(), &time)) { - return time; - } - - return time.UTCMidnight() + base::TimeDelta::FromDays(1) - - base::TimeDelta::FromMilliseconds(1); -} - -int64_t DistantPastAsTimestamp() { - return 0; // Thursday, 1 January 1970 00:00:00 -} - -base::Time DistantPast() { - return base::Time::FromDoubleT(DistantPastAsTimestamp()); -} - -std::string DistantPastAsISO8601() { - return base::TimeToISO8601(DistantPast()); -} - -int64_t NowAsTimestamp() { - return static_cast(Now().ToDoubleT()); -} - -base::Time Now() { - return base::Time::Now(); -} - -std::string NowAsISO8601() { - return base::TimeToISO8601(Now()); -} - -int64_t DistantFutureAsTimestamp() { - return 4102444799; // Thursday, 31 December 2099 23:59:59 -} - -base::Time DistantFuture() { - return base::Time::FromDoubleT(DistantFutureAsTimestamp()); -} - -std::string DistantFutureAsISO8601() { - return base::TimeToISO8601(DistantFuture()); -} - } // namespace ads diff --git a/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.h b/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.h index 22f5a78fa60d..1f6cbcb8c770 100644 --- a/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.h +++ b/vendor/bat-native-ads/src/bat/ads/internal/unittest_util.h @@ -13,12 +13,9 @@ #include #include -#include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" -#include "bat/ads/database.h" #include "bat/ads/internal/platform/platform_helper_mock.h" #include "bat/ads/public/interfaces/ads.mojom.h" -#include "brave/components/l10n/browser/locale_helper_mock.h" #include "testing/gtest/include/gtest/gtest.h" namespace absl { @@ -30,6 +27,10 @@ namespace base { class Time; } // namespace base +namespace brave_l10n { +class LocaleHelperMock; +} // namespace brave_l10n + namespace ads { // A list of endpoints where the response can be inline, i.e. @@ -83,16 +84,7 @@ using URLEndpointResponses = std::vector; using URLEndpoints = std::map; class AdsClientMock; - -base::FilePath GetTestPath(); - -absl::optional ReadFileFromTestPathToString( - const std::string& name); - -base::FilePath GetResourcesPath(); - -absl::optional ReadFileFromResourcePathToString( - const std::string& name); +class Database; void SetEnvironment(const mojom::Environment environment); @@ -143,21 +135,6 @@ void MockRunDBTransaction(const std::unique_ptr& mock, void MockPrefs(const std::unique_ptr& mock); -int64_t TimestampFromDateString(const std::string& date); -base::Time TimeFromDateString(const std::string& date); - -int64_t DistantPastAsTimestamp(); -base::Time DistantPast(); -std::string DistantPastAsISO8601(); - -int64_t NowAsTimestamp(); -base::Time Now(); -std::string NowAsISO8601(); - -int64_t DistantFutureAsTimestamp(); -base::Time DistantFuture(); -std::string DistantFutureAsISO8601(); - } // namespace ads #endif // BRAVE_VENDOR_BAT_NATIVE_ADS_SRC_BAT_ADS_INTERNAL_UNITTEST_UTIL_H_