Merge inbound to mozilla-central. a=merge

This commit is contained in:
Narcis Beleuzu 2018-10-12 00:48:03 +03:00
Родитель 967600d2bd 5af51d1085
Коммит d30168f45c
30 изменённых файлов: 737 добавлений и 339 удалений

Просмотреть файл

@ -108,3 +108,4 @@ support-files =
support-files =
iframe_navigation.html
[browser_navigation_failures.js]
[browser_secure_transport_insecure_scheme.js]

Просмотреть файл

@ -0,0 +1,136 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that an insecure resource routed over a secure transport is considered
// insecure in terms of the site identity panel. We achieve this by running an
// HTTP-over-TLS "proxy" and having Firefox request an http:// URI over it.
// But first, a quick test that we don't incorrectly treat a
// blob:https://example.com URI as secure.
add_task(async function() {
let uri = getRootDirectory(gTestPath).replace("chrome://mochitests/content",
"https://example.com") + "dummy_page.html";
await BrowserTestUtils.withNewTab(uri, async (browser) => {
await ContentTask.spawn(browser, null, async () => {
Cu.importGlobalProperties(["Blob", "URL"]);
let debug = {hello: "world"};
let blob = new Blob([JSON.stringify(debug, null, 2)], {type: "application/json"});
let blobUri = URL.createObjectURL(blob);
content.document.location = blobUri;
});
await BrowserTestUtils.browserLoaded(browser);
let identityMode = window.document.getElementById("identity-box").className;
is(identityMode, "unknownIdentity", "identity should be 'unknown'");
});
});
// This server pretends to be a HTTP over TLS proxy. It isn't really, but this
// is sufficient for the purposes of this test.
function startServer(cert) {
let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"]
.createInstance(Ci.nsITLSServerSocket);
tlsServer.init(-1, true, -1);
tlsServer.serverCert = cert;
let input, output;
let listener = {
onSocketAccepted(socket, transport) {
let connectionInfo = transport.securityInfo
.QueryInterface(Ci.nsITLSServerConnectionInfo);
connectionInfo.setSecurityObserver(listener);
input = transport.openInputStream(0, 0, 0);
output = transport.openOutputStream(0, 0, 0);
},
onHandshakeDone(socket, status) {
input.asyncWait({
onInputStreamReady(readyInput) {
try {
let request = NetUtil.readInputStreamToString(readyInput,
readyInput.available());
ok(request.startsWith("GET ") && request.includes("HTTP/1.1"),
"expecting an HTTP/1.1 GET request");
let response = "HTTP/1.1 200 OK\r\nContent-Type:text/plain\r\n" +
"Connection:Close\r\nContent-Length:2\r\n\r\nOK";
output.write(response, response.length);
} catch (e) {
info(e);
}
},
}, 0, 0, Services.tm.currentThread);
},
onStopListening() {
input.close();
output.close();
},
};
tlsServer.setSessionTickets(false);
tlsServer.asyncListen(listener);
return tlsServer;
}
add_task(async function() {
await SpecialPowers.pushPrefEnv({
// This test fails on some platforms if we leave IPv6 enabled.
set: [["network.dns.disableIPv6", true]],
});
let certService = Cc["@mozilla.org/security/local-cert-service;1"]
.getService(Ci.nsILocalCertService);
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
.getService(Ci.nsICertOverrideService);
let cert = await new Promise((resolve, reject) => {
certService.getOrCreateCert("http-over-https-proxy", {
handleCert(c, rv) {
if (!Components.isSuccessCode(rv)) {
reject(rv);
return;
}
resolve(c);
},
});
});
// Start the proxy and configure Firefox to trust its certificate.
let server = startServer(cert);
let overrideBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED |
Ci.nsICertOverrideService.ERROR_MISMATCH;
certOverrideService.rememberValidityOverride("localhost", server.port, cert,
overrideBits, true);
// Configure Firefox to use the proxy.
let systemProxySettings = {
QueryInterface: ChromeUtils.generateQI([Ci.nsISystemProxySettings]),
mainThreadOnly: true,
PACURI: null,
getProxyForURI: (aSpec, aScheme, aHost, aPort) => {
return `HTTPS localhost:${server.port}`;
},
};
let oldProxyType = Services.prefs.getIntPref("network.proxy.type");
Services.prefs.setIntPref("network.proxy.type", Ci.nsIProtocolProxyService.PROXYCONFIG_SYSTEM);
let { MockRegistrar } = ChromeUtils.import("resource://testing-common/MockRegistrar.jsm", {});
let mockProxy = MockRegistrar.register("@mozilla.org/system-proxy-settings;1",
systemProxySettings);
// Register cleanup to undo the configuration changes we've made.
registerCleanupFunction(() => {
certOverrideService.clearValidityOverride("localhost", server.port);
Services.prefs.setIntPref("network.proxy.type", oldProxyType);
MockRegistrar.unregister(mockProxy);
server.close();
});
// Navigate to 'http://example.com'. Our proxy settings will route this via
// the "proxy" we just started. Even though our connection to the proxy is
// secure, in a real situation the connection from the proxy to
// http://example.com won't be secure, so we treat it as not secure.
await BrowserTestUtils.withNewTab("http://example.com/", async (browser) => {
let identityMode = window.document.getElementById("identity-box").className;
is(identityMode, "unknownIdentity", "identity should be 'unknown'");
});
});

Просмотреть файл

@ -7,15 +7,11 @@
const { PureComponent } = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { translateNodeFrontToGrip } = require("devtools/client/inspector/shared/utils");
loader.lazyGetter(this, "Rep", function() {
return require("devtools/client/shared/components/reps/reps").REPS.Rep;
});
loader.lazyGetter(this, "MODE", function() {
return require("devtools/client/shared/components/reps/reps").MODE;
});
loader.lazyRequireGetter(this, "translateNodeFrontToGrip", "devtools/client/inspector/shared/utils", true);
const { REPS, MODE } = require("devtools/client/shared/components/reps/reps");
const { Rep } = REPS;
const ElementNode = REPS.ElementNode;
const Types = require("../types");
@ -23,22 +19,35 @@ class FlexItem extends PureComponent {
static get propTypes() {
return {
flexItem: PropTypes.shape(Types.flexItem).isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired,
};
}
render() {
const { nodeFront } = this.props.flexItem;
const {
flexItem,
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
setSelectedNode,
} = this.props;
const { nodeFront } = flexItem;
return (
dom.li({},
dom.button(
{
className: "devtools-button devtools-monospace",
onClick: () => this.props.setSelectedNode(nodeFront),
onClick: () => {
setSelectedNode(nodeFront);
onHideBoxModelHighlighter();
},
onMouseOut: () => onHideBoxModelHighlighter(),
onMouseOver: () => onShowBoxModelHighlighterForNode(nodeFront),
},
Rep({
defaultRep: Rep.ElementNode,
defaultRep: ElementNode,
mode: MODE.TINY,
object: translateNodeFrontToGrip(nodeFront),
})

Просмотреть файл

@ -16,6 +16,8 @@ class FlexItemList extends PureComponent {
static get propTypes() {
return {
flexItems: PropTypes.arrayOf(PropTypes.shape(Types.flexItem)).isRequired,
onHideBoxModelHighlighter: PropTypes.func.isRequired,
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
setSelectedNode: PropTypes.func.isRequired,
};
}
@ -23,6 +25,8 @@ class FlexItemList extends PureComponent {
render() {
const {
flexItems,
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
setSelectedNode,
} = this.props;
@ -32,6 +36,8 @@ class FlexItemList extends PureComponent {
flexItems.map(flexItem => FlexItem({
key: flexItem.actorID,
flexItem,
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
setSelectedNode,
}))
)

Просмотреть файл

@ -47,23 +47,23 @@ class Flexbox extends PureComponent {
}
renderFlexContainerProperties() {
// Don't show the flex container properties for the parent flex container of the
// selected element.
if (this.props.flexContainer.isFlexItemContainer) {
return null;
}
return FlexContainerProperties({
properties: this.props.flexContainer.properties,
});
}
renderFlexItemList() {
const { setSelectedNode } = this.props;
const {
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
setSelectedNode,
} = this.props;
const { flexItems } = this.props.flexContainer;
return FlexItemList({
flexItems,
onHideBoxModelHighlighter,
onShowBoxModelHighlighterForNode,
setSelectedNode,
});
}
@ -133,7 +133,7 @@ class Flexbox extends PureComponent {
}),
!flexItemShown && flexItems.length > 0 ? this.renderFlexItemList() : null,
flexItemShown ? this.renderFlexItemSizing() : null,
this.renderFlexContainerProperties()
!flexItemShown ? this.renderFlexContainerProperties() : null
)
);
}

Просмотреть файл

@ -97,9 +97,14 @@ class Header extends PureComponent {
flexItems,
flexItemShown,
} = flexContainer;
const flexItem = flexItems.find(item => item.nodeFront.actorID === flexItemShown);
if (!flexItem) {
return null;
}
return FlexItemSelector({
flexItem: flexItems.find(item => item.nodeFront.actorID === flexItemShown),
flexItem,
flexItems,
setSelectedNode,
});

Просмотреть файл

@ -97,7 +97,6 @@
display: flex;
align-items: center;
height: 32px;
border-bottom: 1px solid var(--theme-splitter-color);
padding: 0 3px;
}
@ -123,8 +122,11 @@
* Flex Item List
*/
.flex-header + .flex-item-list {
border-block-start: 1px solid var(--theme-splitter-color);
}
.flex-item-list {
border-bottom: 1px solid var(--theme-splitter-color);
font-size: 12px;
margin: 0;
padding-inline-start: 34px;
@ -163,6 +165,7 @@
*/
.flex-outline-container {
border-block-start: 1px solid var(--theme-splitter-color);
display: flex;
justify-content: center;
}
@ -348,6 +351,7 @@
*/
#flex-container-properties {
border-block-start: 1px solid var(--theme-splitter-color);
margin-bottom: 5px;
}

Просмотреть файл

@ -58,7 +58,9 @@ DOM4_MSG_DEF(TypeError, "The expression cannot be converted to return the specif
/* IndexedDB errors http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#exceptions */
DOM4_MSG_DEF(UnknownError, "The operation failed for reasons unrelated to the database itself and not covered by any other error code.", NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR)
DOM4_MSG_DEF(ConstraintError, "A mutation operation in the transaction failed because a constraint was not satisfied. For example, an object such as an object store or index already exists and a new one was being attempted to be created.", NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR)
DOM4_MSG_DEF(ConstraintError, "A mutation operation in the transaction failed because a constraint was not satisfied.", NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR)
DOM4_MSG_DEF(ConstraintError, "Object store renamed to an already existing object store.", NS_ERROR_DOM_INDEXEDDB_RENAME_OBJECT_STORE_ERR)
DOM4_MSG_DEF(ConstraintError, "Index already exists and a new one was being attempted to be created.", NS_ERROR_DOM_INDEXEDDB_RENAME_INDEX_ERR)
DOM4_MSG_DEF(DataError, "Data provided to an operation does not meet requirements.", NS_ERROR_DOM_INDEXEDDB_DATA_ERR)
DOM4_MSG_DEF(DataError, "No key or key range specified.", NS_ERROR_DOM_INDEXEDDB_KEY_ERR)
DOM4_MSG_DEF(TransactionInactiveError, "A request was placed against a transaction which is currently not active, or which is finished.", NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR)
@ -72,7 +74,6 @@ DOM4_MSG_DEF(TimeoutError, "A lock for the transaction could not be obtained in
DOM4_MSG_DEF(QuotaExceededError, "The current transaction exceeded its quota limitations.", NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR)
/* A Non-standard IndexedDB error */
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR, "The operation failed because the database was prevented from taking an action. The operation might be able to succeed if the application performs some recovery steps and retries the entire transaction. For example, there was not enough remaining storage space, or the storage quota was reached and the user declined to give more space to the database.")
/* FileSystem DOM errors. */

Просмотреть файл

@ -449,7 +449,10 @@ IDBDatabase::CreateObjectStore(
index < count;
index++) {
if (aName == objectStores[index].metadata().name()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
aRv.ThrowDOMException(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR,
nsPrintfCString(
"Object store named '%s' already exists at index '%u'",
NS_ConvertUTF16toUTF8(aName).get(), index));
return nullptr;
}
}
@ -1323,7 +1326,7 @@ IDBDatabase::RenameObjectStore(int64_t aObjectStoreId, const nsAString& aName)
continue;
}
if (aName == objSpec.metadata().name()) {
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
return NS_ERROR_DOM_INDEXEDDB_RENAME_OBJECT_STORE_ERR;
}
}
@ -1371,7 +1374,7 @@ IDBDatabase::RenameIndex(int64_t aObjectStoreId,
continue;
}
if (aName == metadata.name()) {
return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
return NS_ERROR_DOM_INDEXEDDB_RENAME_INDEX_ERR;
}
}

Просмотреть файл

@ -2239,7 +2239,9 @@ IDBObjectStore::CreateIndex(const nsAString& aName,
index < count;
index++) {
if (aName == indexes[index].name()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
aRv.ThrowDOMException(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR,
nsPrintfCString("Index named '%s' already exists at index '%u'",
NS_ConvertUTF16toUTF8(aName).get(), index));
return nullptr;
}
}

Просмотреть файл

@ -29,6 +29,7 @@ support-files =
unit/test_blocked_order.js
unit/test_clear.js
unit/test_complex_keyPaths.js
unit/test_constraint_error_messages.js
unit/test_count.js
unit/test_create_index.js
unit/test_create_index_with_integer_keys.js
@ -138,6 +139,7 @@ skip-if = e10s && os == 'win' && os_version == '6.1' # Bug 1342415
[test_bug937006.html]
[test_clear.html]
[test_complex_keyPaths.html]
[test_constraint_error_messages.html]
[test_count.html]
[test_create_index.html]
[test_create_index_with_integer_keys.html]

Просмотреть файл

@ -0,0 +1,18 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Indexed Database Property Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="unit/test_constraint_error_messages.js"></script>
<script type="text/javascript" src="helpers.js"></script>
</head>
<body onload="runTest();"></body>
</html>

Просмотреть файл

@ -0,0 +1,64 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function* testSteps()
{
const name = this.window ? window.location.pathname : "Splendid Test";
const objectStoreName = "foo";
const indexName = "bar", keyPath = "bar";
info("Opening database");
let request = indexedDB.open(name);
request.onerror = errorHandler;
request.onupgradeneeded = grabEventAndContinueHandler;
request.onsuccess = unexpectedSuccessHandler;
let event = yield undefined;
let db = event.target.result;
info("Creating objectStore");
let objectStore = db.createObjectStore(objectStoreName);
info("Creating a duplicated object store to get an error");
try {
db.createObjectStore(objectStoreName);
ok(false,
"ConstraintError should be thrown if object store already exists");
} catch (e) {
ok(true, "ConstraintError should be thrown if object store already exists");
is(e.message,
"Object store named '" + objectStoreName +
"' already exists at index '0'",
"Threw with correct error message");
}
info("Creating an index");
objectStore.createIndex(indexName, keyPath);
info("Creating a duplicated indexes to verify the error message");
try {
objectStore.createIndex(indexName, keyPath);
ok(false, "ConstraintError should be thrown if index already exists");
} catch (e) {
ok(true, "ConstraintError should be thrown if index already exists");
is(e.message,
"Index named '" + indexName + "' already exists at index '0'",
"Threw with correct error message");
}
request.onsuccess = grabEventAndContinueHandler;
yield undefined;
db.close();
finishTest();
}

Просмотреть файл

@ -675,22 +675,6 @@ gfxDWriteFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle)
bool needsBold = aFontStyle->NeedsSyntheticBold(this);
DWRITE_FONT_SIMULATIONS sims =
needsBold ? DWRITE_FONT_SIMULATIONS_BOLD : DWRITE_FONT_SIMULATIONS_NONE;
if (HasVariations() && !aFontStyle->variationSettings.IsEmpty()) {
// If we need to apply variations, we can't use the cached mUnscaledFont
// or mUnscaledFontBold here.
// XXX todo: consider caching a small number of variation instances?
RefPtr<IDWriteFontFace> fontFace;
nsresult rv = CreateFontFace(getter_AddRefs(fontFace),
aFontStyle,
sims);
if (NS_FAILED(rv)) {
return nullptr;
}
RefPtr<UnscaledFontDWrite> unscaledFont =
new UnscaledFontDWrite(fontFace, mIsSystemFont ? mFont : nullptr, sims);
return new gfxDWriteFont(unscaledFont, this, aFontStyle);
}
ThreadSafeWeakPtr<UnscaledFontDWrite>& unscaledFontPtr =
needsBold ? mUnscaledFontBold : mUnscaledFont;
RefPtr<UnscaledFontDWrite> unscaledFont(unscaledFontPtr);
@ -705,7 +689,16 @@ gfxDWriteFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle)
mIsSystemFont ? mFont : nullptr, sims);
unscaledFontPtr = unscaledFont;
}
return new gfxDWriteFont(unscaledFont, this, aFontStyle);
RefPtr<IDWriteFontFace> fontFace;
if (HasVariations() && !aFontStyle->variationSettings.IsEmpty()) {
nsresult rv = CreateFontFace(getter_AddRefs(fontFace),
aFontStyle,
sims);
if (NS_FAILED(rv)) {
return nullptr;
}
}
return new gfxDWriteFont(unscaledFont, this, aFontStyle, fontFace);
}
nsresult

Просмотреть файл

@ -81,8 +81,10 @@ GetSystemTextQuality()
gfxDWriteFont::gfxDWriteFont(const RefPtr<UnscaledFontDWrite>& aUnscaledFont,
gfxFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle,
RefPtr<IDWriteFontFace> aFontFace,
AntialiasOption anAAOption)
: gfxFont(aUnscaledFont, aFontEntry, aFontStyle, anAAOption)
, mFontFace(aFontFace ? aFontFace : aUnscaledFont->GetFontFace())
, mCairoFontFace(nullptr)
, mMetrics(nullptr)
, mSpaceGlyph(0)
@ -90,8 +92,6 @@ gfxDWriteFont::gfxDWriteFont(const RefPtr<UnscaledFontDWrite>& aUnscaledFont,
, mAllowManualShowGlyphs(true)
, mAzureScaledFontUsedClearType(false)
{
mFontFace = aUnscaledFont->GetFontFace();
// If the IDWriteFontFace1 interface is available, we can use that for
// faster glyph width retrieval.
mFontFace->QueryInterface(__uuidof(IDWriteFontFace1),
@ -150,7 +150,7 @@ gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
{
auto entry = static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
RefPtr<UnscaledFontDWrite> unscaledFont = static_cast<UnscaledFontDWrite*>(mUnscaledFont.get());
return MakeUnique<gfxDWriteFont>(unscaledFont, entry, &mStyle, anAAOption);
return MakeUnique<gfxDWriteFont>(unscaledFont, entry, &mStyle, mFontFace, anAAOption);
}
const gfxFont::Metrics&

Просмотреть файл

@ -30,6 +30,7 @@ public:
gfxDWriteFont(const RefPtr<mozilla::gfx::UnscaledFontDWrite>& aUnscaledFont,
gfxFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle,
RefPtr<IDWriteFontFace> aFontFace = nullptr,
AntialiasOption = kAntialiasDefault);
~gfxDWriteFont();

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Logging.h"
#include "mozilla/Unused.h"
#include "nsContentUtils.h"
#include "nsIChannel.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
@ -206,6 +207,71 @@ nsSecureBrowserUIImpl::CheckForBlockedContent()
}
}
// Helper function to determine if the given URI can be considered secure.
// Essentially, only "https" URIs can be considered secure. However, the URI we
// have may be e.g. view-source:https://example.com or
// wyciwyg://https://example.com, in which case we have to evaluate the
// innermost URI.
static nsresult
URICanBeConsideredSecure(nsIURI* uri, /* out */ bool& canBeConsideredSecure)
{
MOZ_ASSERT(uri);
NS_ENSURE_ARG(uri);
canBeConsideredSecure = false;
nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(uri);
if (!innermostURI) {
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" couldn't get innermost URI"));
return NS_ERROR_FAILURE;
}
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" innermost URI is '%s'", innermostURI->GetSpecOrDefault().get()));
// Unfortunately, wyciwyg URIs don't know about innermost URIs, so we have to
// manually get the innermost URI if we have such a URI.
bool isWyciwyg;
nsresult rv = innermostURI->SchemeIs("wyciwyg", &isWyciwyg);
if (NS_FAILED(rv)) {
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" nsIURI->SchemeIs failed"));
return rv;
}
if (isWyciwyg) {
nsCOMPtr<nsIURI> nonWyciwygURI;
rv = nsContentUtils::RemoveWyciwygScheme(innermostURI,
getter_AddRefs(nonWyciwygURI));
if (NS_FAILED(rv)) {
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" nsContentUtils::RemoveWyciwygScheme failed"));
return rv;
}
if (!nonWyciwygURI) {
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" apparently that wasn't a valid wyciwyg URI"));
return NS_ERROR_FAILURE;
}
innermostURI = nonWyciwygURI;
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" innermost URI is now '%s'",
innermostURI->GetSpecOrDefault().get()));
}
bool isHttps;
rv = innermostURI->SchemeIs("https", &isHttps);
if (NS_FAILED(rv)) {
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" nsIURI->SchemeIs failed"));
return rv;
}
canBeConsideredSecure = isHttps;
return NS_OK;
}
// Helper function to get the securityInfo from a channel as a
// nsITransportSecurityInfo. The out parameter will be set to null if there is
// no securityInfo set.
@ -246,13 +312,27 @@ nsSecureBrowserUIImpl::UpdateStateAndSecurityInfo(nsIChannel* channel,
mState = STATE_IS_INSECURE;
mTopLevelSecurityInfo = nullptr;
// Only https is considered secure (it is possible to have e.g. an http URI
// with a channel that has a securityInfo that indicates the connection is
// secure - e.g. h2/alt-svc or by visiting an http URI over an https proxy).
bool canBeConsideredSecure;
nsresult rv = URICanBeConsideredSecure(uri, canBeConsideredSecure);
if (NS_FAILED(rv)) {
return rv;
}
if (!canBeConsideredSecure) {
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" URI can't be considered secure"));
return NS_OK;
}
nsCOMPtr<nsITransportSecurityInfo> securityInfo;
GetSecurityInfoFromChannel(channel, getter_AddRefs(securityInfo));
if (securityInfo) {
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" we have a security info %p", securityInfo.get()));
nsresult rv = securityInfo->GetSecurityState(&mState);
rv = securityInfo->GetSecurityState(&mState);
if (NS_FAILED(rv)) {
return rv;
}
@ -329,8 +409,15 @@ nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" we have a channel %p", channel.get()));
nsresult rv = UpdateStateAndSecurityInfo(channel, aLocation);
// Even if this failed, we still want to notify downstream so that we don't
// leave a stale security indicator. We set everything to "not secure" to be
// safe.
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug,
(" Failed to update security info. "
"Setting everything to 'not secure' to be safe."));
mState = STATE_IS_INSECURE;
mTopLevelSecurityInfo = nullptr;
}
}

Просмотреть файл

@ -2,6 +2,7 @@
"use strict";
document.open();
// This test depends on nsSecureBrowserUIImpl handling wyciwyg:https:// URIs properly.
// eslint-disable-next-line no-unsanitized/method
document.write("This is insecure XSS script " + document.cookie);
isSecurityState("broken", "security broken after document write from unsecure script");

Просмотреть файл

@ -443,16 +443,6 @@ class FennecInstance(GeckoInstance):
exc, val, tb = sys.exc_info()
message = "Error possibly due to runner or device args: {}"
reraise(exc, message.format(e.message), tb)
# gecko_log comes from logcat when running with device/emulator
logcat_args = {
"filterspec": "Gecko",
"serial": self.runner.device.app_ctx.device_serial
}
if self.gecko_log == "-":
logcat_args["stream"] = sys.stdout
else:
logcat_args["logfile"] = self.gecko_log
self.runner.device.start_logcat(**logcat_args)
# forward marionette port
self.runner.device.device.forward(

Просмотреть файл

@ -13,12 +13,10 @@ import tempfile
import time
from mozdevice import ADBHost, ADBError
from mozprocess import ProcessHandler
class Device(object):
connected = False
logcat_proc = None
def __init__(self, app_ctx, logdir=None, serial=None, restore=True):
self.app_ctx = app_ctx
@ -141,28 +139,6 @@ class Device(object):
self.connected = True
if self.logdir:
# save logcat
logcat_log = os.path.join(self.logdir, '%s.log' % self.serial)
if os.path.isfile(logcat_log):
self._rotate_log(logcat_log)
self.logcat_proc = self.start_logcat(self.serial, logfile=logcat_log)
def start_logcat(self, serial, logfile=None, stream=None, filterspec=None):
logcat_args = [self.app_ctx.adb, '-s', '%s' % serial,
'logcat', '-v', 'time', '-b', 'main', '-b', 'radio']
# only log filterspec
if filterspec:
logcat_args.extend(['-s', filterspec])
process_args = {}
if logfile:
process_args['logfile'] = logfile
elif stream:
process_args['stream'] = stream
proc = ProcessHandler(logcat_args, **process_args)
proc.run()
return proc
def reboot(self):
"""
Reboots the device via adb.

Просмотреть файл

@ -101,7 +101,7 @@ def FennecEmulatorRunner(avd='mozemulator-4.3',
Typically obtained via tooltool: either 'mozemulator-4.3' or 'mozemulator-x86'.
Defaults to 'mozemulator-4.3'
:param avd_home: Path to avd parent directory
:param logdir: Path to save logfiles such as logcat and qemu output.
:param logdir: Path to save logfiles such as qemu output.
:param serial: Serial of emulator to connect to as seen in `adb devices`.
Defaults to the first entry in `adb devices`.
:param binary: Path to emulator binary.

Просмотреть файл

@ -0,0 +1,50 @@
# ***** BEGIN LICENSE BLOCK *****
# 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/.
# ***** END LICENSE BLOCK *****
import os
config = {
"options": [
"--prefs-root=%(test_path)s/prefs",
"--processes=1",
"--config=%(test_path)s/wptrunner.ini",
"--ca-cert-path=%(test_path)s/tests/tools/certs/cacert.pem",
"--host-key-path=%(test_path)s/tests/tools/certs/web-platform.test.key",
"--host-cert-path=%(test_path)s/tests/tools/certs/web-platform.test.pem",
"--certutil-binary=%(xre_path)s/certutil",
"--product=fennec",
],
"avds_dir": "/builds/worker/workspace/build/.android",
"binary_path": "/tmp",
"download_minidump_stackwalk": False,
"emulator_avd_name": "test-1",
"emulator_extra_args": "-gpu swiftshader_indirect -skip-adb-auth -verbose -show-kernel -use-system-libs -ranchu -selinux permissive -memory 3072 -cores 4",
"emulator_manifest": """
[
{
"size": 135064025,
"digest": "125678c5b0d93ead8bbf01ba94253e532909417b40637460624cfca34e92f431534fc77a0225e9c4728dcbcf2884a8f7fa1ee059efdfa82d827ca20477d41705",
"algorithm": "sha512",
"filename": "android-sdk_r27.1.12-linux-x86emu.tar.gz",
"unpack": "True"
}
] """,
"emulator_process_name": "emulator64-x86",
"env": {
"PATH": "%(PATH)s:%(abs_work_dir)s/android-sdk-linux/emulator:%(abs_work_dir)s/android-sdk-linux/tools:%(abs_work_dir)s/android-sdk-linux/platform-tools",
},
"exes": {
'adb': '%(abs_work_dir)s/android-sdk-linux/platform-tools/adb',
},
"geckodriver": "%(abs_test_bin_dir)s/geckodriver",
"hostutils_manifest_path": "testing/config/tooltool-manifests/linux64/hostutils.manifest",
"log_tbpl_level": "info",
"log_raw_level": "info",
"minidump_stackwalk_path": "/usr/local/bin/linux64-minidump_stackwalk",
"per_test_category": "web-platform",
"tooltool_cache": os.environ.get("TOOLTOOL_CACHE"),
"tooltool_manifest_path": "testing/config/tooltool-manifests/androidx86_7_0/releng.manifest",
"tooltool_servers": ['http://relengapi/tooltool/'],
}

Просмотреть файл

@ -5,12 +5,16 @@
# You can obtain one at http://mozilla.org/MPL/2.0/.
# ***** END LICENSE BLOCK *****
import datetime
import glob
import os
import re
import signal
import subprocess
import time
import tempfile
from mozharness.mozilla.automation import TBPL_RETRY, EXIT_STATUS_DICT
from mozharness.base.script import PostScriptAction
class AndroidMixin(object):
@ -21,6 +25,7 @@ class AndroidMixin(object):
def __init__(self, **kwargs):
self._adb_path = None
self._device = None
self.app_name = None
self.device_name = os.environ.get('DEVICE_NAME', None)
self.device_serial = os.environ.get('DEVICE_SERIAL', None)
self.device_ip = os.environ.get('DEVICE_IP', None)
@ -63,6 +68,24 @@ class AndroidMixin(object):
pass
return self._device
@property
def is_android(self):
try:
c = self.config
installer_url = c.get('installer_url', None)
return self.device_serial is not None or self.is_emulator or \
(installer_url is not None and installer_url.endswith(".apk"))
except AttributeError:
return False
@property
def is_emulator(self):
try:
c = self.config
return True if c.get('emulator_manifest') else False
except AttributeError:
return False
def _get_repo_url(self, path):
"""
Return a url for a file (typically a tooltool manifest) in this hg repo
@ -102,6 +125,112 @@ class AndroidMixin(object):
output_dir=dir,
cache=c.get("tooltool_cache", None))
def _launch_emulator(self):
env = self.query_env()
# Write a default ddms.cfg to avoid unwanted prompts
avd_home_dir = self.abs_dirs['abs_avds_dir']
DDMS_FILE = os.path.join(avd_home_dir, "ddms.cfg")
with open(DDMS_FILE, 'w') as f:
f.write("pingOptIn=false\npingId=0\n")
self.info("wrote dummy %s" % DDMS_FILE)
# Delete emulator auth file, so it doesn't prompt
AUTH_FILE = os.path.join(os.path.expanduser('~'), '.emulator_console_auth_token')
if os.path.exists(AUTH_FILE):
try:
os.remove(AUTH_FILE)
self.info("deleted %s" % AUTH_FILE)
except Exception:
self.warning("failed to remove %s" % AUTH_FILE)
avd_path = os.path.join(avd_home_dir, 'avd')
if os.path.exists(avd_path):
env['ANDROID_AVD_HOME'] = avd_path
self.info("Found avds at %s" % avd_path)
else:
self.warning("AVDs missing? Not found at %s" % avd_path)
if "deprecated_sdk_path" in self.config:
sdk_path = os.path.abspath(os.path.join(avd_home_dir, '..'))
else:
sdk_path = os.path.join(self.abs_dirs['abs_work_dir'], 'android-sdk-linux')
if os.path.exists(sdk_path):
env['ANDROID_SDK_HOME'] = sdk_path
self.info("Found sdk at %s" % sdk_path)
else:
self.warning("Android sdk missing? Not found at %s" % sdk_path)
# extra diagnostics for kvm acceleration
emu = self.config.get('emulator_process_name')
if os.path.exists('/dev/kvm') and emu and 'x86' in emu:
try:
self.run_command(['ls', '-l', '/dev/kvm'])
self.run_command(['kvm-ok'])
self.run_command(["emulator", "-accel-check"], env=env)
except Exception as e:
self.warning("Extra kvm diagnostics failed: %s" % str(e))
command = ["emulator", "-avd", self.config["emulator_avd_name"]]
if "emulator_extra_args" in self.config:
command += self.config["emulator_extra_args"].split()
dir = self.query_abs_dirs()['abs_blob_upload_dir']
tmp_file = tempfile.NamedTemporaryFile(mode='w', prefix='emulator-',
suffix='.log', dir=dir, delete=False)
self.info("Launching the emulator with: %s" % ' '.join(command))
self.info("Writing log to %s" % tmp_file.name)
proc = subprocess.Popen(command, stdout=tmp_file, stderr=tmp_file, env=env, bufsize=0)
return proc
def _verify_emulator(self):
boot_ok = self._retry(30, 10, self.is_boot_completed, "Verify Android boot completed",
max_time=330)
if not boot_ok:
self.warning('Unable to verify Android boot completion')
return False
return True
def _verify_emulator_and_restart_on_fail(self):
emulator_ok = self._verify_emulator()
if not emulator_ok:
self.screenshot("emulator-startup-screenshot-")
self.kill_processes(self.config["emulator_process_name"])
subprocess.check_call(['ps', '-ef'])
# remove emulator tmp files
for dir in glob.glob("/tmp/android-*"):
self.rmtree(dir)
time.sleep(5)
self.emulator_proc = self._launch_emulator()
return emulator_ok
def _retry(self, max_attempts, interval, func, description, max_time=0):
'''
Execute func until it returns True, up to max_attempts times, waiting for
interval seconds between each attempt. description is logged on each attempt.
If max_time is specified, no further attempts will be made once max_time
seconds have elapsed; this provides some protection for the case where
the run-time for func is long or highly variable.
'''
status = False
attempts = 0
if max_time > 0:
end_time = datetime.datetime.now() + datetime.timedelta(seconds=max_time)
else:
end_time = None
while attempts < max_attempts and not status:
if (end_time is not None) and (datetime.datetime.now() > end_time):
self.info("Maximum retry run-time of %d seconds exceeded; "
"remaining attempts abandoned" % max_time)
break
if attempts != 0:
self.info("Sleeping %d seconds" % interval)
time.sleep(interval)
attempts += 1
self.info(">> %s: Attempt #%d of %d" % (description, attempts, max_attempts))
status = func()
return status
def dump_perf_info(self):
'''
Dump some host and android device performance-related information
@ -161,7 +290,6 @@ class AndroidMixin(object):
"""
Start recording logcat. Writes logcat to the upload directory.
"""
self.mkdir_p(self.query_abs_dirs()['abs_blob_upload_dir'])
# Start logcat for the device. The adb process runs until the
# corresponding device is stopped. Output is written directly to
# the blobber upload directory so that it is uploaded automatically
@ -268,3 +396,112 @@ class AndroidMixin(object):
self.run_command(unzip_cmd, cwd=apk_dir, halt_on_failure=True)
self.app_name = str(self.read_from_file(package_path, verbose=True)).rstrip()
return self.app_name
def kill_processes(self, process_name):
self.info("Killing every process called %s" % process_name)
out = subprocess.check_output(['ps', '-A'])
for line in out.splitlines():
if process_name in line:
pid = int(line.split(None, 1)[0])
self.info("Killing pid %d." % pid)
os.kill(pid, signal.SIGKILL)
# Script actions
def setup_avds(self):
"""
If tooltool cache mechanism is enabled, the cached version is used by
the fetch command. If the manifest includes an "unpack" field, tooltool
will unpack all compressed archives mentioned in the manifest.
"""
if not self.is_emulator:
return
c = self.config
dirs = self.query_abs_dirs()
self.mkdir_p(dirs['abs_work_dir'])
self.mkdir_p(dirs['abs_blob_upload_dir'])
# Always start with a clean AVD: AVD includes Android images
# which can be stateful.
self.rmtree(dirs['abs_avds_dir'])
self.mkdir_p(dirs['abs_avds_dir'])
if 'avd_url' in c:
# Intended for experimental setups to evaluate an avd prior to
# tooltool deployment.
url = c['avd_url']
self.download_unpack(url, dirs['abs_avds_dir'])
else:
url = self._get_repo_url(c["tooltool_manifest_path"])
self._tooltool_fetch(url, dirs['abs_avds_dir'])
avd_home_dir = self.abs_dirs['abs_avds_dir']
if avd_home_dir != "/home/cltbld/.android":
# Modify the downloaded avds to point to the right directory.
cmd = [
'bash', '-c',
'sed -i "s|/home/cltbld/.android|%s|" %s/test-*.ini' %
(avd_home_dir, os.path.join(avd_home_dir, 'avd'))
]
subprocess.check_call(cmd)
def start_emulator(self):
"""
Starts the emulator
"""
if not self.is_emulator:
return
if 'emulator_url' in self.config or 'emulator_manifest' in self.config:
dirs = self.query_abs_dirs()
if self.config.get('emulator_url'):
self.download_unpack(self.config['emulator_url'], dirs['abs_work_dir'])
elif self.config.get('emulator_manifest'):
manifest_path = self.create_tooltool_manifest(self.config['emulator_manifest'])
dirs = self.query_abs_dirs()
cache = self.config.get("tooltool_cache", None)
if self.tooltool_fetch(manifest_path,
output_dir=dirs['abs_work_dir'],
cache=cache):
self.fatal("Unable to download emulator via tooltool!")
else:
self.fatal("Cannot get emulator: configure emulator_url or emulator_manifest")
if not os.path.isfile(self.adb_path):
self.fatal("The adb binary '%s' is not a valid file!" % self.adb_path)
self.kill_processes("xpcshell")
self.emulator_proc = self._launch_emulator()
def verify_device(self):
"""
Check to see if the emulator can be contacted via adb.
If any communication attempt fails, kill the emulator, re-launch, and re-check.
"""
if not self.is_android:
return
if self.is_emulator:
max_restarts = 5
emulator_ok = self._retry(max_restarts, 10,
self._verify_emulator_and_restart_on_fail,
"Check emulator")
if not emulator_ok:
self.fatal('INFRA-ERROR: Unable to start emulator after %d attempts'
% max_restarts, EXIT_STATUS_DICT[TBPL_RETRY])
self.mkdir_p(self.query_abs_dirs()['abs_blob_upload_dir'])
self.dump_perf_info()
self.logcat_start()
# Get a post-boot device process list for diagnostics
self.info(self.shell_output('ps'))
@PostScriptAction('run-tests')
def stop_device(self, action, success=None):
"""
Stop logcat and kill the emulator, if necessary.
"""
if not self.is_android:
return
self.logcat_stop()
if self.is_emulator:
self.kill_processes(self.config["emulator_process_name"])

Просмотреть файл

@ -7,23 +7,16 @@
import copy
import datetime
import glob
import os
import re
import sys
import signal
import subprocess
import time
import tempfile
# load modules from parent dir
sys.path.insert(1, os.path.dirname(sys.path[0]))
from mozprocess import ProcessHandler
from mozharness.base.log import FATAL
from mozharness.base.script import BaseScript, PreScriptAction, PostScriptAction
from mozharness.mozilla.automation import TBPL_RETRY, EXIT_STATUS_DICT
from mozharness.base.script import BaseScript, PreScriptAction
from mozharness.mozilla.mozbase import MozbaseMixin
from mozharness.mozilla.testing.android import AndroidMixin
from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
@ -85,8 +78,6 @@ class AndroidEmulatorTest(TestingMixin, BaseScript, MozbaseMixin, CodeCoverageMi
]] + copy.deepcopy(testing_config_options) + \
copy.deepcopy(code_coverage_config_options)
app_name = None
def __init__(self, require_config_file=False):
super(AndroidEmulatorTest, self).__init__(
config_options=self.config_options,
@ -173,124 +164,6 @@ class AndroidEmulatorTest(TestingMixin, BaseScript, MozbaseMixin, CodeCoverageMi
test_dir = test_suite
return os.path.join(dirs['abs_test_install_dir'], test_dir)
def _launch_emulator(self):
env = self.query_env()
# Write a default ddms.cfg to avoid unwanted prompts
avd_home_dir = self.abs_dirs['abs_avds_dir']
DDMS_FILE = os.path.join(avd_home_dir, "ddms.cfg")
with open(DDMS_FILE, 'w') as f:
f.write("pingOptIn=false\npingId=0\n")
self.info("wrote dummy %s" % DDMS_FILE)
# Delete emulator auth file, so it doesn't prompt
AUTH_FILE = os.path.join(os.path.expanduser('~'), '.emulator_console_auth_token')
if os.path.exists(AUTH_FILE):
try:
os.remove(AUTH_FILE)
self.info("deleted %s" % AUTH_FILE)
except Exception:
self.warning("failed to remove %s" % AUTH_FILE)
avd_path = os.path.join(avd_home_dir, 'avd')
if os.path.exists(avd_path):
env['ANDROID_AVD_HOME'] = avd_path
self.info("Found avds at %s" % avd_path)
else:
self.warning("AVDs missing? Not found at %s" % avd_path)
if "deprecated_sdk_path" in self.config:
sdk_path = os.path.abspath(os.path.join(avd_home_dir, '..'))
else:
sdk_path = os.path.join(self.abs_dirs['abs_work_dir'], 'android-sdk-linux')
if os.path.exists(sdk_path):
env['ANDROID_SDK_HOME'] = sdk_path
self.info("Found sdk at %s" % sdk_path)
else:
self.warning("Android sdk missing? Not found at %s" % sdk_path)
# extra diagnostics for kvm acceleration
emu = self.config.get('emulator_process_name')
if os.path.exists('/dev/kvm') and emu and 'x86' in emu:
try:
self.run_command(['ls', '-l', '/dev/kvm'])
self.run_command(['kvm-ok'])
self.run_command(["emulator", "-accel-check"], env=env)
except Exception as e:
self.warning("Extra kvm diagnostics failed: %s" % str(e))
command = ["emulator", "-avd", self.config["emulator_avd_name"]]
if "emulator_extra_args" in self.config:
command += self.config["emulator_extra_args"].split()
dir = self.query_abs_dirs()['abs_blob_upload_dir']
tmp_file = tempfile.NamedTemporaryFile(mode='w', prefix='emulator-',
suffix='.log', dir=dir, delete=False)
self.info("Launching the emulator with: %s" % ' '.join(command))
self.info("Writing log to %s" % tmp_file.name)
proc = subprocess.Popen(command, stdout=tmp_file, stderr=tmp_file, env=env, bufsize=0)
return {
"process": proc,
}
def _retry(self, max_attempts, interval, func, description, max_time=0):
'''
Execute func until it returns True, up to max_attempts times, waiting for
interval seconds between each attempt. description is logged on each attempt.
If max_time is specified, no further attempts will be made once max_time
seconds have elapsed; this provides some protection for the case where
the run-time for func is long or highly variable.
'''
status = False
attempts = 0
if max_time > 0:
end_time = datetime.datetime.now() + datetime.timedelta(seconds=max_time)
else:
end_time = None
while attempts < max_attempts and not status:
if (end_time is not None) and (datetime.datetime.now() > end_time):
self.info("Maximum retry run-time of %d seconds exceeded; "
"remaining attempts abandoned" % max_time)
break
if attempts != 0:
self.info("Sleeping %d seconds" % interval)
time.sleep(interval)
attempts += 1
self.info(">> %s: Attempt #%d of %d" % (description, attempts, max_attempts))
status = func()
return status
def _verify_emulator(self):
boot_ok = self._retry(30, 10, self.is_boot_completed, "Verify Android boot completed",
max_time=330)
if not boot_ok:
self.warning('Unable to verify Android boot completion')
return False
return True
def _verify_emulator_and_restart_on_fail(self):
emulator_ok = self._verify_emulator()
if not emulator_ok:
self.screenshot("emulator-startup-screenshot-")
self._kill_processes(self.config["emulator_process_name"])
subprocess.check_call(['ps', '-ef'])
# remove emulator tmp files
for dir in glob.glob("/tmp/android-*"):
self.rmtree(dir)
time.sleep(5)
self.emulator_proc = self._launch_emulator()
return emulator_ok
def _kill_processes(self, process_name):
p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE, bufsize=0)
out, err = p.communicate()
self.info("Killing every process called %s" % process_name)
for line in out.splitlines():
if process_name in line:
pid = int(line.split(None, 1)[0])
self.info("Killing pid %d." % pid)
os.kill(pid, signal.SIGKILL)
def _build_command(self):
c = self.config
dirs = self.query_abs_dirs()
@ -380,21 +253,6 @@ class AndroidEmulatorTest(TestingMixin, BaseScript, MozbaseMixin, CodeCoverageMi
return cmd
def _install_emulator(self):
dirs = self.query_abs_dirs()
if self.config.get('emulator_url'):
self.download_unpack(self.config['emulator_url'], dirs['abs_work_dir'])
elif self.config.get('emulator_manifest'):
manifest_path = self.create_tooltool_manifest(self.config['emulator_manifest'])
dirs = self.query_abs_dirs()
cache = self.config.get("tooltool_cache", None)
if self.tooltool_fetch(manifest_path,
output_dir=dirs['abs_work_dir'],
cache=cache):
self.fatal("Unable to download emulator via tooltool!")
else:
self.warning("Cannot get emulator: configure emulator_url or emulator_manifest")
def _query_suites(self):
if self.test_suite:
return [(self.test_suite, self.test_suite)]
@ -451,73 +309,6 @@ class AndroidEmulatorTest(TestingMixin, BaseScript, MozbaseMixin, CodeCoverageMi
self.register_virtualenv_module(requirements=[requirements],
two_pass=True)
def setup_avds(self):
'''
If tooltool cache mechanism is enabled, the cached version is used by
the fetch command. If the manifest includes an "unpack" field, tooltool
will unpack all compressed archives mentioned in the manifest.
'''
c = self.config
dirs = self.query_abs_dirs()
self.mkdir_p(dirs['abs_work_dir'])
self.mkdir_p(dirs['abs_blob_upload_dir'])
# Always start with a clean AVD: AVD includes Android images
# which can be stateful.
self.rmtree(dirs['abs_avds_dir'])
self.mkdir_p(dirs['abs_avds_dir'])
if 'avd_url' in c:
# Intended for experimental setups to evaluate an avd prior to
# tooltool deployment.
url = c['avd_url']
self.download_unpack(url, dirs['abs_avds_dir'])
else:
url = self._get_repo_url(c["tooltool_manifest_path"])
self._tooltool_fetch(url, dirs['abs_avds_dir'])
avd_home_dir = self.abs_dirs['abs_avds_dir']
if avd_home_dir != "/home/cltbld/.android":
# Modify the downloaded avds to point to the right directory.
cmd = [
'bash', '-c',
'sed -i "s|/home/cltbld/.android|%s|" %s/test-*.ini' %
(avd_home_dir, os.path.join(avd_home_dir, 'avd'))
]
proc = ProcessHandler(cmd)
proc.run()
proc.wait()
def start_emulator(self):
'''
Starts the emulator
'''
if 'emulator_url' in self.config or 'emulator_manifest' in self.config:
self._install_emulator()
if not os.path.isfile(self.adb_path):
self.fatal("The adb binary '%s' is not a valid file!" % self.adb_path)
if not self.config.get("developer_mode"):
self._kill_processes("xpcshell")
self.emulator_proc = self._launch_emulator()
def verify_device(self):
'''
Check to see if the emulator can be contacted via adb.
If any communication attempt fails, kill the emulator, re-launch, and re-check.
'''
max_restarts = 5
emulator_ok = self._retry(max_restarts, 10, self._verify_emulator_and_restart_on_fail,
"Check emulator")
if not emulator_ok:
self.fatal('INFRA-ERROR: Unable to start emulator after %d attempts' % max_restarts,
EXIT_STATUS_DICT[TBPL_RETRY])
self.dump_perf_info()
self.logcat_start()
# Get a post-boot device process list for diagnostics
self.info(self.shell_output('ps'))
def download_and_extract(self):
"""
Download and extract fennec APK, tests.zip, host utils, and robocop (if required).
@ -619,14 +410,6 @@ class AndroidEmulatorTest(TestingMixin, BaseScript, MozbaseMixin, CodeCoverageMi
self.log("The %s suite: %s ran with return status: %s" %
(suite_category, suite, tbpl_status), level=log_level)
@PostScriptAction('run-tests')
def stop_device(self, action, success=None):
'''
Make sure that the emulator has been stopped
'''
self.logcat_stop()
self._kill_processes(self.config["emulator_process_name"])
if __name__ == '__main__':
test = AndroidEmulatorTest()

Просмотреть файл

@ -16,7 +16,7 @@ import subprocess
sys.path.insert(1, os.path.dirname(sys.path[0]))
from mozharness.base.log import FATAL
from mozharness.base.script import BaseScript, PreScriptAction, PostScriptAction
from mozharness.base.script import BaseScript, PreScriptAction
from mozharness.mozilla.mozbase import MozbaseMixin
from mozharness.mozilla.testing.android import AndroidMixin
from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
@ -68,8 +68,6 @@ class AndroidHardwareTest(TestingMixin, BaseScript, MozbaseMixin,
}
]] + copy.deepcopy(testing_config_options)
app_name = None
def __init__(self, require_config_file=False):
super(AndroidHardwareTest, self).__init__(
config_options=self.config_options,
@ -99,9 +97,6 @@ class AndroidHardwareTest(TestingMixin, BaseScript, MozbaseMixin,
self.test_packages_url = c.get('test_packages_url')
self.test_manifest = c.get('test_manifest')
self.robocop_path = os.path.join(abs_dirs['abs_work_dir'], "robocop.apk")
self.device_name = os.environ['DEVICE_NAME']
self.device_serial = os.environ['DEVICE_SERIAL']
self.device_ip = os.environ['DEVICE_IP']
self.test_suite = c.get('test_suite')
self.this_chunk = c.get('this_chunk')
self.total_chunks = c.get('total_chunks')
@ -290,16 +285,6 @@ class AndroidHardwareTest(TestingMixin, BaseScript, MozbaseMixin,
self.register_virtualenv_module(requirements=[requirements],
two_pass=True)
def verify_device(self):
'''
Check to see if the device can be contacted via adb.
'''
self.mkdir_p(self.query_abs_dirs()['abs_blob_upload_dir'])
self.dump_perf_info()
self.logcat_start()
# Get a post-boot device process list for diagnostics
self.info(self.shell_output('ps'))
def download_and_extract(self):
"""
Download and extract fennec APK, tests.zip, host utils, and robocop (if required).
@ -400,13 +385,6 @@ class AndroidHardwareTest(TestingMixin, BaseScript, MozbaseMixin,
self.log("The %s suite: %s ran with return status: %s" %
(suite_category, suite, tbpl_status), level=log_level)
@PostScriptAction('run-tests')
def stop_device(self, action, success=None):
'''
Cleanup after test run.
'''
self.logcat_stop()
if __name__ == '__main__':
test = AndroidHardwareTest()

Просмотреть файл

@ -18,6 +18,7 @@ import mozinfo
from mozharness.base.errors import BaseErrorList
from mozharness.base.script import PreScriptAction
from mozharness.base.vcs.vcsbase import MercurialScript
from mozharness.mozilla.testing.android import AndroidMixin
from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options
from mozharness.mozilla.testing.codecoverage import (
CodeCoverageMixin,
@ -29,7 +30,7 @@ from mozharness.mozilla.structuredlog import StructuredOutputParser
from mozharness.base.log import INFO
class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin):
class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin, AndroidMixin):
config_options = [
[['--test-type'], {
"action": "extend",
@ -104,9 +105,12 @@ class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin):
config_options=self.config_options,
all_actions=[
'clobber',
'setup-avds',
'start-emulator',
'download-and-extract',
'create-virtualenv',
'pull',
'verify-device',
'install',
'run-tests',
],
@ -121,6 +125,9 @@ class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin):
self.installer_path = c.get('installer_path')
self.binary_path = c.get('binary_path')
self.abs_app_dir = None
self.xre_path = None
if self.is_emulator:
self.device_serial = 'emulator-5554'
def query_abs_app_dir(self):
"""We can't set this in advance, because OSX install directories
@ -144,6 +151,10 @@ class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin):
dirs['abs_test_bin_dir'] = os.path.join(dirs['abs_test_install_dir'], 'bin')
dirs["abs_wpttest_dir"] = os.path.join(dirs['abs_test_install_dir'], "web-platform")
dirs['abs_blob_upload_dir'] = os.path.join(abs_dirs['abs_work_dir'], 'blobber_upload_dir')
if self.is_android:
dirs['abs_xre_dir'] = os.path.join(abs_dirs['abs_work_dir'], 'hostutils')
if self.is_emulator:
dirs['abs_avds_dir'] = self.config.get('avds_dir')
abs_dirs.update(dirs)
self.abs_dirs = abs_dirs
@ -187,7 +198,8 @@ class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin):
'test_path': dirs["abs_wpttest_dir"],
'test_install_path': dirs["abs_test_install_dir"],
'abs_app_dir': abs_app_dir,
'abs_work_dir': dirs["abs_work_dir"]
'abs_work_dir': dirs["abs_work_dir"],
'xre_path': self.xre_path,
}
cmd = [self.query_python_path('python'), '-u']
@ -214,6 +226,10 @@ class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin):
"--run-by-dir=%i" % (3 if not mozinfo.info["asan"] else 0),
"--no-pause-after-test"]
if self.is_android:
cmd += ["--device-serial=%s" % self.device_serial]
cmd += ["--package-name=%s" % self.query_package_name()]
if not sys.platform.startswith("linux"):
cmd += ["--exclude=css"]
@ -282,8 +298,19 @@ class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin):
"mozpack/*",
"mozbuild/*"],
suite_categories=["web-platform"])
if self.is_android:
dirs = self.query_abs_dirs()
self.xre_path = self.download_hostutils(dirs['abs_xre_dir'])
def install(self):
if self.is_android:
self.install_apk(self.installer_path)
else:
super(WebPlatformTest, self).install()
def _install_fonts(self):
if self.is_android:
return
# Ensure the Ahem font is available
dirs = self.query_abs_dirs()
@ -327,6 +354,9 @@ class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin):
else:
env['STYLO_THREADS'] = '4'
if self.is_android:
env['ADB_PATH'] = self.adb_path
env = self.query_env(partial_env=env, log_level=INFO)
start_time = datetime.now()

Просмотреть файл

@ -220,16 +220,6 @@ class FennecBrowser(FirefoxBrowser):
self.runner.start(debug_args=debug_args, interactive=self.debug_info and self.debug_info.interactive)
# gecko_log comes from logcat when running with device/emulator
logcat_args = {
"filterspec": "Gecko",
"serial": self.runner.device.app_ctx.device_serial
}
# TODO setting logcat_args["logfile"] yields an almost empty file
# even without filterspec
logcat_args["stream"] = sys.stdout
self.runner.device.start_logcat(**logcat_args)
self.runner.device.device.forward(
local="tcp:{}".format(self.marionette_port),
remote="tcp:{}".format(self.marionette_port))

Просмотреть файл

@ -37,6 +37,31 @@ InProcessWinCompositorWidget::InProcessWinCompositorWidget(const WinCompositorWi
MOZ_ASSERT(mWindow);
}
void
InProcessWinCompositorWidget::OnDestroyWindow()
{
EnterPresentLock();
WinCompositorWidget::OnDestroyWindow();
LeavePresentLock();
}
void
InProcessWinCompositorWidget::UpdateTransparency(nsTransparencyMode aMode)
{
EnterPresentLock();
WinCompositorWidget::UpdateTransparency(aMode);
LeavePresentLock();
}
void
InProcessWinCompositorWidget::ClearTransparentWindow()
{
EnterPresentLock();
WinCompositorWidget::ClearTransparentWindow();
LeavePresentLock();
}
nsIWidget*
InProcessWinCompositorWidget::RealWidget()
{

Просмотреть файл

@ -24,6 +24,10 @@ public:
const layers::CompositorOptions& aOptions,
nsWindow* aWindow);
void OnDestroyWindow() override;
void UpdateTransparency(nsTransparencyMode aMode) override;
void ClearTransparentWindow() override;
void ObserveVsync(VsyncObserver* aObserver) override;
nsIWidget* RealWidget() override;

Просмотреть файл

@ -975,6 +975,8 @@ with modules["DOM_INDEXEDDB"]:
errors["NS_ERROR_DOM_INDEXEDDB_VERSION_ERR"] = FAILURE(12)
errors["NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR"] = FAILURE(1001)
errors["NS_ERROR_DOM_INDEXEDDB_KEY_ERR"] = FAILURE(1002)
errors["NS_ERROR_DOM_INDEXEDDB_RENAME_OBJECT_STORE_ERR"] = FAILURE(1003)
errors["NS_ERROR_DOM_INDEXEDDB_RENAME_INDEX_ERR"] = FAILURE(1004)
# =======================================================================