Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import os | 5 import os |
| 6 import sys | 6 import sys |
| 7 import unittest | 7 import unittest |
| 8 | 8 |
| 9 import dag | 9 import dag |
| 10 import loading_model | 10 import loading_model |
| 11 import log_parser | 11 import loading_trace |
| 12 import request_track | |
| 13 | |
| 14 class SimpleLens(object): | |
|
Benoit L
2016/01/21 09:09:26
nit: 2 lines between top-level declarations.
mattcary
2016/01/21 10:04:22
Done.
| |
| 15 def __init__(self, trace): | |
| 16 self._trace = trace | |
| 17 | |
| 18 def GetRequestDependencies(self): | |
| 19 url_to_rq = {} | |
| 20 deps = [] | |
| 21 for rq in self._trace.request_track.GetEvents(): | |
| 22 assert rq.url not in url_to_rq | |
| 23 url_to_rq[rq.url] = rq | |
| 24 for rq in self._trace.request_track.GetEvents(): | |
| 25 if rq.initiator in url_to_rq: | |
| 26 deps.append((rq, url_to_rq[rq.initiator], '')) | |
| 27 return deps | |
| 28 | |
| 29 | |
| 30 class MockRequestTrack(object): | |
| 31 def __init__(self, requests): | |
| 32 self._requests = requests | |
| 33 | |
| 34 def GetEvents(self): | |
| 35 return self._requests | |
| 36 | |
| 12 | 37 |
| 13 class LoadingModelTestCase(unittest.TestCase): | 38 class LoadingModelTestCase(unittest.TestCase): |
| 14 | 39 |
| 40 def setUp(self): | |
| 41 loading_model.ResourceGraph.REQUEST_LENS = SimpleLens | |
| 42 self._next_request_id = 0 | |
| 43 | |
| 15 def MakeParserRequest(self, url, source_url, start_time, end_time, | 44 def MakeParserRequest(self, url, source_url, start_time, end_time, |
| 16 magic_content_type=False): | 45 magic_content_type=False): |
| 17 timing_data = {f: -1 for f in log_parser.Timing._fields} | 46 rq = request_track.Request.FromJsonDict({ |
| 18 # We should ignore connectEnd. | 47 'request_id': self._next_request_id, |
| 19 timing_data['connectEnd'] = (end_time - start_time) / 2 | 48 'url': 'http://' + str(url), |
| 20 timing_data['receiveHeadersEnd'] = end_time - start_time | 49 'initiator': 'http://' + str(source_url), |
| 21 timing_data['requestTime'] = start_time / 1000.0 | 50 'response_headers': {'Content-Type': |
| 22 return log_parser.RequestData( | 51 'null' if not magic_content_type |
| 23 None, {'Content-Type': 'null' if not magic_content_type | 52 else 'magic-debug-content' }, |
| 24 else 'magic-debug-content' }, | 53 'timing': request_track.TimingFromDict({ |
| 25 None, start_time, timing_data, 'http://' + str(url), False, | 54 # connectEnd should be ignored. |
| 26 {'type': 'parser', 'url': 'http://' + str(source_url)}) | 55 'connectEnd': (end_time - start_time) / 2, |
| 56 'receiveHeadersEnd': end_time - start_time, | |
| 57 'requestTime': start_time / 1000.0}) | |
| 58 }) | |
| 59 | |
| 60 | |
|
Benoit L
2016/01/21 09:09:26
nit: extra blank line.
mattcary
2016/01/21 10:04:22
Done.
| |
| 61 self._next_request_id += 1 | |
| 62 return rq | |
| 63 | |
| 64 def MakeGraph(self, requests): | |
| 65 return loading_model.ResourceGraph(loading_trace.LoadingTrace( | |
| 66 None, None, None, MockRequestTrack(requests), None)) | |
| 27 | 67 |
| 28 def SortedIndicies(self, graph): | 68 def SortedIndicies(self, graph): |
| 29 return [n.Index() for n in dag.TopologicalSort(graph._nodes)] | 69 return [n.Index() for n in dag.TopologicalSort(graph._nodes)] |
| 30 | 70 |
| 31 def SuccessorIndicies(self, node): | 71 def SuccessorIndicies(self, node): |
| 32 return [c.Index() for c in node.SortedSuccessors()] | 72 return [c.Index() for c in node.SortedSuccessors()] |
| 33 | 73 |
| 34 def test_Costing(self): | 74 def test_Costing(self): |
| 35 requests = [self.MakeParserRequest(0, 'null', 100, 110), | 75 requests = [self.MakeParserRequest(0, 'null', 100, 110), |
| 36 self.MakeParserRequest(1, 0, 115, 120), | 76 self.MakeParserRequest(1, 0, 115, 120), |
| 37 self.MakeParserRequest(2, 0, 112, 120), | 77 self.MakeParserRequest(2, 0, 112, 120), |
| 38 self.MakeParserRequest(3, 1, 122, 126), | 78 self.MakeParserRequest(3, 1, 122, 126), |
| 39 self.MakeParserRequest(4, 3, 127, 128), | 79 self.MakeParserRequest(4, 3, 127, 128), |
| 40 self.MakeParserRequest(5, 'null', 100, 105), | 80 self.MakeParserRequest(5, 'null', 100, 105), |
| 41 self.MakeParserRequest(6, 5, 105, 110)] | 81 self.MakeParserRequest(6, 5, 105, 110)] |
| 42 graph = loading_model.ResourceGraph(requests) | 82 graph = self.MakeGraph(requests) |
| 43 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1, 2]) | 83 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1, 2]) |
| 44 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), [3]) | 84 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), [3]) |
| 45 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), []) | 85 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), []) |
| 46 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), [4]) | 86 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), [4]) |
| 47 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) | 87 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) |
| 48 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), [6]) | 88 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), [6]) |
| 49 self.assertEqual(self.SuccessorIndicies(graph._nodes[6]), []) | 89 self.assertEqual(self.SuccessorIndicies(graph._nodes[6]), []) |
| 50 self.assertEqual(self.SortedIndicies(graph), [0, 5, 1, 2, 6, 3, 4]) | 90 self.assertEqual(self.SortedIndicies(graph), [0, 5, 1, 2, 6, 3, 4]) |
| 51 self.assertEqual(28, graph.Cost()) | 91 self.assertEqual(28, graph.Cost()) |
| 52 graph.Set(cache_all=True) | 92 graph.Set(cache_all=True) |
| 53 self.assertEqual(8, graph.Cost()) | 93 self.assertEqual(8, graph.Cost()) |
| 54 | 94 |
| 55 def test_MaxPath(self): | 95 def test_MaxPath(self): |
| 56 requests = [self.MakeParserRequest(0, 'null', 100, 110), | 96 requests = [self.MakeParserRequest(0, 'null', 100, 110), |
| 57 self.MakeParserRequest(1, 0, 115, 120), | 97 self.MakeParserRequest(1, 0, 115, 120), |
| 58 self.MakeParserRequest(2, 0, 112, 120), | 98 self.MakeParserRequest(2, 0, 112, 120), |
| 59 self.MakeParserRequest(3, 1, 122, 126), | 99 self.MakeParserRequest(3, 1, 122, 126), |
| 60 self.MakeParserRequest(4, 3, 127, 128), | 100 self.MakeParserRequest(4, 3, 127, 128), |
| 61 self.MakeParserRequest(5, 'null', 100, 105), | 101 self.MakeParserRequest(5, 'null', 100, 105), |
| 62 self.MakeParserRequest(6, 5, 105, 110)] | 102 self.MakeParserRequest(6, 5, 105, 110)] |
| 63 graph = loading_model.ResourceGraph(requests) | 103 graph = self.MakeGraph(requests) |
| 64 path_list = [] | 104 path_list = [] |
| 65 self.assertEqual(28, graph.Cost(path_list)) | 105 self.assertEqual(28, graph.Cost(path_list)) |
| 66 self.assertEqual([0, 1, 3, 4], [n.Index() for n in path_list]) | 106 self.assertEqual([0, 1, 3, 4], [n.Index() for n in path_list]) |
| 67 | 107 |
| 68 # More interesting would be a test when a node has multiple predecessors, | 108 # More interesting would be a test when a node has multiple predecessors, |
| 69 # but it's not possible for us to construct such a graph from requests yet. | 109 # but it's not possible for us to construct such a graph from requests yet. |
| 70 | 110 |
| 71 def test_TimingSplit(self): | 111 def test_TimingSplit(self): |
| 72 # Timing adds node 1 as a parent to 2 but not 3. | 112 # Timing adds node 1 as a parent to 2 but not 3. |
| 73 requests = [self.MakeParserRequest(0, 'null', 100, 110, | 113 requests = [self.MakeParserRequest(0, 'null', 100, 110, |
| 74 magic_content_type=True), | 114 magic_content_type=True), |
| 75 self.MakeParserRequest(1, 0, 115, 120, | 115 self.MakeParserRequest(1, 0, 115, 120, |
| 76 magic_content_type=True), | 116 magic_content_type=True), |
| 77 self.MakeParserRequest(2, 0, 121, 122, | 117 self.MakeParserRequest(2, 0, 121, 122, |
| 78 magic_content_type=True), | 118 magic_content_type=True), |
| 79 self.MakeParserRequest(3, 0, 112, 119), | 119 self.MakeParserRequest(3, 0, 112, 119, |
| 120 magic_content_type=True), | |
| 80 self.MakeParserRequest(4, 2, 122, 126), | 121 self.MakeParserRequest(4, 2, 122, 126), |
| 81 self.MakeParserRequest(5, 2, 122, 126)] | 122 self.MakeParserRequest(5, 2, 122, 126)] |
| 82 graph = loading_model.ResourceGraph(requests) | 123 graph = self.MakeGraph(requests) |
| 83 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1, 3]) | 124 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1, 3]) |
| 84 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), [2]) | 125 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), [2]) |
| 85 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), [4, 5]) | 126 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), [4, 5]) |
| 86 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), []) | 127 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), []) |
| 87 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) | 128 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) |
| 88 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), []) | 129 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), []) |
| 89 self.assertEqual(self.SortedIndicies(graph), [0, 1, 3, 2, 4, 5]) | 130 self.assertEqual(self.SortedIndicies(graph), [0, 1, 3, 2, 4, 5]) |
| 90 | 131 |
| 91 # Change node 1 so it is a parent of 3, which become parent of 2. | 132 # Change node 1 so it is a parent of 3, which becomes the parent of 2. |
| 92 requests[1] = self.MakeParserRequest(1, 0, 110, 111, | 133 requests[1] = self.MakeParserRequest(1, 0, 110, 111, |
| 93 magic_content_type=True) | 134 magic_content_type=True) |
| 94 graph = loading_model.ResourceGraph(requests) | 135 graph = self.MakeGraph(requests) |
| 95 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1]) | 136 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1]) |
| 96 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), [3]) | 137 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), [3]) |
| 97 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), [4, 5]) | 138 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), [4, 5]) |
| 98 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), [2]) | 139 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), [2]) |
| 99 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) | 140 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) |
| 100 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), []) | 141 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), []) |
| 101 self.assertEqual(self.SortedIndicies(graph), [0, 1, 3, 2, 4, 5]) | 142 self.assertEqual(self.SortedIndicies(graph), [0, 1, 3, 2, 4, 5]) |
| 102 | 143 |
| 103 # Add an initiator dependence to 1 that will become the parent of 3. | 144 # Add an initiator dependence to 1 that will become the parent of 3. |
| 104 requests[1] = self.MakeParserRequest(1, 0, 110, 111) | |
| 105 requests.append(self.MakeParserRequest(6, 1, 111, 112)) | |
| 106 graph = loading_model.ResourceGraph(requests) | |
| 107 # Check it doesn't change until we change the content type of 1. | |
| 108 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), [3, 6]) | |
| 109 requests[1] = self.MakeParserRequest(1, 0, 110, 111, | 145 requests[1] = self.MakeParserRequest(1, 0, 110, 111, |
| 110 magic_content_type=True) | 146 magic_content_type=True) |
| 111 graph = loading_model.ResourceGraph(requests) | 147 requests.append(self.MakeParserRequest(6, 1, 111, 112)) |
| 148 graph = self.MakeGraph(requests) | |
| 149 # Check it doesn't change until we change the content type of 6. | |
| 150 self.assertEqual(self.SuccessorIndicies(graph._nodes[6]), []) | |
| 151 requests[6] = self.MakeParserRequest(6, 1, 111, 112, | |
| 152 magic_content_type=True) | |
| 153 graph = self.MakeGraph(requests) | |
| 112 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1]) | 154 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1]) |
| 113 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), [6]) | 155 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), [6]) |
| 114 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), [4, 5]) | 156 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), [4, 5]) |
| 115 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), [2]) | 157 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), [2]) |
| 116 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) | 158 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) |
| 117 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), []) | 159 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), []) |
| 118 self.assertEqual(self.SuccessorIndicies(graph._nodes[6]), [3]) | 160 self.assertEqual(self.SuccessorIndicies(graph._nodes[6]), [3]) |
| 119 self.assertEqual(self.SortedIndicies(graph), [0, 1, 6, 3, 2, 4, 5]) | 161 self.assertEqual(self.SortedIndicies(graph), [0, 1, 6, 3, 2, 4, 5]) |
| 120 | 162 |
| 121 def test_TimingSplitImage(self): | 163 def test_TimingSplitImage(self): |
| 122 # If we're all image types, then we shouldn't split by timing. | 164 # If we're all image types, then we shouldn't split by timing. |
| 123 requests = [self.MakeParserRequest(0, 'null', 100, 110), | 165 requests = [self.MakeParserRequest(0, 'null', 100, 110), |
| 124 self.MakeParserRequest(1, 0, 115, 120), | 166 self.MakeParserRequest(1, 0, 115, 120), |
| 125 self.MakeParserRequest(2, 0, 121, 122), | 167 self.MakeParserRequest(2, 0, 121, 122), |
| 126 self.MakeParserRequest(3, 0, 112, 119), | 168 self.MakeParserRequest(3, 0, 112, 119), |
| 127 self.MakeParserRequest(4, 2, 122, 126), | 169 self.MakeParserRequest(4, 2, 122, 126), |
| 128 self.MakeParserRequest(5, 2, 122, 126)] | 170 self.MakeParserRequest(5, 2, 122, 126)] |
| 129 for r in requests: | 171 for r in requests: |
| 130 r.headers['Content-Type'] = 'image/gif' | 172 r.response_headers['Content-Type'] = 'image/gif' |
| 131 graph = loading_model.ResourceGraph(requests) | 173 graph = self.MakeGraph(requests) |
| 132 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1, 2, 3]) | 174 self.assertEqual(self.SuccessorIndicies(graph._nodes[0]), [1, 2, 3]) |
| 133 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), []) | 175 self.assertEqual(self.SuccessorIndicies(graph._nodes[1]), []) |
| 134 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), [4, 5]) | 176 self.assertEqual(self.SuccessorIndicies(graph._nodes[2]), [4, 5]) |
| 135 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), []) | 177 self.assertEqual(self.SuccessorIndicies(graph._nodes[3]), []) |
| 136 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) | 178 self.assertEqual(self.SuccessorIndicies(graph._nodes[4]), []) |
| 137 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), []) | 179 self.assertEqual(self.SuccessorIndicies(graph._nodes[5]), []) |
| 138 self.assertEqual(self.SortedIndicies(graph), [0, 1, 2, 3, 4, 5]) | 180 self.assertEqual(self.SortedIndicies(graph), [0, 1, 2, 3, 4, 5]) |
| 139 | 181 |
| 140 def test_AdUrl(self): | 182 def test_AdUrl(self): |
| 141 self.assertTrue(loading_model.ResourceGraph._IsAdUrl( | 183 self.assertTrue(loading_model.ResourceGraph._IsAdUrl( |
| 142 'http://afae61024b33032ef.profile.sfo20.cloudfront.net/test.png')) | 184 'http://afae61024b33032ef.profile.sfo20.cloudfront.net/test.png')) |
| 143 self.assertFalse(loading_model.ResourceGraph._IsAdUrl( | 185 self.assertFalse(loading_model.ResourceGraph._IsAdUrl( |
| 144 'http://afae61024b33032ef.profile.sfo20.cloudfront.net/tst.png')) | 186 'http://afae61024b33032ef.profile.sfo20.cloudfront.net/tst.png')) |
| 145 | 187 |
| 146 self.assertTrue(loading_model.ResourceGraph._IsAdUrl( | 188 self.assertTrue(loading_model.ResourceGraph._IsAdUrl( |
| 147 'http://ums.adtechus.com/mapuser?providerid=1003;' | 189 'http://ums.adtechus.com/mapuser?providerid=1003;' |
| 148 'userid=RUmecco4z3o====')) | 190 'userid=RUmecco4z3o====')) |
| 149 self.assertTrue(loading_model.ResourceGraph._IsAdUrl( | 191 self.assertTrue(loading_model.ResourceGraph._IsAdUrl( |
| 150 'http://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js')) | 192 'http://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js')) |
| 151 | 193 |
| 152 | 194 |
| 153 if __name__ == '__main__': | 195 if __name__ == '__main__': |
| 154 unittest.main() | 196 unittest.main() |
| OLD | NEW |