This file is indexed.

/usr/lib/python3/dist-packages/checkbox/test_resource.py is in python3-checkbox 0.17.6-0ubuntu6.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# This file is part of Checkbox.
#
# Copyright 2013 Canonical Ltd.
# Written by:
#   Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
#
# Checkbox is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3,
# as published by the Free Software Foundation.

#
# Checkbox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Checkbox.  If not, see <http://www.gnu.org/licenses/>.

"""
checkbox.test_resource
======================

Test definitions for :mod:`checkbox.resource`
"""

from unittest import TestCase

from checkbox.resource import ResourceIterator
from checkbox.resource import ResourceMap


class ResourceMapTests(TestCase):

    def setUp(self):
        # Create a resource map with two resources:
        #
        # 'resource_list' is a list with two values, each with an 'attr'
        # attribute. This is how resources with multiple values are normally
        # stored.
        #
        # 'resource_tuple' is similar to 'resource_list', holding the same data
        # but using a tuple instead of a list.
        #
        # 'resource_dict' is a dictionary with one attribute 'name'. This is
        # how resources with one value might be stored.
        self.resource_map = ResourceMap({
            'resource_list': [
                {"attr": "value"},
                {"attr": "other-value"}
            ],
            'resource_tuple': (
                {"attr": "value"},
                {"attr": "other-value"}
            ),
            'resource_dict': {"attr": "value"},
            'resource_int': 42,
        })
        # This is an empty map, it is used by some of the tests
        self.empty_map = ResourceMap()

    def test_resource_map_is_a_dict(self):
        # While it's a derived class it's still a dictionary
        self.assertIsInstance(self.resource_map, dict)

    def test_missing_resource(self):
        # Missing resources just raise KeyError as they normally would in a
        # dictionary
        with self.assertRaises(KeyError):
            self.resource_map['resource_missing']

    def test_existing_resource_list(self):
        # Accessing a resource wrapped in a list returns a ResourceIterator
        thing = self.resource_map['resource_list']
        self.assertIsInstance(thing, ResourceIterator)

    def test_existing_resource_tuple(self):
        # Accessing a resource wrapped in a tuple returns a ResourceIterator
        thing = self.resource_map['resource_tuple']
        self.assertIsInstance(thing, ResourceIterator)

    def test_existing_resource_dict(self):
        # Accessing a resource wrapped in a dict returns a ResourceIterator
        thing = self.resource_map['resource_dict']
        self.assertIsInstance(thing, ResourceIterator)

    def test_existing_resource_int(self):
        # Accessing a resource wrapped in a int returns the value directly
        thing = self.resource_map['resource_int']
        self.assertIsInstance(thing, int)
        # The helper integer is 42
        self.assertEqual(thing, 42)

    def test_eval_smoke(self):
        # Evaluating anything valid against an empty map returns None
        self.assertIs(None, self.empty_map.eval("resource.attr == 'value'"))
        # Evaluating borked code against an empty map also returns None
        self.assertIs(None, self.empty_map.eval("adpasdasd .asdaasd asd a"))

    def test_under_results(self):
        # The resource map has an instance variable, _results that is only
        # assigned after the call to ResourceMap.eval().
        with self.assertRaises(AttributeError):
            self.empty_map._results
        # Calling eval() initializes/overrides it
        self.empty_map.eval('')
        # With an empty list (that list may contain other values normally but
        # with an empty resource map it is always empty)
        self.assertEqual(self.empty_map._results, [])

    def test_eval_globals(self):
        # ResourceMap.eval() has a fixed list of globals
        #
        # We can poke at that list by using specially crafted expressions.
        # Each time the expression evaluates to 1, we get an empty list back.
        self.assertEqual([], self.empty_map.eval("'bool' in globals() and 1"))
        self.assertEqual([], self.empty_map.eval("'float' in globals() and 1"))
        self.assertEqual([], self.empty_map.eval("'int' in globals() and 1"))
        self.assertEqual([], self.empty_map.eval("'str' in globals() and 1"))
        # Each of those globals is a special ResourceBuiltin object
        self.assertEqual([], self.resource_map.eval(
            "bool.__class__.__name__ == 'ResourceBuiltin'"))
        self.assertEqual([], self.resource_map.eval(
            "float.__class__.__name__ == 'ResourceBuiltin'"))
        self.assertEqual([], self.resource_map.eval(
            "int.__class__.__name__ == 'ResourceBuiltin'"))
        self.assertEqual([], self.resource_map.eval(
            "str.__class__.__name__ == 'ResourceBuiltin'"))
        # Unfortunately, __builtins__ is also in the global scope
        #
        # With builtins being available we have a way to access anything in
        # python via __import__
        self.assertEqual([], self.empty_map.eval(
            "'__builtins__' in globals() and 1"))
        # There are no other globals than what was checked for above:
        #
        # The goal is to ensure that there are only particular globals
        # in the context that is being used to evaluate the expression.
        #
        # We cannot return the value directly and compare it outside
        # (well we can but that trick is used later to keep this code
        # simple and portable across changes in checkbox)
        #
        # The return value of globals().keys() is a special dict_keys() proxy
        # that returns the items in undetermined order.
        #
        # The result is a simple comparison of two sorted list generated by
        # list comprehensions from iterating over all the keys in global() and
        # in the list of expected global symbols
        self.assertEqual([], self.empty_map.eval(
            "sorted([x for x in globals().keys()])"
            " == "
            "sorted(['__builtins__', 'bool', 'float', 'int', 'str'])"))

    def test_eval_locals(self):
        # As with the globals test above, this test checks what kind of locals
        # are available inside the execution context.
        #
        # In the example of an empty map, the result is -- no locals!
        self.assertEqual([], self.empty_map.eval(
            "sorted([x for x in locals().keys()])"
            " == "
            "[]"))
        # In the example of a resource map with several resources the result
        # are those resources (after wrapping in ResourceIterator)
        self.assertEqual([], self.resource_map.eval(
            "sorted([x for x in locals().keys()])"
            " == "
            "sorted(['resource_list', 'resource_tuple',"
            "        'resource_dict', 'resource_int'])"))
        # Let's just ensure that those are not the raw values anymore Note that
        # we cannot use 'int', 'list', etc. directly they are wrapped in
        # ResourceBuiltin objects (see test_eval_globals() above)
        self.assertEqual([], self.resource_map.eval(
            "locals()['resource_int'] != (0).__class__"))
        self.assertEqual([], self.resource_map.eval(
            "locals()['resource_dict'] != ({}).__class__"))
        self.assertEqual([], self.resource_map.eval(
            "locals()['resource_list'] != ([]).__class__"))
        self.assertEqual([], self.resource_map.eval(
            "locals()['resource_tuple'] != (()).__class__"))

    def test_eval_import(self):
        # The expression can import arbitrary python package
        #
        # Here we import the subprocess module, execute /bin/false which
        # returns 1, this makes the expression True in the terms of checkbox
        # resource programs.
        self.assertEqual([], self.empty_map.eval(
            "__import__('subprocess').call('/bin/false')"))

    def test_eval_can_mutate_results(self):
        # The ResourceMap._results object can be accessed and mutated
        # by using locals(). Calling locals() inside the expression literally
        # returns the ResourceMap instance.
        #
        # Using that trick, any operation can be performed, including mutating
        # or replacing the results object.
        results = self.empty_map.eval(
            "1 "
            "if getattr(locals(), '_results').append('payload') "
            "is None "
            "else 0")
        self.assertIs(self.empty_map._results, results)
        self.assertEqual(results, ['payload'])

    def test_eval_return_value_for_int_resources(self):
        # This test explores how resource_map.eval() result gets
        # computed and what it really is in practice.
        #
        # The important aspect of this code is that it relies on
        # ResourceMap._results being shared by ResourceMap, ResourceIterator
        # and ResourceObject. This makes testing the behavior in isolation
        # difficult.
        #
        # Technically _results are mutated only in ResourceIterator (in the
        # __contains__ function) and in the ResourceObject (in the _try
        # function that is in turn called from all overridden special functions
        # like __eq__) both of those places call _results.append().
        #
        # The appended value is either the element of the ResourceIterator
        # (technically the value) and the converted value of the attribute in
        # ResourceObject._try. This is rather confusing so let's see what
        # happens in practice.
        #
        # Let's explore resource_list first (the flow is the same for all other
        # types so the explanations are only given once).
        #
        # Here each value was a simple dictionary with 'attr' key wrapped in a
        # list. As checked earlier by test_existing_resource_list() that list
        # is converted to a ResourceIterator. Accessing any attribute on the
        # resource iterator creates a ResourceObject bound to that attribute
        # name and the iterator. Calling the equality operator on a
        # ResourceObject calls ResourceObject.__eq__() which in turns calls
        # ResourceObject._try() The _try() function iterates over the
        # ResourceIterator and checks of any of the items returned (which are
        # the raw items as passed to ResourceMap initially) have an entry
        # corresponding to the attribute name (that was accessed on
        # ResourceIterator), if so, the value is looked up, converted using the
        # convert function (identity by default), and passed to the helper
        # function (that corresponds to the logical operation performed by
        # whatever called _try, for example, __eq__ calls lambda a, b: a == b).
        # If the return value of that function matches the expected sentinel
        # object (True is used by default) then the loop over the iterator
        # (inside _try()) is broken and the original item (the dictionary or
        # other object that was initially passed to the ResourceMap) is
        # appended. Lastly the _try() method returns the sentinel object (True
        # by default) there was a match (the loop got broken) or the default
        # value (False by default) otherwise. This is all pretty complicated
        # but in the case of all-defaults it's pretty much equivalent to:
        #
        # results = [
        #     object
        #     for object in resource_map[resource_name]
        #     if object.get(resource_attr) == expected_value]
        #
        # Let's see how that works in practice.
        # Note that the == operator can be replaced by any operator
        # supported by ResourceObject (<, <=, >, >=, =, !=, in)
        self.assertEqual(
            self.resource_map.eval("resource_list.attr == 'value'"),
            [{'attr': 'value'}])
        self.assertEqual(
            self.resource_map.eval("resource_list.attr in ['value']"),
            [{'attr': 'value'}])
        self.assertEqual(
            self.resource_map.eval("resource_list.attr != 'value'"),
            [{'attr': 'other-value'}])
        # The inequality operator used with a value that does not exist in the
        # resource produces the full list of resources back.
        self.assertEqual(
            self.resource_map.eval("resource_list.attr != 'foo'"),
            [{'attr': 'value'}, {'attr': 'other-value'}])

    def test_eval_return_value_for_tuple_resources(self):
        # Set of identical tests for resource_tuple
        self.assertEqual(
            self.resource_map.eval("resource_tuple.attr == 'value'"),
            [{'attr': 'value'}])
        self.assertEqual(
            self.resource_map.eval("resource_tuple.attr in ['value']"),
            [{'attr': 'value'}])
        self.assertEqual(
            self.resource_map.eval("resource_tuple.attr != 'value'"),
            [{'attr': 'other-value'}])

    def test_eval_return_value_for_dict_resources(self):
        # Set of identical tests for resource_dict
        self.assertEqual(
            self.resource_map.eval("resource_dict.attr == 'value'"),
            [{'attr': 'value'}])
        self.assertEqual(
            self.resource_map.eval("resource_dict.attr in ['value']"),
            [{'attr': 'value'}])
        # Here the result is slightly different. This is because there are no
        # matches (there is no 'other-value' like in previous cases). In such
        # case the whole expression does not evaluate to True and the return
        # value is None.
        self.assertEqual(
            self.resource_map.eval("resource_dict.attr != 'value'"),
            None)

    def test_eval_return_value_for_other_resources(self):
        # Set of identical tests for resource_int
        #
        # Here resource_int is not wrapped in a ResourceIterator and unexpected
        # things start to happen. There is no logic to modify the result in
        # such case so although the result of the comparison is True the result
        # of the eval() function is the empty results list.
        #
        # I suspect that such cases were never meant to happen and are an
        # oversight from the initial implementation and lack of testing beyond
        # the expected working cases.
        self.assertEqual(
            self.resource_map.eval("resource_int == 42"),
            [])
        # Confusingly enough, but consistently, when the expression evaluates
        # the False the eval() function returns None.
        self.assertEqual(
            self.resource_map.eval("resource_int != 42"),
            None)

    def test_eval_return_logic_bool(self):
        # There is some extra logic in eval() that should be documented.
        # The return value of the low-level eval() call inside the
        # ResourceMap.eval() method is passed to a set of tests to determine if
        # it is 'true enough' to return the results. Those tests include:
        # 1) A boolean value which is True
        self.assertEqual([], self.empty_map.eval("True"))
        self.assertEqual(None, self.empty_map.eval("False"))

    def test_eval_return_logic_int(self):
        # 2) A non-zero integer
        self.assertEqual([], self.empty_map.eval("1"))
        self.assertEqual(None, self.empty_map.eval("0"))

    def test_eval_return_logic_tuple(self):
        # 3) A tuple with at least one True object
        self.assertEqual([], self.empty_map.eval("(True,)"))
        self.assertEqual([], self.empty_map.eval("(False, True, 7)"))
        self.assertEqual(None, self.empty_map.eval("(False, 7)"))
        self.assertEqual(None, self.empty_map.eval("(7,)"))
        self.assertEqual(None, self.empty_map.eval("()"))

    def test_eval_return_logic_list(self):
        # Sadly this does not apply to lists
        self.assertEqual(None, self.empty_map.eval("[True]"))