~jamesodhunt/click/add-checksum-to-manifest

« back to all changes in this revision

Viewing changes to click/tests/test_database.py

  • Committer: CI bot
  • Author(s): Michael Vogt, Colin Watson
  • Date: 2014-08-06 23:33:12 UTC
  • mfrom: (425.1.67 devel)
  • Revision ID: ps-jenkins@lists.canonical.com-20140806233312-4nc48i27d6zn4i9j
Click 0.4.30: Unit test improvements; fix upgrade if packages are present for removed users; flesh out 14.10 chroots. Fixes: 1334611

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
__metaclass__ = type
21
21
__all__ = [
22
22
    "TestClickDB",
 
23
    "TestClickInstalledPackage",
23
24
    "TestClickSingleDB",
24
25
    ]
25
26
 
28
29
from itertools import takewhile
29
30
import json
30
31
import os
 
32
import unittest
31
33
 
32
 
from gi.repository import Click
 
34
from gi.repository import Click, GLib
33
35
 
34
36
from click.json_helpers import json_array_to_python, json_object_to_python
35
37
from click.tests.gimock_types import Passwd
36
38
from click.tests.helpers import TestCase, mkfile, touch
37
39
 
38
40
 
 
41
class TestClickInstalledPackage(TestCase):
 
42
    def setUp(self):
 
43
        super(TestClickInstalledPackage, self).setUp()
 
44
        self.foo = Click.InstalledPackage.new(
 
45
            "foo", "1.0", "/path/to/foo/1.0", False)
 
46
        self.foo_clone = Click.InstalledPackage.new(
 
47
            "foo", "1.0", "/path/to/foo/1.0", False)
 
48
        self.foo_different_version = Click.InstalledPackage.new(
 
49
            "foo", "2.0", "/path/to/foo/1.0", False)
 
50
        self.foo_different_path = Click.InstalledPackage.new(
 
51
            "foo", "1.0", "/path/to/foo/2.0", False)
 
52
        self.foo_different_writeable = Click.InstalledPackage.new(
 
53
            "foo", "1.0", "/path/to/foo/1.0", True)
 
54
        self.bar = Click.InstalledPackage.new(
 
55
            "bar", "1.0", "/path/to/foo/1.0", False)
 
56
 
 
57
    def test_hash(self):
 
58
        self.assertIsInstance(self.foo.hash(), int)
 
59
        self.assertEqual(self.foo.hash(), self.foo_clone.hash())
 
60
        self.assertNotEqual(self.foo.hash(), self.foo_different_version.hash())
 
61
        self.assertNotEqual(self.foo.hash(), self.foo_different_path.hash())
 
62
        self.assertNotEqual(
 
63
            self.foo.hash(), self.foo_different_writeable.hash())
 
64
        self.assertNotEqual(self.foo.hash(), self.bar.hash())
 
65
 
 
66
    # GLib doesn't allow passing an InstalledPackage as an argument here.
 
67
    @unittest.expectedFailure
 
68
    def test_equal_to(self):
 
69
        self.assertTrue(self.foo.equal_to(self.foo_clone))
 
70
        self.assertFalse(self.foo.equal_to(self.foo_different_version))
 
71
        self.assertFalse(self.foo.equal_to(self.foo_different_path))
 
72
        self.assertFalse(self.foo.equal_to(self.foo_different_writeable))
 
73
        self.assertFalse(self.foo.equal_to(self.bar))
 
74
 
 
75
 
39
76
class TestClickSingleDB(TestCase):
40
77
    def setUp(self):
41
78
        super(TestClickSingleDB, self).setUp()
66
103
        self.assertRaisesDatabaseError(
67
104
            Click.DatabaseError.DOES_NOT_EXIST, self.db.get_path, "a", "1.1")
68
105
 
 
106
    def test_has_package_version(self):
 
107
        os.makedirs(os.path.join(self.temp_dir, "a", "1.0"))
 
108
        self.assertTrue(self.db.has_package_version("a", "1.0"))
 
109
        self.assertFalse(self.db.has_package_version("a", "1.1"))
 
110
 
69
111
    def test_packages_current(self):
70
112
        os.makedirs(os.path.join(self.temp_dir, "a", "1.0"))
71
113
        os.makedirs(os.path.join(self.temp_dir, "a", "1.1"))
107
149
    def test_manifest(self):
108
150
        manifest_path = os.path.join(
109
151
            self.temp_dir, "a", "1.0", ".click", "info", "a.manifest")
110
 
        manifest_obj = {"name": "a", "version": "1.0", "hooks": {"a-app": {}}}
 
152
        manifest_obj = {
 
153
            "name": "a", "version": "1.0", "hooks": {"a-app": {}},
 
154
            "_should_be_removed": "",
 
155
        }
111
156
        with mkfile(manifest_path) as manifest:
112
157
            json.dump(manifest_obj, manifest)
 
158
        del manifest_obj["_should_be_removed"]
113
159
        manifest_obj["_directory"] = os.path.join(self.temp_dir, "a", "1.0")
114
160
        self.assertEqual(
115
161
            manifest_obj,
124
170
            Click.DatabaseError.DOES_NOT_EXIST,
125
171
            self.db.get_manifest_as_string, "a", "1.1")
126
172
 
 
173
    def test_manifest_bad(self):
 
174
        manifest_path = os.path.join(
 
175
            self.temp_dir, "a", "1.0", ".click", "info", "a.manifest")
 
176
        with mkfile(manifest_path) as manifest:
 
177
            print("{bad syntax", file=manifest)
 
178
        self.assertRaisesDatabaseError(
 
179
            Click.DatabaseError.BAD_MANIFEST, self.db.get_manifest, "a", "1.0")
 
180
        self.assertRaisesDatabaseError(
 
181
            Click.DatabaseError.BAD_MANIFEST,
 
182
            self.db.get_manifest_as_string, "a", "1.0")
 
183
        manifest_path = os.path.join(
 
184
            self.temp_dir, "a", "1.1", ".click", "info", "a.manifest")
 
185
        with mkfile(manifest_path) as manifest:
 
186
            print("[0]", file=manifest)
 
187
        self.assertRaisesDatabaseError(
 
188
            Click.DatabaseError.BAD_MANIFEST, self.db.get_manifest, "a", "1.1")
 
189
        self.assertRaisesDatabaseError(
 
190
            Click.DatabaseError.BAD_MANIFEST,
 
191
            self.db.get_manifest_as_string, "a", "1.1")
 
192
 
127
193
    def test_app_running(self):
128
194
        with self.run_in_subprocess(
129
195
                "click_find_on_path", "g_spawn_sync",
193
259
                self.g_spawn_sync_side_effect, {b"ubuntu-app-pid": 0})
194
260
            self.assertFalse(self.db.any_app_running("a", "1.0"))
195
261
 
 
262
    def test_any_app_running_missing_app(self):
 
263
        with self.run_in_subprocess("click_find_on_path") as (enter, preloads):
 
264
            enter()
 
265
            preloads["click_find_on_path"].side_effect = (
 
266
                lambda command: command == b"ubuntu-app-pid")
 
267
            self.assertRaisesDatabaseError(
 
268
                Click.DatabaseError.DOES_NOT_EXIST,
 
269
                self.db.any_app_running, "a", "1.0")
 
270
 
 
271
    def test_any_app_running_bad_manifest(self):
 
272
        with self.run_in_subprocess(
 
273
                "click_find_on_path", "g_spawn_sync",
 
274
                ) as (enter, preloads):
 
275
            enter()
 
276
            manifest_path = os.path.join(
 
277
                self.temp_dir, "a", "1.0", ".click", "info", "a.manifest")
 
278
            with mkfile(manifest_path) as manifest:
 
279
                print("{bad syntax", file=manifest)
 
280
            preloads["click_find_on_path"].side_effect = (
 
281
                lambda command: command == b"ubuntu-app-pid")
 
282
            self.assertFalse(self.db.any_app_running("a", "1.0"))
 
283
            self.assertFalse(preloads["g_spawn_sync"].called)
 
284
 
 
285
    def test_any_app_running_no_hooks(self):
 
286
        with self.run_in_subprocess(
 
287
                "click_find_on_path", "g_spawn_sync",
 
288
                ) as (enter, preloads):
 
289
            enter()
 
290
            manifest_path = os.path.join(
 
291
                self.temp_dir, "a", "1.0", ".click", "info", "a.manifest")
 
292
            with mkfile(manifest_path) as manifest:
 
293
                json.dump({}, manifest)
 
294
            preloads["click_find_on_path"].side_effect = (
 
295
                lambda command: command == b"ubuntu-app-pid")
 
296
            self.assertFalse(self.db.any_app_running("a", "1.0"))
 
297
            self.assertFalse(preloads["g_spawn_sync"].called)
 
298
 
196
299
    def test_maybe_remove_registered(self):
197
300
        with self.run_in_subprocess(
198
301
                "click_find_on_path", "g_spawn_sync",
262
365
 
263
366
    def test_gc(self):
264
367
        with self.run_in_subprocess(
265
 
                "click_find_on_path", "g_spawn_sync",
 
368
                "click_find_on_path", "g_spawn_sync", "getpwnam"
266
369
                ) as (enter, preloads):
267
370
            enter()
 
371
            preloads["getpwnam"].side_effect = (
 
372
                lambda name: self.make_pointer(Passwd(pw_uid=1, pw_gid=1)))
268
373
            os.environ["TEST_QUIET"] = "1"
269
374
            a_path = os.path.join(self.temp_dir, "a", "1.0")
270
375
            a_manifest_path = os.path.join(
298
403
            self.assertTrue(os.path.exists(c_path))
299
404
 
300
405
    def test_gc_ignores_non_directory(self):
301
 
        a_path = os.path.join(self.temp_dir, "a", "1.0")
302
 
        a_manifest_path = os.path.join(
303
 
            a_path, ".click", "info", "a.manifest")
304
 
        with mkfile(a_manifest_path) as manifest:
305
 
            json.dump({"hooks": {"a-app": {}}}, manifest)
306
 
        a_user_path = os.path.join(
307
 
            self.temp_dir, ".click", "users", "test-user", "a")
308
 
        os.makedirs(os.path.dirname(a_user_path))
309
 
        os.symlink(a_path, a_user_path)
310
 
        touch(os.path.join(self.temp_dir, "file"))
311
 
        self.db.gc()
312
 
        self.assertTrue(os.path.exists(a_path))
 
406
        with self.run_in_subprocess(
 
407
                "getpwnam"
 
408
                ) as (enter, preloads):
 
409
            enter()
 
410
            preloads["getpwnam"].side_effect = (
 
411
                lambda name: self.make_pointer(Passwd(pw_uid=1, pw_gid=1)))
 
412
            a_path = os.path.join(self.temp_dir, "a", "1.0")
 
413
            a_manifest_path = os.path.join(
 
414
                a_path, ".click", "info", "a.manifest")
 
415
            with mkfile(a_manifest_path) as manifest:
 
416
                json.dump({"hooks": {"a-app": {}}}, manifest)
 
417
            a_user_path = os.path.join(
 
418
                self.temp_dir, ".click", "users", "test-user", "a")
 
419
            os.makedirs(os.path.dirname(a_user_path))
 
420
            os.symlink(a_path, a_user_path)
 
421
            touch(os.path.join(self.temp_dir, "file"))
 
422
            self.db.gc()
 
423
            self.assertTrue(os.path.exists(a_path))
313
424
 
314
425
    def _make_ownership_test(self):
315
426
        path = os.path.join(self.temp_dir, "a", "1.0")
396
507
                [(1, 1)],
397
508
                set(args[0][1:] for args in preloads["chown"].call_args_list))
398
509
 
 
510
    def test_ensure_ownership_missing_clickpkg_user(self):
 
511
        with self.run_in_subprocess("getpwnam") as (enter, preloads):
 
512
            enter()
 
513
            preloads["getpwnam"].return_value = None
 
514
            self.assertRaisesDatabaseError(
 
515
                Click.DatabaseError.ENSURE_OWNERSHIP, self.db.ensure_ownership)
 
516
 
 
517
    def test_ensure_ownership_failed_chown(self):
 
518
        def stat_side_effect(name, limit, ver, path, buf):
 
519
            st = self.convert_stat_pointer(name, buf)
 
520
            if path == limit:
 
521
                st.st_uid = 2
 
522
                st.st_gid = 2
 
523
                return 0
 
524
            else:
 
525
                self.delegate_to_original(name)
 
526
                return -1
 
527
 
 
528
        with self.run_in_subprocess(
 
529
                "chown", "getpwnam", "__xstat", "__xstat64",
 
530
                ) as (enter, preloads):
 
531
            enter()
 
532
            preloads["chown"].return_value = -1
 
533
            preloads["getpwnam"].side_effect = (
 
534
                lambda name: self.make_pointer(Passwd(pw_uid=1, pw_gid=1)))
 
535
            self._set_stat_side_effect(
 
536
                preloads, stat_side_effect, self.db.props.root)
 
537
 
 
538
            self._make_ownership_test()
 
539
            self.assertRaisesDatabaseError(
 
540
                Click.DatabaseError.ENSURE_OWNERSHIP, self.db.ensure_ownership)
 
541
 
399
542
 
400
543
class TestClickDB(TestCase):
401
544
    def setUp(self):
429
572
        db = Click.DB()
430
573
        self.assertEqual(0, db.props.size)
431
574
 
 
575
    def test_read_nonexistent(self):
 
576
        db = Click.DB()
 
577
        db.read(db_dir=os.path.join(self.temp_dir, "nonexistent"))
 
578
        self.assertEqual(0, db.props.size)
 
579
 
 
580
    def test_read_not_directory(self):
 
581
        path = os.path.join(self.temp_dir, "file")
 
582
        touch(path)
 
583
        db = Click.DB()
 
584
        self.assertRaisesFileError(GLib.FileError.NOTDIR, db.read, db_dir=path)
 
585
 
432
586
    def test_add(self):
433
587
        db = Click.DB()
434
588
        self.assertEqual(0, db.props.size)
474
628
            os.path.join(self.temp_dir, "b", "pkg", "1.1"),
475
629
            db.get_path("pkg", "1.1"))
476
630
 
 
631
    def test_has_package_version(self):
 
632
        with open(os.path.join(self.temp_dir, "a.conf"), "w") as a:
 
633
            print("[Click Database]", file=a)
 
634
            print("root = %s" % os.path.join(self.temp_dir, "a"), file=a)
 
635
        with open(os.path.join(self.temp_dir, "b.conf"), "w") as b:
 
636
            print("[Click Database]", file=b)
 
637
            print("root = %s" % os.path.join(self.temp_dir, "b"), file=b)
 
638
        db = Click.DB()
 
639
        db.read(db_dir=self.temp_dir)
 
640
        self.assertFalse(db.has_package_version("pkg", "1.0"))
 
641
        os.makedirs(os.path.join(self.temp_dir, "a", "pkg", "1.0"))
 
642
        self.assertTrue(db.has_package_version("pkg", "1.0"))
 
643
        self.assertFalse(db.has_package_version("pkg", "1.1"))
 
644
        os.makedirs(os.path.join(self.temp_dir, "b", "pkg", "1.0"))
 
645
        self.assertTrue(db.has_package_version("pkg", "1.0"))
 
646
        os.makedirs(os.path.join(self.temp_dir, "b", "pkg", "1.1"))
 
647
        self.assertTrue(db.has_package_version("pkg", "1.1"))
 
648
 
477
649
    def test_packages_current(self):
478
650
        with open(os.path.join(self.temp_dir, "a.conf"), "w") as a:
479
651
            print("[Click Database]", file=a)
570
742
            b_manifest_obj,
571
743
            json.loads(db.get_manifest_as_string("pkg", "1.1")))
572
744
 
 
745
    def test_manifest_bad(self):
 
746
        with open(os.path.join(self.temp_dir, "a.conf"), "w") as a:
 
747
            print("[Click Database]", file=a)
 
748
            print("root = %s" % os.path.join(self.temp_dir, "a"), file=a)
 
749
        db = Click.DB()
 
750
        db.read(db_dir=self.temp_dir)
 
751
        manifest_path = os.path.join(
 
752
            self.temp_dir, "a", "pkg", "1.0", ".click", "info", "pkg.manifest")
 
753
        with mkfile(manifest_path) as manifest:
 
754
            print("{bad syntax", file=manifest)
 
755
        self.assertRaisesDatabaseError(
 
756
            Click.DatabaseError.BAD_MANIFEST, db.get_manifest, "pkg", "1.0")
 
757
        self.assertRaisesDatabaseError(
 
758
            Click.DatabaseError.BAD_MANIFEST,
 
759
            db.get_manifest_as_string, "pkg", "1.0")
 
760
        manifest_path = os.path.join(
 
761
            self.temp_dir, "a", "pkg", "1.1", ".click", "info", "pkg.manifest")
 
762
        with mkfile(manifest_path) as manifest:
 
763
            print("[0]", file=manifest)
 
764
        self.assertRaisesDatabaseError(
 
765
            Click.DatabaseError.BAD_MANIFEST, db.get_manifest, "pkg", "1.0")
 
766
        self.assertRaisesDatabaseError(
 
767
            Click.DatabaseError.BAD_MANIFEST,
 
768
            db.get_manifest_as_string, "pkg", "1.0")
 
769
 
573
770
    def test_manifests_current(self):
574
771
        with open(os.path.join(self.temp_dir, "a.conf"), "w") as a:
575
772
            print("[Click Database]", file=a)