1#!/usr/bin/python2.7
2#
3# Copyright 2017 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
7import copy
8import logging
9import unittest
10
11import common
12from autotest_lib.utils import labellib
13
14
15_nullhandler = logging.NullHandler()
16
17
18def setUpModule():
19    labellib.logger.addHandler(_nullhandler)
20
21
22def tearDownModule():
23    labellib.logger.removeHandler(_nullhandler)
24
25
26class KeyvalLabelTestCase(unittest.TestCase):
27    """Tests for basic KeyvalLabel functions."""
28
29    def test_parse_keyval_label(self):
30        got = labellib.parse_keyval_label('pool:suites')
31        self.assertEqual(got, labellib.KeyvalLabel('pool', 'suites'))
32
33    def test_parse_keyval_label_with_multiple_colons(self):
34        got = labellib.parse_keyval_label('pool:suites:penthouse')
35        self.assertEqual(got, labellib.KeyvalLabel('pool', 'suites:penthouse'))
36
37    def test_parse_keyval_label_raises(self):
38        with self.assertRaises(ValueError):
39            labellib.parse_keyval_label('webcam')
40
41    def test_format_keyval_label(self):
42        got = labellib.format_keyval_label(
43                labellib.KeyvalLabel('pool', 'suites'))
44        self.assertEqual(got, 'pool:suites')
45
46    def test_format_keyval_label_with_colon_in_value(self):
47        got = labellib.format_keyval_label(
48                labellib.KeyvalLabel('pool', 'suites:penthouse'))
49        self.assertEqual(got, 'pool:suites:penthouse')
50
51
52class LabelsMappingTestCase(unittest.TestCase):
53    """Tests for LabelsMapping class."""
54
55    def test_getlabels(self):
56        labels = ['webcam', 'pool:suites']
57        mapping = labellib.LabelsMapping(labels)
58        self.assertEqual(mapping.getlabels(), labels)
59
60    def test_init_and_getlabels_should_remove_duplicates(self):
61        labels = ['webcam', 'pool:suites', 'pool:party']
62        mapping = labellib.LabelsMapping(labels)
63        self.assertEqual(mapping.getlabels(), ['webcam', 'pool:suites'])
64
65    def test_init_and_getlabels_should_move_plain_labels_first(self):
66        labels = ['ohse:tsubame', 'webcam']
67        mapping = labellib.LabelsMapping(labels)
68        self.assertEqual(mapping.getlabels(), ['webcam', 'ohse:tsubame'])
69
70    def test_init_and_getlabels_should_preserve_plain_label_order(self):
71        labels = ['webcam', 'exec', 'method']
72        mapping = labellib.LabelsMapping(labels)
73        self.assertEqual(mapping.getlabels(), ['webcam', 'exec', 'method'])
74
75    def test_init_and_getlabels_should_preserve_keyval_label_order(self):
76        labels = ['class:protecta', 'method:metafalica', 'exec:chronicle_key']
77        mapping = labellib.LabelsMapping(labels)
78        self.assertEqual(mapping.getlabels(), labels)
79
80    def test_init_should_not_mutate_labels(self):
81        labels = ['class:protecta', 'exec:chronicle_key', 'method:metafalica']
82        input_labels = copy.deepcopy(labels)
83        mapping = labellib.LabelsMapping(input_labels)
84        mapping['class'] = 'distllista'
85        self.assertEqual(input_labels, labels)
86
87    def test_init_mutated_arg_should_not_affect_mapping(self):
88        labels = ['class:protecta', 'exec:chronicle_key', 'method:metafalica']
89        mapping = labellib.LabelsMapping(labels)
90        original_mapping = copy.deepcopy(mapping)
91        labels.pop()
92        self.assertEqual(mapping, original_mapping)
93
94    def test_duplicate_keys_should_take_first(self):
95        labels = ['webcam', 'pool:party', 'pool:suites']
96        mapping = labellib.LabelsMapping(labels)
97        self.assertEqual(mapping['pool'], 'party')
98
99    def test_getitem(self):
100        labels = ['webcam', 'pool:suites']
101        mapping = labellib.LabelsMapping(labels)
102        self.assertEqual(mapping['pool'], 'suites')
103
104    def test_in(self):
105        labels = ['webcam', 'pool:suites']
106        mapping = labellib.LabelsMapping(labels)
107        self.assertIn('pool', mapping)
108
109    def test_setitem(self):
110        labels = ['webcam']
111        mapping = labellib.LabelsMapping(labels)
112        mapping['pool'] = 'suites'
113        self.assertEqual(mapping['pool'], 'suites')
114
115    def test_setitem_to_none_should_delete(self):
116        labels = ['webcam', 'pool:suites']
117        mapping = labellib.LabelsMapping(labels)
118        mapping['pool'] = None
119        self.assertNotIn('pool', mapping)
120
121    def test_setitem_to_none_with_missing_key_should_noop(self):
122        labels = ['webcam', 'pool:suites']
123        mapping = labellib.LabelsMapping(labels)
124        mapping['foo'] = None
125        self.assertNotIn('foo', mapping)
126
127    def test_delitem(self):
128        labels = ['webcam', 'pool:suites']
129        mapping = labellib.LabelsMapping(labels)
130        del mapping['pool']
131        self.assertNotIn('pool', mapping)
132
133    def test_iter(self):
134        labels = ['webcam', 'pool:suites']
135        mapping = labellib.LabelsMapping(labels)
136        self.assertEqual(list(iter(mapping)), ['pool'])
137
138    def test_len(self):
139        labels = ['webcam', 'pool:suites']
140        mapping = labellib.LabelsMapping(labels)
141        self.assertEqual(len(mapping), 1)
142
143
144class CrosVersionTestCase(unittest.TestCase):
145    """Tests for CrosVersion functions."""
146
147    def test_parse_cros_version_without_rc(self):
148        got = labellib.parse_cros_version('lumpy-release/R27-3773.0.0')
149        self.assertEqual(got, labellib.CrosVersion('lumpy-release', 'lumpy',
150                                                   'R27', '3773.0.0', None))
151
152    def test_parse_cros_version_with_rc(self):
153        got = labellib.parse_cros_version('lumpy-release/R27-3773.0.0-rc1')
154        self.assertEqual(got, labellib.CrosVersion('lumpy-release', 'lumpy',
155                                                   'R27', '3773.0.0', 'rc1'))
156
157    def test_parse_cros_version_raises(self):
158        with self.assertRaises(ValueError):
159            labellib.parse_cros_version('foo')
160
161    def test_format_cros_version_without_rc(self):
162        got = labellib.format_cros_version(
163                labellib.CrosVersion('lumpy-release', 'lumpy', 'R27',
164                                     '3773.0.0', None))
165        self.assertEqual(got, 'lumpy-release/R27-3773.0.0')
166
167    def test_format_cros_version_with_rc(self):
168        got = labellib.format_cros_version(
169                labellib.CrosVersion('lumpy-release', 'lumpy',  'R27',
170                                     '3773.0.0', 'rc1'))
171        self.assertEqual(got, 'lumpy-release/R27-3773.0.0-rc1')
172
173    def test_parse_cros_version_for_board(self):
174        test_builds = ['lumpy-release/R27-3773.0.0-rc1',
175                       'trybot-lumpy-paladin/R27-3773.0.0',
176                       'lumpy-pre-cq/R27-3773.0.0-rc1',
177                       'lumpy-test-ap/R27-3773.0.0-rc1',
178                       'lumpy-toolchain/R27-3773.0.0-rc1',
179                       ]
180        for build in test_builds:
181            cros_version = labellib.parse_cros_version(build)
182            self.assertEqual(cros_version.board, 'lumpy')
183            self.assertEqual(cros_version.milestone, 'R27')
184
185        build = 'trybot-lumpy-a-pre-cq/R27-3773.0.0-rc1'
186        cros_version = labellib.parse_cros_version(build)
187        self.assertEqual(cros_version.board, 'lumpy-a')
188        self.assertEqual(cros_version.milestone, 'R27')
189
190        build = 'trybot-lumpy_a-pre-cq/R27-3773.0.0-rc1'
191        cros_version = labellib.parse_cros_version(build)
192        self.assertEqual(cros_version.board, 'lumpy_a')
193        self.assertEqual(cros_version.milestone, 'R27')
194
195
196if __name__ == '__main__':
197    unittest.main()
198