tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_refresh_firefox.py (28649B)


      1 import os
      2 import time
      3 
      4 from marionette_driver.errors import NoAlertPresentException
      5 from marionette_harness import MarionetteTestCase
      6 
      7 
      8 # Holds info about things we need to cleanup after the tests are done.
      9 class PendingCleanup:
     10    desktop_backup_path = None
     11    reset_profile_path = None
     12    reset_profile_local_path = None
     13 
     14    def __init__(self, profile_name_to_remove):
     15        self.profile_name_to_remove = profile_name_to_remove
     16 
     17 
     18 class TestFirefoxRefresh(MarionetteTestCase):
     19    _sandbox = "firefox-refresh"
     20 
     21    _username = "marionette-test-login"
     22    _password = "marionette-test-password"
     23    _bookmarkURL = "about:mozilla"
     24    _bookmarkText = "Some bookmark from Marionette"
     25 
     26    _cookieHost = "firefox-refresh.marionette-test.mozilla.org"
     27    _cookiePath = "some/cookie/path"
     28    _cookieName = "somecookie"
     29    _cookieValue = "some cookie value"
     30 
     31    _historyURL = "http://firefox-refresh.marionette-test.mozilla.org/"
     32    _historyTitle = "Test visit for Firefox Reset"
     33 
     34    _formHistoryFieldName = "some-very-unique-marionette-only-firefox-reset-field"
     35    _formHistoryValue = "special-pumpkin-value"
     36 
     37    _formAutofillAvailable = False
     38    _formAutofillAddressGuid = None
     39 
     40    _expectedURLs = ["about:robots", "about:mozilla"]
     41    _expectedOpenGroupID = "test-open-group"
     42    _expectedSavedGroups = ["test-saved-group"]
     43 
     44    def savePassword(self):
     45        self.runAsyncCode(
     46            """
     47          let [username, password, resolve] = arguments;
     48          let myLogin = new global.LoginInfo(
     49            "test.marionette.mozilla.com",
     50            "http://test.marionette.mozilla.com/some/form/",
     51            null,
     52            username,
     53            password,
     54            "username",
     55            "password"
     56          );
     57          Services.logins.addLoginAsync(myLogin)
     58            .then(() => resolve(false), resolve);
     59        """,
     60            script_args=(self._username, self._password),
     61        )
     62 
     63    def createBookmarkInMenu(self):
     64        error = self.runAsyncCode(
     65            """
     66          // let url = arguments[0];
     67          // let title = arguments[1];
     68          // let resolve = arguments[arguments.length - 1];
     69          let [url, title, resolve] = arguments;
     70          PlacesUtils.bookmarks.insert({
     71            parentGuid: PlacesUtils.bookmarks.menuGuid, url, title
     72          }).then(() => resolve(false), resolve);
     73        """,
     74            script_args=(self._bookmarkURL, self._bookmarkText),
     75        )
     76        if error:
     77            print(error)
     78 
     79    def createBookmarksOnToolbar(self):
     80        error = self.runAsyncCode(
     81            """
     82          let resolve = arguments[arguments.length - 1];
     83          let children = [];
     84          for (let i = 1; i <= 5; i++) {
     85            children.push({url: `about:rights?p=${i}`, title: `Bookmark ${i}`});
     86          }
     87          PlacesUtils.bookmarks.insertTree({
     88            guid: PlacesUtils.bookmarks.toolbarGuid,
     89            children
     90          }).then(() => resolve(false), resolve);
     91        """
     92        )
     93        if error:
     94            print(error)
     95 
     96    def createHistory(self):
     97        error = self.runAsyncCode(
     98            """
     99          let resolve = arguments[arguments.length - 1];
    100          PlacesUtils.history.insert({
    101            url: arguments[0],
    102            title: arguments[1],
    103            visits: [{
    104              date: new Date(Date.now() - 5000),
    105              referrer: "about:mozilla"
    106            }]
    107          }).then(() => resolve(false),
    108                  ex => resolve("Unexpected error in adding visit: " + ex));
    109        """,
    110            script_args=(self._historyURL, self._historyTitle),
    111        )
    112        if error:
    113            print(error)
    114 
    115    def createFormHistory(self):
    116        error = self.runAsyncCode(
    117            """
    118          let updateDefinition = {
    119            op: "add",
    120            fieldname: arguments[0],
    121            value: arguments[1],
    122            firstUsed: (Date.now() - 5000) * 1000,
    123          };
    124          let resolve = arguments[arguments.length - 1];
    125          global.FormHistory.update(updateDefinition).then(() => {
    126            resolve(false);
    127          }, error => {
    128            resolve("Unexpected error in adding formhistory: " + error);
    129          });
    130        """,
    131            script_args=(self._formHistoryFieldName, self._formHistoryValue),
    132        )
    133        if error:
    134            print(error)
    135 
    136    def createFormAutofill(self):
    137        if not self._formAutofillAvailable:
    138            return
    139        self._formAutofillAddressGuid = self.runAsyncCode(
    140            """
    141          let resolve = arguments[arguments.length - 1];
    142          const TEST_ADDRESS_1 = {
    143            "given-name": "John",
    144            "additional-name": "R.",
    145            "family-name": "Smith",
    146            organization: "World Wide Web Consortium",
    147            "street-address": "32 Vassar Street\\\nMIT Room 32-G524",
    148            "address-level2": "Cambridge",
    149            "address-level1": "MA",
    150            "postal-code": "02139",
    151            country: "US",
    152            tel: "+15195555555",
    153            email: "user@example.com",
    154          };
    155          return global.formAutofillStorage.initialize().then(() => {
    156            return global.formAutofillStorage.addresses.add(TEST_ADDRESS_1);
    157          }).then(resolve);
    158        """
    159        )
    160 
    161    def createCookie(self):
    162        self.runCode(
    163            """
    164          // Expire in 15 minutes:
    165          let expireTime = Date.now() + 1000 * 15 * 60;
    166          Services.cookies.add(arguments[0], arguments[1], arguments[2], arguments[3],
    167                               true, false, false, expireTime, {},
    168                               Ci.nsICookie.SAMESITE_UNSET, Ci.nsICookie.SCHEME_UNSET);
    169        """,
    170            script_args=(
    171                self._cookieHost,
    172                self._cookiePath,
    173                self._cookieName,
    174                self._cookieValue,
    175            ),
    176        )
    177 
    178    def createSession(self):
    179        self.runAsyncCode(
    180            """
    181          let resolve = arguments[arguments.length - 1];
    182          const COMPLETE_STATE = Ci.nsIWebProgressListener.STATE_STOP +
    183                                 Ci.nsIWebProgressListener.STATE_IS_NETWORK;
    184          let { TabStateFlusher } = ChromeUtils.importESModule(
    185            "resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
    186          );
    187          let expectedURLs = Array.from(arguments[0])
    188          let expectedOpenGroupID = arguments[1];
    189          gBrowser.addTabsProgressListener({
    190            onStateChange(browser, webprogress, request, flags, status) {
    191              try {
    192                request && request.QueryInterface(Ci.nsIChannel);
    193              } catch (ex) {}
    194              let uriLoaded = request.originalURI && request.originalURI.spec;
    195              if ((flags & COMPLETE_STATE == COMPLETE_STATE) && uriLoaded &&
    196                  expectedURLs.includes(uriLoaded)) {
    197                TabStateFlusher.flush(browser).then(function() {
    198                  expectedURLs.splice(expectedURLs.indexOf(uriLoaded), 1);
    199                  if (!expectedURLs.length) {
    200                    gBrowser.removeTabsProgressListener(this);
    201                    resolve();
    202                  }
    203                });
    204              }
    205            }
    206          });
    207          let expectedTabs = new Set();
    208          for (let url of expectedURLs) {
    209            expectedTabs.add(gBrowser.addTab(url, {
    210              triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
    211            }));
    212          }
    213          if (expectedOpenGroupID) {
    214            gBrowser.addTabGroup([gBrowser.tabs[gBrowser.tabs.length - 1]], { id: expectedOpenGroupID });
    215          }
    216          // Close any other tabs that might be open:
    217          let allTabs = Array.from(gBrowser.tabs);
    218          for (let tab of allTabs) {
    219            if (!expectedTabs.has(tab)) {
    220              gBrowser.removeTab(tab);
    221            }
    222          }
    223        """,  # NOQA: E501
    224            script_args=(self._expectedURLs, self._expectedOpenGroupID),
    225        )
    226 
    227        self.runAsyncCode(
    228            """
    229          let resolve = arguments[arguments.length - 1];
    230          let expectedSavedGroups = Array.from(arguments[0]);
    231          let { TabStateFlusher } = ChromeUtils.importESModule(
    232            "resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
    233          );
    234 
    235          let savePromises = [];
    236          let groups = [];
    237          for (let id of expectedSavedGroups) {
    238            let tab = gBrowser.addTab("about:mozilla", {
    239              triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
    240            });
    241            let group = gBrowser.addTabGroup([tab], { id });
    242            groups.push(group);
    243            let groupSaved = new Promise(res => {
    244              window.addEventListener("TabGroupSaved", (e) => {
    245                if (e.target === group) {
    246                  res()
    247                }
    248              });
    249            });
    250            let groupRemoved = new Promise(res => {
    251              window.addEventListener("TabGroupRemoved", (e) => {
    252                if (e.target === group) {
    253                  res()
    254                }
    255              });
    256            });
    257            savePromises.push(Promise.allSettled([groupSaved, groupRemoved]));
    258          }
    259          TabStateFlusher.flushWindow(gBrowser.ownerGlobal).then(() => {
    260            groups.forEach(group => {
    261              group.saveAndClose();
    262            })
    263            Promise.allSettled(savePromises).then(resolve);
    264          });
    265 
    266        """,
    267            script_args=(self._expectedSavedGroups,),
    268        )
    269 
    270        self.assertEqual(
    271            self.marionette.execute_script(
    272                """
    273                return SessionStore.savedGroups.length;
    274                """
    275            ),
    276            len(self._expectedSavedGroups),
    277            "Correct number of groups were saved",
    278        )
    279 
    280    def createFxa(self):
    281        # This script will write an entry to the login manager and create
    282        # a signedInUser.json in the profile dir.
    283        self.runAsyncCode(
    284            """
    285          let resolve = arguments[arguments.length - 1];
    286          let { FxAccountsStorageManager } = ChromeUtils.importESModule(
    287            "resource://gre/modules/FxAccountsStorage.sys.mjs"
    288          );
    289          let storage = new FxAccountsStorageManager();
    290          let data = {email: "test@test.com", uid: "uid", keyFetchToken: "top-secret"};
    291          storage.initialize(data);
    292          storage.finalize().then(resolve);
    293        """
    294        )
    295 
    296    def createSync(self):
    297        # This script will write the canonical preference which indicates a user
    298        # is signed into sync.
    299        self.marionette.execute_script(
    300            """
    301            Services.prefs.setStringPref("services.sync.username", "test@test.com");
    302        """
    303        )
    304 
    305    def checkPassword(self):
    306        loginInfo = self.runAsyncCode(
    307            """
    308          let [resolve] = arguments;
    309          Services.logins.searchLoginsAsync({
    310            origin: "test.marionette.mozilla.com",
    311            formActionOrigin: "http://test.marionette.mozilla.com/some/form/",
    312          }).then(ary => resolve(ary.length ? ary : {username: "null", password: "null"}));
    313        """
    314        )
    315        self.assertEqual(len(loginInfo), 1)
    316        self.assertEqual(loginInfo[0]["username"], self._username)
    317        self.assertEqual(loginInfo[0]["password"], self._password)
    318 
    319        loginCount = self.runAsyncCode(
    320            """
    321          let resolve = arguments[arguments.length - 1];
    322          Services.logins.getAllLogins().then(logins => resolve(logins.length));
    323        """
    324        )
    325        # Note that we expect 2 logins - one from us, one from sync.
    326        self.assertEqual(loginCount, 2, "No other logins are present")
    327 
    328    def checkBookmarkInMenu(self):
    329        titleInBookmarks = self.runAsyncCode(
    330            """
    331          let [url, resolve] = arguments;
    332          PlacesUtils.bookmarks.fetch({url}).then(
    333            bookmark => resolve(bookmark ? bookmark.title : ""),
    334            ex => resolve(ex)
    335          );
    336        """,
    337            script_args=(self._bookmarkURL,),
    338        )
    339        self.assertEqual(titleInBookmarks, self._bookmarkText)
    340 
    341    def checkBookmarkToolbarVisibility(self):
    342        toolbarVisible = self.marionette.execute_script(
    343            """
    344          const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
    345          return Services.xulStore.getValue(BROWSER_DOCURL, "PersonalToolbar", "collapsed");
    346        """
    347        )
    348        if toolbarVisible == "":
    349            toolbarVisible = "false"
    350        self.assertEqual(toolbarVisible, "false")
    351 
    352    def checkHistory(self):
    353        historyResult = self.runAsyncCode(
    354            """
    355          let resolve = arguments[arguments.length - 1];
    356          PlacesUtils.history.fetch(arguments[0]).then(pageInfo => {
    357            if (!pageInfo) {
    358              resolve("No visits found");
    359            } else {
    360              resolve(pageInfo);
    361            }
    362          }).catch(e => {
    363            resolve("Unexpected error in fetching page: " + e);
    364          });
    365        """,
    366            script_args=(self._historyURL,),
    367        )
    368        if type(historyResult) is str:
    369            self.fail(historyResult)
    370            return
    371 
    372        self.assertEqual(historyResult["title"], self._historyTitle)
    373 
    374    def checkFormHistory(self):
    375        formFieldResults = self.runAsyncCode(
    376            """
    377          let resolve = arguments[arguments.length - 1];
    378          let results = [];
    379          global.FormHistory.search(["value"], {fieldname: arguments[0]})
    380            .then(resolve);
    381        """,
    382            script_args=(self._formHistoryFieldName,),
    383        )
    384        if type(formFieldResults) is str:
    385            self.fail(formFieldResults)
    386            return
    387 
    388        formFieldResultCount = len(formFieldResults)
    389        self.assertEqual(
    390            formFieldResultCount,
    391            1,
    392            "Should have exactly 1 entry for this field, got %d" % formFieldResultCount,
    393        )
    394        if formFieldResultCount == 1:
    395            self.assertEqual(formFieldResults[0]["value"], self._formHistoryValue)
    396 
    397        formHistoryCount = self.runAsyncCode(
    398            """
    399          let [resolve] = arguments;
    400          global.FormHistory.count({}).then(resolve);
    401        """
    402        )
    403        self.assertEqual(
    404            formHistoryCount, 1, "There should be only 1 entry in the form history"
    405        )
    406 
    407    def checkFormAutofill(self):
    408        if not self._formAutofillAvailable:
    409            return
    410 
    411        formAutofillResults = self.runAsyncCode(
    412            """
    413          let resolve = arguments[arguments.length - 1];
    414          return global.formAutofillStorage.initialize().then(() => {
    415            return global.formAutofillStorage.addresses.getAll()
    416          }).then(resolve);
    417        """,
    418        )
    419        if type(formAutofillResults) is str:
    420            self.fail(formAutofillResults)
    421            return
    422 
    423        formAutofillAddressCount = len(formAutofillResults)
    424        self.assertEqual(
    425            formAutofillAddressCount,
    426            1,
    427            "Should have exactly 1 saved address, got %d" % formAutofillAddressCount,
    428        )
    429        if formAutofillAddressCount == 1:
    430            self.assertEqual(
    431                formAutofillResults[0]["guid"], self._formAutofillAddressGuid
    432            )
    433 
    434    def checkCookie(self):
    435        cookieInfo = self.runCode(
    436            """
    437          try {
    438            let cookies = Services.cookies.getCookiesFromHost(arguments[0], {});
    439            let cookie = null;
    440            for (let hostCookie of cookies) {
    441              // getCookiesFromHost returns any cookie from the BASE host.
    442              if (hostCookie.rawHost != arguments[0])
    443                continue;
    444              if (cookie != null) {
    445                return "more than 1 cookie! That shouldn't happen!";
    446              }
    447              cookie = hostCookie;
    448            }
    449            return {path: cookie.path, name: cookie.name, value: cookie.value};
    450          } catch (ex) {
    451            return "got exception trying to fetch cookie: " + ex;
    452          }
    453        """,
    454            script_args=(self._cookieHost,),
    455        )
    456        if not isinstance(cookieInfo, dict):
    457            self.fail(cookieInfo)
    458            return
    459        self.assertEqual(cookieInfo["path"], self._cookiePath)
    460        self.assertEqual(cookieInfo["value"], self._cookieValue)
    461        self.assertEqual(cookieInfo["name"], self._cookieName)
    462 
    463    def checkSession(self):
    464        tabURIs = self.runCode(
    465            """
    466          return [... gBrowser.browsers].map(b => b.currentURI && b.currentURI.spec)
    467        """
    468        )
    469        self.assertSequenceEqual(tabURIs, ["about:welcomeback"])
    470 
    471        # Dismiss modal dialog if any. This is mainly to dismiss the check for
    472        # default browser dialog if it shows up.
    473        try:
    474            alert = self.marionette.switch_to_alert()
    475            alert.dismiss()
    476        except NoAlertPresentException:
    477            pass
    478 
    479        tabURIs = self.runAsyncCode(
    480            """
    481          let resolve = arguments[arguments.length - 1]
    482          let mm = gBrowser.selectedBrowser.messageManager;
    483 
    484          window.addEventListener("SSWindowStateReady", function() {
    485            window.addEventListener("SSTabRestored", function() {
    486              resolve(Array.from(gBrowser.browsers, b => b.currentURI?.spec));
    487            }, { capture: false, once: true });
    488          }, { capture: false, once: true });
    489 
    490          let fs = function() {
    491            if (content.document.readyState === "complete") {
    492              content.document.getElementById("errorTryAgain").click();
    493            } else {
    494              content.window.addEventListener("load", function(event) {
    495                content.document.getElementById("errorTryAgain").click();
    496              }, { once: true });
    497            }
    498          };
    499 
    500          Services.prefs.setBoolPref("security.allow_parent_unrestricted_js_loads", true);
    501          mm.loadFrameScript("data:application/javascript,(" + fs.toString() + ")()", true);
    502          Services.prefs.setBoolPref("security.allow_parent_unrestricted_js_loads", false);
    503        """  # NOQA: E501
    504        )
    505        self.assertSequenceEqual(tabURIs, self._expectedURLs)
    506 
    507        if self._expectedOpenGroupID:
    508            groupExists = self.runCode(
    509                """
    510              let groupID = arguments[0];
    511              let group = gBrowser.getTabGroupById(groupID);
    512              return !!group;
    513            """,
    514                script_args=(self._expectedOpenGroupID,),
    515            )
    516            self.assertTrue(groupExists, "open group was restored")
    517 
    518        savedGroupIDs = self.runAsyncCode(
    519            """
    520          let resolve = arguments[arguments.length - 1];
    521          let groupIDs = [];
    522          for (let group of window.SessionStore.savedGroups) {
    523            groupIDs.push(group.id);
    524          }
    525          resolve(groupIDs);
    526        """,
    527            script_args=(self._expectedSavedGroups,),
    528        )
    529        self.assertSequenceEqual(savedGroupIDs, self._expectedSavedGroups)
    530 
    531    def checkFxA(self):
    532        result = self.runAsyncCode(
    533            """
    534          let { FxAccountsStorageManager } = ChromeUtils.importESModule(
    535            "resource://gre/modules/FxAccountsStorage.sys.mjs"
    536          );
    537          let resolve = arguments[arguments.length - 1];
    538          let storage = new FxAccountsStorageManager();
    539          let result = {};
    540          storage.initialize();
    541          storage.getAccountData().then(data => {
    542            result.accountData = data;
    543            return storage.finalize();
    544          }).then(() => {
    545            resolve(result);
    546          }).catch(err => {
    547            resolve(err.toString());
    548          });
    549        """
    550        )
    551        if type(result) is not dict:
    552            self.fail(result)
    553            return
    554        self.assertEqual(result["accountData"]["email"], "test@test.com")
    555        self.assertEqual(result["accountData"]["uid"], "uid")
    556        self.assertEqual(result["accountData"]["keyFetchToken"], "top-secret")
    557 
    558    def checkSync(self, expect_sync_user):
    559        pref_value = self.marionette.execute_script(
    560            """
    561            return Services.prefs.getStringPref("services.sync.username", null);
    562        """
    563        )
    564        expected_value = "test@test.com" if expect_sync_user else None
    565        self.assertEqual(pref_value, expected_value)
    566 
    567    def checkStartupMigrationStateCleared(self):
    568        result = self.runCode(
    569            """
    570          let { MigrationUtils } = ChromeUtils.importESModule(
    571            "resource:///modules/MigrationUtils.sys.mjs"
    572          );
    573          return MigrationUtils.isStartupMigration;
    574        """
    575        )
    576        self.assertFalse(result)
    577 
    578    def checkRefreshPromptDisabled(self):
    579        refreshPromptDisabled = self.runCode(
    580            """
    581          return Services.prefs.getStringPref("browser.disableResetPrompt", false);
    582      """
    583        )
    584        self.assertTrue(refreshPromptDisabled)
    585 
    586    def checkProfile(self, has_migrated=False, expect_sync_user=True):
    587        self.checkPassword()
    588        self.checkBookmarkInMenu()
    589        self.checkHistory()
    590        self.checkFormHistory()
    591        self.checkFormAutofill()
    592        self.checkCookie()
    593        self.checkFxA()
    594        self.checkSync(expect_sync_user)
    595        if has_migrated:
    596            self.checkBookmarkToolbarVisibility()
    597            self.checkSession()
    598            self.checkStartupMigrationStateCleared()
    599            self.checkRefreshPromptDisabled()
    600 
    601    def createProfileData(self):
    602        self.savePassword()
    603        self.createBookmarkInMenu()
    604        self.createBookmarksOnToolbar()
    605        self.createHistory()
    606        self.createFormHistory()
    607        self.createFormAutofill()
    608        self.createCookie()
    609        self.createSession()
    610        self.createFxa()
    611        self.createSync()
    612 
    613    def setUpScriptData(self):
    614        self.marionette.set_context(self.marionette.CONTEXT_CHROME)
    615        self.runCode(
    616            """
    617          window.global = {};
    618          global.LoginInfo = Components.Constructor("@mozilla.org/login-manager/loginInfo;1", "nsILoginInfo", "init");
    619          global.profSvc = Cc["@mozilla.org/toolkit/profile-service;1"].getService(Ci.nsIToolkitProfileService);
    620          global.Preferences = ChromeUtils.importESModule(
    621            "resource://gre/modules/Preferences.sys.mjs"
    622          ).Preferences;
    623          global.FormHistory = ChromeUtils.importESModule(
    624            "resource://gre/modules/FormHistory.sys.mjs"
    625          ).FormHistory;
    626        """  # NOQA: E501
    627        )
    628        self._formAutofillAvailable = self.runCode(
    629            """
    630          try {
    631            global.formAutofillStorage = ChromeUtils.importESModule(
    632              "resource://formautofill/FormAutofillStorage.sys.mjs"
    633            ).formAutofillStorage;
    634          } catch(e) {
    635            return false;
    636          }
    637          return true;
    638        """  # NOQA: E501
    639        )
    640 
    641    def runCode(self, script, *args, **kwargs):
    642        return self.marionette.execute_script(
    643            script, new_sandbox=False, sandbox=self._sandbox, *args, **kwargs
    644        )
    645 
    646    def runAsyncCode(self, script, *args, **kwargs):
    647        return self.marionette.execute_async_script(
    648            script, new_sandbox=False, sandbox=self._sandbox, *args, **kwargs
    649        )
    650 
    651    def setUp(self):
    652        MarionetteTestCase.setUp(self)
    653        self.setUpScriptData()
    654 
    655        self.cleanups = []
    656 
    657    def tearDown(self):
    658        # Force yet another restart with a clean profile to disconnect from the
    659        # profile and environment changes we've made, to leave a more or less
    660        # blank slate for the next person.
    661        self.marionette.restart(in_app=False, clean=True)
    662        self.setUpScriptData()
    663 
    664        # Super
    665        MarionetteTestCase.tearDown(self)
    666 
    667        # A helper to deal with removing a load of files
    668        import mozfile
    669 
    670        for cleanup in self.cleanups:
    671            if cleanup.desktop_backup_path:
    672                mozfile.remove(cleanup.desktop_backup_path)
    673 
    674            if cleanup.reset_profile_path:
    675                # Remove ourselves from profiles.ini
    676                self.runCode(
    677                    """
    678                  let name = arguments[0];
    679                  let profile = global.profSvc.getProfileByName(name);
    680                  profile.remove(false)
    681                  global.profSvc.flush();
    682                """,
    683                    script_args=(cleanup.profile_name_to_remove,),
    684                )
    685                # Remove the local profile dir if it's not the same as the profile dir:
    686                different_path = (
    687                    cleanup.reset_profile_local_path != cleanup.reset_profile_path
    688                )
    689                if cleanup.reset_profile_local_path and different_path:
    690                    mozfile.remove(cleanup.reset_profile_local_path)
    691 
    692                # And delete all the files.
    693                mozfile.remove(cleanup.reset_profile_path)
    694 
    695    def doReset(self):
    696        profileName = "marionette-test-profile-" + str(int(time.time() * 1000))
    697        cleanup = PendingCleanup(profileName)
    698        self.runCode(
    699            """
    700          // Ensure the current (temporary) profile is in profiles.ini:
    701          let profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
    702          let profileName = arguments[1];
    703          let myProfile = global.profSvc.createProfile(profD, profileName);
    704          global.profSvc.flush()
    705 
    706          // Now add the reset parameters:
    707          let prefsToKeep = Array.from(Services.prefs.getChildList("marionette."));
    708          // Add all the modified preferences set from geckoinstance.py to avoid
    709          // non-local connections.
    710          prefsToKeep = prefsToKeep.concat(JSON.parse(
    711              Services.env.get("MOZ_MARIONETTE_REQUIRED_PREFS")));
    712          let prefObj = {};
    713          for (let pref of prefsToKeep) {
    714            prefObj[pref] = global.Preferences.get(pref);
    715          }
    716          Services.env.set("MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS", JSON.stringify(prefObj));
    717          Services.env.set("MOZ_RESET_PROFILE_RESTART", "1");
    718          Services.env.set("XRE_PROFILE_PATH", arguments[0]);
    719        """,
    720            script_args=(
    721                self.marionette.instance.profile.profile,
    722                profileName,
    723            ),
    724        )
    725 
    726        profileLeafName = os.path.basename(
    727            os.path.normpath(self.marionette.instance.profile.profile)
    728        )
    729 
    730        # Now restart the browser to get it reset:
    731        self.marionette.restart(clean=False, in_app=True)
    732        self.setUpScriptData()
    733 
    734        # Determine the new profile path (we'll need to remove it when we're done)
    735        [cleanup.reset_profile_path, cleanup.reset_profile_local_path] = self.runCode(
    736            """
    737          let profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
    738          let localD = Services.dirsvc.get("ProfLD", Ci.nsIFile);
    739          return [profD.path, localD.path];
    740        """
    741        )
    742 
    743        # Determine the backup path
    744        cleanup.desktop_backup_path = self.runCode(
    745            """
    746          let container;
    747          try {
    748            container = Services.dirsvc.get("Desk", Ci.nsIFile);
    749          } catch (ex) {
    750            container = Services.dirsvc.get("Home", Ci.nsIFile);
    751          }
    752          let bundle = Services.strings.createBundle("chrome://mozapps/locale/profile/profileSelection.properties");
    753          let dirName = bundle.formatStringFromName("resetBackupDirectory", [Services.appinfo.name]);
    754          container.append(dirName);
    755          container.append(arguments[0]);
    756          return container.path;
    757        """,  # NOQA: E501
    758            script_args=(profileLeafName,),
    759        )
    760 
    761        self.assertTrue(
    762            os.path.isdir(cleanup.reset_profile_path),
    763            "Reset profile path should be present",
    764        )
    765        self.assertTrue(
    766            os.path.isdir(cleanup.desktop_backup_path),
    767            "Backup profile path should be present",
    768        )
    769        self.assertIn(cleanup.profile_name_to_remove, cleanup.reset_profile_path)
    770        return cleanup
    771 
    772    def testResetEverything(self):
    773        self.createProfileData()
    774 
    775        self.checkProfile(expect_sync_user=True)
    776 
    777        this_cleanup = self.doReset()
    778        self.cleanups.append(this_cleanup)
    779 
    780        # Now check that we're doing OK...
    781        self.checkProfile(has_migrated=True, expect_sync_user=True)
    782 
    783    def testFxANoSync(self):
    784        # This test doesn't need to repeat all the non-sync tests...
    785        # Setup FxA but *not* sync
    786        self.createFxa()
    787 
    788        self.checkFxA()
    789        self.checkSync(False)
    790 
    791        this_cleanup = self.doReset()
    792        self.cleanups.append(this_cleanup)
    793 
    794        self.checkFxA()
    795        self.checkSync(False)