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