1# Copyright 2016 The Chromium OS 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 cStringIO
6import json
7import mock
8import os
9import shutil
10import tempfile
11import unittest
12import urllib2
13
14import common
15
16from autotest_lib.site_utils import hwid_lib
17
18
19class HwIdUnittests(unittest.TestCase):
20    """Unittest for testing get_hwid_info."""
21
22    def setUp(self):
23        # Create tmp dir and dummy key files.
24        self.tmp_dir = tempfile.mkdtemp(prefix='hwid_test')
25        self.dummy_key = 'dummy_key'
26        self.dummy_key_file = os.path.join(self.tmp_dir, 'dummy_key')
27        with open(self.dummy_key_file, 'w') as f:
28            f.write(self.dummy_key)
29        self.dummy_key_file_spaces = os.path.join(self.tmp_dir,
30                                                  'dummy_key_spaces')
31        with open(self.dummy_key_file_spaces, 'w') as f:
32            f.write('  %s   ' % self.dummy_key)
33        self.dummy_key_file_newline = os.path.join(self.tmp_dir,
34                                                  'dummy_key_newline')
35        with open(self.dummy_key_file_newline, 'w') as f:
36            f.write('%s\n' % self.dummy_key)
37        self.invalid_dummy_key_file = os.path.join(self.tmp_dir,
38                                                   'invalid_dummy_key_file')
39
40
41    def tearDown(self):
42        mock.patch.stopall()
43        if os.path.exists(self.tmp_dir):
44            shutil.rmtree(self.tmp_dir)
45
46
47    def validate_exception(self, exception, *args):
48        """Helper method to validate proper exception is raised.
49
50        @param exception: The exception class to check against.
51        @param args: The unamed args to pass to func.
52        """
53        with self.assertRaises(exception):
54            hwid_lib.get_hwid_info(*args)
55
56
57    def test_none_hwid(self):
58        """Test that an empty hwid raises a ValueError."""
59        self.validate_exception(ValueError, None, None, None)
60
61
62    def test_invalid_info_type(self):
63        """Test that an invalid info type raises a ValueError."""
64        self.validate_exception(ValueError, 'hwid', 'invalid_info_type', None)
65
66
67    def test_fail_open_with_nonexistent_file(self):
68        """Test that trying to open non-existent file will raise an IOError."""
69        self.validate_exception(IOError, 'hwid', hwid_lib.HWID_INFO_BOM,
70                                self.invalid_dummy_key_file)
71
72
73    @mock.patch('urllib2.urlopen', side_effect=urllib2.URLError('url error'))
74    def test_fail_to_open_url_urlerror(self, *args, **dargs):
75        """Test that failing to open a url will raise a HwIdException."""
76        self.validate_exception(hwid_lib.HwIdException, 'hwid',
77                                hwid_lib.HWID_INFO_BOM, self.dummy_key_file)
78
79
80    # pylint: disable=missing-docstring
81    @mock.patch('urllib2.urlopen')
82    def test_fail_decode_hwid(self, mock_urlopen, *args, **dargs):
83        """Test that supplying bad json raises a HwIdException."""
84        mock_page_contents = mock.Mock(wraps=cStringIO.StringIO('bad json'))
85        mock_urlopen.return_value = mock_page_contents
86        self.validate_exception(hwid_lib.HwIdException, 'hwid',
87                                hwid_lib.HWID_INFO_BOM, self.dummy_key_file)
88        mock_page_contents.close.assert_called_once_with()
89
90
91    # pylint: disable=missing-docstring
92    @mock.patch('urllib2.urlopen')
93    def test_success(self, mock_urlopen, *args, **dargs):
94        """Test that get_hwid_info successfully returns a hwid dict.
95
96        We want to check that it works on all valid info types.
97        """
98        returned_json = '{"key1": "data1"}'
99        expected_dict = json.loads(returned_json)
100        for valid_info_type in hwid_lib.HWID_INFO_TYPES:
101            mock_page_contents = mock.Mock(
102                    wraps=cStringIO.StringIO(returned_json))
103            mock_urlopen.return_value = mock_page_contents
104            self.assertEqual(hwid_lib.get_hwid_info('hwid', valid_info_type,
105                                                    self.dummy_key_file),
106                             expected_dict)
107            mock_page_contents.close.assert_called_once_with()
108
109
110    # pylint: disable=missing-docstring
111    @mock.patch('urllib2.urlopen')
112    def test_url_properly_constructed(self, mock_urlopen, *args, **dargs):
113        """Test that the url is properly constructed.
114
115        Let's make sure that the key is properly cleaned before getting
116        inserted into the url by trying all the different dummy_key_files.
117        """
118        info_type = hwid_lib.HWID_INFO_BOM
119        hwid = 'mock_hwid'
120        expected_url = ('%s/%s/%s/%s/?key=%s' % (hwid_lib.HWID_BASE_URL,
121                                                 hwid_lib.HWID_VERSION,
122                                                 info_type, hwid,
123                                                 self.dummy_key))
124
125        for dummy_key_file in [self.dummy_key_file,
126                               self.dummy_key_file_spaces,
127                               self.dummy_key_file_newline]:
128            mock_page_contents = mock.Mock(wraps=cStringIO.StringIO('{}'))
129            mock_urlopen.return_value = mock_page_contents
130            hwid_lib.get_hwid_info(hwid, info_type, dummy_key_file)
131            mock_urlopen.assert_called_with(expected_url)
132
133
134    # pylint: disable=missing-docstring
135    @mock.patch('urllib2.urlopen')
136    def test_url_properly_constructed_again(self, mock_urlopen, *args, **dargs):
137        """Test that the url is properly constructed with special hwid.
138
139        Let's make sure that a hwid with a space is properly transformed.
140        """
141        info_type = hwid_lib.HWID_INFO_BOM
142        hwid = 'mock hwid with space'
143        hwid_quoted = 'mock%20hwid%20with%20space'
144        expected_url = ('%s/%s/%s/%s/?key=%s' % (hwid_lib.HWID_BASE_URL,
145                                                 hwid_lib.HWID_VERSION,
146                                                 info_type, hwid_quoted,
147                                                 self.dummy_key))
148
149        mock_page_contents = mock.Mock(wraps=cStringIO.StringIO('{}'))
150        mock_urlopen.return_value = mock_page_contents
151        hwid_lib.get_hwid_info(hwid, info_type, self.dummy_key_file)
152        mock_urlopen.assert_called_with(expected_url)
153
154
155    def test_dummy_key_file(self):
156        """Test that we get an empty dict with a dummy key file."""
157        info_type = hwid_lib.HWID_INFO_BOM
158        hwid = 'mock hwid with space'
159        key_file = hwid_lib.KEY_FILENAME_NO_HWID
160        self.assertEqual(hwid_lib.get_hwid_info(hwid, info_type, key_file), {})
161
162
163if __name__ == '__main__':
164    unittest.main()
165