~free.ekanayaka/landscape-client/jaunty-1.5.0-0ubuntu0.9.04.0

« back to all changes in this revision

Viewing changes to landscape/package/tests/test_taskhandler.py

  • Committer: Bazaar Package Importer
  • Author(s): Free Ekanayaka
  • Date: 2009-12-16 10:50:05 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20091216105005-9p9absehm0l6sd2t
Tags: 1.4.0-0ubuntu0.9.04.0
* New upstream release (LP: #497351)

* Bug fixes:
  - Fix landscape daemons fail to start when too many groups are
    available (LP: #456124)
  - Fix landscape programs wake up far too much. (LP: #340843)
  - Fix Package manager fails with 'no such table: task' (LP #465846)
  - Fix test suite leaving temporary files around (LP #476418)
  - Fix the 1hr long wait for user data to be uploaded following a
    resynchronisation (LP #369000)

* Add support for Ubuntu release upgrades:
  - Add helper function to fetch many files at once (LP: #450629)
  - Handle release-upgrade messages in the packagemanager
    plugin (LP: #455217)
  - Add a release-upgrader task handler (LP: #462543)
  - Support upgrade-tool environment variables (LP: #463321)

* Add initial support for Smart package locking:
  - Detect and report changes about Smart package locks (#488108)

* Packaging fixes:
  - Turn unnecessary Pre-Depends on python-gobject into a regular Depends
  - If it's empty, remove /etc/landscape upon purge

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
from twisted.internet.defer import Deferred, fail
5
5
 
6
6
from landscape.lib.lock import lock_path
7
 
from landscape.lib.command import CommandError
8
 
 
9
 
from landscape.deployment import Configuration
10
 
from landscape.broker.remote import RemoteBroker
11
 
 
12
 
from landscape.package.taskhandler import PackageTaskHandler, run_task_handler
 
7
 
 
8
from landscape.package.taskhandler import (
 
9
    PackageTaskHandlerConfiguration, PackageTaskHandler, run_task_handler,
 
10
    LazyRemoteBroker)
13
11
from landscape.package.facade import SmartFacade
14
12
from landscape.package.store import HashIdStore, PackageStore
15
13
from landscape.package.tests.helpers import SmartFacadeHelper
16
14
 
17
15
from landscape.tests.helpers import (
18
 
    LandscapeIsolatedTest, RemoteBrokerHelper)
 
16
    LandscapeTest, LandscapeIsolatedTest, RemoteBrokerHelper)
19
17
from landscape.tests.mocker import ANY, ARGS, MATCH
20
18
 
21
19
 
23
21
    return MATCH(lambda arg: type(arg) is match_type)
24
22
 
25
23
 
 
24
SAMPLE_LSB_RELEASE = "DISTRIB_CODENAME=codename\n"
 
25
 
 
26
 
26
27
class PackageTaskHandlerTest(LandscapeIsolatedTest):
27
28
 
28
29
    helpers = [SmartFacadeHelper, RemoteBrokerHelper]
30
31
    def setUp(self):
31
32
        super(PackageTaskHandlerTest, self).setUp()
32
33
 
33
 
        self.config = Configuration()
 
34
        self.config = PackageTaskHandlerConfiguration()
34
35
        self.store = PackageStore(self.makeFile())
35
 
 
36
 
        self.handler = PackageTaskHandler(self.store, self.facade, self.remote, self.config)
 
36
        self.handler = PackageTaskHandler(self.store, self.facade, self.remote,
 
37
                                          self.config)
37
38
 
38
39
    def test_ensure_channels_reloaded(self):
39
40
        self.assertEquals(len(self.facade.get_packages()), 0)
60
61
        # Fake uuid, codename and arch
61
62
        message_store = self.broker_service.message_store
62
63
        message_store.set_server_uuid("uuid")
63
 
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
64
 
        command_mock("lsb_release -cs")
65
 
        self.mocker.result("codename")
 
64
        self.handler.lsb_release_filename = self.makeFile(SAMPLE_LSB_RELEASE)
66
65
        self.facade.set_arch("arch")
67
66
 
68
67
        # Attach the hash=>id database to our store
83
82
        message_store.set_server_uuid("uuid")
84
83
 
85
84
        # Undetermined codename
86
 
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
87
 
        command_mock("lsb_release -cs")
88
 
        command_error = CommandError("lsb_release -cs", 1, "error")
89
 
        self.mocker.throw(command_error)
90
 
 
91
 
        # The failure should be properly logged
92
 
        logging_mock = self.mocker.replace("logging.warning")
93
 
        logging_mock("Couldn't determine which hash=>id database to use: %s" %
94
 
                     str(command_error))
95
 
        self.mocker.result(None)
96
 
 
97
 
        # Go!
98
 
        self.mocker.replay()
99
 
        result = self.handler.use_hash_id_db()
100
 
 
 
85
        self.handler.lsb_release_filename = self.makeFile("Foo=bar")
 
86
 
 
87
        # The failure should be properly logged
 
88
        logging_mock = self.mocker.replace("logging.warning")
 
89
        logging_mock("Couldn't determine which hash=>id database to use: "
 
90
                     "missing code-name key in %s" %
 
91
                     self.handler.lsb_release_filename)
 
92
        self.mocker.result(None)
 
93
 
 
94
        # Go!
 
95
        self.mocker.replay()
 
96
        result = self.handler.use_hash_id_db()
 
97
        return result
 
98
 
 
99
    def test_use_hash_id_db_wit_non_existing_lsb_release(self):
 
100
 
 
101
        # Fake uuid
 
102
        message_store = self.broker_service.message_store
 
103
        message_store.set_server_uuid("uuid")
 
104
 
 
105
        # Undetermined codename
 
106
        self.handler.lsb_release_filename = self.makeFile()
 
107
 
 
108
        # The failure should be properly logged
 
109
        logging_mock = self.mocker.replace("logging.warning")
 
110
        logging_mock("Couldn't determine which hash=>id database to use: "
 
111
                     "[Errno 2] No such file or directory: '%s'" %
 
112
                     self.handler.lsb_release_filename)
 
113
        self.mocker.result(None)
 
114
 
 
115
        # Go!
 
116
        self.mocker.replay()
 
117
        result = self.handler.use_hash_id_db()
101
118
        return result
102
119
 
103
120
    def test_wb_determine_hash_id_db_filename_server_uuid_is_none(self):
109
126
        message_store.set_server_uuid(None)
110
127
 
111
128
        result = self.handler._determine_hash_id_db_filename()
 
129
 
112
130
        def callback(hash_id_db_filename):
113
131
            self.assertIs(hash_id_db_filename, None)
114
132
        result.addCallback(callback)
115
133
        return result
116
 
        
 
134
 
117
135
    def test_use_hash_id_db_undetermined_server_uuid(self):
118
136
        """
119
137
        If the server-uuid can't be determined for some reason, no hash-id db
129
147
        self.mocker.replay()
130
148
 
131
149
        result = self.handler.use_hash_id_db()
 
150
 
132
151
        def callback(ignore):
133
152
            self.assertFalse(self.store.has_hash_id_db())
134
153
        result.addCallback(callback)
139
158
        # Fake uuid and codename
140
159
        message_store = self.broker_service.message_store
141
160
        message_store.set_server_uuid("uuid")
142
 
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
143
 
        command_mock("lsb_release -cs")
144
 
        self.mocker.result("codename")
 
161
        self.handler.lsb_release_filename = self.makeFile(SAMPLE_LSB_RELEASE)
145
162
 
146
163
        # Undetermined arch
147
164
        self.facade.set_arch(None)
166
183
        # Fake uuid, codename and arch
167
184
        message_store = self.broker_service.message_store
168
185
        message_store.set_server_uuid("uuid")
169
 
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
170
 
        command_mock("lsb_release -cs")
171
 
        self.mocker.result("codename")
 
186
        self.handler.lsb_release_filename = self.makeFile(SAMPLE_LSB_RELEASE)
172
187
        self.facade.set_arch("arch")
173
188
 
174
189
        # Let's try
194
209
        # Fake uuid, codename and arch
195
210
        message_store = self.broker_service.message_store
196
211
        message_store.set_server_uuid("uuid")
197
 
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
198
 
        command_mock("lsb_release -cs")
199
 
        self.mocker.result("codename")
 
212
        self.handler.lsb_release_filename = self.makeFile(SAMPLE_LSB_RELEASE)
200
213
        self.facade.set_arch("arch")
201
214
 
202
215
        # The failure should be properly logged
235
248
        results = [Deferred() for i in range(3)]
236
249
 
237
250
        stash = []
 
251
 
238
252
        def handle_task(task):
239
253
            result = results[task.data]
240
254
            result.addCallback(lambda x: stash.append(task.data))
256
270
 
257
271
        results[0].callback(None)
258
272
        self.assertEquals(stash, [0, 1])
259
 
        self.assertFalse(handle_tasks_result.called)
 
273
        self.assertTrue(handle_tasks_result.called)
260
274
        self.assertEquals(self.store.get_next_task(queue_name).data, 2)
261
275
 
262
276
        results[2].callback(None)
272
286
 
273
287
        self.store.add_task(queue_name, 0)
274
288
 
275
 
        class MyException(Exception): pass
 
289
        class MyException(Exception):
 
290
            pass
276
291
 
277
292
        def handle_task(task):
278
293
            result = Deferred()
305
320
        # Prepare the mock objects.
306
321
        lock_path_mock = self.mocker.replace("landscape.lib.lock.lock_path",
307
322
                                             passthrough=False)
308
 
        install_mock = self.mocker.replace("twisted.internet."
309
 
                                           "glib2reactor.install")
 
323
        install_mock = self.mocker.replace("landscape.reactor.install")
310
324
        reactor_mock = self.mocker.replace("twisted.internet.reactor",
311
325
                                           passthrough=False)
312
326
        init_logging_mock = self.mocker.replace("landscape.deployment"
330
344
        # Once locking is done, it's safe to start logging without
331
345
        # corrupting the file.  We don't want any output unless it's
332
346
        # breaking badly, so the quiet option should be set.
333
 
        init_logging_mock(ISTYPE(Configuration), "package-default")
 
347
        init_logging_mock(ISTYPE(PackageTaskHandlerConfiguration),
 
348
                          "package-task-handler")
334
349
 
335
350
        # Then, it must create an instance of the TaskHandler subclass
336
351
        # passed in as a parameter.  We'll keep track of the arguments
337
352
        # given and verify them later.
338
353
        handler_args = []
339
 
        handler_mock = HandlerMock(ANY, ANY, ANY, ANY)
 
354
        HandlerMock(ANY, ANY, ANY, ANY)
340
355
        self.mocker.passthrough() # Let the real constructor run for testing.
341
356
        self.mocker.call(lambda *args: handler_args.extend(args))
342
357
 
343
 
        # Finally, the task handler must be run, and will return a deferred.
344
 
        # We'll return a real deferred so that we can call it back and test
345
 
        # whatever was hooked in as well.
346
 
        deferred = Deferred()
347
 
        handler_mock.run()
348
 
        self.mocker.result(deferred)
 
358
        to_call = []
 
359
        reactor_mock.callWhenRunning(ANY)
 
360
        self.mocker.call(lambda callback: to_call.append(callback))
349
361
 
350
362
        # With all of that done, the Twisted reactor must be run, so that
351
363
        # deferred tasks are correctly performed.
369
381
 
370
382
        try:
371
383
            # DO IT!
372
 
            result = run_task_handler(HandlerMock,
373
 
                                      ["--data-path", data_path,
374
 
                                       "--bus", "session"])
 
384
            run_task_handler(HandlerMock, ["--data-path", data_path,
 
385
                                           "--bus", "session"])
375
386
 
376
387
            # reactor.stop() wasn't run yet, so it must fail right now.
377
388
            self.assertRaises(AssertionError, self.mocker.verify)
378
389
 
379
390
            # DO THE REST OF IT! :-)
380
 
            result.callback(None)
 
391
            to_call[0]()
381
392
 
382
393
            # Are we there yet!?
383
394
            self.mocker.verify()
390
401
        # Verify if the arguments to the reporter constructor were correct.
391
402
        self.assertEquals(type(store), PackageStore)
392
403
        self.assertEquals(type(facade), SmartFacade)
393
 
        self.assertEquals(type(broker), RemoteBroker)
394
 
        self.assertEquals(type(config), Configuration)
 
404
        self.assertEquals(type(broker), LazyRemoteBroker)
 
405
        self.assertEquals(type(config), PackageTaskHandlerConfiguration)
395
406
 
396
407
        # Let's see if the store path is where it should be.
397
408
        filename = os.path.join(data_path, "package", "database")
406
417
    def test_run_task_handler_when_already_locked(self):
407
418
        data_path = self.makeDir()
408
419
 
409
 
        install_mock = self.mocker.replace("twisted.internet."
410
 
                                           "glib2reactor.install")
 
420
        install_mock = self.mocker.replace("landscape.reactor.install")
411
421
        install_mock()
412
422
 
413
423
        self.mocker.replay()
425
435
    def test_run_task_handler_when_already_locked_and_quiet_option(self):
426
436
        data_path = self.makeDir()
427
437
 
428
 
        install_mock = self.mocker.replace("twisted.internet."
429
 
                                           "glib2reactor.install")
 
438
        install_mock = self.mocker.replace("landscape.reactor.install")
430
439
        install_mock()
431
440
 
432
441
        self.mocker.replay()
444
453
 
445
454
    def test_errors_in_tasks_are_printed_and_exit_program(self):
446
455
        # Ignore a bunch of crap that we don't care about
447
 
        install_mock = self.mocker.replace("twisted.internet."
448
 
                                           "glib2reactor.install")
 
456
        install_mock = self.mocker.replace("landscape.reactor.install")
449
457
        install_mock()
450
458
        reactor_mock = self.mocker.proxy(reactor)
451
459
        init_logging_mock = self.mocker.replace("landscape.deployment"
481
489
            self.assertIn("MyException", self.logfile.getvalue())
482
490
 
483
491
        return done.addCallback(everything_stopped)
 
492
 
 
493
 
 
494
class LazyRemoteBrokerTest(LandscapeTest):
 
495
 
 
496
 
 
497
    def test_wb_is_lazy(self):
 
498
        """
 
499
        The L{LazyRemoteBroker} class doesn't initialize the actual remote
 
500
        broker until one of its attributes gets actually accessed.
 
501
        """
 
502
        self.broker = LazyRemoteBroker("bus")
 
503
        self.assertIdentical(self.broker._remote, None)
 
504
        get_bus_mock = self.mocker.replace("landscape.lib.dbus_util.get_bus")
 
505
        get_bus_mock("bus")
 
506
        self.mocker.result("bus_object")
 
507
        self.mocker.replay()
 
508
        self.assertEquals(self.broker.bus, "bus_object")