Home | History | Annotate | Download | only in extension
      1 // Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 var cycle_tabs = {};
      6 var cycles = {};
      7 var time_ratio = 3600 * 1000 / test_time_ms; // default test time is 1 hour
      8 var preexisting_windows = [];
      9 var log_lines = [];
     10 var error_codes = {}; //for each active tabId
     11 var page_load_times = [];
     12 var page_load_time_counter = {};
     13 var unique_url_salt = 1;
     14 
     15 function setupTest() {
     16   //adding these listeners to track request failure codes
     17   chrome.webRequest.onCompleted.addListener(capture_completed_status, {urls: ["<all_urls>"]});
     18   chrome.windows.getAll(null, function(windows) {
     19     preexisting_windows = windows;
     20     for (var i = 0; i < tasks.length; i++) {
     21       setTimeout(launch_task, tasks[i].start / time_ratio, tasks[i]);
     22     }
     23     var end = 3600 * 1000 / time_ratio;
     24     log_lines = [];
     25     page_load_times = [];
     26     page_load_time_counter = {};
     27     record_log_entry(dateToString(new Date()) + " Loop started");
     28     setTimeout(send_summary, end);
     29   });
     30 }
     31 
     32 function close_preexisting_windows() {
     33   for (var i = 0; i < preexisting_windows.length; i++) {
     34     chrome.windows.remove(preexisting_windows[i].id);
     35   }
     36   preexisting_windows.length = 0;
     37 }
     38 
     39 function get_active_url(cycle) {
     40   active_idx = cycle.idx == 0 ? cycle.urls.length - 1 : cycle.idx - 1;
     41   return cycle.urls[active_idx];
     42 }
     43 
     44 function testListener(request, sender, sendResponse) {
     45   end = Date.now()
     46   if (sender.tab.id in cycle_tabs) {
     47     cycle = cycle_tabs[sender.tab.id];
     48     cycle.successful_loads++;
     49     url = get_active_url(cycle);
     50    var page_load_time = end - page_load_time_counter[cycle.id]
     51    page_load_times.push({'url': (unique_url_salt++) + url, 'time': page_load_time});
     52    console.log(JSON.stringify(page_load_times));
     53     record_log_entry(dateToString(new Date()) + " [load success] " + url);
     54     if (request.action == "should_scroll" && cycle.focus) {
     55       sendResponse({"should_scroll": should_scroll,
     56                     "should_scroll_up": should_scroll_up,
     57                     "scroll_loop": scroll_loop,
     58                     "scroll_interval": scroll_interval_ms,
     59                     "scroll_by": scroll_by_pixels});
     60     }
     61     delete cycle_tabs[sender.tab.id];
     62   }
     63 }
     64 
     65 function capture_completed_status(details) {
     66   var tabId = details.tabId;
     67   if (!(details.tabId in error_codes)) {
     68     error_codes[tabId] = [];
     69   }
     70   var report = {
     71     'url':details.url,
     72     'code': details.statusCode,
     73     'status': details.statusLine,
     74     'time': new Date(details.timeStamp)
     75   }
     76   error_codes[tabId].push(report);
     77 }
     78 
     79 
     80 function cycle_navigate(cycle) {
     81   cycle_tabs[cycle.id] = cycle;
     82   var url = cycle.urls[cycle.idx];
     83   // Resetting the error codes.
     84   // TODO(coconutruben) Verify if reseeting here might give us
     85   // garbage data since some requests/responses might still come
     86   // in before we update the tab, but we'll register them as
     87   // information about the subsequent url
     88   error_codes[cycle.id] = [];
     89   record_log_entry(dateToString(new Date()) + " [load start] " + url)
     90   var start = Date.now();
     91   page_load_time_counter[cycle.id] = start;
     92   chrome.tabs.update(cycle.id, {'url': url, 'selected': true});
     93   cycle.idx = (cycle.idx + 1) % cycle.urls.length;
     94   if (cycle.timeout < cycle.delay / time_ratio && cycle.timeout > 0) {
     95     cycle.timer = setTimeout(cycle_check_timeout, cycle.timeout, cycle);
     96   } else {
     97     cycle.timer = setTimeout(cycle_navigate, cycle.delay / time_ratio, cycle);
     98   }
     99 }
    100 
    101 function record_error_codes(cycle) {
    102   var error_report = dateToString(new Date()) + " [load failure details] " + get_active_url(cycle) + "\n";
    103   var reports = error_codes[cycle.id];
    104   for (var i = 0; i < reports.length; i++) {
    105     report = reports[i];
    106     error_report = error_report + "\t\t" +
    107     dateToString(report.time) + " | " +
    108     "[response code] " + report.code + " | " +
    109     "[url] " + report.url + " | " +
    110     "[status line] " + report.status + "\n";
    111   }
    112   log_lines.push(error_report);
    113   console.log(error_report);
    114 }
    115 
    116 function cycle_check_timeout(cycle) {
    117   if (cycle.id in cycle_tabs) {
    118     cycle.failed_loads++;
    119     record_error_codes(cycle);
    120     record_log_entry(dateToString(new Date()) + " [load failure] " + get_active_url(cycle));
    121     cycle_navigate(cycle);
    122   } else {
    123     cycle.timer = setTimeout(cycle_navigate,
    124                              cycle.delay / time_ratio - cycle.timeout,
    125                              cycle);
    126   }
    127 }
    128 
    129 function launch_task(task) {
    130   if (task.type == 'window' && task.tabs) {
    131     chrome.windows.create({'url': 'about:blank'}, function (win) {
    132       close_preexisting_windows();
    133       chrome.tabs.getSelected(win.id, function(tab) {
    134         chrome.tabs.update(tab.id, {'url': task.tabs[0], 'selected': true});
    135         for (var i = 1; i < task.tabs.length; i++) {
    136           chrome.tabs.create({'windowId':win.id, url: task.tabs[i]});
    137         }
    138         setTimeout(chrome.windows.remove, task.duration / time_ratio, win.id);
    139       });
    140     });
    141   } else if (task.type == 'cycle' && task.urls) {
    142     chrome.windows.create({'url': 'about:blank'}, function (win) {
    143       close_preexisting_windows();
    144       chrome.tabs.getSelected(win.id, function(tab) {
    145         var cycle = {
    146            'timeout': task.timeout,
    147            'name': task.name,
    148            'delay': task.delay,
    149            'urls': task.urls,
    150            'id': tab.id,
    151            'idx': 0,
    152            'timer': null,
    153            'focus': !!task.focus,
    154            'successful_loads': 0,
    155            'failed_loads': 0
    156         };
    157         cycles[task.name] = cycle;
    158         cycle_navigate(cycle);
    159         setTimeout(function(cycle, win_id) {
    160           clearTimeout(cycle.timer);
    161           chrome.windows.remove(win_id);
    162         }, task.duration / time_ratio, cycle, win.id);
    163       });
    164     });
    165   }
    166 }
    167 
    168 function record_log_entry(entry) {
    169   log_lines.push(entry);
    170 }
    171 
    172 function send_log_entries() {
    173   var post = [];
    174   log_lines.forEach(function (item, index, array) {
    175     var entry = encodeURIComponent(item);
    176     post.push('url'+ index + '=' + entry);
    177   });
    178 
    179   var log_url = 'http://localhost:8001/log';
    180   //  TODO(coconutruben): code-snippet below is shared
    181   //  across record_log_entry and send_keyvals. Consider
    182   //  pull into helper if we use more urls.
    183   var req = new XMLHttpRequest();
    184   req.open('POST', log_url, true);
    185   req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    186   req.send(post.join("&"));
    187   console.log(post.join("&"));
    188 }
    189 
    190 function send_keyvals() {
    191   var post = ["status=good"];
    192 
    193   for (var name in cycles) {
    194     var cycle = cycles[name];
    195     post.push(name + "_successful_loads=" + cycle.successful_loads);
    196     post.push(name + "_failed_loads=" + cycle.failed_loads);
    197   }
    198 
    199   chrome.runtime.onMessage.removeListener(testListener);
    200 
    201   var status_url = 'http://localhost:8001/status';
    202   var req = new XMLHttpRequest();
    203   req.open('POST', status_url, true);
    204   req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    205   req.send(post.join("&"));
    206   console.log(post.join("&"));
    207 }
    208 
    209 function send_raw_page_load_time_info() {
    210   var post = [];
    211   page_load_times.forEach(function (item, index, array) {
    212     var key = encodeURIComponent(item.url);
    213     post.push(key + "=" + item.time);
    214   })
    215 
    216   var pagelt_info_url = 'http://localhost:8001/pagelt'
    217   var req = new XMLHttpRequest();
    218   req.open('POST', pagelt_info_url, true);
    219   req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    220   req.send(post.join("&"));
    221   console.log(post.join("&"));
    222 }
    223 
    224 function send_summary() {
    225   send_log_entries();
    226   send_raw_page_load_time_info();
    227   send_keyvals();
    228 }
    229 
    230 function startTest() {
    231   time_ratio = 3600 * 1000 / test_time_ms; // default test time is 1 hour
    232   chrome.runtime.onMessage.addListener(testListener);
    233   setTimeout(setupTest, 1000);
    234 }
    235 
    236 function initialize() {
    237   // Called when the user clicks on the browser action.
    238   chrome.browserAction.onClicked.addListener(function(tab) {
    239     // Start the test with default settings.
    240     chrome.runtime.onMessage.addListener(testListener);
    241     setTimeout(setupTest, 1000);
    242   });
    243 }
    244 
    245 window.addEventListener("load", initialize);
    246