toolkit/components/telemetry/tests/unit/test_TelemetrySendOldPings.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* Any copyright is dedicated to the Public Domain.
     2    http://creativecommons.org/publicdomain/zero/1.0/
     4 /**
     5  * This test case populates the profile with some fake stored
     6  * pings, and checks that:
     7  *
     8  * 1) Pings that are considered "expired" are deleted and never sent.
     9  * 2) Pings that are considered "overdue" trigger a send of all
    10  *    overdue and recent pings.
    11  */
    13 "use strict"
    15 const Cc = Components.classes;
    16 const Ci = Components.interfaces;
    17 const Cr = Components.results;
    18 const Cu = Components.utils;
    20 Cu.import("resource://gre/modules/Services.jsm", this);
    21 Cu.import("resource://testing-common/httpd.js", this);
    22 Cu.import("resource://gre/modules/Promise.jsm", this);
    23 Cu.import("resource://gre/modules/TelemetryFile.jsm", this);
    24 Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
    25 Cu.import("resource://gre/modules/Task.jsm", this);
    26 let {OS: {File, Path, Constants}} = Cu.import("resource://gre/modules/osfile.jsm", {});
    28 // We increment TelemetryFile's MAX_PING_FILE_AGE and
    29 // OVERDUE_PING_FILE_AGE by 1 minute so that our test pings exceed
    30 // those points in time, even taking into account file system imprecision.
    31 const ONE_MINUTE_MS = 60 * 1000;
    32 const EXPIRED_PING_FILE_AGE = TelemetryFile.MAX_PING_FILE_AGE + ONE_MINUTE_MS;
    33 const OVERDUE_PING_FILE_AGE = TelemetryFile.OVERDUE_PING_FILE_AGE + ONE_MINUTE_MS;
    35 const PING_SAVE_FOLDER = "saved-telemetry-pings";
    36 const PING_TIMEOUT_LENGTH = 5000;
    37 const EXPIRED_PINGS = 5;
    38 const OVERDUE_PINGS = 6;
    39 const RECENT_PINGS = 4;
    41 const TOTAL_EXPECTED_PINGS = OVERDUE_PINGS + RECENT_PINGS;
    43 let gHttpServer = new HttpServer();
    44 let gCreatedPings = 0;
    45 let gSeenPings = 0;
    47 /**
    48  * Creates some TelemetryPings for the current session and
    49  * saves them to disk. Each ping gets a unique ID slug based on
    50  * an incrementor.
    51  *
    52  * @param aNum the number of pings to create.
    53  * @param aAge the age in milliseconds to offset from now. A value
    54  *             of 10 would make the ping 10ms older than now, for
    55  *             example.
    56  * @returns Promise
    57  * @resolve an Array with the created pings.
    58  */
    59 function createSavedPings(aNum, aAge) {
    60   return Task.spawn(function*(){
    61     // Create a TelemetryPing service that we can generate payloads from.
    62     // Luckily, the TelemetryPing constructor does nothing that we need to
    63     // clean up.
    64     let pings = [];
    65     let age = Date.now() - aAge;
    67     for (let i = 0; i < aNum; ++i) {
    68       let payload = TelemetryPing.getPayload();
    69       let ping = { slug: "test-ping-" + gCreatedPings, reason: "test", payload: payload };
    71       yield TelemetryFile.savePing(ping);
    73       if (aAge) {
    74         // savePing writes to the file synchronously, so we're good to
    75         // modify the lastModifedTime now.
    76         let file = getSavePathForPing(ping);
    77         yield File.setDates(file, null, age);
    78       }
    79       gCreatedPings++;
    80       pings.push(ping);
    81     }
    82     return pings;
    83   });
    84 }
    86 /**
    87  * Deletes locally saved pings in aPings if they
    88  * exist.
    89  *
    90  * @param aPings an Array of pings to delete.
    91  * @returns Promise
    92  */
    93 function clearPings(aPings) {
    94   return Task.spawn(function*() {
    95     for (let ping of aPings) {
    96       let path = getSavePathForPing(ping);
    97       yield File.remove(path);
    98     }
    99   });
   100 }
   102 /**
   103  * Returns a handle for the file that aPing should be
   104  * stored in locally.
   105  *
   106  * @returns path
   107  */
   108 function getSavePathForPing(aPing) {
   109   return Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, aPing.slug);
   110 }
   112 /**
   113  * Check if the number of TelemetryPings received by the
   114  * HttpServer is not equal to aExpectedNum.
   115  *
   116  * @param aExpectedNum the number of pings we expect to receive.
   117  */
   118 function assertReceivedPings(aExpectedNum) {
   119   do_check_eq(gSeenPings, aExpectedNum);
   120 }
   122 /**
   123  * Throws if any pings in aPings is saved locally.
   124  *
   125  * @param aPings an Array of pings to check.
   126  * @returns Promise
   127  */
   128 function assertNotSaved(aPings) {
   129   return Task.spawn(function*() {
   130     let saved = 0;
   131     for (let ping of aPings) {
   132       let file = getSavePathForPing(ping);
   133       if (yield File.exists()) {
   134         saved++;
   135       }
   136     }
   137     if (saved > 0) {
   138       do_throw("Found " + saved + " unexpected saved pings.");
   139     }
   140   });
   141 }
   143 /**
   144  * Our handler function for the HttpServer that simply
   145  * increments the gSeenPings global when it successfully
   146  * receives and decodes a TelemetryPing payload.
   147  *
   148  * @param aRequest the HTTP request sent from HttpServer.
   149  */
   150 function pingHandler(aRequest) {
   151   gSeenPings++;
   152 }
   154 /**
   155  * Returns a Promise that resolves when gHttpServer has been
   156  * successfully shut down.
   157  *
   158  * @returns Promise
   159  */
   160 function stopHttpServer() {
   161   let deferred = Promise.defer();
   162   gHttpServer.stop(function() {
   163     deferred.resolve();
   164   })
   165   return deferred.promise;
   166 }
   168 /**
   169  * Teardown a TelemetryPing instance and clear out any pending
   170  * pings to put as back in the starting state.
   171  */
   172 function resetTelemetry() {
   173   TelemetryPing.uninstall();
   174   // Quick and dirty way to clear TelemetryFile's pendingPings
   175   // collection, and put it back in its initial state.
   176   let gen = TelemetryFile.popPendingPings();
   177   for (let item of gen) {};
   178 }
   180 /**
   181  * Creates and returns a TelemetryPing instance in "testing"
   182  * mode.
   183  */
   184 function startTelemetry() {
   185   return TelemetryPing.setup();
   186 }
   188 function run_test() {
   189   gHttpServer.registerPrefixHandler("/submit/telemetry/", pingHandler);
   190   gHttpServer.start(-1);
   191   do_get_profile();
   192   Services.prefs.setBoolPref(TelemetryPing.Constants.PREF_ENABLED, true);
   193   Services.prefs.setCharPref(TelemetryPing.Constants.PREF_SERVER,
   194                              "http://localhost:" + gHttpServer.identity.primaryPort);
   195   run_next_test();
   196 }
   198 /**
   199  * Test that pings that are considered too old are just chucked out
   200  * immediately and never sent.
   201  */
   202 add_task(function test_expired_pings_are_deleted() {
   203   let expiredPings = yield createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
   204   yield startTelemetry();
   205   assertReceivedPings(0);
   206   yield assertNotSaved(expiredPings);
   207   yield resetTelemetry();
   208 });
   210 /**
   211  * Test that really recent pings are not sent on Telemetry initialization.
   212  */
   213 add_task(function test_recent_pings_not_sent() {
   214   let recentPings = yield createSavedPings(RECENT_PINGS);
   215   yield startTelemetry();
   216   assertReceivedPings(0);
   217   yield resetTelemetry();
   218   yield clearPings(recentPings);
   219 });
   221 /**
   222  * Create some recent, expired and overdue pings. The overdue pings should
   223  * trigger a send of all recent and overdue pings, but the expired pings
   224  * should just be deleted.
   225  */
   226 add_task(function test_overdue_pings_trigger_send() {
   227   let recentPings = yield createSavedPings(RECENT_PINGS);
   228   let expiredPings = yield createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
   229   let overduePings = yield createSavedPings(OVERDUE_PINGS, OVERDUE_PING_FILE_AGE);
   231   yield startTelemetry();
   232   assertReceivedPings(TOTAL_EXPECTED_PINGS);
   234   yield assertNotSaved(recentPings);
   235   yield assertNotSaved(expiredPings);
   236   yield assertNotSaved(overduePings);
   237   yield resetTelemetry();
   238 });
   240 add_task(function teardown() {
   241   yield stopHttpServer();
   242 });

mercurial