prediction_service_unittest.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/permissions/prediction_service/prediction_service.h"
  5. #include <memory>
  6. #include <vector>
  7. #include "base/bind.h"
  8. #include "base/command_line.h"
  9. #include "base/run_loop.h"
  10. #include "base/test/scoped_feature_list.h"
  11. #include "base/test/task_environment.h"
  12. #include "base/threading/thread_task_runner_handle.h"
  13. #include "base/time/time.h"
  14. #include "components/permissions/features.h"
  15. #include "components/permissions/permission_request_enums.h"
  16. #include "components/permissions/prediction_service/prediction_common.h"
  17. #include "components/permissions/prediction_service/prediction_request_features.h"
  18. #include "components/permissions/prediction_service/prediction_service_messages.pb.h"
  19. #include "components/permissions/request_type.h"
  20. #include "google/protobuf/message_lite.h"
  21. #include "net/base/net_errors.h"
  22. #include "net/http/http_response_headers.h"
  23. #include "net/http/http_status_code.h"
  24. #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  25. #include "services/network/public/mojom/url_response_head.mojom.h"
  26. #include "services/network/test/test_url_loader_factory.h"
  27. #include "third_party/abseil-cpp/absl/types/optional.h"
  28. #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
  29. namespace {
  30. // Helper common requests and responses. All of these are for the NOTIFICATION
  31. // type.
  32. // A request that has all counts 0. With user gesture.
  33. const permissions::PredictionRequestFeatures kFeaturesAllCountsZero = {
  34. permissions::PermissionRequestGestureType::GESTURE,
  35. permissions::RequestType::kNotifications,
  36. {0, 0, 0, 0},
  37. {0, 0, 0, 0}};
  38. // A request that has all counts 5 expect for "grants" which are 6. Without user
  39. // gesture.
  40. const permissions::PredictionRequestFeatures kFeaturesCountsNeedingRounding = {
  41. permissions::PermissionRequestGestureType::NO_GESTURE,
  42. permissions::RequestType::kNotifications,
  43. {6, 5, 5, 5},
  44. {6, 5, 5, 5}};
  45. // A request that has all counts 50. With user gesture.
  46. const permissions::PredictionRequestFeatures kFeaturesEvenCountsOver100 = {
  47. permissions::PermissionRequestGestureType::GESTURE,
  48. permissions::RequestType::kNotifications,
  49. {50, 50, 50, 50},
  50. {50, 50, 50, 50}};
  51. // A request that has all counts 100. With user gesture.
  52. const permissions::PredictionRequestFeatures kFeaturesEvenCountsOver100Alt = {
  53. permissions::PermissionRequestGestureType::GESTURE,
  54. permissions::RequestType::kNotifications,
  55. {100, 100, 100, 100},
  56. {100, 100, 100, 100}};
  57. // A request that has generic counts 50, and notification counts 0. Without user
  58. // gesture.
  59. const permissions::PredictionRequestFeatures kFeaturesDifferentCounts = {
  60. permissions::PermissionRequestGestureType::NO_GESTURE,
  61. permissions::RequestType::kNotifications,
  62. {0, 0, 0, 0},
  63. {50, 50, 50, 50}};
  64. // A proto request that has all ratios and total counts 0. With user gesture.
  65. permissions::GeneratePredictionsRequest kRequestAllCountsZero;
  66. // A proto request that has all ratios 0.24 (~5/21) except for "grants" which
  67. // are 0.29 (~6/21). Without user gesture.
  68. permissions::GeneratePredictionsRequest kRequestRoundedCounts;
  69. // A proto request that has all ratios .25 and total count 100. With user
  70. // gesture.
  71. permissions::GeneratePredictionsRequest kRequestEqualCountsTotal20;
  72. // A proot request that has generic ratios .25 and total count 100 and
  73. // notifications ratios and counts 0. Without user gesture.
  74. permissions::GeneratePredictionsRequest kRequestDifferentCounts;
  75. // A response that has a likelihood of DiscretizedLikelihood::LIKELY.
  76. permissions::GeneratePredictionsResponse kResponseLikely;
  77. // A response that has a likelihood of DiscretizedLikelihood::UNLIKELY.
  78. permissions::GeneratePredictionsResponse kResponseUnlikely;
  79. void InitializeProtoHelperObjects() {
  80. kRequestAllCountsZero.mutable_client_features()
  81. ->mutable_client_stats()
  82. ->set_avg_deny_rate(0);
  83. kRequestAllCountsZero.mutable_client_features()
  84. ->mutable_client_stats()
  85. ->set_avg_dismiss_rate(0);
  86. kRequestAllCountsZero.mutable_client_features()
  87. ->mutable_client_stats()
  88. ->set_avg_grant_rate(0);
  89. kRequestAllCountsZero.mutable_client_features()
  90. ->mutable_client_stats()
  91. ->set_avg_ignore_rate(0);
  92. kRequestAllCountsZero.mutable_client_features()
  93. ->mutable_client_stats()
  94. ->set_prompts_count(0);
  95. kRequestAllCountsZero.mutable_client_features()->set_platform(
  96. permissions::GetCurrentPlatformProto());
  97. kRequestAllCountsZero.mutable_client_features()->set_platform_enum(
  98. permissions::GetCurrentPlatformEnumProto());
  99. kRequestAllCountsZero.mutable_client_features()->set_gesture(
  100. permissions::ClientFeatures_Gesture_GESTURE);
  101. kRequestAllCountsZero.mutable_client_features()->set_gesture_enum(
  102. permissions::ClientFeatures_GestureEnum_GESTURE_V2);
  103. kRequestAllCountsZero.mutable_permission_features()->Clear();
  104. auto* permission_feature =
  105. kRequestAllCountsZero.mutable_permission_features()->Add();
  106. permission_feature->mutable_permission_stats()->set_avg_deny_rate(0);
  107. permission_feature->mutable_permission_stats()->set_avg_dismiss_rate(0);
  108. permission_feature->mutable_permission_stats()->set_avg_grant_rate(0);
  109. permission_feature->mutable_permission_stats()->set_avg_ignore_rate(0);
  110. permission_feature->mutable_permission_stats()->set_prompts_count(0);
  111. permission_feature->mutable_notification_permission()->Clear();
  112. kRequestRoundedCounts.mutable_client_features()
  113. ->mutable_client_stats()
  114. ->set_avg_deny_rate(0.2);
  115. kRequestRoundedCounts.mutable_client_features()
  116. ->mutable_client_stats()
  117. ->set_avg_dismiss_rate(0.2);
  118. kRequestRoundedCounts.mutable_client_features()
  119. ->mutable_client_stats()
  120. ->set_avg_grant_rate(0.3);
  121. kRequestRoundedCounts.mutable_client_features()
  122. ->mutable_client_stats()
  123. ->set_avg_ignore_rate(0.2);
  124. kRequestRoundedCounts.mutable_client_features()
  125. ->mutable_client_stats()
  126. ->set_prompts_count(20);
  127. kRequestRoundedCounts.mutable_client_features()->set_platform(
  128. permissions::GetCurrentPlatformProto());
  129. kRequestRoundedCounts.mutable_client_features()->set_platform_enum(
  130. permissions::GetCurrentPlatformEnumProto());
  131. kRequestRoundedCounts.mutable_client_features()->set_gesture(
  132. permissions::ClientFeatures_Gesture_NO_GESTURE);
  133. kRequestRoundedCounts.mutable_client_features()->set_gesture_enum(
  134. permissions::ClientFeatures_GestureEnum_GESTURE_UNSPECIFIED_V2);
  135. kRequestRoundedCounts.mutable_permission_features()->Clear();
  136. permission_feature =
  137. kRequestRoundedCounts.mutable_permission_features()->Add();
  138. permission_feature->mutable_permission_stats()->set_avg_deny_rate(0.2);
  139. permission_feature->mutable_permission_stats()->set_avg_dismiss_rate(0.2);
  140. permission_feature->mutable_permission_stats()->set_avg_grant_rate(0.3);
  141. permission_feature->mutable_permission_stats()->set_avg_ignore_rate(0.2);
  142. permission_feature->mutable_permission_stats()->set_prompts_count(20);
  143. permission_feature->mutable_notification_permission()->Clear();
  144. kRequestEqualCountsTotal20.mutable_client_features()
  145. ->mutable_client_stats()
  146. ->set_avg_deny_rate(.3);
  147. kRequestEqualCountsTotal20.mutable_client_features()
  148. ->mutable_client_stats()
  149. ->set_avg_dismiss_rate(.3);
  150. kRequestEqualCountsTotal20.mutable_client_features()
  151. ->mutable_client_stats()
  152. ->set_avg_grant_rate(.3);
  153. kRequestEqualCountsTotal20.mutable_client_features()
  154. ->mutable_client_stats()
  155. ->set_avg_ignore_rate(.3);
  156. kRequestEqualCountsTotal20.mutable_client_features()
  157. ->mutable_client_stats()
  158. ->set_prompts_count(20);
  159. kRequestEqualCountsTotal20.mutable_client_features()->set_platform(
  160. permissions::GetCurrentPlatformProto());
  161. kRequestEqualCountsTotal20.mutable_client_features()->set_platform_enum(
  162. permissions::GetCurrentPlatformEnumProto());
  163. kRequestEqualCountsTotal20.mutable_client_features()->set_gesture(
  164. permissions::ClientFeatures_Gesture_GESTURE);
  165. kRequestEqualCountsTotal20.mutable_client_features()->set_gesture_enum(
  166. permissions::ClientFeatures_GestureEnum_GESTURE_V2);
  167. kRequestEqualCountsTotal20.mutable_permission_features()->Clear();
  168. permission_feature =
  169. kRequestEqualCountsTotal20.mutable_permission_features()->Add();
  170. permission_feature->mutable_permission_stats()->set_avg_deny_rate(.3);
  171. permission_feature->mutable_permission_stats()->set_avg_dismiss_rate(.3);
  172. permission_feature->mutable_permission_stats()->set_avg_grant_rate(.3);
  173. permission_feature->mutable_permission_stats()->set_avg_ignore_rate(.3);
  174. permission_feature->mutable_permission_stats()->set_prompts_count(20);
  175. permission_feature->mutable_notification_permission()->Clear();
  176. kRequestDifferentCounts.mutable_client_features()
  177. ->mutable_client_stats()
  178. ->set_avg_deny_rate(.3);
  179. kRequestDifferentCounts.mutable_client_features()
  180. ->mutable_client_stats()
  181. ->set_avg_dismiss_rate(.3);
  182. kRequestDifferentCounts.mutable_client_features()
  183. ->mutable_client_stats()
  184. ->set_avg_grant_rate(.3);
  185. kRequestDifferentCounts.mutable_client_features()
  186. ->mutable_client_stats()
  187. ->set_avg_ignore_rate(.3);
  188. kRequestDifferentCounts.mutable_client_features()
  189. ->mutable_client_stats()
  190. ->set_prompts_count(20);
  191. kRequestDifferentCounts.mutable_client_features()->set_platform(
  192. permissions::GetCurrentPlatformProto());
  193. kRequestDifferentCounts.mutable_client_features()->set_platform_enum(
  194. permissions::GetCurrentPlatformEnumProto());
  195. kRequestDifferentCounts.mutable_client_features()->set_gesture(
  196. permissions::ClientFeatures_Gesture_NO_GESTURE);
  197. kRequestDifferentCounts.mutable_client_features()->set_gesture_enum(
  198. permissions::ClientFeatures_GestureEnum_GESTURE_UNSPECIFIED_V2);
  199. kRequestDifferentCounts.mutable_permission_features()->Clear();
  200. permission_feature =
  201. kRequestDifferentCounts.mutable_permission_features()->Add();
  202. permission_feature->mutable_permission_stats()->set_avg_deny_rate(0);
  203. permission_feature->mutable_permission_stats()->set_avg_dismiss_rate(0);
  204. permission_feature->mutable_permission_stats()->set_avg_grant_rate(0);
  205. permission_feature->mutable_permission_stats()->set_avg_ignore_rate(0);
  206. permission_feature->mutable_permission_stats()->set_prompts_count(0);
  207. permission_feature->mutable_notification_permission()->Clear();
  208. kResponseLikely.mutable_prediction()->Clear();
  209. auto* prediction = kResponseLikely.mutable_prediction()->Add();
  210. prediction->mutable_grant_likelihood()->set_discretized_likelihood(
  211. permissions::
  212. PermissionPrediction_Likelihood_DiscretizedLikelihood_LIKELY);
  213. kResponseUnlikely.mutable_prediction()->Clear();
  214. prediction = kResponseUnlikely.mutable_prediction()->Add();
  215. prediction->mutable_grant_likelihood()->set_discretized_likelihood(
  216. permissions::
  217. PermissionPrediction_Likelihood_DiscretizedLikelihood_UNLIKELY);
  218. }
  219. } // namespace
  220. namespace permissions {
  221. class PredictionServiceTest : public testing::Test {
  222. public:
  223. PredictionServiceTest()
  224. : test_shared_loader_factory_(
  225. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  226. &test_url_loader_factory_)) {}
  227. ~PredictionServiceTest() override = default;
  228. void SetUp() override {
  229. prediction_service_ =
  230. std::make_unique<PredictionService>(test_shared_loader_factory_);
  231. InitializeProtoHelperObjects();
  232. }
  233. void Respond(const GURL& url,
  234. double delay_in_seconds = 0,
  235. int err_code = net::OK) {
  236. if (delay_in_seconds > 0) {
  237. // Post a task to rerun this after |delay_in_seconds| seconds
  238. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  239. FROM_HERE,
  240. base::BindOnce(&PredictionServiceTest::Respond,
  241. base::Unretained(this), url, 0, err_code),
  242. base::Seconds(delay_in_seconds));
  243. return;
  244. }
  245. auto head = network::mojom::URLResponseHead::New();
  246. head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
  247. head->headers->AddHeader("Content-Type", "application/octet-stream");
  248. test_url_loader_factory_.SimulateResponseForPendingRequest(
  249. url, network::URLLoaderCompletionStatus(err_code), std::move(head),
  250. GetResponseForUrl(url));
  251. }
  252. void StartLookup(const PredictionRequestFeatures& entity,
  253. base::RunLoop* request_loop,
  254. base::RunLoop* response_loop) {
  255. prediction_service_->StartLookup(
  256. entity,
  257. base::BindOnce(&PredictionServiceTest::RequestCallback,
  258. base::Unretained(this), request_loop),
  259. base::BindOnce(&PredictionServiceTest::ResponseCallback,
  260. base::Unretained(this), response_loop));
  261. }
  262. void RequestCallback(base::RunLoop* request_loop,
  263. std::unique_ptr<GeneratePredictionsRequest> request,
  264. std::string access_token) {
  265. received_requests_.emplace_back(std::move(request));
  266. if (request_loop)
  267. request_loop->Quit();
  268. // Access token should always be the empty string.
  269. EXPECT_EQ(std::string(), access_token);
  270. }
  271. void ResponseCallback(
  272. base::RunLoop* response_loop,
  273. bool lookup_successful,
  274. bool response_from_cache,
  275. const absl::optional<GeneratePredictionsResponse>& response) {
  276. received_responses_.emplace_back(response);
  277. if (response_loop)
  278. response_loop->Quit();
  279. // The response is never from the cache.
  280. EXPECT_FALSE(response_from_cache);
  281. }
  282. protected:
  283. std::vector<std::unique_ptr<GeneratePredictionsRequest>> received_requests_;
  284. std::vector<absl::optional<GeneratePredictionsResponse>> received_responses_;
  285. std::unique_ptr<PredictionService> prediction_service_;
  286. // Different paths to simulate different server behaviours.
  287. const GURL kUrl_Unlikely{"http://predictionsevice.com/unlikely"};
  288. const GURL kUrl_Likely{"http://predictionsevice.com/likely"};
  289. const GURL kUrl_Invalid{"http://predictionsevice.com/invalid"};
  290. private:
  291. std::string GetResponseForUrl(const GURL& url) {
  292. if (url == kUrl_Unlikely) {
  293. return kResponseUnlikely.SerializeAsString();
  294. } else if (url == kUrl_Likely) {
  295. return kResponseLikely.SerializeAsString();
  296. } else if (url == GURL(permissions::kDefaultPredictionServiceUrl)) {
  297. return kResponseLikely.SerializeAsString();
  298. } else if (url == kUrl_Invalid) {
  299. return "This is not a valid response";
  300. }
  301. return "";
  302. }
  303. base::test::SingleThreadTaskEnvironment task_environment_;
  304. network::TestURLLoaderFactory test_url_loader_factory_;
  305. scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
  306. };
  307. TEST_F(PredictionServiceTest, BuiltProtoRequestIsCorrect) {
  308. struct {
  309. PredictionRequestFeatures entity;
  310. GeneratePredictionsRequest expected_request;
  311. } kTests[] = {
  312. {kFeaturesAllCountsZero, kRequestAllCountsZero},
  313. {kFeaturesCountsNeedingRounding, kRequestRoundedCounts},
  314. {kFeaturesEvenCountsOver100, kRequestEqualCountsTotal20},
  315. {kFeaturesEvenCountsOver100Alt, kRequestEqualCountsTotal20},
  316. {kFeaturesDifferentCounts, kRequestDifferentCounts},
  317. };
  318. prediction_service_->set_prediction_service_url_for_testing(
  319. GURL(kUrl_Likely));
  320. for (const auto& kTest : kTests) {
  321. base::RunLoop run_loop;
  322. StartLookup(kTest.entity, &run_loop, nullptr /* response_loop */);
  323. run_loop.Run();
  324. EXPECT_EQ(1u, received_requests_.size());
  325. EXPECT_EQ(kTest.expected_request.SerializeAsString(),
  326. received_requests_[0]->SerializeAsString());
  327. received_requests_.clear();
  328. }
  329. }
  330. TEST_F(PredictionServiceTest, ResponsesAreCorrect) {
  331. struct {
  332. GURL url;
  333. absl::optional<GeneratePredictionsResponse> expected_response;
  334. double delay_in_seconds;
  335. int err_code;
  336. } kTests[] = {
  337. // Test different responses.
  338. {kUrl_Likely,
  339. absl::optional<GeneratePredictionsResponse>(kResponseLikely)},
  340. {kUrl_Unlikely,
  341. absl::optional<GeneratePredictionsResponse>(kResponseUnlikely)},
  342. // Test the response's timeout.
  343. {kUrl_Likely,
  344. absl::optional<GeneratePredictionsResponse>(kResponseLikely), 0.5},
  345. {kUrl_Likely, absl::nullopt, 2},
  346. // Test error code responses.
  347. {kUrl_Likely, absl::nullopt, 0, net::ERR_SSL_PROTOCOL_ERROR},
  348. {kUrl_Likely, absl::nullopt, 0, net::ERR_CONNECTION_FAILED},
  349. };
  350. for (const auto& kTest : kTests) {
  351. prediction_service_->set_prediction_service_url_for_testing(kTest.url);
  352. base::RunLoop response_loop;
  353. StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
  354. Respond(kTest.url, kTest.delay_in_seconds, kTest.err_code);
  355. response_loop.Run();
  356. EXPECT_EQ(1u, received_responses_.size());
  357. if (kTest.expected_response.has_value()) {
  358. EXPECT_TRUE(received_responses_[0]);
  359. EXPECT_EQ(kTest.expected_response->SerializeAsString(),
  360. received_responses_[0]->SerializeAsString());
  361. } else {
  362. EXPECT_FALSE(received_responses_[0]);
  363. }
  364. received_responses_.clear();
  365. }
  366. }
  367. // Test that the Web Prediction Service url can be overridden via feature params
  368. // and command line, and the fallback logic in case the provided url is not
  369. // valid.
  370. TEST_F(PredictionServiceTest, FeatureParamAndCommandLineCanOverrideDefaultUrl) {
  371. struct {
  372. absl::optional<std::string> command_line_switch_value;
  373. absl::optional<std::string> url_override_param_value;
  374. GURL expected_request_url;
  375. permissions::GeneratePredictionsResponse expected_response;
  376. } kTests[] = {
  377. // Test without any overrides.
  378. {absl::nullopt, absl::nullopt, GURL(kDefaultPredictionServiceUrl),
  379. kResponseLikely},
  380. // Test only the FeatureParam override.
  381. {absl::nullopt, kUrl_Unlikely.spec(), kUrl_Unlikely, kResponseUnlikely},
  382. {absl::nullopt, "this is not a url", GURL(kDefaultPredictionServiceUrl),
  383. kResponseLikely},
  384. {absl::nullopt, "", GURL(kDefaultPredictionServiceUrl), kResponseLikely},
  385. // Test only the command line override.
  386. {kUrl_Unlikely.spec(), absl::nullopt, kUrl_Unlikely, kResponseUnlikely},
  387. {"this is not a url", absl::nullopt, GURL(kDefaultPredictionServiceUrl),
  388. kResponseLikely},
  389. {"", absl::nullopt, GURL(kDefaultPredictionServiceUrl), kResponseLikely},
  390. // Command line takes precedence over FeatureParam, if valid.
  391. {kUrl_Likely.spec(), kUrl_Unlikely.spec(), kUrl_Likely, kResponseLikely},
  392. {"this is not a url", kUrl_Unlikely.spec(), kUrl_Unlikely,
  393. kResponseUnlikely},
  394. {"this is not a url", "this is not a url",
  395. GURL(kDefaultPredictionServiceUrl), kResponseLikely},
  396. };
  397. prediction_service_->recalculate_service_url_every_time_for_testing();
  398. for (const auto& kTest : kTests) {
  399. base::test::ScopedFeatureList scoped_feature_list;
  400. if (kTest.url_override_param_value.has_value()) {
  401. scoped_feature_list.InitAndEnableFeatureWithParameters(
  402. features::kPermissionPredictionServiceUseUrlOverride,
  403. {{feature_params::kPermissionPredictionServiceUrlOverride.name,
  404. kTest.url_override_param_value.value()}});
  405. }
  406. if (kTest.command_line_switch_value.has_value()) {
  407. base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
  408. kDefaultPredictionServiceUrlSwitchKey,
  409. kTest.command_line_switch_value.value());
  410. }
  411. base::RunLoop response_loop;
  412. StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
  413. Respond(kTest.expected_request_url);
  414. response_loop.Run();
  415. EXPECT_EQ(1u, received_responses_.size());
  416. EXPECT_TRUE(received_responses_[0]);
  417. EXPECT_EQ(kTest.expected_response.SerializeAsString(),
  418. received_responses_[0]->SerializeAsString());
  419. // Cleanup for next test.
  420. received_responses_.clear();
  421. base::CommandLine::ForCurrentProcess()->RemoveSwitch(
  422. kDefaultPredictionServiceUrlSwitchKey);
  423. }
  424. }
  425. TEST_F(PredictionServiceTest,
  426. FeatureEnabledWithNoFeatureParamFallsBackOnDefault) {
  427. prediction_service_->recalculate_service_url_every_time_for_testing();
  428. base::test::ScopedFeatureList scoped_feature_list;
  429. scoped_feature_list.InitAndEnableFeature(
  430. features::kPermissionPredictionServiceUseUrlOverride);
  431. base::RunLoop response_loop;
  432. StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
  433. Respond(GURL(kDefaultPredictionServiceUrl));
  434. response_loop.Run();
  435. EXPECT_EQ(1u, received_responses_.size());
  436. EXPECT_TRUE(received_responses_[0]);
  437. EXPECT_EQ(kResponseLikely.SerializeAsString(),
  438. received_responses_[0]->SerializeAsString());
  439. }
  440. TEST_F(PredictionServiceTest, HandleSimultaneousRequests) {
  441. prediction_service_->set_prediction_service_url_for_testing(kUrl_Likely);
  442. base::RunLoop response_loop;
  443. StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
  444. prediction_service_->set_prediction_service_url_for_testing(kUrl_Unlikely);
  445. base::RunLoop response_loop2;
  446. StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop2);
  447. EXPECT_EQ(2u, prediction_service_->pending_requests_for_testing().size());
  448. Respond(kUrl_Unlikely);
  449. response_loop2.Run();
  450. EXPECT_EQ(1u, received_responses_.size());
  451. EXPECT_TRUE(received_responses_[0]);
  452. EXPECT_EQ(kResponseUnlikely.SerializeAsString(),
  453. received_responses_[0]->SerializeAsString());
  454. EXPECT_EQ(1u, prediction_service_->pending_requests_for_testing().size());
  455. Respond(kUrl_Likely);
  456. response_loop.Run();
  457. EXPECT_EQ(2u, received_responses_.size());
  458. EXPECT_TRUE(received_responses_[1]);
  459. EXPECT_EQ(kResponseLikely.SerializeAsString(),
  460. received_responses_[1]->SerializeAsString());
  461. EXPECT_EQ(0u, prediction_service_->pending_requests_for_testing().size());
  462. }
  463. TEST_F(PredictionServiceTest, InvalidResponse) {
  464. base::RunLoop response_loop;
  465. StartLookup(kFeaturesAllCountsZero, nullptr, &response_loop);
  466. Respond(GURL(kUrl_Invalid));
  467. response_loop.Run();
  468. EXPECT_FALSE(received_responses_[0]);
  469. }
  470. TEST_F(PredictionServiceTest, PromptCountsAreBucketed) {
  471. struct {
  472. size_t prompt_count;
  473. int expected_bucket;
  474. } kTests[] = {{4, 4}, {5, 5}, {6, 6}, {7, 7}, {8, 8},
  475. {9, 9}, {10, 10}, {11, 10}, {12, 12}, {14, 12},
  476. {15, 15}, {19, 15}, {20, 20}, {100, 20}, {1000, 20}};
  477. prediction_service_->set_prediction_service_url_for_testing(
  478. GURL(kUrl_Likely));
  479. for (const auto& kTest : kTests) {
  480. permissions::PredictionRequestFeatures features = kFeaturesAllCountsZero;
  481. features.requested_permission_counts.denies = kTest.prompt_count;
  482. permissions::GeneratePredictionsRequest expected_request =
  483. kRequestAllCountsZero;
  484. expected_request.mutable_permission_features()
  485. ->at(0)
  486. .mutable_permission_stats()
  487. ->set_avg_deny_rate(1);
  488. expected_request.mutable_permission_features()
  489. ->at(0)
  490. .mutable_permission_stats()
  491. ->set_prompts_count(kTest.expected_bucket);
  492. base::RunLoop run_loop;
  493. StartLookup(features, &run_loop, nullptr /* response_loop */);
  494. run_loop.Run();
  495. EXPECT_EQ(1u, received_requests_.size());
  496. EXPECT_EQ(expected_request.SerializeAsString(),
  497. received_requests_[0]->SerializeAsString());
  498. received_requests_.clear();
  499. }
  500. }
  501. } // namespace permissions