1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5"use strict"; 6 7ChromeUtils.import("resource://gre/modules/Preferences.jsm"); 8ChromeUtils.import("resource://gre/modules/Services.jsm"); 9ChromeUtils.import("resource://gre/modules/osfile.jsm"); 10ChromeUtils.import("resource://testing-common/Assert.jsm"); 11ChromeUtils.defineModuleGetter(this, "FileTestUtils", 12 "resource://testing-common/FileTestUtils.jsm"); 13 14var EXPORTED_SYMBOLS = ["EnterprisePolicyTesting", "PoliciesPrefTracker"]; 15 16var EnterprisePolicyTesting = { 17 // |json| must be an object representing the desired policy configuration, OR a 18 // path to the JSON file containing the policy configuration. 19 setupPolicyEngineWithJson: async function setupPolicyEngineWithJson(json, customSchema) { 20 let filePath; 21 if (typeof(json) == "object") { 22 filePath = FileTestUtils.getTempFile("policies.json").path; 23 24 // This file gets automatically deleted by FileTestUtils 25 // at the end of the test run. 26 await OS.File.writeAtomic(filePath, JSON.stringify(json), { 27 encoding: "utf-8", 28 }); 29 } else { 30 filePath = json; 31 } 32 33 Services.prefs.setStringPref("browser.policies.alternatePath", filePath); 34 35 let promise = new Promise(resolve => { 36 Services.obs.addObserver(function observer() { 37 Services.obs.removeObserver(observer, "EnterprisePolicies:AllPoliciesApplied"); 38 resolve(); 39 }, "EnterprisePolicies:AllPoliciesApplied"); 40 }); 41 42 // Clear any previously used custom schema 43 Cu.unload("resource:///modules/policies/schema.jsm"); 44 45 if (customSchema) { 46 let schemaModule = ChromeUtils.import("resource:///modules/policies/schema.jsm", {}); 47 schemaModule.schema = customSchema; 48 } 49 50 Services.obs.notifyObservers(null, "EnterprisePolicies:Restart"); 51 return promise; 52 }, 53 54 checkPolicyPref(prefName, expectedValue, expectedLockedness) { 55 if (expectedLockedness !== undefined) { 56 Assert.equal(Preferences.locked(prefName), expectedLockedness, `Pref ${prefName} is correctly locked/unlocked`); 57 } 58 59 Assert.equal(Preferences.get(prefName), expectedValue, `Pref ${prefName} has the correct value`); 60 }, 61 62 resetRunOnceState: function resetRunOnceState() { 63 const runOnceBaseKeys = [ 64 "browser.policies.runonce.", 65 "browser.policies.runOncePerModification." 66 ]; 67 for (let base of runOnceBaseKeys) { 68 for (let key of Services.prefs.getChildList(base, {})) { 69 if (Services.prefs.prefHasUserValue(key)) 70 Services.prefs.clearUserPref(key); 71 } 72 } 73 }, 74}; 75 76/** 77 * This helper will track prefs that have been changed 78 * by the policy engine through the setAndLockPref and 79 * setDefaultPref APIs (from Policies.jsm) and make sure 80 * that they are restored to their original values when 81 * the test ends or another test case restarts the engine. 82 */ 83var PoliciesPrefTracker = { 84 _originalFunc: null, 85 _originalValues: new Map(), 86 87 start() { 88 let PoliciesBackstage = ChromeUtils.import("resource:///modules/policies/Policies.jsm", {}); 89 this._originalFunc = PoliciesBackstage.setDefaultPref; 90 PoliciesBackstage.setDefaultPref = this.hoistedSetDefaultPref.bind(this); 91 }, 92 93 stop() { 94 this.restoreDefaultValues(); 95 96 let PoliciesBackstage = ChromeUtils.import("resource:///modules/policies/Policies.jsm", {}); 97 PoliciesBackstage.setDefaultPref = this._originalFunc; 98 this._originalFunc = null; 99 }, 100 101 hoistedSetDefaultPref(prefName, prefValue) { 102 // If this pref is seen multiple times, the very first 103 // value seen is the one that is actually the default. 104 if (!this._originalValues.has(prefName)) { 105 let defaults = new Preferences({defaultBranch: true}); 106 let stored = {}; 107 108 if (defaults.has(prefName)) { 109 stored.originalDefaultValue = defaults.get(prefName); 110 } else { 111 stored.originalDefaultValue = undefined; 112 } 113 114 if (Preferences.isSet(prefName) && 115 Preferences.get(prefName) == prefValue) { 116 // If a user value exists, and we're changing the default 117 // value to be th same as the user value, that will cause 118 // the user value to be dropped. In that case, let's also 119 // store it to ensure that we restore everything correctly. 120 stored.originalUserValue = Preferences.get(prefName); 121 } 122 123 this._originalValues.set(prefName, stored); 124 } 125 126 // Now that we've stored the original values, call the 127 // original setDefaultPref function. 128 this._originalFunc(prefName, prefValue); 129 }, 130 131 restoreDefaultValues() { 132 let defaults = new Preferences({defaultBranch: true}); 133 134 for (let [prefName, stored] of this._originalValues) { 135 // If a pref was used through setDefaultPref instead 136 // of setAndLockPref, it wasn't locked, but calling 137 // unlockPref is harmless 138 Preferences.unlock(prefName); 139 140 if (stored.originalDefaultValue !== undefined) { 141 defaults.set(prefName, stored.originalDefaultValue); 142 } else { 143 Services.prefs.getDefaultBranch("").deleteBranch(prefName); 144 } 145 146 if (stored.originalUserValue !== undefined) { 147 Preferences.set(prefName, stored.originalUserValue); 148 } 149 } 150 151 this._originalValues.clear(); 152 }, 153}; 154