blob: 291189d6a58a0d81d71f4d959aed4bb23262605a [file] [log] [blame]
Amin Hassani7fca2862019-03-28 16:09:22 -07001//
2// Copyright (C) 2019 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "update_engine/omaha_request_builder_xml.h"
18
19#include <string>
Jae Hoon Kimb7ee3872019-06-06 14:59:03 -070020#include <utility>
21#include <vector>
Amin Hassani7fca2862019-03-28 16:09:22 -070022
Jae Hoon Kim6ada5912019-06-14 10:11:34 -070023#include <base/guid.h>
Amin Hassani7fca2862019-03-28 16:09:22 -070024#include <gtest/gtest.h>
25
Jae Hoon Kim6ada5912019-06-14 10:11:34 -070026#include "update_engine/fake_system_state.h"
27
Jae Hoon Kimb7ee3872019-06-06 14:59:03 -070028using std::pair;
Amin Hassani7fca2862019-03-28 16:09:22 -070029using std::string;
Jae Hoon Kimb7ee3872019-06-06 14:59:03 -070030using std::vector;
Amin Hassani7fca2862019-03-28 16:09:22 -070031
32namespace chromeos_update_engine {
33
Jae Hoon Kim6ada5912019-06-14 10:11:34 -070034namespace {
35// Helper to find key and extract value from the given string |xml|, instead
36// of using a full parser. The attribute key will be followed by "=\"" as xml
37// attribute values must be within double quotes (not single quotes).
38static string FindAttributeKeyValueInXml(const string& xml,
39 const string& key,
40 const size_t val_size) {
41 string key_with_quotes = key + "=\"";
42 const size_t val_start_pos = xml.find(key);
43 if (val_start_pos == string::npos)
44 return "";
45 return xml.substr(val_start_pos + key_with_quotes.size(), val_size);
46}
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -080047// Helper to find the count of substring in a string.
48static size_t CountSubstringInString(const string& str, const string& substr) {
49 size_t count = 0, pos = 0;
50 while ((pos = str.find(substr, pos ? pos + 1 : 0)) != string::npos)
51 ++count;
52 return count;
53}
Jae Hoon Kim6ada5912019-06-14 10:11:34 -070054} // namespace
55
56class OmahaRequestBuilderXmlTest : public ::testing::Test {
57 protected:
58 void SetUp() override {}
59 void TearDown() override {}
60
61 FakeSystemState fake_system_state_;
62 static constexpr size_t kGuidSize = 36;
63};
Amin Hassani7fca2862019-03-28 16:09:22 -070064
65TEST_F(OmahaRequestBuilderXmlTest, XmlEncodeTest) {
66 string output;
Jae Hoon Kimb7ee3872019-06-06 14:59:03 -070067 vector<pair<string, string>> xml_encode_pairs = {
68 {"ab", "ab"},
69 {"a<b", "a&lt;b"},
70 {"<&>\"\'\\", "&lt;&amp;&gt;&quot;&apos;\\"},
71 {"&lt;&amp;&gt;", "&amp;lt;&amp;amp;&amp;gt;"}};
72 for (const auto& xml_encode_pair : xml_encode_pairs) {
73 const auto& before_encoding = xml_encode_pair.first;
74 const auto& after_encoding = xml_encode_pair.second;
75 EXPECT_TRUE(XmlEncode(before_encoding, &output));
76 EXPECT_EQ(after_encoding, output);
77 }
Amin Hassani7fca2862019-03-28 16:09:22 -070078 // Check that unterminated UTF-8 strings are handled properly.
79 EXPECT_FALSE(XmlEncode("\xc2", &output));
80 // Fail with invalid ASCII-7 chars.
81 EXPECT_FALSE(XmlEncode("This is an 'n' with a tilde: \xc3\xb1", &output));
82}
83
84TEST_F(OmahaRequestBuilderXmlTest, XmlEncodeWithDefaultTest) {
Jae Hoon Kimb7ee3872019-06-06 14:59:03 -070085 EXPECT_EQ("", XmlEncodeWithDefault(""));
Amin Hassani7fca2862019-03-28 16:09:22 -070086 EXPECT_EQ("&lt;&amp;&gt;", XmlEncodeWithDefault("<&>", "something else"));
87 EXPECT_EQ("<not escaped>", XmlEncodeWithDefault("\xc2", "<not escaped>"));
88}
89
Jae Hoon Kim37d15372020-01-08 18:11:26 -080090TEST_F(OmahaRequestBuilderXmlTest, PlatformGetAppTest) {
91 OmahaRequestParams omaha_request_params{&fake_system_state_};
92 omaha_request_params.set_device_requisition("device requisition");
93 OmahaRequestBuilderXml omaha_request{nullptr,
94 &omaha_request_params,
95 false,
96 false,
97 0,
98 0,
99 0,
100 fake_system_state_.prefs(),
101 ""};
Amin Hassani2b68e6b2020-04-17 10:49:12 -0700102 OmahaAppData dlc_app_data = {.id = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
103 .version = "",
104 .skip_update = false,
105 .is_dlc = false};
Jae Hoon Kim37d15372020-01-08 18:11:26 -0800106
107 // Verify that the attributes that shouldn't be missing for Platform AppID are
108 // in fact present in the <app ...></app>.
Amin Hassani2b68e6b2020-04-17 10:49:12 -0700109 const string app = omaha_request.GetApp(dlc_app_data);
Jae Hoon Kim37d15372020-01-08 18:11:26 -0800110 EXPECT_NE(string::npos, app.find("lang="));
111 EXPECT_NE(string::npos, app.find("fw_version="));
112 EXPECT_NE(string::npos, app.find("ec_version="));
113 EXPECT_NE(string::npos, app.find("requisition="));
114}
115
116TEST_F(OmahaRequestBuilderXmlTest, DlcGetAppTest) {
117 OmahaRequestParams omaha_request_params{&fake_system_state_};
118 omaha_request_params.set_device_requisition("device requisition");
119 OmahaRequestBuilderXml omaha_request{nullptr,
120 &omaha_request_params,
121 false,
122 false,
123 0,
124 0,
125 0,
126 fake_system_state_.prefs(),
127 ""};
Amin Hassani2b68e6b2020-04-17 10:49:12 -0700128 OmahaAppData dlc_app_data = {
Jae Hoon Kim37d15372020-01-08 18:11:26 -0800129 .id = "_dlc_id", .version = "", .skip_update = false, .is_dlc = true};
130
131 // Verify that the attributes that should be missing for DLC AppIDs are in
132 // fact not present in the <app ...></app>.
Amin Hassani2b68e6b2020-04-17 10:49:12 -0700133 const string app = omaha_request.GetApp(dlc_app_data);
Jae Hoon Kim37d15372020-01-08 18:11:26 -0800134 EXPECT_EQ(string::npos, app.find("lang="));
135 EXPECT_EQ(string::npos, app.find("fw_version="));
136 EXPECT_EQ(string::npos, app.find("ec_version="));
137 EXPECT_EQ(string::npos, app.find("requisition="));
138}
139
Jae Hoon Kim6ada5912019-06-14 10:11:34 -0700140TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlRequestIdTest) {
Jae Hoon Kim6ada5912019-06-14 10:11:34 -0700141 OmahaRequestParams omaha_request_params{&fake_system_state_};
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800142 OmahaRequestBuilderXml omaha_request{nullptr,
Jae Hoon Kim6ada5912019-06-14 10:11:34 -0700143 &omaha_request_params,
144 false,
145 false,
146 0,
147 0,
148 0,
Jae Hoon Kimedb65502019-06-14 11:52:17 -0700149 fake_system_state_.prefs(),
150 ""};
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700151 const string kRequestXml = omaha_request.GetRequest();
Jae Hoon Kim6ada5912019-06-14 10:11:34 -0700152 const string key = "requestid";
153 const string request_id =
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700154 FindAttributeKeyValueInXml(kRequestXml, key, kGuidSize);
Jae Hoon Kim6ada5912019-06-14 10:11:34 -0700155 // A valid |request_id| is either a GUID version 4 or empty string.
156 if (!request_id.empty())
157 EXPECT_TRUE(base::IsValidGUID(request_id));
158}
159
Jae Hoon Kimedb65502019-06-14 11:52:17 -0700160TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlSessionIdTest) {
161 const string gen_session_id = base::GenerateGUID();
Jae Hoon Kimedb65502019-06-14 11:52:17 -0700162 OmahaRequestParams omaha_request_params{&fake_system_state_};
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800163 OmahaRequestBuilderXml omaha_request{nullptr,
Jae Hoon Kimedb65502019-06-14 11:52:17 -0700164 &omaha_request_params,
165 false,
166 false,
167 0,
168 0,
169 0,
170 fake_system_state_.prefs(),
171 gen_session_id};
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700172 const string kRequestXml = omaha_request.GetRequest();
Jae Hoon Kimedb65502019-06-14 11:52:17 -0700173 const string key = "sessionid";
174 const string session_id =
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700175 FindAttributeKeyValueInXml(kRequestXml, key, kGuidSize);
Jae Hoon Kimedb65502019-06-14 11:52:17 -0700176 // A valid |session_id| is either a GUID version 4 or empty string.
177 if (!session_id.empty()) {
178 EXPECT_TRUE(base::IsValidGUID(session_id));
179 }
180 EXPECT_EQ(gen_session_id, session_id);
181}
182
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800183TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlPlatformUpdateTest) {
184 OmahaRequestParams omaha_request_params{&fake_system_state_};
185 OmahaRequestBuilderXml omaha_request{nullptr,
186 &omaha_request_params,
187 false,
188 false,
189 0,
190 0,
191 0,
192 fake_system_state_.prefs(),
193 ""};
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700194 const string kRequestXml = omaha_request.GetRequest();
195 EXPECT_EQ(1, CountSubstringInString(kRequestXml, "<updatecheck"))
196 << kRequestXml;
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800197}
198
199TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlPlatformUpdateWithDlcsTest) {
200 OmahaRequestParams omaha_request_params{&fake_system_state_};
Andrewe045aef2020-01-08 16:29:22 -0800201 omaha_request_params.set_dlc_apps_params(
202 {{omaha_request_params.GetDlcAppId("dlc_no_0"), {.name = "dlc_no_0"}},
203 {omaha_request_params.GetDlcAppId("dlc_no_1"), {.name = "dlc_no_1"}}});
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800204 OmahaRequestBuilderXml omaha_request{nullptr,
205 &omaha_request_params,
206 false,
207 false,
208 0,
209 0,
210 0,
211 fake_system_state_.prefs(),
212 ""};
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700213 const string kRequestXml = omaha_request.GetRequest();
214 EXPECT_EQ(3, CountSubstringInString(kRequestXml, "<updatecheck"))
215 << kRequestXml;
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800216}
217
218TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcInstallationTest) {
219 OmahaRequestParams omaha_request_params{&fake_system_state_};
Andrewe045aef2020-01-08 16:29:22 -0800220 const std::map<std::string, OmahaRequestParams::AppParams> dlcs = {
221 {omaha_request_params.GetDlcAppId("dlc_no_0"), {.name = "dlc_no_0"}},
222 {omaha_request_params.GetDlcAppId("dlc_no_1"), {.name = "dlc_no_1"}}};
223 omaha_request_params.set_dlc_apps_params(dlcs);
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800224 omaha_request_params.set_is_install(true);
225 OmahaRequestBuilderXml omaha_request{nullptr,
226 &omaha_request_params,
227 false,
228 false,
229 0,
230 0,
231 0,
232 fake_system_state_.prefs(),
233 ""};
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700234 const string kRequestXml = omaha_request.GetRequest();
235 EXPECT_EQ(2, CountSubstringInString(kRequestXml, "<updatecheck"))
236 << kRequestXml;
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800237
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700238 auto FindAppId = [kRequestXml](size_t pos) -> size_t {
239 return kRequestXml.find("<app appid", pos);
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800240 };
241 // Skip over the Platform AppID, which is always first.
242 size_t pos = FindAppId(0);
243 for (auto&& _ : dlcs) {
244 (void)_;
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700245 EXPECT_NE(string::npos, (pos = FindAppId(pos + 1))) << kRequestXml;
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800246 const string dlc_app_id_version = FindAttributeKeyValueInXml(
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700247 kRequestXml.substr(pos), "version", string(kNoVersion).size());
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800248 EXPECT_EQ(kNoVersion, dlc_app_id_version);
249
250 const string false_str = "false";
251 const string dlc_app_id_delta_okay = FindAttributeKeyValueInXml(
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700252 kRequestXml.substr(pos), "delta_okay", false_str.length());
Jae Hoon Kim5fc00a22020-01-08 20:15:42 -0800253 EXPECT_EQ(false_str, dlc_app_id_delta_okay);
254 }
255}
256
Andrewe045aef2020-01-08 16:29:22 -0800257TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcNoPing) {
258 OmahaRequestParams omaha_request_params{&fake_system_state_};
259 omaha_request_params.set_dlc_apps_params(
260 {{omaha_request_params.GetDlcAppId("dlc_no_0"), {.name = "dlc_no_0"}}});
261 OmahaRequestBuilderXml omaha_request{nullptr,
262 &omaha_request_params,
263 false,
264 false,
265 0,
266 0,
267 0,
268 fake_system_state_.prefs(),
269 ""};
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700270 const string kRequestXml = omaha_request.GetRequest();
271 EXPECT_EQ(0, CountSubstringInString(kRequestXml, "<ping")) << kRequestXml;
Andrewe045aef2020-01-08 16:29:22 -0800272}
273
274TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcPingRollCallNoActive) {
275 OmahaRequestParams omaha_request_params{&fake_system_state_};
276 omaha_request_params.set_dlc_apps_params(
277 {{omaha_request_params.GetDlcAppId("dlc_no_0"),
278 {.active_counting_type = OmahaRequestParams::kDateBased,
279 .name = "dlc_no_0",
280 .ping_date_last_active = 25,
281 .ping_date_last_rollcall = 36,
282 .send_ping = true}}});
283 OmahaRequestBuilderXml omaha_request{nullptr,
284 &omaha_request_params,
285 false,
286 false,
287 0,
288 0,
289 0,
290 fake_system_state_.prefs(),
291 ""};
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700292 const string kRequestXml = omaha_request.GetRequest();
293 EXPECT_EQ(1, CountSubstringInString(kRequestXml, "<ping rd=\"36\""))
294 << kRequestXml;
Andrewe045aef2020-01-08 16:29:22 -0800295}
296
297TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcPingRollCallAndActive) {
298 OmahaRequestParams omaha_request_params{&fake_system_state_};
299 omaha_request_params.set_dlc_apps_params(
300 {{omaha_request_params.GetDlcAppId("dlc_no_0"),
301 {.active_counting_type = OmahaRequestParams::kDateBased,
302 .name = "dlc_no_0",
303 .ping_active = 1,
304 .ping_date_last_active = 25,
305 .ping_date_last_rollcall = 36,
306 .send_ping = true}}});
307 OmahaRequestBuilderXml omaha_request{nullptr,
308 &omaha_request_params,
309 false,
310 false,
311 0,
312 0,
313 0,
314 fake_system_state_.prefs(),
315 ""};
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700316 const string kRequestXml = omaha_request.GetRequest();
Andrewe045aef2020-01-08 16:29:22 -0800317 EXPECT_EQ(1,
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700318 CountSubstringInString(kRequestXml,
Andrewe045aef2020-01-08 16:29:22 -0800319 "<ping active=\"1\" ad=\"25\" rd=\"36\""))
Jae Hoon Kim3e69b4c2020-06-16 09:23:39 -0700320 << kRequestXml;
321}
322
323TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlUpdateCompleteEvent) {
324 OmahaRequestParams omaha_request_params{&fake_system_state_};
325 OmahaEvent event(OmahaEvent::kTypeUpdateComplete);
326 OmahaRequestBuilderXml omaha_request{&event,
327 &omaha_request_params,
328 false,
329 false,
330 0,
331 0,
332 0,
333 fake_system_state_.prefs(),
334 ""};
335 const string kRequestXml = omaha_request.GetRequest();
336 LOG(INFO) << kRequestXml;
337 EXPECT_EQ(
338 1,
339 CountSubstringInString(
340 kRequestXml, "<event eventtype=\"3\" eventresult=\"1\"></event>"))
341 << kRequestXml;
342}
343
344TEST_F(OmahaRequestBuilderXmlTest,
345 GetRequestXmlUpdateCompleteEventSomeDlcsExcluded) {
346 OmahaRequestParams omaha_request_params{&fake_system_state_};
347 omaha_request_params.set_dlc_apps_params({
348 {omaha_request_params.GetDlcAppId("dlc_1"), {.updated = true}},
349 {omaha_request_params.GetDlcAppId("dlc_2"), {.updated = false}},
350 });
351 OmahaEvent event(OmahaEvent::kTypeUpdateComplete);
352 OmahaRequestBuilderXml omaha_request{&event,
353 &omaha_request_params,
354 false,
355 false,
356 0,
357 0,
358 0,
359 fake_system_state_.prefs(),
360 ""};
361 const string kRequestXml = omaha_request.GetRequest();
362 EXPECT_EQ(
363 2,
364 CountSubstringInString(
365 kRequestXml, "<event eventtype=\"3\" eventresult=\"1\"></event>"))
366 << kRequestXml;
367 EXPECT_EQ(
368 1,
369 CountSubstringInString(
370 kRequestXml,
371 "<event eventtype=\"3\" eventresult=\"0\" errorcode=\"60\"></event>"))
372 << kRequestXml;
373}
374
375TEST_F(OmahaRequestBuilderXmlTest,
376 GetRequestXmlUpdateCompleteEventAllDlcsExcluded) {
377 OmahaRequestParams omaha_request_params{&fake_system_state_};
378 omaha_request_params.set_dlc_apps_params({
379 {omaha_request_params.GetDlcAppId("dlc_1"), {.updated = false}},
380 {omaha_request_params.GetDlcAppId("dlc_2"), {.updated = false}},
381 });
382 OmahaEvent event(OmahaEvent::kTypeUpdateComplete);
383 OmahaRequestBuilderXml omaha_request{&event,
384 &omaha_request_params,
385 false,
386 false,
387 0,
388 0,
389 0,
390 fake_system_state_.prefs(),
391 ""};
392 const string kRequestXml = omaha_request.GetRequest();
393 EXPECT_EQ(
394 1,
395 CountSubstringInString(
396 kRequestXml, "<event eventtype=\"3\" eventresult=\"1\"></event>"))
397 << kRequestXml;
398 EXPECT_EQ(
399 2,
400 CountSubstringInString(
401 kRequestXml,
402 "<event eventtype=\"3\" eventresult=\"0\" errorcode=\"60\"></event>"))
403 << kRequestXml;
Andrewe045aef2020-01-08 16:29:22 -0800404}
Amin Hassani7fca2862019-03-28 16:09:22 -0700405} // namespace chromeos_update_engine