/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/
*/

/**
 * This file only contains the |test_abortedSessionQueued| test. This needs
 * to be in a separate, stand-alone file since we're initializing Telemetry
 * twice, in a non-standard way to simulate incorrect shutdowns. Doing this
 * in other files might interfere with the other tests.
 */

Cu.import("resource://gre/modules/TelemetryStorage.jsm", this);
Cu.import("resource://gre/modules/Services.jsm", this);

const DATAREPORTING_DIR = "datareporting";
const ABORTED_PING_FILE_NAME = "aborted-session-ping";
const ABORTED_SESSION_UPDATE_INTERVAL_MS = 5 * 60 * 1000;

const PING_TYPE_MAIN = "main";
const REASON_ABORTED_SESSION = "aborted-session";

XPCOMUtils.defineLazyGetter(this, "DATAREPORTING_PATH", function() {
  return OS.Path.join(OS.Constants.Path.profileDir, DATAREPORTING_DIR);
});

add_task(async function test_setup() {
  do_get_profile();
  PingServer.start();
  Services.prefs.setCharPref(TelemetryUtils.Preferences.Server, "http://localhost:" + PingServer.port);
});

add_task(async function test_abortedSessionQueued() {
  const ABORTED_FILE = OS.Path.join(DATAREPORTING_PATH, ABORTED_PING_FILE_NAME);

  // Make sure the aborted sessions directory does not exist to test its creation.
  await OS.File.removeDir(DATAREPORTING_PATH, { ignoreAbsent: true });

  let schedulerTickCallback = null;
  let now = new Date(2040, 1, 1, 0, 0, 0);
  fakeNow(now);
  // Fake scheduler functions to control aborted-session flow in tests.
  fakeSchedulerTimer(callback => schedulerTickCallback = callback, () => {});
  await TelemetryController.testReset();

  Assert.ok((await OS.File.exists(DATAREPORTING_PATH)),
            "Telemetry must create the aborted session directory when starting.");

  // Fake now again so that the scheduled aborted-session save takes place.
  now = futureDate(now, ABORTED_SESSION_UPDATE_INTERVAL_MS);
  fakeNow(now);
  // The first aborted session checkpoint must take place right after the initialisation.
  Assert.ok(!!schedulerTickCallback);
  // Execute one scheduler tick.
  await schedulerTickCallback();
  // Check that the aborted session is due at the correct time.
  Assert.ok((await OS.File.exists(ABORTED_FILE)),
            "There must be an aborted session ping.");

  await TelemetryStorage.testClearPendingPings();
  PingServer.clearRequests();
  await TelemetryController.testReset();

  Assert.ok(!(await OS.File.exists(ABORTED_FILE)),
            "The aborted session ping must be removed from the aborted session ping directory.");

  // Restarting Telemetry again to trigger sending pings in TelemetrySend.
  await TelemetryController.testReset();

  // We should have received an aborted-session ping.
  const receivedPing = await PingServer.promiseNextPing();
  Assert.equal(receivedPing.type, PING_TYPE_MAIN, "Should have the correct type");
  Assert.equal(receivedPing.payload.info.reason, REASON_ABORTED_SESSION, "Ping should have the correct reason");

  await TelemetryController.testShutdown();
});

add_task(async function stopServer() {
  await PingServer.stop();
});
