def test_cleanup_extracted_file():
    with freeze_time('2017-01-08 10:01:00'):
        viewer = FileViewer(make_file(1, get_file('webextension.xpi')))

        assert '0108' in viewer.dest
        assert not os.path.exists(viewer.dest)

        viewer.extract()

        assert os.path.exists(viewer.dest)

        # Cleaning up only cleans up yesterdays files so it doesn't touch
        # us today...
        cleanup_extracted_file()

        assert os.path.exists(viewer.dest)

    # Even hours later we don't cleanup yet...
    with freeze_time('2017-01-08 23:59:00'):
        assert os.path.exists(viewer.dest)

        cleanup_extracted_file()

        assert os.path.exists(viewer.dest)

    # But yesterday... we'll cleanup properly
    with freeze_time('2017-01-07 10:01:00'):
        assert os.path.exists(viewer.dest)

        cleanup_extracted_file()

        assert not os.path.exists(viewer.dest)
Example #2
0
    def setUp(self):
        super(FilesBase, self).setUp()
        self.addon = Addon.objects.get(pk=3615)
        self.dev = self.addon.authors.all()[0]
        self.regular = UserProfile.objects.get(pk=999)
        self.version = self.addon.versions.latest()
        self.file = self.version.all_files[0]

        p = [amo.PLATFORM_LINUX.id, amo.PLATFORM_WIN.id, amo.PLATFORM_MAC.id]

        self.file.update(platform=p[0])

        self.files = [
            self.file,
            File.objects.create(version=self.version,
                                platform=p[1],
                                hash='abc123',
                                filename='dictionary-test.xpi'),
            File.objects.create(version=self.version,
                                platform=p[2],
                                hash='abc123',
                                filename='dictionary-test.xpi')
        ]

        self.login_as_editor()

        for file_obj in self.files:
            src = os.path.join(settings.ROOT, dictionary)
            try:
                os.makedirs(os.path.dirname(file_obj.file_path))
            except OSError:
                pass
            shutil.copyfile(src, file_obj.file_path)

        self.file_viewer = FileViewer(self.file)
Example #3
0
    def setUp(self):
        super(TestSearchEngineHelper, self).setUp()
        self.left = File.objects.get(pk=25753)
        self.viewer = FileViewer(self.left)

        if not os.path.exists(os.path.dirname(self.viewer.src)):
            os.makedirs(os.path.dirname(self.viewer.src))
            with storage.open(self.viewer.src, 'w') as f:
                f.write('some data\n')
Example #4
0
    def setUp(self):
        super(FilesBase, self).setUp()
        self.addon = Addon.objects.get(pk=3615)
        self.dev = self.addon.authors.all()[0]
        self.regular = UserProfile.objects.get(pk=999)
        self.version = self.addon.versions.latest()
        self.file = self.version.all_files[0]

        p = [amo.PLATFORM_LINUX.id, amo.PLATFORM_WIN.id, amo.PLATFORM_MAC.id]

        self.file.update(platform=p[0])

        self.files = [self.file,
                      File.objects.create(version=self.version,
                                          platform=p[1],
                                          hash='abc123',
                                          filename='dictionary-test.xpi'),
                      File.objects.create(version=self.version,
                                          platform=p[2],
                                          hash='abc123',
                                          filename='dictionary-test.xpi')]

        self.login_as_editor()

        for file_obj in self.files:
            src = os.path.join(settings.ROOT, dictionary)
            try:
                os.makedirs(os.path.dirname(file_obj.file_path))
            except OSError:
                pass
            shutil.copyfile(src, file_obj.file_path)

        self.file_viewer = FileViewer(self.file)
Example #5
0
    def setUp(self):
        super(TestSearchEngineHelper, self).setUp()
        self.left = File.objects.get(pk=25753)
        self.viewer = FileViewer(self.left)

        if not os.path.exists(os.path.dirname(self.viewer.src)):
            os.makedirs(os.path.dirname(self.viewer.src))
            with storage.open(self.viewer.src, 'w') as f:
                f.write('some data\n')
Example #6
0
 def wrapper(request, file_id, key, *args, **kw):
     viewer = FileViewer(get_object_or_404(File, pk=file_id))
     token = request.GET.get('token')
     if not token:
         log.error('Denying access to %s, no token.' % viewer.file.id)
         raise PermissionDenied
     if not Token.valid(token, [viewer.file.id, key]):
         log.error('Denying access to %s, token invalid.' % viewer.file.id)
         raise PermissionDenied
     return func(request, viewer, key, *args, **kw)
Example #7
0
    def setUp(self):
        super(FilesBase, self).setUp()
        self.addon = Addon.objects.get(pk=3615)
        self.dev = self.addon.authors.all()[0]
        self.regular = UserProfile.objects.get(pk=999)
        self.version = self.addon.versions.latest()
        self.file = self.version.all_files[0]

        p = [amo.PLATFORM_LINUX.id, amo.PLATFORM_WIN.id, amo.PLATFORM_MAC.id]

        self.file.update(platform=p[0])

        self.files = [
            self.file,
            File.objects.create(version=self.version,
                                platform=p[1],
                                hash='abc123',
                                filename='dictionary-test.xpi'),
            File.objects.create(version=self.version,
                                platform=p[2],
                                hash='abc123',
                                filename='dictionary-test.xpi')
        ]

        self.login_as_editor()

        for file_obj in self.files:
            src = os.path.join(settings.ROOT, dictionary)
            try:
                os.makedirs(os.path.dirname(file_obj.file_path))
            except OSError:
                pass
            shutil.copyfile(src, file_obj.file_path)

        self.file_viewer = FileViewer(self.file)
        # Setting this to True, so we are delaying the extraction of files,
        # in the tests, the files won't be extracted.
        # Most of these tests extract as needed to.
        Switch.objects.get_or_create(name='delay-file-viewer', active=True)
Example #8
0
    def wrapper(request, file_id, *args, **kw):
        file_ = get_object_or_404(File, pk=file_id)
        result = allowed(request, file_)
        if result is not True:
            return result
        try:
            obj = FileViewer(file_,)
        except ObjectDoesNotExist:
            raise http.Http404

        response = func(request, obj, *args, **kw)
        if obj.selected:
            response['ETag'] = '"%s"' % obj.selected.get('md5')
            response['Last-Modified'] = http_date(obj.selected.get('modified'))
        return response
Example #9
0
    def setUp(self):
        super(FilesBase, self).setUp()
        self.addon = Addon.objects.get(pk=3615)
        self.dev = self.addon.authors.all()[0]
        self.regular = UserProfile.objects.get(pk=999)
        self.version = self.addon.versions.latest()
        self.file = self.version.all_files[0]

        p = [amo.PLATFORM_LINUX.id, amo.PLATFORM_WIN.id, amo.PLATFORM_MAC.id]

        self.file.update(platform=p[0])

        self.files = [self.file,
                      File.objects.create(version=self.version,
                                          platform=p[1],
                                          hash='abc123',
                                          filename='dictionary-test.xpi'),
                      File.objects.create(version=self.version,
                                          platform=p[2],
                                          hash='abc123',
                                          filename='dictionary-test.xpi')]

        self.login_as_editor()

        for file_obj in self.files:
            src = os.path.join(settings.ROOT, dictionary)
            try:
                os.makedirs(os.path.dirname(file_obj.file_path))
            except OSError:
                pass
            shutil.copyfile(src, file_obj.file_path)

        self.file_viewer = FileViewer(self.file)
        # Setting this to True, so we are delaying the extraction of files,
        # in the tests, the files won't be extracted.
        # Most of these tests extract as needed to.
        Switch.objects.get_or_create(name='delay-file-viewer', active=True)
Example #10
0
class FilesBase(object):
    def login_as_admin(self):
        assert self.client.login(email='*****@*****.**')

    def login_as_editor(self):
        assert self.client.login(email='*****@*****.**')

    def setUp(self):
        super(FilesBase, self).setUp()
        self.addon = Addon.objects.get(pk=3615)
        self.dev = self.addon.authors.all()[0]
        self.regular = UserProfile.objects.get(pk=999)
        self.version = self.addon.versions.latest()
        self.file = self.version.all_files[0]

        p = [amo.PLATFORM_LINUX.id, amo.PLATFORM_WIN.id, amo.PLATFORM_MAC.id]

        self.file.update(platform=p[0])

        self.files = [
            self.file,
            File.objects.create(version=self.version,
                                platform=p[1],
                                hash='abc123',
                                filename='dictionary-test.xpi'),
            File.objects.create(version=self.version,
                                platform=p[2],
                                hash='abc123',
                                filename='dictionary-test.xpi')
        ]

        self.login_as_editor()

        for file_obj in self.files:
            src = os.path.join(settings.ROOT, dictionary)
            try:
                os.makedirs(os.path.dirname(file_obj.file_path))
            except OSError:
                pass
            shutil.copyfile(src, file_obj.file_path)

        self.file_viewer = FileViewer(self.file)

    def tearDown(self):
        self.file_viewer.cleanup()
        super(FilesBase, self).tearDown()

    def files_redirect(self, file):
        return reverse('files.redirect', args=[self.file.pk, file])

    def files_serve(self, file):
        return reverse('files.serve', args=[self.file.pk, file])

    def test_view_access_anon(self):
        self.client.logout()
        self.check_urls(403)

    def test_view_access_anon_view_source(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.client.logout()
        self.check_urls(200)

    def test_view_access_editor(self):
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_editor_view_source(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_developer(self):
        self.client.logout()
        assert self.client.login(email=self.dev.email)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_reviewed(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.client.logout()

        for status in amo.UNREVIEWED_FILE_STATUSES:
            self.addon.update(status=status)
            self.check_urls(403)

        for status in amo.REVIEWED_STATUSES:
            self.addon.update(status=status)
            self.check_urls(200)

    def test_view_access_developer_view_source(self):
        self.client.logout()
        assert self.client.login(email=self.dev.email)
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_another_developer(self):
        self.client.logout()
        assert self.client.login(email=self.regular.email)
        self.file_viewer.extract()
        self.check_urls(403)

    def test_view_access_another_developer_view_source(self):
        self.client.logout()
        assert self.client.login(email=self.regular.email)
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_poll_extracted(self):
        self.file_viewer.extract()
        res = self.client.get(self.poll_url())
        assert res.status_code == 200
        assert json.loads(res.content)['status']

    def test_poll_not_extracted(self):
        res = self.client.get(self.poll_url())
        assert res.status_code == 200
        assert not json.loads(res.content)['status']

    def test_poll_extracted_anon(self):
        self.client.logout()
        res = self.client.get(self.poll_url())
        assert res.status_code == 403

    def test_content_headers(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url('install.js'))
        assert 'etag' in res._headers
        assert 'last-modified' in res._headers

    def test_content_headers_etag(self):
        self.file_viewer.extract()
        self.file_viewer.select('install.js')
        obj = getattr(self.file_viewer, 'left', self.file_viewer)
        etag = obj.selected.get('sha256')
        res = self.client.get(self.file_url('install.js'),
                              HTTP_IF_NONE_MATCH=etag)
        assert res.status_code == 304

    def test_content_headers_if_modified(self):
        self.file_viewer.extract()
        self.file_viewer.select('install.js')
        obj = getattr(self.file_viewer, 'left', self.file_viewer)
        date = http_date(obj.selected.get('modified'))
        res = self.client.get(self.file_url('install.js'),
                              HTTP_IF_MODIFIED_SINCE=date)
        assert res.status_code == 304

    def test_file_header(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        url = res.context['file_link']['url']
        assert url == reverse('editors.review', args=[self.addon.slug])

    def test_file_header_anon(self):
        self.client.logout()
        self.file_viewer.extract()
        self.addon.update(view_source=True)
        res = self.client.get(self.file_url(not_binary))
        url = res.context['file_link']['url']
        assert url == reverse('addons.detail', args=[self.addon.pk])

    def test_content_no_file(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url())
        doc = pq(res.content)
        assert len(doc('#content')) == 0

    def test_files(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url())
        assert res.status_code == 200
        assert 'files' in res.context

    def test_files_anon(self):
        self.client.logout()
        res = self.client.get(self.file_url())
        assert res.status_code == 403

    def test_files_file(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        assert res.status_code == 200
        assert 'selected' in res.context

    def test_files_back_link(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        doc = pq(res.content)
        assert doc('#commands td')[-1].text_content() == 'Back to review'

    def test_files_back_link_anon(self):
        self.file_viewer.extract()
        self.client.logout()
        self.addon.update(view_source=True)
        res = self.client.get(self.file_url(not_binary))
        assert res.status_code == 200
        doc = pq(res.content)
        assert doc('#commands td')[-1].text_content() == 'Back to add-on'

    def test_diff_redirect(self):
        ids = self.files[0].id, self.files[1].id

        res = self.client.post(self.file_url(), {
            'left': ids[0],
            'right': ids[1]
        })
        self.assert3xx(res, reverse('files.compare', args=ids))

    def test_browse_redirect(self):
        ids = self.files[0].id,

        res = self.client.post(self.file_url(), {'left': ids[0]})
        self.assert3xx(res, reverse('files.list', args=ids))

    def test_browse_404(self):
        res = self.client.get('/files/browse/file/dont/exist.png', follow=True)
        assert res.status_code == 404

    def test_invalid_redirect(self):
        res = self.client.post(self.file_url(), {})
        self.assert3xx(res, self.file_url())

    def test_file_chooser(self):
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left = doc('#id_left')
        assert len(left) == 1

        ver = left('optgroup')
        assert len(ver) == 1

        assert ver.attr('label') == self.version.version

        files = ver('option')
        assert len(files) == 2

    def test_file_chooser_coalescing(self):
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        unreviewed_file = doc('#id_left > optgroup > option.status-unreviewed')
        public_file = doc('#id_left > optgroup > option.status-public')
        assert public_file.text() == str(self.files[0].get_platform_display())
        assert unreviewed_file.text() == (
            '%s, %s' % (self.files[1].get_platform_display(),
                        self.files[2].get_platform_display()))

        assert public_file.attr('value') == str(self.files[0].id)
        assert unreviewed_file.attr('value') == str(self.files[1].id)

    def test_file_chooser_disabled_coalescing(self):
        self.files[1].update(status=amo.STATUS_DISABLED)

        res = self.client.get(self.file_url())
        doc = pq(res.content)

        disabled_file = doc('#id_left > optgroup > option.status-disabled')
        assert disabled_file.attr('value') == str(self.files[2].id)

    def test_files_for_unlisted_addon_returns_404(self):
        """Files browsing isn't allowed for unlisted addons."""
        self.make_addon_unlisted(self.addon)
        assert self.client.get(self.file_url()).status_code == 404

    def test_files_for_unlisted_addon_with_admin(self):
        """Files browsing is allowed for unlisted addons if you're admin."""
        self.login_as_admin()
        self.make_addon_unlisted(self.addon)
        assert self.client.get(self.file_url()).status_code == 200

    def test_all_versions_shown_for_admin(self):
        self.login_as_admin()
        listed_ver = version_factory(addon=self.addon,
                                     channel=amo.RELEASE_CHANNEL_LISTED,
                                     version='4.0',
                                     created=self.days_ago(1))
        unlisted_ver = version_factory(addon=self.addon,
                                       channel=amo.RELEASE_CHANNEL_UNLISTED,
                                       version='5.0')
        assert self.addon.versions.count() == 3
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left_select = doc('#id_left')
        assert left_select('optgroup').attr('label') == self.version.version
        file_options = left_select('option.status-public')
        assert len(file_options) == 3, left_select.html()
        # Check the files in the list are the two we added and the default.
        assert file_options.eq(0).attr('value') == str(
            unlisted_ver.all_files[0].pk)
        assert file_options.eq(1).attr('value') == str(
            listed_ver.all_files[0].pk)
        assert file_options.eq(2).attr('value') == str(self.file.pk)
        # Check there are prefixes on the labels for the channels
        assert file_options.eq(0).text().endswith('[Self]')
        assert file_options.eq(1).text().endswith('[AMO]')
        assert file_options.eq(2).text().endswith('[AMO]')

    def test_channel_prefix_not_shown_when_no_mixed_channels(self):
        self.login_as_admin()
        version_factory(addon=self.addon, channel=amo.RELEASE_CHANNEL_LISTED)
        assert self.addon.versions.count() == 2
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left_select = doc('#id_left')
        assert left_select('optgroup').attr('label') == self.version.version
        # Check there are NO prefixes on the labels for the channels
        file_options = left_select('option.status-public')
        assert not file_options.eq(0).text().endswith('[Self]')
        assert not file_options.eq(1).text().endswith('[AMO]')
        assert not file_options.eq(2).text().endswith('[AMO]')

    def test_only_listed_versions_shown_for_editor(self):
        listed_ver = version_factory(addon=self.addon,
                                     channel=amo.RELEASE_CHANNEL_LISTED,
                                     version='4.0')
        version_factory(addon=self.addon,
                        channel=amo.RELEASE_CHANNEL_UNLISTED,
                        version='5.0')
        assert self.addon.versions.count() == 3
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left_select = doc('#id_left')
        assert left_select('optgroup').attr('label') == self.version.version
        # Check the files in the list are just the listed, and the default.
        file_options = left_select('option.status-public')
        assert len(file_options) == 2, left_select.html()
        assert file_options.eq(0).attr('value') == str(
            listed_ver.all_files[0].pk)
        assert file_options.eq(1).attr('value') == str(self.file.pk)
        # Check there are NO prefixes on the labels for the channels
        assert not file_options.eq(0).text().endswith('[AMO]')
        assert not file_options.eq(1).text().endswith('[AMO]')
Example #11
0
class TestFileViewer(TestCase):
    def setUp(self):
        super(TestFileViewer, self).setUp()
        self.viewer = FileViewer(make_file(1, get_file('dictionary-test.xpi')))

    def tearDown(self):
        self.viewer.cleanup()
        super(TestFileViewer, self).tearDown()

    def test_files_not_extracted(self):
        assert not self.viewer.is_extracted()

    def test_files_extracted(self):
        self.viewer.extract()
        assert self.viewer.is_extracted()

    def test_recurse_extract(self):
        self.viewer.src = get_file('recurse.xpi')
        self.viewer.extract()
        assert self.viewer.is_extracted()

    def test_recurse_contents(self):
        self.viewer.src = get_file('recurse.xpi')
        self.viewer.extract()
        files = self.viewer.get_files()
        file_list = [
            'recurse/recurse.xpi/chrome/test-root.txt',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar/test'
        ]
        for name in file_list:
            assert name in files

    def test_recurse_contents_of_zip(self):
        self.viewer.src = get_file('recurse.zip')
        self.viewer.extract()
        files = self.viewer.get_files()
        file_list = [
            'recurse/recurse.xpi/chrome/test-root.txt',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar/test'
        ]
        for name in file_list:
            assert name in files

    def test_locked(self):
        self.viewer.src = get_file('dictionary-test.xpi')

        # Lock was successfully attained
        assert self.viewer.extract()

        lock = flufl.lock.Lock(
            os.path.join(settings.TMP_PATH,
                         'file-viewer-%s.lock' % self.viewer.file.pk))

        assert not lock.is_locked

        lock.lock()

        assert lock.is_locked

        # Not extracting, the viewer is locked, lock could not be attained
        assert not self.viewer.extract()

    def test_extract_file_locked_message(self):
        self.viewer.src = get_file('dictionary-test.xpi')
        assert not self.viewer.is_extracted()

        lock = flufl.lock.Lock(
            os.path.join(settings.TMP_PATH,
                         'file-viewer-%s.lock' % self.viewer.file.pk))

        assert not lock.is_locked

        lock.lock()

        assert lock.is_locked

        msg = extract_file(self.viewer)
        assert str(msg.get()).startswith(u'File viewer is locked')
        msg.delete()

    def test_cleanup(self):
        self.viewer.extract()
        self.viewer.cleanup()
        assert not self.viewer.is_extracted()

    @freeze_time('2017-01-08 02:01:00')
    def test_dest(self):
        viewer = FileViewer(make_file(1, get_file('webextension.xpi')))
        assert viewer.dest == os.path.join(settings.TMP_PATH, 'file_viewer',
                                           '0108', str(self.viewer.file.pk))

    def test_isbinary(self):
        binary = self.viewer._is_binary
        for f in [
                'foo.rdf', 'foo.xml', 'foo.js', 'foo.py'
                'foo.html', 'foo.txt', 'foo.dtd', 'foo.xul', 'foo.sh',
                'foo.properties', 'foo.json', 'foo.src', 'CHANGELOG'
        ]:
            m, encoding = mimetypes.guess_type(f)
            assert not binary(m, f), '%s should not be binary' % f

        for f in ['foo.png', 'foo.gif', 'foo.exe', 'foo.swf']:
            m, encoding = mimetypes.guess_type(f)
            assert binary(m, f), '%s should be binary' % f

        filename = os.path.join(settings.TMP_PATH, 'test_isbinary')
        for txt in ['#!/usr/bin/python', '#python', u'\0x2']:
            open(filename, 'w').write(txt)
            m, encoding = mimetypes.guess_type(filename)
            assert not binary(m, filename), '%s should not be binary' % txt

        for txt in ['MZ']:
            open(filename, 'w').write(txt)
            m, encoding = mimetypes.guess_type(filename)
            assert binary(m, filename), '%s should be binary' % txt
        os.remove(filename)

    def test_truncate(self):
        truncate = self.viewer.truncate
        for x, y in (
            ['foo.rdf', 'foo.rdf'],
            ['somelongfilename.rdf', 'somelongfilenam...rdf'],
            [u'unicodeì‚®.txt', u'unicode\uc0ae.txt'],
            [u'unicodesomelongì‚®.txt', u'unicodesomelong...txt'],
            [
                'somelongfilename.somelongextension',
                'somelongfilenam...somelonge..'
            ],
        ):
            assert truncate(x) == y

    def test_get_files_not_extracted(self):
        assert not self.viewer.get_files()

    def test_get_files_size(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        assert len(files) == 14

    def test_get_files_directory(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        assert not files['install.js']['directory']
        assert not files['install.js']['binary']
        assert files['__MACOSX']['directory']
        assert not files['__MACOSX']['binary']

    def test_url_file(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        url = reverse('files.list',
                      args=[self.viewer.file.id, 'file', 'install.js'])
        file_url = files['install.js']['url']
        assert file_url == url
        assert file_url.startswith('/en-US')

        # Make sure that the locale is properly used (see bug 1168794).
        with self.activate('fr'):
            self.viewer._files = {}  # Reset the viewer's internal cache.
            files = self.viewer.get_files()
            url = reverse('files.list',
                          args=[self.viewer.file.id, 'file', 'install.js'])
            file_url = files['install.js']['url']
            assert file_url == url
            assert file_url.startswith('/fr')

    def test_get_files_depth(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        assert files['dictionaries/license.txt']['depth'] == 1

    def test_bom(self):
        dest = os.path.join(settings.TMP_PATH, 'test_bom')
        open(dest, 'w').write('foo'.encode('utf-16'))
        self.viewer.select('foo')
        self.viewer.selected = {'full': dest, 'size': 1}
        assert self.viewer.read_file() == u'foo'
        os.remove(dest)

    def test_syntax(self):
        for filename, syntax in [('foo.rdf', 'xml'), ('foo.xul', 'xml'),
                                 ('foo.json', 'js'), ('foo.jsm', 'js'),
                                 ('foo.htm', 'html'), ('foo.bar', 'plain'),
                                 ('foo.diff', 'plain')]:
            assert self.viewer.get_syntax(filename) == syntax

    def test_file_order(self):
        self.viewer.extract()
        dest = self.viewer.dest
        open(os.path.join(dest, 'chrome.manifest'), 'w')
        subdir = os.path.join(dest, 'chrome')
        os.mkdir(subdir)
        open(os.path.join(subdir, 'foo'), 'w')
        cache.clear()
        files = self.viewer.get_files().keys()
        rt = files.index(u'chrome')
        assert files[rt:rt + 3] == [u'chrome', u'chrome/foo', u'dictionaries']

    @patch.object(settings, 'FILE_VIEWER_SIZE_LIMIT', 5)
    def test_file_size(self):
        self.viewer.extract()
        self.viewer.get_files()
        self.viewer.select('install.js')
        res = self.viewer.read_file()
        assert res == ''
        assert self.viewer.selected['msg'].startswith('File size is')

    @patch.object(settings, 'FILE_VIEWER_SIZE_LIMIT', 5)
    def test_file_size_unicode(self):
        with self.activate(locale='he'):
            self.viewer.extract()
            self.viewer.get_files()
            self.viewer.select('install.js')
            res = self.viewer.read_file()
            assert res == ''
            assert self.viewer.selected['msg'].startswith('File size is')

    @patch.object(settings, 'FILE_UNZIP_SIZE_LIMIT', 5)
    def test_contents_size(self):
        self.assertRaises(forms.ValidationError, self.viewer.extract)

    def test_default(self):
        self.viewer.extract()
        assert self.viewer.get_default(None) == 'install.rdf'

    def test_default_webextension(self):
        viewer = FileViewer(make_file(2, get_file('webextension.xpi')))
        viewer.extract()
        assert viewer.get_default(None) == 'manifest.json'

    def test_default_webextension_zip(self):
        viewer = FileViewer(make_file(2, get_file('webextension_no_id.zip')))
        viewer.extract()
        assert viewer.get_default(None) == 'manifest.json'

    def test_default_webextension_crx(self):
        viewer = FileViewer(make_file(2, get_file('webextension.crx')))
        viewer.extract()
        assert viewer.get_default(None) == 'manifest.json'

    def test_default_package_json(self):
        viewer = FileViewer(make_file(3, get_file('new-format-0.0.1.xpi')))
        viewer.extract()
        assert viewer.get_default(None) == 'package.json'

    def test_delete_mid_read(self):
        self.viewer.extract()
        self.viewer.select('install.js')
        os.remove(os.path.join(self.viewer.dest, 'install.js'))
        res = self.viewer.read_file()
        assert res == ''
        assert self.viewer.selected['msg'].startswith('That file no')

    @patch('olympia.files.helpers.get_sha256')
    def test_delete_mid_tree(self, get_sha256):
        get_sha256.side_effect = IOError('ow')
        self.viewer.extract()
        assert {} == self.viewer.get_files()

    @patch('olympia.files.helpers.os.fsync')
    def test_verify_files_doesnt_call_fsync_regularly(self, fsync):
        self.viewer.extract()

        assert not fsync.called

    @patch('olympia.files.helpers.os.fsync')
    def test_verify_files_calls_fsync_on_differences(self, fsync):
        self.viewer.extract()

        assert not fsync.called

        files_to_verify = get_all_files(self.viewer.dest)
        files_to_verify.pop()

        with patch('olympia.files.helpers.get_all_files') as get_all_files_mck:
            get_all_files_mck.return_value = files_to_verify

            with pytest.raises(ValueError):
                # We don't put things back into place after fsync
                # so a `ValueError` is raised
                self.viewer._verify_files(files_to_verify)

        assert len(fsync.call_args_list) == len(files_to_verify) + 1
Example #12
0
 def test_dest(self):
     viewer = FileViewer(make_file(1, get_file('webextension.xpi')))
     assert viewer.dest == os.path.join(settings.TMP_PATH, 'file_viewer',
                                        '0108', str(self.viewer.file.pk))
Example #13
0
 def setUp(self):
     super(TestFileHelper, self).setUp()
     self.viewer = FileViewer(make_file(1, get_file('dictionary-test.xpi')))
Example #14
0
class TestFileHelper(TestCase):

    def setUp(self):
        super(TestFileHelper, self).setUp()
        self.viewer = FileViewer(make_file(1, get_file('dictionary-test.xpi')))

    def tearDown(self):
        self.viewer.cleanup()
        super(TestFileHelper, self).tearDown()

    def test_files_not_extracted(self):
        assert not self.viewer.is_extracted()

    def test_files_extracted(self):
        self.viewer.extract()
        assert self.viewer.is_extracted()

    def test_recurse_extract(self):
        self.viewer.src = get_file('recurse.xpi')
        self.viewer.extract()
        assert self.viewer.is_extracted()

    def test_recurse_contents(self):
        self.viewer.src = get_file('recurse.xpi')
        self.viewer.extract()
        files = self.viewer.get_files()
        file_list = [
            'recurse/recurse.xpi/chrome/test-root.txt',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar/test'
        ]
        for name in file_list:
            assert name in files

    def test_recurse_contents_of_zip(self):
        self.viewer.src = get_file('recurse.zip')
        self.viewer.extract()
        files = self.viewer.get_files()
        file_list = [
            'recurse/recurse.xpi/chrome/test-root.txt',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar/test'
        ]
        for name in file_list:
            assert name in files

    def test_cleanup(self):
        self.viewer.extract()
        self.viewer.cleanup()
        assert not self.viewer.is_extracted()

    def test_isbinary(self):
        binary = self.viewer._is_binary
        for f in ['foo.rdf', 'foo.xml', 'foo.js', 'foo.py'
                  'foo.html', 'foo.txt', 'foo.dtd', 'foo.xul', 'foo.sh',
                  'foo.properties', 'foo.json', 'foo.src', 'CHANGELOG']:
            m, encoding = mimetypes.guess_type(f)
            assert not binary(m, f), '%s should not be binary' % f

        for f in ['foo.png', 'foo.gif', 'foo.exe', 'foo.swf']:
            m, encoding = mimetypes.guess_type(f)
            assert binary(m, f), '%s should be binary' % f

        filename = os.path.join(settings.TMP_PATH, 'test_isbinary')
        for txt in ['#!/usr/bin/python', '#python', u'\0x2']:
            open(filename, 'w').write(txt)
            m, encoding = mimetypes.guess_type(filename)
            assert not binary(m, filename), '%s should not be binary' % txt

        for txt in ['MZ']:
            open(filename, 'w').write(txt)
            m, encoding = mimetypes.guess_type(filename)
            assert binary(m, filename), '%s should be binary' % txt
        os.remove(filename)

    def test_truncate(self):
        truncate = self.viewer.truncate
        for x, y in (['foo.rdf', 'foo.rdf'],
                     ['somelongfilename.rdf', 'somelongfilenam...rdf'],
                     [u'unicodeì‚®.txt', u'unicode\uc0ae.txt'],
                     [u'unicodesomelongì‚®.txt', u'unicodesomelong...txt'],
                     ['somelongfilename.somelongextension',
                      'somelongfilenam...somelonge..'],):
            assert truncate(x) == y

    def test_get_files_not_extracted(self):
        assert not self.viewer.get_files()

    def test_get_files_size(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        assert len(files) == 14

    def test_get_files_directory(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        assert not files['install.js']['directory']
        assert not files['install.js']['binary']
        assert files['__MACOSX']['directory']
        assert not files['__MACOSX']['binary']

    def test_url_file(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        url = reverse('files.list', args=[self.viewer.file.id,
                                          'file', 'install.js'])
        file_url = files['install.js']['url']
        assert file_url == url
        assert file_url.startswith('/en-US')

        # Make sure that the locale is properly used (see bug 1168794).
        with self.activate('fr'):
            self.viewer._files = {}  # Reset the viewer's internal cache.
            files = self.viewer.get_files()
            url = reverse('files.list', args=[self.viewer.file.id,
                                              'file', 'install.js'])
            file_url = files['install.js']['url']
            assert file_url == url
            assert file_url.startswith('/fr')

    def test_get_files_depth(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        assert files['dictionaries/license.txt']['depth'] == 1

    def test_bom(self):
        dest = os.path.join(settings.TMP_PATH, 'test_bom')
        open(dest, 'w').write('foo'.encode('utf-16'))
        self.viewer.select('foo')
        self.viewer.selected = {'full': dest, 'size': 1}
        assert self.viewer.read_file() == u'foo'
        os.remove(dest)

    def test_syntax(self):
        for filename, syntax in [('foo.rdf', 'xml'),
                                 ('foo.xul', 'xml'),
                                 ('foo.json', 'js'),
                                 ('foo.jsm', 'js'),
                                 ('foo.bar', 'plain')]:
            assert self.viewer.get_syntax(filename) == syntax

    def test_file_order(self):
        self.viewer.extract()
        dest = self.viewer.dest
        open(os.path.join(dest, 'chrome.manifest'), 'w')
        subdir = os.path.join(dest, 'chrome')
        os.mkdir(subdir)
        open(os.path.join(subdir, 'foo'), 'w')
        cache.clear()
        files = self.viewer.get_files().keys()
        rt = files.index(u'chrome')
        assert files[rt:rt + 3] == [u'chrome', u'chrome/foo', u'dictionaries']

    @patch.object(settings, 'FILE_VIEWER_SIZE_LIMIT', 5)
    def test_file_size(self):
        self.viewer.extract()
        self.viewer.get_files()
        self.viewer.select('install.js')
        res = self.viewer.read_file()
        assert res == ''
        assert self.viewer.selected['msg'].startswith('File size is')

    @patch.object(settings, 'FILE_VIEWER_SIZE_LIMIT', 5)
    def test_file_size_unicode(self):
        with self.activate(locale='he'):
            self.viewer.extract()
            self.viewer.get_files()
            self.viewer.select('install.js')
            res = self.viewer.read_file()
            assert res == ''
            assert self.viewer.selected['msg'].startswith('File size is')

    @patch.object(settings, 'FILE_UNZIP_SIZE_LIMIT', 5)
    def test_contents_size(self):
        self.assertRaises(forms.ValidationError, self.viewer.extract)

    def test_default(self):
        self.viewer.extract()
        assert self.viewer.get_default(None) == 'install.rdf'

    def test_default_webextension(self):
        viewer = FileViewer(make_file(2, get_file('webextension.xpi')))
        viewer.extract()
        assert viewer.get_default(None) == 'manifest.json'

    def test_default_webextension_zip(self):
        viewer = FileViewer(make_file(2, get_file('webextension_no_id.zip')))
        viewer.extract()
        assert viewer.get_default(None) == 'manifest.json'

    def test_default_webextension_crx(self):
        viewer = FileViewer(make_file(2, get_file('webextension.crx')))
        viewer.extract()
        assert viewer.get_default(None) == 'manifest.json'

    def test_default_package_json(self):
        viewer = FileViewer(make_file(3, get_file('new-format-0.0.1.xpi')))
        viewer.extract()
        assert viewer.get_default(None) == 'package.json'

    def test_delete_mid_read(self):
        self.viewer.extract()
        self.viewer.select('install.js')
        os.remove(os.path.join(self.viewer.dest, 'install.js'))
        res = self.viewer.read_file()
        assert res == ''
        assert self.viewer.selected['msg'].startswith('That file no')

    @patch('olympia.files.helpers.get_md5')
    def test_delete_mid_tree(self, get_md5):
        get_md5.side_effect = IOError('ow')
        self.viewer.extract()
        assert {} == self.viewer.get_files()
Example #15
0
    def test_unicode_fails_with_wrong_configured_basepath(self):
        file_viewer = FileViewer(self.file)
        file_viewer.src = unicode_filenames

        with pytest.raises(UnicodeDecodeError):
            file_viewer.extract()
Example #16
0
    def test_unicode_fails_with_wrong_configured_basepath(self):
        file_viewer = FileViewer(self.file)
        file_viewer.src = unicode_filenames

        with pytest.raises(UnicodeDecodeError):
            file_viewer.extract()
Example #17
0
class TestFileHelper(TestCase):
    def setUp(self):
        super(TestFileHelper, self).setUp()
        self.viewer = FileViewer(make_file(1, get_file('dictionary-test.xpi')))

    def tearDown(self):
        self.viewer.cleanup()
        super(TestFileHelper, self).tearDown()

    def test_files_not_extracted(self):
        eq_(self.viewer.is_extracted(), False)

    def test_files_extracted(self):
        self.viewer.extract()
        eq_(self.viewer.is_extracted(), True)

    def test_recurse_extract(self):
        self.viewer.src = get_file('recurse.xpi')
        self.viewer.extract()
        eq_(self.viewer.is_extracted(), True)

    def test_recurse_contents(self):
        self.viewer.src = get_file('recurse.xpi')
        self.viewer.extract()
        files = self.viewer.get_files()
        nm = [
            'recurse/recurse.xpi/chrome/test-root.txt',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar',
            'recurse/somejar.jar/recurse/recurse.xpi/chrome/test.jar/test'
        ]
        for name in nm:
            eq_(name in files, True, 'File %r not extracted' % name)

    def test_cleanup(self):
        self.viewer.extract()
        self.viewer.cleanup()
        eq_(self.viewer.is_extracted(), False)

    def test_isbinary(self):
        binary = self.viewer._is_binary
        for f in [
                'foo.rdf', 'foo.xml', 'foo.js', 'foo.py'
                'foo.html', 'foo.txt', 'foo.dtd', 'foo.xul', 'foo.sh',
                'foo.properties', 'foo.json', 'foo.src', 'CHANGELOG'
        ]:
            m, encoding = mimetypes.guess_type(f)
            assert not binary(m, f), '%s should not be binary' % f

        for f in ['foo.png', 'foo.gif', 'foo.exe', 'foo.swf']:
            m, encoding = mimetypes.guess_type(f)
            assert binary(m, f), '%s should be binary' % f

        filename = os.path.join(settings.TMP_PATH, 'test_isbinary')
        for txt in ['#!/usr/bin/python', '#python', u'\0x2']:
            open(filename, 'w').write(txt)
            m, encoding = mimetypes.guess_type(filename)
            assert not binary(m, filename), '%s should not be binary' % txt

        for txt in ['MZ']:
            open(filename, 'w').write(txt)
            m, encoding = mimetypes.guess_type(filename)
            assert binary(m, filename), '%s should be binary' % txt
        os.remove(filename)

    def test_truncate(self):
        truncate = self.viewer.truncate
        for x, y in (
            ['foo.rdf', 'foo.rdf'],
            ['somelongfilename.rdf', 'somelongfilenam...rdf'],
            [u'unicodeì‚®.txt', u'unicode\uc0ae.txt'],
            [u'unicodesomelongì‚®.txt', u'unicodesomelong...txt'],
            [
                'somelongfilename.somelongextension',
                'somelongfilenam...somelonge..'
            ],
        ):
            eq_(truncate(x), y)

    def test_get_files_not_extracted(self):
        assert not self.viewer.get_files()

    def test_get_files_size(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        eq_(len(files), 14)

    def test_get_files_directory(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        eq_(files['install.js']['directory'], False)
        eq_(files['install.js']['binary'], False)
        eq_(files['__MACOSX']['directory'], True)
        eq_(files['__MACOSX']['binary'], False)

    def test_url_file(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        url = reverse('files.list',
                      args=[self.viewer.file.id, 'file', 'install.js'])
        file_url = files['install.js']['url']
        assert file_url == url
        assert file_url.startswith('/en-US')

        # Make sure that the locale is properly used (see bug 1168794).
        with self.activate('fr'):
            self.viewer._files = {}  # Reset the viewer's internal cache.
            files = self.viewer.get_files()
            url = reverse('files.list',
                          args=[self.viewer.file.id, 'file', 'install.js'])
            file_url = files['install.js']['url']
            assert file_url == url
            assert file_url.startswith('/fr')

    def test_get_files_depth(self):
        self.viewer.extract()
        files = self.viewer.get_files()
        eq_(files['dictionaries/license.txt']['depth'], 1)

    def test_bom(self):
        dest = os.path.join(settings.TMP_PATH, 'test_bom')
        open(dest, 'w').write('foo'.encode('utf-16'))
        self.viewer.select('foo')
        self.viewer.selected = {'full': dest, 'size': 1}
        eq_(self.viewer.read_file(), u'foo')
        os.remove(dest)

    def test_syntax(self):
        for filename, syntax in [('foo.rdf', 'xml'), ('foo.xul', 'xml'),
                                 ('foo.json', 'js'), ('foo.jsm', 'js'),
                                 ('foo.bar', 'plain')]:
            eq_(self.viewer.get_syntax(filename), syntax)

    def test_file_order(self):
        self.viewer.extract()
        dest = self.viewer.dest
        open(os.path.join(dest, 'chrome.manifest'), 'w')
        subdir = os.path.join(dest, 'chrome')
        os.mkdir(subdir)
        open(os.path.join(subdir, 'foo'), 'w')
        cache.clear()
        files = self.viewer.get_files().keys()
        rt = files.index(u'chrome')
        eq_(files[rt:rt + 3], [u'chrome', u'chrome/foo', u'dictionaries'])

    @patch.object(settings, 'FILE_VIEWER_SIZE_LIMIT', 5)
    def test_file_size(self):
        self.viewer.extract()
        self.viewer.get_files()
        self.viewer.select('install.js')
        res = self.viewer.read_file()
        eq_(res, '')
        assert self.viewer.selected['msg'].startswith('File size is')

    @patch.object(settings, 'FILE_VIEWER_SIZE_LIMIT', 5)
    def test_file_size_unicode(self):
        with self.activate(locale='he'):
            self.viewer.extract()
            self.viewer.get_files()
            self.viewer.select('install.js')
            res = self.viewer.read_file()
            eq_(res, '')
            assert self.viewer.selected['msg'].startswith('File size is')

    @patch.object(settings, 'FILE_UNZIP_SIZE_LIMIT', 5)
    def test_contents_size(self):
        self.assertRaises(forms.ValidationError, self.viewer.extract)

    def test_default(self):
        self.viewer.extract()
        assert self.viewer.get_default(None) == 'install.rdf'

    def test_default_webextension(self):
        viewer = FileViewer(make_file(2, get_file('webextension.xpi')))
        viewer.extract()
        assert viewer.get_default(None) == 'manifest.json'

    def test_default_package_json(self):
        viewer = FileViewer(make_file(3, get_file('new-format-0.0.1.xpi')))
        viewer.extract()
        assert viewer.get_default(None) == 'package.json'

    def test_delete_mid_read(self):
        self.viewer.extract()
        self.viewer.select('install.js')
        os.remove(os.path.join(self.viewer.dest, 'install.js'))
        res = self.viewer.read_file()
        eq_(res, '')
        assert self.viewer.selected['msg'].startswith('That file no')

    @patch('olympia.files.helpers.get_md5')
    def test_delete_mid_tree(self, get_md5):
        get_md5.side_effect = IOError('ow')
        self.viewer.extract()
        eq_({}, self.viewer.get_files())
Example #18
0
class TestSearchEngineHelper(TestCase):
    fixtures = ['base/addon_4594_a9']

    def setUp(self):
        super(TestSearchEngineHelper, self).setUp()
        self.left = File.objects.get(pk=25753)
        self.viewer = FileViewer(self.left)

        if not os.path.exists(os.path.dirname(self.viewer.src)):
            os.makedirs(os.path.dirname(self.viewer.src))
            with storage.open(self.viewer.src, 'w') as f:
                f.write('some data\n')

    def tearDown(self):
        self.viewer.cleanup()
        super(TestSearchEngineHelper, self).tearDown()

    def test_is_search_engine(self):
        assert self.viewer.is_search_engine()

    def test_extract_search_engine(self):
        self.viewer.extract()
        assert os.path.exists(self.viewer.dest)

    def test_default(self):
        self.viewer.extract()
        eq_(self.viewer.get_default(None), 'a9.xml')

    def test_default_no_files(self):
        self.viewer.extract()
        os.remove(os.path.join(self.viewer.dest, 'a9.xml'))
        eq_(self.viewer.get_default(None), None)
Example #19
0
 def test_default_webextension(self):
     viewer = FileViewer(make_file(2, get_file('webextension.xpi')))
     viewer.extract()
     assert viewer.get_default(None) == 'manifest.json'
Example #20
0
class FilesBase(object):
    def login_as_editor(self):
        assert self.client.login(username='******',
                                 password='******')

    def setUp(self):
        super(FilesBase, self).setUp()
        self.addon = Addon.objects.get(pk=3615)
        self.dev = self.addon.authors.all()[0]
        self.regular = UserProfile.objects.get(pk=999)
        self.version = self.addon.versions.latest()
        self.file = self.version.all_files[0]

        p = [amo.PLATFORM_LINUX.id, amo.PLATFORM_WIN.id, amo.PLATFORM_MAC.id]

        self.file.update(platform=p[0])

        self.files = [
            self.file,
            File.objects.create(version=self.version,
                                platform=p[1],
                                hash='abc123',
                                filename='dictionary-test.xpi'),
            File.objects.create(version=self.version,
                                platform=p[2],
                                hash='abc123',
                                filename='dictionary-test.xpi')
        ]

        self.login_as_editor()

        for file_obj in self.files:
            src = os.path.join(settings.ROOT, dictionary)
            try:
                os.makedirs(os.path.dirname(file_obj.file_path))
            except OSError:
                pass
            shutil.copyfile(src, file_obj.file_path)

        self.file_viewer = FileViewer(self.file)
        # Setting this to True, so we are delaying the extraction of files,
        # in the tests, the files won't be extracted.
        # Most of these tests extract as needed to.
        Switch.objects.get_or_create(name='delay-file-viewer', active=True)

    def tearDown(self):
        self.file_viewer.cleanup()
        super(FilesBase, self).tearDown()

    def files_redirect(self, file):
        return reverse('files.redirect', args=[self.file.pk, file])

    def files_serve(self, file):
        return reverse('files.serve', args=[self.file.pk, file])

    def test_view_access_anon(self):
        self.client.logout()
        self.check_urls(403)

    def test_view_access_anon_view_source(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.client.logout()
        self.check_urls(200)

    def test_view_access_editor(self):
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_editor_view_source(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_developer(self):
        self.client.logout()
        assert self.client.login(username=self.dev.email, password='******')
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_reviewed(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.client.logout()

        for status in amo.UNREVIEWED_STATUSES:
            self.addon.update(status=status)
            self.check_urls(403)

        for status in amo.REVIEWED_STATUSES:
            self.addon.update(status=status)
            self.check_urls(200)

    def test_view_access_developer_view_source(self):
        self.client.logout()
        assert self.client.login(username=self.dev.email, password='******')
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_another_developer(self):
        self.client.logout()
        assert self.client.login(username=self.regular.email,
                                 password='******')
        self.file_viewer.extract()
        self.check_urls(403)

    def test_view_access_another_developer_view_source(self):
        self.client.logout()
        assert self.client.login(username=self.regular.email,
                                 password='******')
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_poll_extracted(self):
        self.file_viewer.extract()
        res = self.client.get(self.poll_url())
        assert res.status_code == 200
        assert json.loads(res.content)['status']

    def test_poll_not_extracted(self):
        res = self.client.get(self.poll_url())
        assert res.status_code == 200
        assert not json.loads(res.content)['status']

    def test_poll_extracted_anon(self):
        self.client.logout()
        res = self.client.get(self.poll_url())
        assert res.status_code == 403

    def test_content_headers(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url('install.js'))
        assert 'etag' in res._headers
        assert 'last-modified' in res._headers

    def test_content_headers_etag(self):
        self.file_viewer.extract()
        self.file_viewer.select('install.js')
        obj = getattr(self.file_viewer, 'left', self.file_viewer)
        etag = obj.selected.get('md5')
        res = self.client.get(self.file_url('install.js'),
                              HTTP_IF_NONE_MATCH=etag)
        assert res.status_code == 304

    def test_content_headers_if_modified(self):
        self.file_viewer.extract()
        self.file_viewer.select('install.js')
        obj = getattr(self.file_viewer, 'left', self.file_viewer)
        date = http_date(obj.selected.get('modified'))
        res = self.client.get(self.file_url('install.js'),
                              HTTP_IF_MODIFIED_SINCE=date)
        assert res.status_code == 304

    def test_file_header(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        url = res.context['file_link']['url']
        assert url == reverse('editors.review', args=[self.addon.slug])

    def test_file_header_anon(self):
        self.client.logout()
        self.file_viewer.extract()
        self.addon.update(view_source=True)
        res = self.client.get(self.file_url(not_binary))
        url = res.context['file_link']['url']
        assert url == reverse('addons.detail', args=[self.addon.pk])

    def test_content_no_file(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url())
        doc = pq(res.content)
        assert len(doc('#content')) == 0

    def test_no_files(self):
        res = self.client.get(self.file_url())
        assert res.status_code == 200
        assert 'files' not in res.context

    @patch('waffle.switch_is_active')
    def test_no_files_switch(self, switch_is_active):
        switch_is_active.return_value = False
        # By setting the switch to False, we are not delaying the file
        # extraction. The files will be extracted and there will be
        # files in context.
        res = self.client.get(self.file_url())
        assert res.status_code == 200
        assert 'files' in res.context

    def test_files(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url())
        assert res.status_code == 200
        assert 'files' in res.context

    def test_files_anon(self):
        self.client.logout()
        res = self.client.get(self.file_url())
        assert res.status_code == 403

    def test_files_file(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        assert res.status_code == 200
        assert 'selected' in res.context

    def test_files_back_link(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        doc = pq(res.content)
        assert doc('#commands td:last').text() == 'Back to review'

    def test_files_back_link_anon(self):
        self.file_viewer.extract()
        self.client.logout()
        self.addon.update(view_source=True)
        res = self.client.get(self.file_url(not_binary))
        assert res.status_code == 200
        doc = pq(res.content)
        assert doc('#commands td:last').text() == 'Back to addon'

    def test_diff_redirect(self):
        ids = self.files[0].id, self.files[1].id

        res = self.client.post(self.file_url(), {
            'left': ids[0],
            'right': ids[1]
        })
        self.assert3xx(res, reverse('files.compare', args=ids))

    def test_browse_redirect(self):
        ids = self.files[0].id,

        res = self.client.post(self.file_url(), {'left': ids[0]})
        self.assert3xx(res, reverse('files.list', args=ids))

    def test_browse_404(self):
        res = self.client.get('/files/browse/file/dont/exist.png', follow=True)
        assert res.status_code == 404

    def test_invalid_redirect(self):
        res = self.client.post(self.file_url(), {})
        self.assert3xx(res, self.file_url())

    def test_file_chooser(self):
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left = doc('#id_left')
        assert len(left) == 1

        ver = left('optgroup')
        assert len(ver) == 1

        assert ver.attr('label') == self.version.version

        files = ver('option')
        assert len(files) == 2

    def test_file_chooser_coalescing(self):
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        unreviewed_file = doc('#id_left > optgroup > option.status-unreviewed')
        public_file = doc('#id_left > optgroup > option.status-public')
        assert public_file.text() == str(self.files[0].get_platform_display())
        assert unreviewed_file.text() == (
            '%s, %s' % (self.files[1].get_platform_display(),
                        self.files[2].get_platform_display()))

        assert public_file.attr('value') == str(self.files[0].id)
        assert unreviewed_file.attr('value') == str(self.files[1].id)

    def test_file_chooser_disabled_coalescing(self):
        self.files[1].update(status=amo.STATUS_DISABLED)

        res = self.client.get(self.file_url())
        doc = pq(res.content)

        disabled_file = doc('#id_left > optgroup > option.status-disabled')
        assert disabled_file.attr('value') == str(self.files[2].id)
Example #21
0
class FilesBase(object):

    def login_as_editor(self):
        assert self.client.login(username='******',
                                 password='******')

    def setUp(self):
        super(FilesBase, self).setUp()
        self.addon = Addon.objects.get(pk=3615)
        self.dev = self.addon.authors.all()[0]
        self.regular = UserProfile.objects.get(pk=999)
        self.version = self.addon.versions.latest()
        self.file = self.version.all_files[0]

        p = [amo.PLATFORM_LINUX.id, amo.PLATFORM_WIN.id, amo.PLATFORM_MAC.id]

        self.file.update(platform=p[0])

        self.files = [self.file,
                      File.objects.create(version=self.version,
                                          platform=p[1],
                                          hash='abc123',
                                          filename='dictionary-test.xpi'),
                      File.objects.create(version=self.version,
                                          platform=p[2],
                                          hash='abc123',
                                          filename='dictionary-test.xpi')]

        self.login_as_editor()

        for file_obj in self.files:
            src = os.path.join(settings.ROOT, dictionary)
            try:
                os.makedirs(os.path.dirname(file_obj.file_path))
            except OSError:
                pass
            shutil.copyfile(src, file_obj.file_path)

        self.file_viewer = FileViewer(self.file)
        # Setting this to True, so we are delaying the extraction of files,
        # in the tests, the files won't be extracted.
        # Most of these tests extract as needed to.
        Switch.objects.get_or_create(name='delay-file-viewer', active=True)

    def tearDown(self):
        self.file_viewer.cleanup()
        super(FilesBase, self).tearDown()

    def files_redirect(self, file):
        return reverse('files.redirect', args=[self.file.pk, file])

    def files_serve(self, file):
        return reverse('files.serve', args=[self.file.pk, file])

    def test_view_access_anon(self):
        self.client.logout()
        self.check_urls(403)

    def test_view_access_anon_view_source(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.client.logout()
        self.check_urls(200)

    def test_view_access_editor(self):
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_editor_view_source(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_developer(self):
        self.client.logout()
        assert self.client.login(username=self.dev.email, password='******')
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_reviewed(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.client.logout()

        for status in amo.UNREVIEWED_STATUSES:
            self.addon.update(status=status)
            self.check_urls(403)

        for status in amo.REVIEWED_STATUSES:
            self.addon.update(status=status)
            self.check_urls(200)

    def test_view_access_developer_view_source(self):
        self.client.logout()
        assert self.client.login(username=self.dev.email, password='******')
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_another_developer(self):
        self.client.logout()
        assert self.client.login(username=self.regular.email,
                                 password='******')
        self.file_viewer.extract()
        self.check_urls(403)

    def test_view_access_another_developer_view_source(self):
        self.client.logout()
        assert self.client.login(username=self.regular.email,
                                 password='******')
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_poll_extracted(self):
        self.file_viewer.extract()
        res = self.client.get(self.poll_url())
        eq_(res.status_code, 200)
        eq_(json.loads(res.content)['status'], True)

    def test_poll_not_extracted(self):
        res = self.client.get(self.poll_url())
        eq_(res.status_code, 200)
        eq_(json.loads(res.content)['status'], False)

    def test_poll_extracted_anon(self):
        self.client.logout()
        res = self.client.get(self.poll_url())
        eq_(res.status_code, 403)

    def test_content_headers(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url('install.js'))
        assert 'etag' in res._headers
        assert 'last-modified' in res._headers

    def test_content_headers_etag(self):
        self.file_viewer.extract()
        self.file_viewer.select('install.js')
        obj = getattr(self.file_viewer, 'left', self.file_viewer)
        etag = obj.selected.get('md5')
        res = self.client.get(self.file_url('install.js'),
                              HTTP_IF_NONE_MATCH=etag)
        eq_(res.status_code, 304)

    def test_content_headers_if_modified(self):
        self.file_viewer.extract()
        self.file_viewer.select('install.js')
        obj = getattr(self.file_viewer, 'left', self.file_viewer)
        date = http_date(obj.selected.get('modified'))
        res = self.client.get(self.file_url('install.js'),
                              HTTP_IF_MODIFIED_SINCE=date)
        eq_(res.status_code, 304)

    def test_file_header(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        url = res.context['file_link']['url']
        eq_(url, reverse('editors.review', args=[self.addon.slug]))

    def test_file_header_anon(self):
        self.client.logout()
        self.file_viewer.extract()
        self.addon.update(view_source=True)
        res = self.client.get(self.file_url(not_binary))
        url = res.context['file_link']['url']
        eq_(url, reverse('addons.detail', args=[self.addon.pk]))

    def test_content_no_file(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url())
        doc = pq(res.content)
        eq_(len(doc('#content')), 0)

    def test_no_files(self):
        res = self.client.get(self.file_url())
        eq_(res.status_code, 200)
        assert 'files' not in res.context

    @patch('waffle.switch_is_active')
    def test_no_files_switch(self, switch_is_active):
        switch_is_active.return_value = False
        # By setting the switch to False, we are not delaying the file
        # extraction. The files will be extracted and there will be
        # files in context.
        res = self.client.get(self.file_url())
        eq_(res.status_code, 200)
        assert 'files' in res.context

    def test_files(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url())
        eq_(res.status_code, 200)
        assert 'files' in res.context

    def test_files_anon(self):
        self.client.logout()
        res = self.client.get(self.file_url())
        eq_(res.status_code, 403)

    def test_files_file(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        eq_(res.status_code, 200)
        assert 'selected' in res.context

    def test_files_back_link(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        doc = pq(res.content)
        eq_(doc('#commands td:last').text(), 'Back to review')

    def test_files_back_link_anon(self):
        self.file_viewer.extract()
        self.client.logout()
        self.addon.update(view_source=True)
        res = self.client.get(self.file_url(not_binary))
        eq_(res.status_code, 200)
        doc = pq(res.content)
        eq_(doc('#commands td:last').text(), 'Back to addon')

    def test_diff_redirect(self):
        ids = self.files[0].id, self.files[1].id

        res = self.client.post(self.file_url(),
                               {'left': ids[0], 'right': ids[1]})
        self.assert3xx(res, reverse('files.compare', args=ids))

    def test_browse_redirect(self):
        ids = self.files[0].id,

        res = self.client.post(self.file_url(), {'left': ids[0]})
        self.assert3xx(res, reverse('files.list', args=ids))

    def test_browse_404(self):
        res = self.client.get('/files/browse/file/dont/exist.png', follow=True)
        eq_(res.status_code, 404)

    def test_invalid_redirect(self):
        res = self.client.post(self.file_url(), {})
        self.assert3xx(res, self.file_url())

    def test_file_chooser(self):
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left = doc('#id_left')
        eq_(len(left), 1)

        ver = left('optgroup')
        eq_(len(ver), 1)

        eq_(ver.attr('label'), self.version.version)

        files = ver('option')
        eq_(len(files), 2)

    def test_file_chooser_coalescing(self):
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        unreviewed_file = doc('#id_left > optgroup > option.status-unreviewed')
        public_file = doc('#id_left > optgroup > option.status-public')
        eq_(public_file.text(), str(self.files[0].get_platform_display()))
        eq_(unreviewed_file.text(),
            '%s, %s' % (self.files[1].get_platform_display(),
                        self.files[2].get_platform_display()))

        eq_(public_file.attr('value'), str(self.files[0].id))
        eq_(unreviewed_file.attr('value'), str(self.files[1].id))

    def test_file_chooser_disabled_coalescing(self):
        self.files[1].update(status=amo.STATUS_DISABLED)

        res = self.client.get(self.file_url())
        doc = pq(res.content)

        disabled_file = doc('#id_left > optgroup > option.status-disabled')
        eq_(disabled_file.attr('value'), str(self.files[2].id))
Example #22
0
 def test_default_package_json(self):
     viewer = FileViewer(make_file(3, get_file('new-format-0.0.1.xpi')))
     viewer.extract()
     assert viewer.get_default(None) == 'package.json'
Example #23
0
 def test_default_webextension_crx(self):
     viewer = FileViewer(make_file(2, get_file('webextension.crx')))
     viewer.extract()
     assert viewer.get_default(None) == 'manifest.json'
Example #24
0
 def test_default_package_json(self):
     viewer = FileViewer(make_file(3, get_file('new-format-0.0.1.xpi')))
     viewer.extract()
     assert viewer.get_default(None) == 'package.json'
Example #25
0
class TestSearchEngineHelper(TestCase):
    fixtures = ['base/addon_4594_a9']

    def setUp(self):
        super(TestSearchEngineHelper, self).setUp()
        self.left = File.objects.get(pk=25753)
        self.viewer = FileViewer(self.left)

        if not os.path.exists(os.path.dirname(self.viewer.src)):
            os.makedirs(os.path.dirname(self.viewer.src))
            with storage.open(self.viewer.src, 'w') as f:
                f.write('some data\n')

    def tearDown(self):
        self.viewer.cleanup()
        super(TestSearchEngineHelper, self).tearDown()

    def test_is_search_engine(self):
        assert self.viewer.is_search_engine()

    def test_extract_search_engine(self):
        self.viewer.extract()
        assert os.path.exists(self.viewer.dest)

    def test_default(self):
        self.viewer.extract()
        assert self.viewer.get_default(None) == 'a9.xml'

    def test_default_no_files(self):
        self.viewer.extract()
        os.remove(os.path.join(self.viewer.dest, 'a9.xml'))
        assert self.viewer.get_default(None) is None
Example #26
0
 def setUp(self):
     super(TestFileHelper, self).setUp()
     self.viewer = FileViewer(make_file(1, get_file('dictionary-test.xpi')))
Example #27
0
class FilesBase(object):

    def login_as_admin(self):
        assert self.client.login(email='*****@*****.**')

    def login_as_editor(self):
        assert self.client.login(email='*****@*****.**')

    def setUp(self):
        super(FilesBase, self).setUp()
        self.addon = Addon.objects.get(pk=3615)
        self.dev = self.addon.authors.all()[0]
        self.regular = UserProfile.objects.get(pk=999)
        self.version = self.addon.versions.latest()
        self.file = self.version.all_files[0]

        p = [amo.PLATFORM_LINUX.id, amo.PLATFORM_WIN.id, amo.PLATFORM_MAC.id]

        self.file.update(platform=p[0])

        self.files = [self.file,
                      File.objects.create(version=self.version,
                                          platform=p[1],
                                          hash='abc123',
                                          filename='dictionary-test.xpi'),
                      File.objects.create(version=self.version,
                                          platform=p[2],
                                          hash='abc123',
                                          filename='dictionary-test.xpi')]

        self.login_as_editor()

        for file_obj in self.files:
            src = os.path.join(settings.ROOT, dictionary)
            try:
                os.makedirs(os.path.dirname(file_obj.file_path))
            except OSError:
                pass
            shutil.copyfile(src, file_obj.file_path)

        self.file_viewer = FileViewer(self.file)

    def tearDown(self):
        self.file_viewer.cleanup()
        super(FilesBase, self).tearDown()

    def files_redirect(self, file):
        return reverse('files.redirect', args=[self.file.pk, file])

    def files_serve(self, file):
        return reverse('files.serve', args=[self.file.pk, file])

    def test_view_access_anon(self):
        self.client.logout()
        self.check_urls(403)

    def test_view_access_anon_view_source(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.client.logout()
        self.check_urls(200)

    def test_view_access_editor(self):
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_editor_view_source(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_developer(self):
        self.client.logout()
        assert self.client.login(email=self.dev.email)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_reviewed(self):
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.client.logout()

        for status in amo.UNREVIEWED_FILE_STATUSES:
            self.addon.update(status=status)
            self.check_urls(403)

        for status in amo.REVIEWED_STATUSES:
            self.addon.update(status=status)
            self.check_urls(200)

    def test_view_access_developer_view_source(self):
        self.client.logout()
        assert self.client.login(email=self.dev.email)
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_view_access_another_developer(self):
        self.client.logout()
        assert self.client.login(email=self.regular.email)
        self.file_viewer.extract()
        self.check_urls(403)

    def test_view_access_another_developer_view_source(self):
        self.client.logout()
        assert self.client.login(email=self.regular.email)
        self.addon.update(view_source=True)
        self.file_viewer.extract()
        self.check_urls(200)

    def test_poll_extracted(self):
        self.file_viewer.extract()
        res = self.client.get(self.poll_url())
        assert res.status_code == 200
        assert json.loads(res.content)['status']

    def test_poll_not_extracted(self):
        res = self.client.get(self.poll_url())
        assert res.status_code == 200
        assert not json.loads(res.content)['status']

    def test_poll_extracted_anon(self):
        self.client.logout()
        res = self.client.get(self.poll_url())
        assert res.status_code == 403

    def test_content_headers(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url('install.js'))
        assert 'etag' in res._headers
        assert 'last-modified' in res._headers

    def test_content_headers_etag(self):
        self.file_viewer.extract()
        self.file_viewer.select('install.js')
        obj = getattr(self.file_viewer, 'left', self.file_viewer)
        etag = obj.selected.get('md5')
        res = self.client.get(self.file_url('install.js'),
                              HTTP_IF_NONE_MATCH=etag)
        assert res.status_code == 304

    def test_content_headers_if_modified(self):
        self.file_viewer.extract()
        self.file_viewer.select('install.js')
        obj = getattr(self.file_viewer, 'left', self.file_viewer)
        date = http_date(obj.selected.get('modified'))
        res = self.client.get(self.file_url('install.js'),
                              HTTP_IF_MODIFIED_SINCE=date)
        assert res.status_code == 304

    def test_file_header(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        url = res.context['file_link']['url']
        assert url == reverse('editors.review', args=[self.addon.slug])

    def test_file_header_anon(self):
        self.client.logout()
        self.file_viewer.extract()
        self.addon.update(view_source=True)
        res = self.client.get(self.file_url(not_binary))
        url = res.context['file_link']['url']
        assert url == reverse('addons.detail', args=[self.addon.pk])

    def test_content_no_file(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url())
        doc = pq(res.content)
        assert len(doc('#content')) == 0

    def test_files(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url())
        assert res.status_code == 200
        assert 'files' in res.context

    def test_files_anon(self):
        self.client.logout()
        res = self.client.get(self.file_url())
        assert res.status_code == 403

    def test_files_file(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        assert res.status_code == 200
        assert 'selected' in res.context

    def test_files_back_link(self):
        self.file_viewer.extract()
        res = self.client.get(self.file_url(not_binary))
        doc = pq(res.content)
        assert doc('#commands td')[-1].text_content() == 'Back to review'

    def test_files_back_link_anon(self):
        self.file_viewer.extract()
        self.client.logout()
        self.addon.update(view_source=True)
        res = self.client.get(self.file_url(not_binary))
        assert res.status_code == 200
        doc = pq(res.content)
        assert doc('#commands td')[-1].text_content() == 'Back to add-on'

    def test_diff_redirect(self):
        ids = self.files[0].id, self.files[1].id

        res = self.client.post(self.file_url(),
                               {'left': ids[0], 'right': ids[1]})
        self.assert3xx(res, reverse('files.compare', args=ids))

    def test_browse_redirect(self):
        ids = self.files[0].id,

        res = self.client.post(self.file_url(), {'left': ids[0]})
        self.assert3xx(res, reverse('files.list', args=ids))

    def test_browse_404(self):
        res = self.client.get('/files/browse/file/dont/exist.png', follow=True)
        assert res.status_code == 404

    def test_invalid_redirect(self):
        res = self.client.post(self.file_url(), {})
        self.assert3xx(res, self.file_url())

    def test_file_chooser(self):
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left = doc('#id_left')
        assert len(left) == 1

        ver = left('optgroup')
        assert len(ver) == 1

        assert ver.attr('label') == self.version.version

        files = ver('option')
        assert len(files) == 2

    def test_file_chooser_coalescing(self):
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        unreviewed_file = doc('#id_left > optgroup > option.status-unreviewed')
        public_file = doc('#id_left > optgroup > option.status-public')
        assert public_file.text() == str(self.files[0].get_platform_display())
        assert unreviewed_file.text() == (
            '%s, %s' % (self.files[1].get_platform_display(),
                        self.files[2].get_platform_display()))

        assert public_file.attr('value') == str(self.files[0].id)
        assert unreviewed_file.attr('value') == str(self.files[1].id)

    def test_file_chooser_disabled_coalescing(self):
        self.files[1].update(status=amo.STATUS_DISABLED)

        res = self.client.get(self.file_url())
        doc = pq(res.content)

        disabled_file = doc('#id_left > optgroup > option.status-disabled')
        assert disabled_file.attr('value') == str(self.files[2].id)

    def test_files_for_unlisted_addon_returns_404(self):
        """Files browsing isn't allowed for unlisted addons."""
        self.make_addon_unlisted(self.addon)
        assert self.client.get(self.file_url()).status_code == 404

    def test_files_for_unlisted_addon_with_admin(self):
        """Files browsing is allowed for unlisted addons if you're admin."""
        self.login_as_admin()
        self.make_addon_unlisted(self.addon)
        assert self.client.get(self.file_url()).status_code == 200

    def test_all_versions_shown_for_admin(self):
        self.login_as_admin()
        listed_ver = version_factory(
            addon=self.addon, channel=amo.RELEASE_CHANNEL_LISTED,
            version='4.0', created=self.days_ago(1))
        unlisted_ver = version_factory(
            addon=self.addon, channel=amo.RELEASE_CHANNEL_UNLISTED,
            version='5.0')
        assert self.addon.versions.count() == 3
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left_select = doc('#id_left')
        assert left_select('optgroup').attr('label') == self.version.version
        file_options = left_select('option.status-public')
        assert len(file_options) == 3, left_select.html()
        # Check the files in the list are the two we added and the default.
        assert file_options.eq(0).attr('value') == str(
            unlisted_ver.all_files[0].pk)
        assert file_options.eq(1).attr('value') == str(
            listed_ver.all_files[0].pk)
        assert file_options.eq(2).attr('value') == str(self.file.pk)
        # Check there are prefixes on the labels for the channels
        assert file_options.eq(0).text().endswith('[Self]')
        assert file_options.eq(1).text().endswith('[AMO]')
        assert file_options.eq(2).text().endswith('[AMO]')

    def test_channel_prefix_not_shown_when_no_mixed_channels(self):
        self.login_as_admin()
        version_factory(addon=self.addon, channel=amo.RELEASE_CHANNEL_LISTED)
        assert self.addon.versions.count() == 2
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left_select = doc('#id_left')
        assert left_select('optgroup').attr('label') == self.version.version
        # Check there are NO prefixes on the labels for the channels
        file_options = left_select('option.status-public')
        assert not file_options.eq(0).text().endswith('[Self]')
        assert not file_options.eq(1).text().endswith('[AMO]')
        assert not file_options.eq(2).text().endswith('[AMO]')

    def test_only_listed_versions_shown_for_editor(self):
        listed_ver = version_factory(
            addon=self.addon, channel=amo.RELEASE_CHANNEL_LISTED,
            version='4.0')
        version_factory(
            addon=self.addon, channel=amo.RELEASE_CHANNEL_UNLISTED,
            version='5.0')
        assert self.addon.versions.count() == 3
        res = self.client.get(self.file_url())
        doc = pq(res.content)

        left_select = doc('#id_left')
        assert left_select('optgroup').attr('label') == self.version.version
        # Check the files in the list are just the listed, and the default.
        file_options = left_select('option.status-public')
        assert len(file_options) == 2, left_select.html()
        assert file_options.eq(0).attr('value') == str(
            listed_ver.all_files[0].pk)
        assert file_options.eq(1).attr('value') == str(self.file.pk)
        # Check there are NO prefixes on the labels for the channels
        assert not file_options.eq(0).text().endswith('[AMO]')
        assert not file_options.eq(1).text().endswith('[AMO]')