~registry/ubuntu-system-image/client

« back to all changes in this revision

Viewing changes to systemimage/tests/test_state.py

  • Committer: Barry Warsaw
  • Date: 2015-01-16 22:56:50 UTC
  • mfrom: (293.1.18 lp1373467)
  • Revision ID: barry@python.org-20150116225650-fug42a0rd33g3gb2
 * Support multiple configuration files, as in a ``config.d`` directory.  Now,
   configuration files are named `NN_whatever.ini` where "NN" must be a
   numeric prefix.  Files are loaded in sorted numeric order, with later files
   overriding newer files.  Support for both the ``client.ini`` and
   ``channel.ini`` files has been removed. (LP: #1373467)
 * The ``[system]build_file`` variable has been removed.  Build number
   information now must come from the ``.ini`` files, and last update date
   comes from the newest ``.ini`` file loaded.

Also:

 * Manpages updated.
 * Removed support for the [system]build_file variable.
 * Massive renaming of test data files for better matchup with their
   associated tests.
 * Provide a little more information when a logging level command line
   parameter is a bogus value.
 * -C now takes path to configuration directory.
 * Add a little more debug-level logging.
 * More sophistication for the @configuration decorator.
 * touch_build() helper now takes a use_config optional keyword argument.
 * When running the test suite, -M now takes a full logging specifier,
   e.g. either a single word like `debug` or a split like `info:debug`.
 * Skip some tests when running under UDM, due to LP: #1411866

Show diffs side-by-side

added added

removed removed

Lines of Context:
71
71
            self._serverdir = self._stack.enter_context(temporary_directory())
72
72
            self._stack.push(make_http_server(
73
73
                self._serverdir, 8943, 'cert.pem', 'key.pem'))
74
 
            copy('channels_01.json', self._serverdir, 'channels.json')
 
74
            copy('state.channels_07.json', self._serverdir, 'channels.json')
75
75
            self._channels_path = os.path.join(
76
76
                self._serverdir, 'channels.json')
77
77
        except:
386
386
class TestRebooting(ServerTestBase):
387
387
    """Test various state transitions leading to a reboot."""
388
388
 
389
 
    INDEX_FILE = 'index_13.json'
390
 
    CHANNEL_FILE = 'channels_06.json'
 
389
    INDEX_FILE = 'state.index_03.json'
 
390
    CHANNEL_FILE = 'state.channels_02.json'
391
391
    CHANNEL = 'stable'
392
392
    DEVICE = 'nexus7'
393
393
 
416
416
        self.assertFalse(os.path.exists(signing_path + '.asc'))
417
417
        self.assertFalse(os.path.exists(device_path + '.asc'))
418
418
        # None of the data files are found yet.
419
 
        for image in get_index('index_13.json').images:
 
419
        for image in get_index('state.index_03.json').images:
420
420
            for filerec in image.files:
421
421
                path = os.path.join(cache_dir, os.path.basename(filerec.path))
422
422
                asc = os.path.join(
441
441
        self.assertTrue(os.path.exists(signing_path + '.asc'))
442
442
        self.assertTrue(os.path.exists(device_path + '.asc'))
443
443
        # All of the data files are found.
444
 
        for image in get_index('index_13.json').images:
 
444
        for image in get_index('state.index_03.json').images:
445
445
            for filerec in image.files:
446
446
                path = os.path.join(cache_dir, os.path.basename(filerec.path))
447
447
                asc = os.path.join(
512
512
 
513
513
 
514
514
class TestRebootingNoDeviceSigning(ServerTestBase):
515
 
    INDEX_FILE = 'index_13.json'
516
 
    CHANNEL_FILE = 'channels_11.json'
 
515
    INDEX_FILE = 'state.index_03.json'
 
516
    CHANNEL_FILE = 'state.channels_03.json'
517
517
    CHANNEL = 'stable'
518
518
    DEVICE = 'nexus7'
519
519
    SIGNING_KEY = 'image-signing.gpg'
544
544
        self.assertFalse(os.path.exists(signing_path + '.asc'))
545
545
        self.assertFalse(os.path.exists(device_path + '.asc'))
546
546
        # None of the data files are found yet.
547
 
        for image in get_index('index_13.json').images:
 
547
        for image in get_index('state.index_03.json').images:
548
548
            for filerec in image.files:
549
549
                path = os.path.join(cache_dir, os.path.basename(filerec.path))
550
550
                asc = os.path.join(
570
570
        self.assertTrue(os.path.exists(signing_path + '.asc'))
571
571
        self.assertFalse(os.path.exists(device_path + '.asc'))
572
572
        # All of the data files are found.
573
 
        for image in get_index('index_13.json').images:
 
573
        for image in get_index('state.index_03.json').images:
574
574
            for filerec in image.files:
575
575
                path = os.path.join(cache_dir, os.path.basename(filerec.path))
576
576
                asc = os.path.join(
580
580
 
581
581
 
582
582
class TestCommandFileFull(ServerTestBase):
583
 
    INDEX_FILE = 'index_13.json'
584
 
    CHANNEL_FILE = 'channels_06.json'
 
583
    INDEX_FILE = 'state.index_03.json'
 
584
    CHANNEL_FILE = 'state.channels_02.json'
585
585
    CHANNEL = 'stable'
586
586
    DEVICE = 'nexus7'
587
587
 
628
628
 
629
629
 
630
630
class TestCommandFileDelta(ServerTestBase):
631
 
    INDEX_FILE = 'index_15.json'
632
 
    CHANNEL_FILE = 'channels_06.json'
 
631
    INDEX_FILE = 'state.index_04.json'
 
632
    CHANNEL_FILE = 'state.channels_02.json'
633
633
    CHANNEL = 'stable'
634
634
    DEVICE = 'nexus7'
635
635
 
656
656
 
657
657
 
658
658
class TestFileOrder(ServerTestBase):
659
 
    INDEX_FILE = 'index_16.json'
660
 
    CHANNEL_FILE = 'channels_06.json'
 
659
    INDEX_FILE = 'state.index_05.json'
 
660
    CHANNEL_FILE = 'state.channels_02.json'
661
661
    CHANNEL = 'stable'
662
662
    DEVICE = 'nexus7'
663
663
 
694
694
class TestDailyProposed(ServerTestBase):
695
695
    """Test that the daily-proposed channel works as expected."""
696
696
 
697
 
    INDEX_FILE = 'index_13.json'
698
 
    CHANNEL_FILE = 'channels_07.json'
 
697
    INDEX_FILE = 'state.index_03.json'
 
698
    CHANNEL_FILE = 'state.channels_04.json'
699
699
    CHANNEL = 'daily-proposed'
700
700
    DEVICE = 'grouper'
701
701
 
729
729
 
730
730
 
731
731
class TestVersionedProposed(ServerTestBase):
732
 
    INDEX_FILE = 'index_13.json'
733
 
    CHANNEL_FILE = 'channels_08.json'
 
732
    INDEX_FILE = 'state.index_03.json'
 
733
    CHANNEL_FILE = 'state.channels_05.json'
734
734
    CHANNEL = '14.04-proposed'
735
735
    DEVICE = 'grouper'
736
736
 
751
751
 
752
752
 
753
753
class TestFilters(ServerTestBase):
754
 
    INDEX_FILE = 'index_15.json'
755
 
    CHANNEL_FILE = 'channels_06.json'
 
754
    INDEX_FILE = 'state.index_04.json'
 
755
    CHANNEL_FILE = 'state.channels_02.json'
756
756
    CHANNEL = 'stable'
757
757
    DEVICE = 'nexus7'
758
758
 
779
779
 
780
780
 
781
781
class TestStateNewChannelsFormat(ServerTestBase):
782
 
    CHANNEL_FILE = 'channels_09.json'
 
782
    CHANNEL_FILE = 'state.channels_06.json'
783
783
    CHANNEL = 'saucy'
784
784
    DEVICE = 'manta'
785
 
    INDEX_FILE = 'index_21.json'
 
785
    INDEX_FILE = 'state.index_06.json'
786
786
 
787
787
    @configuration
788
 
    def test_full_reboot(self):
 
788
    def test_full_reboot(self, config_d):
789
789
        # Test that state transitions through reboot work for the new channel
790
790
        # format.  Also check that the right files get moved into place.
791
 
        config.load(data_path('channel_04.ini'), override=True)
 
791
        shutil.copy(data_path('state.channel_01.ini'),
 
792
                    os.path.join(config_d, '02_channel.ini'))
 
793
        config.reload()
792
794
        self._setup_server_keyrings()
793
795
        state = State()
794
796
        # Do not use self._resources to manage the check_output mock.  Because
820
822
 
821
823
 
822
824
class TestChannelAlias(ServerTestBase):
823
 
    CHANNEL_FILE = 'channels_10.json'
 
825
    CHANNEL_FILE = 'state.channels_01.json'
824
826
    CHANNEL = 'daily'
825
827
    DEVICE = 'manta'
826
 
    INDEX_FILE = 'index_20.json'
 
828
    INDEX_FILE = 'state.index_01.json'
827
829
 
828
830
    @configuration
829
 
    def test_channel_alias_switch(self):
 
831
    def test_channel_alias_switch(self, config_d):
830
832
        # Channels in the channel.json files can have an optional "alias" key,
831
833
        # which if set, describes the other channel this channel is based on
832
834
        # (only in a server-side generated way; the client sees all channels
833
835
        # as fully "stocked").
834
836
        #
835
 
        # The channel.ini file can have a channel_target key which names the
 
837
        # The [service] section can have a `channel_target` key which names the
836
838
        # channel alias this device has been tracking.  If the channel_target
837
839
        # does not match the channel alias, then the client considers its
838
840
        # internal version number to be 0 and does a full update.
848
850
        # upgrade from build number 0 to get on the right track.
849
851
        #
850
852
        # To test this condition, we calculate the upgrade path first in the
851
 
        # absence of a channels.ini file.  The device is tracking the daily
852
 
        # channel, and there isno channel_target attribute, so we get the
853
 
        # latest build on that channel.
 
853
        # absence of a [service]channel_target key.  The device is tracking the
 
854
        # daily channel, so we get the latest build on that channel.
854
855
        self._setup_server_keyrings()
855
856
        touch_build(300)
856
857
        config.channel = 'daily'
874
875
        # Set the build number back to 300 for the next test.
875
876
        del config.build_number
876
877
        touch_build(300)
877
 
        # Now we pretend there was a channel.ini file, and load it.  This also
878
 
        # tells us the current build number is 300, but through the
879
 
        # channel_target field it tells us that the previous daily channel
880
 
        # alias was saucy.  Now (via the channels.json file) it's tubular, and
881
 
        # the upgrade path starting at build 0 is different.
882
 
        config.load(data_path('channel_05.ini'), override=True)
 
878
        # Now we drop in a configuration file which sets the
 
879
        # [service]channel_target key.  This also tells us the current build
 
880
        # number is 300, but through the channel_target field it tells us that
 
881
        # the previous daily channel alias was saucy.  Now (via the
 
882
        # channels.json file) it's tubular, and the upgrade path starting at
 
883
        # build 0 is different.
 
884
        override_path = os.path.join(config_d, '02_override.ini')
 
885
        with open(override_path, 'w', encoding='utf-8') as fp:
 
886
            print('[service]\nchannel_target: saucy\n', file=fp)
 
887
        config.reload()
883
888
        # All things being equal to the first test above, except that now
884
889
        # we're in the middle of an alias switch.  The upgrade path is exactly
885
890
        # the same as if we were upgrading from build 0.
890
895
                         [200, 201, 304])
891
896
 
892
897
    @configuration
893
 
    def test_channel_alias_switch_with_cli_option(self):
 
898
    def test_channel_alias_switch_with_cli_option(self, config_d):
894
899
        # Like the above test, but in similating the use of `system-image-cli
895
900
        # --build 300`, we set the build number explicitly.  This prevent the
896
901
        # channel alias squashing of the build number to 0.
907
912
            state.run_thru('calculate_winner')
908
913
        self.assertEqual([image.version for image in state.winner],
909
914
                         [301, 304])
910
 
        # Now we pretend there was a channel.ini file, and load it.  This also
911
 
        # tells us the current build number is 300, but through the
912
 
        # channel_target field it tells us that the previous daily channel
913
 
        # alias was saucy.  Now (via the channels.json file) it's tubular.
914
 
        config.load(data_path('channel_05.ini'), override=True)
 
915
        # Now we have an override file.  This also tells us the current build
 
916
        # number is 300, but through the channel_target field it tells us that
 
917
        # the previous daily channel alias was saucy.  Now (via the
 
918
        # channels.json file) it's tubular.
 
919
        override_path = os.path.join(config_d, '02_override.ini')
 
920
        with open(override_path, 'w', encoding='utf-8') as fp:
 
921
            print("""\
 
922
[service]
 
923
channel_target: saucy
 
924
channeL: daily
 
925
build_number: 300
 
926
""", file=fp)
 
927
        config.reload()
915
928
        # All things being equal to the first test above, except that now
916
929
        # we're in the middle of an alias switch.  The upgrade path is exactly
917
930
        # the same as if we were upgrading from build 0.
921
934
        state.run_thru('calculate_winner')
922
935
        self.assertEqual([image.version for image in state.winner],
923
936
                         [200, 201, 304])
924
 
        # Finally, this mimic the effect of --build 300, thus giving us back
 
937
        # Finally, this mimics the effect of --build 300, thus giving us back
925
938
        # the original upgrade path.
926
939
        config.build_number = 300
927
940
        state = State()
931
944
 
932
945
 
933
946
class TestPhasedUpdates(ServerTestBase):
934
 
    CHANNEL_FILE = 'channels_10.json'
 
947
    CHANNEL_FILE = 'state.channels_01.json'
935
948
    CHANNEL = 'daily'
936
949
    DEVICE = 'manta'
937
 
    INDEX_FILE = 'index_22.json'
 
950
    INDEX_FILE = 'state.index_07.json'
938
951
 
939
952
    @configuration
940
953
    def test_inside_phased_updates_0(self):
1027
1040
 
1028
1041
 
1029
1042
class TestPhasedUpdatesPulled(ServerTestBase):
1030
 
    CHANNEL_FILE = 'channels_10.json'
 
1043
    CHANNEL_FILE = 'state.channels_01.json'
1031
1044
    CHANNEL = 'daily'
1032
1045
    DEVICE = 'manta'
1033
 
    INDEX_FILE = 'index_26.json'
 
1046
    INDEX_FILE = 'state.index_02.json'
1034
1047
 
1035
1048
    @configuration
1036
1049
    def test_pulled_update(self):
1089
1102
 
1090
1103
 
1091
1104
class TestCachedFiles(ServerTestBase):
1092
 
    CHANNEL_FILE = 'channels_11.json'
 
1105
    CHANNEL_FILE = 'state.channels_03.json'
1093
1106
    CHANNEL = 'stable'
1094
1107
    DEVICE = 'nexus7'
1095
 
    INDEX_FILE = 'index_13.json'
 
1108
    INDEX_FILE = 'state.index_03.json'
1096
1109
    SIGNING_KEY = 'image-signing.gpg'
1097
1110
 
1098
1111
    @configuration
1449
1462
 
1450
1463
 
1451
1464
class TestKeyringDoubleChecks(ServerTestBase):
1452
 
    CHANNEL_FILE = 'channels_11.json'
 
1465
    CHANNEL_FILE = 'state.channels_03.json'
1453
1466
    CHANNEL = 'stable'
1454
1467
    DEVICE = 'nexus7'
1455
 
    INDEX_FILE = 'index_13.json'
 
1468
    INDEX_FILE = 'state.index_03.json'
1456
1469
    SIGNING_KEY = 'image-signing.gpg'
1457
1470
 
1458
1471
    @configuration
1617
1630
class TestStateDuplicateDestinations(ServerTestBase):
1618
1631
    """An index.json with duplicate destination files is broken."""
1619
1632
 
1620
 
    INDEX_FILE = 'index_23.json'
1621
 
    CHANNEL_FILE = 'channels_06.json'
 
1633
    INDEX_FILE = 'state.index_08.json'
 
1634
    CHANNEL_FILE = 'state.channels_02.json'
1622
1635
    CHANNEL = 'stable'
1623
1636
    DEVICE = 'nexus7'
1624
1637
 
1625
1638
    @configuration
1626
1639
    def test_duplicate_destinations(self):
1627
 
        # index_23.json has the bug we saw in the wild in LP: #1250181.
 
1640
        # state.index_08.json has the bug we saw in the wild in LP: #1250181.
1628
1641
        # There, the server erroneously included a data file twice in two
1629
1642
        # different images.  This can't happen and indicates a server
1630
1643
        # problem.  The client must refuse to upgrade in this case, by raising
1652
1665
class TestMiscellaneous(ServerTestBase):
1653
1666
    """Test a few additional things for full code coverage."""
1654
1667
 
1655
 
    INDEX_FILE = 'index_13.json'
1656
 
    CHANNEL_FILE = 'channels_06.json'
 
1668
    INDEX_FILE = 'state.index_03.json'
 
1669
    CHANNEL_FILE = 'state.channels_02.json'
1657
1670
    CHANNEL = 'stable'
1658
1671
    DEVICE = 'nexus7'
1659
1672