Merge m-c to inbound. a=merge

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2015-05-01 10:50:07 -04:00
commit f87c951071
223 changed files with 4436 additions and 5420 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -134,7 +134,7 @@
<project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
<project name="kernel/common" path="kernel" revision="0be9cc12cd81b145e1471016c19722429ff9285e"/>
<project name="kernel/common" path="kernel" revision="a2977758950865feb5980996d8e889677dea3bd4"/>
<project name="platform/system/core" path="system/core" revision="7992618bd4ee33ce96897675a5c0a9b619122f13"/>
<project name="u-boot" path="u-boot" revision="f1502910977ac88f43da7bf9277c3523ad4b0b2f"/>
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="7d6e1269be7186b2073fa568958b357826692c4b"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -125,7 +125,7 @@
<!-- Flame specific things -->
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
<project name="device/qcom/common" path="device/qcom/common" revision="2501e5940ba69ece7654ff85611c76ae5bda299c"/>
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="b83fc73de7b64594cd74b33e498bf08332b5d87b"/>
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="a9f3f8fb8b0844724de32426b7bcc4e6dc4fa2ed"/>
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="0865bc4134b67220df4058625fba29305d6b10c3"/>
<project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/>
<project name="platform_bootable_recovery" path="bootable/recovery" remote="b2g" revision="d5e53ed6f22fa06052351dc03510af9473af01ea"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "759a1f935a6a81c32ad66e39a6353b334dfa4f91",
"git_revision": "8e64346ce8197b50b815a294278797bc144aa3e6",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "d88d79f407d14635451063c4397724d836efcbaa",
"revision": "1bbaa54b674c42e0d8b2fe31d8b0080901811fa0",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="759a1f935a6a81c32ad66e39a6353b334dfa4f91"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -1327,8 +1327,8 @@ pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
// Developer edition preferences
#ifdef MOZ_DEV_EDITION
pref("lightweightThemes.selectedThemeID", "firefox-devedition@mozilla.org");
pref("browser.devedition.theme.enabled", true);
sticky_pref("lightweightThemes.selectedThemeID", "firefox-devedition@mozilla.org");
sticky_pref("browser.devedition.theme.enabled", true);
#endif
// Developer edition promo preferences
@ -1443,6 +1443,15 @@ pref("devtools.performance.ui.show-idle-blocks", true);
pref("devtools.performance.ui.enable-memory", false);
pref("devtools.performance.ui.enable-framerate", true);
pref("devtools.performance.ui.show-jit-optimizations", false);
// If in aurora (40.0, will revert for 40.1), set default
// to retro mode.
// TODO bug 1160313
#if MOZ_UPDATE_CHANNEL == aurora
pref("devtools.performance.ui.retro-mode", true);
#else
pref("devtools.performance.ui.retro-mode", false);
#endif
// The default cache UI setting
pref("devtools.cache.disabled", false);
@ -1507,9 +1516,9 @@ pref("devtools.webaudioeditor.inspectorWidth", 300);
// Default theme ("dark" or "light")
#ifdef MOZ_DEV_EDITION
pref("devtools.theme", "dark");
sticky_pref("devtools.theme", "dark");
#else
pref("devtools.theme", "light");
sticky_pref("devtools.theme", "light");
#endif
// Display the introductory text
@ -1646,10 +1655,10 @@ pref("browser.newtabpage.rows", 3);
pref("browser.newtabpage.columns", 5);
// directory tiles download URL
pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v2/links/fetch/%LOCALE%");
pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v3/links/fetch/%LOCALE%/%CHANNEL%");
// endpoint to send newtab click and view pings
pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v2/links/");
pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v3/links/");
// Enable the DOM fullscreen API.
pref("full-screen-api.enabled", true);
@ -1863,7 +1872,7 @@ pref("browser.polaris.enabled", false);
pref("privacy.trackingprotection.ui.enabled", false);
#endif
#ifdef NIGHTLY_BUILD
#ifdef E10S_TESTING_ONLY
// At the moment, autostart.2 is used, while autostart.1 is unused.
// We leave it here set to false to reset users' defaults and allow
// us to change everybody to true in the future, when desired.
@ -1871,7 +1880,7 @@ pref("browser.tabs.remote.autostart.1", false);
pref("browser.tabs.remote.autostart.2", true);
#endif
#ifdef NIGHTLY_BUILD
#ifdef E10S_TESTING_ONLY
// Enable e10s add-on interposition by default.
pref("extensions.interposition.enabled", true);
pref("extensions.interposition.prefetching", true);
@ -1900,6 +1909,7 @@ pref("browser.readinglist.sidebarEverOpened", false);
pref("readinglist.scheduler.enabled", false);
pref("readinglist.server", "https://readinglist.services.mozilla.com/v1");
pref("browser.reader.detectedFirstArticle", false);
// Don't limit how many nodes we care about on desktop:
pref("reader.parse-node-limit", 0);

View File

@ -133,7 +133,7 @@ Site.prototype = {
if (this.link.targetedSite) {
this.node.setAttribute("suggested", true);
let targetedSite = `<strong> ${this.link.targetedSite} </strong>`;
let targetedSite = `<strong> ${this.link.targetedName} </strong>`;
this._querySelector(".newtab-suggested").innerHTML =
`<div class='newtab-suggested-bounds'> ${newTabString("suggested.button", [targetedSite])} </div>`;
}

View File

@ -555,7 +555,9 @@ addEventListener("unload", () => {
}, false);
addMessageListener("Browser:AppTab", function(message) {
docShell.isAppTab = message.data.isAppTab;
if (docShell) {
docShell.isAppTab = message.data.isAppTab;
}
});
let WebBrowserChrome = {

View File

@ -6,30 +6,6 @@ Components.utils.import("resource://gre/modules/Promise.jsm", this);
let chatbar = document.getElementById("pinnedchats");
function waitForCondition(condition, errorMsg) {
let deferred = Promise.defer();
var tries = 0;
var interval = setInterval(function() {
if (tries >= 30) {
ok(false, errorMsg);
moveOn();
}
var conditionPassed;
try {
conditionPassed = condition();
} catch (e) {
ok(false, e + "\n" + e.stack);
conditionPassed = false;
}
if (conditionPassed) {
moveOn();
}
tries++;
}, 100);
var moveOn = function() { clearInterval(interval); deferred.resolve(); };
return deferred.promise;
}
add_chat_task(function* testOpenCloseChat() {
let chatbox = yield promiseOpenChat("http://example.com");
Assert.strictEqual(chatbox, chatbar.selectedChat);
@ -115,7 +91,7 @@ add_chat_task(function* testSecondTopLevelWindow() {
secondWindow.close();
});
// Test that chats are created in the correct window.
// Test that findChromeWindowForChats() returns the expected window.
add_chat_task(function* testChatWindowChooser() {
let chat = yield promiseOpenChat("http://example.com");
Assert.equal(numChatsInWindow(window), 1, "first window has the chat");
@ -124,42 +100,34 @@ add_chat_task(function* testChatWindowChooser() {
let secondWindow = OpenBrowserWindow();
yield promiseOneEvent(secondWindow, "load");
Assert.equal(secondWindow, Chat.findChromeWindowForChats(null), "Second window is the preferred chat window");
Assert.equal(numChatsInWindow(secondWindow), 0, "second window starts with no chats");
yield promiseOpenChat("http://example.com#2");
Assert.equal(numChatsInWindow(secondWindow), 1, "second window now has chats");
Assert.equal(numChatsInWindow(window), 1, "first window still has 1 chat");
chat.close();
// a bit heavy handed, but handy fixing bug 1090633
yield waitForCondition(function () !chat.parentNode, "chat has been detached");
Assert.equal(numChatsInWindow(window), 0, "first window now has no chats");
// now open another chat - it should still open in the second.
yield promiseOpenChat("http://example.com#3");
Assert.equal(numChatsInWindow(window), 0, "first window still has no chats");
Assert.equal(numChatsInWindow(secondWindow), 2, "second window has both chats");
// focus the first window, and check it will be selected for future chats.
// Bug 1090633 - there are lots of issues around focus, especially when the
// browser itself doesn't have focus. We can end up with
// Services.wm.getMostRecentWindow("navigator:browser") returning a different
// window than, say, Services.focus.activeWindow. But the focus manager isn't
// the point of this test.
// So we simply keep focusing the first window until it is reported as the
// most recent.
do {
dump("trying to force window to become the most recent.\n");
secondWindow.focus();
window.focus();
yield promiseWaitForFocus();
} while (Services.wm.getMostRecentWindow("navigator:browser") != window)
// focus the first window, and open yet another chat - it
// should open in the first window.
window.focus();
yield promiseWaitForFocus();
chat = yield promiseOpenChat("http://example.com#4");
Assert.equal(numChatsInWindow(window), 1, "first window got new chat");
chat.close();
Assert.equal(numChatsInWindow(window), 0, "first window has no chats");
Assert.equal(window, Chat.findChromeWindowForChats(null), "First window now the preferred chat window");
let privateWindow = OpenBrowserWindow({private: true});
yield promiseOneEvent(privateWindow, "load")
// open a last chat - the focused window can't accept
// chats (it's a private window), so the chat should open
// in the window that was selected before. This is known
// to be broken on Linux.
chat = yield promiseOpenChat("http://example.com#5");
let os = Services.appinfo.OS;
const BROKEN_WM_Z_ORDER = os != "WINNT" && os != "Darwin";
let fn = BROKEN_WM_Z_ORDER ? todo : ok;
fn(numChatsInWindow(window) == 1, "first window got the chat");
chat.close();
// The focused window can't accept chats (it's a private window), so the
// chat should open in the window that was selected before. This will be
// either window or secondWindow (linux may choose a different one) but the
// point is that the window is *not* the private one.
Assert.ok(Chat.findChromeWindowForChats(null) == window ||
Chat.findChromeWindowForChats(null) == secondWindow,
"Private window isn't selected for new chats.");
privateWindow.close();
secondWindow.close();
});

View File

@ -10,12 +10,16 @@ const CHAT_URL = "https://example.com/browser/browser/base/content/test/chat/cha
// Is the currently opened tab focused?
function isTabFocused() {
let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
return Services.focus.focusedWindow == tabb.contentWindow;
// focus sucks in tests - our window may have lost focus.
let elt = Services.focus.getFocusedElementForWindow(window, false, {});
return elt == tabb;
}
// Is the specified chat focused?
function isChatFocused(chat) {
return chat.chatbar._isChatFocused(chat);
// focus sucks in tests - our window may have lost focus.
let elt = Services.focus.getFocusedElementForWindow(window, false, {});
return elt == chat.content;
}
let chatbar = document.getElementById("pinnedchats");

View File

@ -32,19 +32,29 @@ add_task(function* test_reader_button() {
TEST_PREFS.forEach(([name, value]) => {
Services.prefs.setBoolPref(name, value);
});
Services.prefs.setBoolPref("browser.reader.detectedFirstArticle", false);
let tab = gBrowser.selectedTab = gBrowser.addTab();
is_element_hidden(readerButton, "Reader mode button is not present on a new tab");
ok(!UITour.isInfoOnTarget(window, "readerMode-urlBar"),
"Info panel shouldn't appear without the reader mode button");
ok(!Services.prefs.getBoolPref("browser.reader.detectedFirstArticle"),
"Shouldn't have detected the first article");
// Point tab to a test page that is reader-able.
let url = TEST_PATH + "readerModeArticle.html";
yield promiseTabLoadEvent(tab, url);
yield promiseWaitForCondition(() => !readerButton.hidden);
is_element_visible(readerButton, "Reader mode button is present on a reader-able page");
ok(UITour.isInfoOnTarget(window, "readerMode-urlBar"),
"Info panel should be anchored at the reader mode button");
ok(Services.prefs.getBoolPref("browser.reader.detectedFirstArticle"),
"Should have detected the first article");
// Switch page into reader mode.
readerButton.click();
yield promiseTabLoadEvent(tab);
ok(!UITour.isInfoOnTarget(window, "readerMode-urlBar"), "Info panel should have closed");
let readerUrl = gBrowser.selectedBrowser.currentURI.spec;
ok(readerUrl.startsWith("about:reader"), "about:reader loaded after clicking reader mode button");

View File

@ -18,6 +18,8 @@ gDirectorySource = "data:application/json," + JSON.stringify({
});
function runTests() {
let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
DirectoryLinksProvider.getFrecentSitesName = () => "";
let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
NewTabUtils.isTopPlacesSite = (site) => false;
@ -84,4 +86,5 @@ function runTests() {
yield blockCell(1);
yield addNewTabPageTab();
checkGrid("1,2,3,4,5,6,7,8,9");
DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
}

View File

@ -26,8 +26,11 @@ gDirectorySource = "data:application/json," + JSON.stringify({
});
function runTests() {
let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
DirectoryLinksProvider.getFrecentSitesName = () => "";
let origEnhanced = NewTabUtils.allPages.enhanced;
registerCleanupFunction(() => {
DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
Services.prefs.clearUserPref(PRELOAD_PREF);
NewTabUtils.allPages.enhanced = origEnhanced;
});

View File

@ -1,15 +1,14 @@
# We still need to fix warnings in this file.
MozLoopWorker.js
# This file currently uses es7 features
MozLoopAPI.jsm
# This file currently uses a non-standard (and not on a standards track)
# if statement within catch.
modules/MozLoopWorker.js
# This file currently uses es7 features eslint issue:
# https://github.com/eslint/espree/issues/125
modules/MozLoopAPI.jsm
# Libs we don't need to check
content/libs
content/shared/libs
standalone/content/libs
standalone/node_modules
# We should look at turning these on when we fix the warnings
test/xpcshell
test/mochitest
# Libs we don't need to check
test/shared/vendor

View File

@ -1,3 +1,5 @@
// Note: there are extra allowances for files used solely in Firefox desktop,
// see content/js/.eslintrc and modules/.eslintrc
{
"plugins": [
"react"
@ -5,18 +7,6 @@
"ecmaFeatures": {
"forOf": true,
"jsx": true,
// These are on for this directory for .jsm and content/js files.
// If adding more items here, consider turning them off for the following
// files if they aren't supported by all browsers.
// content/shared/.eslintrc
// content/standalone/.eslintrc
"blockBindings": true,
"arrowFunctions": true,
"destructuring": true,
"generators": true,
"spread": true,
"restParams": true,
"objectLiteralShorthandMethods": true
},
"env": {
"browser": true,
@ -43,49 +33,50 @@
// problems they find, one at a time.
// Eslint built-in rules are documented at <http://eslint.org/docs/rules/>
"camelcase": 0,
"comma-dangle": 0,
"comma-spacing": 0,
"consistent-return": 0,
"curly": 0,
"dot-notation": 0,
"eol-last": 0,
"eqeqeq": 0,
"global-strict": 0,
"key-spacing": 0,
"new-cap": 0,
"no-catch-shadow": 0,
"no-console": 0,
"no-empty": 0,
"no-extra-bind": 0,
"no-extra-boolean-cast": 0,
"no-extra-semi": 0,
"no-multi-spaces": 0,
"no-new": 0,
"no-redeclare": 0,
"no-return-assign": 0,
"no-shadow": 0,
"no-spaced-func": 0,
"no-trailing-spaces": 0,
"no-undef": 0,
"no-underscore-dangle": 0,
"no-unused-expressions": 0,
"no-unused-vars": 0,
"no-use-before-define": 0,
"no-wrap-func": 0,
"quotes": 0,
"semi": 0,
"semi-spacing": 0,
"space-infix-ops": 0,
"space-return-throw-case": 0,
"strict": 0,
"yoda": 0,
"camelcase": 0, // TODO: Remove (use default)
"comma-dangle": 0, // TODO: Remove (use default)
"comma-spacing": 0, // TODO: Remove (use default)
"consistent-return": 0, // TODO: Remove (use default)
"curly": 0, // TODO: Remove (use default)
"dot-notation": 0, // TODO: Remove (use default)
"eol-last": 0, // TODO: Remove (use default)
"eqeqeq": 0, // TBD. Might need to be separate for content & chrome
"global-strict": 0, // Leave as zero (this will be unsupported in eslint 1.0.0)
"key-spacing": 0, // TODO: Remove (use default)
"new-cap": 0, // TODO: Remove (use default)
"no-catch-shadow": 0, // TODO: Remove (use default)
"no-console": 0, // Leave as 0. We use console logging in content code.
"no-empty": 0, // TODO: Remove (use default)
"no-extra-bind": 0, // Leave as 0
"no-extra-boolean-cast": 0, // TODO: Remove (use default)
"no-extra-semi": 0, // TODO: Remove (use default)
"no-multi-spaces": 0, // TBD.
"no-new": 0, // TODO: Remove (use default)
"no-redeclare": 0, // TODO: Remove (use default)
"no-return-assign": 0, // TODO: Remove (use default)
"no-shadow": 0, // TODO: Remove (use default)
"no-spaced-func": 0, // TODO: Remove (use default)
"no-trailing-spaces": 0, // TODO: Remove (use default)
"no-undef": 0, // TODO: Remove (use default)
"no-underscore-dangle": 0, // Leave as 0. Commonly used for private variables.
"no-unused-expressions": 0, // TODO: Remove (use default)
"no-unused-vars": 0, // TODO: Remove (use default)
"no-use-before-define": 0, // TODO: Remove (use default)
"no-wrap-func": 0, // TODO: Remove (use default)
"quotes": 0, // [2, "double", "avoid-escape"],
"semi": 0, // TODO: Remove (use default)
"semi-spacing": 0, // TODO: Remove (use default)
"space-infix-ops": 0, // TODO: Remove (use default)
"space-return-throw-case": 0, // TODO: Remove (use default)
"strict": 0, // [2, "function"],
"yoda": 0, // [2, "never"],
// eslint-plugin-react rules. These are documented at
// <https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules>
"react/jsx-quotes": [2, "double", "avoid-escape"],
"react/jsx-no-undef": 2,
// Need to fix instances where this is failing.
"react/jsx-sort-props": 0,
"react/jsx-sort-prop-types": 0,
"react/jsx-uses-vars": 2,
// Need to fix the couple of instances which don't
// currently pass this rule.
@ -101,6 +92,7 @@
"react/react-in-jsx-scope": 0,
// These ones we don't want to ever enable
"react/display-name": 0,
"react/jsx-boolean-value": 0,
"react/no-multi-comp": 0
}
}

View File

@ -54,7 +54,7 @@ If you install eslint and the react plugin globally:
You can also run it by hand in the browser/components/loop directory:
eslint -ext .js -ext .jsx --ext .jsm .
eslint --ext .js --ext .jsx --ext .jsm .
Front-End Unit Tests
====================

View File

@ -0,0 +1,15 @@
{
"ecmaFeatures": {
// These are on for this directory for .jsm and content/js files.
"blockBindings": true,
"arrowFunctions": true,
"destructuring": true,
"generators": true,
"spread": true,
"restParams": true,
"objectLiteralShorthandMethods": true
},
"rules": {
"generator-star-spacing": [2, "after"]
}
}

View File

@ -222,7 +222,7 @@ loop.contacts = (function(_, mozL10n) {
"disabled": !this.props.canEdit }),
onClick: this.onItemClick, "data-action": "remove"},
React.createElement("i", {className: "icon icon-remove"}),
mozL10n.get("remove_contact_menu_button")
mozL10n.get("remove_contact_menu_button2")
)
)
);
@ -587,7 +587,7 @@ loop.contacts = (function(_, mozL10n) {
React.createElement(ButtonGroup, null,
React.createElement(Button, {caption: this.state.importBusy
? mozL10n.get("importing_contacts_progress_button")
: mozL10n.get("import_contacts_button"),
: mozL10n.get("import_contacts_button2"),
disabled: this.state.importBusy,
onClick: this.handleImportButtonClick},
React.createElement("div", {className: cx({"contact-import-spinner": true,

View File

@ -222,7 +222,7 @@ loop.contacts = (function(_, mozL10n) {
"disabled": !this.props.canEdit })}
onClick={this.onItemClick} data-action="remove">
<i className="icon icon-remove" />
{mozL10n.get("remove_contact_menu_button")}
{mozL10n.get("remove_contact_menu_button2")}
</li>
</ul>
);
@ -587,7 +587,7 @@ loop.contacts = (function(_, mozL10n) {
<ButtonGroup>
<Button caption={this.state.importBusy
? mozL10n.get("importing_contacts_progress_button")
: mozL10n.get("import_contacts_button")}
: mozL10n.get("import_contacts_button2")}
disabled={this.state.importBusy}
onClick={this.handleImportButtonClick}>
<div className={cx({"contact-import-spinner": true,

View File

@ -11,10 +11,11 @@ var loop = loop || {};
loop.roomViews = (function(mozL10n) {
"use strict";
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var ROOM_STATES = loop.store.ROOM_STATES;
var SCREEN_SHARE_STATES = loop.shared.utils.SCREEN_SHARE_STATES;
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var sharedUtils = loop.shared.utils;
var sharedViews = loop.shared.views;
/**
@ -312,13 +313,25 @@ loop.roomViews = (function(mozL10n) {
var thumbnail = URL && URL.thumbnail || "";
var URLDescription = URL && URL.description || "";
var location = URL && URL.location || "";
var locationData = null;
if (location) {
locationData = sharedUtils.formatURL(location);
}
if (!locationData) {
return null;
}
return (
React.createElement("div", {className: "room-context"},
React.createElement("img", {className: "room-context-thumbnail", src: thumbnail}),
React.createElement("div", {className: "room-context-content"},
React.createElement("div", {className: "room-context-label"}, mozL10n.get("context_inroom_label")),
React.createElement("div", {className: "room-context-description"}, URLDescription),
React.createElement("a", {className: "room-context-url", href: location, target: "_blank"}, location),
React.createElement("a", {className: "room-context-url",
href: location,
target: "_blank",
title: locationData.location}, locationData.hostname),
this.props.roomData.roomDescription ?
React.createElement("div", {className: "room-context-comment"}, this.props.roomData.roomDescription) :
null,

View File

@ -11,10 +11,11 @@ var loop = loop || {};
loop.roomViews = (function(mozL10n) {
"use strict";
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var ROOM_STATES = loop.store.ROOM_STATES;
var SCREEN_SHARE_STATES = loop.shared.utils.SCREEN_SHARE_STATES;
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var sharedUtils = loop.shared.utils;
var sharedViews = loop.shared.views;
/**
@ -312,13 +313,25 @@ loop.roomViews = (function(mozL10n) {
var thumbnail = URL && URL.thumbnail || "";
var URLDescription = URL && URL.description || "";
var location = URL && URL.location || "";
var locationData = null;
if (location) {
locationData = sharedUtils.formatURL(location);
}
if (!locationData) {
return null;
}
return (
<div className="room-context">
<img className="room-context-thumbnail" src={thumbnail}/>
<div className="room-context-content">
<div className="room-context-label">{mozL10n.get("context_inroom_label")}</div>
<div className="room-context-description">{URLDescription}</div>
<a className="room-context-url" href={location} target="_blank">{location}</a>
<a className="room-context-url"
href={location}
target="_blank"
title={locationData.location}>{locationData.hostname}</a>
{this.props.roomData.roomDescription ?
<div className="room-context-comment">{this.props.roomData.roomDescription}</div> :
null}

View File

@ -1,14 +0,0 @@
{
"ecmaFeatures": {
// Turn off top-level items needed for the jsm files, but not wanted
// for shared code as we can't support them.
"blockBindings": false,
"arrowFunctions": false,
"destructuring": false,
"forOf": true,
"generators": false,
"spread": false,
"restParams": false,
"objectLiteralShorthandMethods": false
}
}

View File

@ -789,7 +789,7 @@ loop.OTSdkDriver = (function() {
bucket = buckets.MORE_THAN_5M;
}
this.mozLoop.telemetryAddValue("LOOP_TWO_WAY_MEDIA_CONN_LENGTH", bucket);
this.mozLoop.telemetryAddValue("LOOP_TWO_WAY_MEDIA_CONN_LENGTH_1", bucket);
this._setTwoWayMediaStartTime(this.CONNECTION_START_TIME_ALREADY_NOTED);
this._connectionLengthNotedCalls++;
@ -857,7 +857,7 @@ loop.OTSdkDriver = (function() {
return;
}
this.mozLoop.telemetryAddValue("LOOP_SHARING_STATE_CHANGE", bucket);
this.mozLoop.telemetryAddValue("LOOP_SHARING_STATE_CHANGE_1", bucket);
}
};

View File

@ -271,6 +271,33 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
};
}
/**
* Formats a url for display purposes. This includes converting the
* domain to punycode, and then decoding the url.
*
* @param {String} url The url to format.
* @return {Object} An object containing the hostname and full location.
*/
function formatURL(url) {
// We're using new URL to pass this through the browser's ACE/punycode
// processing system. If the browser considers a url to need to be
// punycode encoded for it to be displayed, then new URL will do that for
// us. This saves us needing our own punycode library.
var urlObject;
try {
urlObject = new URL(url);
} catch (ex) {
console.error("Error occurred whilst parsing URL:", ex);
return null;
}
// Finally, ensure we look good.
return {
hostname: urlObject.hostname,
location: decodeURI(urlObject.href)
};
}
/**
* Generates and opens a mailto: url with call URL information prefilled.
* Note: This only works for Desktop.
@ -536,6 +563,7 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
ROOM_INFO_FAILURES: ROOM_INFO_FAILURES,
composeCallUrlEmail: composeCallUrlEmail,
formatDate: formatDate,
formatURL: formatURL,
getBoolPreference: getBoolPreference,
getOS: getOS,
getOSVersion: getOSVersion,

View File

@ -0,0 +1,17 @@
{
"ecmaFeatures": {
"arrowFunctions": true,
"blockBindings": true,
"destructuring": true,
"generators": true,
"restParams": true,
"spread": true,
"objectLiteralShorthandMethods": true,
},
"rules": {
"generator-star-spacing": [2, "after"],
// We should fix the errors and enable this (set to 2)
"no-var": 0,
"strict": [2, "global"]
}
}

View File

@ -13,18 +13,18 @@ BROWSER_CHROME_MANIFESTS += [
]
EXTRA_JS_MODULES.loop += [
'CardDavImporter.jsm',
'content/shared/js/crypto.js',
'content/shared/js/utils.js',
'GoogleImporter.jsm',
'LoopCalls.jsm',
'LoopContacts.jsm',
'LoopRooms.jsm',
'LoopStorage.jsm',
'MozLoopAPI.jsm',
'MozLoopPushHandler.jsm',
'MozLoopService.jsm',
'MozLoopWorker.js',
'modules/CardDavImporter.jsm',
'modules/GoogleImporter.jsm',
'modules/LoopCalls.jsm',
'modules/LoopContacts.jsm',
'modules/LoopRooms.jsm',
'modules/LoopStorage.jsm',
'modules/MozLoopAPI.jsm',
'modules/MozLoopPushHandler.jsm',
'modules/MozLoopService.jsm',
'modules/MozLoopWorker.js',
]
with Files('**'):

View File

@ -1,14 +0,0 @@
{
"ecmaFeatures": {
// Turn off top-level items needed for the jsm files, but not wanted
// for shared code as we can't support them.
"blockBindings": false,
"arrowFunctions": false,
"destructuring": false,
"forOf": true,
"generators": false,
"spread": false,
"restParams": false,
"objectLiteralShorthandMethods": false
}
}

View File

@ -16,6 +16,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
var ROOM_STATES = loop.store.ROOM_STATES;
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var sharedUtils = loop.shared.utils;
var sharedViews = loop.shared.views;
var StandaloneRoomInfoArea = React.createClass({displayName: "StandaloneRoomInfoArea",
@ -248,7 +249,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
return null;
}
var location = this.props.roomContextUrl.location;
var locationInfo = sharedUtils.formatURL(this.props.roomContextUrl.location);
if (!locationInfo) {
return null;
}
var cx = React.addons.classSet;
@ -262,9 +266,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
React.createElement("img", {src: this.props.roomContextUrl.thumbnail}),
React.createElement("div", {className: "standalone-context-url-description-wrapper"},
this.props.roomContextUrl.description,
React.createElement("br", null), React.createElement("a", {href: location,
React.createElement("br", null), React.createElement("a", {href: locationInfo.location,
onClick: this.recordClick,
target: "_blank"}, location)
target: "_blank",
title: locationInfo.location}, locationInfo.hostname)
)
)
);

View File

@ -16,6 +16,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
var ROOM_STATES = loop.store.ROOM_STATES;
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var sharedUtils = loop.shared.utils;
var sharedViews = loop.shared.views;
var StandaloneRoomInfoArea = React.createClass({
@ -248,7 +249,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
return null;
}
var location = this.props.roomContextUrl.location;
var locationInfo = sharedUtils.formatURL(this.props.roomContextUrl.location);
if (!locationInfo) {
return null;
}
var cx = React.addons.classSet;
@ -262,9 +266,10 @@ loop.standaloneRoomViews = (function(mozL10n) {
<img src={this.props.roomContextUrl.thumbnail} />
<div className="standalone-context-url-description-wrapper">
{this.props.roomContextUrl.description}
<br /><a href={location}
<br /><a href={locationInfo.location}
onClick={this.recordClick}
target="_blank">{location}</a>
target="_blank"
title={locationInfo.location}>{locationInfo.hostname}</a>
</div>
</div>
);

View File

@ -12,8 +12,8 @@
},
"dependencies": {},
"devDependencies": {
"eslint": "0.18.x",
"eslint-plugin-react": "2.0.x",
"eslint": "0.20.x",
"eslint-plugin-react": "2.2.x",
"express": "3.x"
},
"scripts": {

View File

@ -0,0 +1,7 @@
{
"rules": {
// This is useful for some of the tests, e.g.
// expect(new Foo()).to.Throw(/error/)
"no-new": 0
}
}

View File

@ -242,6 +242,23 @@ describe("loop.roomViews", function () {
expect(view.getDOMNode().querySelector(".room-context")).to.not.eql(null);
});
it("should format the context url for display", function() {
sandbox.stub(sharedUtils, "formatURL").returns({
location: "location",
hostname: "hostname"
});
view = mountTestComponent({
showContext: true,
roomData: {
roomContextUrls: [fakeContextURL]
}
});
expect(view.getDOMNode().querySelector(".room-context-url").textContent)
.eql("hostname");
});
});
});

View File

@ -0,0 +1,17 @@
{
"ecmaFeatures": {
"arrowFunctions": true,
"blockBindings": true,
"destructuring": true,
"generators": true,
"restParams": true,
"spread": true,
"objectLiteralShorthandMethods": true,
},
"rules": {
"generator-star-spacing": [2, "after"],
// We should fix the errors and enable this (set to 2)
"no-var": 0,
"strict": [2, "global"]
}
}

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {CardDavImporter} = Cu.import("resource:///modules/loop/CardDavImporter.jsm", {});
const kAuth = {

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {GoogleImporter} = Cu.import("resource:///modules/loop/GoogleImporter.jsm", {});
let importer = new GoogleImporter();

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {LoopContacts} = Cu.import("resource:///modules/loop/LoopContacts.jsm", {});
const {LoopStorage} = Cu.import("resource:///modules/loop/LoopStorage.jsm", {});
@ -221,8 +223,13 @@ add_task(function* () {
Assert.ok(!err, "There shouldn't be an error");
Assert.equal(result.length, toRetrieve.length, "Result list should be the same " +
"size as the list of items to retrieve");
function resultFilter(c) {
return c._guid == this._guid;
}
for (let contact of toRetrieve) {
let found = result.filter(c => c._guid == contact._guid);
let found = result.filter(resultFilter.bind(contact));
Assert.ok(found.length, "Contact " + contact._guid + " should be in the list");
compareContacts(found[0], contact);
}

View File

@ -6,6 +6,8 @@
* effects - rather than just testing MozLoopAPI alone.
*/
"use strict";
Components.utils.import("resource://gre/modules/Promise.jsm", this);
add_task(loadLoopPanel);

View File

@ -6,6 +6,8 @@
* effects - rather than just testing MozLoopAPI alone.
*/
"use strict";
Components.utils.import("resource://gre/modules/Promise.jsm", this);
add_task(loadLoopPanel);

View File

@ -1,21 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This is an integration test from navigator.mozLoop through to the end
* effects - rather than just testing MozLoopAPI alone.
*/
Components.utils.import("resource://gre/modules/Promise.jsm", this);
add_task(loadLoopPanel);
add_task(function* test_mozLoop_pluralStrings() {
Assert.ok(gMozLoopAPI, "mozLoop should exist");
var strings = JSON.parse(gMozLoopAPI.getStrings("feedback_window_will_close_in2"));
Assert.equal(gMozLoopAPI.getPluralForm(0, strings.textContent),
"This window will close in {{countdown}} seconds");
Assert.equal(gMozLoopAPI.getPluralForm(1, strings.textContent),
"This window will close in {{countdown}} second");
});
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This is an integration test from navigator.mozLoop through to the end
* effects - rather than just testing MozLoopAPI alone.
*/
"use strict";
Components.utils.import("resource://gre/modules/Promise.jsm", this);
add_task(loadLoopPanel);
add_task(function* test_mozLoop_pluralStrings() {
Assert.ok(gMozLoopAPI, "mozLoop should exist");
var strings = JSON.parse(gMozLoopAPI.getStrings("feedback_window_will_close_in2"));
Assert.equal(gMozLoopAPI.getPluralForm(0, strings.textContent),
"This window will close in {{countdown}} seconds");
Assert.equal(gMozLoopAPI.getPluralForm(1, strings.textContent),
"This window will close in {{countdown}} second");
});

View File

@ -6,6 +6,8 @@
* effects - rather than just testing MozLoopAPI alone.
*/
"use strict";
Components.utils.import("resource://gre/modules/Promise.jsm", this);
add_task(loadLoopPanel);

View File

@ -6,6 +6,8 @@
* effects - rather than just testing MozLoopAPI alone.
*/
"use strict";
Cu.import("resource://gre/modules/Promise.jsm");
const {SocialService} = Cu.import("resource://gre/modules/SocialService.jsm", {});

View File

@ -4,6 +4,9 @@
/*
* This file contains tests for the mozLoop telemetry API.
*/
"use strict";
Components.utils.import("resource://gre/modules/Promise.jsm", this);
add_task(loadLoopPanel);
@ -23,7 +26,7 @@ add_task(function* test_initialize() {
* Tests that enumerated bucket histograms exist and can be updated.
*/
add_task(function* test_mozLoop_telemetryAdd_buckets() {
let histogramId = "LOOP_TWO_WAY_MEDIA_CONN_LENGTH";
let histogramId = "LOOP_TWO_WAY_MEDIA_CONN_LENGTH_1";
let histogram = Services.telemetry.getHistogramById(histogramId);
let CONN_LENGTH = gMozLoopAPI.TWO_WAY_MEDIA_CONN_LENGTH;
@ -49,7 +52,7 @@ add_task(function* test_mozLoop_telemetryAdd_buckets() {
});
add_task(function* test_mozLoop_telemetryAdd_sharing_buckets() {
let histogramId = "LOOP_SHARING_STATE_CHANGE";
let histogramId = "LOOP_SHARING_STATE_CHANGE_1";
let histogram = Services.telemetry.getHistogramById(histogramId);
const SHARING_STATES = gMozLoopAPI.SHARING_STATE_CHANGE;

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const HAWK_TOKEN_LENGTH = 64;
const {
LOOP_SESSION_TYPE,
@ -123,8 +125,8 @@ function loadLoopPanel(aOverrideOptions = {}) {
let loopPanel = document.getElementById("loop-notification-panel");
loopPanel.setAttribute("animate", "false");
// Now get the actual API.
yield promiseGetMozLoopAPI();
// Now get the actual API loaded into gMozLoopAPI.
return promiseGetMozLoopAPI();
}
function promiseOAuthParamsSetup(baseURL, params) {
@ -319,7 +321,7 @@ const mockDb = {
callback(null, details);
},
remove: function(guid, callback) {
if (!guid in this._store) {
if (!(guid in this._store)) {
callback(new Error("Could not find _guid '" + guid + "' in database"));
return;
}

View File

@ -473,7 +473,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(mozLoop.telemetryAddValue);
sinon.assert.calledWith(mozLoop.telemetryAddValue,
"LOOP_TWO_WAY_MEDIA_CONN_LENGTH",
"LOOP_TWO_WAY_MEDIA_CONN_LENGTH_1",
mozLoop.TWO_WAY_MEDIA_CONN_LENGTH.SHORTER_THAN_10S);
});
@ -485,7 +485,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(mozLoop.telemetryAddValue);
sinon.assert.calledWith(mozLoop.telemetryAddValue,
"LOOP_TWO_WAY_MEDIA_CONN_LENGTH",
"LOOP_TWO_WAY_MEDIA_CONN_LENGTH_1",
mozLoop.TWO_WAY_MEDIA_CONN_LENGTH.BETWEEN_10S_AND_30S);
});
@ -497,7 +497,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(mozLoop.telemetryAddValue);
sinon.assert.calledWith(mozLoop.telemetryAddValue,
"LOOP_TWO_WAY_MEDIA_CONN_LENGTH",
"LOOP_TWO_WAY_MEDIA_CONN_LENGTH_1",
mozLoop.TWO_WAY_MEDIA_CONN_LENGTH.BETWEEN_30S_AND_5M);
});
@ -508,7 +508,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(mozLoop.telemetryAddValue);
sinon.assert.calledWith(mozLoop.telemetryAddValue,
"LOOP_TWO_WAY_MEDIA_CONN_LENGTH",
"LOOP_TWO_WAY_MEDIA_CONN_LENGTH_1",
mozLoop.TWO_WAY_MEDIA_CONN_LENGTH.MORE_THAN_5M);
});
@ -530,7 +530,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(mozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(mozLoop.telemetryAddValue,
"LOOP_SHARING_STATE_CHANGE",
"LOOP_SHARING_STATE_CHANGE_1",
mozLoop.SHARING_STATE_CHANGE.WINDOW_ENABLED);
});
@ -539,7 +539,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(mozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(mozLoop.telemetryAddValue,
"LOOP_SHARING_STATE_CHANGE",
"LOOP_SHARING_STATE_CHANGE_1",
mozLoop.SHARING_STATE_CHANGE.BROWSER_ENABLED);
});
@ -548,7 +548,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(mozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(mozLoop.telemetryAddValue,
"LOOP_SHARING_STATE_CHANGE",
"LOOP_SHARING_STATE_CHANGE_1",
mozLoop.SHARING_STATE_CHANGE.WINDOW_DISABLED);
});
@ -557,7 +557,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(mozLoop.telemetryAddValue);
sinon.assert.calledWithExactly(mozLoop.telemetryAddValue,
"LOOP_SHARING_STATE_CHANGE",
"LOOP_SHARING_STATE_CHANGE_1",
mozLoop.SHARING_STATE_CHANGE.BROWSER_DISABLED);
});
});

View File

@ -145,6 +145,31 @@ describe("loop.shared.utils", function() {
});
});
describe("#formatURL", function() {
it("should decode encoded URIs", function() {
expect(sharedUtils.formatURL("http://invalid.com/?a=Foo%20Bar"))
.eql({
location: "http://invalid.com/?a=Foo Bar",
hostname: "invalid.com"
});
});
it("should change some idn urls to ascii encoded", function() {
// Note, this is based on the browser's list of what does/doesn't get
// altered for punycode, so if the list changes this could change in the
// future.
expect(sharedUtils.formatURL("http://\u0261oogle.com/"))
.eql({
location: "http://xn--oogle-qmc.com/",
hostname: "xn--oogle-qmc.com"
});
});
it("should return null if it the url is not valid", function() {
expect(sharedUtils.formatURL("hinvalid//url")).eql(null);
});
});
describe("#composeCallUrlEmail", function() {
var composeEmail;

View File

@ -13,6 +13,7 @@ describe("loop.standaloneRoomViews", function() {
var FEEDBACK_STATES = loop.store.FEEDBACK_STATES;
var ROOM_INFO_FAILURES = loop.shared.utils.ROOM_INFO_FAILURES;
var sharedActions = loop.shared.actions;
var sharedUtils = loop.shared.utils;
var sandbox, dispatcher, activeRoomStore, feedbackStore, dispatch;
@ -96,6 +97,26 @@ describe("loop.standaloneRoomViews", function() {
expect(view.getDOMNode().querySelector(".standalone-context-url")).not.eql(null);
});
it("should format the url for display", function() {
sandbox.stub(sharedUtils, "formatURL").returns({
location: "location",
hostname: "hostname"
});
var view = mountTestComponent({
roomName: "Mike's room",
roomContextUrls: [{
description: "Mark's super page",
location: "http://invalid.com",
thumbnail: "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
}]
});
expect(view.getDOMNode()
.querySelector(".standalone-context-url-description-wrapper > a").textContent)
.eql("hostname");
});
it("should not display context information if no urls are supplied", function() {
var view = mountTestComponent({
roomName: "Mike's room"

View File

@ -0,0 +1,17 @@
{
"ecmaFeatures": {
"arrowFunctions": true,
"blockBindings": true,
"destructuring": true,
"generators": true,
"restParams": true,
"spread": true,
"objectLiteralShorthandMethods": true,
},
"rules": {
"generator-star-spacing": [2, "after"],
// We should fix the errors and enable this (set to 2)
"no-var": 0,
"strict": [2, "global"]
}
}

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");

View File

@ -1,222 +1,223 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
{
let dummyCallback = () => {};
let mockWebSocket = new MockWebSocketChannel();
let pushServerRequestCount = 0;
add_test(function test_initalize_offline() {
Services.io.offline = true;
do_check_false(MozLoopPushHandler.initialize());
Services.io.offline = false;
run_next_test();
});
"use strict";
add_test(function test_initalize_missing_chanid() {
Assert.throws(() => MozLoopPushHandler.register(null, dummyCallback, dummyCallback));
run_next_test();
});
let dummyCallback = () => {};
let mockWebSocket = new MockWebSocketChannel();
let pushServerRequestCount = 0;
add_test(function test_initalize_missing_regcallback() {
Assert.throws(() => MozLoopPushHandler.register("chan-1", null, dummyCallback));
run_next_test();
});
add_test(function test_initalize_offline() {
Services.io.offline = true;
do_check_false(MozLoopPushHandler.initialize());
Services.io.offline = false;
run_next_test();
});
add_test(function test_initalize_missing_notifycallback() {
Assert.throws(() => MozLoopPushHandler.register("chan-1", dummyCallback, null));
run_next_test();
});
add_test(function test_initalize_missing_chanid() {
Assert.throws(() => MozLoopPushHandler.register(null, dummyCallback, dummyCallback));
run_next_test();
});
add_test(function test_initalize_websocket() {
do_check_true(MozLoopPushHandler.initialize({mockWebSocket: mockWebSocket}));
MozLoopPushHandler.register(
"chan-1",
function(err, url, id) {
Assert.equal(err, null, "err should be null to indicate success");
Assert.equal(url, kEndPointUrl, "Should return push server application URL");
Assert.equal(id, "chan-1", "Should have channel id = chan-1");
Assert.equal(mockWebSocket.uri.prePath, kServerPushUrl,
"Should have the url from preferences");
Assert.equal(mockWebSocket.origin, kServerPushUrl,
"Should have the origin url from preferences");
Assert.equal(mockWebSocket.protocol, "push-notification",
"Should have the protocol set to push-notifications");
mockWebSocket.notify(15);
},
function(version, id) {
Assert.equal(version, 15, "Should have version number 15");
Assert.equal(id, "chan-1", "Should have channel id = chan-1");
run_next_test();
});
});
add_test(function test_initalize_missing_regcallback() {
Assert.throws(() => MozLoopPushHandler.register("chan-1", null, dummyCallback));
run_next_test();
});
add_test(function test_register_twice_same_channel() {
MozLoopPushHandler.register(
"chan-2",
function(err, url, id) {
Assert.equal(err, null, "Should return null for success");
Assert.equal(url, kEndPointUrl, "Should return push server application URL");
Assert.equal(id, "chan-2", "Should have channel id = chan-2");
Assert.equal(mockWebSocket.uri.prePath, kServerPushUrl,
"Should have the url from preferences");
Assert.equal(mockWebSocket.origin, kServerPushUrl,
"Should have the origin url from preferences");
Assert.equal(mockWebSocket.protocol, "push-notification",
"Should have the protocol set to push-notifications");
add_test(function test_initalize_missing_notifycallback() {
Assert.throws(() => MozLoopPushHandler.register("chan-1", dummyCallback, null));
run_next_test();
});
// Register again for the same channel
MozLoopPushHandler.register(
"chan-2",
function(err, url, id) {
Assert.equal(err, null, "Should return null for success");
Assert.equal(id, "chan-2", "Should have channel id = chan-2");
run_next_test();
},
dummyCallback
);
},
dummyCallback
);
});
// Test that the PushHander will re-connect after the near-end disconnect.
// The uaID is cleared to force re-registration of all notification channels.
add_test(function test_reconnect_websocket() {
MozLoopPushHandler.uaID = undefined;
mockWebSocket.stop();
// Previously registered onRegistration callbacks will fire and be checked (see above).
});
// Test that the PushHander will re-connect after the far-end disconnect.
// The uaID is cleared to force re-regsitration of all notification channels.
add_test(function test_reopen_websocket() {
MozLoopPushHandler.uaID = undefined;
MozLoopPushHandler.registeredChannels = {}; //Do this to force a new registration callback.
mockWebSocket.serverClose();
// Previously registered onRegistration callbacks will fire and be checked (see above).
});
// Force a re-registration cycle and have the PushServer return a 500.
// A retry should occur and the registration then complete.
add_test(function test_retry_registration() {
MozLoopPushHandler.uaID = undefined;
mockWebSocket.initRegStatus = 500;
mockWebSocket.stop();
});
add_test(function test_reconnect_no_registration() {
let regCnt = 0;
MozLoopPushHandler.shutdown();
MozLoopPushHandler.initialize({mockWebSocket: mockWebSocket});
MozLoopPushHandler.register(
"test-chan",
function(err, url, id) {
Assert.equal(++regCnt, 1, "onRegistered should only be called once");
Assert.equal(err, null, "err should be null to indicate success");
Assert.equal(url, kEndPointUrl, "Should return push server application URL");
Assert.equal(id, "test-chan", "Should have channel id = test-chan");
mockWebSocket.stop();
setTimeout(run_next_test(), 0);
},
dummyCallback
);
});
add_test(function test_ping_websocket() {
let pingReceived = false,
socketClosed = false;
mockWebSocket.defaultMsgHandler = (msg) => {
pingReceived = true;
// Do not send a ping response.
}
mockWebSocket.close = () => {
socketClosed = true;
}
MozLoopPushHandler.shutdown();
MozLoopPushHandler.initialize({mockWebSocket: mockWebSocket});
MozLoopPushHandler.register(
"test-chan",
function(err, url) {
Assert.equal(err, null, "err should be null to indicate success");
waitForCondition(() => pingReceived).then(() => {
waitForCondition(() => socketClosed).then(() => {
run_next_test();
}, () => {
do_throw("should have closed the websocket");
});
}, () => {
do_throw("should have sent ping");
});
},
dummyCallback
);
});
add_test(function test_retry_pushurl() {
MozLoopPushHandler.shutdown();
loopServer.registerPathHandler("/push-server-config", (request, response) => {
// The PushHandler should retry the request for the push-server-config for
// each of these cases without throwing an error.
let n = 0;
switch (++pushServerRequestCount) {
case ++n:
// Non-200 response
response.setStatusLine(null, 500, "Retry");
response.processAsync();
response.finish();
break;
case ++n:
// missing parameter
response.setStatusLine(null, 200, "OK");
response.write(JSON.stringify({pushServerURI: null}));
response.processAsync();
response.finish();
break;
case ++n:
// json parse error
response.setStatusLine(null, 200, "OK");
response.processAsync();
response.finish();
break;
case ++n:
response.setStatusLine(null, 200, "OK");
response.write(JSON.stringify({pushServerURI: kServerPushUrl}));
response.processAsync();
response.finish();
run_next_test();
break;
}
add_test(function test_initalize_websocket() {
do_check_true(MozLoopPushHandler.initialize({mockWebSocket: mockWebSocket}));
MozLoopPushHandler.register(
"chan-1",
function(err, url, id) {
Assert.equal(err, null, "err should be null to indicate success");
Assert.equal(url, kEndPointUrl, "Should return push server application URL");
Assert.equal(id, "chan-1", "Should have channel id = chan-1");
Assert.equal(mockWebSocket.uri.prePath, kServerPushUrl,
"Should have the url from preferences");
Assert.equal(mockWebSocket.origin, kServerPushUrl,
"Should have the origin url from preferences");
Assert.equal(mockWebSocket.protocol, "push-notification",
"Should have the protocol set to push-notifications");
mockWebSocket.notify(15);
},
function(version, id) {
Assert.equal(version, 15, "Should have version number 15");
Assert.equal(id, "chan-1", "Should have channel id = chan-1");
run_next_test();
});
});
do_check_true(MozLoopPushHandler.initialize({mockWebSocket: mockWebSocket}));
});
add_test(function test_register_twice_same_channel() {
MozLoopPushHandler.register(
"chan-2",
function(err, url, id) {
Assert.equal(err, null, "Should return null for success");
Assert.equal(url, kEndPointUrl, "Should return push server application URL");
Assert.equal(id, "chan-2", "Should have channel id = chan-2");
Assert.equal(mockWebSocket.uri.prePath, kServerPushUrl,
"Should have the url from preferences");
Assert.equal(mockWebSocket.origin, kServerPushUrl,
"Should have the origin url from preferences");
Assert.equal(mockWebSocket.protocol, "push-notification",
"Should have the protocol set to push-notifications");
function run_test() {
setupFakeLoopServer();
// Register again for the same channel
MozLoopPushHandler.register(
"chan-2",
function(err, url, id) {
Assert.equal(err, null, "Should return null for success");
Assert.equal(id, "chan-2", "Should have channel id = chan-2");
run_next_test();
},
dummyCallback
);
},
dummyCallback
);
});
loopServer.registerPathHandler("/push-server-config", (request, response) => {
// Test that the PushHander will re-connect after the near-end disconnect.
// The uaID is cleared to force re-registration of all notification channels.
add_test(function test_reconnect_websocket() {
MozLoopPushHandler.uaID = undefined;
mockWebSocket.stop();
// Previously registered onRegistration callbacks will fire and be checked (see above).
});
// Test that the PushHander will re-connect after the far-end disconnect.
// The uaID is cleared to force re-regsitration of all notification channels.
add_test(function test_reopen_websocket() {
MozLoopPushHandler.uaID = undefined;
MozLoopPushHandler.registeredChannels = {}; //Do this to force a new registration callback.
mockWebSocket.serverClose();
// Previously registered onRegistration callbacks will fire and be checked (see above).
});
// Force a re-registration cycle and have the PushServer return a 500.
// A retry should occur and the registration then complete.
add_test(function test_retry_registration() {
MozLoopPushHandler.uaID = undefined;
mockWebSocket.initRegStatus = 500;
mockWebSocket.stop();
});
add_test(function test_reconnect_no_registration() {
let regCnt = 0;
MozLoopPushHandler.shutdown();
MozLoopPushHandler.initialize({mockWebSocket: mockWebSocket});
MozLoopPushHandler.register(
"test-chan",
function(err, url, id) {
Assert.equal(++regCnt, 1, "onRegistered should only be called once");
Assert.equal(err, null, "err should be null to indicate success");
Assert.equal(url, kEndPointUrl, "Should return push server application URL");
Assert.equal(id, "test-chan", "Should have channel id = test-chan");
mockWebSocket.stop();
setTimeout(run_next_test(), 0);
},
dummyCallback
);
});
add_test(function test_ping_websocket() {
let pingReceived = false,
socketClosed = false;
mockWebSocket.defaultMsgHandler = (msg) => {
pingReceived = true;
// Do not send a ping response.
}
mockWebSocket.close = () => {
socketClosed = true;
}
MozLoopPushHandler.shutdown();
MozLoopPushHandler.initialize({mockWebSocket: mockWebSocket});
MozLoopPushHandler.register(
"test-chan",
function(err, url) {
Assert.equal(err, null, "err should be null to indicate success");
waitForCondition(() => pingReceived).then(() => {
waitForCondition(() => socketClosed).then(() => {
run_next_test();
}, () => {
do_throw("should have closed the websocket");
});
}, () => {
do_throw("should have sent ping");
});
},
dummyCallback
);
});
add_test(function test_retry_pushurl() {
MozLoopPushHandler.shutdown();
loopServer.registerPathHandler("/push-server-config", (request, response) => {
// The PushHandler should retry the request for the push-server-config for
// each of these cases without throwing an error.
let n = 0;
switch (++pushServerRequestCount) {
case ++n:
// Non-200 response
response.setStatusLine(null, 500, "Retry");
response.processAsync();
response.finish();
break;
case ++n:
// missing parameter
response.setStatusLine(null, 200, "OK");
response.write(JSON.stringify({pushServerURI: null}));
response.processAsync();
response.finish();
break;
case ++n:
// json parse error
response.setStatusLine(null, 200, "OK");
response.processAsync();
response.finish();
break;
case ++n:
response.setStatusLine(null, 200, "OK");
response.write(JSON.stringify({pushServerURI: kServerPushUrl}));
response.processAsync();
response.finish();
});
Services.prefs.setCharPref("services.push.serverURL", kServerPushUrl);
Services.prefs.setIntPref("loop.retry_delay.start", 10); // 10 ms
Services.prefs.setIntPref("loop.retry_delay.limit", 20); // 20 ms
Services.prefs.setIntPref("loop.ping.interval", 50); // 50 ms
Services.prefs.setIntPref("loop.ping.timeout", 20); // 20 ms
run_next_test();
break;
}
});
do_register_cleanup(function() {
Services.prefs.clearUserPref("services.push.serverULR");
Services.prefs.clearUserPref("loop.retry_delay.start");
Services.prefs.clearUserPref("loop.retry_delay.limit");
Services.prefs.clearUserPref("loop.ping.interval");
Services.prefs.clearUserPref("loop.ping.timeout");
});
do_check_true(MozLoopPushHandler.initialize({mockWebSocket: mockWebSocket}));
});
run_next_test();
};
}
function run_test() {
setupFakeLoopServer();
loopServer.registerPathHandler("/push-server-config", (request, response) => {
response.setStatusLine(null, 200, "OK");
response.write(JSON.stringify({pushServerURI: kServerPushUrl}));
response.processAsync();
response.finish();
});
Services.prefs.setCharPref("services.push.serverURL", kServerPushUrl);
Services.prefs.setIntPref("loop.retry_delay.start", 10); // 10 ms
Services.prefs.setIntPref("loop.retry_delay.limit", 20); // 20 ms
Services.prefs.setIntPref("loop.ping.interval", 50); // 50 ms
Services.prefs.setIntPref("loop.ping.timeout", 20); // 20 ms
do_register_cleanup(function() {
Services.prefs.clearUserPref("services.push.serverULR");
Services.prefs.clearUserPref("loop.retry_delay.start");
Services.prefs.clearUserPref("loop.retry_delay.limit");
Services.prefs.clearUserPref("loop.ping.interval");
Services.prefs.clearUserPref("loop.ping.timeout");
});
run_next_test();
};

View File

@ -2,6 +2,8 @@
* 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/. */
"use strict";
Cu.import("resource://services-common/utils.js");
Cu.import("resource:///modules/loop/LoopRooms.jsm");
Cu.import("resource:///modules/Chat.jsm");

View File

@ -2,6 +2,8 @@
* 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/. */
"use strict";
const { LoopCallsInternal } = Cu.import("resource:///modules/loop/LoopCalls.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "Chat",

View File

@ -2,6 +2,8 @@
* 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/. */
"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "Chat",
"resource:///modules/Chat.jsm");
let openChatOrig = Chat.open;

View File

@ -2,6 +2,8 @@
* 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/. */
"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "Chat",
"resource:///modules/Chat.jsm");
let openChatOrig = Chat.open;
@ -41,7 +43,7 @@ add_test(function test_do_not_disturb_disabled_should_open_chat_window() {
mockPushHandler.notify(1, MozLoopService.channelIDs.callsFxA);
waitForCondition(function() opened).then(() => {
waitForCondition(() => opened).then(() => {
run_next_test();
}, () => {
do_throw("should have opened a chat window");

View File

@ -2,6 +2,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/* global Services, Assert */
"use strict";
const kGuestKeyPref = "loop.key";
const kFxAKeyPref = "loop.key.fxa";

View File

@ -1,13 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let startTimerCalled = false;
/**
* Tests that registration doesn't happen when the expiry time is
* not set.
*/
add_task(function test_initialize_no_expiry() {
add_task(function* test_initialize_no_expiry() {
startTimerCalled = false;
let initializedPromise = yield MozLoopService.initialize();

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function test_locale() {
// Set the pref to something controlled.
Services.prefs.setCharPref("general.useragent.locale", "ab-CD");

View File

@ -2,6 +2,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/*global XPCOMUtils, Services, Assert */
"use strict";
var fakeCharPrefName = "color";
var fakeBoolPrefName = "boolean";
var fakePrefValue = "green";

View File

@ -2,6 +2,8 @@
* 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/. */
"use strict";
XPCOMUtils.defineLazyModuleGetter(this, "Chat",
"resource:///modules/Chat.jsm");
@ -20,7 +22,7 @@ add_test(function test_openChatWindow_on_notification() {
mockPushHandler.notify(1, MozLoopService.channelIDs.callsFxA);
waitForCondition(function() opened).then(() => {
waitForCondition(() => opened).then(() => {
do_check_true(opened, "should open a chat window");
do_check_eq(Services.prefs.getCharPref("loop.seenToS"), "seen",

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://services-common/utils.js");
/**

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://services-common/utils.js");

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const FAKE_FXA_TOKEN_DATA = JSON.stringify({
"token_type": "bearer",
"access_token": "1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1752",
@ -20,7 +22,7 @@ const LOOP_INITIAL_DELAY_PREF = "loop.initialDelay";
* This file is to test restart+reauth.
*/
add_task(function test_initialize_with_no_guest_rooms_and_no_auth_token() {
add_task(function* test_initialize_with_no_guest_rooms_and_no_auth_token() {
// Set time to be 2 seconds in the past.
var nowSeconds = Date.now() / 1000;
Services.prefs.setBoolPref(LOOP_CREATED_ROOM_PREF, false);
@ -34,7 +36,7 @@ add_task(function test_initialize_with_no_guest_rooms_and_no_auth_token() {
});
});
add_task(function test_initialize_with_created_room_and_no_auth_token() {
add_task(function* test_initialize_with_created_room_and_no_auth_token() {
Services.prefs.setBoolPref(LOOP_CREATED_ROOM_PREF, true);
Services.prefs.clearUserPref(LOOP_FXA_TOKEN_PREF);
@ -50,7 +52,7 @@ add_task(function test_initialize_with_created_room_and_no_auth_token() {
});
});
add_task(function test_initialize_with_invalid_fxa_token() {
add_task(function* test_initialize_with_invalid_fxa_token() {
Services.prefs.setCharPref(LOOP_FXA_PROFILE_PREF, FAKE_FXA_PROFILE);
Services.prefs.setCharPref(LOOP_FXA_TOKEN_PREF, FAKE_FXA_TOKEN_DATA);
@ -83,7 +85,7 @@ add_task(function test_initialize_with_invalid_fxa_token() {
});
});
add_task(function test_initialize_with_fxa_token() {
add_task(function* test_initialize_with_fxa_token() {
Services.prefs.setCharPref(LOOP_FXA_PROFILE_PREF, FAKE_FXA_PROFILE);
Services.prefs.setCharPref(LOOP_FXA_TOKEN_PREF, FAKE_FXA_TOKEN_DATA);

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const LOOP_HAWK_PREF = "loop.hawk-session-token";
const fakeSessionToken1 = "1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1751";
const fakeSessionToken2 = "1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1750";

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test that things behave reasonably when a reasonable Hawk-Session-Token
* header is returned with the registration response.

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
add_test(function test_registration_uses_hawk_session_token() {
Services.prefs.setCharPref("loop.hawk-session-token",
"1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1750");

View File

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// XXX should report error if Hawk-Session-Token is lexically invalid
// (not a string of 64 hex digits) to help resist other possible injection
// attacks. For now, however, we're just checking if it's the right length.

View File

@ -1004,12 +1004,14 @@ let gEditItemOverlay = {
aLastModified, aItemType) {
if (aProperty == "tags" && this._paneInfo.visibleRows.has("tagsRow"))
this._onTagsChange(aItemId);
else if (this._paneInfo.isItem && aProperty == "title")
this._onItemTitleChange(aItemId, aValue);
else (!this._paneInfo.isItem || this._paneInfo.itemId != aItemId)
else if (!this._paneInfo.isItem || this._paneInfo.itemId != aItemId)
return;
switch (aProperty) {
case "title":
if (this._paneInfo.isItem)
this._onItemTitleChange(aItemId, aValue);
break;
case "uri":
let newURI = NetUtil.newURI(aValue);
if (!newURI.equals(this._paneInfo.uri)) {

View File

@ -1468,6 +1468,12 @@ this.UITour = {
showInfoPanel.bind(this, this._correctAnchor(aAnchor.node)));
},
isInfoOnTarget(aChromeWindow, aTargetName) {
let document = aChromeWindow.document;
let tooltip = document.getElementById("UITourTooltip");
return tooltip.getAttribute("targetName") == aTargetName && tooltip.state != "closed";
},
hideInfo: function(aWindow) {
let document = aWindow.document;

View File

@ -26,6 +26,9 @@ loader.lazyRequireGetter(this, "MarkersOverview",
loader.lazyRequireGetter(this, "EventEmitter",
"devtools/toolkit/event-emitter");
// TODO get rid of retro mode in bug 1160313
loader.lazyRequireGetter(this, "Services");
/**
* For line graphs
*/
@ -165,6 +168,24 @@ const GRAPH_DEFINITIONS = {
}
};
// TODO get rid of retro mode in bug 1160313
const GRAPH_DEFINITIONS_RETRO = {
memory: {
constructor: MemoryGraph,
selector: "#memory-overview",
},
framerate: {
constructor: FramerateGraph,
selector: "#time-framerate",
needsBlueprints: true,
primaryLink: true
},
timeline: {
constructor: TimelineGraph,
selector: "#markers-overview",
}
};
/**
* A controller for orchestrating the performance's tool overview graphs. Constructs,
* syncs, toggles displays and defines the memory, framerate and timeline view.
@ -177,7 +198,9 @@ const GRAPH_DEFINITIONS = {
function GraphsController ({ definition, root, getBlueprint, getTheme }) {
this._graphs = {};
this._enabled = new Set();
this._definition = definition || GRAPH_DEFINITIONS;
// TODO get rid of retro mode in bug 1160313
let RETRO_MODE = Services.prefs.getBoolPref("devtools.performance.ui.retro-mode");
this._definition = definition || (RETRO_MODE ? GRAPH_DEFINITIONS_RETRO : GRAPH_DEFINITIONS);
this._root = root;
this._getBlueprint = getBlueprint;
this._getTheme = getTheme;

View File

@ -284,11 +284,16 @@ let PerformanceController = {
* when the front has started to record.
*/
startRecording: Task.async(function *() {
// Store retro-mode here so we can easily list true/false
// values for reverting.
// TODO bug 1160313
let superMode = !this.getOption("retro-mode");
let options = {
withMarkers: true,
withMemory: this.getOption("enable-memory"),
withMarkers: superMode ? true : false,
withMemory: superMode ? this.getOption("enable-memory") : false,
withTicks: this.getOption("enable-framerate"),
withAllocations: this.getOption("enable-memory"),
withAllocations: superMode ? this.getOption("enable-memory") : false,
allocationsSampleProbability: this.getPref("memory-sample-probability"),
allocationsMaxLogLength: this.getPref("memory-max-log-length"),
bufferSize: this.getPref("profiler-buffer-size"),

View File

@ -122,5 +122,10 @@ support-files =
[browser_profiler_tree-view-06.js]
[browser_profiler_tree-view-07.js]
[browser_profiler_tree-view-08.js]
[browser_timeline_blueprint.js]
[browser_timeline_filters.js]
[browser_timeline-blueprint.js]
[browser_timeline-filters.js]
[browser_timeline-waterfall-background.js]
[browser_timeline-waterfall-generic.js]
[browser_timeline-waterfall-sidebar.js]
# remove in bug 1160313
[browser_retro-test.js]

View File

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that only js-calltree view is on, default, and many things are hidden
* when in retro mode.
*/
const HIDDEN_OPTIONS = ["option-enable-memory", "option-invert-flame-graph", "option-show-jit-optimizations", "option-flatten-tree-recursion"];
Services.prefs.setBoolPref("devtools.performance.ui.retro-mode", true);
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, PerformanceController, $, $$, JsCallTreeView } = panel.panelWin;
yield startRecording(panel);
yield stopRecording(panel);
let model = PerformanceController.getCurrentRecording();
ok(model.getMemory().length === 0, "model did not record memory.");
ok(model.getTicks().length !== 0, "model did get ticks.");
ok(model.getAllocations().sites.length === 0, "model did get allocation data.");
ok(model.getAllocations().timestamps.length === 0, "model did get allocation data.");
ok(model.getAllocations().frames.length === 0, "model did get allocation data.");
ok(model.getAllocations().counts.length === 0, "model did get allocation data.");
ok(DetailsView.isViewSelected(JsCallTreeView),
"The jscalltree view is selected by default");
for (let option of $$("#performance-options-menupopup > menuitem")) {
if (HIDDEN_OPTIONS.indexOf(option.id) !== -1) {
ok(option.hidden === true, `${option.id} should be hidden.`);
} else {
ok(option.hidden === false, `${option.id} should be visible.`);
}
}
for (let viewbutton of $$("#performance-toolbar-controls-detail-views > toolbarbutton")) {
ok (viewbutton.hidden === true, `${viewbutton.id} should be hidden.`);
}
ok($("#markers-overview").hidden, "markers overview should be hidden.");
ok($("#memory-overview").hidden, "memory overview should be hidden.");
ok(!$("#time-framerate").hidden, "framerate should be shown.");
yield teardown(panel);
finish();
}

View File

@ -0,0 +1,53 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the waterfall background is a 1px high canvas stretching across
* the container bounds.
*/
function spawnTest () {
let { target, panel } = yield initPerformance(SIMPLE_URL);
let { $, EVENTS, PerformanceController, OverviewView, DetailsView, WaterfallView } = panel.panelWin;
yield startRecording(panel);
ok(true, "Recording has started.");
let updated = 0;
OverviewView.on(EVENTS.OVERVIEW_RENDERED, () => updated++);
ok((yield waitUntil(() => updated > 0)),
"The overview graphs were updated a bunch of times.");
ok((yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length > 0)),
"There are some markers available.");
let rendered = Promise.all([
DetailsView.selectView("waterfall"),
once(WaterfallView, EVENTS.WATERFALL_RENDERED)
]);
yield stopRecording(panel);
ok(true, "Recording has ended.");
yield rendered;
// Test the waterfall background.
let parentWidth = $("#waterfall-view").getBoundingClientRect().width;
let sidebarWidth = $(".waterfall-sidebar").getBoundingClientRect().width;
let detailsWidth = $("#waterfall-details").getBoundingClientRect().width;
let waterfallWidth = WaterfallView.waterfall._waterfallWidth;
is(waterfallWidth, parentWidth - sidebarWidth - detailsWidth,
"The waterfall width is correct.")
ok(WaterfallView.waterfall._canvas,
"A canvas should be created after the recording ended.");
ok(WaterfallView.waterfall._ctx,
"A 2d context should be created after the recording ended.");
is(WaterfallView.waterfall._canvas.width, waterfallWidth,
"The canvas width is correct.");
is(WaterfallView.waterfall._canvas.height, 1,
"The canvas height is correct.");
yield teardown(panel);
finish();
}

View File

@ -5,22 +5,22 @@
* Tests if the waterfall is properly built after finishing a recording.
*/
add_task(function*() {
let { target, panel } = yield initTimelinePanel(SIMPLE_URL);
let { $, $$, EVENTS, TimelineController } = panel.panelWin;
function spawnTest () {
let { target, panel } = yield initPerformance(SIMPLE_URL);
let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
yield TimelineController.toggleRecording();
yield startRecording(panel);
ok(true, "Recording has started.");
let updated = 0;
panel.panelWin.on(EVENTS.OVERVIEW_UPDATED, () => updated++);
OverviewView.on(EVENTS.OVERVIEW_RENDERED, () => updated++);
ok((yield waitUntil(() => updated > 0)),
"The overview graphs were updated a bunch of times.");
ok((yield waitUntil(() => TimelineController.getMarkers().length > 0)),
ok((yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length > 0)),
"There are some markers available.");
yield TimelineController.toggleRecording();
yield stopRecording(panel);
ok(true, "Recording has ended.");
// Test the header container.
@ -62,4 +62,6 @@ add_task(function*() {
"Some marker waterfall nodes should have been created.");
ok($$(".waterfall-marker-item:not(spacer) > .waterfall-marker-bar").length,
"Some marker color bars should have been created inside the waterfall.");
});
yield teardown(panel);
finish();
}

View File

@ -5,35 +5,34 @@
* Tests if the sidebar is properly updated when a marker is selected.
*/
add_task(function*() {
let { target, panel } = yield initTimelinePanel(SIMPLE_URL);
let { $, $$, EVENTS, TimelineController, TimelineView, TIMELINE_BLUEPRINT} = panel.panelWin;
let { L10N } = devtools.require("devtools/shared/timeline/global");
function spawnTest () {
let { target, panel } = yield initPerformance(SIMPLE_URL);
let { $, $$, EVENTS, PerformanceController, OverviewView } = panel.panelWin;
let { L10N, TIMELINE_BLUEPRINT } = devtools.require("devtools/shared/timeline/global");
yield TimelineController.toggleRecording();
yield startRecording(panel);
ok(true, "Recording has started.");
yield waitUntil(() => {
// Wait until we get 3 different markers.
let markers = TimelineController.getMarkers();
let markers = PerformanceController.getCurrentRecording().getMarkers();
return markers.some(m => m.name == "Styles") &&
markers.some(m => m.name == "Reflow") &&
markers.some(m => m.name == "Paint");
});
yield TimelineController.toggleRecording();
yield stopRecording(panel);
ok(true, "Recording has ended.");
// Select everything
TimelineView.markersOverview.setSelection({ start: 0, end: TimelineView.markersOverview.width })
OverviewView.graphs.get("timeline").setSelection({ start: 0, end: OverviewView.graphs.get("timeline").width })
let bars = $$(".waterfall-marker-item:not(spacer) > .waterfall-marker-bar");
let markers = TimelineController.getMarkers();
let markers = PerformanceController.getCurrentRecording().getMarkers();
ok(bars.length > 2, "got at least 3 markers");
let sidebar = $("#timeline-waterfall-details");
let sidebar = $("#waterfall-details");
for (let i = 0; i < bars.length; i++) {
let bar = bars[i];
bar.click();
@ -41,7 +40,7 @@ add_task(function*() {
let name = TIMELINE_BLUEPRINT[m.name].label;
is($("#timeline-waterfall-details .marker-details-type").getAttribute("value"), name,
is($("#waterfall-details .marker-details-type").getAttribute("value"), name,
"sidebar title matches markers name");
let printedStartTime = $(".marker-details-start .marker-details-labelvalue").getAttribute("value");
@ -55,4 +54,6 @@ add_task(function*() {
is(toMs(m.end), printedEndTime, "sidebar end time is valid");
is(toMs(m.end - m.start), printedDuration, "sidebar duration is valid");
}
});
yield teardown(panel);
finish();
}

View File

@ -56,6 +56,7 @@ let DEFAULT_PREFS = [
"devtools.performance.memory.max-log-length",
"devtools.performance.profiler.buffer-size",
"devtools.performance.profiler.sample-frequency-khz",
"devtools.performance.ui.retro-mode",
].reduce((prefs, pref) => {
prefs[pref] = Preferences.get(pref);
return prefs;
@ -67,6 +68,10 @@ Services.prefs.setBoolPref("devtools.performance.enabled", true);
// be affected by this pref.
Services.prefs.setBoolPref("devtools.debugger.log", false);
// Disable retro mode.
// TODO bug 1160313
Services.prefs.setBoolPref("devtools.performance.ui.retro-mode", false);
/**
* Call manually in tests that use frame script utils after initializing
* the tool. Must be called after initializing so we can detect

View File

@ -71,6 +71,12 @@ let DetailsSubview = {
*/
observedPrefs: [],
/**
* Flag specifying if this view should update while the overview selection
* area is actively being dragged by the mouse.
*/
shouldUpdateWhileMouseIsActive: false,
/**
* Called when recording stops or is selected.
*/
@ -90,7 +96,14 @@ let DetailsSubview = {
*/
_onOverviewRangeChange: function (_, interval) {
if (DetailsView.isViewSelected(this)) {
let debounced = () => this.render(interval);
let debounced = () => {
if (!this.shouldUpdateWhileMouseIsActive && OverviewView.isMouseActive) {
// Don't render yet, while the selection is still being dragged.
setNamedTimeout("range-change-debounce", this.rangeChangeDebounceTime, debounced);
} else {
this.render(interval);
}
};
setNamedTimeout("range-change-debounce", this.rangeChangeDebounceTime, debounced);
} else {
this.shouldUpdateWhenShown = true;

View File

@ -13,7 +13,7 @@ let JsCallTreeView = Heritage.extend(DetailsSubview, {
"show-platform-data"
],
rangeChangeDebounceTime: 50, // ms
rangeChangeDebounceTime: 75, // ms
/**
* Sets up the view with event binding.

View File

@ -9,6 +9,8 @@
*/
let JsFlameGraphView = Heritage.extend(DetailsSubview, {
shouldUpdateWhileMouseIsActive: true,
rerenderPrefs: [
"invert-flame-graph",
"flatten-tree-recursion",

View File

@ -9,6 +9,8 @@
*/
let MemoryFlameGraphView = Heritage.extend(DetailsSubview, {
shouldUpdateWhileMouseIsActive: true,
rerenderPrefs: [
"invert-flame-graph",
"flatten-tree-recursion",

View File

@ -16,7 +16,7 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
"hidden-markers"
],
rangeChangeDebounceTime: 10, // ms
rangeChangeDebounceTime: 75, // ms
/**
* Sets up the view with event binding.
@ -74,6 +74,11 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
*/
_onMarkerSelected: function (event, marker) {
let recording = PerformanceController.getCurrentRecording();
// Race condition in tests due to lazy rendering of markers in the
// waterfall? intermittent bug 1157523
if (!recording) {
return;
}
let frames = recording.getFrames();
if (event === "selected") {

View File

@ -94,9 +94,12 @@ let DetailsView = {
let invalidCurrentView = false;
for (let [name, { view }] of Iterator(this.components)) {
let isSupported = this._isViewSupported(name, false);
// TODO bug 1160313 get rid of retro mode checks.
let isRetro = PerformanceController.getOption("retro-mode");
let isSupported = isRetro ? name === "js-calltree" : this._isViewSupported(name, false);
$(`toolbarbutton[data-view=${name}]`).hidden = !isSupported;
// TODO bug 1160313 hide all view buttons, but let js-calltree still be "supported"
$(`toolbarbutton[data-view=${name}]`).hidden = isRetro ? true : !isSupported;
// If the view is currently selected and not supported, go back to the
// default view.

View File

@ -92,6 +92,16 @@ let OverviewView = {
yield this.graphs.destroy();
}),
/**
* Returns true if any of the overview graphs have mouse dragging active,
* false otherwise.
*/
get isMouseActive() {
return (this.markersOverview && this.markersOverview.isMouseActive) ||
(this.memoryOverview && this.memoryOverview.isMouseActive) ||
(this.framerateGraph && this.framerateGraph.isMouseActive);
},
/**
* Disabled in the event we're using a Timeline mock, so we'll have no
* timeline, ticks or memory data to show, so just block rendering and hide

Some files were not shown because too many files have changed in this diff Show More