blob: 3cf5cc06d4841dcb89720d02e3d1badd4b7f51f8 [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 ""};
102 OmahaAppData dlc_module_app = {.id = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
103 .version = "",
104 .skip_update = false,
105 .is_dlc = false};
106
107 // Verify that the attributes that shouldn't be missing for Platform AppID are
108 // in fact present in the <app ...></app>.
109 const string app = omaha_request.GetApp(dlc_module_app);
110 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 ""};
128 OmahaAppData dlc_module_app = {
129 .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>.
133 const string app = omaha_request.GetApp(dlc_module_app);
134 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 Kim6ada5912019-06-14 10:11:34 -0700151 const string request_xml = omaha_request.GetRequest();
152 const string key = "requestid";
153 const string request_id =
154 FindAttributeKeyValueInXml(request_xml, key, kGuidSize);
155 // 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};
172 const string request_xml = omaha_request.GetRequest();
173 const string key = "sessionid";
174 const string session_id =
175 FindAttributeKeyValueInXml(request_xml, key, kGuidSize);
176 // 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 ""};
194 const string request_xml = omaha_request.GetRequest();
195 EXPECT_EQ(1, CountSubstringInString(request_xml, "<updatecheck"))
196 << request_xml;
197}
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 ""};
213 const string request_xml = omaha_request.GetRequest();
214 EXPECT_EQ(3, CountSubstringInString(request_xml, "<updatecheck"))
215 << request_xml;
216}
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 ""};
234 const string request_xml = omaha_request.GetRequest();
235 EXPECT_EQ(2, CountSubstringInString(request_xml, "<updatecheck"))
236 << request_xml;
237
238 auto FindAppId = [request_xml](size_t pos) -> size_t {
239 return request_xml.find("<app appid", pos);
240 };
241 // Skip over the Platform AppID, which is always first.
242 size_t pos = FindAppId(0);
243 for (auto&& _ : dlcs) {
244 (void)_;
245 EXPECT_NE(string::npos, (pos = FindAppId(pos + 1))) << request_xml;
246 const string dlc_app_id_version = FindAttributeKeyValueInXml(
247 request_xml.substr(pos), "version", string(kNoVersion).size());
248 EXPECT_EQ(kNoVersion, dlc_app_id_version);
249
250 const string false_str = "false";
251 const string dlc_app_id_delta_okay = FindAttributeKeyValueInXml(
252 request_xml.substr(pos), "delta_okay", false_str.length());
253 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 ""};
270 const string request_xml = omaha_request.GetRequest();
271 EXPECT_EQ(0, CountSubstringInString(request_xml, "<ping")) << request_xml;
272}
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 ""};
292 const string request_xml = omaha_request.GetRequest();
293 EXPECT_EQ(1, CountSubstringInString(request_xml, "<ping rd=\"36\""))
294 << request_xml;
295}
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 ""};
316 const string request_xml = omaha_request.GetRequest();
317 EXPECT_EQ(1,
318 CountSubstringInString(request_xml,
319 "<ping active=\"1\" ad=\"25\" rd=\"36\""))
320 << request_xml;
321}
Amin Hassani7fca2862019-03-28 16:09:22 -0700322} // namespace chromeos_update_engine