prioritized_dispatcher_unittest.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. // Copyright (c) 2012 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 "net/base/prioritized_dispatcher.h"
  5. #include <ctype.h>
  6. #include <memory>
  7. #include <string>
  8. #include "base/check.h"
  9. #include "base/compiler_specific.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "base/test/gtest_util.h"
  12. #include "net/base/request_priority.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. namespace net {
  15. namespace {
  16. // We rely on the priority enum values being sequential having starting at 0,
  17. // and increasing for higher priorities.
  18. static_assert(MINIMUM_PRIORITY == 0u && MINIMUM_PRIORITY == THROTTLED &&
  19. THROTTLED < IDLE &&
  20. IDLE < LOWEST &&
  21. LOWEST < HIGHEST &&
  22. HIGHEST <= MAXIMUM_PRIORITY,
  23. "priority indexes incompatible");
  24. class PrioritizedDispatcherTest : public testing::Test {
  25. public:
  26. typedef PrioritizedDispatcher::Priority Priority;
  27. // A job that appends |tag| to |log| when started and '.' when finished.
  28. // This is intended to confirm the execution order of a sequence of jobs added
  29. // to the dispatcher. Note that finishing order of jobs does not matter.
  30. class TestJob : public PrioritizedDispatcher::Job {
  31. public:
  32. TestJob(PrioritizedDispatcher* dispatcher,
  33. char tag,
  34. Priority priority,
  35. std::string* log)
  36. : dispatcher_(dispatcher), tag_(tag), priority_(priority), log_(log) {}
  37. bool running() const {
  38. return running_;
  39. }
  40. const PrioritizedDispatcher::Handle handle() const {
  41. return handle_;
  42. }
  43. void Add(bool at_head) {
  44. CHECK(handle_.is_null());
  45. CHECK(!running_);
  46. size_t num_queued = dispatcher_->num_queued_jobs();
  47. size_t num_running = dispatcher_->num_running_jobs();
  48. if (!at_head) {
  49. handle_ = dispatcher_->Add(this, priority_);
  50. } else {
  51. handle_ = dispatcher_->AddAtHead(this, priority_);
  52. }
  53. if (handle_.is_null()) {
  54. EXPECT_EQ(num_queued, dispatcher_->num_queued_jobs());
  55. EXPECT_TRUE(running_);
  56. EXPECT_EQ(num_running + 1, dispatcher_->num_running_jobs());
  57. } else {
  58. EXPECT_FALSE(running_);
  59. EXPECT_EQ(priority_, handle_.priority());
  60. EXPECT_EQ(tag_, reinterpret_cast<TestJob*>(handle_.value())->tag_);
  61. EXPECT_EQ(num_running, dispatcher_->num_running_jobs());
  62. }
  63. }
  64. void ChangePriority(Priority priority) {
  65. CHECK(!handle_.is_null());
  66. CHECK(!running_);
  67. size_t num_queued = dispatcher_->num_queued_jobs();
  68. size_t num_running = dispatcher_->num_running_jobs();
  69. handle_ = dispatcher_->ChangePriority(handle_, priority);
  70. if (handle_.is_null()) {
  71. EXPECT_TRUE(running_);
  72. EXPECT_EQ(num_queued - 1, dispatcher_->num_queued_jobs());
  73. EXPECT_EQ(num_running + 1, dispatcher_->num_running_jobs());
  74. } else {
  75. EXPECT_FALSE(running_);
  76. EXPECT_EQ(priority, handle_.priority());
  77. EXPECT_EQ(tag_, reinterpret_cast<TestJob*>(handle_.value())->tag_);
  78. EXPECT_EQ(num_queued, dispatcher_->num_queued_jobs());
  79. EXPECT_EQ(num_running, dispatcher_->num_running_jobs());
  80. }
  81. }
  82. void Cancel() {
  83. CHECK(!handle_.is_null());
  84. CHECK(!running_);
  85. size_t num_queued = dispatcher_->num_queued_jobs();
  86. dispatcher_->Cancel(handle_);
  87. EXPECT_EQ(num_queued - 1, dispatcher_->num_queued_jobs());
  88. handle_ = PrioritizedDispatcher::Handle();
  89. }
  90. void Finish() {
  91. CHECK(running_);
  92. running_ = false;
  93. log_->append(1u, '.');
  94. dispatcher_->OnJobFinished();
  95. }
  96. // PrioritizedDispatcher::Job interface
  97. void Start() override {
  98. EXPECT_FALSE(running_);
  99. handle_ = PrioritizedDispatcher::Handle();
  100. running_ = true;
  101. log_->append(1u, tag_);
  102. }
  103. private:
  104. raw_ptr<PrioritizedDispatcher> dispatcher_;
  105. char tag_;
  106. Priority priority_;
  107. PrioritizedDispatcher::Handle handle_;
  108. bool running_ = false;
  109. raw_ptr<std::string> log_;
  110. };
  111. protected:
  112. void Prepare(const PrioritizedDispatcher::Limits& limits) {
  113. dispatcher_ = std::make_unique<PrioritizedDispatcher>(limits);
  114. }
  115. std::unique_ptr<TestJob> AddJob(char data, Priority priority) {
  116. auto job =
  117. std::make_unique<TestJob>(dispatcher_.get(), data, priority, &log_);
  118. job->Add(false);
  119. return job;
  120. }
  121. std::unique_ptr<TestJob> AddJobAtHead(char data, Priority priority) {
  122. auto job =
  123. std::make_unique<TestJob>(dispatcher_.get(), data, priority, &log_);
  124. job->Add(true);
  125. return job;
  126. }
  127. void Expect(const std::string& log) {
  128. EXPECT_EQ(0u, dispatcher_->num_queued_jobs());
  129. EXPECT_EQ(0u, dispatcher_->num_running_jobs());
  130. EXPECT_EQ(log, log_);
  131. log_.clear();
  132. }
  133. std::string log_;
  134. std::unique_ptr<PrioritizedDispatcher> dispatcher_;
  135. };
  136. TEST_F(PrioritizedDispatcherTest, GetLimits) {
  137. // Set non-trivial initial limits.
  138. PrioritizedDispatcher::Limits original_limits(NUM_PRIORITIES, 5);
  139. original_limits.reserved_slots[HIGHEST] = 1;
  140. original_limits.reserved_slots[LOW] = 2;
  141. Prepare(original_limits);
  142. // Get current limits, make sure the original limits are returned.
  143. PrioritizedDispatcher::Limits retrieved_limits = dispatcher_->GetLimits();
  144. ASSERT_EQ(original_limits.total_jobs, retrieved_limits.total_jobs);
  145. ASSERT_EQ(static_cast<size_t>(NUM_PRIORITIES),
  146. retrieved_limits.reserved_slots.size());
  147. for (size_t priority = MINIMUM_PRIORITY; priority <= MAXIMUM_PRIORITY;
  148. ++priority) {
  149. EXPECT_EQ(original_limits.reserved_slots[priority],
  150. retrieved_limits.reserved_slots[priority]);
  151. }
  152. // Set new limits.
  153. PrioritizedDispatcher::Limits new_limits(NUM_PRIORITIES, 6);
  154. new_limits.reserved_slots[MEDIUM] = 3;
  155. new_limits.reserved_slots[LOWEST] = 1;
  156. Prepare(new_limits);
  157. // Get current limits, make sure the new limits are returned.
  158. retrieved_limits = dispatcher_->GetLimits();
  159. ASSERT_EQ(new_limits.total_jobs, retrieved_limits.total_jobs);
  160. ASSERT_EQ(static_cast<size_t>(NUM_PRIORITIES),
  161. retrieved_limits.reserved_slots.size());
  162. for (size_t priority = MINIMUM_PRIORITY; priority <= MAXIMUM_PRIORITY;
  163. ++priority) {
  164. EXPECT_EQ(new_limits.reserved_slots[priority],
  165. retrieved_limits.reserved_slots[priority]);
  166. }
  167. }
  168. TEST_F(PrioritizedDispatcherTest, AddAFIFO) {
  169. // Allow only one running job.
  170. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
  171. Prepare(limits);
  172. std::unique_ptr<TestJob> job_a = AddJob('a', IDLE);
  173. std::unique_ptr<TestJob> job_b = AddJob('b', IDLE);
  174. std::unique_ptr<TestJob> job_c = AddJob('c', IDLE);
  175. std::unique_ptr<TestJob> job_d = AddJob('d', IDLE);
  176. ASSERT_TRUE(job_a->running());
  177. job_a->Finish();
  178. ASSERT_TRUE(job_b->running());
  179. job_b->Finish();
  180. ASSERT_TRUE(job_c->running());
  181. job_c->Finish();
  182. ASSERT_TRUE(job_d->running());
  183. job_d->Finish();
  184. Expect("a.b.c.d.");
  185. }
  186. TEST_F(PrioritizedDispatcherTest, AddPriority) {
  187. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
  188. Prepare(limits);
  189. std::unique_ptr<TestJob> job_a = AddJob('a', IDLE);
  190. std::unique_ptr<TestJob> job_b = AddJob('b', MEDIUM);
  191. std::unique_ptr<TestJob> job_c = AddJob('c', HIGHEST);
  192. std::unique_ptr<TestJob> job_d = AddJob('d', HIGHEST);
  193. std::unique_ptr<TestJob> job_e = AddJob('e', MEDIUM);
  194. ASSERT_TRUE(job_a->running());
  195. job_a->Finish();
  196. ASSERT_TRUE(job_c->running());
  197. job_c->Finish();
  198. ASSERT_TRUE(job_d->running());
  199. job_d->Finish();
  200. ASSERT_TRUE(job_b->running());
  201. job_b->Finish();
  202. ASSERT_TRUE(job_e->running());
  203. job_e->Finish();
  204. Expect("a.c.d.b.e.");
  205. }
  206. TEST_F(PrioritizedDispatcherTest, AddAtHead) {
  207. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
  208. Prepare(limits);
  209. std::unique_ptr<TestJob> job_a = AddJob('a', MEDIUM);
  210. std::unique_ptr<TestJob> job_b = AddJobAtHead('b', MEDIUM);
  211. std::unique_ptr<TestJob> job_c = AddJobAtHead('c', HIGHEST);
  212. std::unique_ptr<TestJob> job_d = AddJobAtHead('d', HIGHEST);
  213. std::unique_ptr<TestJob> job_e = AddJobAtHead('e', MEDIUM);
  214. std::unique_ptr<TestJob> job_f = AddJob('f', MEDIUM);
  215. ASSERT_TRUE(job_a->running());
  216. job_a->Finish();
  217. ASSERT_TRUE(job_d->running());
  218. job_d->Finish();
  219. ASSERT_TRUE(job_c->running());
  220. job_c->Finish();
  221. ASSERT_TRUE(job_e->running());
  222. job_e->Finish();
  223. ASSERT_TRUE(job_b->running());
  224. job_b->Finish();
  225. ASSERT_TRUE(job_f->running());
  226. job_f->Finish();
  227. Expect("a.d.c.e.b.f.");
  228. }
  229. TEST_F(PrioritizedDispatcherTest, EnforceLimits) {
  230. // Reserve 2 for HIGHEST and 1 for LOW or higher.
  231. // This leaves 2 for LOWEST or lower.
  232. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 5);
  233. limits.reserved_slots[HIGHEST] = 2;
  234. limits.reserved_slots[LOW] = 1;
  235. Prepare(limits);
  236. std::unique_ptr<TestJob> job_a = AddJob('a', IDLE); // Uses unreserved slot.
  237. std::unique_ptr<TestJob> job_b = AddJob('b', IDLE); // Uses unreserved slot.
  238. std::unique_ptr<TestJob> job_c = AddJob('c', LOWEST); // Must wait.
  239. std::unique_ptr<TestJob> job_d = AddJob('d', LOW); // Uses reserved slot.
  240. std::unique_ptr<TestJob> job_e = AddJob('e', MEDIUM); // Must wait.
  241. std::unique_ptr<TestJob> job_f = AddJob('f', HIGHEST); // Uses reserved slot.
  242. std::unique_ptr<TestJob> job_g = AddJob('g', HIGHEST); // Uses reserved slot.
  243. std::unique_ptr<TestJob> job_h = AddJob('h', HIGHEST); // Must wait.
  244. EXPECT_EQ(5u, dispatcher_->num_running_jobs());
  245. EXPECT_EQ(3u, dispatcher_->num_queued_jobs());
  246. ASSERT_TRUE(job_a->running());
  247. ASSERT_TRUE(job_b->running());
  248. ASSERT_TRUE(job_d->running());
  249. ASSERT_TRUE(job_f->running());
  250. ASSERT_TRUE(job_g->running());
  251. // a, b, d, f, g are running. Finish them in any order.
  252. job_b->Finish(); // Releases h.
  253. job_f->Finish();
  254. job_a->Finish();
  255. job_g->Finish(); // Releases e.
  256. job_d->Finish();
  257. ASSERT_TRUE(job_e->running());
  258. ASSERT_TRUE(job_h->running());
  259. // h, e are running.
  260. job_e->Finish(); // Releases c.
  261. ASSERT_TRUE(job_c->running());
  262. job_c->Finish();
  263. job_h->Finish();
  264. Expect("abdfg.h...e..c..");
  265. }
  266. TEST_F(PrioritizedDispatcherTest, ChangePriority) {
  267. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 2);
  268. // Reserve one slot only for HIGHEST priority requests.
  269. limits.reserved_slots[HIGHEST] = 1;
  270. Prepare(limits);
  271. std::unique_ptr<TestJob> job_a = AddJob('a', IDLE);
  272. std::unique_ptr<TestJob> job_b = AddJob('b', LOW);
  273. std::unique_ptr<TestJob> job_c = AddJob('c', MEDIUM);
  274. std::unique_ptr<TestJob> job_d = AddJob('d', MEDIUM);
  275. std::unique_ptr<TestJob> job_e = AddJob('e', IDLE);
  276. ASSERT_FALSE(job_b->running());
  277. ASSERT_FALSE(job_c->running());
  278. job_b->ChangePriority(MEDIUM);
  279. job_c->ChangePriority(LOW);
  280. ASSERT_TRUE(job_a->running());
  281. job_a->Finish();
  282. ASSERT_TRUE(job_d->running());
  283. job_d->Finish();
  284. EXPECT_FALSE(job_e->running());
  285. // Increasing |job_e|'s priority to HIGHEST should result in it being
  286. // started immediately.
  287. job_e->ChangePriority(HIGHEST);
  288. ASSERT_TRUE(job_e->running());
  289. job_e->Finish();
  290. ASSERT_TRUE(job_b->running());
  291. job_b->Finish();
  292. ASSERT_TRUE(job_c->running());
  293. job_c->Finish();
  294. Expect("a.d.be..c.");
  295. }
  296. TEST_F(PrioritizedDispatcherTest, Cancel) {
  297. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
  298. Prepare(limits);
  299. std::unique_ptr<TestJob> job_a = AddJob('a', IDLE);
  300. std::unique_ptr<TestJob> job_b = AddJob('b', IDLE);
  301. std::unique_ptr<TestJob> job_c = AddJob('c', IDLE);
  302. std::unique_ptr<TestJob> job_d = AddJob('d', IDLE);
  303. std::unique_ptr<TestJob> job_e = AddJob('e', IDLE);
  304. ASSERT_FALSE(job_b->running());
  305. ASSERT_FALSE(job_d->running());
  306. job_b->Cancel();
  307. job_d->Cancel();
  308. ASSERT_TRUE(job_a->running());
  309. job_a->Finish();
  310. ASSERT_TRUE(job_c->running());
  311. job_c->Finish();
  312. ASSERT_TRUE(job_e->running());
  313. job_e->Finish();
  314. Expect("a.c.e.");
  315. }
  316. TEST_F(PrioritizedDispatcherTest, Evict) {
  317. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
  318. Prepare(limits);
  319. std::unique_ptr<TestJob> job_a = AddJob('a', IDLE);
  320. std::unique_ptr<TestJob> job_b = AddJob('b', LOW);
  321. std::unique_ptr<TestJob> job_c = AddJob('c', HIGHEST);
  322. std::unique_ptr<TestJob> job_d = AddJob('d', LOW);
  323. std::unique_ptr<TestJob> job_e = AddJob('e', HIGHEST);
  324. EXPECT_EQ(job_b.get(), dispatcher_->EvictOldestLowest());
  325. EXPECT_EQ(job_d.get(), dispatcher_->EvictOldestLowest());
  326. ASSERT_TRUE(job_a->running());
  327. job_a->Finish();
  328. ASSERT_TRUE(job_c->running());
  329. job_c->Finish();
  330. ASSERT_TRUE(job_e->running());
  331. job_e->Finish();
  332. Expect("a.c.e.");
  333. }
  334. TEST_F(PrioritizedDispatcherTest, EvictFromEmpty) {
  335. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
  336. Prepare(limits);
  337. EXPECT_TRUE(dispatcher_->EvictOldestLowest() == nullptr);
  338. }
  339. TEST_F(PrioritizedDispatcherTest, AddWhileZeroLimits) {
  340. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 2);
  341. Prepare(limits);
  342. dispatcher_->SetLimitsToZero();
  343. std::unique_ptr<TestJob> job_a = AddJob('a', LOW);
  344. std::unique_ptr<TestJob> job_b = AddJob('b', MEDIUM);
  345. std::unique_ptr<TestJob> job_c = AddJobAtHead('c', MEDIUM);
  346. EXPECT_EQ(0u, dispatcher_->num_running_jobs());
  347. EXPECT_EQ(3u, dispatcher_->num_queued_jobs());
  348. dispatcher_->SetLimits(limits);
  349. EXPECT_EQ(2u, dispatcher_->num_running_jobs());
  350. EXPECT_EQ(1u, dispatcher_->num_queued_jobs());
  351. ASSERT_TRUE(job_b->running());
  352. job_b->Finish();
  353. ASSERT_TRUE(job_c->running());
  354. job_c->Finish();
  355. ASSERT_TRUE(job_a->running());
  356. job_a->Finish();
  357. Expect("cb.a..");
  358. }
  359. TEST_F(PrioritizedDispatcherTest, ReduceLimitsWhileJobQueued) {
  360. PrioritizedDispatcher::Limits initial_limits(NUM_PRIORITIES, 2);
  361. Prepare(initial_limits);
  362. std::unique_ptr<TestJob> job_a = AddJob('a', MEDIUM);
  363. std::unique_ptr<TestJob> job_b = AddJob('b', MEDIUM);
  364. std::unique_ptr<TestJob> job_c = AddJob('c', MEDIUM);
  365. std::unique_ptr<TestJob> job_d = AddJob('d', MEDIUM);
  366. std::unique_ptr<TestJob> job_e = AddJob('e', MEDIUM);
  367. EXPECT_EQ(2u, dispatcher_->num_running_jobs());
  368. EXPECT_EQ(3u, dispatcher_->num_queued_jobs());
  369. // Reduce limits to just allow one job at a time. Running jobs should not
  370. // be affected.
  371. dispatcher_->SetLimits(PrioritizedDispatcher::Limits(NUM_PRIORITIES, 1));
  372. EXPECT_EQ(2u, dispatcher_->num_running_jobs());
  373. EXPECT_EQ(3u, dispatcher_->num_queued_jobs());
  374. // Finishing a job should not result in another job starting.
  375. ASSERT_TRUE(job_a->running());
  376. job_a->Finish();
  377. EXPECT_EQ(1u, dispatcher_->num_running_jobs());
  378. EXPECT_EQ(3u, dispatcher_->num_queued_jobs());
  379. ASSERT_TRUE(job_b->running());
  380. job_b->Finish();
  381. EXPECT_EQ(1u, dispatcher_->num_running_jobs());
  382. EXPECT_EQ(2u, dispatcher_->num_queued_jobs());
  383. // Increasing the limits again should let c start.
  384. dispatcher_->SetLimits(initial_limits);
  385. ASSERT_TRUE(job_c->running());
  386. job_c->Finish();
  387. ASSERT_TRUE(job_d->running());
  388. job_d->Finish();
  389. ASSERT_TRUE(job_e->running());
  390. job_e->Finish();
  391. Expect("ab..cd.e..");
  392. }
  393. TEST_F(PrioritizedDispatcherTest, ZeroLimitsThenCancel) {
  394. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
  395. Prepare(limits);
  396. std::unique_ptr<TestJob> job_a = AddJob('a', IDLE);
  397. std::unique_ptr<TestJob> job_b = AddJob('b', IDLE);
  398. std::unique_ptr<TestJob> job_c = AddJob('c', IDLE);
  399. dispatcher_->SetLimitsToZero();
  400. ASSERT_TRUE(job_a->running());
  401. EXPECT_FALSE(job_b->running());
  402. EXPECT_FALSE(job_c->running());
  403. job_a->Finish();
  404. EXPECT_FALSE(job_b->running());
  405. EXPECT_FALSE(job_c->running());
  406. // Cancelling b shouldn't start job c.
  407. job_b->Cancel();
  408. EXPECT_FALSE(job_c->running());
  409. // Restoring the limits should start c.
  410. dispatcher_->SetLimits(limits);
  411. ASSERT_TRUE(job_c->running());
  412. job_c->Finish();
  413. Expect("a.c.");
  414. }
  415. TEST_F(PrioritizedDispatcherTest, ZeroLimitsThenIncreasePriority) {
  416. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 2);
  417. limits.reserved_slots[HIGHEST] = 1;
  418. Prepare(limits);
  419. std::unique_ptr<TestJob> job_a = AddJob('a', IDLE);
  420. std::unique_ptr<TestJob> job_b = AddJob('b', IDLE);
  421. EXPECT_TRUE(job_a->running());
  422. EXPECT_FALSE(job_b->running());
  423. dispatcher_->SetLimitsToZero();
  424. job_b->ChangePriority(HIGHEST);
  425. EXPECT_FALSE(job_b->running());
  426. job_a->Finish();
  427. EXPECT_FALSE(job_b->running());
  428. job_b->Cancel();
  429. Expect("a.");
  430. }
  431. #if GTEST_HAS_DEATH_TEST
  432. TEST_F(PrioritizedDispatcherTest, CancelNull) {
  433. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
  434. Prepare(limits);
  435. EXPECT_DCHECK_DEATH(dispatcher_->Cancel(PrioritizedDispatcher::Handle()));
  436. }
  437. TEST_F(PrioritizedDispatcherTest, CancelMissing) {
  438. PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
  439. Prepare(limits);
  440. AddJob('a', IDLE);
  441. std::unique_ptr<TestJob> job_b = AddJob('b', IDLE);
  442. PrioritizedDispatcher::Handle handle = job_b->handle();
  443. ASSERT_FALSE(handle.is_null());
  444. dispatcher_->Cancel(handle);
  445. EXPECT_DCHECK_DEATH(dispatcher_->Cancel(handle));
  446. }
  447. #endif // GTEST_HAS_DEATH_TEST
  448. } // namespace
  449. } // namespace net