1# Copyright 2016 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"""
6Cache temperature specifies how the browser cache should be configured before
7the page run.
8
9See design doc for details:
10https://docs.google.com/document/u/1/d/12D7tkhZi887g9d0U2askU9JypU_wYiEI7Lw0bfwxUgA
11"""
12
13import logging
14
15import py_utils
16
17# Default Cache Temperature. The page doesn't care which browser cache state
18# it is run on.
19ANY = 'any'
20# Emulates PageCycler V1 cold runs. Clears system DNS cache, browser DiskCache,
21# net/ predictor cache, and net/ host resolver cache.
22PCV1_COLD = 'pcv1-cold'
23# Emulates PageCycler V1 warm runs. Ensures that the page was visited at least
24# once just before the run.
25PCV1_WARM = 'pcv1-warm'
26
27class MarkTelemetryInternal(object):
28
29  def __init__(self, browser, identifier):
30    self.browser = browser
31    self.identifier = identifier
32
33  def __enter__(self):
34    marker = 'telemetry.internal.%s.start' % self.identifier
35    self.browser.tabs[0].ExecuteJavaScript(
36        "console.time({{ marker }});", marker=marker)
37    self.browser.tabs[0].ExecuteJavaScript(
38        "console.timeEnd({{ marker }});", marker=marker)
39    return self
40
41  def __exit__(self, exception_type, exception_value, traceback):
42    if exception_type:
43      return True
44
45    marker = 'telemetry.internal.%s.end' % self.identifier
46    self.browser.tabs[0].ExecuteJavaScript(
47        "console.time({{ marker }});", marker=marker)
48    self.browser.tabs[0].ExecuteJavaScript(
49        "console.timeEnd({{ marker }});", marker=marker)
50    return True
51
52def EnsurePageCacheTemperature(page, browser, previous_page=None):
53  temperature = page.cache_temperature
54  logging.info('PageCacheTemperature: %s', temperature)
55
56  if temperature == ANY:
57    return
58
59  if temperature == PCV1_COLD:
60    if previous_page is None:
61      with MarkTelemetryInternal(browser, 'ensure_diskcache'):
62        tab = browser.tabs[0]
63        tab.Navigate("http://does.not.exist")
64        tab.WaitForDocumentReadyStateToBeComplete()
65
66    any_tab = browser.tabs[0]
67    any_tab.ClearCache(force=True)
68  elif temperature == PCV1_WARM:
69    if (previous_page is not None and
70        previous_page.url == page.url and
71        (previous_page.cache_temperature == PCV1_COLD or
72            previous_page.cache_temperature == PCV1_WARM)):
73      if '#' in page.url:
74        # Navigate to inexistent URL to avoid in-page hash navigation.
75        # Note: Unlike PCv1, PCv2 iterates the same URL for different cache
76        #       configurations. This may issue blink in-page hash navigations,
77        #       which isn't intended here.
78        with MarkTelemetryInternal(browser, 'avoid_double_hash_navigation'):
79          tab = browser.tabs[0]
80          tab.Navigate("http://does.not.exist")
81          tab.WaitForDocumentReadyStateToBeComplete()
82      return
83
84    with MarkTelemetryInternal(browser, 'warmCache'):
85      tab = browser.tabs[0]
86      tab.Navigate(page.url)
87      py_utils.WaitFor(tab.HasReachedQuiescence, 60)
88      tab.WaitForDocumentReadyStateToBeComplete()
89      tab.Navigate("about:blank")
90      tab.WaitForDocumentReadyStateToBeComplete()
91