Bug 1464006 - Move Normandy FilterExpressions to toolkit/components/utils r=mythmon draft
authorMathieu Leplatre <mathieu@mozilla.com>
Thu, 24 May 2018 10:48:00 +0200
changeset 799550 6d767860b0ec7fc328d7589aba5f31b0337bbe5b
parent 798691 d36cd8bdbc5c0df1d1d7a167f5fedb95c3a3648e
push id111102
push usermleplatre@mozilla.com
push dateThu, 24 May 2018 22:18:45 +0000
reviewersmythmon
bugs1464006
milestone62.0a1
Bug 1464006 - Move Normandy FilterExpressions to toolkit/components/utils r=mythmon MozReview-Commit-ID: 98SsHd2jZi8
services/common/remote-settings.js
services/common/tests/unit/test_blocklist_clients.js
services/common/tests/unit/xpcshell.ini
toolkit/components/normandy/lib/FilterExpressions.jsm
toolkit/components/normandy/lib/NormandyDriver.jsm
toolkit/components/normandy/lib/PreferenceFilters.jsm
toolkit/components/normandy/lib/RecipeRunner.jsm
toolkit/components/normandy/lib/Sampling.jsm
toolkit/components/normandy/test/browser/browser.ini
toolkit/components/normandy/test/browser/browser_FilterExpressions.js
toolkit/components/normandy/test/unit/test_Sampling.js
toolkit/components/normandy/test/unit/xpcshell.ini
toolkit/components/normandy/vendor/mozjexl.js
toolkit/components/utils/FilterExpressions.jsm
toolkit/components/utils/PreferenceFilters.jsm
toolkit/components/utils/Sampling.jsm
toolkit/components/utils/moz.build
toolkit/components/utils/mozjexl.js
toolkit/components/utils/test/unit/.eslintrc.js
toolkit/components/utils/test/unit/test_FilterExpressions.js
toolkit/components/utils/test/unit/test_Sampling.js
toolkit/components/utils/test/unit/xpcshell.ini
--- a/services/common/remote-settings.js
+++ b/services/common/remote-settings.js
@@ -19,17 +19,18 @@ ChromeUtils.defineModuleGetter(this, "Ki
 ChromeUtils.defineModuleGetter(this, "KintoHttpClient",
                                "resource://services-common/kinto-http-client.js");
 ChromeUtils.defineModuleGetter(this, "CanonicalJSON",
                                "resource://gre/modules/CanonicalJSON.jsm");
 ChromeUtils.defineModuleGetter(this, "UptakeTelemetry",
                                "resource://services-common/uptake-telemetry.js");
 ChromeUtils.defineModuleGetter(this, "ClientEnvironmentBase",
                                "resource://gre/modules/components-utils/ClientEnvironment.jsm");
-ChromeUtils.defineModuleGetter(this, "FilterExpressions", "resource://normandy/lib/FilterExpressions.jsm");
+ChromeUtils.defineModuleGetter(this, "FilterExpressions",
+                               "resource://gre/modules/components-utils/FilterExpressions.jsm");
 
 const PREF_SETTINGS_SERVER             = "services.settings.server";
 const PREF_SETTINGS_DEFAULT_BUCKET     = "services.settings.default_bucket";
 const PREF_SETTINGS_DEFAULT_SIGNER     = "services.settings.default_signer";
 const PREF_SETTINGS_VERIFY_SIGNATURE   = "services.settings.verify_signature";
 const PREF_SETTINGS_SERVER_BACKOFF     = "services.settings.server.backoff";
 const PREF_SETTINGS_CHANGES_PATH       = "services.settings.changes.path";
 const PREF_SETTINGS_LAST_UPDATE        = "services.settings.last_update_seconds";
--- a/services/common/tests/unit/test_blocklist_clients.js
+++ b/services/common/tests/unit/test_blocklist_clients.js
@@ -241,22 +241,16 @@ add_task(async function test_sync_event_
     const collection = await client.openCollection();
     const { data: internalData } = await collection.list();
     ok(internalData.length > current.length, `event current data for ${client.collectionName}`);
   }
 });
 add_task(clear_state);
 
 add_task(async function test_entries_are_filtered_when_jexl_filters_is_present() {
-  if (IS_ANDROID) {
-    // JEXL filters are not supported on Android.
-    // See https://bugzilla.mozilla.org/show_bug.cgi?id=1463502
-    return;
-  }
-
   const records = [{
       willMatch: true,
     }, {
       willMatch: true,
       filters: null
     }, {
       willMatch: true,
       filters: "1 == 1"
--- a/services/common/tests/unit/xpcshell.ini
+++ b/services/common/tests/unit/xpcshell.ini
@@ -18,17 +18,16 @@ tags = blocklist
 tags = blocklist
 [test_blocklist_pinning.js]
 tags = blocklist
 [test_remote_settings.js]
 tags = remote-settings blocklist
 [test_remote_settings_poll.js]
 tags = remote-settings blocklist
 [test_remote_settings_jexl_filters.js]
-skip-if = os == "android"
 tags = remote-settings
 
 [test_kinto.js]
 tags = blocklist
 [test_blocklist_signatures.js]
 tags = remote-settings blocklist
 [test_storage_adapter.js]
 tags = remote-settingsblocklist
--- a/toolkit/components/normandy/lib/NormandyDriver.jsm
+++ b/toolkit/components/normandy/lib/NormandyDriver.jsm
@@ -9,21 +9,21 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/Preferences.jsm");
 ChromeUtils.import("resource:///modules/ShellService.jsm");
 ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
 ChromeUtils.import("resource://gre/modules/Timer.jsm");
 ChromeUtils.import("resource://normandy/lib/Addons.jsm");
 ChromeUtils.import("resource://normandy/lib/LogManager.jsm");
 ChromeUtils.import("resource://normandy/lib/Storage.jsm");
 ChromeUtils.import("resource://normandy/lib/Heartbeat.jsm");
-ChromeUtils.import("resource://normandy/lib/FilterExpressions.jsm");
 ChromeUtils.import("resource://normandy/lib/ClientEnvironment.jsm");
 ChromeUtils.import("resource://normandy/lib/PreferenceExperiments.jsm");
-ChromeUtils.import("resource://normandy/lib/Sampling.jsm");
 
+ChromeUtils.defineModuleGetter(
+  this, "Sampling", "resource://gre/modules/components-utils/Sampling.jsm");
 ChromeUtils.defineModuleGetter(this, "UpdateUtils", "resource://gre/modules/UpdateUtils.jsm");
 ChromeUtils.defineModuleGetter(
   this, "AddonStudies", "resource://normandy/lib/AddonStudies.jsm");
 
 const {generateUUID} = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
 
 var EXPORTED_SYMBOLS = ["NormandyDriver"];
 
--- a/toolkit/components/normandy/lib/RecipeRunner.jsm
+++ b/toolkit/components/normandy/lib/RecipeRunner.jsm
@@ -9,17 +9,17 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://normandy/lib/LogManager.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "timerManager",
                                    "@mozilla.org/updates/timer-manager;1",
                                    "nsIUpdateTimerManager");
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   Storage: "resource://normandy/lib/Storage.jsm",
-  FilterExpressions: "resource://normandy/lib/FilterExpressions.jsm",
+  FilterExpressions: "resource://gre/modules/components-utils/FilterExpressions.jsm",
   NormandyApi: "resource://normandy/lib/NormandyApi.jsm",
   ClientEnvironment: "resource://normandy/lib/ClientEnvironment.jsm",
   CleanupManager: "resource://normandy/lib/CleanupManager.jsm",
   AddonStudies: "resource://normandy/lib/AddonStudies.jsm",
   Uptake: "resource://normandy/lib/Uptake.jsm",
   ActionsManager: "resource://normandy/lib/ActionsManager.jsm",
 });
 
--- a/toolkit/components/normandy/test/browser/browser.ini
+++ b/toolkit/components/normandy/test/browser/browser.ini
@@ -14,17 +14,16 @@ skip-if = true # bug 1442712
 [browser_ActionSandboxManager.js]
 [browser_ActionsManager.js]
 [browser_Addons.js]
 [browser_AddonStudies.js]
 [browser_BaseAction.js]
 [browser_CleanupManager.js]
 [browser_ClientEnvironment.js]
 [browser_EventEmitter.js]
-[browser_FilterExpressions.js]
 [browser_Heartbeat.js]
 [browser_LogManager.js]
 [browser_Normandy.js]
 [browser_NormandyDriver.js]
 [browser_PreferenceExperiments.js]
 [browser_PreferenceRollouts.js]
 [browser_RecipeRunner.js]
 [browser_ShieldPreferences.js]
--- a/toolkit/components/normandy/test/unit/xpcshell.ini
+++ b/toolkit/components/normandy/test/unit/xpcshell.ini
@@ -4,10 +4,9 @@ support-files =
   mock_api/**
   invalid_recipe_signature_api/**
   query_server.sjs
   echo_server.sjs
   utils.js
 tags = normandy
 
 [test_NormandyApi.js]
-[test_Sampling.js]
 [test_SandboxManager.js]
rename from toolkit/components/normandy/lib/FilterExpressions.jsm
rename to toolkit/components/utils/FilterExpressions.jsm
--- a/toolkit/components/normandy/lib/FilterExpressions.jsm
+++ b/toolkit/components/utils/FilterExpressions.jsm
@@ -1,19 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-ChromeUtils.import("resource://normandy/lib/Sampling.jsm");
-ChromeUtils.import("resource://normandy/lib/PreferenceFilters.jsm");
 
-ChromeUtils.defineModuleGetter(this, "mozjexl", "resource://normandy-vendor/mozjexl.js");
+ChromeUtils.defineModuleGetter(this, "PreferenceFilters", "resource://gre/modules/components-utils/PreferenceFilters.jsm");
+ChromeUtils.defineModuleGetter(this, "Sampling", "resource://gre/modules/components-utils/Sampling.jsm");
+ChromeUtils.defineModuleGetter(this, "mozjexl", "resource://gre/modules/components-utils/mozjexl.js");
 
 var EXPORTED_SYMBOLS = ["FilterExpressions"];
 
 XPCOMUtils.defineLazyGetter(this, "jexl", () => {
   const jexl = new mozjexl.Jexl();
   jexl.addTransforms({
     date: dateString => new Date(dateString),
     stableSample: Sampling.stableSample,
rename from toolkit/components/normandy/lib/PreferenceFilters.jsm
rename to toolkit/components/utils/PreferenceFilters.jsm
rename from toolkit/components/normandy/lib/Sampling.jsm
rename to toolkit/components/utils/Sampling.jsm
--- a/toolkit/components/utils/moz.build
+++ b/toolkit/components/utils/moz.build
@@ -9,12 +9,17 @@ with Files('**'):
 
 EXTRA_COMPONENTS += [
     'simpleServices.js',
     'utils.manifest',
 ]
 
 EXTRA_JS_MODULES['components-utils'] = [
     'ClientEnvironment.jsm',
+    'FilterExpressions.jsm',
     'JsonSchemaValidator.jsm',
+    'mozjexl.js',
+    'PreferenceFilters.jsm',
+    'Sampling.jsm',
 ]
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
+XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
rename from toolkit/components/normandy/vendor/mozjexl.js
rename to toolkit/components/utils/mozjexl.js
new file mode 100644
--- /dev/null
+++ b/toolkit/components/utils/test/unit/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/xpcshell-test"
+  ]
+};
rename from toolkit/components/normandy/test/browser/browser_FilterExpressions.js
rename to toolkit/components/utils/test/unit/test_FilterExpressions.js
--- a/toolkit/components/normandy/test/browser/browser_FilterExpressions.js
+++ b/toolkit/components/utils/test/unit/test_FilterExpressions.js
@@ -1,39 +1,42 @@
 "use strict";
 
-ChromeUtils.import("resource://normandy/lib/FilterExpressions.jsm", this);
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+ChromeUtils.defineModuleGetter(this, "FilterExpressions",
+                               "resource://gre/modules/components-utils/FilterExpressions.jsm");
 
 // Basic JEXL tests
 add_task(async function() {
   let val;
   // Test that basic expressions work
   val = await FilterExpressions.eval("2+2");
-  is(val, 4, "basic expression works");
+  equal(val, 4, "basic expression works");
 
   // Test that multiline expressions work
   val = await FilterExpressions.eval(`
     2
     +
     2
   `);
-  is(val, 4, "multiline expression works");
+  equal(val, 4, "multiline expression works");
 
   // Test that it reads from the context correctly.
   val = await FilterExpressions.eval("first + second + 3", {first: 1, second: 2});
-  is(val, 6, "context is available to filter expressions");
+  equal(val, 6, "context is available to filter expressions");
 });
 
 // Date tests
 add_task(async function() {
   let val;
   // Test has a date transform
   val = await FilterExpressions.eval('"2016-04-22"|date');
   const d = new Date(Date.UTC(2016, 3, 22)); // months are 0 based
-  is(val.toString(), d.toString(), "Date transform works");
+  equal(val.toString(), d.toString(), "Date transform works");
 
   // Test dates are comparable
   const context = {someTime: Date.UTC(2016, 0, 1)};
   val = await FilterExpressions.eval('"2015-01-01"|date < someTime', context);
   ok(val, "dates are comparable with less-than");
   val = await FilterExpressions.eval('"2017-01-01"|date > someTime', context);
   ok(val, "dates are comparable with greater-than");
 });
@@ -61,17 +64,19 @@ add_task(async function() {
   val = await FilterExpressions.eval('["test-4"]|bucketSample(0, 5, 10)');
   ok(!val, "Bucket sample returns false for a known sample");
 });
 
 // Preference tests
 add_task(async function() {
   let val;
   // Compare the value of the preference
-  await SpecialPowers.pushPrefEnv({set: [["normandy.test.value", 3]]});
+  Services.prefs.setIntPref("normandy.test.value", 3);
+  registerCleanupFunction(() => Services.prefs.clearUserPref("normandy.test.value"));
+
   val = await FilterExpressions.eval('"normandy.test.value"|preferenceValue == 3');
   ok(val, "preferenceValue expression compares against preference values");
   val = await FilterExpressions.eval('"normandy.test.value"|preferenceValue == "test"');
   ok(!val, "preferenceValue expression fails value checks appropriately");
 
   // preferenceValue can take a default value as an optional argument, which
   // defaults to `undefined`.
   val = await FilterExpressions.eval('"normandy.test.default"|preferenceValue(false) == false');
@@ -113,49 +118,49 @@ add_task(async function testKeys() {
     new Set(["baz", "biff"]),
     "keys returns the keys from an object in the context",
   );
 
   // Test that values from the prototype are not included
   context = {ctxObject: Object.create({fooProto: 7})};
   context.ctxObject.baz = 8;
   context.ctxObject.biff = 5;
-  is(
+  equal(
     await FilterExpressions.eval("ctxObject.fooProto", context),
     7,
     "Prototype properties are accessible via property access",
   );
   val = await FilterExpressions.eval("ctxObject|keys", context);
   Assert.deepEqual(
     new Set(val),
     new Set(["baz", "biff"]),
     "keys does not return properties from the object's prototype chain",
   );
 
   // Return undefined for non-objects
-  is(
+  equal(
     await FilterExpressions.eval("ctxObject|keys", {ctxObject: 45}),
     undefined,
     "keys returns undefined for numbers",
   );
-  is(
+  equal(
     await FilterExpressions.eval("ctxObject|keys", {ctxObject: null}),
     undefined,
     "keys returns undefined for null",
   );
 
   // Object properties are not cached
   let pong = 0;
   context = {ctxObject: {
     get ping() {
       return ++pong;
     }
   }};
   await FilterExpressions.eval("ctxObject.ping == 0 || ctxObject.ping == 1", context);
-  is(pong, 2, "Properties are not reifed");
+  equal(pong, 2, "Properties are not reifed");
 });
 
 // intersect tests
 add_task(async function testIntersect() {
   let val;
 
   val = await FilterExpressions.eval("[1, 2, 3] intersect [4, 2, 6, 7, 3]");
   Assert.deepEqual(
@@ -175,24 +180,24 @@ add_task(async function testIntersect() 
   val = await FilterExpressions.eval("['string', 2] intersect [4, 'string', 'other', 3]");
   Assert.deepEqual(
     new Set(val),
     new Set(["string"]),
     "intersect can compare strings",
   );
 
   // Return undefined when intersecting things that aren't lists.
-  is(
+  equal(
     await FilterExpressions.eval("5 intersect 7"),
     undefined,
     "intersect returns undefined for numbers",
   );
-  is(
+  equal(
     await FilterExpressions.eval("val intersect other", {val: null, other: null}),
     undefined,
     "intersect returns undefined for null",
   );
-  is(
+  equal(
     await FilterExpressions.eval("5 intersect [1, 2, 5]"),
     undefined,
     "intersect returns undefined if only one operand is a list",
   );
 });
rename from toolkit/components/normandy/test/unit/test_Sampling.js
rename to toolkit/components/utils/test/unit/test_Sampling.js
--- a/toolkit/components/normandy/test/unit/test_Sampling.js
+++ b/toolkit/components/utils/test/unit/test_Sampling.js
@@ -1,11 +1,12 @@
 "use strict";
 
-ChromeUtils.import("resource://normandy/lib/Sampling.jsm", this);
+ChromeUtils.import("resource://gre/modules/components-utils/Sampling.jsm", this);
+
 
 add_task(async function testStableSample() {
   // Absolute samples
   equal(await Sampling.stableSample("test", 1), true, "stableSample returns true for 100% sample");
   equal(await Sampling.stableSample("test", 0), false, "stableSample returns false for 0% sample");
 
   // Known samples. The numbers are nonces to make the tests pass
   equal(await Sampling.stableSample("test-0", 0.5), true, "stableSample returns true for known matching sample");
new file mode 100644
--- /dev/null
+++ b/toolkit/components/utils/test/unit/xpcshell.ini
@@ -0,0 +1,2 @@
+[test_FilterExpressions.js]
+[test_Sampling.js]