105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham# Copyright 2015 The Chromium OS Authors. All rights reserved.
205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham# Use of this source code is governed by a BSD-style license that can be
305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham# found in the LICENSE file.
405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunninghamimport json
605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunninghamimport logging
705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunninghamimport os
805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunninghamfrom autotest_lib.client.bin import utils
1005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunninghamfrom autotest_lib.client.common_lib import error
1105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunninghamfrom autotest_lib.client.common_lib.cros import chrome
1205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunninghamfrom autotest_lib.client.cros import cryptohome
1305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunninghamfrom autotest_lib.client.cros import enterprise_base
14d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunninghamfrom autotest_lib.client.cros import httpd
1505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
16c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott CunninghamCROSDEV_FLAGS = [
1705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    '--gaia-url=https://gaiastaging.corp.google.com',
1811f22dde2da61f8bc413b7a99d2bc7a300c2fe52Scott Cunningham    '--lso-url=https://gaiastaging.corp.google.com',
1905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    '--google-apis-url=https://www-googleapis-test.sandbox.google.com',
2005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    '--oauth2-client-id=236834563817.apps.googleusercontent.com',
2105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    '--oauth2-client-secret=RsKv5AwFKSzNgE0yjnurkPVI',
2205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    ('--cloud-print-url='
2305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham     'https://cloudprint-nightly-ps.sandbox.google.com/cloudprint'),
2405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    '--ignore-urlfetcher-cert-requests']
25c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott CunninghamCROSAUTO_FLAGS = [
26c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    ('--cloud-print-url='
27c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham     'https://cloudprint-nightly-ps.sandbox.google.com/cloudprint'),
28c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    '--ignore-urlfetcher-cert-requests']
29c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott CunninghamTESTDMS_FLAGS = [
3005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    '--ignore-urlfetcher-cert-requests',
3105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    '--enterprise-enrollment-skip-robot-auth',
3205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    '--disable-policy-key-verification']
33c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott CunninghamFLAGS_DICT = {
3405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    'prod': [],
35c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    'cr-dev': CROSDEV_FLAGS,
36c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    'cr-auto': CROSAUTO_FLAGS,
37c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    'dm-test': TESTDMS_FLAGS,
38c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    'dm-fake': TESTDMS_FLAGS
3905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham}
40c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott CunninghamDMS_URL_DICT = {
4105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    'prod': 'http://m.google.com/devicemanagement/data/api',
4205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    'cr-dev': 'https://cros-dev.sandbox.google.com/devicemanagement/data/api',
4305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    'cr-auto': 'https://cros-auto.sandbox.google.com/devicemanagement/data/api',
4405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    'dm-test': 'http://chromium-dm-test.appspot.com/d/%s',
4505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    'dm-fake': 'http://127.0.0.1:%d/'
4605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham}
47c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott CunninghamDMSERVER = '--device-management-url=%s'
4805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
4905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
5005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunninghamclass EnterprisePolicyTest(enterprise_base.EnterpriseTest):
5105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    """Base class for Enterprise Policy Tests."""
5205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
5305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    def setup(self):
5405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        os.chdir(self.srcdir)
5505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        utils.make()
5605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
571301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham    def initialize(self, args=()):
5805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self._initialize_test_context(args)
5905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
6005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        # Start AutoTest DM Server if using local fake server.
6105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if self.env == 'dm-fake':
6205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            self.import_dmserver(self.srcdir)
6305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            self.start_dmserver()
6405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self._initialize_chrome_extra_flags()
65d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        self._web_server = None
6605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
6705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    def cleanup(self):
6805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        # Clean up AutoTest DM Server if using local fake server.
6905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if self.env == 'dm-fake':
7005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            super(EnterprisePolicyTest, self).cleanup()
7105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
72d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        # Stop web server if it was started.
73d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        if self._web_server:
74d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham            self._web_server.stop()
75d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham
7605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        # Close Chrome instance if opened.
7705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if self.cr:
7805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            self.cr.close()
7905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
80d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham    def start_webserver(self, port):
81d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """Set up an HTTP Server to serve pages from localhost.
82d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham
83d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        @param port: Port used by HTTP server.
84d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham
851301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        """
86d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        if self.mode != 'list':
87d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham            self._web_server = httpd.HTTPListener(port, docroot=self.bindir)
88d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham            self._web_server.run()
89d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham
90d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham    def _initialize_test_context(self, args=()):
91d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """Initialize class-level test context parameters.
921301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
931301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        @raises error.TestError if an arg is given an invalid value or some
941301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                combination of args is given incompatible values.
951301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
961301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        """
9705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        # Extract local parameters from command line args.
9805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        args_dict = utils.args_to_dict(args)
9905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self.mode = args_dict.get('mode', 'all')
10005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self.case = args_dict.get('case')
10105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self.value = args_dict.get('value')
1021301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        self.env = args_dict.get('env', 'dm-fake')
10305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self.username = args_dict.get('username')
10405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self.password = args_dict.get('password')
10505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self.dms_name = args_dict.get('dms_name')
10605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
107c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        # If |mode| is 'list', set |env| to generic 'prod', and blank out
108c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        # the other key parameters: case, value.
109c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        if self.mode == 'list':
110c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            self.env = 'prod'
111c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            self.case = None
112c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            self.value = None
113c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
114c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        # If |case| is given then set |mode| to 'single'.
115c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        if self.case:
116c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            self.mode = 'single'
117c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
1181301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        # If |mode| is 'all', then |env| must be 'dm-fake', and
1191301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        # the |case| and |value| args must not be given.
1201301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        if self.mode == 'all':
1211301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            if self.env != 'dm-fake':
1221301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                raise error.TestError('env must be "dm-fake" '
1231301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                                      'when mode=all.')
1241301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            if self.case:
1251301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                raise error.TestError('case must not be given '
1261301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                                      'when mode=all.')
1271301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            if self.value:
1281301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                raise error.TestError('value must not be given '
1291301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                                      'when mode=all.')
1301301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
1318f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        # If |value| is given, set |is_value_given| flag to True. If it
1328f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        # was given as 'none', 'null', or '', then set |value| to 'null'.
1331301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        if self.value is not None:
1341301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            self.is_value_given = True
1358f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham            if (self.value.lower() == 'none' or
1368f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham                self.value.lower() == 'null' or
1378f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham                self.value == ''):
1388f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham                self.value = 'null'
1391301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        else:
1401301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            self.is_value_given = False
14105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
1421301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        # Verify |env| is a valid environment.
143c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        if self.env is not None and self.env not in FLAGS_DICT:
14405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            raise error.TestError('env=%s is invalid.' % self.env)
14505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
1461301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        # If |env| is 'dm-fake', ensure value and credentials are not given.
1471301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        if self.env == 'dm-fake':
1481301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            if self.is_value_given:
1491301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                raise error.TestError('value must not be given when using '
1501301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                                      'the fake DM Server.')
1511301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            if self.username or self.password:
1521301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                raise error.TestError('user credentials must not be given '
1531301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                                      'when using the fake DM Server.')
1541301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
1551301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        # If either credential is not given, set both to default.
1561301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        if self.username is None or self.password is None:
1571301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            self.username = self.USERNAME
1581301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            self.password = self.PASSWORD
1591301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
160c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        # Verify |case| is given if |mode|==single.
1611301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        if self.mode == 'single' and not self.case:
1621301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            raise error.TestError('case must be given when mode is single.')
1631301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
1641301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        # Verify |case| is given if a |value| is given.
1651301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        if self.is_value_given and self.case is None:
1661301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            raise error.TestError('value must not be given without also '
1671301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                                  'giving a test case.')
16805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
16905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        # Verify |dms_name| is given iff |env|==dm-test.
17005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if self.env == 'dm-test' and not self.dms_name:
17105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            raise error.TestError('dms_name must be given when using '
17205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham                                  'env=dm-test.')
17305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if self.env != 'dm-test' and self.dms_name:
17405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            raise error.TestError('dms_name must not be given when not using '
17505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham                                  'env=dm-test.')
17605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
17705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        # Log the test context parameters.
17805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('Test Context Parameters:')
17905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('  Run Mode: %r', self.mode)
18005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('  Test Case: %r', self.case)
1811301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        logging.info('  Expected Value: %r', self.value)
18205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('  Environment: %r', self.env)
18305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('  Username: %r', self.username)
18405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('  Password: %r', self.password)
18505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('  Test DMS Name: %r', self.dms_name)
18605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
18705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    def _initialize_chrome_extra_flags(self):
188d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """Initialize flags used to create Chrome instance."""
18905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        # Construct DM Server URL flags.
19005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        env_flag_list = []
19105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if self.env != 'prod':
19205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            if self.env == 'dm-fake':
19305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham                # Use URL provided by AutoTest DM server.
194c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                dmserver_str = (DMSERVER % self.dm_server_url)
19505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            else:
19605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham                # Use URL defined in DMS URL dictionary.
197c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                dmserver_str = (DMSERVER % (DMS_URL_DICT[self.env]))
19805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham                if self.env == 'dm-test':
19905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham                    dmserver_str = (dmserver_str % self.dms_name)
20005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
20105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            # Merge with other flags needed by non-prod enviornment.
202c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            env_flag_list = ([dmserver_str] + FLAGS_DICT[self.env])
20305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
20405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self.extra_flags = env_flag_list
20505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self.cr = None
20605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
2071301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham    def setup_case(self, policy_name, policy_value, policies_json):
208c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        """Set up and confirm the preconditions of a test case.
209c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
210c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        If the AutoTest fake DM Server is initialized, make a policy blob
211c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        from |policies_json|, and upload it to the fake server.
2121301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
213c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        Launch a chrome browser, and sign in to Chrome OS. Examine the user's
214c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        cryptohome vault, to confirm it signed in successfully.
215c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
216c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        Open the Policies page, and confirm that it shows the specified
217c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        |policy_name| and has the correct |policy_value|.
21805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
21905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        @param policy_name: Name of the policy under test.
2201301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        @param policy_value: Expected value to appear on chrome://policy page.
2211301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        @param policies_json: JSON string to set up the fake DMS policy value.
2221301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
2231301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        @raises error.TestError if cryptohome vault is not mounted for user.
2241301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        @raises error.TestFail if |policy_name| and |policy_value| are not
2251301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                shown on the Policies page.
2261301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
22705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        """
2281301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        # Set up policy on AutoTest DM Server only if initialized.
22905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if self.env == 'dm-fake':
230c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            self.setup_policy(self._make_json_blob(policies_json))
231c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
232c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        self._launch_chrome_browser()
233c876b9937f5967e19395d969a379b6d1b8bae443Scott Cunningham        tab = self.navigate_to_url('chrome://policy')
234c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        if not cryptohome.is_vault_mounted(user=self.username,
235c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                                           allow_fail=True):
236c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            raise error.TestError('Expected to find a mounted vault for %s.'
237c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                                  % self.username)
238c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        value_shown = self._get_policy_value_shown(tab, policy_name)
239c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        if not self._policy_value_matches_shown(policy_value, value_shown):
240c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            raise error.TestFail('Policy value shown is not correct: %s '
241c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                                 '(expected: %s)' %
242c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                                 (value_shown, policy_value))
243c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        tab.Close()
24405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
245c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    def _launch_chrome_browser(self):
246c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        """Launch Chrome browser and sign in."""
24705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('Chrome Browser Arguments:')
24805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('  extra_browser_args: %s', self.extra_flags)
24905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('  username: %s', self.username)
25005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        logging.info('  password: %s', self.password)
25105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
25205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        self.cr = chrome.Chrome(extra_browser_args=self.extra_flags,
2531301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                                username=self.username,
2541301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                                password=self.password,
25505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham                                gaia_login=True,
25605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham                                disable_gaia_services=False,
2571301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham                                autotest_ext=True)
25805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
259c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    def navigate_to_url(self, url, tab=None):
260c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        """Navigate tab to the specified |url|. Create new tab if none given.
26105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
262c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @param url: URL of web page to load.
263c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @param tab: browser tab to load (if any).
264c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @returns: browser tab loaded with web page.
26505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
266c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        """
267c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        logging.info('Navigating to URL: %r', url)
268c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        if not tab:
269c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            tab = self.cr.browser.tabs.New()
270c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            tab.Activate()
271c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        tab.Navigate(url, timeout=5)
272c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        tab.WaitForDocumentReadyStateToBeComplete()
273c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        return tab
274c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
275c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    def _policy_value_matches_shown(self, policy_value, value_shown):
276c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        """Compare |policy_value| to |value_shown| with whitespace removed.
277c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
278c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        Compare the expected policy value with the value actually shown on the
2798f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        chrome://policies page. Before comparing, convert both values to JSON
2808f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        formatted strings, and remove all whitespace. Whitespace is removed
2818f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        because Chrome processes some policy values to show them in a more
2828f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        human readable format.
283c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
284c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @param policy_value: Expected value to appear on chrome://policy page.
285c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @param value_shown: Value as it appears on chrome://policy page.
286c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @param policies_json: JSON string to set up the fake DMS policy value.
28705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
288c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @returns: True if the strings match after removing all whitespace.
28905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
290c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        """
2918f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        # Convert Python None or '' to JSON formatted 'null' string.
2928f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        if value_shown is None or value_shown == '':
2938f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham            value_shown = 'null'
2948f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        if policy_value is None or policy_value == '':
2958f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham            policy_value = 'null'
2968f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham
2978f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        # Remove whitespace.
2988f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        trimmed_value = ''.join(policy_value.split())
2998f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        trimmed_shown = ''.join(value_shown.split())
3008f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        logging.info('Trimmed policy value shown: %r (expected: %r)',
3018f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham                     trimmed_shown, trimmed_value)
302c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        return trimmed_value == trimmed_shown
3031301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
304c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    def _make_json_blob(self, policies_json):
305c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        """Create policy blob from policies JSON object.
306c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
307c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @param policies_json: Policies JSON object (name-value pairs).
308c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @returns: Policy blob to be used to setup the policy server.
30905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
31005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        """
3111301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        policies_json = self._move_modeless_to_mandatory(policies_json)
3121301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        policies_json = self._remove_null_policies(policies_json)
31305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
31405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        policy_blob = """{
31505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            "google/chromeos/user": %s,
31605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            "managed_users": ["*"],
31705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            "policy_user": "%s",
31805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            "current_key_index": 0,
31905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            "invalidation_source": 16,
32005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            "invalidation_name": "test_policy"
3211301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        }""" % (json.dumps(policies_json), self.USERNAME)
322c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        return policy_blob
32305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
3241301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham    def _move_modeless_to_mandatory(self, policies_json):
325d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """Add the 'mandatory' mode if a policy's mode was omitted.
32605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
32705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        The AutoTest fake DM Server requires that every policy be contained
32805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        within either a 'mandatory' or 'recommended' dictionary, to indicate
329d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        the mode of the policy. This function moves modeless policies into
330d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        the 'mandatory' dictionary.
33105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
3321301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        @param policies_json: The policy JSON data (name-value pairs).
33305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        @returns: dict of policies grouped by mode keys.
3341301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
33505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        """
33605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        mandatory_policies = {}
33705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        recommended_policies = {}
33805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        collated_json = {}
33905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
3408f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        # Extract mandatory and recommended mode dicts.
3411301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        if 'mandatory' in policies_json:
3421301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            mandatory_policies = policies_json['mandatory']
3431301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            del policies_json['mandatory']
3441301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        if 'recommended' in policies_json:
3451301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            recommended_policies = policies_json['recommended']
3461301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            del policies_json['recommended']
34705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
3488f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        # Move any remaining modeless policies into mandatory dict.
3491301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        if policies_json:
3501301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham            mandatory_policies.update(policies_json)
35105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
35205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        # Collate all policies into mandatory & recommended dicts.
35305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if recommended_policies:
35405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            collated_json.update({'recommended': recommended_policies})
35505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if mandatory_policies:
35605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            collated_json.update({'mandatory': mandatory_policies})
35705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
35805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        return collated_json
35905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
3601301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham    def _remove_null_policies(self, policies_json):
361d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """Remove policy dict data that is set to None or ''.
36205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
36305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        For the status of a policy to be shown as "Not set" on the
36405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        chrome://policy page, the policy blob must contain no dictionary entry
36505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        for that policy. This function removes policy NVPs from a copy of the
366d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        |policies_json| dictionary that the test case had set to None or ''.
36705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
3681301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        @param policies_json: setup policy JSON data (name-value pairs).
36905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        @returns: setup policy JSON data with all 'Not set' policies removed.
3701301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
37105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        """
3721301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        policies_json_copy = policies_json.copy()
373d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        for policies in policies_json_copy.values():
37405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            for policy_data in policies.items():
3758f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham                if policy_data[1] is None or policy_data[1] == '':
37605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham                    policies.pop(policy_data[0])
3771301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham        return policies_json_copy
37805a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
37905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham    def _get_policy_value_shown(self, policy_tab, policy_name):
380d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """Get the value shown for the named policy on the Policies page.
38105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
38205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        Takes |policy_name| as a parameter and returns the corresponding
38305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        policy value shown on the chrome://policy page.
38405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
38505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        @param policy_tab: Tab displaying the chrome://policy page.
38605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        @param policy_name: The name of the policy.
38705a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        @returns: The value shown for the policy on the Policies page.
3881301b11f7bb5a2dd011e34706e0857e2046258bcScott Cunningham
38905a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        """
39005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        row_values = policy_tab.EvaluateJavaScript('''
391c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            var section = document.getElementsByClassName("policy-table-section")[0];
392c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            var table = section.getElementsByTagName('table')[0];
393c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            rowValues = '';
394c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            for (var i = 1, row; row = table.rows[i]; i++) {
395c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham               if (row.className !== 'expanded-value-container') {
396c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                  var name_div = row.getElementsByClassName('name elide')[0];
397c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                  var name = name_div.textContent;
398c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                  if (name === '%s') {
399c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                     var value_span = row.getElementsByClassName('value')[0];
400c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                     var value = value_span.textContent;
401c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                     var status_div = row.getElementsByClassName('status elide')[0];
402c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                     var status = status_div.textContent;
403c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                     rowValues = [name, value, status];
404c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                     break;
405c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                  }
406c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham               }
407c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            }
408c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            rowValues;
409c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        ''' % policy_name)
41005a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
41105a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        value_shown = row_values[1].encode('ascii', 'ignore')
41205a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        status_shown = row_values[2].encode('ascii', 'ignore')
41305a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        if status_shown == 'Not set.':
41405a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham            return None
41505a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham        return value_shown
41605a5c9b729ef43cd345e2a9dfc9d2ab49399c69fScott Cunningham
417c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham    def get_elements_from_page(self, tab, cmd):
418c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        """Get collection of page elements that match the |cmd| filter.
419c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
420c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @param tab: tab containing the page to be scraped.
421c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @param cmd: JavaScript command to evaluate on the page.
422c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @returns object containing elements on page that match the cmd.
423c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        @raises: TestFail if matching elements are not found on the page.
424c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
425c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        """
426c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        try:
427c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            elements = tab.EvaluateJavaScript(cmd)
428c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        except Exception as err:
429c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham            raise error.TestFail('Unable to find matching elements on '
430c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham                                 'the test page: %s\n %r' %(tab.url, err))
431c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham        return elements
432c31421ed37fb70be86c54dbf90cbf67161dfc4eeScott Cunningham
4338f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham    def json_string(self, policy_value):
4348f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham         """Convert policy value to a JSON formatted string.
4358f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham
4368f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham         @param policy_value: object containing a policy value.
4378f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham         @returns: string in JSON format.
4388f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham         """
4398f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham         return json.dumps(policy_value)
4408f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham
441d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham    def _validate_and_run_test_case(self, test_case, run_test):
442d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """Validate test case and call the test runner in the test class.
443d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham
444d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        @param test_case: name of the test case to run.
445d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        @param run_test: method in test class that runs a test case.
446d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham
447d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """
448d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        if test_case not in self.TEST_CASES:
449d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham            raise error.TestError('Test case is not valid: %s' % test_case)
450d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        logging.info('Running test case: %s', test_case)
451d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        run_test(test_case)
452d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham
453d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham    def run_once_impl(self, run_test):
454d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """Dispatch the common run modes for all child test classes.
455d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham
456d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        @param run_test: method in test class that runs a test case.
457d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham
458d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        """
459d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        if self.mode == 'all':
460d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham            for test_case in sorted(self.TEST_CASES):
461d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham                self._validate_and_run_test_case(test_case, run_test)
462d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        elif self.mode == 'single':
463d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham            self._validate_and_run_test_case(self.case, run_test)
464d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        elif self.mode == 'list':
465d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham            logging.info('List Test Cases:')
466d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham            for test_case, value in sorted(self.TEST_CASES.items()):
467d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham                logging.info('  case=%s, value="%s"', test_case, value)
468d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham        else:
469d07ace98b0bab4cac0a134cb7f808b7af4539ad2Scott Cunningham            raise error.TestError('Run mode is not valid: %s' % self.mode)
4708f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham
4718f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham    def run_once(self):
4728f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        # The run_once() method is core to all autotest tests. We define it
4738f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        # herein to support tests that do not define their own override.
4748f9a120954621a1e1830d79602df250fc7cd3fc3Scott Cunningham        self.run_once_impl(self.run_test_case)
475