From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../browser_actions_PreferenceRollbackAction.js | 348 +++++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 toolkit/components/normandy/test/browser/browser_actions_PreferenceRollbackAction.js (limited to 'toolkit/components/normandy/test/browser/browser_actions_PreferenceRollbackAction.js') diff --git a/toolkit/components/normandy/test/browser/browser_actions_PreferenceRollbackAction.js b/toolkit/components/normandy/test/browser/browser_actions_PreferenceRollbackAction.js new file mode 100644 index 0000000000..ac28ba05ad --- /dev/null +++ b/toolkit/components/normandy/test/browser/browser_actions_PreferenceRollbackAction.js @@ -0,0 +1,348 @@ +"use strict"; + +const { BaseAction } = ChromeUtils.importESModule( + "resource://normandy/actions/BaseAction.sys.mjs" +); +const { PreferenceRollbackAction } = ChromeUtils.importESModule( + "resource://normandy/actions/PreferenceRollbackAction.sys.mjs" +); +const { Uptake } = ChromeUtils.importESModule( + "resource://normandy/lib/Uptake.sys.mjs" +); +const { PreferenceRollouts } = ChromeUtils.importESModule( + "resource://normandy/lib/PreferenceRollouts.sys.mjs" +); + +// Test that a simple recipe rollsback as expected +decorate_task( + withStub(TelemetryEnvironment, "setExperimentInactive"), + withSendEventSpy(), + PreferenceRollouts.withTestMock(), + async function simple_rollback({ setExperimentInactiveStub, sendEventSpy }) { + Services.prefs.getDefaultBranch("").setIntPref("test.pref1", 2); + Services.prefs + .getDefaultBranch("") + .setCharPref("test.pref2", "rollout value"); + Services.prefs.getDefaultBranch("").setBoolPref("test.pref3", true); + + await PreferenceRollouts.add({ + slug: "test-rollout", + state: PreferenceRollouts.STATE_ACTIVE, + preferences: [ + { preferenceName: "test.pref1", value: 2, previousValue: 1 }, + { + preferenceName: "test.pref2", + value: "rollout value", + previousValue: "builtin value", + }, + { preferenceName: "test.pref3", value: true, previousValue: false }, + ], + }); + + const recipe = { id: 1, arguments: { rolloutSlug: "test-rollout" } }; + + const action = new PreferenceRollbackAction(); + await action.processRecipe(recipe, BaseAction.suitability.FILTER_MATCH); + await action.finalize(); + is(action.lastError, null, "lastError should be null"); + + // rollout prefs are reset + is( + Services.prefs.getIntPref("test.pref1"), + 1, + "integer pref should be rolled back" + ); + is( + Services.prefs.getCharPref("test.pref2"), + "builtin value", + "string pref should be rolled back" + ); + is( + Services.prefs.getBoolPref("test.pref3"), + false, + "boolean pref should be rolled back" + ); + + // start up prefs are unset + is( + Services.prefs.getPrefType("app.normandy.startupRolloutPrefs.test.pref1"), + Services.prefs.PREF_INVALID, + "integer startup pref should be unset" + ); + is( + Services.prefs.getPrefType("app.normandy.startupRolloutPrefs.test.pref2"), + Services.prefs.PREF_INVALID, + "string startup pref should be unset" + ); + is( + Services.prefs.getPrefType("app.normandy.startupRolloutPrefs.test.pref3"), + Services.prefs.PREF_INVALID, + "boolean startup pref should be unset" + ); + + // rollout in db was updated + const rollouts = await PreferenceRollouts.getAll(); + Assert.deepEqual( + rollouts, + [ + { + slug: "test-rollout", + state: PreferenceRollouts.STATE_ROLLED_BACK, + preferences: [ + { preferenceName: "test.pref1", value: 2, previousValue: 1 }, + { + preferenceName: "test.pref2", + value: "rollout value", + previousValue: "builtin value", + }, + { preferenceName: "test.pref3", value: true, previousValue: false }, + ], + }, + ], + "Rollout should be updated in db" + ); + + // Telemetry is updated + sendEventSpy.assertEvents([ + [ + "unenroll", + "preference_rollback", + recipe.arguments.rolloutSlug, + { reason: "rollback" }, + ], + ]); + Assert.deepEqual( + setExperimentInactiveStub.args, + [["test-rollout"]], + "the telemetry experiment should deactivated" + ); + + // Cleanup + Services.prefs.getDefaultBranch("").deleteBranch("test.pref1"); + Services.prefs.getDefaultBranch("").deleteBranch("test.pref2"); + Services.prefs.getDefaultBranch("").deleteBranch("test.pref3"); + } +); + +// Test that a graduated rollout can't be rolled back +decorate_task( + withSendEventSpy(), + PreferenceRollouts.withTestMock(), + async function cant_rollback_graduated({ sendEventSpy }) { + Services.prefs.getDefaultBranch("").setIntPref("test.pref", 1); + await PreferenceRollouts.add({ + slug: "graduated-rollout", + state: PreferenceRollouts.STATE_GRADUATED, + preferences: [ + { preferenceName: "test.pref", value: 1, previousValue: 1 }, + ], + }); + + let recipe = { id: 1, arguments: { rolloutSlug: "graduated-rollout" } }; + + const action = new PreferenceRollbackAction(); + await action.processRecipe(recipe, BaseAction.suitability.FILTER_MATCH); + await action.finalize(); + is(action.lastError, null, "lastError should be null"); + + is(Services.prefs.getIntPref("test.pref"), 1, "pref should not change"); + is( + Services.prefs.getPrefType("app.normandy.startupRolloutPrefs.test.pref"), + Services.prefs.PREF_INVALID, + "no startup pref should be added" + ); + + // rollout in the DB hasn't changed + Assert.deepEqual( + await PreferenceRollouts.getAll(), + [ + { + slug: "graduated-rollout", + state: PreferenceRollouts.STATE_GRADUATED, + preferences: [ + { preferenceName: "test.pref", value: 1, previousValue: 1 }, + ], + }, + ], + "Rollout should not change in db" + ); + + sendEventSpy.assertEvents([ + [ + "unenrollFailed", + "preference_rollback", + "graduated-rollout", + { reason: "graduated" }, + ], + ]); + + // Cleanup + Services.prefs.getDefaultBranch("").deleteBranch("test.pref"); + } +); + +// Test that a rollback without a matching rollout does not send telemetry +decorate_task( + withSendEventSpy(), + withStub(Uptake, "reportRecipe"), + PreferenceRollouts.withTestMock(), + async function rollback_without_rollout({ sendEventSpy, reportRecipeStub }) { + let recipe = { id: 1, arguments: { rolloutSlug: "missing-rollout" } }; + + const action = new PreferenceRollbackAction(); + await action.processRecipe(recipe, BaseAction.suitability.FILTER_MATCH); + await action.finalize(); + is(action.lastError, null, "lastError should be null"); + + sendEventSpy.assertEvents([]); + Assert.deepEqual( + reportRecipeStub.args, + [[recipe, Uptake.RECIPE_SUCCESS]], + "recipe should be reported as succesful" + ); + } +); + +// Test that rolling back an already rolled back recipe doesn't do anything +decorate_task( + withStub(TelemetryEnvironment, "setExperimentInactive"), + withSendEventSpy(), + PreferenceRollouts.withTestMock(), + async function rollback_already_rolled_back({ + setExperimentInactiveStub, + sendEventSpy, + }) { + Services.prefs.getDefaultBranch("").setIntPref("test.pref", 1); + + const recipe = { id: 1, arguments: { rolloutSlug: "test-rollout" } }; + const rollout = { + slug: "test-rollout", + state: PreferenceRollouts.STATE_ROLLED_BACK, + preferences: [ + { preferenceName: "test.pref", value: 2, previousValue: 1 }, + ], + }; + await PreferenceRollouts.add(rollout); + + const action = new PreferenceRollbackAction(); + await action.processRecipe(recipe, BaseAction.suitability.FILTER_MATCH); + await action.finalize(); + is(action.lastError, null, "lastError should be null"); + + is(Services.prefs.getIntPref("test.pref"), 1, "pref shouldn't change"); + is( + Services.prefs.getPrefType("app.normandy.startupRolloutPrefs.test.pref"), + Services.prefs.PREF_INVALID, + "startup pref should not be set" + ); + + // rollout in db was updated + Assert.deepEqual( + await PreferenceRollouts.getAll(), + [rollout], + "Rollout shouldn't change in db" + ); + + // Telemetry is updated + sendEventSpy.assertEvents([]); + Assert.deepEqual( + setExperimentInactiveStub.args, + [], + "telemetry experiments should not be updated" + ); + + // Cleanup + Services.prefs.getDefaultBranch("").deleteBranch("test.pref"); + } +); + +// Test that a rollback doesn't affect user prefs +decorate_task( + PreferenceRollouts.withTestMock(), + async function simple_rollback() { + Services.prefs + .getDefaultBranch("") + .setCharPref("test.pref", "rollout value"); + Services.prefs.setCharPref("test.pref", "user value"); + + await PreferenceRollouts.add({ + slug: "test-rollout", + state: PreferenceRollouts.STATE_ACTIVE, + preferences: [ + { + preferenceName: "test.pref", + value: "rollout value", + previousValue: "builtin value", + }, + ], + }); + + const recipe = { id: 1, arguments: { rolloutSlug: "test-rollout" } }; + + const action = new PreferenceRollbackAction(); + await action.processRecipe(recipe, BaseAction.suitability.FILTER_MATCH); + await action.finalize(); + is(action.lastError, null, "lastError should be null"); + + is( + Services.prefs.getDefaultBranch("").getCharPref("test.pref"), + "builtin value", + "default branch should be reset" + ); + is( + Services.prefs.getCharPref("test.pref"), + "user value", + "user branch should remain the same" + ); + + // Cleanup + Services.prefs.deleteBranch("test.pref"); + Services.prefs.getDefaultBranch("").deleteBranch("test.pref"); + } +); + +// Test that a rollouts in the graduation set can't be rolled back +decorate_task( + withSendEventSpy(), + PreferenceRollouts.withTestMock({ + graduationSet: new Set(["graduated-rollout"]), + }), + async function cant_rollback_graduation_set({ sendEventSpy }) { + Services.prefs.getDefaultBranch("").setIntPref("test.pref", 1); + + let recipe = { id: 1, arguments: { rolloutSlug: "graduated-rollout" } }; + + const action = new PreferenceRollbackAction(); + await action.processRecipe(recipe, BaseAction.suitability.FILTER_MATCH); + await action.finalize(); + is(action.lastError, null, "lastError should be null"); + + is(Services.prefs.getIntPref("test.pref"), 1, "pref should not change"); + is( + Services.prefs.getPrefType("app.normandy.startupRolloutPrefs.test.pref"), + Services.prefs.PREF_INVALID, + "no startup pref should be added" + ); + + // No entry in the DB + Assert.deepEqual( + await PreferenceRollouts.getAll(), + [], + "Rollout should be in the db" + ); + + sendEventSpy.assertEvents([ + [ + "unenrollFailed", + "preference_rollback", + "graduated-rollout", + { + reason: "in-graduation-set", + }, + ], + ]); + + // Cleanup + Services.prefs.getDefaultBranch("").deleteBranch("test.pref"); + } +); -- cgit v1.2.3