| OLD | NEW | 
|    1 // Copyright 2016 The Chromium Authors. All rights reserved. |    1 // Copyright 2016 The Chromium Authors. All rights reserved. | 
|    2 // Use of this source code is governed by a BSD-style license that can be |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include <utility> |    5 #include <utility> | 
|    6  |    6  | 
|    7 #include "base/bind.h" |    7 #include "base/bind.h" | 
|    8 #include "base/files/file_util.h" |    8 #include "base/files/file_util.h" | 
|    9 #include "base/files/scoped_temp_dir.h" |    9 #include "base/files/scoped_temp_dir.h" | 
|   10 #include "base/hash.h" |   10 #include "base/hash.h" | 
|   11 #include "base/logging.h" |   11 #include "base/logging.h" | 
|   12 #include "base/memory/ptr_util.h" |   12 #include "base/memory/ptr_util.h" | 
|   13 #include "base/message_loop/message_loop.h" |   13 #include "base/message_loop/message_loop.h" | 
|   14 #include "base/run_loop.h" |   14 #include "base/run_loop.h" | 
|   15 #include "base/single_thread_task_runner.h" |   15 #include "base/single_thread_task_runner.h" | 
|   16 #include "base/threading/thread_task_runner_handle.h" |   16 #include "base/threading/thread_task_runner_handle.h" | 
|   17 #include "chromeos/printing/ppd_cache.h" |   17 #include "chromeos/printing/ppd_cache.h" | 
|   18 #include "net/url_request/test_url_request_interceptor.h" |   18 #include "net/url_request/test_url_request_interceptor.h" | 
|   19 #include "net/url_request/url_request_test_util.h" |   19 #include "net/url_request/url_request_test_util.h" | 
|   20 #include "testing/gtest/include/gtest/gtest.h" |   20 #include "testing/gtest/include/gtest/gtest.h" | 
|   21  |   21  | 
|   22 namespace chromeos { |   22 namespace chromeos { | 
|   23 namespace printing { |   23 namespace printing { | 
|   24 namespace { |   24 namespace { | 
|   25  |   25  | 
|   26 const char kTestManufacturer[] = "FooPrinters, Inc."; |  | 
|   27 const char kTestModel[] = "Laser BarMatic 1000"; |  | 
|   28 const char kTestUserUrl[] = "/some/path/to/some/ppd/file"; |  | 
|   29 const char kTestPpdContents[] = "This is the ppd for the first printer"; |  | 
|   30 // Output of 'gzip -9' on a file with contents 'ppd contents' |  | 
|   31 const char kTestGZippedPpdContents[] = { |  | 
|   32     0x1f, 0x8b, 0x08, 0x08, 0xe4, 0x2e, 0x00, 0x58, 0x02, 0x03, 0x70, |  | 
|   33     0x70, 0x64, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x2b, 0x28, 0x48, 0x51, |  | 
|   34     0x48, 0xce, 0xcf, 0x2b, 0x49, 0xcd, 0x2b, 0x29, 0xe6, 0x02, 0x00, |  | 
|   35     0x2b, 0x51, 0x91, 0x24, 0x0d, 0x00, 0x00, 0x00}; |  | 
|   36  |  | 
|   37 // Generate and return a PPDReference that has the fields set from the kTest |  | 
|   38 // constants above. |  | 
|   39 Printer::PpdReference TestReference() { |  | 
|   40   Printer::PpdReference ret; |  | 
|   41   ret.effective_manufacturer = kTestManufacturer; |  | 
|   42   ret.effective_model = kTestModel; |  | 
|   43   ret.user_supplied_ppd_url = kTestUserUrl; |  | 
|   44   return ret; |  | 
|   45 } |  | 
|   46  |  | 
|   47 // This fixture just points the cache at a temporary directory for the life of |   26 // This fixture just points the cache at a temporary directory for the life of | 
|   48 // the test. |   27 // the test. | 
|   49 class PpdCacheTest : public ::testing::Test { |   28 class PpdCacheTest : public ::testing::Test { | 
|   50  public: |   29  public: | 
 |   30   PpdCacheTest() : loop_(base::MessageLoop::TYPE_IO) {} | 
|   51   void SetUp() override { |   31   void SetUp() override { | 
|   52     ASSERT_TRUE(ppd_cache_temp_dir_.CreateUniqueTempDir()); |   32     ASSERT_TRUE(ppd_cache_temp_dir_.CreateUniqueTempDir()); | 
|   53   } |   33   } | 
|   54  |   34  | 
|   55   // Make and return a cache for the test that uses a temporary directory |   35   // Make and return a cache for the test that uses a temporary directory | 
|   56   // which is cleaned up at the end of the test.  Note that we pass |   36   // which is cleaned up at the end of the test.  Note that we pass | 
|   57   // a (nonexistant) subdirectory of temp_dir_ to the cache to exercise |   37   // a (nonexistant) subdirectory of temp_dir_ to the cache to exercise | 
|   58   // the lazy-creation-of-the-cache-directory code. |   38   // the lazy-creation-of-the-cache-directory code. | 
|   59   std::unique_ptr<PpdCache> CreateTestCache( |   39   scoped_refptr<PpdCache> CreateTestCache() { | 
|   60       const PpdCache::Options& options = PpdCache::Options()) { |  | 
|   61     return PpdCache::Create(ppd_cache_temp_dir_.GetPath().Append("Cache"), |   40     return PpdCache::Create(ppd_cache_temp_dir_.GetPath().Append("Cache"), | 
|   62                             options); |   41                             loop_.task_runner().get()); | 
|   63   } |   42   } | 
|   64  |   43  | 
 |   44   void CaptureFindResult(const PpdCache::FindResult& result) { | 
 |   45     ++captured_find_results_; | 
 |   46     find_result_ = result; | 
 |   47   } | 
 |   48  | 
 |   49   void CaptureStoreResult() { ++captured_store_results_; } | 
 |   50  | 
|   65  protected: |   51  protected: | 
 |   52   // Number of find results we've captured. | 
 |   53   int captured_find_results_ = 0; | 
 |   54  | 
 |   55   // Most recent captured result. | 
 |   56   PpdCache::FindResult find_result_; | 
 |   57  | 
 |   58   // Number of store callbacks we've seen. | 
 |   59   int captured_store_results_ = 0; | 
 |   60  | 
|   66   // Overrider for DIR_CHROMEOS_PPD_CACHE that points it at a temporary |   61   // Overrider for DIR_CHROMEOS_PPD_CACHE that points it at a temporary | 
|   67   // directory for the life of the test. |   62   // directory for the life of the test. | 
|   68   base::ScopedTempDir ppd_cache_temp_dir_; |   63   base::ScopedTempDir ppd_cache_temp_dir_; | 
 |   64   base::MessageLoop loop_; | 
|   69 }; |   65 }; | 
|   70  |   66  | 
|   71 // Check that path has a value, and the contents of the referenced file are |  | 
|   72 // |expected_contents|. |  | 
|   73 void CheckFileContentsAre(base::Optional<base::FilePath> result, |  | 
|   74                           const std::string& expected_contents) { |  | 
|   75   // Make sure we have a value. |  | 
|   76   ASSERT_TRUE(result); |  | 
|   77   // Make sure we get the ppd back that we stored. |  | 
|   78   std::string contents; |  | 
|   79   ASSERT_TRUE(base::ReadFileToString(result.value(), &contents)); |  | 
|   80   EXPECT_EQ(expected_contents, contents); |  | 
|   81 } |  | 
|   82  |   67  | 
|   83 // Test that we miss on an empty cache. |   68 // Test that we miss on an empty cache. | 
|   84 TEST_F(PpdCacheTest, SimpleMiss) { |   69 TEST_F(PpdCacheTest, SimpleMiss) { | 
|   85   auto cache = CreateTestCache(); |   70   auto cache = CreateTestCache(); | 
|   86   EXPECT_FALSE(cache->Find(TestReference())); |   71   cache->Find("foo", base::Bind(&PpdCacheTest::CaptureFindResult, | 
 |   72                                 base::Unretained(this))); | 
 |   73   base::RunLoop().RunUntilIdle(); | 
 |   74   EXPECT_EQ(captured_find_results_, 1); | 
 |   75   EXPECT_FALSE(find_result_.success); | 
|   87 } |   76 } | 
|   88  |   77  | 
|   89 // Test that when we store stuff, we get it back. |  | 
|   90 TEST_F(PpdCacheTest, MissThenHit) { |   78 TEST_F(PpdCacheTest, MissThenHit) { | 
|   91   auto cache = CreateTestCache(); |   79   auto cache = CreateTestCache(); | 
|   92   auto ref = TestReference(); |   80   const char kTestKey[] = "My totally awesome key"; | 
|   93   EXPECT_FALSE(cache->Find(ref)); |   81   const char kTestKey2[] = "A different key"; | 
 |   82   const char kTestContents[] = "Like, totally awesome contents"; | 
|   94  |   83  | 
|   95   // Store should give us a reference to the file. |   84   cache->Find(kTestKey, base::Bind(&PpdCacheTest::CaptureFindResult, | 
|   96   CheckFileContentsAre(cache->Store(ref, kTestPpdContents), kTestPpdContents); |   85                                    base::Unretained(this))); | 
 |   86   base::RunLoop().RunUntilIdle(); | 
 |   87   EXPECT_EQ(captured_find_results_, 1); | 
 |   88   EXPECT_FALSE(find_result_.success); | 
|   97  |   89  | 
|   98   // We should also get it back in response to a Find. |   90   cache->Store( | 
|   99   CheckFileContentsAre(cache->Find(ref), kTestPpdContents); |   91       kTestKey, kTestContents, | 
|  100 } |   92       base::Bind(&PpdCacheTest::CaptureStoreResult, base::Unretained(this))); | 
 |   93   base::RunLoop().RunUntilIdle(); | 
 |   94   EXPECT_EQ(captured_store_results_, 1); | 
|  101  |   95  | 
|  102 // Test that mutating any field in the reference causes us to miss in the cache |   96   cache->Find(kTestKey, base::Bind(&PpdCacheTest::CaptureFindResult, | 
|  103 // when we change the highest priority resolve criteria. |   97                                    base::Unretained(this))); | 
|  104 TEST_F(PpdCacheTest, FieldChangeMeansCacheMiss) { |   98   base::RunLoop().RunUntilIdle(); | 
|  105   auto cache = CreateTestCache(); |   99   EXPECT_EQ(captured_find_results_, 2); | 
|  106   auto ref = TestReference(); |  100   EXPECT_TRUE(find_result_.success); | 
|  107   CheckFileContentsAre(cache->Store(ref, kTestPpdContents), kTestPpdContents); |  101   EXPECT_EQ(find_result_.contents, kTestContents); | 
 |  102   EXPECT_LT(find_result_.age, base::TimeDelta::FromMinutes(5)); | 
|  108  |  103  | 
|  109   // We have a user url, so should still cache hit on manufacturer change. |  104   cache->Find(kTestKey2, base::Bind(&PpdCacheTest::CaptureFindResult, | 
|  110   ref.effective_manufacturer = "Something else"; |  105                                     base::Unretained(this))); | 
|  111   EXPECT_TRUE(cache->Find(ref)); |  106   base::RunLoop().RunUntilIdle(); | 
|  112   ref = TestReference(); |  107   EXPECT_EQ(captured_find_results_, 3); | 
|  113  |  108   EXPECT_FALSE(find_result_.success); | 
|  114   // We have a user url, so should still cache hit on model change. |  | 
|  115   ref.effective_model = "Something else"; |  | 
|  116   EXPECT_TRUE(cache->Find(ref)); |  | 
|  117   ref = TestReference(); |  | 
|  118  |  | 
|  119   // But if we change th user url, that's a cache miss. |  | 
|  120   ref.user_supplied_ppd_url = "Something else"; |  | 
|  121   EXPECT_FALSE(cache->Find(ref)); |  | 
|  122   ref = TestReference(); |  | 
|  123   // Should still find the initial Store when ref *is* identical. |  | 
|  124   CheckFileContentsAre(cache->Find(ref), kTestPpdContents); |  | 
|  125  |  | 
|  126   // Now store the reference with no test url. |  | 
|  127   ref.user_supplied_ppd_url.clear(); |  | 
|  128   CheckFileContentsAre(cache->Store(ref, kTestPpdContents), kTestPpdContents); |  | 
|  129  |  | 
|  130   // Now changing the model or manufacturer should cause a cache miss. |  | 
|  131   ref.effective_manufacturer = "Something else"; |  | 
|  132   EXPECT_FALSE(cache->Find(ref)); |  | 
|  133   ref = TestReference(); |  | 
|  134   ref.user_supplied_ppd_url.clear(); |  | 
|  135   ref.effective_model = "Something else"; |  | 
|  136   EXPECT_FALSE(cache->Find(ref)); |  | 
|  137 } |  | 
|  138  |  | 
|  139 // Test that gzipped contents get stored as .ppd.gz, and non-gzipped |  | 
|  140 // contents get stored as .ppd |  | 
|  141 TEST_F(PpdCacheTest, StoredExtensions) { |  | 
|  142   auto cache = CreateTestCache(); |  | 
|  143   auto ref = TestReference(); |  | 
|  144  |  | 
|  145   // Not compressed, so should store as .ppd |  | 
|  146   auto result = cache->Store(ref, kTestPpdContents); |  | 
|  147   EXPECT_EQ(".ppd", cache->Store(ref, kTestPpdContents).value().Extension()); |  | 
|  148  |  | 
|  149   // Compressed, so should identify this and store as .ppd.gz |  | 
|  150   std::string gzipped_contents(kTestGZippedPpdContents, |  | 
|  151                                sizeof(kTestGZippedPpdContents)); |  | 
|  152   EXPECT_EQ(".ppd.gz", cache->Store(ref, gzipped_contents).value().Extension()); |  | 
|  153 } |  | 
|  154  |  | 
|  155 // Test that we get back what we stored when we store an available printers |  | 
|  156 // list. |  | 
|  157 TEST_F(PpdCacheTest, StoreAndRetrieveAvailablePrinters) { |  | 
|  158   auto cache = CreateTestCache(); |  | 
|  159  |  | 
|  160   // Nothing stored, so should miss in the cache. |  | 
|  161   auto result = cache->FindAvailablePrinters(); |  | 
|  162   EXPECT_FALSE(result); |  | 
|  163  |  | 
|  164   // Create something to store. |  | 
|  165   auto a = base::MakeUnique<PpdProvider::AvailablePrintersMap>(); |  | 
|  166   (*a)["foo"] = {"bar", "baz", "sna"}; |  | 
|  167   (*a)["bar"] = {"c", "d", "e"}; |  | 
|  168   (*a)["baz"] = {"f", "g", "h"}; |  | 
|  169   PpdProvider::AvailablePrintersMap original = *a; |  | 
|  170  |  | 
|  171   // Store it, get it back. |  | 
|  172   cache->StoreAvailablePrinters(std::move(a)); |  | 
|  173   result = cache->FindAvailablePrinters(); |  | 
|  174   ASSERT_TRUE(result); |  | 
|  175  |  | 
|  176   EXPECT_EQ(original, result.value()); |  | 
|  177 } |  | 
|  178  |  | 
|  179 // When an entry is too old, we shouldn't return it. |  | 
|  180 TEST_F(PpdCacheTest, ExpireStaleAvailablePrinters) { |  | 
|  181   PpdCache::Options options; |  | 
|  182   // Expire stuff immediately by setting the staleness limit to 0. |  | 
|  183   options.max_available_list_staleness = base::TimeDelta(); |  | 
|  184   auto cache = CreateTestCache(options); |  | 
|  185  |  | 
|  186   // Store an empty map.  (Contents don't really matter for this test). |  | 
|  187   cache->StoreAvailablePrinters( |  | 
|  188       base::MakeUnique<PpdProvider::AvailablePrintersMap>()); |  | 
|  189  |  | 
|  190   // Should *miss* in the cache because the entry is already expired. |  | 
|  191   EXPECT_FALSE(cache->FindAvailablePrinters()); |  | 
|  192 } |  109 } | 
|  193  |  110  | 
|  194 }  // namespace |  111 }  // namespace | 
|  195 }  // namespace printing |  112 }  // namespace printing | 
|  196 }  // namespace chromeos |  113 }  // namespace chromeos | 
| OLD | NEW |