1// Copyright 2014 The Chromium 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 5#include "net/spdy/spdy_priority_tree.h" 6 7#include "base/basictypes.h" 8#include "testing/gtest/include/gtest/gtest.h" 9 10namespace net { 11 12namespace test { 13 14template <typename NodeId> 15class SpdyPriorityTreePeer { 16 public: 17 explicit SpdyPriorityTreePeer(SpdyPriorityTree<NodeId>* tree) : tree_(tree) {} 18 19 void PropagateNodeState(NodeId node) { 20 tree_->PropagateNodeState(node); 21 } 22 23 private: 24 SpdyPriorityTree<NodeId>* tree_; 25}; 26 27TEST(SpdyPriorityTreeTest, AddAndRemoveNodes) { 28 SpdyPriorityTree<uint32> tree; 29 EXPECT_EQ(1, tree.num_nodes()); 30 EXPECT_TRUE(tree.NodeExists(0)); 31 EXPECT_FALSE(tree.NodeExists(1)); 32 33 EXPECT_TRUE(tree.AddNode(1, 0, 100, false)); 34 EXPECT_EQ(2, tree.num_nodes()); 35 ASSERT_TRUE(tree.NodeExists(1)); 36 EXPECT_EQ(100, tree.GetWeight(1)); 37 EXPECT_FALSE(tree.NodeExists(5)); 38 39 EXPECT_TRUE(tree.AddNode(5, 0, 50, false)); 40 // Should not be able to add a node with an id that already exists. 41 EXPECT_FALSE(tree.AddNode(5, 1, 50, false)); 42 EXPECT_EQ(3, tree.num_nodes()); 43 EXPECT_TRUE(tree.NodeExists(1)); 44 ASSERT_TRUE(tree.NodeExists(5)); 45 EXPECT_EQ(50, tree.GetWeight(5)); 46 EXPECT_FALSE(tree.NodeExists(13)); 47 48 EXPECT_TRUE(tree.AddNode(13, 5, 130, true)); 49 EXPECT_EQ(4, tree.num_nodes()); 50 EXPECT_TRUE(tree.NodeExists(1)); 51 EXPECT_TRUE(tree.NodeExists(5)); 52 ASSERT_TRUE(tree.NodeExists(13)); 53 EXPECT_EQ(130, tree.GetWeight(13)); 54 EXPECT_EQ(5u, tree.GetParent(13)); 55 56 EXPECT_TRUE(tree.RemoveNode(5)); 57 // Cannot remove a node that has already been removed. 58 EXPECT_FALSE(tree.RemoveNode(5)); 59 EXPECT_EQ(3, tree.num_nodes()); 60 EXPECT_TRUE(tree.NodeExists(1)); 61 EXPECT_FALSE(tree.NodeExists(5)); 62 EXPECT_TRUE(tree.NodeExists(13)); 63 EXPECT_EQ(0u, tree.GetParent(13)); 64 65 // The parent node 19 doesn't exist, so this should fail: 66 EXPECT_FALSE(tree.AddNode(7, 19, 70, false)); 67 // This should succeed, creating node 7: 68 EXPECT_TRUE(tree.AddNode(7, 13, 70, false)); 69 // Now node 7 already exists, so this should fail: 70 EXPECT_FALSE(tree.AddNode(7, 1, 70, false)); 71 // Try adding a second child to node 13: 72 EXPECT_TRUE(tree.AddNode(17, 13, 170, false)); 73 74 ASSERT_TRUE(tree.ValidateInvariantsForTests()); 75} 76 77TEST(SpdyPriorityTreeTest, SetParent) { 78 SpdyPriorityTree<uint32> tree; 79 tree.AddNode(1, 0, 100, false); 80 tree.AddNode(2, 1, 20, false); 81 tree.AddNode(3, 2, 30, false); 82 tree.AddNode(5, 3, 50, false); 83 tree.AddNode(7, 5, 70, false); 84 tree.AddNode(9, 7, 90, false); 85 tree.AddNode(11, 0, 200, false); 86 tree.AddNode(13, 11, 130, false); 87 // We can't set the parent of a nonexistent node, or set the parent of an 88 // existing node to a nonexistent node. 89 EXPECT_FALSE(tree.SetParent(99, 13, false)); 90 EXPECT_FALSE(tree.SetParent(5, 99, false)); 91 // We should be able to add multiple children to nodes. 92 EXPECT_TRUE(tree.SetParent(13, 7, false)); 93 EXPECT_TRUE(tree.SetParent(3, 11, false)); 94 // We should adjust the tree if a new dependency would create a cycle. 95 EXPECT_TRUE(tree.SetParent(11, 13, false)); 96 EXPECT_TRUE(tree.SetParent(1, 9, false)); 97 EXPECT_TRUE(tree.SetParent(3, 9, false)); 98 // Test dependency changes. 99 EXPECT_TRUE(tree.HasChild(5, 7)); 100 EXPECT_TRUE(tree.SetParent(7, 13, false)); 101 EXPECT_EQ(13u, tree.GetParent(7)); 102 EXPECT_TRUE(tree.HasChild(13, 7)); 103 104 EXPECT_TRUE(tree.SetParent(1, 9, false)); 105 EXPECT_EQ(9u, tree.GetParent(1)); 106 EXPECT_TRUE(tree.HasChild(9, 1)); 107 // Setting the parent of a node to its same parent should be a no-op. 108 EXPECT_EQ(1u, tree.GetParent(2)); 109 EXPECT_TRUE(tree.HasChild(1, 2)); 110 EXPECT_TRUE(tree.SetParent(2, 1, true)); 111 EXPECT_EQ(1u, tree.GetParent(2)); 112 EXPECT_TRUE(tree.HasChild(1, 2)); 113 114 ASSERT_TRUE(tree.ValidateInvariantsForTests()); 115} 116 117TEST(SpdyPriorityTreeTest, BlockAndUnblock) { 118 /* Create the tree. 119 120 0 121 /|\ 122 1 2 3 123 /| | \ 124 4 5 6 7 125 /| |\ \ |\ 126 8 91011121314 127 / \ 128 15 16 129 130 */ 131 SpdyPriorityTree<uint32> tree; 132 SpdyPriorityTreePeer<uint32> tree_peer(&tree); 133 tree.AddNode(1, 0, 100, false); 134 tree.AddNode(2, 0, 100, false); 135 tree.AddNode(3, 0, 100, false); 136 tree.AddNode(4, 1, 100, false); 137 tree.AddNode(5, 1, 100, false); 138 tree.AddNode(8, 4, 100, false); 139 tree.AddNode(9, 4, 100, false); 140 tree.AddNode(10, 5, 100, false); 141 tree.AddNode(11, 5, 100, false); 142 tree.AddNode(15, 8, 100, false); 143 tree.AddNode(16, 8, 100, false); 144 tree.AddNode(12, 2, 100, false); 145 tree.AddNode(6, 2, 100, true); 146 tree.AddNode(7, 0, 100, false); 147 tree.AddNode(13, 7, 100, true); 148 tree.AddNode(14, 7, 100, false); 149 tree.SetParent(7, 3, false); 150 EXPECT_EQ(0u, tree.GetParent(1)); 151 EXPECT_EQ(0u, tree.GetParent(2)); 152 EXPECT_EQ(0u, tree.GetParent(3)); 153 EXPECT_EQ(1u, tree.GetParent(4)); 154 EXPECT_EQ(1u, tree.GetParent(5)); 155 EXPECT_EQ(2u, tree.GetParent(6)); 156 EXPECT_EQ(3u, tree.GetParent(7)); 157 EXPECT_EQ(4u, tree.GetParent(8)); 158 EXPECT_EQ(4u, tree.GetParent(9)); 159 EXPECT_EQ(5u, tree.GetParent(10)); 160 EXPECT_EQ(5u, tree.GetParent(11)); 161 EXPECT_EQ(6u, tree.GetParent(12)); 162 EXPECT_EQ(7u, tree.GetParent(13)); 163 EXPECT_EQ(7u, tree.GetParent(14)); 164 EXPECT_EQ(8u, tree.GetParent(15)); 165 EXPECT_EQ(8u, tree.GetParent(16)); 166 ASSERT_TRUE(tree.ValidateInvariantsForTests()); 167 168 EXPECT_EQ(tree.FindNode(0)->total_child_weights, 169 tree.FindNode(1)->weight + 170 tree.FindNode(2)->weight + 171 tree.FindNode(3)->weight); 172 EXPECT_EQ(tree.FindNode(3)->total_child_weights, 173 tree.FindNode(7)->weight); 174 EXPECT_EQ(tree.FindNode(7)->total_child_weights, 175 tree.FindNode(13)->weight + tree.FindNode(14)->weight); 176 EXPECT_EQ(tree.FindNode(13)->total_child_weights, 0); 177 EXPECT_EQ(tree.FindNode(14)->total_child_weights, 0); 178 179 // Set all nodes ready to write. 180 EXPECT_TRUE(tree.SetReady(1, true)); 181 EXPECT_TRUE(tree.SetReady(2, true)); 182 EXPECT_TRUE(tree.SetReady(3, true)); 183 EXPECT_TRUE(tree.SetReady(4, true)); 184 EXPECT_TRUE(tree.SetReady(5, true)); 185 EXPECT_TRUE(tree.SetReady(6, true)); 186 EXPECT_TRUE(tree.SetReady(7, true)); 187 EXPECT_TRUE(tree.SetReady(8, true)); 188 EXPECT_TRUE(tree.SetReady(9, true)); 189 EXPECT_TRUE(tree.SetReady(10, true)); 190 EXPECT_TRUE(tree.SetReady(11, true)); 191 EXPECT_TRUE(tree.SetReady(12, true)); 192 EXPECT_TRUE(tree.SetReady(13, true)); 193 EXPECT_TRUE(tree.SetReady(14, true)); 194 EXPECT_TRUE(tree.SetReady(15, true)); 195 EXPECT_TRUE(tree.SetReady(16, true)); 196 197 // Number of readable child weights should not change because 198 // 7 has unblocked children. 199 tree.SetBlocked(7, true); 200 tree_peer.PropagateNodeState(kRootNodeId); 201 EXPECT_EQ(tree.FindNode(3)->total_child_weights, 202 tree.FindNode(3)->total_writeable_child_weights); 203 204 // Readable children for 7 should decrement. 205 // Number of readable child weights for 3 still should not change. 206 tree.SetBlocked(13, true); 207 tree_peer.PropagateNodeState(kRootNodeId); 208 EXPECT_EQ(tree.FindNode(3)->total_child_weights, 209 tree.FindNode(3)->total_writeable_child_weights); 210 EXPECT_EQ(tree.FindNode(14)->weight, 211 tree.FindNode(7)->total_writeable_child_weights); 212 213 // Once 14 becomes blocked, readable children for 7 and 3 should both be 214 // decremented. Total readable weights at the root should still be the same 215 // because 3 is still writeable. 216 tree.SetBlocked(14, true); 217 tree_peer.PropagateNodeState(kRootNodeId); 218 EXPECT_EQ(0, tree.FindNode(3)->total_writeable_child_weights); 219 EXPECT_EQ(0, tree.FindNode(7)->total_writeable_child_weights); 220 EXPECT_EQ(tree.FindNode(0)->total_child_weights, 221 tree.FindNode(1)->weight + 222 tree.FindNode(2)->weight + 223 tree.FindNode(3)->weight); 224 225 // And now the root should be decremented as well. 226 tree.SetBlocked(3, true); 227 tree_peer.PropagateNodeState(kRootNodeId); 228 EXPECT_EQ(tree.FindNode(1)->weight + tree.FindNode(2)->weight, 229 tree.FindNode(0)->total_writeable_child_weights); 230 231 // Unblocking 7 should propagate all the way up to the root. 232 tree.SetBlocked(7, false); 233 tree_peer.PropagateNodeState(kRootNodeId); 234 EXPECT_EQ(tree.FindNode(0)->total_writeable_child_weights, 235 tree.FindNode(1)->weight + 236 tree.FindNode(2)->weight + 237 tree.FindNode(3)->weight); 238 EXPECT_EQ(tree.FindNode(3)->total_writeable_child_weights, 239 tree.FindNode(7)->weight); 240 EXPECT_EQ(0, tree.FindNode(7)->total_writeable_child_weights); 241 242 // Ditto for reblocking 7. 243 tree.SetBlocked(7, true); 244 tree_peer.PropagateNodeState(kRootNodeId); 245 EXPECT_EQ(tree.FindNode(0)->total_writeable_child_weights, 246 tree.FindNode(1)->weight + tree.FindNode(2)->weight); 247 EXPECT_EQ(0, tree.FindNode(3)->total_writeable_child_weights); 248 EXPECT_EQ(0, tree.FindNode(7)->total_writeable_child_weights); 249 ASSERT_TRUE(tree.ValidateInvariantsForTests()); 250} 251 252TEST(SpdyPriorityTreeTest, GetPriorityList) { 253 typedef uint32 SpdyStreamId; 254 typedef std::pair<SpdyStreamId, float> PriorityNode; 255 typedef std::vector<PriorityNode> PriorityList; 256 257 PriorityList expected_list; 258 PriorityList priority_list; 259 260 /* Create the tree. 261 262 0 263 /|\ 264 1 2 3 265 /| |\ 266 4 5 6 7 267 / 268 8 269 270 */ 271 SpdyPriorityTree<uint32> tree; 272 tree.AddNode(1, 0, 10, false); 273 tree.AddNode(2, 0, 20, false); 274 tree.AddNode(3, 0, 30, false); 275 tree.AddNode(4, 1, 10, false); 276 tree.AddNode(5, 1, 90, false); 277 tree.AddNode(6, 2, 10, false); 278 tree.AddNode(7, 2, 10, false); 279 tree.AddNode(8, 4, 256, false); 280 281 // Set all nodes ready to write. 282 EXPECT_TRUE(tree.SetReady(1, true)); 283 EXPECT_TRUE(tree.SetReady(2, true)); 284 EXPECT_TRUE(tree.SetReady(3, true)); 285 EXPECT_TRUE(tree.SetReady(4, true)); 286 EXPECT_TRUE(tree.SetReady(5, true)); 287 EXPECT_TRUE(tree.SetReady(6, true)); 288 EXPECT_TRUE(tree.SetReady(7, true)); 289 EXPECT_TRUE(tree.SetReady(8, true)); 290 291 expected_list.push_back(PriorityNode(3, 1.0/2.0)); 292 expected_list.push_back(PriorityNode(2, 1.0/3.0)); 293 expected_list.push_back(PriorityNode(1, 1.0/6.0)); 294 priority_list = tree.GetPriorityList(); 295 EXPECT_EQ(expected_list, priority_list); 296 297 // Check that the list updates as expected when a node gets blocked. 298 EXPECT_TRUE(tree.SetReady(1, false)); 299 expected_list.clear(); 300 expected_list.push_back(PriorityNode(3, 1.0/2.0)); 301 expected_list.push_back(PriorityNode(2, 1.0/3.0)); 302 expected_list.push_back(PriorityNode(5, 0.9*1.0/6.0)); 303 expected_list.push_back(PriorityNode(4, 0.1*1.0/6.0)); 304 priority_list = tree.GetPriorityList(); 305 EXPECT_EQ(expected_list, priority_list); 306 307 // Block multiple levels of nodes. 308 EXPECT_TRUE(tree.SetReady(4, false)); 309 EXPECT_TRUE(tree.SetReady(5, false)); 310 expected_list.clear(); 311 expected_list.push_back(PriorityNode(3, 1.0/2.0)); 312 expected_list.push_back(PriorityNode(2, 1.0/3.0)); 313 expected_list.push_back(PriorityNode(8, 1.0/6.0)); 314 priority_list = tree.GetPriorityList(); 315 EXPECT_EQ(expected_list, priority_list); 316 317 // Remove a node from the tree to make sure priorities 318 // get redistributed accordingly. 319 EXPECT_TRUE(tree.RemoveNode(1)); 320 expected_list.clear(); 321 expected_list.push_back(PriorityNode(3, 30.0/51.0)); 322 expected_list.push_back(PriorityNode(2, 20.0/51.0)); 323 expected_list.push_back(PriorityNode(8, 1.0/51.0)); 324 priority_list = tree.GetPriorityList(); 325 EXPECT_EQ(expected_list, priority_list); 326 327 // Block an entire subtree. 328 EXPECT_TRUE(tree.SetReady(8, false)); 329 expected_list.clear(); 330 expected_list.push_back(PriorityNode(3, 0.6)); 331 expected_list.push_back(PriorityNode(2, 0.4)); 332 priority_list = tree.GetPriorityList(); 333 EXPECT_EQ(expected_list, priority_list); 334 335 // Unblock previously blocked nodes. 336 EXPECT_TRUE(tree.SetReady(4, true)); 337 EXPECT_TRUE(tree.SetReady(5, true)); 338 expected_list.clear(); 339 expected_list.push_back(PriorityNode(3, 1.0/2.0)); 340 expected_list.push_back(PriorityNode(2, 1.0/3.0)); 341 expected_list.push_back(PriorityNode(5, 9.0/60.0)); 342 expected_list.push_back(PriorityNode(4, 1.0/60.0)); 343 priority_list = tree.GetPriorityList(); 344 EXPECT_EQ(expected_list, priority_list); 345 346 // Blocked nodes in multiple subtrees. 347 EXPECT_TRUE(tree.SetReady(2, false)); 348 EXPECT_TRUE(tree.SetReady(6, false)); 349 EXPECT_TRUE(tree.SetReady(7, false)); 350 expected_list.clear(); 351 expected_list.push_back(PriorityNode(3, 3.0/4.0)); 352 expected_list.push_back(PriorityNode(5, 9.0/40.0)); 353 expected_list.push_back(PriorityNode(4, 1.0/40.0)); 354 priority_list = tree.GetPriorityList(); 355 EXPECT_EQ(expected_list, priority_list); 356} 357 358TEST(SpdyPriorityTreeTest, CalculateRoundedWeights) { 359 typedef uint32 SpdyStreamId; 360 typedef std::pair<SpdyStreamId, float> PriorityNode; 361 typedef std::vector<PriorityNode> PriorityList; 362 363 PriorityList expected_list; 364 PriorityList priority_list; 365 366 /* Create the tree. 367 368 0 369 / \ 370 1 2 371 //|\ |\ 372 83 4 5 6 7 373 */ 374 SpdyPriorityTree<uint32> tree; 375 tree.AddNode(3, 0, 100, false); 376 tree.AddNode(4, 0, 100, false); 377 tree.AddNode(5, 0, 100, false); 378 tree.AddNode(1, 0, 10, true); 379 tree.AddNode(2, 0, 5, false); 380 tree.AddNode(6, 2, 1, false); 381 tree.AddNode(7, 2, 1, false); 382 tree.AddNode(8, 1, 1, false); 383 384 // Remove higher-level nodes. 385 tree.RemoveNode(1); 386 tree.RemoveNode(2); 387 388 // 3.3 rounded down = 3. 389 EXPECT_EQ(3, tree.GetWeight(3)); 390 EXPECT_EQ(3, tree.GetWeight(4)); 391 EXPECT_EQ(3, tree.GetWeight(5)); 392 // 2.5 rounded up = 3. 393 EXPECT_EQ(3, tree.GetWeight(6)); 394 EXPECT_EQ(3, tree.GetWeight(7)); 395 // 0 is not a valid weight, so round up to 1. 396 EXPECT_EQ(1, tree.GetWeight(8)); 397} 398} // namespace test 399} // namespace gfe_spdy 400