~ubuntu-branches/ubuntu/lucid/landscape-client/lucid-updates-201411191716

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug, Free Ekanayaka
  • Date: 2009-07-22 14:54:50 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090722145450-pvbp13gh8734c8ft
Tags: 1.3.2.2-0ubuntu0.9.10.1
[ Free Ekanayaka ]
* New upstream release:
  - Include the README file in landscape-client (LP: #396260)
  - Fix client capturing stderr from run_command when constructing
    hash-id-databases url (LP: #397480)
  - Use substvars to conditionally depend on update-motd or
    libpam-modules (LP: #393454)
  - Fix reporting wrong version to the server (LP: #391225)
  - The init script does not wait for the network to be available
    before checking for EC2 user data (LP: #383336)
  - When the broker is restarted by the watchdog, the state of the client
    is inconsistent (LP: #380633)
  - Package stays unknown forever in the client with hash-id-databases
    support (LP: #381356)
  - Standard error not captured when calling smart-update (LP: #387441)
  - Changer calls reporter without switching groups, just user (LP: #388092)
  - Run smart update in the package-reporter instead of having a cronjob (LP: #362355)
  - Package changer does not inherit proxy settings (LP: #381241)
  - The ./test script doesn't work in landscape-client (LP: #381613)
  - The source package should build on all supported releases (LP: #385098)
  - Strip smart update's output (LP: #387331)
  - The fetch() timeout isn't based on activity (#389224)
  - Client can use a UUID of "None" when fetching the hash-id-database (LP: #381291)
  - Registration should use the fqdn rather than just the hostname (LP: #385730)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
import glob
2
2
import sys
3
3
import os
 
4
import logging
4
5
 
5
6
from twisted.internet.defer import Deferred
 
7
from twisted.internet import reactor
6
8
 
7
 
from landscape.lib.lock import lock_path
 
9
from landscape.lib.fetch import fetch_async, FetchError
 
10
from landscape.lib.command import CommandError
8
11
 
9
12
from landscape.package.store import PackageStore, UnknownHashIDRequest
10
13
from landscape.package.reporter import (
12
15
from landscape.package import reporter
13
16
from landscape.package.facade import SmartFacade
14
17
 
 
18
from landscape.deployment import Configuration
15
19
from landscape.broker.remote import RemoteBroker
16
20
 
17
21
from landscape.package.tests.helpers import (
30
34
        super(PackageReporterTest, self).setUp()
31
35
 
32
36
        self.store = PackageStore(self.makeFile())
33
 
        self.reporter = PackageReporter(self.store, self.facade, self.remote)
 
37
        self.config = Configuration()
 
38
        self.reporter = PackageReporter(self.store, self.facade, self.remote, self.config)
34
39
 
35
40
    def set_pkg2_upgrades_pkg1(self):
36
41
        previous = self.Facade.channels_reloaded
219
224
        deferred = self.reporter.handle_tasks()
220
225
        return deferred.addCallback(got_result)
221
226
 
 
227
    def test_fetch_hash_id_db(self):
 
228
 
 
229
        # Assume package_hash_id_url is set
 
230
        self.config.data_path = self.makeDir()
 
231
        self.config.package_hash_id_url = "http://fake.url/path/"
 
232
        os.makedirs(os.path.join(self.config.data_path, "package", "hash-id"))
 
233
        hash_id_db_filename = os.path.join(self.config.data_path, "package",
 
234
                                           "hash-id", "uuid_codename_arch")
 
235
 
 
236
        # Fake uuid, codename and arch
 
237
        message_store = self.broker_service.message_store
 
238
        message_store.set_server_uuid("uuid")
 
239
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
 
240
        command_mock("lsb_release -cs")
 
241
        self.mocker.result("codename")
 
242
        self.facade.set_arch("arch")
 
243
 
 
244
        # Let's say fetch_async is successful
 
245
        hash_id_db_url = self.config.package_hash_id_url + "uuid_codename_arch"
 
246
        fetch_async_mock = self.mocker.replace("landscape.lib.fetch.fetch_async")
 
247
        fetch_async_mock(hash_id_db_url)
 
248
        fetch_async_result = Deferred()
 
249
        fetch_async_result.callback("hash-ids")
 
250
        self.mocker.result(fetch_async_result)
 
251
 
 
252
        # The download should be properly logged
 
253
        logging_mock = self.mocker.replace("logging.info")
 
254
        logging_mock("Downloaded hash=>id database from %s" % hash_id_db_url)
 
255
        self.mocker.result(None)
 
256
 
 
257
        # We don't have our hash=>id database yet
 
258
        self.assertFalse(os.path.exists(hash_id_db_filename))
 
259
 
 
260
        # Now go!
 
261
        self.mocker.replay()
 
262
        result = self.reporter.fetch_hash_id_db()
 
263
 
 
264
        # Check the database
 
265
        def callback(ignored):
 
266
            self.assertTrue(os.path.exists(hash_id_db_filename))
 
267
            self.assertEquals(open(hash_id_db_filename).read(), "hash-ids")
 
268
        result.addCallback(callback)
 
269
 
 
270
        return result
 
271
 
 
272
    def test_fetch_hash_id_db_does_not_download_twice(self):
 
273
 
 
274
        # Let's say that the hash=>id database is already there
 
275
        self.config.package_hash_id_url = "http://fake.url/path/"
 
276
        self.config.data_path = self.makeDir()
 
277
        os.makedirs(os.path.join(self.config.data_path, "package", "hash-id"))
 
278
        hash_id_db_filename = os.path.join(self.config.data_path, "package",
 
279
                                           "hash-id", "uuid_codename_arch")
 
280
        open(hash_id_db_filename, "w").write("test")
 
281
 
 
282
        # Fake uuid, codename and arch
 
283
        message_store = self.broker_service.message_store
 
284
        message_store.set_server_uuid("uuid")
 
285
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
 
286
        command_mock("lsb_release -cs")
 
287
        self.mocker.result("codename")
 
288
        self.facade.set_arch("arch")
 
289
 
 
290
        # Intercept any call to fetch_async
 
291
        fetch_async_mock = self.mocker.replace("landscape.lib.fetch.fetch_async")
 
292
        fetch_async_mock(ANY)
 
293
 
 
294
        # Go!
 
295
        self.mocker.replay()
 
296
        result = self.reporter.fetch_hash_id_db()
 
297
 
 
298
        def callback(ignored):
 
299
            # Check that fetch_async hasn't been called
 
300
            self.assertRaises(AssertionError, self.mocker.verify)
 
301
            fetch_async(None)
 
302
 
 
303
            # The hash=>id database is still there
 
304
            self.assertEquals(open(hash_id_db_filename).read(), "test")
 
305
 
 
306
        result.addCallback(callback)
 
307
 
 
308
        return result
 
309
 
 
310
    def test_fetch_hash_id_db_undetermined_server_uuid(self):
 
311
        """
 
312
        If the server-uuid can't be determined for some reason, no download
 
313
        should be attempted and the failure should be properly logged.
 
314
        """
 
315
        message_store = self.broker_service.message_store
 
316
        message_store.set_server_uuid(None)
 
317
 
 
318
        logging_mock = self.mocker.replace("logging.warning")
 
319
        logging_mock("Couldn't determine which hash=>id database to use: "
 
320
                     "server UUID not available")
 
321
        self.mocker.result(None)
 
322
        self.mocker.replay()
 
323
 
 
324
        result = self.reporter.fetch_hash_id_db()
 
325
        return result
 
326
 
 
327
    def test_fetch_hash_id_db_undetermined_codename(self):
 
328
 
 
329
        # Fake uuid
 
330
        message_store = self.broker_service.message_store
 
331
        message_store.set_server_uuid("uuid")
 
332
 
 
333
        # Undetermined codename
 
334
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
 
335
        command_mock("lsb_release -cs")
 
336
        command_error = CommandError("lsb_release -cs", 1, "error")
 
337
        self.mocker.throw(command_error)
 
338
 
 
339
        # The failure should be properly logged
 
340
        logging_mock = self.mocker.replace("logging.warning")
 
341
        logging_mock("Couldn't determine which hash=>id database to use: %s" %
 
342
                     str(command_error))
 
343
        self.mocker.result(None)
 
344
 
 
345
        # Go!
 
346
        self.mocker.replay()
 
347
        result = self.reporter.fetch_hash_id_db()
 
348
 
 
349
        return result
 
350
 
 
351
    def test_fetch_hash_id_db_undetermined_arch(self):
 
352
 
 
353
        # Fake uuid and codename
 
354
        message_store = self.broker_service.message_store
 
355
        message_store.set_server_uuid("uuid")
 
356
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
 
357
        command_mock("lsb_release -cs")
 
358
        self.mocker.result("codename")
 
359
 
 
360
        # Undetermined arch
 
361
        self.facade.set_arch(None)
 
362
 
 
363
        # The failure should be properly logged
 
364
        logging_mock = self.mocker.replace("logging.warning")
 
365
        logging_mock("Couldn't determine which hash=>id database to use: "\
 
366
                     "unknown dpkg architecture")
 
367
        self.mocker.result(None)
 
368
 
 
369
        # Go!
 
370
        self.mocker.replay()
 
371
        result = self.reporter.fetch_hash_id_db()
 
372
 
 
373
        return result
 
374
 
 
375
    def test_fetch_hash_id_db_with_default_url(self):
 
376
 
 
377
        # Let's say package_hash_id_url is not set but url is
 
378
        self.config.data_path = self.makeDir()
 
379
        self.config.package_hash_id_url = None
 
380
        self.config.url = "http://fake.url/path/message-system/"
 
381
        os.makedirs(os.path.join(self.config.data_path, "package", "hash-id"))
 
382
        hash_id_db_filename = os.path.join(self.config.data_path, "package",
 
383
                                           "hash-id", "uuid_codename_arch")
 
384
 
 
385
        # Fake uuid, codename and arch
 
386
        message_store = self.broker_service.message_store
 
387
        message_store.set_server_uuid("uuid")
 
388
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
 
389
        command_mock("lsb_release -cs")
 
390
        self.mocker.result("codename")
 
391
        self.facade.set_arch("arch")
 
392
 
 
393
        # Check fetch_async is called with the default url
 
394
        hash_id_db_url = "http://fake.url/path/hash-id-databases/" \
 
395
                         "uuid_codename_arch"
 
396
        fetch_async_mock = self.mocker.replace("landscape.lib.fetch.fetch_async")
 
397
        fetch_async_mock(hash_id_db_url)
 
398
        fetch_async_result = Deferred()
 
399
        fetch_async_result.callback("hash-ids")
 
400
        self.mocker.result(fetch_async_result)
 
401
 
 
402
        # Now go!
 
403
        self.mocker.replay()
 
404
        result = self.reporter.fetch_hash_id_db()
 
405
 
 
406
        # Check the database
 
407
        def callback(ignored):
 
408
            self.assertTrue(os.path.exists(hash_id_db_filename))
 
409
            self.assertEquals(open(hash_id_db_filename).read(), "hash-ids")
 
410
        result.addCallback(callback)
 
411
        return result
 
412
 
 
413
    def test_fetch_hash_id_db_with_download_error(self):
 
414
 
 
415
        # Assume package_hash_id_url is set
 
416
        self.config.data_path = self.makeDir()
 
417
        self.config.package_hash_id_url = "http://fake.url/path/"
 
418
 
 
419
        # Fake uuid, codename and arch
 
420
        message_store = self.broker_service.message_store
 
421
        message_store.set_server_uuid("uuid")
 
422
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
 
423
        command_mock("lsb_release -cs")
 
424
        self.mocker.result("codename")
 
425
        self.facade.set_arch("arch")
 
426
 
 
427
        # Let's say fetch_async fails
 
428
        hash_id_db_url = self.config.package_hash_id_url + "uuid_codename_arch"
 
429
        fetch_async_mock = self.mocker.replace("landscape.lib.fetch.fetch_async")
 
430
        fetch_async_mock(hash_id_db_url)
 
431
        fetch_async_result = Deferred()
 
432
        fetch_async_result.errback(FetchError("fetch error"))
 
433
        self.mocker.result(fetch_async_result)
 
434
 
 
435
        # The failure should be properly logged
 
436
        logging_mock = self.mocker.replace("logging.warning")
 
437
        logging_mock("Couldn't download hash=>id database: fetch error")
 
438
        self.mocker.result(None)
 
439
 
 
440
        # Now go!
 
441
        self.mocker.replay()
 
442
        result = self.reporter.fetch_hash_id_db()
 
443
 
 
444
        # We shouldn't have any hash=>id database
 
445
        def callback(ignored):
 
446
            hash_id_db_filename = os.path.join(self.config.data_path, "package",
 
447
                                               "hash-id", "uuid_codename_arch")
 
448
            self.assertEquals(os.path.exists(hash_id_db_filename), False)
 
449
        result.addCallback(callback)
 
450
 
 
451
        return result
 
452
 
 
453
    def test_fetch_hash_id_db_with_undetermined_url(self):
 
454
 
 
455
        # We don't know where to fetch the hash=>id database from
 
456
        self.config.url = None
 
457
        self.config.package_hash_id_url = None
 
458
 
 
459
        # Fake uuid, codename and arch
 
460
        message_store = self.broker_service.message_store
 
461
        message_store.set_server_uuid("uuid")
 
462
        command_mock = self.mocker.replace("landscape.lib.command.run_command")
 
463
        command_mock("lsb_release -cs")
 
464
        self.mocker.result("codename")
 
465
        self.facade.set_arch("arch")
 
466
 
 
467
        # The failure should be properly logged
 
468
        logging_mock = self.mocker.replace("logging.warning")
 
469
        logging_mock("Can't determine the hash=>id database url")
 
470
        self.mocker.result(None)
 
471
 
 
472
        # Let's go
 
473
        self.mocker.replay()
 
474
 
 
475
        result = self.reporter.fetch_hash_id_db()
 
476
 
 
477
        # We shouldn't have any hash=>id database
 
478
        def callback(ignored):
 
479
            hash_id_db_filename = os.path.join(self.config.data_path, "package",
 
480
                                               "hash-id", "uuid_codename_arch")
 
481
            self.assertEquals(os.path.exists(hash_id_db_filename), False)
 
482
        result.addCallback(callback)
 
483
 
 
484
        return result
 
485
 
 
486
    def test_run_smart_update(self):
 
487
        """
 
488
        The L{PackageReporter.run_smart_update} method should run smart-update
 
489
        with the proper arguments.
 
490
        """
 
491
        self.reporter.smart_update_filename = self.makeFile(
 
492
            "#!/bin/sh\necho -n $@")
 
493
        os.chmod(self.reporter.smart_update_filename, 0755)
 
494
        logging_mock = self.mocker.replace("logging.debug")
 
495
        logging_mock("'%s' exited with status 0 (out='--after %d', err=''" % (
 
496
            self.reporter.smart_update_filename,
 
497
            self.reporter.smart_update_interval))
 
498
        self.mocker.replay()
 
499
        deferred = Deferred()
 
500
 
 
501
        def do_test():
 
502
            def raiseme(x):
 
503
                raise Exception
 
504
            logging.warning = raiseme
 
505
            result = self.reporter.run_smart_update()
 
506
            def callback((out, err, code)):
 
507
                interval = self.reporter.smart_update_interval
 
508
                self.assertEquals(out, "--after %d" % interval)
 
509
                self.assertEquals(err, "")
 
510
                self.assertEquals(code, 0)
 
511
            result.addCallback(callback)
 
512
            result.chainDeferred(deferred)
 
513
 
 
514
        reactor.callWhenRunning(do_test)
 
515
        return deferred
 
516
 
 
517
    def test_run_smart_update_warns_about_failures(self):
 
518
        """
 
519
        The L{PackageReporter.run_smart_update} method should log a warning
 
520
        in case smart-update terminates with a non-zero exit code other than 1.
 
521
        """
 
522
        self.reporter.smart_update_filename = self.makeFile(
 
523
            "#!/bin/sh\necho -n error >&2\necho -n output\nexit 2")
 
524
        os.chmod(self.reporter.smart_update_filename, 0755)
 
525
        logging_mock = self.mocker.replace("logging.warning")
 
526
        logging_mock("'%s' exited with status 2"
 
527
                     " (error)" % self.reporter.smart_update_filename)
 
528
        self.mocker.replay()
 
529
        deferred = Deferred()
 
530
 
 
531
        def do_test():
 
532
            result = self.reporter.run_smart_update()
 
533
            def callback((out, err, code)):
 
534
                interval = self.reporter.smart_update_interval
 
535
                self.assertEquals(out, "output")
 
536
                self.assertEquals(err, "error")
 
537
                self.assertEquals(code, 2)
 
538
            result.addCallback(callback)
 
539
            result.chainDeferred(deferred)
 
540
 
 
541
        reactor.callWhenRunning(do_test)
 
542
        return deferred
 
543
 
 
544
    def test_run_smart_update_warns_exit_code_1_and_non_empty_stderr(self):
 
545
        """
 
546
        The L{PackageReporter.run_smart_update} method should log a warning
 
547
        in case smart-update terminates with exit code 1 and non empty stderr.
 
548
        """
 
549
        self.reporter.smart_update_filename = self.makeFile(
 
550
            "#!/bin/sh\necho -n \"error  \" >&2\nexit 1")
 
551
        os.chmod(self.reporter.smart_update_filename, 0755)
 
552
        logging_mock = self.mocker.replace("logging.warning")
 
553
        logging_mock("'%s' exited with status 1"
 
554
                     " (error  )" % self.reporter.smart_update_filename)
 
555
        self.mocker.replay()
 
556
        deferred = Deferred()
 
557
        def do_test():
 
558
            result = self.reporter.run_smart_update()
 
559
            def callback((out, err, code)):
 
560
                interval = self.reporter.smart_update_interval
 
561
                self.assertEquals(out, "")
 
562
                self.assertEquals(err, "error  ")
 
563
                self.assertEquals(code, 1)
 
564
            result.addCallback(callback)
 
565
            result.chainDeferred(deferred)
 
566
 
 
567
        reactor.callWhenRunning(do_test)
 
568
        return deferred
 
569
 
 
570
    def test_run_smart_update_ignores_exit_code_1_and_empty_output(self):
 
571
        """
 
572
        The L{PackageReporter.run_smart_update} method should not log anything
 
573
        in case smart-update terminates with exit code 1 and output containing
 
574
        only a newline character.
 
575
        """
 
576
        self.reporter.smart_update_filename = self.makeFile(
 
577
            "#!/bin/sh\necho\nexit 1")
 
578
        os.chmod(self.reporter.smart_update_filename, 0755)
 
579
        deferred = Deferred()
 
580
        def do_test():
 
581
            def raiseme(x):
 
582
                raise Exception
 
583
            logging.warning = raiseme
 
584
            result = self.reporter.run_smart_update()
 
585
            def callback((out, err, code)):
 
586
                interval = self.reporter.smart_update_interval
 
587
                self.assertEquals(out, "\n")
 
588
                self.assertEquals(err, "")
 
589
                self.assertEquals(code, 1)
 
590
            result.addCallback(callback)
 
591
            result.chainDeferred(deferred)
 
592
 
 
593
        reactor.callWhenRunning(do_test)
 
594
        return deferred
 
595
 
222
596
    def test_remove_expired_hash_id_request(self):
223
597
        request = self.store.add_hash_id_request(["hash1"])
224
598
        request.message_id = 9999
569
943
 
570
944
        self.mocker.order()
571
945
 
572
 
        results = [Deferred() for i in range(4)]
 
946
        results = [Deferred() for i in range(7)]
 
947
 
 
948
        reporter_mock.run_smart_update()
 
949
        self.mocker.result(results[0])
 
950
 
 
951
        reporter_mock.fetch_hash_id_db()
 
952
        self.mocker.result(results[1])
 
953
 
 
954
        reporter_mock.use_hash_id_db()
 
955
        self.mocker.result(results[2])
573
956
 
574
957
        reporter_mock.handle_tasks()
575
 
        self.mocker.result(results[0])
 
958
        self.mocker.result(results[3])
576
959
 
577
960
        reporter_mock.remove_expired_hash_id_requests()
578
 
        self.mocker.result(results[1])
 
961
        self.mocker.result(results[4])
579
962
 
580
963
        reporter_mock.request_unknown_hashes()
581
 
        self.mocker.result(results[2])
 
964
        self.mocker.result(results[5])
582
965
 
583
966
        reporter_mock.detect_changes()
584
 
        self.mocker.result(results[3])
 
967
        self.mocker.result(results[6])
585
968
 
586
969
        self.mocker.replay()
587
970