summaryrefslogtreecommitdiffstats
path: root/toolkit/components/backgroundtasks/tests/xpcshell/test_backgroundtask_simultaneous_instances.js
blob: acae92084962942ec910d7c13c3b2bce753050d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 * vim: sw=4 ts=4 sts=4 et
 * 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/. */

// Display logging for ease of debugging.
let moz_log = "BackgroundTasks:5";

// Background task temporary profiles are created in the OS temporary directory.
// On Windows, we can put the temporary directory in a testing-specific location
// by setting TMP, per
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw.
// On Linux, this works as well: see
// [GetSpecialSystemDirectory](https://searchfox.org/mozilla-central/source/xpcom/io/SpecialSystemDirectory.cpp).
// On macOS, we can't set the temporary directory in this manner, so we will
// leak some temporary directories.  It's important to test this functionality
// on macOS so we accept this.
let tmp = do_get_profile();
tmp.append("Temp");

add_setup(() => {
  if (Services.env.exists("MOZ_LOG")) {
    moz_log += `,${Services.env.get("MOZ_LOG")}`;
  }

  tmp.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o700);
});

async function launch_one(index) {
  let sentinel = Services.uuid.generateUUID().toString();
  sentinel = sentinel.substring(1, sentinel.length - 1);

  let stdoutLines = [];
  let exitCode = await do_backgroundtask("unique_profile", {
    extraArgs: [sentinel],
    extraEnv: {
      MOZ_BACKGROUNDTASKS_NO_REMOVE_PROFILE: "1",
      MOZ_LOG: moz_log,
      TMP: tmp.path, // Ignored on macOS.
    },
    onStdoutLine: line => stdoutLines.push(line),
  });

  let profile;
  for (let line of stdoutLines) {
    if (line.includes(sentinel)) {
      let info = JSON.parse(line.split(sentinel)[1]);
      profile = info[1];
    }
  }

  return { index, sentinel, exitCode, profile };
}

add_task(async function test_backgroundtask_simultaneous_instances() {
  let expectedCount = 10;
  let promises = [];

  for (let i = 0; i < expectedCount; i++) {
    promises.push(launch_one(i));
  }

  let results = await Promise.all(promises);

  registerCleanupFunction(() => {
    for (let result of results) {
      if (!result.profile) {
        return;
      }

      let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
      dir.initWithPath(result.profile);
      try {
        dir.remove();
      } catch (e) {
        console.warn("Could not clean up profile directory", e);
      }
    }
  });

  for (let result of results) {
    Assert.equal(
      0,
      result.exitCode,
      `Invocation ${result.index} with sentinel ${result.sentinel} exited with code 0`
    );
    Assert.ok(
      result.profile,
      `Invocation ${result.index} with sentinel ${result.sentinel} yielded a temporary profile directory`
    );
  }

  let profiles = new Set(results.map(it => it.profile));
  Assert.equal(
    expectedCount,
    profiles.size,
    `Invocations used ${expectedCount} different temporary profile directories`
  );
});