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
5import logging
6import os
7import unittest
8
9from telemetry.core import discover
10from telemetry.internal.browser import browser_credentials
11from telemetry import page
12from telemetry import story as story_module
13from telemetry.wpr import archive_info
14
15
16class StorySetSmokeTest(unittest.TestCase):
17
18  def setUp(self):
19    # Make sure the added failure message is appended to the default failure
20    # message.
21    self.longMessage = True
22
23  def GetAllStorySetClasses(self, story_sets_dir, top_level_dir):
24    # We can't test page sets that aren't directly constructible since we
25    # don't know what arguments to put for the constructor.
26    return discover.DiscoverClasses(story_sets_dir, top_level_dir,
27                                    story_module.StorySet,
28                                    directly_constructable=True).values()
29
30  def CheckArchive(self, story_set):
31    """Verify that all URLs of pages in story_set have an associated archive."""
32    # TODO: Eventually these should be fatal.
33    if not story_set.archive_data_file:
34      logging.warning('Skipping %s: no archive data file', story_set.file_path)
35      return
36
37    logging.info('Testing %s', story_set.file_path)
38
39    archive_data_file_path = os.path.join(story_set.base_dir,
40                                          story_set.archive_data_file)
41    self.assertTrue(os.path.exists(archive_data_file_path),
42                    msg='Archive data file not found for %s' %
43                    story_set.file_path)
44
45    wpr_archive_info = archive_info.WprArchiveInfo.FromFile(
46        archive_data_file_path, story_set.bucket)
47    for story in story_set.stories:
48      if isinstance(story, page.Page) and story.url.startswith('http'):
49        self.assertTrue(wpr_archive_info.WprFilePathForStory(story),
50                        msg='No archive found for %s in %s' % (
51                            story.url, story_set.archive_data_file))
52
53  def CheckCredentials(self, story_set):
54    """Verify that all pages in story_set use proper credentials"""
55    for story in story_set.stories:
56      if not isinstance(story, page.Page):
57        continue
58      credentials = browser_credentials.BrowserCredentials()
59      if story.credentials_path:
60        credentials.credentials_path = (
61            os.path.join(story.base_dir, story.credentials_path))
62      fail_message = ('page %s of %s has invalid credentials %s' %
63                      (story.url, story_set.file_path, story.credentials))
64      if story.credentials:
65        try:
66          self.assertTrue(credentials.CanLogin(story.credentials), fail_message)
67        except browser_credentials.CredentialsError:
68          self.fail(fail_message)
69
70  def CheckAttributes(self, story_set):
71    """Verify that story_set and its stories base attributes have the right
72       types.
73    """
74    self.CheckAttributesOfStorySetBasicAttributes(story_set)
75    for story in story_set.stories:
76      self.CheckAttributesOfStoryBasicAttributes(story)
77
78  def CheckAttributesOfStorySetBasicAttributes(self, story_set):
79    if story_set.base_dir is not None:
80      self.assertTrue(
81          isinstance(story_set.base_dir, str),
82          msg='story_set %\'s base_dir must have type string')
83
84    self.assertTrue(
85        isinstance(story_set.archive_data_file, str),
86        msg='story_set\'s archive_data_file path must have type string')
87
88  def CheckAttributesOfStoryBasicAttributes(self, story):
89    self.assertTrue(not hasattr(story, 'disabled'))
90    self.assertTrue(
91       isinstance(story.name, str),
92       msg='story %s \'s name field must have type string' % story.display_name)
93    self.assertTrue(
94       isinstance(story.labels, set),
95       msg='story %s \'s labels field must have type set' % story.display_name)
96    for l in story.labels:
97      self.assertTrue(
98         isinstance(l, str),
99         msg='label %s in story %s \'s labels must have type string'
100         % (str(l), story.display_name))
101    if not isinstance(story, page.Page):
102      return
103    self.assertTrue(
104       # We use basestring instead of str because story's URL can be string of
105       # unicode.
106       isinstance(story.url, basestring),
107       msg='page %s \'s url must have type string' % story.display_name)
108    self.assertTrue(
109        isinstance(story.startup_url, str),
110        msg=('page %s \'s startup_url field must have type string'
111            % story.display_name))
112    self.assertIsInstance(
113        story.make_javascript_deterministic, bool,
114        msg='page %s \'s make_javascript_deterministic must have type bool'
115            % story.display_name)
116
117  def CheckSharedStates(self, story_set):
118    if not story_set.allow_mixed_story_states:
119      shared_state_class = (
120          story_set.stories[0].shared_state_class)
121      for story in story_set:
122        self.assertIs(
123            shared_state_class,
124            story.shared_state_class,
125            msg='story %s\'s shared_state_class field is different '
126            'from other story\'s shared_state_class whereas '
127            'story set %s disallows having mixed states' %
128            (story, story_set))
129
130  def RunSmokeTest(self, story_sets_dir, top_level_dir):
131    """Run smoke test on all story sets in story_sets_dir.
132
133    Subclass of StorySetSmokeTest is supposed to call this in some test
134    method to run smoke test.
135    """
136    story_sets = self.GetAllStorySetClasses(story_sets_dir, top_level_dir)
137    for story_set_class in story_sets:
138      story_set = story_set_class()
139      logging.info('Testing %s', story_set.file_path)
140      self.CheckArchive(story_set)
141      self.CheckCredentials(story_set)
142      self.CheckAttributes(story_set)
143      self.CheckSharedStates(story_set)
144