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