2009-11-11 Eric Z. Ayers <zundel@google.com>
authoreric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Nov 2009 17:05:30 +0000 (17:05 +0000)
committereric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 11 Nov 2009 17:05:30 +0000 (17:05 +0000)
        Reviewed by Timothy Hatcher.

        Adds a test that dumps the timeline data for a simple script tag.

        https://bugs.webkit.org/show_bug.cgi?id=31204

        * inspector/inspector-test.js:
        (onload):
        * inspector/timeline-script-tag-1-expected.txt: Added.
        * inspector/timeline-script-tag-1.html: Added.
        * inspector/timeline-test.js: Added.
        (retrieveTimelineData):
        ():
        (dumpTimelineRecords):
        (printTimelineRecordProperties):
        (isNonDeterministicProp):
        (printProps):
        (isTimelineOverheadRecord):
        (markTimelineRecordAsOverhead):
        (timelineAgentTypeToString):
        (frontend_startTimelineProfiler.window.WebInspector.addRecordToTimeline):
        (frontend_startTimelineProfiler):
        (frontend_getTimelineResults):
        (frontend_setup):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@50809 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/inspector/inspector-test.js
LayoutTests/inspector/timeline-script-tag-1-expected.txt [new file with mode: 0644]
LayoutTests/inspector/timeline-script-tag-1.html [new file with mode: 0644]
LayoutTests/inspector/timeline-test.js [new file with mode: 0644]

index 62b5502..14d240b 100644 (file)
@@ -1,3 +1,30 @@
+2009-11-11  Eric Z. Ayers  <zundel@google.com>
+
+        Reviewed by Timothy Hatcher.
+
+        Adds a test that dumps the timeline data for a simple script tag.
+
+        https://bugs.webkit.org/show_bug.cgi?id=31204
+
+        * inspector/inspector-test.js:
+        (onload):
+        * inspector/timeline-script-tag-1-expected.txt: Added.
+        * inspector/timeline-script-tag-1.html: Added.
+        * inspector/timeline-test.js: Added.
+        (retrieveTimelineData):
+        ():
+        (dumpTimelineRecords):
+        (printTimelineRecordProperties):
+        (isNonDeterministicProp):
+        (printProps):
+        (isTimelineOverheadRecord):
+        (markTimelineRecordAsOverhead):
+        (timelineAgentTypeToString):
+        (frontend_startTimelineProfiler.window.WebInspector.addRecordToTimeline):
+        (frontend_startTimelineProfiler):
+        (frontend_getTimelineResults):
+        (frontend_setup):
+
 2009-11-11  Gustavo Noronha Silva  <gustavo.noronha@collabora.co.uk>
 
         Unreviewed. Skipping new tests.
index 60c3761..f87bbc0 100755 (executable)
@@ -10,28 +10,39 @@ if (window.layoutTestController) {
 // to capture events that happen during the initial page load.
 var ignoreLoad = window.location.href.indexOf("?reload") === -1;
 if (ignoreLoad) {
+    // Start in a timer, as synchronous opening of web inspector may fail on Windows
     setTimeout(function() {
         if (window.layoutTestController)
             layoutTestController.showWebInspector();
-        window.location.href += "?reload";
     }, 0);
 }
 
 function onload()
 {
-    if (ignoreLoad)
+    if (ignoreLoad) {
+        // Inject scripts into the frontend on the first pass.  Some other logic may want to
+        // use them before the reload.
+        var toInject = [];
+        for (var name in window) {
+            if (name.indexOf("frontend_") === 0 && typeof window[name] === "function")
+                toInject.push(window[name].toString());
+        }
+        // Invoke a setup method if it has been specified
+        if (window["frontend_setup"]) 
+            toInject.push("frontend_setup();");
+
+        evaluateInWebInspector(toInject.join("\n"), function(arg) {
+            window.location.href += "?reload";
+        });
         return;
+    }
 
     var outputElement = document.createElement("div");
     outputElement.id = "output";
     document.body.appendChild(outputElement);
 
-    var toInject = [];
-    for (var name in window) {
-        if (name.indexOf("frontend_") === 0 && typeof window[name] === "function")
-            toInject.push(window[name].toString());
-    }
-    evaluateInWebInspector(toInject.join("\n"), doit);
+    // Make sure web inspector has settled down before executing user code
+    evaluateInWebInspector("true", doit);
 
     // Make sure web inspector window is closed before the test is interrupted.
     setTimeout(function() {
diff --git a/LayoutTests/inspector/timeline-script-tag-1-expected.txt b/LayoutTests/inspector/timeline-script-tag-1-expected.txt
new file mode 100644 (file)
index 0000000..3011441
--- /dev/null
@@ -0,0 +1,16 @@
+Tests the Timeline API instrumentation of an HTML script tag.
+
+ParseHTML
+----> EvaluateScript
+--------> MarkTimeline : SCRIPT TAG
+
+EvaluateScript Properties:
++ startTime : * DEFINED *
++ data : {
++- url : * DEFINED *
++- lineNumber : 76
++ }
++ children : * DEFINED *
++ endTime : * DEFINED *
++ type : 10
+
diff --git a/LayoutTests/inspector/timeline-script-tag-1.html b/LayoutTests/inspector/timeline-script-tag-1.html
new file mode 100644 (file)
index 0000000..9828f7f
--- /dev/null
@@ -0,0 +1,81 @@
+<html>
+<head>
+<script src="inspector-test.js"></script>
+<script src="timeline-test.js"></script>
+<script>
+var timelineMark = "SCRIPT TAG";
+
+function analyzeEvaluateScript(record) 
+{
+    var numChildren = record.children ? record.children.length : 0;
+    for (var i = 0; i < numChildren; ++i) {
+        var child = record.children[i];
+        if (child.type == timelineAgentRecordType.MarkTimeline
+            && child.data.message == timelineMark
+            && record.data.url.indexOf("timeline-script-tag-1.html") !== -1) {
+
+            // Finish printing the record as a tree
+            dumpTimelineRecord(record, 1);
+            output("");
+
+            // Now print the important fields of the record
+            printTimelineRecordProperties(record);
+            return true;
+        }
+    }
+    return false;
+}
+
+function analyzeParseHTML(record) 
+{
+    // Now, dump the specific Script tag that includes the Marker and dump it in detail.
+    var numChildren = record.children ? record.children.length : 0;
+    for (var i = 0; i < numChildren; ++i) {
+        var child = record.children[i];
+        if (child.type == timelineAgentRecordType.EvaluateScript)
+            if (analyzeEvaluateScript(child))
+                return true;
+    }
+    return false;
+}  
+
+// Look for the ParseHtml->EvaluateScript->MarkTimeline that correlates 
+// to the <script> tag below.
+function analyzeTimelineData(timelineRecords) 
+{
+    // Uncomment to debugging the list of data returned.
+    // dumpTimelineRecords(timelineRecords);
+
+    // Search for a ParseHTML record
+    var numRecords = timelineRecords.length;
+    for (var i = 0 ; i < numRecords; ++i) {
+        var record = timelineRecords[i];
+        if (record.type == timelineAgentRecordType.ParseHTML) {
+            // Uncomment to debug the ParseHTML data record
+            // dumpTimelineRecord(record, 0);
+            output("ParseHTML");
+            if (!analyzeParseHTML(record))
+                output("Failed to find timeline mark: " + timelineMark);
+        }
+    }
+}
+
+function doit() 
+{
+    retrieveTimelineData(analyzeTimelineData);
+}
+
+</script>
+</head>
+
+<body onload="onload()">
+<p>
+Tests the Timeline API instrumentation of an HTML script tag.
+</p>
+
+<script>
+     // Mark this script tag so we can find it in the timeline data.
+     console.markTimeline(timelineMark);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/inspector/timeline-test.js b/LayoutTests/inspector/timeline-test.js
new file mode 100644 (file)
index 0000000..7d040fc
--- /dev/null
@@ -0,0 +1,156 @@
+// Used to mark timeline records as belonging to the test framework.
+var timelineOverheadMark = "***Overhead***";
+
+// TimelineAgent record type definitions from the inspector
+var timelineAgentRecordType = {};
+
+// Scrub values when printing out these properties in the record or data field.
+var timelineNonDeterministicProps = { 
+    children : 1,
+    endTime : 1, 
+    startTime : 1,
+    url : 1
+};
+
+// Call this function from the doit() function in the main test page.
+// Pass a function that will get an array of timeline data to process.
+function retrieveTimelineData(analyzeFunction)
+{
+    evaluateInWebInspector("WebInspector.TimelineAgent.RecordType", function(result) {
+        timelineAgentRecordType = result;
+    });
+
+    evaluateInWebInspector("frontend_getTimelineResults()", function(timelineRecords) {
+        if (typeof(timelineRecords) === "string")
+            output("Error fetching Timeline results: " + timelineRecords);
+        else 
+            analyzeFunction(timelineRecords);
+        notifyDone();
+    });
+    markTimelineRecordAsOverhead("onload" + (ignoreLoad ? ":ignoreLoad": ""));
+}
+
+// Dump just the record name, indenting output on separate lines for subrecords
+function dumpTimelineRecord(record, level) 
+{
+    var prefix = "";
+    var suffix = "";
+    for (var i = 0; i < level ; ++i)
+        prefix = "----" + prefix;
+    if (level > 0)
+        prefix = prefix + "> ";
+    if (record.type == timelineAgentRecordType.MarkTimeline) {
+        suffix = " : " + record.data.message;
+    }
+    output(prefix + timelineAgentTypeToString(record.type) + suffix);
+
+    var numChildren = record.children ? record.children.length : 0;
+    for (var i = 0; i < numChildren; ++i)
+        dumpTimelineRecord(record.children[i], level + 1);
+}
+
+// Dumps an entire list of records, culling out those marked as overhead
+function dumpTimelineRecords(timelineRecords) {
+    var numRecords = timelineRecords.length;
+    for (var i = 0; i < numRecords; ++i) {
+        var record = timelineRecords[i];
+        if (!isTimelineOverheadRecord(record))
+            dumpTimelineRecord(record, 0);
+    }
+}
+
+// Sort the fields, then strip out startTime and endTime, they are not deterministic.
+// Also remove children - that field isn't important for the printout.
+function printTimelineRecordProperties(record)
+{
+    output(timelineAgentTypeToString(record.type) + " Properties:");
+    // Use this recursive routine to print the properties
+    printProps(record, 0);
+}
+
+function isNonDeterministicProp(propName)
+{
+    if (timelineNonDeterministicProps[propName])
+        return true;
+    return false;
+}
+
+function printProps (record, level)
+{
+    var props = new Array();
+    for (var prop in record) {
+        props.push(prop);
+    }
+
+    var prefix = "+";
+    for (var i = 0; i < level ; i++) {
+        prefix = prefix + "-";
+    }
+
+    prefix = prefix + " ";
+    for (var prop in props) {
+        var propName = props[prop];
+        var propValue = record[propName];
+        if (isNonDeterministicProp(propName))
+            output(prefix + propName + " : " + (propValue === undefined ? "<undefined>" : " * DEFINED *"));
+        else if (typeof propValue === "object") {
+            output(prefix + propName + " : {");
+            printProps(propValue, level + 1);
+            output(prefix + "}");
+        } else
+            output(prefix + propName + " : " + propValue);
+    }
+}
+
+// Records that have been marked with console.markTimeline(timelineMark)
+// are a part of the test framework and not a part of the test being performed
+function isTimelineOverheadRecord(record) {
+    if (record.type === 11 && record.data.message.indexOf(timelineOverheadMark) !== -1)
+        return true;
+    var numChildren = record.children ?  record.children.length : 0;
+    for (var i = 0; i < numChildren; ++i) {
+        if (isTimelineOverheadRecord(record.children[i]))
+            return true;
+    }
+    return false;
+}
+
+// This mark will help the test analysis cull out records that are overhead.
+function markTimelineRecordAsOverhead(arg)
+{
+    var suffix = '';
+    if (arg)
+        suffix = ": " + arg;
+    console.markTimeline(timelineOverheadMark + suffix);
+}
+
+function timelineAgentTypeToString(numericType)
+{
+    for (var prop in timelineAgentRecordType) {
+        if (timelineAgentRecordType[prop] == numericType)
+            return prop;
+    }
+    return undefined;
+}
+
+// Injected into Inspector window
+function frontend_startTimelineProfiler()
+{
+    window.timelineResults = new Array();
+    window.WebInspector.addRecordToTimeline = function(arg) {
+        window.timelineResults.push(arg);
+    };
+    window.InspectorController.startTimelineProfiler();
+    return 'done';
+}
+
+// Injected into Inspector window
+function frontend_getTimelineResults() {
+    return window.timelineResults;
+}
+
+// Injected into Inspector window
+// frontend_setup always gets called before the page is reloaded.
+function frontend_setup() {
+    frontend_startTimelineProfiler();
+}