1import os
2import unittest
3
4JSON_TYPE = None
5try:
6    import simplejson as json
7    assert json
8except ImportError:
9    import json
10    JSON_TYPE = 'json'
11else:
12    JSON_TYPE = 'simplejson'
13
14import mozharness.base.config as config
15from copy import deepcopy
16
17MH_DIR = os.path.dirname(os.path.dirname(__file__))
18
19
20class TestParseConfigFile(unittest.TestCase):
21    def _get_json_config(self, filename=os.path.join(MH_DIR, "configs", "test", "test.json"),
22                         output='dict'):
23        fh = open(filename)
24        contents = json.load(fh)
25        fh.close()
26        if 'output' == 'dict':
27            return dict(contents)
28        else:
29            return contents
30
31    def _get_python_config(self, filename=os.path.join(MH_DIR, "configs", "test", "test.py"),
32                           output='dict'):
33        global_dict = {}
34        local_dict = {}
35        execfile(filename, global_dict, local_dict)
36        return local_dict['config']
37
38    def test_json_config(self):
39        c = config.BaseConfig(initial_config_file='test/test.json')
40        content_dict = self._get_json_config()
41        for key in content_dict.keys():
42            self.assertEqual(content_dict[key], c._config[key])
43
44    def test_python_config(self):
45        c = config.BaseConfig(initial_config_file='test/test.py')
46        config_dict = self._get_python_config()
47        for key in config_dict.keys():
48            self.assertEqual(config_dict[key], c._config[key])
49
50    def test_illegal_config(self):
51        self.assertRaises(
52            IOError,
53            config.parse_config_file, "this_file_does_not_exist.py", search_path="yadda")
54
55    def test_illegal_suffix(self):
56        self.assertRaises(RuntimeError, config.parse_config_file, "test/test.illegal_suffix")
57
58    def test_malformed_json(self):
59        if JSON_TYPE == 'simplejson':
60            self.assertRaises(
61                json.decoder.JSONDecodeError,
62                config.parse_config_file, "test/test_malformed.json")
63        else:
64            self.assertRaises(ValueError, config.parse_config_file, "test/test_malformed.json")
65
66    def test_malformed_python(self):
67        self.assertRaises(SyntaxError, config.parse_config_file, "test/test_malformed.py")
68
69    def test_multiple_config_files_override_string(self):
70        c = config.BaseConfig(initial_config_file='test/test.py')
71        c.parse_args(['--cfg', 'test/test_override.py,test/test_override2.py'])
72        self.assertEqual(c._config['override_string'], 'yay')
73
74    def test_multiple_config_files_override_list(self):
75        c = config.BaseConfig(initial_config_file='test/test.py')
76        c.parse_args(['--cfg', 'test/test_override.py,test/test_override2.py'])
77        self.assertEqual(c._config['override_list'], ['yay', 'worked'])
78
79    def test_multiple_config_files_override_dict(self):
80        c = config.BaseConfig(initial_config_file='test/test.py')
81        c.parse_args(['--cfg', 'test/test_override.py,test/test_override2.py'])
82        self.assertEqual(c._config['override_dict'], {'yay': 'worked'})
83
84    def test_multiple_config_files_keep_string(self):
85        c = config.BaseConfig(initial_config_file='test/test.py')
86        c.parse_args(['--cfg', 'test/test_override.py,test/test_override2.py'])
87        self.assertEqual(c._config['keep_string'], "don't change me")
88
89    def test_optional_config_files_override_value(self):
90        c = config.BaseConfig(initial_config_file='test/test.py')
91        c.parse_args(['--cfg', 'test/test_override.py,test/test_override2.py',
92                      '--opt-cfg', 'test/test_optional.py'])
93        self.assertEqual(c._config['opt_override'], "new stuff")
94
95    def test_optional_config_files_missing_config(self):
96        c = config.BaseConfig(initial_config_file='test/test.py')
97        c.parse_args(['--cfg', 'test/test_override.py,test/test_override2.py',
98                      '--opt-cfg', 'test/test_optional.py,does_not_exist.py'])
99        self.assertEqual(c._config['opt_override'], "new stuff")
100
101    def test_optional_config_files_keep_string(self):
102        c = config.BaseConfig(initial_config_file='test/test.py')
103        c.parse_args(['--cfg', 'test/test_override.py,test/test_override2.py',
104                      '--opt-cfg', 'test/test_optional.py'])
105        self.assertEqual(c._config['keep_string'], "don't change me")
106
107
108class TestReadOnlyDict(unittest.TestCase):
109    control_dict = {
110        'b': '2',
111        'c': {'d': '4'},
112        'h': ['f', 'g'],
113        'e': ['f', 'g', {'turtles': ['turtle1']}],
114        'd': {
115            'turtles': ['turtle1']
116        }
117    }
118
119    def get_unlocked_ROD(self):
120        r = config.ReadOnlyDict(self.control_dict)
121        return r
122
123    def get_locked_ROD(self):
124        r = config.ReadOnlyDict(self.control_dict)
125        r.lock()
126        return r
127
128    def test_create_ROD(self):
129        r = self.get_unlocked_ROD()
130        self.assertEqual(r, self.control_dict,
131                         msg="can't transfer dict to ReadOnlyDict")
132
133    def test_pop_item(self):
134        r = self.get_unlocked_ROD()
135        r.popitem()
136        self.assertEqual(len(r), len(self.control_dict) - 1,
137                         msg="can't popitem() ReadOnlyDict when unlocked")
138
139    def test_pop(self):
140        r = self.get_unlocked_ROD()
141        r.pop('e')
142        self.assertEqual(len(r), len(self.control_dict) - 1,
143                         msg="can't pop() ReadOnlyDict when unlocked")
144
145    def test_set(self):
146        r = self.get_unlocked_ROD()
147        r['e'] = 'yarrr'
148        self.assertEqual(r['e'], 'yarrr',
149                         msg="can't set var in ReadOnlyDict when unlocked")
150
151    def test_del(self):
152        r = self.get_unlocked_ROD()
153        del r['e']
154        self.assertEqual(len(r), len(self.control_dict) - 1,
155                         msg="can't del in ReadOnlyDict when unlocked")
156
157    def test_clear(self):
158        r = self.get_unlocked_ROD()
159        r.clear()
160        self.assertEqual(r, {},
161                         msg="can't clear() ReadOnlyDict when unlocked")
162
163    def test_set_default(self):
164        r = self.get_unlocked_ROD()
165        for key in self.control_dict.keys():
166            r.setdefault(key, self.control_dict[key])
167        self.assertEqual(r, self.control_dict,
168                         msg="can't setdefault() ReadOnlyDict when unlocked")
169
170    def test_locked_set(self):
171        r = self.get_locked_ROD()
172        # TODO use |with self.assertRaises(AssertionError):| if/when we're
173        # all on 2.7.
174        try:
175            r['e'] = 2
176        except AssertionError:
177            pass
178        else:
179            self.assertEqual(0, 1, msg="can set r['e'] when locked")
180
181    def test_locked_del(self):
182        r = self.get_locked_ROD()
183        try:
184            del r['e']
185        except AssertionError:
186            pass
187        else:
188            self.assertEqual(0, 1, "can del r['e'] when locked")
189
190    def test_locked_popitem(self):
191        r = self.get_locked_ROD()
192        self.assertRaises(AssertionError, r.popitem)
193
194    def test_locked_update(self):
195        r = self.get_locked_ROD()
196        self.assertRaises(AssertionError, r.update, {})
197
198    def test_locked_set_default(self):
199        r = self.get_locked_ROD()
200        self.assertRaises(AssertionError, r.setdefault, {})
201
202    def test_locked_pop(self):
203        r = self.get_locked_ROD()
204        self.assertRaises(AssertionError, r.pop)
205
206    def test_locked_clear(self):
207        r = self.get_locked_ROD()
208        self.assertRaises(AssertionError, r.clear)
209
210    def test_locked_second_level_dict_pop(self):
211        r = self.get_locked_ROD()
212        self.assertRaises(AssertionError, r['c'].update, {})
213
214    def test_locked_second_level_list_pop(self):
215        r = self.get_locked_ROD()
216        with self.assertRaises(AttributeError):
217            r['e'].pop()
218
219    def test_locked_third_level_mutate(self):
220        r = self.get_locked_ROD()
221        with self.assertRaises(AttributeError):
222            r['d']['turtles'].append('turtle2')
223
224    def test_locked_object_in_tuple_mutate(self):
225        r = self.get_locked_ROD()
226        with self.assertRaises(AttributeError):
227            r['e'][2]['turtles'].append('turtle2')
228
229    def test_locked_second_level_dict_pop2(self):
230        r = self.get_locked_ROD()
231        self.assertRaises(AssertionError, r['c'].update, {})
232
233    def test_locked_second_level_list_pop2(self):
234        r = self.get_locked_ROD()
235        with self.assertRaises(AttributeError):
236            r['e'].pop()
237
238    def test_locked_third_level_mutate2(self):
239        r = self.get_locked_ROD()
240        with self.assertRaises(AttributeError):
241            r['d']['turtles'].append('turtle2')
242
243    def test_locked_object_in_tuple_mutate2(self):
244        r = self.get_locked_ROD()
245        with self.assertRaises(AttributeError):
246            r['e'][2]['turtles'].append('turtle2')
247
248    def test_locked_deepcopy_set(self):
249        r = self.get_locked_ROD()
250        c = deepcopy(r)
251        c['e'] = 'hey'
252        self.assertEqual(c['e'], 'hey', "can't set var in ROD after deepcopy")
253
254
255class TestActions(unittest.TestCase):
256    all_actions = ['a', 'b', 'c', 'd', 'e']
257    default_actions = ['b', 'c', 'd']
258
259    def test_verify_actions(self):
260        c = config.BaseConfig(initial_config_file='test/test.json')
261        try:
262            c.verify_actions(['not_a_real_action'])
263        except SystemExit:
264            pass
265        else:
266            self.assertEqual(0, 1, msg="verify_actions() didn't die on invalid action")
267        c = config.BaseConfig(initial_config_file='test/test.json')
268        returned_actions = c.verify_actions(c.all_actions)
269        self.assertEqual(c.all_actions, returned_actions,
270                         msg="returned actions from verify_actions() changed")
271
272    def test_default_actions(self):
273        c = config.BaseConfig(default_actions=self.default_actions,
274                              all_actions=self.all_actions,
275                              initial_config_file='test/test.json')
276        self.assertEqual(self.default_actions, c.get_actions(),
277                         msg="default_actions broken")
278
279    def test_no_action1(self):
280        c = config.BaseConfig(default_actions=self.default_actions,
281                              all_actions=self.all_actions,
282                              initial_config_file='test/test.json')
283        c.parse_args(args=['foo', '--no-action', 'a'])
284        self.assertEqual(self.default_actions, c.get_actions(),
285                         msg="--no-ACTION broken")
286
287    def test_no_action2(self):
288        c = config.BaseConfig(default_actions=self.default_actions,
289                              all_actions=self.all_actions,
290                              initial_config_file='test/test.json')
291        c.parse_args(args=['foo', '--no-c'])
292        self.assertEqual(['b', 'd'], c.get_actions(),
293                         msg="--no-ACTION broken")
294
295    def test_add_action(self):
296        c = config.BaseConfig(default_actions=self.default_actions,
297                              all_actions=self.all_actions,
298                              initial_config_file='test/test.json')
299        c.parse_args(args=['foo', '--add-action', 'e'])
300        self.assertEqual(['b', 'c', 'd', 'e'], c.get_actions(),
301                         msg="--add-action ACTION broken")
302
303    def test_only_action(self):
304        c = config.BaseConfig(default_actions=self.default_actions,
305                              all_actions=self.all_actions,
306                              initial_config_file='test/test.json')
307        c.parse_args(args=['foo', '--a', '--e'])
308        self.assertEqual(['a', 'e'], c.get_actions(),
309                         msg="--ACTION broken")
310
311
312if __name__ == '__main__':
313    unittest.main()
314