Home | History | Annotate | Download | only in cros
      1 #!/usr/bin/python
      2 # -*- coding: utf-8 -*-
      3 # Copyright 2018 The Chromium OS Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 """Tests for gs_cache_client."""
      8 
      9 from __future__ import absolute_import
     10 from __future__ import division
     11 from __future__ import print_function
     12 
     13 import itertools
     14 import json
     15 import requests
     16 import unittest
     17 
     18 import mock
     19 
     20 import common
     21 from autotest_lib.client.common_lib import error
     22 from autotest_lib.client.common_lib.cros import gs_cache_client
     23 
     24 
     25 # pylint: disable=unused-argument
     26 class ApiTest(unittest.TestCase):
     27     """Test class for _GsCacheAPI."""
     28     def setUp(self):
     29         self.api = gs_cache_client._GsCacheAPI('localhost')
     30 
     31     def test_extract_via_ssh(self):
     32         """Test extracting via ssh."""
     33         gs_cache_client._USE_SSH_CONNECTION = True
     34         self.api._is_in_restricted_subnet = True
     35         with mock.patch('autotest_lib.client.common_lib.utils.run') as m:
     36             m.return_value.stdout = '{}'
     37             result = self.api.extract(
     38                     gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET, 'archive',
     39                     'file')
     40             self.assertEqual(result, {})
     41 
     42     def test_extract_via_http(self):
     43         """Test extracting via http."""
     44         with mock.patch('requests.get') as m:
     45             m.return_value = mock.MagicMock(ok=True, content='{}')
     46             result = self.api.extract(
     47                     gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET, 'archive',
     48                     'file')
     49             self.assertEqual(result, {})
     50 
     51     def test_extract_many_files_via_http(self):
     52         """Test extracting many files via http."""
     53         with mock.patch('requests.get') as m:
     54             m.return_value = mock.MagicMock(ok=True, content='{}')
     55             result = self.api.extract(
     56                     gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET, 'archive',
     57                     ['the_file'] * 1000)
     58             self.assertEqual(result, {})
     59             self.assertTrue(m.call_count > 1)
     60 
     61     @mock.patch('time.sleep')
     62     @mock.patch('time.time', side_effect=itertools.cycle([0, 400]))
     63     def test_extract_via_ssh_has_error(self, *args):
     64         """Test extracting via ssh when has errors."""
     65         gs_cache_client._USE_SSH_CONNECTION = True
     66         self.api._is_in_restricted_subnet = True
     67         with mock.patch('autotest_lib.client.common_lib.utils.run') as m:
     68             m.side_effect = error.CmdError('cmd', mock.MagicMock(exit_status=1))
     69             with self.assertRaises(gs_cache_client.CommunicationError):
     70                 self.api.extract(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
     71                                  'archive', 'file')
     72 
     73             m.side_effect = error.CmdError('cmd', mock.MagicMock(
     74                     exit_status=gs_cache_client._CURL_RC_CANNOT_CONNECT_TO_HOST)
     75             )
     76             with self.assertRaises(gs_cache_client.NoGsCacheServerError):
     77                 self.api.extract(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
     78                                  'archive', 'file')
     79 
     80             m.side_effect = None
     81             m.return_value.stdout = '...'
     82             with self.assertRaises(gs_cache_client.ResponseContentError):
     83                 self.api.extract(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
     84                                  'archive', 'file')
     85 
     86     @mock.patch('time.sleep')
     87     @mock.patch('time.time', side_effect=itertools.cycle([0, 400]))
     88     def test_extract_via_http_has_error(self, *args):
     89         """Test extracting via http when has errors."""
     90         with mock.patch('requests.get') as m:
     91             m.return_value = mock.MagicMock(ok=False)
     92             with self.assertRaises(gs_cache_client.CommunicationError):
     93                 self.api.extract(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
     94                                  'archive', 'file')
     95 
     96             m.return_value = mock.MagicMock(ok=True, content='...')
     97             with self.assertRaises(gs_cache_client.ResponseContentError):
     98                 self.api.extract(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
     99                                  'archive', 'file')
    100 
    101             m.side_effect = requests.ConnectionError('Gs Cache is not running.')
    102             with self.assertRaises(gs_cache_client.NoGsCacheServerError):
    103                 self.api.extract(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
    104                                  'archive', 'file')
    105 
    106 
    107 class ClientTest(unittest.TestCase):
    108     """Test class for GsCacheClient."""
    109     def setUp(self):
    110         self.api = mock.MagicMock(server_netloc='api_netloc')
    111         self.dev_server = mock.MagicMock()
    112         self.client = gs_cache_client.GsCacheClient(self.dev_server, self.api)
    113 
    114     def test_list_suite_controls_in_map(self):
    115         """Test list controls of a suite in map file."""
    116         build = 'release/build'
    117         suite = 'suite'
    118         control_files = ['suite_control', 'control.1']
    119 
    120         map_file_name = 'autotest/test_suites/suite_to_control_file_map'
    121         self.api.extract.return_value = {
    122                 map_file_name: json.dumps({suite: control_files})}
    123         self.client.list_suite_controls(build, suite)
    124 
    125         expected_calls = [
    126                 mock.call(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
    127                           build + '/test_suites.tar.bz2', [map_file_name]),
    128                 mock.call(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
    129                           build + '/control_files.tar',
    130                           ['autotest/' + c for c in control_files])
    131         ]
    132         self.assertListEqual(self.api.extract.call_args_list, expected_calls)
    133 
    134     def test_list_suite_controls_not_in_map(self):
    135         """Test list controls of a suite not in map file."""
    136         build = 'release/build'
    137         suite = 'suite'
    138         map_file_name = 'autotest/test_suites/suite_to_control_file_map'
    139 
    140         self.api.extract.return_value = {map_file_name: json.dumps({})}
    141         self.client.list_suite_controls(build, suite)
    142 
    143         expected_calls = [
    144                 mock.call(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
    145                           build + '/test_suites.tar.bz2', [map_file_name]),
    146                 mock.call(gs_cache_client._CROS_IMAGE_ARCHIVE_BUCKET,
    147                           build + '/control_files.tar',
    148                           ['*/control', '*/control.*'])
    149         ]
    150         self.assertListEqual(self.api.extract.call_args_list, expected_calls)
    151 
    152     def test_fall_back_to_dev_server(self):
    153         """Test falling back to calls of dev_server."""
    154         self.client._list_suite_controls = mock.MagicMock(
    155                 side_effect=gs_cache_client.CommunicationError()
    156         )
    157         self.client.list_suite_controls('build', 'suite')
    158         self.dev_server.list_suite_controls.assert_called()
    159 
    160     def test_fall_back_to_dev_server_on_content_error(self):
    161         """Test falling back to calls of dev_server on wrong content."""
    162         self.api.extract.return_value = {k: 'xx' for k in range(999)}
    163         self.client.list_suite_controls('build', 'suite')
    164         self.dev_server.list_suite_controls.assert_called()
    165 
    166 
    167 if __name__ == '__main__':
    168     unittest.main()
    169