1 // Copyright 2014 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.
5 package org.chromium.chrome.browser.omaha;
7 import android.test.InstrumentationTestCase;
8 import android.test.suitebuilder.annotation.SmallTest;
9 import android.util.Xml;
11 import org.chromium.base.test.util.Feature;
12 import org.xmlpull.v1.XmlSerializer;
14 import java.io.IOException;
15 import java.io.StringWriter;
18 * Unit tests for the Omaha ResponseParser.
20 public class ResponseParserTest extends InstrumentationTestCase {
21 // Note that the Omaha server appends "/" to the end of the URL codebase.
22 private static final String STRIPPED_URL =
23 "https://play.google.com/store/apps/details?id=com.google.android.apps.chrome";
24 private static final String URL = STRIPPED_URL + "/";
25 private static final String NEXT_VERSION = "1.2.3.4";
27 private static final String APP_STATUS_OK = "ok";
28 private static final String APP_STATUS_RESTRICTED = "restricted";
29 private static final String APP_STATUS_ERROR = "error-whatever-else";
31 private static final String UPDATE_STATUS_OK = "ok";
32 private static final String UPDATE_STATUS_NOUPDATE = "noupdate";
33 private static final String UPDATE_STATUS_ERROR = "error-osnotsupported";
34 private static final String UPDATE_STATUS_WTF = "omgwtfbbq";
37 * Create XML for testing.
38 * @param xmlProtocol Version number of the protocol. Expected to be "3.0" for valid XML.
39 * @param elapsedSeconds Number of seconds since server midnight.
40 * @param appStatus Status to use for the <app> element.
41 * @param addInstall Whether or not to add an install event.
42 * @param addPing Whether or not to add a ping event.
43 * @param updateStatus Status to use for the <updatecheck> element.
44 * @return The completed XML.
46 private static String createTestXML(String xmlProtocol, String elapsedSeconds,
47 String appStatus, boolean addInstall, boolean addPing, String updateStatus,
49 StringWriter writer = new StringWriter();
51 XmlSerializer serializer = Xml.newSerializer();
52 serializer.setOutput(writer);
53 serializer.startDocument("UTF-8", true);
55 // Set up <response ...>
56 serializer.startTag(null, "response");
57 serializer.attribute(null, "server", "prod");
58 if (xmlProtocol != null) {
59 serializer.attribute(null, "protocol", xmlProtocol);
62 // Create <daystart> element.
63 if (elapsedSeconds != null) {
64 serializer.startTag(null, "daystart");
65 serializer.attribute(null, "elapsed_seconds", elapsedSeconds);
66 serializer.endTag(null, "daystart");
69 // Create <app> element with unused attribute.
70 serializer.startTag(null, "app");
71 serializer.attribute(null, "appid", "{APP_ID}");
72 serializer.attribute(null, "status", appStatus);
73 serializer.attribute(null, "unused", "attribute");
76 serializer.startTag(null, "event");
77 serializer.attribute(null, "status", "ok");
78 serializer.endTag(null, "event");
82 serializer.startTag(null, "ping");
83 serializer.attribute(null, "status", "ok");
84 serializer.endTag(null, "ping");
87 if (updateStatus != null) {
88 serializer.startTag(null, "updatecheck");
89 serializer.attribute(null, "status", updateStatus);
90 if (UPDATE_STATUS_OK.equals(updateStatus)) {
91 createUpdateXML(serializer, updateUrl);
93 serializer.endTag(null, "updatecheck");
95 serializer.endTag(null, "app");
97 // Create extraneous tag.
98 serializer.startTag(null, "extraneous");
99 serializer.attribute(null, "useless", "yes");
100 serializer.endTag(null, "extraneous");
102 serializer.endTag(null, "response");
103 serializer.endDocument();
104 } catch (IOException e) {
105 fail("Caught an IOException creating the XML: " + e);
106 } catch (IllegalArgumentException e) {
107 fail("Caught an IllegalArgumentException creating the XML: " + e);
108 } catch (IllegalStateException e) {
109 fail("Caught an IllegalStateException creating the XML: " + e);
112 return writer.toString();
115 private static void createUpdateXML(XmlSerializer serializer, String updateUrl)
117 // End result should look something like:
118 // <updatecheck status="ok">
120 // <url codebase="URL" />
122 // <manifest garbage="attribute" version="NEXT_VERSION">
124 // <package hash="0" name="dummy.apk" required="true" size="0" />
127 // <action event="install" run="dummy.apk" />
128 // <action event="postinstall" />
131 // <better be="ignored" />
134 // Create <urls> and its descendants.
135 serializer.startTag(null, "urls");
136 if (updateUrl != null) {
137 serializer.startTag(null, "url");
138 serializer.attribute(null, "codebase", updateUrl);
139 serializer.endTag(null, "url");
141 serializer.endTag(null, "urls");
143 // Create <manifest> and its descendants.
144 serializer.startTag(null, "manifest");
145 serializer.attribute(null, "garbage", "attribute");
146 serializer.attribute(null, "version", NEXT_VERSION);
148 // Create <packages> and its children.
149 serializer.startTag(null, "packages");
150 serializer.startTag(null, "package");
151 serializer.attribute(null, "hash", "0");
152 serializer.attribute(null, "name", "dummy.apk");
153 serializer.attribute(null, "required", "true");
154 serializer.attribute(null, "size", "0");
155 serializer.endTag(null, "package");
156 serializer.endTag(null, "packages");
158 // Create <actions> and its children.
159 serializer.startTag(null, "actions");
160 serializer.startTag(null, "action");
161 serializer.attribute(null, "event", "install");
162 serializer.attribute(null, "run", "dummy.apk");
163 serializer.endTag(null, "action");
165 serializer.startTag(null, "action");
166 serializer.attribute(null, "event", "postinstall");
167 serializer.endTag(null, "action");
168 serializer.endTag(null, "actions");
169 serializer.endTag(null, "manifest");
171 // Create a dummy element for testing to make sure it's ignored.
172 serializer.startTag(null, "dummy");
173 serializer.attribute(null, "hopefully", "ignored");
174 serializer.endTag(null, "dummy");
178 * Runs a test that is expected to pass.
179 * @param appStatus Status to use for the <app> element.
180 * @param addInstall Whether or not to add an install event.
181 * @param addPing Whether or not to add a ping.
182 * @param updateStatus Status to use for the <updatecheck> element.
183 * @throws RequestFailureException Thrown if the test fails.
185 private static void runSuccessTest(String appStatus, boolean addInstall, boolean addPing,
186 String updateStatus) throws RequestFailureException {
188 createTestXML("3.0", "12345", appStatus, addInstall, addPing, updateStatus, URL);
189 ResponseParser parser =
190 new ResponseParser(true, "{APP_ID}", addInstall, addPing, updateStatus != null);
191 parser.parseResponse(xml);
193 assertEquals("elapsed_seconds doesn't match.", 12345, parser.getDaystartSeconds());
194 assertEquals("<app> status doesn't match.", appStatus, parser.getAppStatus());
195 assertEquals("<updatecheck> status doesn't match.", updateStatus, parser.getUpdateStatus());
196 if (UPDATE_STATUS_OK.equals(updateStatus)) {
197 assertEquals("Version number doesn't match.", "1.2.3.4", parser.getNewVersion());
198 assertEquals("Market URL doesn't match.", STRIPPED_URL, parser.getURL());
200 assertEquals("Version number doesn't match.", null, parser.getNewVersion());
201 assertEquals("Market URL doesn't match.", null, parser.getURL());
206 * Runs a test that is expected to fail in a particular way.
207 * @param xml XML to parse.
208 * @param expectedErrorCode Expected error code.
209 * @param expectInstall Whether or not the parser should expect an install event.
210 * @param expectPing Whether or not the parser should expect a ping element.
211 * @param expectUpdate Whether or not the parser should expect an update check.
213 private static void runFailureTest(String xml, int expectedErrorCode,
214 boolean expectInstall, boolean expectPing, boolean expectUpdate) {
215 ResponseParser parser =
216 new ResponseParser(true, "{APP_ID}", expectInstall, expectPing, expectUpdate);
219 parser.parseResponse(xml);
220 } catch (RequestFailureException e) {
221 assertEquals("Incorrect error code received.", expectedErrorCode, e.errorCode);
225 fail("Failed to throw RequestFailureException for bad XML.");
230 public void testValidAllTypes() throws RequestFailureException {
231 runSuccessTest(APP_STATUS_OK, true, true, UPDATE_STATUS_OK);
236 public void testValidNoInstall() throws RequestFailureException {
237 runSuccessTest(APP_STATUS_OK, false, true, UPDATE_STATUS_OK);
242 public void testValidNoPing() throws RequestFailureException {
243 runSuccessTest(APP_STATUS_OK, true, false, UPDATE_STATUS_OK);
248 public void testValidNoUpdatecheck() throws RequestFailureException {
249 runSuccessTest(APP_STATUS_OK, true, true, null);
254 public void testValidUpdatecheckNoUpdate() throws RequestFailureException {
255 runSuccessTest(APP_STATUS_OK, false, false, UPDATE_STATUS_NOUPDATE);
260 public void testValidUpdatecheckError() throws RequestFailureException {
261 runSuccessTest(APP_STATUS_OK, false, false, UPDATE_STATUS_ERROR);
266 public void testValidUpdatecheckUnknown() throws RequestFailureException {
267 runSuccessTest(APP_STATUS_OK, false, false, UPDATE_STATUS_WTF);
272 public void testValidAppStatusRestricted() throws RequestFailureException {
273 runSuccessTest(APP_STATUS_RESTRICTED, false, false, null);
278 public void testFailBogusResponse() {
279 String xml = "Bogus";
280 runFailureTest(xml, RequestFailureException.ERROR_MALFORMED_XML, false, false, false);
285 public void testBadResponseProtocol() {
287 createTestXML("2.0", "12345", APP_STATUS_OK, false, false, UPDATE_STATUS_OK, URL);
288 runFailureTest(xml, RequestFailureException.ERROR_PARSE_RESPONSE, false, false, false);
293 public void testFailMissingDaystart() {
295 createTestXML("3.0", null, APP_STATUS_OK, false, false, UPDATE_STATUS_OK, URL);
296 runFailureTest(xml, RequestFailureException.ERROR_PARSE_DAYSTART, false, false, true);
301 public void testAppTagMissingUpdatecheck() {
303 createTestXML("3.0", "12345", APP_STATUS_OK, true, false, null, URL);
304 runFailureTest(xml, RequestFailureException.ERROR_PARSE_UPDATECHECK, true, false, true);
309 public void testAppTagUnexpectedUpdatecheck() {
311 createTestXML("3.0", "12345", APP_STATUS_OK, true, false, UPDATE_STATUS_OK, URL);
312 runFailureTest(xml, RequestFailureException.ERROR_PARSE_UPDATECHECK, true, false, false);
317 public void testAppTagMissingPing() {
319 createTestXML("3.0", "12345", APP_STATUS_OK, false, false, UPDATE_STATUS_OK, URL);
320 runFailureTest(xml, RequestFailureException.ERROR_PARSE_PING, false, true, true);
325 public void testAppTagUnexpectedPing() {
327 createTestXML("3.0", "12345", APP_STATUS_OK, false, true, UPDATE_STATUS_OK, URL);
328 runFailureTest(xml, RequestFailureException.ERROR_PARSE_PING, false, false, true);
333 public void testAppTagMissingInstall() {
335 createTestXML("3.0", "12345", APP_STATUS_OK, false, false, UPDATE_STATUS_OK, URL);
336 runFailureTest(xml, RequestFailureException.ERROR_PARSE_EVENT, true, false, true);
341 public void testAppTagUnexpectedInstall() {
343 createTestXML("3.0", "12345", APP_STATUS_OK, true, false, UPDATE_STATUS_OK, URL);
344 runFailureTest(xml, RequestFailureException.ERROR_PARSE_EVENT, false, false, true);
349 public void testAppTagStatusError() {
351 createTestXML("3.0", "12345", APP_STATUS_ERROR, false, false, null, URL);
352 runFailureTest(xml, RequestFailureException.ERROR_PARSE_APP, false, false, false);
357 public void testUpdatecheckMissingUrl() {
358 String xml = createTestXML(
359 "3.0", "12345", APP_STATUS_OK, false, false, UPDATE_STATUS_OK, null);
360 runFailureTest(xml, RequestFailureException.ERROR_PARSE_URLS, false, false, true);