summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/imap/test/unit/test_largeOfflineStore.js
blob: 6e0d2e9dd1515bd978ce8a1de8720084bfa6ccf9 (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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* 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/. */

/*
 * Test to ensure that downloadAllForOffline works correctly for large imap
 * stores, i.e., over 4 GiB.
 */

var { MessageGenerator, MessageScenarioFactory } = ChromeUtils.import(
  "resource://testing-common/mailnews/MessageGenerator.jsm"
);
var { PromiseTestUtils } = ChromeUtils.import(
  "resource://testing-common/mailnews/PromiseTestUtils.jsm"
);

Services.prefs.setCharPref(
  "mail.serverDefaultStoreContractID",
  "@mozilla.org/msgstore/berkeleystore;1"
);

var gOfflineStoreSize;

add_setup(async function () {
  setupIMAPPump();

  // Figure out the name of the IMAP inbox
  let inboxFile = IMAPPump.incomingServer.rootMsgFolder.filePath;
  inboxFile.append("INBOX");
  if (!inboxFile.exists()) {
    inboxFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0644", 8));
  }

  let neededFreeSpace = 0x200000000;
  // On Windows, check whether the drive is NTFS. If it is, mark the file as
  // sparse. If it isn't, then bail out now, because in all probability it is
  // FAT32, which doesn't support file sizes greater than 4 GB.
  if (
    "@mozilla.org/windows-registry-key;1" in Cc &&
    mailTestUtils.get_file_system(inboxFile) != "NTFS"
  ) {
    throw new Error("On Windows, this test only works on NTFS volumes.\n");
  }

  let isFileSparse = mailTestUtils.mark_file_region_sparse(
    inboxFile,
    0,
    0x10000000f
  );
  let freeDiskSpace = inboxFile.diskSpaceAvailable;
  Assert.ok(
    isFileSparse && freeDiskSpace > neededFreeSpace,
    "This test needs " +
      mailTestUtils.toMiBString(neededFreeSpace) +
      " free space to run."
  );
});

add_task(async function addOfflineMessages() {
  // Create a couple test messages on the IMAP server.
  let messages = [];
  let messageGenerator = new MessageGenerator();
  let scenarioFactory = new MessageScenarioFactory(messageGenerator);

  messages = messages.concat(scenarioFactory.directReply(2));
  let dataUri = Services.io.newURI(
    "data:text/plain;base64," + btoa(messages[0].toMessageString())
  );
  let imapMsg = new ImapMessage(dataUri.spec, IMAPPump.mailbox.uidnext++, []);
  IMAPPump.mailbox.addMessage(imapMsg);

  dataUri = Services.io.newURI(
    "data:text/plain;base64," + btoa(messages[1].toMessageString())
  );
  imapMsg = new ImapMessage(dataUri.spec, IMAPPump.mailbox.uidnext++, []);
  IMAPPump.mailbox.addMessage(imapMsg);

  // Extend local IMAP inbox to over 4 GiB.
  let outputStream = Cc["@mozilla.org/network/file-output-stream;1"]
    .createInstance(Ci.nsIFileOutputStream)
    .QueryInterface(Ci.nsISeekableStream);
  // Open in write-only mode, no truncate.
  outputStream.init(IMAPPump.inbox.filePath, 0x02, -1, 0);
  // seek to 15 bytes past 4GB.
  outputStream.seek(0, 0x10000000f);
  // Write an empty "from" line.
  outputStream.write("from\r\n", 6);
  outputStream.close();

  // Save initial file size.
  gOfflineStoreSize = IMAPPump.inbox.filePath.fileSize;
  dump(
    "Offline store size (before 1st downloadAllForOffline()) = " +
      gOfflineStoreSize +
      "\n"
  );

  // Download for offline use, to append created messages to local IMAP inbox.
  let listener = new PromiseTestUtils.PromiseUrlListener();
  IMAPPump.inbox.downloadAllForOffline(listener, null);
  await listener.promise;
});

add_task(async function check_result() {
  // Call downloadAllForOffline() a second time.
  let listener = new PromiseTestUtils.PromiseUrlListener();
  IMAPPump.inbox.downloadAllForOffline(listener, null);
  await listener.promise;

  // Make sure offline store grew (i.e., we were not writing over data).
  let offlineStoreSize = IMAPPump.inbox.filePath.fileSize;
  dump(
    "Offline store size (after 2nd downloadAllForOffline()): " +
      offlineStoreSize +
      " Msg hdr offsets should be close to it.\n"
  );
  Assert.ok(offlineStoreSize > gOfflineStoreSize);

  // Verify that the message headers have the offline flag set.
  for (let header of IMAPPump.inbox.msgDatabase.enumerateMessages()) {
    // Verify that each message has been downloaded and looks OK.
    Assert.ok(
      header instanceof Ci.nsIMsgDBHdr &&
        header.flags & Ci.nsMsgMessageFlags.Offline,
      "Message downloaded for offline use"
    );

    // Make sure we don't fall over if we ask to read the message.
    IMAPPump.inbox.getLocalMsgStream(header).close();
  }
});

add_task(function teardown() {
  // Free up disk space - if you want to look at the file after running
  // this test, comment out this line.
  if (IMAPPump.inbox) {
    IMAPPump.inbox.filePath.remove(false);
  }

  teardownIMAPPump();
});