def test_list_plugins_non_tty(self): self.maxDiff = None fake_terminal = fixture_setup.FakeTerminal(isatty=False) self.useFixture(fake_terminal) main([self.command_name]) self.assertEqual(fake_terminal.getvalue(), self.default_plugin_output)
def test_configure_must_support_no_tty(self): self.fake_terminal = fixture_setup.FakeTerminal(isatty=False) self.useFixture(self.fake_terminal) logger_name = self.id() log.configure(logger_name, log_level=logging.DEBUG) logger = logging.getLogger(logger_name) logger.debug('Test debug') logger.info('Test info') logger.warning('Test warning') logger.error('Test error') logger.critical('Test critical') stdout = self.fake_terminal.getvalue() self.assertThat(stdout, Contains('Test debug')) self.assertThat(stdout, Contains('Test info')) self.assertThat(stdout, Not(Contains(self.info_color))) self.assertThat(stdout, Contains('Test warning')) self.assertThat(stdout, Not(Contains(self.warning_color))) self.assertThat(stdout, Not(Contains('\033[0m'))) stderr = self.fake_terminal.getvalue(stderr=True) self.assertThat(stderr, Contains('Test error')) self.assertThat(stderr, Not(Contains(self.error_color))) self.assertThat(stderr, Contains('Test critical')) self.assertThat(stderr, Not(Contains(self.critical_color)))
def test_push_revision_uses_available_delta(self): self.useFixture(fixture_setup.FakeTerminal()) if self.enable_deltas: self.useFixture(fixture_setup.DeltaUploads()) # Create a source snap main(['init']) main(['snap']) snap_file = glob.glob('*.snap')[0] # Upload with mock.patch('snapcraft.storeapi.StatusTracker'): main(['push', snap_file]) # create an additional snap, potentially a delta target main(['snap']) new_snap_file = glob.glob('*.snap')[0] # Upload with mock.patch('snapcraft.storeapi.StatusTracker'): main(['push', new_snap_file]) _, kwargs = self.mock_upload.call_args if self.enable_deltas: self.assertEqual(kwargs.get('delta_format'), 'xdelta3') else: self.assertIsNone(kwargs.get('delta_format'))
def test_push_revision_cached_with_experimental_deltas(self): self.useFixture(fixture_setup.FakeTerminal()) if self.enable_deltas: self.useFixture(fixture_setup.DeltaUploads()) # Create a snap main(['init']) main(['snap']) snap_file = glob.glob('*.snap')[0] # Upload with mock.patch('snapcraft.storeapi.StatusTracker'): main(['push', snap_file]) snap_cache = os.path.join( BaseDirectory.xdg_cache_home, 'snapcraft', 'projects', 'my-snap-name', 'snap_hashes', self.deb_arch, ) cached_snap = os.path.join(snap_cache, file_utils.calculate_sha3_384(snap_file)) if self.enable_deltas: self.assertThat(cached_snap, FileExists()) else: self.assertThat(cached_snap, Not(FileExists()))
def test_push_a_snap(self): self.useFixture(fixture_setup.FakeTerminal()) mock_tracker = mock.Mock(storeapi.StatusTracker) mock_tracker.track.return_value = { 'code': 'ready_to_release', 'processed': True, 'can_release': True, 'url': '/fake/url', 'revision': 9, } patcher = mock.patch.object(storeapi.StoreClient, 'upload') mock_upload = patcher.start() self.addCleanup(patcher.stop) mock_upload.return_value = mock_tracker # Create a snap main(['init']) main(['snap']) snap_file = glob.glob('*.snap')[0] # Upload with mock.patch('snapcraft.storeapi.StatusTracker') as mock_tracker: main(['push', snap_file]) self.assertRegexpMatches( self.fake_logger.output, ".*Pushing 'my-snap-name_0\.1_\w*.snap' to the store\.\n" "Revision 9 of 'my-snap-name' created\.", ) mock_upload.assert_called_once_with('my-snap-name', snap_file)
def test_push_unregistered_snap_must_raise_exception(self): self.useFixture(fixture_setup.FakeTerminal()) class MockResponse: status_code = 404 error_list = [{ 'code': 'resource-not-found', 'message': 'Snap not found for name=my-snap-name' }] patcher = mock.patch.object(storeapi.StoreClient, 'push_precheck') mock_precheck = patcher.start() self.addCleanup(patcher.stop) mock_precheck.side_effect = StorePushError('my-snap-name', MockResponse()) # Create a snap main(['init']) main(['snap']) snap_file = glob.glob('*.snap')[0] self.assertRaises(SystemExit, main, ['push', snap_file]) self.assertIn( 'You are not the publisher or allowed to push revisions for this ' 'snap. To become the publisher, run `snapcraft register ' 'my-snap-name` and try to push again.', self.fake_logger.output)
def test_status_by_series(self, mock_account_api, mock_status): fake_terminal = fixture_setup.FakeTerminal() self.useFixture(fake_terminal) mock_status.return_value = { 'channel_map_tree': { 'latest': { '16': self.expected } } } main(['status', 'snap-test', '--series=16']) mock_status.assert_called_once_with('snap-test', '16', None) terminal_output = fake_terminal.getvalue() expected_output = [ 'Track Arch Channel Version Revision', 'latest amd64 stable 1.0-amd64 2', ' beta 1.1-amd64 4', ' edge ^ ^', ' i386 stable - -', ' beta - -', ' edge 1.0-i386 3' ] self.assertEqual(expected_output, terminal_output.splitlines())
def setUp(self): super().setUp() temp_cwd_fixture = fixture_setup.TempCWD() self.useFixture(temp_cwd_fixture) self.path = temp_cwd_fixture.path self.useFixture(fixture_setup.TempXDG(self.path)) self.fake_terminal = fixture_setup.FakeTerminal() self.useFixture(self.fake_terminal) # Some tests will directly or indirectly change the plugindir, which # is a module variable. Make sure that it is returned to the original # value when a test ends. self.addCleanup(common.set_plugindir, common.get_plugindir()) self.addCleanup(common.set_schemadir, common.get_schemadir()) self.addCleanup(common.set_librariesdir, common.get_librariesdir()) self.addCleanup(common.set_tourdir, common.get_tourdir()) self.addCleanup(common.reset_env) common.set_schemadir(os.path.join(__file__, '..', '..', '..', 'schema')) self.useFixture(fixtures.FakeLogger(level=logging.ERROR)) patcher = mock.patch('multiprocessing.cpu_count') self.cpu_count = patcher.start() self.cpu_count.return_value = 2 self.addCleanup(patcher.stop) patcher = mock.patch('snapcraft.internal.indicators.ProgressBar', new=SilentProgressBar) patcher.start() self.addCleanup(patcher.stop) # These are what we expect by default self.snap_dir = os.path.join(os.getcwd(), 'prime') self.stage_dir = os.path.join(os.getcwd(), 'stage') self.parts_dir = os.path.join(os.getcwd(), 'parts') self.local_plugins_dir = os.path.join(self.parts_dir, 'plugins')
def test_upload_raises_deprecation_warning(self): self.useFixture(fixture_setup.FakeTerminal()) mock_tracker = mock.Mock(storeapi.StatusTracker) mock_tracker.track.return_value = { 'code': 'ready_to_release', 'processed': True, 'can_release': True, 'url': '/fake/url', 'revision': 9, } patcher = mock.patch.object(storeapi.StoreClient, 'upload') mock_upload = patcher.start() self.addCleanup(patcher.stop) mock_upload.return_value = mock_tracker # Create a snap main(['init']) main(['snap']) snap_file = glob.glob('*.snap')[0] # Upload with mock.patch('snapcraft.storeapi.StatusTracker') as mock_tracker: main(['upload', snap_file]) self.assertIn( 'Uploading my-snap_0_amd64.snap.\n' 'Revision 9 of \'my-snap\' created.', self.fake_logger.output) mock_upload.assert_called_once_with('my-snap', snap_file)
def test_list_plugins_large_terminal(self): self.maxDiff = None fake_terminal = fixture_setup.FakeTerminal(columns=999) self.useFixture(fake_terminal) main([self.command_name]) self.assertEqual(fake_terminal.getvalue(), self.default_plugin_output)
def test_push_revision_prune_snap_cache(self): self.useFixture(fixture_setup.FakeTerminal()) self.useFixture(fixture_setup.DeltaUploads()) snap_revision = 9 patcher = mock.patch('snapcraft.storeapi.StoreClient.push_precheck') patcher.start() self.addCleanup(patcher.stop) patcher = mock.patch.object(storeapi.StoreClient, 'get_snap_history') mock_release = patcher.start() self.addCleanup(patcher.stop) mock_release.return_value = [snap_revision] mock_tracker = mock.Mock(storeapi.StatusTracker) mock_tracker.track.return_value = { 'code': 'ready_to_release', 'processed': True, 'can_release': True, 'url': '/fake/url', 'revision': snap_revision, } patcher = mock.patch.object(storeapi.StoreClient, 'upload') mock_upload = patcher.start() self.addCleanup(patcher.stop) mock_upload.return_value = mock_tracker deb_arch = snapcraft.ProjectOptions().deb_arch snap_cache = os.path.join(BaseDirectory.xdg_cache_home, 'snapcraft', 'projects', 'my-snap-name', 'snap_hashes', deb_arch) os.makedirs(snap_cache) for cached_snap in self.cached_snaps: cached_snap = cached_snap.format(deb_arch) open(os.path.join(snap_cache, cached_snap), 'a').close() # Create a snap main(['init']) main(['snap']) snap_file = glob.glob('*.snap')[0] # Upload with mock.patch('snapcraft.storeapi.StatusTracker'): main(['push', snap_file]) real_cached_snap = os.path.join( snap_cache, file_utils.calculate_sha3_384(snap_file)) self.assertThat(os.path.join(snap_cache, real_cached_snap), FileExists()) for snap in self.cached_snaps: snap = snap.format(deb_arch) self.assertThat(os.path.join(snap_cache, snap), Not(FileExists())) self.assertEqual(1, len(os.listdir(snap_cache)))
def test_push_and_release_a_snap_to_N_channels(self): self.useFixture(fixture_setup.FakeTerminal()) mock_tracker = mock.Mock(storeapi.StatusTracker) mock_tracker.track.return_value = { 'code': 'ready_to_release', 'processed': True, 'can_release': True, 'url': '/fake/url', 'revision': 9, } patcher = mock.patch.object(storeapi.StoreClient, 'upload') mock_upload = patcher.start() self.addCleanup(patcher.stop) mock_upload.return_value = mock_tracker patcher = mock.patch.object(storeapi.StoreClient, 'release') mock_release = patcher.start() self.addCleanup(patcher.stop) mock_release.return_value = { 'opened_channels': ['beta,edge,candidate'], 'channel_map_tree': { 'latest': { '16': { 'amd64': [ {'channel': 'stable', 'info': 'none'}, {'revision': 9, 'channel': 'candidate', 'version': '0', 'info': 'specific'}, {'revision': 9, 'channel': 'beta', 'version': '0', 'info': 'specific'}, {'revision': 9, 'channel': 'edge', 'version': '0', 'info': 'specific'}, ] } } } } # Create a snap main(['init']) main(['snap']) snap_file = glob.glob('*.snap')[0] # Upload with mock.patch('snapcraft.storeapi.StatusTracker') as mock_tracker: main(['push', snap_file, '--release', 'edge,beta,candidate']) self.assertRegexpMatches( self.fake_logger.output, ".*Pushing 'my-snap-name_0\.1_\w*.snap\' to the store\.\n" "Revision 9 of 'my-snap-name' created\.\n" "The 'beta,edge,candidate' channel is now open\.\n" ) mock_upload.assert_called_once_with('my-snap-name', snap_file) mock_release.assert_called_once_with('my-snap-name', 9, ['edge', 'beta', 'candidate'])
def test_prune_snap_cache(self): self.useFixture(fixture_setup.FakeTerminal()) # Create snaps with open(os.path.join(self.path, 'snapcraft.yaml'), 'w') as f: f.write("""name: my-snap-name summary: test cached snap description: test cached snap architectures: ['{}'] confinement: devmode grade: devel version: '0.1' parts: my-part: plugin: nil """.format(self.deb_arch)) result = self.run_command(['snap']) self.assertThat(result.exit_code, Equals(0)) snap_file = glob.glob('*0.1_*.snap')[0] snap_cache = cache.SnapCache(project_name='my-snap-name') snap_file_path = snap_cache.cache(snap_filename=snap_file) _, snap_file_hash = os.path.split(snap_file_path) with open(os.path.join(self.path, 'snapcraft.yaml'), 'w') as f: f.write("""name: my-snap-name summary: test cached snap description: test cached snap architectures: ['{}'] confinement: devmode grade: devel version: '0.2' parts: my-part: plugin: nil """.format(self.deb_arch)) result = self.run_command(['snap']) self.assertThat(result.exit_code, Equals(0)) snap_file_2 = glob.glob('*0.2*.snap')[0] snap_file_2_path = snap_cache.cache(snap_filename=snap_file_2) snap_file_2_dir, snap_file_2_hash = os.path.split(snap_file_2_path) # confirm expected snap cached self.assertEqual(2, len(os.listdir(snap_file_2_dir))) # prune pruned_files = snap_cache.prune(deb_arch=self.deb_arch, keep_hash=snap_file_2_hash) self.assertEqual(1, len(pruned_files)) self.assertIn( os.path.join(snap_cache.snap_cache_root, self.deb_arch, snap_file_hash), pruned_files) self.assertNotIn( os.path.join(snap_cache.snap_cache_root, snap_file_2_hash), pruned_files)
def test_list_plugins_large_terminal(self): self.maxDiff = None fake_terminal = fixture_setup.FakeTerminal(columns=999) self.useFixture(fake_terminal) result = self.run_command([self.command_name]) self.assertThat(result.exit_code, Equals(0)) self.assertThat(result.output, Contains(self.default_plugin_output))
def test_search_only_first_line_of_description(self): fake_terminal = fixture_setup.FakeTerminal() self.useFixture(fake_terminal) main.main(['search', 'mulitline-part']) expected_output = ('PART NAME DESCRIPTION\n' 'multiline-part this is a multiline description\n') self.assertEqual(fake_terminal.getvalue(), expected_output)
def test_searching_for_a_part_that_exists(self): fake_terminal = fixture_setup.FakeTerminal() self.useFixture(fake_terminal) main.main(['search', 'curl']) expected_output = """PART NAME DESCRIPTION curl test entry for curl """ self.assertEqual(fake_terminal.getvalue(), expected_output)
def test_search_on_non_tty(self): fake_terminal = fixture_setup.FakeTerminal(isatty=False) self.useFixture(fake_terminal) result = self.run_command(['search', 'curl']) self.assertThat(result.exit_code, Equals(0)) self.assertThat(result.output, Contains(dedent("""\ PART NAME DESCRIPTION curl test entry for curl""")))
def test_search_on_non_tty(self): fake_terminal = fixture_setup.FakeTerminal(isatty=False) self.useFixture(fake_terminal) main.main(['search', 'curl']) expected_output = """PART NAME DESCRIPTION curl test entry for curl """ self.assertEqual(fake_terminal.getvalue(), expected_output)
def test_snap_cache_get_latest(self): self.useFixture(fixture_setup.FakeTerminal()) # Create snaps with open(os.path.join(self.path, 'snapcraft.yaml'), 'w') as f: f.write("""name: my-snap-name summary: test cached snap description: test cached snap architectures: ['{}'] confinement: devmode grade: devel version: '0.1' parts: my-part: plugin: nil """.format(self.deb_arch)) main(['snap']) snap_file = glob.glob('*0.1*.snap')[0] snap_cache = cache.SnapCache(project_name='my-snap-name') snap_cache.cache(snap_filename=snap_file) with open(os.path.join(self.path, 'snapcraft.yaml'), 'w') as f: f.write("""name: my-snap-name summary: test cached snap description: test cached snap architectures: ['{}'] confinement: devmode grade: devel version: '0.2' parts: my-part: plugin: nil """.format(self.deb_arch)) main(['snap']) snap_file_latest = glob.glob('*0.2*.snap')[0] snap_cache.cache(snap_filename=snap_file_latest) latest_hash = file_utils.calculate_sha3_384(snap_file_latest) # get latest latest_snap = snap_cache.get(deb_arch=self.deb_arch) expected_snap_path = os.path.join( snap_cache.snap_cache_root, self.deb_arch, latest_hash ) self.assertEqual(expected_snap_path, latest_snap)
def test_search_trims_long_descriptions(self): fake_terminal = fixture_setup.FakeTerminal() self.useFixture(fake_terminal) main.main(['search', 'long-described-part']) expected_output = ( 'PART NAME DESCRIPTION\n' 'long-described-part this is a repetitive description this is a ' 'repetitive de...\n') self.assertEqual(fake_terminal.getvalue(), expected_output)
def test_prune_snap_cache(self): self.useFixture(fixture_setup.FakeTerminal()) snap_cache = cache.SnapCache(project_name='my-snap-name') snap_revision = 9 snap_file = 'my-snap-name_0.1_amd64.snap' # create dummy snap open(os.path.join(self.path, snap_file), 'a').close() # cache snap snap_cache.cache(snap_file, snap_revision) # create other cached snap revisions to_be_deleted_files = [] cached_snaps = [ 'a-cached-snap_0.3_amd64_8.snap', 'another-cached-snap_1.0_arm64_6.snap' ] for cached_snap in cached_snaps: cached_snap_path = os.path.join(snap_cache.snap_cache_dir, cached_snap) to_be_deleted_files.append(cached_snap_path) open(cached_snap_path, 'a').close() real_cached_snap = _rewrite_snap_filename_with_revision( snap_file, snap_revision) # confirm expected snap cached self.assertEqual(3, len(os.listdir(snap_cache.snap_cache_dir))) self.assertTrue( os.path.isfile( os.path.join(snap_cache.snap_cache_dir, real_cached_snap))) if not self.valid_revision: with self.assertRaises(ValueError): snap_cache.prune(keep_revision='invalid-revision') with self.assertRaises(TypeError): snap_cache.prune(keep_revision=None) else: # prune cached snaps purned_file_list = snap_cache.prune(keep_revision=snap_revision) # confirm other snaps are purged self.assertEqual(set(purned_file_list), set(to_be_deleted_files)) for snap in purned_file_list: self.assertFalse(os.path.isfile(snap)) # confirm the expected cached file still exist self.assertEqual(1, len(os.listdir(snap_cache.snap_cache_dir))) self.assertTrue( os.path.isfile( os.path.join(snap_cache.snap_cache_dir, real_cached_snap)))
def test_push_and_release_a_snap(self): self.useFixture(fixture_setup.FakeTerminal()) mock_tracker = mock.Mock(storeapi.StatusTracker) mock_tracker.track.return_value = { 'code': 'ready_to_release', 'processed': True, 'can_release': True, 'url': '/fake/url', 'revision': 9, } patcher = mock.patch.object(storeapi.StoreClient, 'upload') mock_upload = patcher.start() self.addCleanup(patcher.stop) mock_upload.return_value = mock_tracker patcher = mock.patch.object(storeapi.StoreClient, 'release') mock_release = patcher.start() self.addCleanup(patcher.stop) mock_release.return_value = { 'opened_channels': ['beta'], 'channel_map': [{ 'channel': 'stable', 'info': 'none' }, { 'channel': 'candidate', 'info': 'none' }, { 'revision': 9, 'channel': 'beta', 'version': '0', 'info': 'specific' }, { 'channel': 'edge', 'info': 'tracking' }] } # Create a snap main(['init']) main(['snap']) snap_file = glob.glob('*.snap')[0] # Upload with mock.patch('snapcraft.storeapi.StatusTracker') as mock_tracker: main(['push', snap_file, '--release', 'beta']) self.assertIn( 'Uploading my-snap_0_amd64.snap.\n' 'Revision 9 of \'my-snap\' created.', self.fake_logger.output) mock_upload.assert_called_once_with('my-snap', snap_file) mock_release.assert_called_once_with('my-snap', 9, ['beta'])
def test_searching_for_a_part_that_doesnt_exist_helps_out(self): self.useFixture(fixture_setup.FakeTerminal()) fake_logger = fixtures.FakeLogger(level=logging.INFO) self.useFixture(fake_logger) main.main(['search', 'part that does not exist']) self.assertEqual( fake_logger.output, 'No matches found, try to run `snapcraft update` to refresh the ' 'remote parts cache.\n')
def test_history_with_deprecation_message(self, mock_account_api, mock_revisions): fake_terminal = fixture_setup.FakeTerminal() self.useFixture(fake_terminal) mock_revisions.return_value = self.expected main(['history', 'snap-test', '--series=16']) self.assertThat( fake_terminal.getvalue(), Contains("DEPRECATED: The 'history' command has been replaced by " "'list-revisions'."))
def test_list_plugins_small_terminal(self): fake_terminal = fixture_setup.FakeTerminal(columns=60) self.useFixture(fake_terminal) expected_output = ( 'ant dump jdk nil qmake \n' 'autotools go kbuild nodejs rust \n' 'catkin godeps kernel plainbox-provider scons \n' 'cmake gradle make python2 tar-content\n' 'copy gulp maven python3 \n') main(['list-plugins']) self.assertEqual(fake_terminal.getvalue(), expected_output)
def test_snap_cache(self): self.useFixture(fixture_setup.FakeTerminal()) # cache snap snap_cache = cache.SnapCache(project_name='cache-test') cached_snap_path = snap_cache.cache(snap_filename=self.snap_path) expected_snap_path = os.path.join( snap_cache.snap_cache_root, 'amd64', file_utils.calculate_sha3_384(self.snap_path)) self.assertEqual(expected_snap_path, cached_snap_path) self.assertTrue(os.path.isfile(cached_snap_path))
def setUp(self): super().setUp() patcher = mock.patch('snapcraft.internal.indicators.is_dumb_terminal') dumb_mock = patcher.start() dumb_mock.return_value = True self.addCleanup(patcher.stop) self.useFixture(fixture_setup.FakeTerminal()) patcher = mock.patch('snapcraft.internal.lifecycle._packer.Popen', new=mock.Mock(wraps=subprocess.Popen)) self.popen_spy = patcher.start() self.addCleanup(patcher.stop)
def test_empty_search_searches_all(self): fake_terminal = fixture_setup.FakeTerminal() self.useFixture(fake_terminal) main.main(['search']) output = fake_terminal.getvalue() self.assertEqual( output.split('\n')[0], 'PART NAME DESCRIPTION') self.assertTrue('part1 test entry for part1' in output) self.assertTrue('curl test entry for curl' in output) self.assertTrue( 'long-described-part this is a repetitive description ' 'this is a repetitive de...' in output)
def test_print_topic_help_with_devel_for_valid_topic(self): expected = { 'sources': 'Help on package snapcraft', 'plugins': 'Help on package snapcraft', } fake_terminal = fixture_setup.FakeTerminal() self.useFixture(fake_terminal) main(['help', self.topic, '--devel']) output = fake_terminal.getvalue()[:len(expected[self.topic])] self.assertEqual( output, expected[self.topic], 'The help message does not start with {!r} but with ' '{!r} instead'.format(expected[self.topic], output))
def test_snap_cache_get_by_hash(self): self.useFixture(fixture_setup.FakeTerminal()) snap_cache = cache.SnapCache(project_name='my-snap-name') snap_cache.cache(snap_filename=self.snap_path) # get hash of snap snap_hash = file_utils.calculate_sha3_384(self.snap_path) # get snap by hash snap = snap_cache.get(deb_arch='amd64', snap_hash=snap_hash) self.assertEqual( os.path.join(snap_cache.snap_cache_root, 'amd64', snap_hash), snap)