mobile/android/base/tests/SessionTest.java

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 package org.mozilla.gecko.tests;
michael@0 2
michael@0 3 import java.io.File;
michael@0 4 import java.io.FileReader;
michael@0 5 import java.io.FileWriter;
michael@0 6 import java.io.IOException;
michael@0 7
michael@0 8 import org.json.JSONArray;
michael@0 9 import org.json.JSONException;
michael@0 10 import org.json.JSONObject;
michael@0 11 import org.mozilla.gecko.Actions;
michael@0 12 import org.mozilla.gecko.Assert;
michael@0 13 import org.mozilla.gecko.FennecMochitestAssert;
michael@0 14
michael@0 15 public abstract class SessionTest extends BaseTest {
michael@0 16 protected Navigation mNavigation;
michael@0 17
michael@0 18 @Override
michael@0 19 public void setUp() throws Exception {
michael@0 20 super.setUp();
michael@0 21
michael@0 22 mNavigation = new Navigation(mDevice);
michael@0 23 }
michael@0 24
michael@0 25 /**
michael@0 26 * A generic session object representing a collection of items that has a
michael@0 27 * selected index.
michael@0 28 */
michael@0 29 protected abstract class SessionObject<T> {
michael@0 30 private final int mIndex;
michael@0 31 private final T[] mItems;
michael@0 32
michael@0 33 public SessionObject(int index, T... items) {
michael@0 34 mIndex = index;
michael@0 35 mItems = items;
michael@0 36 }
michael@0 37
michael@0 38 public int getIndex() {
michael@0 39 return mIndex;
michael@0 40 }
michael@0 41
michael@0 42 public T[] getItems() {
michael@0 43 return mItems;
michael@0 44 }
michael@0 45 }
michael@0 46
michael@0 47 protected class PageInfo {
michael@0 48 private String url;
michael@0 49 private String title;
michael@0 50
michael@0 51 public PageInfo(String key) {
michael@0 52 if (key.startsWith("about:")) {
michael@0 53 url = key;
michael@0 54 } else {
michael@0 55 url = getPage(key);
michael@0 56 }
michael@0 57 title = key;
michael@0 58 }
michael@0 59 }
michael@0 60
michael@0 61 protected class SessionTab extends SessionObject<PageInfo> {
michael@0 62 public SessionTab(int index, PageInfo... items) {
michael@0 63 super(index, items);
michael@0 64 }
michael@0 65 }
michael@0 66
michael@0 67 protected class Session extends SessionObject<SessionTab> {
michael@0 68 public Session(int index, SessionTab... items) {
michael@0 69 super(index, items);
michael@0 70 }
michael@0 71 }
michael@0 72
michael@0 73 /**
michael@0 74 * Walker for visiting items in a browser-like navigation order.
michael@0 75 */
michael@0 76 protected abstract class NavigationWalker<T> {
michael@0 77 private final T[] mItems;
michael@0 78 private final int mIndex;
michael@0 79
michael@0 80 public NavigationWalker(SessionObject<T> obj) {
michael@0 81 mItems = obj.getItems();
michael@0 82 mIndex = obj.getIndex();
michael@0 83 }
michael@0 84
michael@0 85 /**
michael@0 86 * Walks over the list of items, calling the onItem() callback for each.
michael@0 87 *
michael@0 88 * The selected item is the first item visited. Each item after the
michael@0 89 * selected item is then visited in ascending index order. Finally, the
michael@0 90 * list is iterated in reverse, and each item before the selected item
michael@0 91 * is visited in descending index order.
michael@0 92 */
michael@0 93 public void walk() {
michael@0 94 onItem(mItems[mIndex], mIndex);
michael@0 95 for (int i = mIndex + 1; i < mItems.length; i++) {
michael@0 96 goForward();
michael@0 97 onItem(mItems[i], i);
michael@0 98 }
michael@0 99 if (mIndex > 0) {
michael@0 100 for (int i = mItems.length - 2; i >= 0; i--) {
michael@0 101 goBack();
michael@0 102 if (i < mIndex) {
michael@0 103 onItem(mItems[i], i);
michael@0 104 }
michael@0 105 }
michael@0 106 }
michael@0 107 }
michael@0 108
michael@0 109 /**
michael@0 110 * Callback when an item is visited during a walk.
michael@0 111 *
michael@0 112 * Only one callback is executed per item.
michael@0 113 */
michael@0 114 public abstract void onItem(T item, int currentIndex);
michael@0 115
michael@0 116 /**
michael@0 117 * Callback executed for each back step of the walk.
michael@0 118 */
michael@0 119 public void goBack() {}
michael@0 120
michael@0 121 /**
michael@0 122 * Callback executed for each forward step of the walk.
michael@0 123 */
michael@0 124 public void goForward() {}
michael@0 125 }
michael@0 126
michael@0 127 /**
michael@0 128 * Loads a set of tabs in the browser specified by the given session.
michael@0 129 *
michael@0 130 * @param session Session to load
michael@0 131 */
michael@0 132 protected void loadSessionTabs(Session session) {
michael@0 133 // Verify initial about:home tab
michael@0 134 verifyTabCount(1);
michael@0 135 verifyUrl("about:home");
michael@0 136
michael@0 137 SessionTab[] tabs = session.getItems();
michael@0 138 for (int i = 0; i < tabs.length; i++) {
michael@0 139 final SessionTab tab = tabs[i];
michael@0 140 final PageInfo[] pages = tab.getItems();
michael@0 141
michael@0 142 // New tabs always start with about:home, so make sure about:home
michael@0 143 // is always the first entry.
michael@0 144 mAsserter.is(pages[0].url, "about:home", "first page in tab is about:home");
michael@0 145
michael@0 146 // If this is the first tab, the tab already exists, so no need to
michael@0 147 // create a new one. Otherwise, create a new tab if we're loading
michael@0 148 // the first the first page in the set.
michael@0 149 if (i > 0) {
michael@0 150 addTab();
michael@0 151 }
michael@0 152
michael@0 153 for (int j = 1; j < pages.length; j++) {
michael@0 154 Actions.EventExpecter pageShowExpecter = mActions.expectGeckoEvent("Content:PageShow");
michael@0 155
michael@0 156 loadUrl(pages[j].url);
michael@0 157
michael@0 158 pageShowExpecter.blockForEvent();
michael@0 159 pageShowExpecter.unregisterListener();
michael@0 160 }
michael@0 161
michael@0 162 final int index = tab.getIndex();
michael@0 163 for (int j = pages.length - 1; j > index; j--) {
michael@0 164 mNavigation.back();
michael@0 165 }
michael@0 166 }
michael@0 167
michael@0 168 selectTabAt(session.getIndex());
michael@0 169 }
michael@0 170
michael@0 171 /**
michael@0 172 * Verifies that the set of open tabs matches the given session.
michael@0 173 *
michael@0 174 * @param session Session to verify
michael@0 175 */
michael@0 176 protected void verifySessionTabs(Session session) {
michael@0 177 verifyTabCount(session.getItems().length);
michael@0 178
michael@0 179 (new NavigationWalker<SessionTab>(session) {
michael@0 180 boolean mFirstTabVisited;
michael@0 181
michael@0 182 @Override
michael@0 183 public void onItem(SessionTab tab, int currentIndex) {
michael@0 184 // The first tab to check should already be selected at startup
michael@0 185 if (mFirstTabVisited) {
michael@0 186 selectTabAt(currentIndex);
michael@0 187 } else {
michael@0 188 mFirstTabVisited = true;
michael@0 189 }
michael@0 190
michael@0 191 (new NavigationWalker<PageInfo>(tab) {
michael@0 192 @Override
michael@0 193 public void onItem(PageInfo page, int currentIndex) {
michael@0 194 if (page.url.equals("about:home")) {
michael@0 195 waitForText("Enter Search or Address");
michael@0 196 verifyUrl(page.url);
michael@0 197 } else {
michael@0 198 waitForText(page.title);
michael@0 199 verifyPageTitle(page.title);
michael@0 200 }
michael@0 201 }
michael@0 202
michael@0 203 @Override
michael@0 204 public void goBack() {
michael@0 205 mNavigation.back();
michael@0 206 }
michael@0 207
michael@0 208 @Override
michael@0 209 public void goForward() {
michael@0 210 mNavigation.forward();
michael@0 211 }
michael@0 212 }).walk();
michael@0 213 }
michael@0 214 }).walk();
michael@0 215 }
michael@0 216
michael@0 217 /**
michael@0 218 * Gets session restore JSON corresponding to the open session.
michael@0 219 *
michael@0 220 * The JSON format follows the format used in Gecko for session restore and
michael@0 221 * should be interchangeable with the Gecko's generated sessionstore.js.
michael@0 222 *
michael@0 223 * @param session Session to serialize
michael@0 224 * @return JSON string of session
michael@0 225 */
michael@0 226 protected String buildSessionJSON(Session session) {
michael@0 227 final SessionTab[] sessionTabs = session.getItems();
michael@0 228 String sessionString = null;
michael@0 229
michael@0 230 try {
michael@0 231 final JSONArray tabs = new JSONArray();
michael@0 232
michael@0 233 for (int i = 0; i < sessionTabs.length; i++) {
michael@0 234 final JSONObject tab = new JSONObject();
michael@0 235 final JSONArray entries = new JSONArray();
michael@0 236 final SessionTab sessionTab = sessionTabs[i];
michael@0 237 final PageInfo[] pages = sessionTab.getItems();
michael@0 238
michael@0 239 for (int j = 0; j < pages.length; j++) {
michael@0 240 final PageInfo page = pages[j];
michael@0 241 final JSONObject entry = new JSONObject();
michael@0 242 entry.put("url", page.url);
michael@0 243 entry.put("title", page.title);
michael@0 244 entries.put(entry);
michael@0 245 }
michael@0 246
michael@0 247 tab.put("entries", entries);
michael@0 248 tab.put("index", sessionTab.getIndex() + 1);
michael@0 249 tabs.put(tab);
michael@0 250 }
michael@0 251
michael@0 252 JSONObject window = new JSONObject();
michael@0 253 window.put("tabs", tabs);
michael@0 254 window.put("selected", session.getIndex() + 1);
michael@0 255 sessionString = new JSONObject().put("windows", new JSONArray().put(window)).toString();
michael@0 256 } catch (JSONException e) {
michael@0 257 mAsserter.ok(false, "JSON exception", getStackTraceString(e));
michael@0 258 }
michael@0 259
michael@0 260 return sessionString;
michael@0 261 }
michael@0 262
michael@0 263 /**
michael@0 264 * @see SessionTest#verifySessionJSON(Session, String, Assert)
michael@0 265 */
michael@0 266 protected void verifySessionJSON(Session session, String sessionString) {
michael@0 267 verifySessionJSON(session, sessionString, mAsserter);
michael@0 268 }
michael@0 269
michael@0 270 /**
michael@0 271 * Verifies a session JSON string against the given session.
michael@0 272 *
michael@0 273 * @param session Session to verify against
michael@0 274 * @param sessionString JSON string to verify
michael@0 275 * @param asserter Assert class to use during verification
michael@0 276 */
michael@0 277 protected void verifySessionJSON(Session session, String sessionString, Assert asserter) {
michael@0 278 final SessionTab[] sessionTabs = session.getItems();
michael@0 279
michael@0 280 try {
michael@0 281 final JSONObject window = new JSONObject(sessionString).getJSONArray("windows").getJSONObject(0);
michael@0 282 final JSONArray tabs = window.getJSONArray("tabs");
michael@0 283 final int optSelected = window.optInt("selected", -1);
michael@0 284
michael@0 285 asserter.is(optSelected, session.getIndex() + 1, "selected tab matches");
michael@0 286
michael@0 287 for (int i = 0; i < tabs.length(); i++) {
michael@0 288 final JSONObject tab = tabs.getJSONObject(i);
michael@0 289 final int index = tab.getInt("index");
michael@0 290 final JSONArray entries = tab.getJSONArray("entries");
michael@0 291 final SessionTab sessionTab = sessionTabs[i];
michael@0 292 final PageInfo[] pages = sessionTab.getItems();
michael@0 293
michael@0 294 asserter.is(index, sessionTab.getIndex() + 1, "selected page index matches");
michael@0 295
michael@0 296 for (int j = 0; j < entries.length(); j++) {
michael@0 297 final JSONObject entry = entries.getJSONObject(j);
michael@0 298 final String url = entry.getString("url");
michael@0 299 final String title = entry.optString("title");
michael@0 300 final PageInfo page = pages[j];
michael@0 301
michael@0 302 asserter.is(url, page.url, "URL in JSON matches session URL");
michael@0 303 if (!page.url.startsWith("about:")) {
michael@0 304 asserter.is(title, page.title, "title in JSON matches session title");
michael@0 305 }
michael@0 306 }
michael@0 307 }
michael@0 308 } catch (JSONException e) {
michael@0 309 asserter.ok(false, "JSON exception", getStackTraceString(e));
michael@0 310 }
michael@0 311 }
michael@0 312
michael@0 313 /**
michael@0 314 * Exception thrown by NonFatalAsserter for assertion failures.
michael@0 315 */
michael@0 316 public static class AssertException extends RuntimeException {
michael@0 317 public AssertException(String msg) {
michael@0 318 super(msg);
michael@0 319 }
michael@0 320 }
michael@0 321
michael@0 322 /**
michael@0 323 * Asserter that throws an AssertException on failure instead of aborting
michael@0 324 * the test.
michael@0 325 *
michael@0 326 * This can be used in methods called via waitForCondition() where an assertion
michael@0 327 * might not immediately succeed.
michael@0 328 */
michael@0 329 public class NonFatalAsserter extends FennecMochitestAssert {
michael@0 330 @Override
michael@0 331 public void ok(boolean condition, String name, String diag) {
michael@0 332 if (!condition) {
michael@0 333 String details = (diag == null ? "" : " | " + diag);
michael@0 334 throw new AssertException("Assertion failed: " + name + details);
michael@0 335 }
michael@0 336 mAsserter.ok(condition, name, diag);
michael@0 337 }
michael@0 338 }
michael@0 339
michael@0 340 /**
michael@0 341 * Gets a URL for a dynamically-generated page.
michael@0 342 *
michael@0 343 * The page will have a URL unique to the given ID, and the page's title
michael@0 344 * will match the given ID.
michael@0 345 *
michael@0 346 * @param id ID used to generate page URL
michael@0 347 * @return URL of the page
michael@0 348 */
michael@0 349 protected String getPage(String id) {
michael@0 350 return getAbsoluteUrl("/robocop/robocop_dynamic.sjs?id=" + id);
michael@0 351 }
michael@0 352
michael@0 353 protected String readProfileFile(String filename) {
michael@0 354 try {
michael@0 355 return readFile(new File(mProfile, filename));
michael@0 356 } catch (IOException e) {
michael@0 357 mAsserter.ok(false, "Error reading" + filename, getStackTraceString(e));
michael@0 358 }
michael@0 359 return null;
michael@0 360 }
michael@0 361
michael@0 362 protected void writeProfileFile(String filename, String data) {
michael@0 363 try {
michael@0 364 writeFile(new File(mProfile, filename), data);
michael@0 365 } catch (IOException e) {
michael@0 366 mAsserter.ok(false, "Error writing to " + filename, getStackTraceString(e));
michael@0 367 }
michael@0 368 }
michael@0 369
michael@0 370 private String readFile(File target) throws IOException {
michael@0 371 if (!target.exists()) {
michael@0 372 return null;
michael@0 373 }
michael@0 374
michael@0 375 FileReader fr = new FileReader(target);
michael@0 376 try {
michael@0 377 StringBuffer sb = new StringBuffer();
michael@0 378 char[] buf = new char[8192];
michael@0 379 int read = fr.read(buf);
michael@0 380 while (read >= 0) {
michael@0 381 sb.append(buf, 0, read);
michael@0 382 read = fr.read(buf);
michael@0 383 }
michael@0 384 return sb.toString();
michael@0 385 } finally {
michael@0 386 fr.close();
michael@0 387 }
michael@0 388 }
michael@0 389
michael@0 390 private void writeFile(File target, String data) throws IOException {
michael@0 391 FileWriter writer = new FileWriter(target);
michael@0 392 try {
michael@0 393 writer.write(data);
michael@0 394 } finally {
michael@0 395 writer.close();
michael@0 396 }
michael@0 397 }
michael@0 398 }

mercurial