• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5var cycle_tabs = {};
6var cycles = {};
7var time_ratio = 3600 * 1000 / test_time_ms; // default test time is 1 hour
8var preexisting_windows = [];
9var log_lines = [];
10var error_codes = {}; //for each active tabId
11var page_timestamps = [];
12var page_timestamps_recorder = {};
13var unique_url_salt = 1;
14
15function setupTest() {
16  //adding these listeners to track request failure codes
17  chrome.webRequest.onCompleted.addListener(capture_completed_status,
18                                            {urls: ["<all_urls>"]});
19  chrome.windows.getAll(null, function(windows) {
20    preexisting_windows = windows;
21    for (var i = 0; i < tasks.length; i++) {
22      setTimeout(launch_task, tasks[i].start / time_ratio, tasks[i]);
23    }
24    var end = 3600 * 1000 / time_ratio;
25    log_lines = [];
26    page_timestamps = [];
27    page_timestamps_recorder = {};
28    record_log_entry(dateToString(new Date()) + " Loop started");
29    setTimeout(send_summary, end);
30  });
31}
32
33function close_preexisting_windows() {
34  for (var i = 0; i < preexisting_windows.length; i++) {
35    chrome.windows.remove(preexisting_windows[i].id);
36  }
37  preexisting_windows.length = 0;
38}
39
40function get_active_url(cycle) {
41  active_idx = cycle.idx == 0 ? cycle.urls.length - 1 : cycle.idx - 1;
42  return cycle.urls[active_idx];
43}
44
45function testListener(request, sender, sendResponse) {
46  end = Date.now()
47  page = page_timestamps_recorder[sender.tab.id];
48  page['end_load_time'] = end;
49  console.log("page_timestamps_recorder:");
50  console.log(JSON.stringify(page_timestamps_recorder));
51  if (sender.tab.id in cycle_tabs) {
52    cycle = cycle_tabs[sender.tab.id];
53    cycle.successful_loads++;
54    url = get_active_url(cycle);
55    record_log_entry(dateToString(new Date()) + " [load success] " + url);
56    if (request.action == "should_scroll" && cycle.focus) {
57      sendResponse({"should_scroll": should_scroll,
58                    "should_scroll_up": should_scroll_up,
59                    "scroll_loop": scroll_loop,
60                    "scroll_interval": scroll_interval_ms,
61                    "scroll_by": scroll_by_pixels});
62    }
63    delete cycle_tabs[sender.tab.id];
64  }
65}
66
67function report_page_nav_to_test() {
68  //Sends message to PLT informing that user is navigating to new page.
69  var ping_url = 'http://localhost:8001/pagenav';
70  var req = new XMLHttpRequest();
71  req.open('GET', ping_url, true);
72  req.send("");
73}
74
75function capture_completed_status(details) {
76  var tabId = details.tabId;
77  if (!(details.tabId in error_codes)) {
78    error_codes[tabId] = [];
79  }
80  var report = {
81    'url':details.url,
82    'code': details.statusCode,
83    'status': details.statusLine,
84    'time': new Date(details.timeStamp)
85  }
86  error_codes[tabId].push(report);
87}
88
89
90function cycle_navigate(cycle) {
91  cycle_tabs[cycle.id] = cycle;
92  var url = cycle.urls[cycle.idx];
93  // Resetting the error codes.
94  // TODO(coconutruben) Verify if reseeting here might give us
95  // garbage data since some requests/responses might still come
96  // in before we update the tab, but we'll register them as
97  // information about the subsequent url
98  error_codes[cycle.id] = [];
99  record_log_entry(dateToString(new Date()) + " [load start] " + url)
100  var start = Date.now();
101  // start_time of next page is end_browse_time of previous page
102  if (cycle.id in page_timestamps_recorder) {
103    page = page_timestamps_recorder[cycle.id];
104    page['end_browse_time'] = start;
105    page_timestamps.push(page);
106    console.log(JSON.stringify(page_timestamps));
107  }
108  page_timestamps_new_record(cycle.id, url, start);
109  chrome.tabs.update(cycle.id, {'url': url, 'selected': true});
110  report_page_nav_to_test()
111  cycle.idx = (cycle.idx + 1) % cycle.urls.length;
112  if (cycle.timeout < cycle.delay / time_ratio && cycle.timeout > 0) {
113    cycle.timer = setTimeout(cycle_check_timeout, cycle.timeout, cycle);
114  } else {
115    cycle.timer = setTimeout(cycle_navigate, cycle.delay / time_ratio, cycle);
116  }
117}
118
119function record_error_codes(cycle) {
120  var error_report = dateToString(new Date()) + " [load failure details] "
121                     + get_active_url(cycle) + "\n";
122  var reports = error_codes[cycle.id];
123  for (var i = 0; i < reports.length; i++) {
124    report = reports[i];
125    error_report = error_report + "\t\t" +
126    dateToString(report.time) + " | " +
127    "[response code] " + report.code + " | " +
128    "[url] " + report.url + " | " +
129    "[status line] " + report.status + "\n";
130  }
131  log_lines.push(error_report);
132  console.log(error_report);
133}
134
135function cycle_check_timeout(cycle) {
136  if (cycle.id in cycle_tabs) {
137    cycle.failed_loads++;
138    record_error_codes(cycle);
139    record_log_entry(dateToString(new Date()) + " [load failure] " +
140                                  get_active_url(cycle));
141    cycle_navigate(cycle);
142  } else {
143    cycle.timer = setTimeout(cycle_navigate,
144                             cycle.delay / time_ratio - cycle.timeout,
145                             cycle);
146  }
147}
148
149function launch_task(task) {
150  if (task.type == 'window' && task.tabs) {
151    chrome.windows.create({'url': '/focus.html'}, function (win) {
152      close_preexisting_windows();
153      chrome.tabs.getSelected(win.id, function(tab) {
154        for (var i = 1; i < task.tabs.length; i++) {
155          chrome.tabs.create({'windowId':win.id, 'url': '/focus.html'});
156        }
157        chrome.tabs.getAllInWindow(win.id, function(tabs) {
158          for (var i = 0; i < tabs.length; i++) {
159            tab = tabs[i];
160            url = task.tabs[i];
161            start = Date.now();
162            page_timestamps_new_record(tab.id, url, start);
163            chrome.tabs.update(tab.id, {'url': url, 'selected': true});
164          }
165          console.log(JSON.stringify(page_timestamps_recorder));
166        });
167        setTimeout(function(win_id) {
168          record_end_browse_time_for_window(win_id);
169          chrome.windows.remove(win_id);
170        }, task.duration / time_ratio, win.id);
171      });
172    });
173  } else if (task.type == 'cycle' && task.urls) {
174    chrome.windows.create({'url': '/focus.html'}, function (win) {
175      close_preexisting_windows();
176      chrome.tabs.getSelected(win.id, function(tab) {
177        var cycle = {
178           'timeout': task.timeout,
179           'name': task.name,
180           'delay': task.delay,
181           'urls': task.urls,
182           'id': tab.id,
183           'idx': 0,
184           'timer': null,
185           'focus': !!task.focus,
186           'successful_loads': 0,
187           'failed_loads': 0
188        };
189        cycles[task.name] = cycle;
190        cycle_navigate(cycle);
191        setTimeout(function(cycle, win_id) {
192          clearTimeout(cycle.timer);
193          record_end_browse_time_for_window(win_id);
194          chrome.windows.remove(win_id);
195        }, task.duration / time_ratio, cycle, win.id);
196      });
197    });
198  }
199}
200
201function page_timestamps_new_record(tab_id, url, start) {
202  // sanitize url, make http(s)://www.abc.com/d/e/f into www.abc.com
203  sanitized_url = url.replace(/https?:\/\//, '').split('/')[0];
204  page_timestamps_recorder[tab_id] = {
205    'url': sanitized_url,
206    'start_time': start,
207    'end_load_time': null,
208    'end_browse_time': null
209  }
210}
211
212function record_end_browse_time_for_window(win_id) {
213  chrome.tabs.getAllInWindow(win_id, function(tabs) {
214    end = Date.now();
215    console.log("page_timestamps_recorder:");
216    console.log(JSON.stringify(page_timestamps_recorder));
217    tabs.forEach(function (tab) {
218      if (tab.id in page_timestamps_recorder) {
219        page = page_timestamps_recorder[tab.id];
220        page['end_browse_time'] = end;
221        page_timestamps.push(page);
222      }
223    });
224    console.log(JSON.stringify("page_timestamps:"));
225    console.log(JSON.stringify(page_timestamps));
226  });
227}
228
229function record_log_entry(entry) {
230  log_lines.push(entry);
231}
232
233function send_log_entries() {
234  var post = [];
235  log_lines.forEach(function (item, index, array) {
236    var entry = encodeURIComponent(item);
237    post.push('url'+ index + '=' + entry);
238  });
239
240  var log_url = 'http://localhost:8001/log';
241  //  TODO(coconutruben): code-snippet below is shared
242  //  across record_log_entry and send_keyvals. Consider
243  //  pull into helper if we use more urls.
244  var req = new XMLHttpRequest();
245  req.open('POST', log_url, true);
246  req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
247  req.send(post.join("&"));
248  console.log(post.join("&"));
249}
250
251function send_keyvals() {
252  var post = ["status=good"];
253
254  for (var name in cycles) {
255    var cycle = cycles[name];
256    post.push(name + "_successful_loads=" + cycle.successful_loads);
257    post.push(name + "_failed_loads=" + cycle.failed_loads);
258  }
259
260  chrome.runtime.onMessage.removeListener(testListener);
261
262  var status_url = 'http://localhost:8001/status';
263  var req = new XMLHttpRequest();
264  req.open('POST', status_url, true);
265  req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
266  req.send(post.join("&"));
267  console.log(post.join("&"));
268}
269
270function send_raw_page_time_info() {
271  var post = [];
272  page_timestamps.forEach(function (item) {
273    var unique_url = (unique_url_salt++) + item.url;
274    var key = encodeURIComponent(unique_url);
275    post.push(key + "=" + JSON.stringify(item));
276  })
277
278  var pagetime_info_url = 'http://localhost:8001/pagetime';
279  var req = new XMLHttpRequest();
280  req.open('POST', pagetime_info_url, true);
281  req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
282  req.send(post.join("&"));
283  console.log(post.join("&"));
284}
285
286function send_summary() {
287  send_log_entries();
288  send_raw_page_time_info();
289  send_keyvals();
290}
291
292function startTest() {
293  time_ratio = 3600 * 1000 / test_time_ms; // default test time is 1 hour
294  chrome.runtime.onMessage.addListener(testListener);
295  setTimeout(setupTest, 1000);
296}
297
298function initialize() {
299  // Called when the user clicks on the browser action.
300  chrome.browserAction.onClicked.addListener(function(tab) {
301    // Start the test with default settings.
302    chrome.runtime.onMessage.addListener(testListener);
303    setTimeout(setupTest, 1000);
304  });
305}
306
307window.addEventListener("load", initialize);
308