tor-browser

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

PersonalityProvider.test.js (11750B)


      1 import { GlobalOverrider } from "test/unit/utils";
      2 import { PersonalityProvider } from "lib/PersonalityProvider/PersonalityProvider.sys.mjs";
      3 
      4 describe("Personality Provider", () => {
      5  let instance;
      6  let RemoteSettingsStub;
      7  let RemoteSettingsOnStub;
      8  let RemoteSettingsOffStub;
      9  let RemoteSettingsGetStub;
     10  let sandbox;
     11  let globals;
     12 
     13  beforeEach(() => {
     14    sandbox = sinon.createSandbox();
     15    globals = new GlobalOverrider();
     16 
     17    RemoteSettingsOnStub = sandbox.stub().returns();
     18    RemoteSettingsOffStub = sandbox.stub().returns();
     19    RemoteSettingsGetStub = sandbox.stub().returns([]);
     20 
     21    RemoteSettingsStub = () => ({
     22      get: RemoteSettingsGetStub,
     23      on: RemoteSettingsOnStub,
     24      off: RemoteSettingsOffStub,
     25    });
     26 
     27    sinon.spy(global, "BasePromiseWorker");
     28    sinon.spy(global.BasePromiseWorker.prototype, "post");
     29 
     30    globals.set("RemoteSettings", RemoteSettingsStub);
     31    globals.set("Utils", {
     32      baseAttachmentsURL: () => "https://baseattachmentsurl",
     33    });
     34 
     35    instance = new PersonalityProvider();
     36    instance.interestConfig = {
     37      history_item_builder: "history_item_builder",
     38      history_required_fields: ["a", "b", "c"],
     39      interest_finalizer: "interest_finalizer",
     40      item_to_rank_builder: "item_to_rank_builder",
     41      item_ranker: "item_ranker",
     42      interest_combiner: "interest_combiner",
     43    };
     44  });
     45  afterEach(() => {
     46    sinon.restore();
     47    sandbox.restore();
     48    globals.restore();
     49  });
     50  describe("#personalityProviderWorker", () => {
     51    it("should create a new promise worker on first call", async () => {
     52      const { personalityProviderWorker } = instance;
     53      assert.calledOnce(global.BasePromiseWorker);
     54      assert.isDefined(personalityProviderWorker);
     55    });
     56    it("should cache _personalityProviderWorker on first call", async () => {
     57      instance._personalityProviderWorker = null;
     58      const { personalityProviderWorker } = instance;
     59      assert.isDefined(instance._personalityProviderWorker);
     60      assert.isDefined(personalityProviderWorker);
     61    });
     62    it("should use old promise worker on second call", async () => {
     63      let { personalityProviderWorker } = instance;
     64      personalityProviderWorker = instance.personalityProviderWorker;
     65      assert.calledOnce(global.BasePromiseWorker);
     66      assert.isDefined(personalityProviderWorker);
     67    });
     68  });
     69  describe("#setup", () => {
     70    it("should setup two sync attachments", () => {
     71      sinon.spy(instance, "setupSyncAttachment");
     72      instance.setup();
     73      assert.calledTwice(instance.setupSyncAttachment);
     74    });
     75  });
     76  describe("#teardown", () => {
     77    it("should teardown two sync attachments", () => {
     78      sinon.spy(instance, "teardownSyncAttachment");
     79      instance.teardown();
     80      assert.calledTwice(instance.teardownSyncAttachment);
     81    });
     82    it("should terminate worker", () => {
     83      const terminateStub = sandbox.stub().returns();
     84      instance._personalityProviderWorker = {
     85        terminate: terminateStub,
     86      };
     87      instance.teardown();
     88      assert.calledOnce(terminateStub);
     89    });
     90  });
     91  describe("#setupSyncAttachment", () => {
     92    it("should call remote settings on twice for setupSyncAttachment", () => {
     93      assert.calledTwice(RemoteSettingsOnStub);
     94    });
     95  });
     96  describe("#teardownSyncAttachment", () => {
     97    it("should call remote settings off for teardownSyncAttachment", () => {
     98      instance.teardownSyncAttachment();
     99      assert.calledOnce(RemoteSettingsOffStub);
    100    });
    101  });
    102  describe("#onSync", () => {
    103    it("should call worker onSync", () => {
    104      instance.onSync();
    105      assert.calledWith(global.BasePromiseWorker.prototype.post, "onSync");
    106    });
    107  });
    108  describe("#getAttachment", () => {
    109    it("should call worker onSync", () => {
    110      instance.getAttachment();
    111      assert.calledWith(
    112        global.BasePromiseWorker.prototype.post,
    113        "getAttachment"
    114      );
    115    });
    116  });
    117  describe("#getRecipe", () => {
    118    it("should call worker getRecipe and remote settings get", async () => {
    119      RemoteSettingsGetStub = sandbox.stub().returns([
    120        {
    121          key: 1,
    122        },
    123      ]);
    124      sinon.spy(instance, "getAttachment");
    125      RemoteSettingsStub = () => ({
    126        get: RemoteSettingsGetStub,
    127        on: RemoteSettingsOnStub,
    128        off: RemoteSettingsOffStub,
    129      });
    130      globals.set("RemoteSettings", RemoteSettingsStub);
    131 
    132      const result = await instance.getRecipe();
    133      assert.calledOnce(RemoteSettingsGetStub);
    134      assert.calledOnce(instance.getAttachment);
    135      assert.equal(result.recordKey, 1);
    136    });
    137  });
    138  describe("#fetchHistory", () => {
    139    it("should return a history object for fetchHistory", async () => {
    140      const history = await instance.fetchHistory(["requiredColumn"], 1, 1);
    141      assert.equal(
    142        history.sql,
    143        `SELECT url, title, visit_count, frecency, last_visit_date, description\n    FROM moz_places\n    WHERE last_visit_date >= 1000000\n    AND last_visit_date < 1000000 AND IFNULL(requiredColumn, '') <> '' LIMIT 30000`
    144      );
    145      assert.equal(history.options.columns.length, 1);
    146      assert.equal(Object.keys(history.options.params).length, 0);
    147    });
    148  });
    149  describe("#getHistory", () => {
    150    it("should return an empty array", async () => {
    151      instance.interestConfig = {
    152        history_required_fields: [],
    153      };
    154      const result = await instance.getHistory();
    155      assert.equal(result.length, 0);
    156    });
    157    it("should call fetchHistory", async () => {
    158      sinon.spy(instance, "fetchHistory");
    159      await instance.getHistory();
    160    });
    161  });
    162  describe("#setBaseAttachmentsURL", () => {
    163    it("should call worker setBaseAttachmentsURL", async () => {
    164      await instance.setBaseAttachmentsURL();
    165      assert.calledWith(
    166        global.BasePromiseWorker.prototype.post,
    167        "setBaseAttachmentsURL"
    168      );
    169    });
    170  });
    171  describe("#setInterestConfig", () => {
    172    it("should call worker setInterestConfig", async () => {
    173      await instance.setInterestConfig();
    174      assert.calledWith(
    175        global.BasePromiseWorker.prototype.post,
    176        "setInterestConfig"
    177      );
    178    });
    179  });
    180  describe("#setInterestVector", () => {
    181    it("should call worker setInterestVector", async () => {
    182      await instance.setInterestVector();
    183      assert.calledWith(
    184        global.BasePromiseWorker.prototype.post,
    185        "setInterestVector"
    186      );
    187    });
    188  });
    189  describe("#fetchModels", () => {
    190    it("should call worker fetchModels and remote settings get", async () => {
    191      await instance.fetchModels();
    192      assert.calledOnce(RemoteSettingsGetStub);
    193      assert.calledWith(global.BasePromiseWorker.prototype.post, "fetchModels");
    194    });
    195  });
    196  describe("#generateTaggers", () => {
    197    it("should call worker generateTaggers", async () => {
    198      await instance.generateTaggers();
    199      assert.calledWith(
    200        global.BasePromiseWorker.prototype.post,
    201        "generateTaggers"
    202      );
    203    });
    204  });
    205  describe("#generateRecipeExecutor", () => {
    206    it("should call worker generateRecipeExecutor", async () => {
    207      await instance.generateRecipeExecutor();
    208      assert.calledWith(
    209        global.BasePromiseWorker.prototype.post,
    210        "generateRecipeExecutor"
    211      );
    212    });
    213  });
    214  describe("#createInterestVector", () => {
    215    it("should call worker createInterestVector", async () => {
    216      await instance.createInterestVector();
    217      assert.calledWith(
    218        global.BasePromiseWorker.prototype.post,
    219        "createInterestVector"
    220      );
    221    });
    222  });
    223  describe("#init", () => {
    224    it("should return early if setInterestConfig fails", async () => {
    225      sandbox.stub(instance, "setBaseAttachmentsURL").returns();
    226      sandbox.stub(instance, "setInterestConfig").returns();
    227      instance.interestConfig = null;
    228      const callback = globals.sandbox.stub();
    229      await instance.init(callback);
    230      assert.notCalled(callback);
    231    });
    232    it("should return early if fetchModels fails", async () => {
    233      sandbox.stub(instance, "setBaseAttachmentsURL").returns();
    234      sandbox.stub(instance, "setInterestConfig").returns();
    235      sandbox.stub(instance, "fetchModels").resolves({
    236        ok: false,
    237      });
    238      const callback = globals.sandbox.stub();
    239      await instance.init(callback);
    240      assert.notCalled(callback);
    241    });
    242    it("should return early if createInterestVector fails", async () => {
    243      sandbox.stub(instance, "setBaseAttachmentsURL").returns();
    244      sandbox.stub(instance, "setInterestConfig").returns();
    245      sandbox.stub(instance, "fetchModels").resolves({
    246        ok: true,
    247      });
    248      sandbox.stub(instance, "generateRecipeExecutor").resolves({
    249        ok: true,
    250      });
    251      sandbox.stub(instance, "createInterestVector").resolves({
    252        ok: false,
    253      });
    254      const callback = globals.sandbox.stub();
    255      await instance.init(callback);
    256      assert.notCalled(callback);
    257    });
    258    it("should call callback on successful init", async () => {
    259      sandbox.stub(instance, "setBaseAttachmentsURL").returns();
    260      sandbox.stub(instance, "setInterestConfig").returns();
    261      sandbox.stub(instance, "fetchModels").resolves({
    262        ok: true,
    263      });
    264      sandbox.stub(instance, "generateRecipeExecutor").resolves({
    265        ok: true,
    266      });
    267      sandbox.stub(instance, "createInterestVector").resolves({
    268        ok: true,
    269      });
    270      sandbox.stub(instance, "setInterestVector").resolves();
    271      const callback = globals.sandbox.stub();
    272      await instance.init(callback);
    273      assert.calledOnce(callback);
    274      assert.isTrue(instance.initialized);
    275    });
    276    it("should do generic init stuff when calling init with no cache", async () => {
    277      sandbox.stub(instance, "setBaseAttachmentsURL").returns();
    278      sandbox.stub(instance, "setInterestConfig").returns();
    279      sandbox.stub(instance, "fetchModels").resolves({
    280        ok: true,
    281      });
    282      sandbox.stub(instance, "generateRecipeExecutor").resolves({
    283        ok: true,
    284      });
    285      sandbox.stub(instance, "createInterestVector").resolves({
    286        ok: true,
    287        interestVector: "interestVector",
    288      });
    289      sandbox.stub(instance, "setInterestVector").resolves();
    290      await instance.init();
    291      assert.calledOnce(instance.setBaseAttachmentsURL);
    292      assert.calledOnce(instance.setInterestConfig);
    293      assert.calledOnce(instance.fetchModels);
    294      assert.calledOnce(instance.generateRecipeExecutor);
    295      assert.calledOnce(instance.createInterestVector);
    296      assert.calledOnce(instance.setInterestVector);
    297    });
    298  });
    299  describe("#calculateItemRelevanceScore", () => {
    300    it("should return score for uninitialized provider", async () => {
    301      instance.initialized = false;
    302      assert.equal(
    303        await instance.calculateItemRelevanceScore({ item_score: 2 }),
    304        2
    305      );
    306    });
    307    it("should return score for initialized provider", async () => {
    308      instance.initialized = true;
    309 
    310      instance._personalityProviderWorker = {
    311        post: (postName, [item]) => ({
    312          rankingVector: { score: item.item_score },
    313        }),
    314      };
    315 
    316      assert.equal(
    317        await instance.calculateItemRelevanceScore({ item_score: 2 }),
    318        2
    319      );
    320    });
    321    it("should post calculateItemRelevanceScore to PersonalityProviderWorker", async () => {
    322      instance.initialized = true;
    323      await instance.calculateItemRelevanceScore({ item_score: 2 });
    324      assert.calledWith(
    325        global.BasePromiseWorker.prototype.post,
    326        "calculateItemRelevanceScore"
    327      );
    328    });
    329  });
    330  describe("#getScores", () => {
    331    it("should return correct data for getScores", () => {
    332      const scores = instance.getScores();
    333      assert.isDefined(scores.interestConfig);
    334    });
    335  });
    336 });