// Copyright (c) 2014 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. var cycle_tabs = {}; var cycles = {}; var time_ratio = 3600 * 1000 / test_time_ms; // default test time is 1 hour var preexisting_windows = []; var log_lines = []; var error_codes = {}; //for each active tabId var page_timestamps = []; var page_timestamps_recorder = {}; var keys_values = []; function setupTest() { //adding these listeners to track request failure codes chrome.webRequest.onCompleted.addListener(capture_completed_status, {urls: [""]}); task_monitor.bind(); chrome.windows.getAll(null, function(windows) { preexisting_windows = windows; for (var i = 0; i < tasks.length; i++) { setTimeout(launch_task, tasks[i].start / time_ratio, tasks[i]); } var end = 3600 * 1000 / time_ratio; log_lines = []; page_timestamps = []; page_timestamps_recorder = {}; keys_values = []; record_log_entry(dateToString(new Date()) + " Loop started"); setTimeout(send_summary, end); }); } function close_preexisting_windows() { for (var i = 0; i < preexisting_windows.length; i++) { chrome.windows.remove(preexisting_windows[i].id); } preexisting_windows.length = 0; } function get_active_url(cycle) { active_idx = cycle.idx == 0 ? cycle.urls.length - 1 : cycle.idx - 1; return cycle.urls[active_idx]; } function testListener(request, sender, sendResponse) { end = Date.now() page = page_timestamps_recorder[sender.tab.id]; page['end_load_time'] = end; console.log("page_timestamps_recorder:"); console.log(JSON.stringify(page_timestamps_recorder)); if (sender.tab.id in cycle_tabs) { cycle = cycle_tabs[sender.tab.id]; cycle.successful_loads++; url = get_active_url(cycle); record_log_entry(dateToString(new Date()) + " [load success] " + url); if (request.action == "should_scroll" && cycle.focus) { sendResponse({"should_scroll": should_scroll, "should_scroll_up": should_scroll_up, "scroll_loop": scroll_loop, "scroll_interval": scroll_interval_ms, "scroll_by": scroll_by_pixels}); } delete cycle_tabs[sender.tab.id]; } } function report_page_nav_to_test() { //Sends message to PLT informing that user is navigating to new page. var ping_url = 'http://localhost:8001/pagenav'; var req = new XMLHttpRequest(); req.open('GET', ping_url, true); req.send(""); } function capture_completed_status(details) { var tabId = details.tabId; if (!(details.tabId in error_codes)) { error_codes[tabId] = []; } var report = { 'url':details.url, 'code': details.statusCode, 'status': details.statusLine, 'time': new Date(details.timeStamp) } error_codes[tabId].push(report); } function cycle_navigate(cycle) { cycle_tabs[cycle.id] = cycle; var url = cycle.urls[cycle.idx]; // Resetting the error codes. // TODO(coconutruben) Verify if reseting here might give us // garbage data since some requests/responses might still come // in before we update the tab, but we'll register them as // information about the subsequent url error_codes[cycle.id] = []; record_log_entry(dateToString(new Date()) + " [load start] " + url) var start = Date.now(); // start_time of next page is end_browse_time of previous page if (cycle.id in page_timestamps_recorder) { page = page_timestamps_recorder[cycle.id]; page['end_browse_time'] = start; page_timestamps.push(page); console.log(JSON.stringify(page_timestamps)); } page_timestamps_new_record(cycle.id, url, start); chrome.tabs.update(cycle.id, {'url': url, 'selected': true}); report_page_nav_to_test() cycle.idx = (cycle.idx + 1) % cycle.urls.length; if (cycle.timeout < cycle.delay / time_ratio && cycle.timeout > 0) { cycle.timer = setTimeout(cycle_check_timeout, cycle.timeout, cycle); } else { cycle.timer = setTimeout(cycle_navigate, cycle.delay / time_ratio, cycle); } } function record_error_codes(cycle) { var error_report = dateToString(new Date()) + " [load failure details] " + get_active_url(cycle) + "\n"; var reports = error_codes[cycle.id]; for (var i = 0; i < reports.length; i++) { report = reports[i]; error_report = error_report + "\t\t" + dateToString(report.time) + " | " + "[response code] " + report.code + " | " + "[url] " + report.url + " | " + "[status line] " + report.status + "\n"; } log_lines.push(error_report); console.log(error_report); } function cycle_check_timeout(cycle) { if (cycle.id in cycle_tabs) { cycle.failed_loads++; record_error_codes(cycle); record_log_entry(dateToString(new Date()) + " [load failure] " + get_active_url(cycle)); cycle_navigate(cycle); } else { cycle.timer = setTimeout(cycle_navigate, cycle.delay / time_ratio - cycle.timeout, cycle); } } function launch_task(task) { if (task.type == 'window' && task.tabs) { chrome.windows.create({'url': '/focus.html'}, function (win) { close_preexisting_windows(); chrome.tabs.getSelected(win.id, function(tab) { for (var i = 1; i < task.tabs.length; i++) { chrome.tabs.create({'windowId':win.id, 'url': '/focus.html'}); } chrome.tabs.getAllInWindow(win.id, function(tabs) { for (var i = 0; i < tabs.length; i++) { tab = tabs[i]; url = task.tabs[i]; start = Date.now(); page_timestamps_new_record(tab.id, url, start); chrome.tabs.update(tab.id, {'url': url, 'selected': true}); } console.log(JSON.stringify(page_timestamps_recorder)); }); setTimeout(function(win_id) { record_end_browse_time_for_window(win_id); chrome.windows.remove(win_id); }, (task.duration / time_ratio), win.id); }); }); } else if (task.type == 'cycle' && task.urls) { chrome.windows.create({'url': '/focus.html'}, function (win) { close_preexisting_windows(); chrome.tabs.getSelected(win.id, function(tab) { var cycle = { 'timeout': task.timeout, 'name': task.name, 'delay': task.delay, 'urls': task.urls, 'id': tab.id, 'idx': 0, 'timer': null, 'focus': !!task.focus, 'successful_loads': 0, 'failed_loads': 0 }; cycles[task.name] = cycle; cycle_navigate(cycle); setTimeout(function(cycle, win_id) { clearTimeout(cycle.timer); record_end_browse_time_for_window(win_id); chrome.windows.remove(win_id); }, task.duration / time_ratio, cycle, win.id); }); }); } } function page_timestamps_new_record(tab_id, url, start) { // sanitize url, make http(s)://www.abc.com/d/e/f into www.abc.com sanitized_url = url.replace(/https?:\/\//, '').split('/')[0]; page_timestamps_recorder[tab_id] = { 'url': sanitized_url, 'start_time': start, 'end_load_time': null, 'end_browse_time': null } } function record_end_browse_time_for_window(win_id) { chrome.tabs.getAllInWindow(win_id, function(tabs) { end = Date.now(); console.log("page_timestamps_recorder:"); console.log(JSON.stringify(page_timestamps_recorder)); tabs.forEach(function (tab) { if (tab.id in page_timestamps_recorder) { page = page_timestamps_recorder[tab.id]; page['end_browse_time'] = end; page_timestamps.push(page); } }); console.log(JSON.stringify("page_timestamps:")); console.log(JSON.stringify(page_timestamps)); }); } function record_log_entry(entry) { log_lines.push(entry); } function record_key_values(dictionary) { keys_values.push(dictionary); } function send_log_entries() { var post = []; log_lines.forEach(function (item, index) { var entry = encodeURIComponent(item); post.push('log'+ index + '=' + entry); }); var log_url = 'http://localhost:8001/log'; send_post_data(post, log_url) } function send_status() { var post = ["status=good"]; for (var name in cycles) { var cycle = cycles[name]; post.push(name + "_successful_loads=" + cycle.successful_loads); post.push(name + "_failed_loads=" + cycle.failed_loads); } chrome.runtime.onMessage.removeListener(testListener); var status_url = 'http://localhost:8001/status'; send_post_data(post, status_url) } function send_raw_page_time_info() { var post = []; page_timestamps.forEach(function (item, index) { post.push('page_time_data'+ index + "=" + JSON.stringify(item)); }) var pagetime_info_url = 'http://localhost:8001/pagetime'; send_post_data(post, pagetime_info_url) } function send_key_values() { var post = []; keys_values.forEach(function (item, index) { post.push("keyval" + index + "=" + JSON.stringify(item)); }) var key_values_info_url = 'http://localhost:8001/keyvalues'; send_post_data(post, key_values_info_url) } function send_post_data(post, url) { var req = new XMLHttpRequest(); req.open('POST', url, true); req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); req.send(post.join("&")); console.log(post.join("&")); } function send_summary() { send_raw_page_time_info(); task_monitor.unbind(); send_key_values(); send_status(); send_log_entries(); } function startTest() { time_ratio = 3600 * 1000 / test_time_ms; // default test time is 1 hour chrome.runtime.onMessage.addListener(testListener); setTimeout(setupTest, 1000); } function initialize() { // Called when the user clicks on the browser action. chrome.browserAction.onClicked.addListener(function(tab) { // Start the test with default settings. chrome.runtime.onMessage.addListener(testListener); setTimeout(setupTest, 1000); }); } window.addEventListener("load", initialize);