tor-browser

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

ASRouterStorage.test.js (24614B)


      1 import { ASRouterStorage } from "modules/ASRouterStorage.sys.mjs";
      2 import { GlobalOverrider } from "tests/unit/utils";
      3 
      4 let overrider = new GlobalOverrider();
      5 
      6 describe("ASRouterStorage", () => {
      7  let sandbox;
      8  let indexedDB;
      9  let storage;
     10  beforeEach(() => {
     11    sandbox = sinon.createSandbox();
     12    indexedDB = {
     13      open: sandbox.stub().resolves({}),
     14      deleteDatabase: sandbox.stub().resolves(),
     15    };
     16    overrider.set({ IndexedDB: indexedDB });
     17    storage = new ASRouterStorage({
     18      storeNames: ["storage_test"],
     19      telemetry: { handleUndesiredEvent: sandbox.stub() },
     20    });
     21  });
     22  afterEach(() => {
     23    sandbox.restore();
     24  });
     25  it("should throw if required arguments not provided", () => {
     26    assert.throws(() => new ASRouterStorage({ telemetry: true }));
     27  });
     28  describe(".db", () => {
     29    it("should not throw an error when accessing db", async () => {
     30      assert.ok(storage.db);
     31    });
     32 
     33    it("should delete and recreate the db if opening db fails", async () => {
     34      const newDb = {};
     35      indexedDB.open.onFirstCall().rejects(new Error("fake error"));
     36      indexedDB.open.onSecondCall().resolves(newDb);
     37 
     38      const db = await storage.db;
     39      assert.calledOnce(indexedDB.deleteDatabase);
     40      assert.calledTwice(indexedDB.open);
     41      assert.equal(db, newDb);
     42    });
     43  });
     44  describe("#getDbTable", () => {
     45    let testStorage;
     46    let storeStub;
     47    beforeEach(() => {
     48      storeStub = {
     49        getAll: sandbox.stub().resolves(),
     50        getAllKeys: sandbox.stub().resolves(),
     51        get: sandbox.stub().resolves(),
     52        put: sandbox.stub().resolves(),
     53      };
     54      sandbox.stub(storage, "_getStore").resolves(storeStub);
     55      testStorage = storage.getDbTable("storage_test");
     56    });
     57    it("should reverse key value parameters for put", async () => {
     58      await testStorage.set("key", "value");
     59 
     60      assert.calledOnce(storeStub.put);
     61      assert.calledWith(storeStub.put, "value", "key");
     62    });
     63    it("should return the correct value for get", async () => {
     64      storeStub.get.withArgs("foo").resolves("foo");
     65 
     66      const result = await testStorage.get("foo");
     67 
     68      assert.calledOnce(storeStub.get);
     69      assert.equal(result, "foo");
     70    });
     71    it("should return the correct value for getAll", async () => {
     72      storeStub.getAll.resolves(["bar"]);
     73 
     74      const result = await testStorage.getAll();
     75 
     76      assert.calledOnce(storeStub.getAll);
     77      assert.deepEqual(result, ["bar"]);
     78    });
     79    it("should return the correct value for getAllKeys", async () => {
     80      storeStub.getAllKeys.resolves(["key1", "key2", "key3"]);
     81 
     82      const result = await testStorage.getAllKeys();
     83 
     84      assert.calledOnce(storeStub.getAllKeys);
     85      assert.deepEqual(result, ["key1", "key2", "key3"]);
     86    });
     87    it("should query the correct object store", async () => {
     88      await testStorage.get();
     89 
     90      assert.calledOnce(storage._getStore);
     91      assert.calledWithExactly(storage._getStore, "storage_test");
     92    });
     93    it("should throw if table is not found", () => {
     94      assert.throws(() => storage.getDbTable("undefined_store"));
     95    });
     96  });
     97  it("should get the correct objectStore when calling _getStore", async () => {
     98    const objectStoreStub = sandbox.stub();
     99    indexedDB.open.resolves({ objectStore: objectStoreStub });
    100 
    101    await storage._getStore("foo");
    102 
    103    assert.calledOnce(objectStoreStub);
    104    assert.calledWithExactly(objectStoreStub, "foo", "readwrite");
    105  });
    106  it("should create a db with the correct store name", async () => {
    107    const dbStub = {
    108      createObjectStore: sandbox.stub(),
    109      objectStoreNames: { contains: sandbox.stub().returns(false) },
    110    };
    111    await storage.db;
    112 
    113    // call the cb with a stub
    114    indexedDB.open.args[0][2](dbStub);
    115 
    116    assert.calledOnce(dbStub.createObjectStore);
    117    assert.calledWithExactly(dbStub.createObjectStore, "storage_test");
    118  });
    119  it("should handle an array of object store names", async () => {
    120    storage = new ASRouterStorage({
    121      storeNames: ["store1", "store2"],
    122      telemetry: {},
    123    });
    124    const dbStub = {
    125      createObjectStore: sandbox.stub(),
    126      objectStoreNames: { contains: sandbox.stub().returns(false) },
    127    };
    128    await storage.db;
    129 
    130    // call the cb with a stub
    131    indexedDB.open.args[0][2](dbStub);
    132 
    133    assert.calledTwice(dbStub.createObjectStore);
    134    assert.calledWith(dbStub.createObjectStore, "store1");
    135    assert.calledWith(dbStub.createObjectStore, "store2");
    136  });
    137  it("should skip creating existing stores", async () => {
    138    storage = new ASRouterStorage({
    139      storeNames: ["store1", "store2"],
    140      telemetry: {},
    141    });
    142    const dbStub = {
    143      createObjectStore: sandbox.stub(),
    144      objectStoreNames: { contains: sandbox.stub().returns(true) },
    145    };
    146    await storage.db;
    147 
    148    // call the cb with a stub
    149    indexedDB.open.args[0][2](dbStub);
    150 
    151    assert.notCalled(dbStub.createObjectStore);
    152  });
    153  describe("#_requestWrapper", () => {
    154    it("should return a successful result", async () => {
    155      const result = await storage._requestWrapper(() =>
    156        Promise.resolve("foo")
    157      );
    158 
    159      assert.equal(result, "foo");
    160      assert.notCalled(storage.telemetry.handleUndesiredEvent);
    161    });
    162    it("should report failures", async () => {
    163      try {
    164        await storage._requestWrapper(() => Promise.reject(new Error()));
    165      } catch (e) {
    166        assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    167      }
    168    });
    169  });
    170 });
    171 
    172 function assertMessageBlockedTransaction(mockConnection, expectedMessageId) {
    173  assert.callCount(mockConnection.executeCached, 2);
    174 
    175  const [call1, call2] = [
    176    mockConnection.executeCached.getCall(0),
    177    mockConnection.executeCached.getCall(1),
    178  ];
    179 
    180  assert.match(call1.args[0], /INSERT INTO MessagingSystemMessageBlocklist/);
    181  assert.match(call2.args[0], /DELETE FROM MessagingSystemMessageImpressions/);
    182 
    183  assert.deepEqual(call1.args[1], { messageId: expectedMessageId });
    184  assert.deepEqual(call2.args[1], { messageId: expectedMessageId });
    185 }
    186 
    187 describe("Shared database methods", () => {
    188  let sandbox;
    189  let mockConnection;
    190  let storage;
    191  let errorStub;
    192 
    193  beforeEach(() => {
    194    sandbox = sinon.createSandbox();
    195    errorStub = sandbox.stub();
    196 
    197    storage = new ASRouterStorage({
    198      storeNames: ["storage_test"],
    199      telemetry: { handleUndesiredEvent: sandbox.stub() },
    200    });
    201 
    202    mockConnection = {
    203      executeCached: sandbox.stub(),
    204      executeBeforeShutdown: sandbox.stub(),
    205      executeTransaction: sandbox.stub(),
    206    };
    207 
    208    mockConnection.executeBeforeShutdown.callsFake(async (label, fn) => {
    209      return await fn();
    210    });
    211    mockConnection.executeTransaction.callsFake(async fn => {
    212      return await fn();
    213    });
    214 
    215    overrider.set({
    216      ASRouterPreferences: {
    217        console: {
    218          error: errorStub,
    219        },
    220      },
    221      IndexedDB: indexedDB,
    222      ProfilesDatastoreService: {
    223        getConnection: sandbox.stub().resolves(mockConnection),
    224        notify: sandbox.stub(),
    225      },
    226    });
    227  });
    228 
    229  afterEach(() => {
    230    sandbox.restore();
    231    overrider.restore();
    232  });
    233 
    234  describe("#getSharedMessageImpressions", () => {
    235    it("should return message impressions data when records exist", async () => {
    236      const mockRows = [
    237        {
    238          getResultByName: columnName => {
    239            if (columnName === "messageId") {
    240              return "message1";
    241            }
    242            if (columnName === "impressions") {
    243              return JSON.stringify([123, 456]);
    244            }
    245            return null;
    246          },
    247        },
    248        {
    249          getResultByName: columnName => {
    250            if (columnName === "messageId") {
    251              return "message2";
    252            }
    253            if (columnName === "impressions") {
    254              return JSON.stringify([123, 456, 789]);
    255            }
    256            return null;
    257          },
    258        },
    259      ];
    260 
    261      mockConnection.executeCached.resolves(mockRows);
    262 
    263      const result = await storage.getSharedMessageImpressions();
    264 
    265      // Execute should be called with expected SQL
    266      assert.calledOnce(mockConnection.executeCached);
    267      assert.calledWith(
    268        mockConnection.executeCached,
    269        "SELECT messageId, json(impressions) AS impressions FROM MessagingSystemMessageImpressions;"
    270      );
    271 
    272      assert.deepEqual(result, {
    273        message1: [123, 456],
    274        message2: [123, 456, 789],
    275      });
    276    });
    277 
    278    it("should return null when no records exist", async () => {
    279      mockConnection.executeCached.resolves([]);
    280 
    281      const result = await storage.getSharedMessageImpressions();
    282 
    283      assert.ok(result === null);
    284    });
    285 
    286    it("should handle database errors and call telemetry", async () => {
    287      const error = new Error("Database connection failed");
    288      mockConnection.executeCached.rejects(error);
    289 
    290      const result = await storage.getSharedMessageImpressions();
    291 
    292      assert.equal(result, null);
    293      assert.calledOnce(errorStub);
    294      assert.calledWith(
    295        errorStub,
    296        "ASRouterStorage: Failed reading from MessagingSystemMessageImpressions",
    297        error
    298      );
    299      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    300      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    301        event: "SHARED_DB_READ_FAILED",
    302      });
    303    });
    304 
    305    it("should return null when getConnection throws an error", async () => {
    306      const connectionError = new Error("Failed to get database connection");
    307 
    308      overrider.set({
    309        ASRouterPreferences: {
    310          console: { error: errorStub },
    311        },
    312        ProfilesDatastoreService: {
    313          getConnection: sandbox.stub().rejects(connectionError),
    314          notify: sandbox.stub(),
    315        },
    316      });
    317 
    318      const result = await storage.getSharedMessageImpressions();
    319 
    320      assert.equal(result, null);
    321      assert.calledOnce(errorStub);
    322      assert.calledWith(
    323        errorStub,
    324        "ASRouterStorage: Failed reading from MessagingSystemMessageImpressions",
    325        connectionError
    326      );
    327      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    328      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    329        event: "SHARED_DB_READ_FAILED",
    330      });
    331    });
    332 
    333    it("should return null when getConnection returns null", async () => {
    334      overrider.set({
    335        ProfilesDatastoreService: {
    336          getConnection: sandbox.stub().resolves(null),
    337          notify: sandbox.stub(),
    338        },
    339      });
    340 
    341      const result = await storage.getSharedMessageImpressions();
    342 
    343      assert.equal(result, null);
    344    });
    345  });
    346 
    347  describe("#setSharedMessageImpressions", () => {
    348    it("should return a true success state when the transaction succeeds", async () => {
    349      mockConnection.executeCached.resolves();
    350 
    351      const result = await storage.setSharedMessageImpressions(
    352        "test_message",
    353        [123, 456]
    354      );
    355 
    356      assert.equal(result, true);
    357      assert.calledOnce(mockConnection.executeBeforeShutdown);
    358      assert.calledWith(
    359        mockConnection.executeBeforeShutdown,
    360        "ASRouter: setSharedMessageImpressions"
    361      );
    362    });
    363 
    364    it("should return a false success state when the transaction fails", async () => {
    365      const error = new Error("Database write failed");
    366      mockConnection.executeCached.rejects(error);
    367 
    368      const result = await storage.setSharedMessageImpressions(
    369        "test_message",
    370        [123, 456]
    371      );
    372 
    373      assert.equal(result, false);
    374      assert.calledOnce(errorStub);
    375      assert.calledWith(
    376        errorStub,
    377        "ASRouterStorage: Failed writing to MessagingSystemMessageImpressions",
    378        error
    379      );
    380      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    381      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    382        event: "SHARED_DB_WRITE_FAILED",
    383      });
    384    });
    385 
    386    it("should gracefully fail when called with no message ID", async () => {
    387      const result = await storage.setSharedMessageImpressions(
    388        null,
    389        [123, 456]
    390      );
    391 
    392      assert.equal(result, false);
    393      assert.calledOnce(errorStub);
    394      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    395      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    396        event: "SHARED_DB_WRITE_FAILED",
    397      });
    398    });
    399 
    400    it("should execute the appropriate sql query with the appropriate message ID", async () => {
    401      mockConnection.executeCached.resolves();
    402 
    403      await storage.setSharedMessageImpressions("test_message", [123, 456]);
    404 
    405      assert.calledOnce(mockConnection.executeCached);
    406      const executeCall = mockConnection.executeCached.getCall(0);
    407 
    408      assert.match(
    409        executeCall.args[0],
    410        /INSERT INTO MessagingSystemMessageImpressions/
    411      );
    412      assert.match(executeCall.args[0], /ON CONFLICT \(messageId\) DO UPDATE/);
    413 
    414      assert.deepEqual(executeCall.args[1], {
    415        messageId: "test_message",
    416        impressions: JSON.stringify([123, 456]),
    417      });
    418    });
    419 
    420    it("should still create a record if the array is empty", async () => {
    421      mockConnection.executeCached.resolves();
    422 
    423      await storage.setSharedMessageImpressions("test_message", []);
    424 
    425      assert.calledOnce(mockConnection.executeCached);
    426      let executeCall = mockConnection.executeCached.getCall(0);
    427      assert.match(
    428        executeCall.args[0],
    429        /INSERT INTO MessagingSystemMessageImpressions/
    430      );
    431      assert.deepEqual(executeCall.args[1], {
    432        messageId: "test_message",
    433        impressions: JSON.stringify([]),
    434      });
    435    });
    436 
    437    it("should delete the record when impressions is falsy", async () => {
    438      mockConnection.executeCached.resolves();
    439 
    440      await storage.setSharedMessageImpressions("test_message", null);
    441 
    442      assert.calledOnce(mockConnection.executeCached);
    443      let executeCall = mockConnection.executeCached.getCall(0);
    444      assert.match(
    445        executeCall.args[0],
    446        /DELETE FROM MessagingSystemMessageImpressions/
    447      );
    448    });
    449 
    450    it("should call ProfilesDatastoreService.notify() after successful operation", async () => {
    451      mockConnection.executeCached.resolves();
    452 
    453      const notifySpy = sandbox.spy();
    454 
    455      overrider.set({
    456        ProfilesDatastoreService: {
    457          getConnection: sandbox.stub().resolves(mockConnection),
    458          notify: notifySpy,
    459        },
    460      });
    461 
    462      await storage.setSharedMessageImpressions("test_message", [123]);
    463      assert.calledOnce(notifySpy);
    464    });
    465 
    466    it("should return false when getConnection throws an error", async () => {
    467      const connectionError = new Error("Failed to get database connection");
    468 
    469      overrider.set({
    470        ASRouterPreferences: {
    471          console: { error: errorStub },
    472        },
    473        ProfilesDatastoreService: {
    474          getConnection: sandbox.stub().rejects(connectionError),
    475          notify: sandbox.stub(),
    476        },
    477      });
    478 
    479      const result = await storage.setSharedMessageImpressions(
    480        "test_message",
    481        [123, 456]
    482      );
    483 
    484      assert.equal(result, false);
    485      assert.calledOnce(errorStub);
    486      assert.calledWith(
    487        errorStub,
    488        "ASRouterStorage: Failed writing to MessagingSystemMessageImpressions",
    489        connectionError
    490      );
    491      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    492      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    493        event: "SHARED_DB_WRITE_FAILED",
    494      });
    495    });
    496 
    497    it("should return false when getConnection returns null", async () => {
    498      overrider.set({
    499        ProfilesDatastoreService: {
    500          getConnection: sandbox.stub().resolves(null),
    501          notify: sandbox.stub(),
    502        },
    503      });
    504 
    505      const result = await storage.setSharedMessageImpressions(
    506        "test_message",
    507        [123, 456]
    508      );
    509 
    510      assert.equal(result, false);
    511    });
    512  });
    513 
    514  describe("#getSharedMessageBlocklist", () => {
    515    it("should return array of blocked message IDs when records exist", async () => {
    516      const mockRows = [
    517        {
    518          getResultByName: columnName => {
    519            if (columnName === "messageId") {
    520              return "blocked_message1";
    521            }
    522            return null;
    523          },
    524        },
    525        {
    526          getResultByName: columnName => {
    527            if (columnName === "messageId") {
    528              return "blocked_message2";
    529            }
    530            return null;
    531          },
    532        },
    533      ];
    534 
    535      mockConnection.executeCached.resolves(mockRows);
    536 
    537      const result = await storage.getSharedMessageBlocklist();
    538 
    539      // Execute should be called with expected SQL
    540      assert.calledOnce(mockConnection.executeCached);
    541      assert.calledWith(
    542        mockConnection.executeCached,
    543        "SELECT messageId FROM MessagingSystemMessageBlocklist;"
    544      );
    545 
    546      assert.deepEqual(result, ["blocked_message1", "blocked_message2"]);
    547    });
    548 
    549    it("should return empty array when no blocked messages exist", async () => {
    550      mockConnection.executeCached.resolves([]);
    551 
    552      const result = await storage.getSharedMessageBlocklist();
    553 
    554      assert.deepEqual(result, []);
    555    });
    556 
    557    it("should handle database errors and return null", async () => {
    558      const error = new Error("Database connection failed");
    559      mockConnection.executeCached.rejects(error);
    560 
    561      const result = await storage.getSharedMessageBlocklist();
    562 
    563      assert.equal(result, null);
    564      assert.calledOnce(errorStub);
    565      assert.calledWith(
    566        errorStub,
    567        "ASRouterStorage: Failed reading from MessagingSystemMessageBlocklist",
    568        error
    569      );
    570 
    571      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    572      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    573        event: "SHARED_DB_READ_FAILED",
    574      });
    575    });
    576 
    577    it("should return null when getConnection throws an error", async () => {
    578      const connectionError = new Error("Failed to get database connection");
    579 
    580      overrider.set({
    581        ASRouterPreferences: {
    582          console: { error: errorStub },
    583        },
    584        ProfilesDatastoreService: {
    585          getConnection: sandbox.stub().rejects(connectionError),
    586          notify: sandbox.stub(),
    587        },
    588      });
    589 
    590      const result = await storage.getSharedMessageBlocklist();
    591 
    592      assert.equal(result, null);
    593      assert.calledOnce(errorStub);
    594      assert.calledWith(
    595        errorStub,
    596        "ASRouterStorage: Failed reading from MessagingSystemMessageBlocklist",
    597        connectionError
    598      );
    599      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    600      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    601        event: "SHARED_DB_READ_FAILED",
    602      });
    603    });
    604 
    605    it("should return null when getConnection returns null", async () => {
    606      overrider.set({
    607        ProfilesDatastoreService: {
    608          getConnection: sandbox.stub().resolves(null),
    609          notify: sandbox.stub(),
    610        },
    611      });
    612 
    613      const result = await storage.getSharedMessageBlocklist();
    614 
    615      assert.equal(result, null);
    616    });
    617  });
    618 
    619  describe("#setSharedMessageBlocked", () => {
    620    it("should return true success state when blocking a message succeeds", async () => {
    621      mockConnection.executeCached.resolves();
    622 
    623      const result = await storage.setSharedMessageBlocked(
    624        "test_message",
    625        true
    626      );
    627 
    628      assert.equal(result, true);
    629      assert.calledOnce(mockConnection.executeTransaction);
    630    });
    631 
    632    it("should return false success state when the transaction fails", async () => {
    633      const error = new Error("Database write failed");
    634      mockConnection.executeCached
    635        .withArgs(sinon.match(/INSERT/))
    636        .rejects(error);
    637 
    638      const result = await storage.setSharedMessageBlocked(
    639        "test_message",
    640        true
    641      );
    642 
    643      assert.equal(result, false);
    644      assert.calledOnce(errorStub);
    645      assert.calledWith(
    646        errorStub,
    647        "ASRouterStorage: Failed writing to MessagingSystemMessageBlocklist",
    648        error
    649      );
    650      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    651      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    652        event: "SHARED_DB_WRITE_FAILED",
    653      });
    654    });
    655 
    656    it("should execute INSERT and DELETE queries in a transaction when blocking a message", async () => {
    657      const messageId = "test_blocking_message";
    658      mockConnection.executeCached.resolves();
    659      await storage.setSharedMessageBlocked(messageId, true);
    660 
    661      assertMessageBlockedTransaction(mockConnection, messageId);
    662    });
    663 
    664    it("should execute DELETE query when unblocking a message", async () => {
    665      mockConnection.executeCached.resolves();
    666 
    667      await storage.setSharedMessageBlocked("test_unblocking_message", false);
    668 
    669      assert.calledOnce(mockConnection.executeCached);
    670      const executeCall = mockConnection.executeCached.getCall(0);
    671      assert.match(
    672        executeCall.args[0],
    673        /DELETE FROM MessagingSystemMessageBlocklist/
    674      );
    675      assert.deepEqual(executeCall.args[1], {
    676        messageId: "test_unblocking_message",
    677      });
    678    });
    679 
    680    it("should default to blocking when isBlocked parameter is not provided", async () => {
    681      const messageId = "default_blocked_message";
    682      mockConnection.executeCached.resolves();
    683 
    684      await storage.setSharedMessageBlocked(messageId);
    685 
    686      assertMessageBlockedTransaction(mockConnection, messageId);
    687    });
    688 
    689    it("should call ProfilesDatastoreService.notify() after successful operation", async () => {
    690      mockConnection.executeCached.resolves();
    691 
    692      const notifySpy = sandbox.spy();
    693 
    694      overrider.set({
    695        ProfilesDatastoreService: {
    696          getConnection: sandbox.stub().resolves(mockConnection),
    697          notify: notifySpy,
    698        },
    699      });
    700 
    701      await storage.setSharedMessageBlocked("test_message", true);
    702      assert.calledOnce(notifySpy);
    703    });
    704 
    705    it("should return false when getConnection throws an error when blocking a message", async () => {
    706      const connectionError = new Error("Failed to get database connection");
    707 
    708      overrider.set({
    709        ASRouterPreferences: {
    710          console: { error: errorStub },
    711        },
    712        ProfilesDatastoreService: {
    713          getConnection: sandbox.stub().rejects(connectionError),
    714          notify: sandbox.stub(),
    715        },
    716      });
    717 
    718      const result = await storage.setSharedMessageBlocked(
    719        "test_message",
    720        true
    721      );
    722 
    723      assert.equal(result, false);
    724      assert.calledOnce(errorStub);
    725      assert.calledWith(
    726        errorStub,
    727        "ASRouterStorage: Failed writing to MessagingSystemMessageBlocklist",
    728        connectionError
    729      );
    730      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    731      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    732        event: "SHARED_DB_WRITE_FAILED",
    733      });
    734    });
    735 
    736    it("should return false when getConnection throws an error when unblocking a message", async () => {
    737      const connectionError = new Error("Failed to get database connection");
    738 
    739      overrider.set({
    740        ASRouterPreferences: {
    741          console: { error: errorStub },
    742        },
    743        ProfilesDatastoreService: {
    744          getConnection: sandbox.stub().rejects(connectionError),
    745          notify: sandbox.stub(),
    746        },
    747      });
    748 
    749      const result = await storage.setSharedMessageBlocked(
    750        "test_message",
    751        false
    752      );
    753 
    754      assert.equal(result, false);
    755      assert.calledOnce(errorStub);
    756      assert.calledWith(
    757        errorStub,
    758        "ASRouterStorage: Failed writing to MessagingSystemMessageBlocklist",
    759        connectionError
    760      );
    761      assert.calledOnce(storage.telemetry.handleUndesiredEvent);
    762      assert.calledWith(storage.telemetry.handleUndesiredEvent, {
    763        event: "SHARED_DB_WRITE_FAILED",
    764      });
    765    });
    766 
    767    it("should return false when getConnection returns null when blocking a mesasge", async () => {
    768      overrider.set({
    769        ProfilesDatastoreService: {
    770          getConnection: sandbox.stub().resolves(null),
    771          notify: sandbox.stub(),
    772        },
    773      });
    774 
    775      const result = await storage.setSharedMessageBlocked(
    776        "test_message",
    777        true
    778      );
    779 
    780      assert.equal(result, false);
    781    });
    782 
    783    it("should return false when getConnection returns null when unblokcing a message", async () => {
    784      overrider.set({
    785        ProfilesDatastoreService: {
    786          getConnection: sandbox.stub().resolves(null),
    787          notify: sandbox.stub(),
    788        },
    789      });
    790 
    791      const result = await storage.setSharedMessageBlocked(
    792        "test_message",
    793        false
    794      );
    795 
    796      assert.equal(result, false);
    797    });
    798  });
    799 });