Bug 1464798 - RemoteSettings should lookup same JEXL field as Normandy r?mythmon
MozReview-Commit-ID: I84nrAG278k
--- a/services/common/blocklist-clients.js
+++ b/services/common/blocklist-clients.js
@@ -129,21 +129,21 @@ async function updateJSONBlocklist(clien
/**
* This custom filter function is used to limit the entries returned
* by `RemoteSettings("...").get()` depending on the target app information
* defined on entries.
*/
async function targetAppFilter(entry, environment) {
- // If the entry has JEXL filters, they should prevail.
+ // If the entry has a JEXL filter expression, it should prevail.
// The legacy target app mechanism will be kept in place for old entries.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1463377
- const { filters } = entry;
- if (filters) {
+ const { filter_expression } = entry;
+ if (filter_expression) {
return jexlFilterFunc(entry, environment);
}
// Keep entries without target information.
if (!("versionRange" in entry)) {
return entry;
}
--- a/services/common/docs/RemoteSettings.rst
+++ b/services/common/docs/RemoteSettings.rst
@@ -107,17 +107,17 @@ Targets and A/B testing
=======================
In order to deliver settings to subsets of the population, you can set targets on entries (platform, language, channel, version range, preferences values, samples, etc.) when editing records on the server.
From the client API standpoint, this is completely transparent: the ``.get()`` method — as well as the event data — will always filter the entries on which the target matches.
.. note::
- The remote settings targets follow the same approach as the :ref:`Normandy recipe client <components/normandy>` (ie. JEXL filters),
+ The remote settings targets follow the same approach as the :ref:`Normandy recipe client <components/normandy>` (ie. JEXL filter expressions),
Uptake Telemetry
================
Some :ref:`uptake telemetry <telemetry/collection/uptake>` is collected in order to monitor how remote settings are propagated.
It is submitted to a single :ref:`keyed histogram <histogram-type-keyed>` whose id is ``UPTAKE_REMOTE_CONTENT_RESULT_1`` and the keys are prefixed with ``main/`` (eg. ``main/a-key`` in the above example).
--- a/services/common/remote-settings.js
+++ b/services/common/remote-settings.js
@@ -72,26 +72,26 @@ class ClientEnvironment extends ClientEn
}
}
/**
* Default entry filtering function, in charge of excluding remote settings entries
* where the JEXL expression evaluates into a falsy value.
*/
async function jexlFilterFunc(entry, environment) {
- const { filters } = entry;
- if (!filters) {
+ const { filter_expression } = entry;
+ if (!filter_expression) {
return entry;
}
let result;
try {
const context = {
environment
};
- result = await FilterExpressions.eval(filters, context);
+ result = await FilterExpressions.eval(filter_expression, context);
} catch (e) {
Cu.reportError(e);
}
return result ? entry : null;
}
function mergeChanges(collection, localRecords, changes) {
--- a/services/common/tests/unit/test_blocklist_clients.js
+++ b/services/common/tests/unit/test_blocklist_clients.js
@@ -240,39 +240,39 @@ add_task(async function test_sync_event_
// and the event current data should differ.
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() {
+add_task(async function test_entries_are_filtered_when_jexl_filter_expression_is_present() {
const records = [{
willMatch: true,
}, {
willMatch: true,
- filters: null
+ filter_expression: null
}, {
willMatch: true,
- filters: "1 == 1"
+ filter_expression: "1 == 1"
}, {
willMatch: false,
- filters: "1 == 2"
+ filter_expression: "1 == 2"
}, {
willMatch: true,
- filters: "1 == 1",
+ filter_expression: "1 == 1",
versionRange: [{
targetApplication: [{
guid: "some-guid"
}],
}]
}, {
willMatch: false, // jexl prevails over versionRange.
- filters: "1 == 2",
+ filter_expression: "1 == 2",
versionRange: [{
targetApplication: [{
guid: "xpcshell@tests.mozilla.org",
minVersion: "0",
maxVersion: "*",
}],
}]
}
--- a/services/common/tests/unit/test_remote_settings_jexl_filters.js
+++ b/services/common/tests/unit/test_remote_settings_jexl_filters.js
@@ -17,155 +17,155 @@ function run_test() {
run_next_test();
}
add_task(async function test_returns_all_without_target() {
await createRecords([{
passwordSelector: "#pass-signin"
}, {
- filters: null,
+ filter_expression: null,
}, {
- filters: "",
+ filter_expression: "",
}]);
const list = await client.get();
equal(list.length, 3);
});
add_task(async function test_filters_can_be_disabled() {
const c = RemoteSettings("no-jexl", { filterFunc: null });
const collection = await c.openCollection();
await collection.create({
- filters: "1 == 2"
+ filter_expression: "1 == 2"
});
await collection.db.saveLastModified(42); // Prevent from loading JSON dump.
const list = await c.get();
equal(list.length, 1);
});
add_task(async function test_returns_entries_where_jexl_is_true() {
await createRecords([{
willMatch: true,
- filters: "1"
+ filter_expression: "1"
}, {
willMatch: true,
- filters: "[42]"
+ filter_expression: "[42]"
}, {
willMatch: true,
- filters: "1 == 2 || 1 == 1"
+ filter_expression: "1 == 2 || 1 == 1"
}, {
willMatch: true,
- filters: 'environment.appID == "xpcshell@tests.mozilla.org"'
+ filter_expression: 'environment.appID == "xpcshell@tests.mozilla.org"'
}, {
willMatch: false,
- filters: "environment.version == undefined"
+ filter_expression: "environment.version == undefined"
}, {
willMatch: true,
- filters: "environment.unknown == undefined"
+ filter_expression: "environment.unknown == undefined"
}, {
willMatch: false,
- filters: "1 == 2"
+ filter_expression: "1 == 2"
}]);
const list = await client.get();
equal(list.length, 5);
ok(list.every(e => e.willMatch));
});
add_task(async function test_ignores_entries_where_jexl_is_invalid() {
await createRecords([{
- filters: "true === true" // JavaScript Error: "Invalid expression token: ="
+ filter_expression: "true === true" // JavaScript Error: "Invalid expression token: ="
}, {
- filters: "Objects.keys({}) == []" // Token ( (openParen) unexpected in expression
+ filter_expression: "Objects.keys({}) == []" // Token ( (openParen) unexpected in expression
}]);
const list = await client.get();
equal(list.length, 0);
});
add_task(async function test_support_of_date_filters() {
await createRecords([{
willMatch: true,
- filters: '"1982-05-08"|date < "2016-03-22"|date'
+ filter_expression: '"1982-05-08"|date < "2016-03-22"|date'
}, {
willMatch: false,
- filters: '"2000-01-01"|date < "1970-01-01"|date'
+ filter_expression: '"2000-01-01"|date < "1970-01-01"|date'
}]);
const list = await client.get();
equal(list.length, 1);
ok(list.every(e => e.willMatch));
});
add_task(async function test_support_of_preferences_filters() {
await createRecords([{
willMatch: true,
- filters: '"services.settings.last_etag"|preferenceValue == 42'
+ filter_expression: '"services.settings.last_etag"|preferenceValue == 42'
}, {
willMatch: true,
- filters: '"services.settings.changes.path"|preferenceExists == true'
+ filter_expression: '"services.settings.changes.path"|preferenceExists == true'
}, {
willMatch: true,
- filters: '"services.settings.changes.path"|preferenceIsUserSet == false'
+ filter_expression: '"services.settings.changes.path"|preferenceIsUserSet == false'
}, {
willMatch: true,
- filters: '"services.settings.last_etag"|preferenceIsUserSet == true'
+ filter_expression: '"services.settings.last_etag"|preferenceIsUserSet == true'
}]);
// Set a pref for the user.
Services.prefs.setIntPref("services.settings.last_etag", 42);
const list = await client.get();
equal(list.length, 4);
ok(list.every(e => e.willMatch));
});
add_task(async function test_support_of_intersect_operator() {
await createRecords([{
willMatch: true,
- filters: '{foo: 1, bar: 2}|keys intersect ["foo"]'
+ filter_expression: '{foo: 1, bar: 2}|keys intersect ["foo"]'
}, {
willMatch: true,
- filters: '(["a", "b"] intersect ["a", 1, 4]) == "a"'
+ filter_expression: '(["a", "b"] intersect ["a", 1, 4]) == "a"'
}, {
willMatch: false,
- filters: '(["a", "b"] intersect [3, 1, 4]) == "c"'
+ filter_expression: '(["a", "b"] intersect [3, 1, 4]) == "c"'
}, {
willMatch: true,
- filters: `
+ filter_expression: `
[1, 2, 3]
intersect
[3, 4, 5]
`
}]);
const list = await client.get();
equal(list.length, 3);
ok(list.every(e => e.willMatch));
});
add_task(async function test_support_of_samples() {
await createRecords([{
willMatch: true,
- filters: '"always-true"|stableSample(1)'
+ filter_expression: '"always-true"|stableSample(1)'
}, {
willMatch: false,
- filters: '"always-false"|stableSample(0)'
+ filter_expression: '"always-false"|stableSample(0)'
}, {
willMatch: true,
- filters: '"turns-to-true-0"|stableSample(0.5)'
+ filter_expression: '"turns-to-true-0"|stableSample(0.5)'
}, {
willMatch: false,
- filters: '"turns-to-false-1"|stableSample(0.5)'
+ filter_expression: '"turns-to-false-1"|stableSample(0.5)'
}, {
willMatch: true,
- filters: '"turns-to-true-0"|bucketSample(0, 50, 100)'
+ filter_expression: '"turns-to-true-0"|bucketSample(0, 50, 100)'
}, {
willMatch: false,
- filters: '"turns-to-false-1"|bucketSample(0, 50, 100)'
+ filter_expression: '"turns-to-false-1"|bucketSample(0, 50, 100)'
}]);
const list = await client.get();
equal(list.length, 3);
ok(list.every(e => e.willMatch));
});