mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 03:35:33 +00:00
Bug 1461746 - 3. Add Promises API support in RDP client; r=snorp
Add support for monitoring Promises, so tests can wait on Promises that content returns. This makes it a lot easier to test Promise-based Web APIs such as getUserMedia. MozReview-Commit-ID: CHbeB7ErJgs --HG-- extra : rebase_source : ccb3e8f4523ebc11389bdafafc16045d8c9fe50e
This commit is contained in:
parent
bbb5f532eb
commit
f174b6c28a
@ -23,7 +23,7 @@ import java.util.Set;
|
||||
* Provide methods for interacting with grips, including unpacking grips into Java
|
||||
* objects.
|
||||
*/
|
||||
/* package */ final class Grip extends Actor {
|
||||
public class Grip extends Actor {
|
||||
|
||||
private static final class Cache extends HashMap<String, Object> {
|
||||
}
|
||||
@ -159,6 +159,22 @@ import java.util.Set;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LongString {
|
||||
private final int mLength;
|
||||
private final String mInitial;
|
||||
|
||||
public LongString(final int length, final @Nullable String initial) {
|
||||
mLength = length;
|
||||
mInitial = (initial != null && !initial.isEmpty()) ? initial.substring(0, 50) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[String(%d)]%s", mLength,
|
||||
(mInitial != null) ? "(" + mInitial + "\u2026)" : "");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack a received grip value into a Java object. The grip can be either a primitive
|
||||
* value, or a JSONObject that represents a live object on the server.
|
||||
@ -166,8 +182,8 @@ import java.util.Set;
|
||||
* @param connection Connection associated with this grip.
|
||||
* @param value Grip value received from the server.
|
||||
*/
|
||||
public static Object unpack(final RDPConnection connection,
|
||||
final Object value) {
|
||||
/* package */ static Object unpack(final @NonNull RDPConnection connection,
|
||||
final @Nullable Object value) {
|
||||
return unpackGrip(new Cache(), connection, value);
|
||||
}
|
||||
|
||||
@ -181,7 +197,8 @@ import java.util.Set;
|
||||
}
|
||||
|
||||
final JSONObject obj = (JSONObject) value;
|
||||
switch (obj.optString("type")) {
|
||||
final String type = obj.optString("type");
|
||||
switch (type) {
|
||||
case "null":
|
||||
case "undefined":
|
||||
return null;
|
||||
@ -193,10 +210,12 @@ import java.util.Set;
|
||||
return Double.NaN;
|
||||
case "-0":
|
||||
return -0.0;
|
||||
case "longString":
|
||||
return new LongString(obj.optInt("length"), obj.optString("initial"));
|
||||
case "object":
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException(String.valueOf(type));
|
||||
}
|
||||
|
||||
final String actor = obj.optString("actor", null);
|
||||
@ -213,6 +232,10 @@ import java.util.Set;
|
||||
final Function output = new Function(userDisplayName);
|
||||
cache.put(actor, output);
|
||||
return output;
|
||||
} else if ("Promise".equals(cls)) {
|
||||
final Promise output = new Promise(connection, obj);
|
||||
cache.put(actor, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
final JSONObject preview = obj.optJSONObject("preview");
|
||||
@ -249,7 +272,7 @@ import java.util.Set;
|
||||
}
|
||||
};
|
||||
|
||||
private Grip(final RDPConnection connection, final JSONObject grip) {
|
||||
/* package */ Grip(final @NonNull RDPConnection connection, final @NonNull JSONObject grip) {
|
||||
super(connection, grip);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,111 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.geckoview.test.rdp;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Object to represent a Promise object returned by JS.
|
||||
*/
|
||||
public final class Promise extends Grip {
|
||||
private JSONObject mGrip;
|
||||
private String mState;
|
||||
private Object mValue;
|
||||
private Object mReason;
|
||||
|
||||
/* package */ Promise(final @NonNull RDPConnection connection, final @NonNull JSONObject grip) {
|
||||
super(connection, grip);
|
||||
setPromiseState(grip);
|
||||
}
|
||||
|
||||
/* package */ void setPromiseState(final @NonNull JSONObject grip) {
|
||||
mGrip = grip;
|
||||
|
||||
final JSONObject state = grip.optJSONObject("promiseState");
|
||||
mState = state.optString("state");
|
||||
if (isFulfilled()) {
|
||||
mValue = Grip.unpack(connection, state.opt("value"));
|
||||
} else if (isRejected()) {
|
||||
mReason = Grip.unpack(connection, state.opt("reason"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this promise is pending.
|
||||
*
|
||||
* @return True if this promise is pending.
|
||||
*/
|
||||
public boolean isPending() {
|
||||
return "pending".equals(mState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this promise is fulfilled.
|
||||
*
|
||||
* @return True if this promise is fulfilled.
|
||||
*/
|
||||
public boolean isFulfilled() {
|
||||
return "fulfilled".equals(mState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the promise value, assuming it is fulfilled.
|
||||
*
|
||||
* @return Promise value.
|
||||
*/
|
||||
public @Nullable Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this promise is rejected.
|
||||
*
|
||||
* @return True if this promise is rejected.
|
||||
*/
|
||||
public boolean isRejected() {
|
||||
return "rejected".equals(mState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the promise reason, assuming it is rejected.
|
||||
*
|
||||
* @return Promise reason.
|
||||
*/
|
||||
public @Nullable Object getReason() {
|
||||
return mReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a property in this promise object.
|
||||
*
|
||||
* @return Value or null if there is no such property.
|
||||
*/
|
||||
public @Nullable Object getProperty(final @NonNull String name) {
|
||||
final JSONObject preview = mGrip.optJSONObject("preview");
|
||||
if (preview == null) {
|
||||
return null;
|
||||
}
|
||||
final JSONObject ownProperties = preview.optJSONObject("ownProperties");
|
||||
if (ownProperties == null) {
|
||||
return null;
|
||||
}
|
||||
final JSONObject prop = ownProperties.optJSONObject(name);
|
||||
if (prop == null) {
|
||||
return null;
|
||||
}
|
||||
return Grip.unpack(connection, prop.opt("value"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[Promise(" + mState + ")]" +
|
||||
(isFulfilled() ? "(" + mValue + ')' : "") +
|
||||
(isRejected() ? "(" + mReason + ')' : "");
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.geckoview.test.rdp;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provide access to the promises API.
|
||||
*/
|
||||
public final class Promises extends Actor {
|
||||
private final ReplyParser<Promise[]> PROMISE_LIST_PARSER = new ReplyParser<Promise[]>() {
|
||||
@Override
|
||||
public boolean canParse(@NonNull JSONObject packet) {
|
||||
return packet.has("promises");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Promise[] parse(@NonNull JSONObject packet) {
|
||||
return getPromisesFromArray(packet.optJSONArray("promises"),
|
||||
/* canCreate */ true);
|
||||
}
|
||||
};
|
||||
|
||||
private final Set<Promise> mPromises = new HashSet<>();
|
||||
|
||||
/* package */ Promises(final RDPConnection connection, final String name) {
|
||||
super(connection, name);
|
||||
attach();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach to the promises API.
|
||||
*/
|
||||
private void attach() {
|
||||
sendPacket("{\"type\":\"attach\"}", JSON_PARSER).get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach from the promises API.
|
||||
*/
|
||||
public void detach() {
|
||||
for (final Promise promise : mPromises) {
|
||||
promise.release();
|
||||
}
|
||||
sendPacket("{\"type\":\"detach\"}", JSON_PARSER).get();
|
||||
}
|
||||
|
||||
/* package */ Promise[] getPromisesFromArray(final @NonNull JSONArray array,
|
||||
final boolean canCreate) {
|
||||
final Promise[] promises = new Promise[array.length()];
|
||||
for (int i = 0; i < promises.length; i++) {
|
||||
final JSONObject grip = array.optJSONObject(i);
|
||||
final Promise promise = (Promise) connection.getActor(grip);
|
||||
if (promise != null) {
|
||||
promise.setPromiseState(grip);
|
||||
promises[i] = promise;
|
||||
} else if (canCreate) {
|
||||
promises[i] = new Promise(connection, grip);
|
||||
}
|
||||
}
|
||||
return promises;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of live promises.
|
||||
*
|
||||
* @returns List of promises.
|
||||
*/
|
||||
public @NonNull Promise[] listPromises() {
|
||||
final Promise[] promises = sendPacket("{\"type\":\"listPromises\"}",
|
||||
PROMISE_LIST_PARSER).get();
|
||||
mPromises.addAll(Arrays.asList(promises));
|
||||
return promises;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPacket(final @NonNull JSONObject packet) {
|
||||
final String type = packet.optString("type", null);
|
||||
if ("new-promises".equals(type)) {
|
||||
// We always call listPromises() to get updated Promises,
|
||||
// so that means we shouldn't handle "new-promises" here.
|
||||
} else if ("promises-settled".equals(type)) {
|
||||
// getPromisesFromArray will update states for us.
|
||||
getPromisesFromArray(packet.optJSONArray("data"),
|
||||
/* canCreate */ false);
|
||||
} else {
|
||||
super.onPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
@ -64,4 +64,15 @@ public final class Tab extends Actor {
|
||||
final Actor console = connection.getActor(name);
|
||||
return (console != null) ? (Console) console : new Console(connection, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the promises object for access to the promises API.
|
||||
*
|
||||
* @return Promises object.
|
||||
*/
|
||||
public Promises getPromises() {
|
||||
final String name = mTab.optString("promisesActor", null);
|
||||
final Actor promises = connection.getActor(name);
|
||||
return (promises != null) ? (Promises) promises : new Promises(connection, name);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user