1 // Copyright 2019 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 
5 #include "chrome/browser/chromeos/printing/print_servers_provider.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "chrome/browser/chromeos/printing/print_server.h"
11 #include "chrome/common/pref_names.h"
12 #include "components/sync_preferences/testing_pref_service_syncable.h"
13 #include "content/public/test/browser_task_environment.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "url/gurl.h"
16 
17 namespace chromeos {
18 namespace {
19 
20 // An example of configuration file with print servers.
21 constexpr char kPrintServersPolicyJson1[] = R"json(
22 [
23   {
24     "id": "id1",
25     "display_name": "MyPrintServer",
26     "url": "ipp://192.168.1.5"
27   }, {
28     "id": "id2",
29     "display_name": "Server API",
30     "url":"ipps://print-server.intra.example.com:444/ipp/cl2k4"
31   }, {
32     "id": "id3",
33     "display_name": "YaLP",
34     "url": "http://192.168.1.8/bleble/print"
35   }
36 ])json";
37 
38 // An example allowlist.
39 const std::vector<std::string> kPrintServersPolicyAllowlist1 = {"id3", "idX",
40                                                                 "id1"};
41 // Test pref name for allowlist.
42 std::string allowlist_pref_name_ = "test";
43 // A different configuration file with print servers.
44 constexpr char kPrintServersPolicyJson2[] = R"json(
45 [
46   {
47     "id": "id1",
48     "display_name": "CUPS",
49     "url": "ipp://192.168.1.15"
50   }
51 ])json";
52 
53 // Another configuration file with print servers, this time with invalid URLs.
54 constexpr char kPrintServersPolicyJson3[] = R"json(
55 [
56   {
57     "id": "1",
58     "display_name": "server_1",
59     "url": "ipp://aaa.bbb.ccc:666/xx"
60   }, {
61     "id": "2",
62     "display_name": "server_2",
63     "url":"ipps:/print.server.intra.example.com:443z/ipp"
64   }, {
65     "id": "3",
66     "display_name": "server_3",
67     "url": "file://192.168.1.8/bleble/print"
68   }, {
69     "id": "4",
70     "display_name": "server_4",
71     "url": "http://aaa.bbb.ccc:666/xx"
72   }, {
73     "id": "5",
74     "display_name": "server_5",
75     "url": "\n \t ipps://aaa.bbb.ccc:666/yy"
76   }, {
77     "id": "6",
78     "display_name": "server_6",
79     "url":"ipps:/print.server^.intra.example.com/ipp"
80   }, {
81     "id": "3",
82     "display_name": "server_7",
83     "url": "file://194.169.2.18/bleble2/print"
84   }, {
85     "display_name": "server_8",
86     "url": "file://195.161.3.28/bleble/print"
87   }
88 ])json";
89 
Server1()90 PrintServer Server1() {
91   return PrintServer("id1", GURL("http://192.168.1.5:631"), "MyPrintServer");
92 }
93 
94 PrintServer Server2() {
95   return PrintServer(
96       "id2", GURL("https://print-server.intra.example.com:444/ipp/cl2k4"),
97       "Server API");
98 }
99 
Server3()100 PrintServer Server3() {
101   return PrintServer("id3", GURL("http://192.168.1.8/bleble/print"), "YaLP");
102 }
103 
104 // Corresponding vector with PrintServers.
PrintServersPolicyData1()105 std::vector<PrintServer> PrintServersPolicyData1() {
106   return std::vector<PrintServer>({Server1(), Server2(), Server3()});
107 }
108 
109 // Corresponding vector filtered with the allowlist defined above.
PrintServersPolicyData1Allowlist1()110 std::vector<PrintServer> PrintServersPolicyData1Allowlist1() {
111   return std::vector<PrintServer>({Server1(), Server3()});
112 }
113 
114 // Corresponding vector with PrintServers.
PrintServersPolicyData2()115 std::vector<PrintServer> PrintServersPolicyData2() {
116   return std::vector<PrintServer>(
117       {{"id1", GURL("http://192.168.1.15:631"), "CUPS"}});
118 }
119 
120 // Corresponding vector with PrintServers. Only two records are included,
121 // because other ones are invalid:
122 // server_1 - OK
123 // server_2 - invalid URL - invalid port number
124 // server_3 - unsupported scheme
125 // server_4 - duplicate of server_1
126 // server_5 - leading whitespaces, but OK
127 // server_6 - invalid URL - forbidden character
128 // server_7 - duplicate id
129 // server_8 - missing id
PrintServersPolicyData3()130 std::vector<PrintServer> PrintServersPolicyData3() {
131   return std::vector<PrintServer>(
132       {{"1", GURL("http://aaa.bbb.ccc:666/xx"), "server_1"},
133        {"5", GURL("https://aaa.bbb.ccc:666/yy"), "server_5"}});
134 }
135 
136 // Observer that stores all its calls.
137 class TestObserver : public PrintServersProvider::Observer {
138  public:
139   struct ObserverCall {
140     bool complete;
141     std::vector<PrintServer> servers;
ObserverCallchromeos::__anon75b43da10111::TestObserver::ObserverCall142     ObserverCall(bool complete, const std::vector<PrintServer>& servers)
143         : complete(complete), servers(servers) {}
144   };
145 
146   ~TestObserver() override = default;
147 
148   // Callback from PrintServersProvider::Observer.
OnServersChanged(bool complete,const std::vector<PrintServer> & servers)149   void OnServersChanged(bool complete,
150                         const std::vector<PrintServer>& servers) override {
151     calls_.emplace_back(complete, servers);
152   }
153 
154   // Returns history of all calls to OnServersChanged(...).
GetCalls() const155   const std::vector<ObserverCall>& GetCalls() const { return calls_; }
156 
157  private:
158   // history of all callbacks
159   std::vector<ObserverCall> calls_;
160 };
161 
162 class PrintServersProviderTest : public testing::Test {
163  public:
PrintServersProviderTest()164   PrintServersProviderTest()
165       : external_servers_(PrintServersProvider::Create()) {}
166 
167  protected:
SetUp()168   void SetUp() override {
169     pref_service_.registry()->RegisterListPref(allowlist_pref_name_);
170     external_servers_->SetAllowlistPref(&pref_service_, allowlist_pref_name_);
171   }
172 
173   // Everything must be called on Chrome_UIThread.
174   content::BrowserTaskEnvironment task_environment_;
175   // Test prefs.
176   sync_preferences::TestingPrefServiceSyncable pref_service_;
177   // Tested object.
178   std::unique_ptr<PrintServersProvider> external_servers_;
179 };
180 
181 // Verify that the object can be destroyed while parsing is in progress.
TEST_F(PrintServersProviderTest,DestructionIsSafe)182 TEST_F(PrintServersProviderTest, DestructionIsSafe) {
183   {
184     std::unique_ptr<PrintServersProvider> servers =
185         PrintServersProvider::Create();
186     servers->SetData(std::make_unique<std::string>(kPrintServersPolicyJson1));
187     // Data is valid.  Computation is proceeding.
188   }
189   // servers is out of scope.  Destructor has run.  Pump the message queue to
190   // see if anything strange happens.
191   task_environment_.RunUntilIdle();
192 }
193 
194 // Verify that we're initially unset and empty.
195 // After initialization "complete" flags = false.
TEST_F(PrintServersProviderTest,InitialConditions)196 TEST_F(PrintServersProviderTest, InitialConditions) {
197   TestObserver obs;
198   external_servers_->AddObserver(&obs);
199   ASSERT_EQ(obs.GetCalls().size(), 1u);
200   EXPECT_EQ(obs.GetCalls().back().complete, false);
201   EXPECT_TRUE(obs.GetCalls().back().servers.empty());
202   external_servers_->RemoveObserver(&obs);
203 }
204 
205 // Verify two ClearData() calls.
206 // ClearData() sets empty list and "complete" flag = true.
TEST_F(PrintServersProviderTest,ClearData2)207 TEST_F(PrintServersProviderTest, ClearData2) {
208   TestObserver obs;
209   external_servers_->AddObserver(&obs);
210   external_servers_->ClearData();
211   ASSERT_EQ(obs.GetCalls().size(), 2u);
212   EXPECT_EQ(obs.GetCalls().back().complete, true);
213   EXPECT_TRUE(obs.GetCalls().back().servers.empty());
214   external_servers_->ClearData();
215   // no changes, because observed object's state is the same
216   ASSERT_EQ(obs.GetCalls().size(), 2u);
217   external_servers_->RemoveObserver(&obs);
218 }
219 
220 // Verifies SetData().
221 // SetData(...) sets "complete" flag = false, then parse given data in the
222 // background and sets resultant list with "complete" flag = true.
TEST_F(PrintServersProviderTest,SetData)223 TEST_F(PrintServersProviderTest, SetData) {
224   auto blob1 = std::make_unique<std::string>(kPrintServersPolicyJson1);
225   TestObserver obs;
226   external_servers_->AddObserver(&obs);
227   external_servers_->SetData(std::move(blob1));
228   // single call from AddObserver, since SetData(...) is not processed yet
229   ASSERT_EQ(obs.GetCalls().size(), 1u);
230   // make sure that SetData(...) is processed
231   task_environment_.RunUntilIdle();
232   // now the call from SetData(...) is there also
233   ASSERT_EQ(obs.GetCalls().size(), 2u);
234   EXPECT_EQ(obs.GetCalls().back().complete, true);
235   EXPECT_EQ(obs.GetCalls().back().servers, PrintServersPolicyData1());
236   external_servers_->RemoveObserver(&obs);
237 }
238 
239 // Verify two SetData() calls.
TEST_F(PrintServersProviderTest,SetData2)240 TEST_F(PrintServersProviderTest, SetData2) {
241   auto blob1 = std::make_unique<std::string>(kPrintServersPolicyJson1);
242   auto blob2 = std::make_unique<std::string>(kPrintServersPolicyJson2);
243   TestObserver obs;
244   external_servers_->AddObserver(&obs);
245   external_servers_->SetData(std::move(blob1));
246   // single call from AddObserver, since SetData(...) is not processed yet
247   ASSERT_EQ(obs.GetCalls().size(), 1u);
248   external_servers_->SetData(std::move(blob2));
249   // no changes, because nothing was processed yet
250   ASSERT_EQ(obs.GetCalls().size(), 1u);
251   task_environment_.RunUntilIdle();
252   // both calls from SetData(...) should be reported
253   ASSERT_EQ(obs.GetCalls().size(), 3u);
254   EXPECT_EQ(obs.GetCalls()[1].complete, false);
255   EXPECT_EQ(obs.GetCalls()[1].servers, PrintServersPolicyData1());
256   EXPECT_EQ(obs.GetCalls()[2].complete, true);
257   EXPECT_EQ(obs.GetCalls()[2].servers, PrintServersPolicyData2());
258   external_servers_->RemoveObserver(&obs);
259 }
260 
261 // Verifies SetData() + ClearData() before SetData() completes.
TEST_F(PrintServersProviderTest,SetDataClearData)262 TEST_F(PrintServersProviderTest, SetDataClearData) {
263   auto blob1 = std::make_unique<std::string>(kPrintServersPolicyJson1);
264   TestObserver obs;
265   external_servers_->AddObserver(&obs);
266   external_servers_->SetData(std::move(blob1));
267   // single call from AddObserver, since SetData(...) is not processed yet
268   ASSERT_EQ(obs.GetCalls().size(), 1u);
269   external_servers_->ClearData();
270   // a call from ClearData() was added, SetData(...) is not processed yet
271   ASSERT_EQ(obs.GetCalls().size(), 2u);
272   EXPECT_EQ(obs.GetCalls().back().complete, true);
273   EXPECT_TRUE(obs.GetCalls().back().servers.empty());
274   // process SetData(...)
275   task_environment_.RunUntilIdle();
276   // no changes, effects of SetData(...) were already replaced by ClearData()
277   ASSERT_EQ(obs.GetCalls().size(), 2u);
278   external_servers_->RemoveObserver(&obs);
279 }
280 
281 // Verifies ClearData() before AddObserver() + SetData() after.
TEST_F(PrintServersProviderTest,ClearDataSetData)282 TEST_F(PrintServersProviderTest, ClearDataSetData) {
283   auto blob1 = std::make_unique<std::string>(kPrintServersPolicyJson1);
284   TestObserver obs;
285   external_servers_->ClearData();
286   external_servers_->AddObserver(&obs);
287   // single call from AddObserver, but with effects of ClearData()
288   ASSERT_EQ(obs.GetCalls().size(), 1u);
289   EXPECT_EQ(obs.GetCalls().back().complete, true);
290   EXPECT_TRUE(obs.GetCalls().back().servers.empty());
291   external_servers_->SetData(std::move(blob1));
292   // SetData(...) is not completed, but generates a call switching "complete"
293   // flag to false
294   ASSERT_EQ(obs.GetCalls().size(), 2u);
295   EXPECT_EQ(obs.GetCalls().back().complete, false);
296   EXPECT_TRUE(obs.GetCalls().back().servers.empty());
297   // process SetData(...)
298   task_environment_.RunUntilIdle();
299   // next call with results from processed SetData(...)
300   ASSERT_EQ(obs.GetCalls().size(), 3u);
301   EXPECT_EQ(obs.GetCalls().back().complete, true);
302   EXPECT_EQ(obs.GetCalls().back().servers, PrintServersPolicyData1());
303   external_servers_->RemoveObserver(&obs);
304 }
305 
306 // Verify that invalid URLs are filtered out.
TEST_F(PrintServersProviderTest,InvalidURLs)307 TEST_F(PrintServersProviderTest, InvalidURLs) {
308   auto blob3 = std::make_unique<std::string>(kPrintServersPolicyJson3);
309   TestObserver obs;
310   external_servers_->AddObserver(&obs);
311   external_servers_->SetData(std::move(blob3));
312   task_environment_.RunUntilIdle();
313   ASSERT_EQ(obs.GetCalls().size(), 2u);
314   EXPECT_EQ(obs.GetCalls().back().complete, true);
315   EXPECT_EQ(obs.GetCalls().back().servers, PrintServersPolicyData3());
316   external_servers_->RemoveObserver(&obs);
317 }
318 
319 // Verify that allowlist works as expected.
TEST_F(PrintServersProviderTest,Allowlist)320 TEST_F(PrintServersProviderTest, Allowlist) {
321   // The sequence from SetData test.
322   auto blob1 = std::make_unique<std::string>(kPrintServersPolicyJson1);
323   TestObserver obs;
324   external_servers_->AddObserver(&obs);
325   external_servers_->SetData(std::move(blob1));
326   // Apply an empty allowlist on the top.
327   auto value = std::make_unique<base::ListValue>();
328   pref_service_.SetManagedPref(allowlist_pref_name_, std::move(value));
329   // Check the resultant list - is is supposed to be empty.
330   task_environment_.RunUntilIdle();
331   ASSERT_FALSE(obs.GetCalls().empty());
332   EXPECT_TRUE(obs.GetCalls().back().complete);
333   EXPECT_TRUE(obs.GetCalls().back().servers.empty());
334   // Apply allowlist1.
335   value = std::make_unique<base::ListValue>();
336   for (const std::string& id : kPrintServersPolicyAllowlist1)
337     value->Append(base::Value(id));
338   pref_service_.SetManagedPref(allowlist_pref_name_, std::move(value));
339   // Check the resultant list.
340   task_environment_.RunUntilIdle();
341   EXPECT_TRUE(obs.GetCalls().back().complete);
342   EXPECT_EQ(obs.GetCalls().back().servers, PrintServersPolicyData1Allowlist1());
343   // The end.
344   external_servers_->RemoveObserver(&obs);
345 }
346 
347 }  // namespace
348 }  // namespace chromeos
349