Bug 1145914 - Make the inspector actor send over only the most recent change for each attribute;r=dcamp
authorBrian Grinstead <bgrinstead@mozilla.com>
Fri, 27 Mar 2015 07:31:14 -0700
changeset 266457 fde5601c5dd4bf12138d70bb24644c90a49888f4
parent 266456 9630284e15e6ff436a1ec2b0a9c2e884eac69d04
child 266458 3f3bb18b9f04ff7f2cce748f18df41bf3ba2e1f1
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdcamp
bugs1145914
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1145914 - Make the inspector actor send over only the most recent change for each attribute;r=dcamp
toolkit/devtools/server/actors/inspector.js
toolkit/devtools/server/tests/mochitest/test_inspector-mutations-attr.html
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -2401,17 +2401,39 @@ var WalkerActor = protocol.ActorClass({
       for (let node of this._orphaned) {
         // Release the orphaned node.  Nodes or children that have been
         // retained will be moved to this._retainedOrphans.
         this.releaseNode(node);
       }
       this._orphaned = new Set();
     }
 
-    return pending;
+
+    // Clear out any duplicate attribute mutations before sending them over
+    // the protocol.  Keep only the most recent change for each attribute.
+    let targetMap = {};
+    let filtered = pending.reverse().filter(mutation => {
+      if (mutation.type === "attributes") {
+        if (!targetMap[mutation.target]) {
+          targetMap[mutation.target] = {};
+        }
+        let attributesForTarget = targetMap[mutation.target];
+
+        if (attributesForTarget[mutation.attributeName]) {
+          // Since the array was reversed, if we've seen this attribute already
+          // then this one is a duplicate and can be skipped.
+          return false;
+        }
+
+        attributesForTarget[mutation.attributeName] = true;
+      }
+      return true;
+    }).reverse();
+
+    return filtered;
   }, {
     request: {
       cleanup: Option(0)
     },
     response: {
       mutations: RetVal("array:dommutation")
     }
   }),
--- a/toolkit/devtools/server/tests/mochitest/test_inspector-mutations-attr.html
+++ b/toolkit/devtools/server/tests/mochitest/test_inspector-mutations-attr.html
@@ -40,20 +40,22 @@ addTest(function setup() {
     }).then(runNextTest));
   });
 });
 
 addTest(setupAttrTest);
 addTest(testAddAttribute);
 addTest(testChangeAttribute);
 addTest(testRemoveAttribute);
+addTest(testQueuedMutations);
 addTest(setupFrameAttrTest);
 addTest(testAddAttribute);
 addTest(testChangeAttribute);
 addTest(testRemoveAttribute);
+addTest(testQueuedMutations);
 
 function setupAttrTest() {
   attrNode = gInspectee.querySelector("#a")
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#a").then(node => {
     attrFront = node;
   }).then(runNextTest));
 }
 
@@ -80,35 +82,70 @@ function testAddAttribute() {
     is(attrFront.attributes.length, 3, "Should have id and two new attributes.");
     is(attrFront.getAttribute("data-newattr"), "newvalue", "Node front should have the first new attribute");
     is(attrFront.getAttribute("data-newattr2"), "newvalue", "Node front should have the second new attribute.");
     runNextTest();
   });
 }
 
 function testChangeAttribute() {
-  attrNode.setAttribute("data-newattr", "changedvalue");
-  gWalker.once("mutations", () => {
+  attrNode.setAttribute("data-newattr", "changedvalue1");
+  attrNode.setAttribute("data-newattr", "changedvalue2");
+  attrNode.setAttribute("data-newattr", "changedvalue3");
+  gWalker.once("mutations", mutations => {
+    is(mutations.length, 1, "Only one mutation is sent for multiple queued attribute changes");
     is(attrFront.attributes.length, 3, "Should have id and two new attributes.");
-    is(attrFront.getAttribute("data-newattr"), "changedvalue", "Node front should have the changed first value");
+    is(attrFront.getAttribute("data-newattr"), "changedvalue3", "Node front should have the changed first value");
     is(attrFront.getAttribute("data-newattr2"), "newvalue", "Second value should remain unchanged.");
     runNextTest();
   });
 }
 
 function testRemoveAttribute() {
   attrNode.removeAttribute("data-newattr2");
   gWalker.once("mutations", () => {
     is(attrFront.attributes.length, 2, "Should have id and one remaining attribute.");
-    is(attrFront.getAttribute("data-newattr"), "changedvalue", "Node front should still have the first value");
+    is(attrFront.getAttribute("data-newattr"), "changedvalue3", "Node front should still have the first value");
     ok(!attrFront.hasAttribute("data-newattr2"), "Second value should be removed.");
     runNextTest();
   })
 }
 
+function testQueuedMutations() {
+  // All modifications to each attribute should be queued in one mutation event.
+
+  attrNode.removeAttribute("data-newattr");
+  attrNode.setAttribute("data-newattr", "1");
+  attrNode.removeAttribute("data-newattr");
+  attrNode.setAttribute("data-newattr", "2");
+  attrNode.removeAttribute("data-newattr");
+
+  for (var i = 0; i <= 1000; i++) {
+    attrNode.setAttribute("data-newattr2", i);
+  }
+
+  attrNode.removeAttribute("data-newattr3");
+  attrNode.setAttribute("data-newattr3", "1");
+  attrNode.removeAttribute("data-newattr3");
+  attrNode.setAttribute("data-newattr3", "2");
+  attrNode.removeAttribute("data-newattr3");
+  attrNode.setAttribute("data-newattr3", "3");
+
+  gWalker.once("mutations", mutations => {
+    is(mutations.length, 3, "Only one mutation each is sent for multiple queued attribute changes");
+    is(attrFront.attributes.length, 3, "Should have id, data-newattr2, and data-newattr3.");
+
+    is(attrFront.getAttribute("data-newattr2"), "1000", "Node front should still have the correct value");
+    is(attrFront.getAttribute("data-newattr3"), "3", "Node front should still have the correct value");
+    ok(!attrFront.hasAttribute("data-newattr"), "Attribute value should be removed.");
+
+    runNextTest();
+  })
+}
+
 addTest(function cleanup() {
   delete gInspectee;
   delete gWalker;
   delete gClient;
   runNextTest();
 });