printer_config_cache_unittest.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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 "chromeos/printing/printer_config_cache.h"
  5. #include <vector>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "base/location.h"
  9. #include "base/run_loop.h"
  10. #include "base/test/bind.h"
  11. #include "base/test/simple_test_clock.h"
  12. #include "base/test/task_environment.h"
  13. #include "base/threading/sequenced_task_runner_handle.h"
  14. #include "base/time/clock.h"
  15. #include "base/time/time.h"
  16. #include "net/http/http_status_code.h"
  17. #include "services/network/test/test_url_loader_factory.h"
  18. #include "testing/gmock/include/gmock/gmock-matchers.h"
  19. #include "testing/gmock/include/gmock/gmock.h"
  20. #include "testing/gtest/include/gtest/gtest.h"
  21. // Maintainer's notes:
  22. //
  23. // 1. The use of base::Unretained throughout this suite is appropriate
  24. // because the sequences of each test live as long as the test does.
  25. // Real consumers probably can't do this.
  26. // 2. The passage of time is controlled by a mock clock, so most Fetch()
  27. // invocations not preceded by clock advancement never hit the
  28. // "networked fetch" codepath. In such tests, the values of the
  29. // TimeDelta argument are arbitrary and meaningless.
  30. namespace chromeos {
  31. namespace {
  32. // Defines some resources (URLs and contents) used throughout this
  33. // test suite.
  34. // Name of the "known-good" resource.
  35. const char kKnownGoodResourceURL[] =
  36. "https://printerconfigurations.googleusercontent.com/chromeos_printing/"
  37. "known-good";
  38. // Arbitrary content for the "known-good" resource.
  39. const char kKnownGoodResourceContent[] = "yakisaba";
  40. // Name of the "known-bad" resource.
  41. const char kKnownBadResourceURL[] =
  42. "https://printerconfigurations.googleusercontent.com/chromeos_printing/"
  43. "known-bad";
  44. // Defines an arbitrary time increment by which we advance the Clock.
  45. constexpr base::TimeDelta kTestingIncrement = base::Seconds(1LL);
  46. // Defines a time of fetch used to construct FetchResult instances that
  47. // you'll use with the TimeInsensitiveFetchResultEquals matcher.
  48. constexpr base::Time kUnusedTimeOfFetch;
  49. MATCHER_P(TimeInsensitiveFetchResultEquals, expected, "") {
  50. return arg.succeeded == expected.succeeded && arg.key == expected.key &&
  51. arg.contents == expected.contents;
  52. }
  53. MATCHER_P(FetchResultEquals, expected, "") {
  54. return arg.succeeded == expected.succeeded && arg.key == expected.key &&
  55. arg.contents == expected.contents &&
  56. arg.time_of_fetch == expected.time_of_fetch;
  57. }
  58. class PrinterConfigCacheTest : public ::testing::Test {
  59. public:
  60. // Creates |this| with
  61. // * a testing task environment for testing sequenced code,
  62. // * a testing clock for time-aware testing, and
  63. // * a loader factory dispenser (specified by header comment on
  64. // Create()).
  65. PrinterConfigCacheTest()
  66. : task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
  67. cache_(PrinterConfigCache::Create(
  68. &clock_,
  69. base::BindLambdaForTesting([&]() {
  70. return reinterpret_cast<network::mojom::URLLoaderFactory*>(
  71. &loader_factory_);
  72. }))) {}
  73. // Sets up the default responses to dispense.
  74. void SetUp() override {
  75. // Dispenses the "known-good" resource with its content.
  76. loader_factory_.AddResponse(kKnownGoodResourceURL,
  77. kKnownGoodResourceContent);
  78. // Dispenses the "known-bad" resource with no content and an
  79. // arbitrary HTTP error.
  80. loader_factory_.AddResponse(kKnownBadResourceURL, "",
  81. net::HTTP_NOT_ACCEPTABLE);
  82. }
  83. // Method passed as a FetchCallback (partially bound) to
  84. // cache_.Fetch(). Saves the |result| in the |fetched_results_|.
  85. // Invokes the |quit_closure| to signal the enclosing RunLoop that
  86. // this method has been called.
  87. void CaptureFetchResult(base::RepeatingClosure quit_closure,
  88. const PrinterConfigCache::FetchResult& result) {
  89. fetched_results_.push_back(result);
  90. // The caller may elect to pass a default-constructed
  91. // RepeatingClosure, indicating that they don't want anything run.
  92. if (quit_closure) {
  93. quit_closure.Run();
  94. }
  95. }
  96. void AdvanceClock(base::TimeDelta amount = kTestingIncrement) {
  97. clock_.Advance(amount);
  98. }
  99. protected:
  100. // Landing area used to collect Fetch()ed results.
  101. std::vector<PrinterConfigCache::FetchResult> fetched_results_;
  102. // Loader factory for testing loaned to |cache_|.
  103. network::TestURLLoaderFactory loader_factory_;
  104. // Environment for task schedulers.
  105. base::test::TaskEnvironment task_environment_;
  106. // Controlled clock that dispenses times of Fetch().
  107. base::SimpleTestClock clock_;
  108. // Class under test.
  109. std::unique_ptr<PrinterConfigCache> cache_;
  110. };
  111. // Tests that we can succeed in Fetch()ing anything at all.
  112. TEST_F(PrinterConfigCacheTest, SucceedAtSingleFetch) {
  113. base::RunLoop run_loop;
  114. // Fetches the "known-good" resource.
  115. base::SequencedTaskRunnerHandle::Get()->PostTask(
  116. FROM_HERE,
  117. base::BindOnce(
  118. &PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  119. "known-good", base::Seconds(0LL),
  120. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  121. base::Unretained(this), run_loop.QuitClosure())));
  122. run_loop.Run();
  123. ASSERT_EQ(fetched_results_.size(), 1ULL);
  124. EXPECT_THAT(
  125. fetched_results_.front(),
  126. TimeInsensitiveFetchResultEquals(PrinterConfigCache::FetchResult::Success(
  127. "known-good", "yakisaba", kUnusedTimeOfFetch)));
  128. }
  129. // Tests that we fail to Fetch() the "known-bad" resource.
  130. TEST_F(PrinterConfigCacheTest, FailAtSingleFetch) {
  131. base::RunLoop run_loop;
  132. // Fetches the "known-bad" resource.
  133. base::SequencedTaskRunnerHandle::Get()->PostTask(
  134. FROM_HERE,
  135. base::BindOnce(
  136. &PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  137. "known-bad", base::Seconds(0LL),
  138. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  139. base::Unretained(this), run_loop.QuitClosure())));
  140. run_loop.Run();
  141. ASSERT_EQ(fetched_results_.size(), 1ULL);
  142. EXPECT_THAT(fetched_results_.front(),
  143. TimeInsensitiveFetchResultEquals(
  144. PrinterConfigCache::FetchResult::Failure("known-bad")));
  145. }
  146. // Tests that we can force a networked Fetch() by demanding
  147. // fresh content.
  148. TEST_F(PrinterConfigCacheTest, RefreshSubsequentFetch) {
  149. // Fetches the "known-good" resource with its stock contents.
  150. base::RunLoop first_run_loop;
  151. base::SequencedTaskRunnerHandle::Get()->PostTask(
  152. FROM_HERE,
  153. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  154. "known-good", base::Seconds(0LL),
  155. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  156. base::Unretained(this),
  157. first_run_loop.QuitClosure())));
  158. first_run_loop.Run();
  159. ASSERT_EQ(fetched_results_.size(), 1ULL);
  160. // To detect a networked fetch, we'll change the served content
  161. // and check that the subsequent Fetch() recovers the new content.
  162. loader_factory_.AddResponse(kKnownGoodResourceURL, "one Argentinian peso");
  163. // We've mutated the content; now, this fetches the "known-good"
  164. // resource with its new contents.
  165. base::RunLoop second_run_loop;
  166. base::SequencedTaskRunnerHandle::Get()->PostTask(
  167. FROM_HERE,
  168. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  169. "known-good", base::Seconds(0LL),
  170. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  171. base::Unretained(this),
  172. second_run_loop.QuitClosure())));
  173. second_run_loop.Run();
  174. ASSERT_EQ(fetched_results_.size(), 2ULL);
  175. EXPECT_THAT(
  176. fetched_results_,
  177. testing::ElementsAre(
  178. TimeInsensitiveFetchResultEquals(
  179. PrinterConfigCache::FetchResult::Success("known-good", "yakisaba",
  180. kUnusedTimeOfFetch)),
  181. TimeInsensitiveFetchResultEquals(
  182. PrinterConfigCache::FetchResult::Success(
  183. "known-good", "one Argentinian peso", kUnusedTimeOfFetch))));
  184. }
  185. // Tests that we can Fetch() locally cached contents by specifying a
  186. // wide age limit.
  187. TEST_F(PrinterConfigCacheTest, LocallyPerformSubsequentFetch) {
  188. // Fetches the "known-good" resource with its stock contents.
  189. base::RunLoop first_run_loop;
  190. base::SequencedTaskRunnerHandle::Get()->PostTask(
  191. FROM_HERE,
  192. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  193. "known-good", base::Seconds(0LL),
  194. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  195. base::Unretained(this),
  196. first_run_loop.QuitClosure())));
  197. first_run_loop.Run();
  198. ASSERT_EQ(fetched_results_.size(), 1ULL);
  199. // As in the RefreshSubsequentFetch test, we'll change the served
  200. // content to detect networked fetch requests made.
  201. loader_factory_.AddResponse(kKnownGoodResourceURL, "apologize darn you");
  202. // The "live" content in the serving root has changed; now, we perform
  203. // some local fetches without hitting the network. These Fetch()es
  204. // will return the stock content.
  205. base::RunLoop second_run_loop;
  206. base::SequencedTaskRunnerHandle::Get()->PostTask(
  207. FROM_HERE,
  208. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  209. "known-good",
  210. // Avoids hitting the network by using a long
  211. // timeout. Bear in mind that this test controls
  212. // the passage of time, so nonzero timeout is
  213. // "long" here...
  214. base::Seconds(1LL),
  215. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  216. base::Unretained(this),
  217. // Avoids quitting this RunLoop.
  218. base::RepeatingClosure())));
  219. // Performs a local Fetch() a few more times for no particular reason.
  220. base::SequencedTaskRunnerHandle::Get()->PostTask(
  221. FROM_HERE,
  222. base::BindOnce(
  223. &PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  224. "known-good", base::Seconds(3600LL),
  225. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  226. base::Unretained(this), base::RepeatingClosure())));
  227. base::SequencedTaskRunnerHandle::Get()->PostTask(
  228. FROM_HERE,
  229. base::BindOnce(
  230. &PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  231. "known-good", base::Seconds(86400LL),
  232. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  233. base::Unretained(this), base::RepeatingClosure())));
  234. // Performs a live Fetch(), returning the live (mutated) contents.
  235. base::SequencedTaskRunnerHandle::Get()->PostTask(
  236. FROM_HERE,
  237. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  238. "known-good",
  239. // Forces the networked fetch.
  240. base::Seconds(0LL),
  241. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  242. base::Unretained(this),
  243. // Ends our RunLoop.
  244. second_run_loop.QuitClosure())));
  245. second_run_loop.Run();
  246. ASSERT_EQ(fetched_results_.size(), 5ULL);
  247. EXPECT_THAT(
  248. fetched_results_,
  249. testing::ElementsAre(
  250. TimeInsensitiveFetchResultEquals(
  251. PrinterConfigCache::FetchResult::Success("known-good", "yakisaba",
  252. kUnusedTimeOfFetch)),
  253. TimeInsensitiveFetchResultEquals(
  254. PrinterConfigCache::FetchResult::Success("known-good", "yakisaba",
  255. kUnusedTimeOfFetch)),
  256. TimeInsensitiveFetchResultEquals(
  257. PrinterConfigCache::FetchResult::Success("known-good", "yakisaba",
  258. kUnusedTimeOfFetch)),
  259. TimeInsensitiveFetchResultEquals(
  260. PrinterConfigCache::FetchResult::Success("known-good", "yakisaba",
  261. kUnusedTimeOfFetch)),
  262. TimeInsensitiveFetchResultEquals(
  263. PrinterConfigCache::FetchResult::Success(
  264. "known-good", "apologize darn you", kUnusedTimeOfFetch))));
  265. }
  266. // Tests that Fetch() respects its |expiration| argument. This is a
  267. // purely time-bound variation on the LocallyPerformSubsequentFetch
  268. // test; the served content doesn't change between RunLoops.
  269. TEST_F(PrinterConfigCacheTest, FetchExpirationIsRespected) {
  270. // This Fetch() is given a useful |expiration|, but it won't matter
  271. // here since there are no locally resident cache entries at this
  272. // time; it'll have to be a networked fetch.
  273. base::RunLoop first_run_loop;
  274. base::SequencedTaskRunnerHandle::Get()->PostTask(
  275. FROM_HERE,
  276. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  277. "known-good", base::Seconds(32LL),
  278. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  279. base::Unretained(this),
  280. first_run_loop.QuitClosure())));
  281. first_run_loop.Run();
  282. ASSERT_EQ(fetched_results_.size(), 1ULL);
  283. const base::Time time_zero = clock_.Now();
  284. // Advance clock to T+31.
  285. AdvanceClock(base::Seconds(31LL));
  286. // This Fetch() is given the same useful |expiration|; it only matters
  287. // in that the clock does not yet indicate that the locally resident
  288. // cache entry has expired.
  289. base::RunLoop second_run_loop;
  290. base::SequencedTaskRunnerHandle::Get()->PostTask(
  291. FROM_HERE,
  292. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  293. "known-good", base::Seconds(32LL),
  294. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  295. base::Unretained(this),
  296. second_run_loop.QuitClosure())));
  297. second_run_loop.Run();
  298. ASSERT_EQ(fetched_results_.size(), 2ULL);
  299. // We don't capture the time right Now() because the above Fetch()
  300. // should have replied with local contents, fetched at time_zero.
  301. // Advance clock to T+32.
  302. AdvanceClock(base::Seconds(1));
  303. // This third Fetch() will be given the same |expiration| as ever.
  304. // The two previous calls to AdvanceClock() will have moved the time
  305. // beyond the staleness threshold, though, so this Fetch() will be
  306. // networked.
  307. base::RunLoop third_run_loop;
  308. base::SequencedTaskRunnerHandle::Get()->PostTask(
  309. FROM_HERE,
  310. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  311. "known-good",
  312. // Entry fetched at T+0 is now stale at T+32.
  313. base::Seconds(32LL),
  314. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  315. base::Unretained(this),
  316. third_run_loop.QuitClosure())));
  317. third_run_loop.Run();
  318. ASSERT_EQ(fetched_results_.size(), 3ULL);
  319. const base::Time time_of_third_fetch = clock_.Now();
  320. EXPECT_THAT(fetched_results_,
  321. testing::ElementsAre(
  322. FetchResultEquals(PrinterConfigCache::FetchResult::Success(
  323. "known-good", "yakisaba", time_zero)),
  324. FetchResultEquals(PrinterConfigCache::FetchResult::Success(
  325. "known-good", "yakisaba", time_zero)),
  326. FetchResultEquals(PrinterConfigCache::FetchResult::Success(
  327. "known-good", "yakisaba", time_of_third_fetch))));
  328. }
  329. // Tests that we can Drop() locally cached contents.
  330. TEST_F(PrinterConfigCacheTest, DropLocalContents) {
  331. base::RunLoop first_run_loop;
  332. // Fetches the "known-good" resource with its stock contents.
  333. base::SequencedTaskRunnerHandle::Get()->PostTask(
  334. FROM_HERE,
  335. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  336. "known-good", base::Seconds(604800LL),
  337. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  338. base::Unretained(this),
  339. first_run_loop.QuitClosure())));
  340. first_run_loop.Run();
  341. // Drops that which we just fetched. This isn't immediately externally
  342. // visible, but its effects will soon be made apparent.
  343. base::SequencedTaskRunnerHandle::Get()->PostTask(
  344. FROM_HERE, base::BindOnce(&PrinterConfigCache::Drop,
  345. base::Unretained(cache_.get()), "known-good"));
  346. // Mutates the contents served for the "known-good" resource.
  347. loader_factory_.AddResponse(kKnownGoodResourceURL, "ultimate dogeza");
  348. // Fetches the "known-good" resource anew with a wide timeout.
  349. // This is where the side effect of the prior Drop() call manifests:
  350. // the "known-good" resource is no longer cached, so not even a wide
  351. // timeout will spare us a networked fetch.
  352. base::RunLoop second_run_loop;
  353. base::SequencedTaskRunnerHandle::Get()->PostTask(
  354. FROM_HERE,
  355. base::BindOnce(&PrinterConfigCache::Fetch, base::Unretained(cache_.get()),
  356. "known-good", base::Seconds(18748800LL),
  357. base::BindOnce(&PrinterConfigCacheTest::CaptureFetchResult,
  358. base::Unretained(this),
  359. second_run_loop.QuitClosure())));
  360. second_run_loop.Run();
  361. // We detect the networked fetch to by observing mutated
  362. // contents.
  363. ASSERT_EQ(fetched_results_.size(), 2ULL);
  364. EXPECT_THAT(
  365. fetched_results_,
  366. testing::ElementsAre(
  367. TimeInsensitiveFetchResultEquals(
  368. PrinterConfigCache::FetchResult::Success("known-good", "yakisaba",
  369. kUnusedTimeOfFetch)),
  370. TimeInsensitiveFetchResultEquals(
  371. PrinterConfigCache::FetchResult::Success(
  372. "known-good", "ultimate dogeza", kUnusedTimeOfFetch))));
  373. }
  374. } // namespace
  375. } // namespace chromeos