Example #1
0
    def test_validate_diff_missing_files(self):
        """Testing ValidateCommitForm.validate_diff for a subsequent commit
        with missing files
        """
        validation_info = base64.b64encode(
            json.dumps({
                'r1': {
                    'parent_id': 'r0',
                    'tree': {
                        'added': [],
                        'removed': [],
                        'modified': [],
                    },
                },
            }))

        form = ValidateCommitForm(repository=self.repository,
                                  request=self.request,
                                  data={
                                      'commit_id': 'r2',
                                      'parent_id': 'r1',
                                      'validation_info': validation_info,
                                  },
                                  files={
                                      'diff': self.diff,
                                  })

        self.assertTrue(form.is_valid())

        with self.assertRaises(FileNotFoundError):
            form.validate_diff()
Example #2
0
    def test_validate_diff_too_big(self):
        """Testing ValidateCommitForm.validate_diff for a diff that is too
        large
        """
        form = ValidateCommitForm(repository=self.repository,
                                  request=self.request,
                                  data={
                                      'commit_id': 'r1',
                                      'parent_id': 'r0',
                                  },
                                  files={
                                      'diff': self.diff,
                                  })

        self.assertTrue(form.is_valid())

        siteconfig = SiteConfiguration.objects.get_current()
        max_diff_size = siteconfig.get('diffviewer_max_diff_size')
        siteconfig.set('diffviewer_max_diff_size', 1)
        siteconfig.save()

        with self.assertRaises(DiffTooBigError):
            try:
                form.validate_diff()
            finally:
                siteconfig.set('diffviewer_max_diff_size', max_diff_size)
                siteconfig.save()
Example #3
0
    def test_validate_diff_too_big(self):
        """Testing ValidateCommitForm.validate_diff for a diff that is too
        large
        """
        form = ValidateCommitForm(
            repository=self.repository,
            request=self.request,
            data={
                'commit_id': 'r1',
                'parent_id': 'r0',
            },
            files={
                'diff': self.diff,
            })

        self.assertTrue(form.is_valid())

        siteconfig = SiteConfiguration.objects.get_current()
        max_diff_size = siteconfig.get('diffviewer_max_diff_size')
        siteconfig.set('diffviewer_max_diff_size', 1)
        siteconfig.save()

        with self.assertRaises(DiffTooBigError):
            try:
                form.validate_diff()
            finally:
                siteconfig.set('diffviewer_max_diff_size', max_diff_size)
                siteconfig.save()
Example #4
0
    def test_validate_diff_missing_files(self):
        """Testing ValidateCommitForm.validate_diff for a subsequent commit
        with missing files
        """
        validation_info = base64.b64encode(json.dumps({
            'r1': {
                'parent_id': 'r0',
                'tree': {
                    'added': [],
                    'removed': [],
                    'modified': [],
                },
            },
        }))

        form = ValidateCommitForm(
            repository=self.repository,
            request=self.request,
            data={
                'commit_id': 'r2',
                'parent_id': 'r1',
                'validation_info': validation_info,
            },
            files={
                'diff': self.diff,
            })

        self.assertTrue(form.is_valid())

        with self.assertRaises(FileNotFoundError):
            form.validate_diff()
Example #5
0
    def test_validate_diff(self):
        """Testing ValidateCommitForm.validate_diff"""
        self.spy_on(self.repository.get_file_exists,
                    call_fake=lambda *args, **kwargs: True)
        form = ValidateCommitForm(repository=self.repository,
                                  request=self.request,
                                  data={
                                      'commit_id': 'r1',
                                      'parent_id': 'r2',
                                  },
                                  files={
                                      'diff': self.diff,
                                  })

        self.assertTrue(form.is_valid())
        form.validate_diff()
Example #6
0
    def test_validate_diff(self):
        """Testing ValidateCommitForm.validate_diff"""
        self.spy_on(self.repository.get_file_exists,
                    call_fake=lambda *args, **kwargs: True)
        form = ValidateCommitForm(
            repository=self.repository,
            request=self.request,
            data={
                'commit_id': 'r1',
                'parent_id': 'r2',
            },
            files={
                'diff': self.diff,
            })

        self.assertTrue(form.is_valid())
        form.validate_diff()
Example #7
0
    def test_validate_diff_parser_error(self):
        """Testing ValidateCommitForm.validate_diff for an invalid diff"""
        form = ValidateCommitForm(
            repository=self.repository,
            request=self.request,
            data={
                'commit_id': 'r1',
                'parent_id': 'r0',
            },
            files={
                'diff': SimpleUploadedFile('diff', b'asdf',
                                           content_type='text/x-patch'),
            })

        self.assertTrue(form.is_valid())

        with self.assertRaises(DiffParserError):
            form.validate_diff()
Example #8
0
    def test_validate_diff_parser_error(self):
        """Testing ValidateCommitForm.validate_diff for an invalid diff"""
        form = ValidateCommitForm(
            repository=self.repository,
            request=self.request,
            data={
                'commit_id': 'r1',
                'parent_id': 'r0',
            },
            files={
                'diff': SimpleUploadedFile('diff', b'asdf',
                                           content_type='text/x-patch'),
            })

        self.assertTrue(form.is_valid())

        with self.assertRaises(DiffParserError):
            form.validate_diff()
Example #9
0
    def test_validate_diff_subsequent_commit(self):
        """Testing ValidateCommitForm.validate_diff for a subsequent commit"""
        diff_content = (
            b'diff --git a/foo b/foo\n'
            b'index %s..%s 1000644\n'
            b'--- a/foo\n'
            b'+++ b/foo\n'
            b'@@ -0,0 +1,2 @@\n'
            b'+This is not a new file.\n'
            % (b'a' * 40, b'b' * 40)
        )
        diff = SimpleUploadedFile('diff', diff_content,
                                  content_type='text/x-patch')

        validation_info = base64.b64encode(json.dumps({
            'r1': {
                'parent_id': 'r0',
                'tree': {
                    'added': [{
                        'filename': 'foo',
                        'revision': 'a' * 40,
                    }],
                    'removed': [],
                    'modified': [],
                },
            },
        }))

        form = ValidateCommitForm(
            repository=self.repository,
            request=self.request,
            data={
                'commit_id': 'r2',
                'parent_id': 'r1',
                'validation_info': validation_info,
            },
            files={
                'diff': diff,
            })

        self.assertTrue(form.is_valid())
        form.validate_diff()
Example #10
0
    def test_validate_diff_subsequent_commit(self):
        """Testing ValidateCommitForm.validate_diff for a subsequent commit"""
        diff_content = (
            b'diff --git a/foo b/foo\n'
            b'index %s..%s 100644\n'
            b'--- a/foo\n'
            b'+++ b/foo\n'
            b'@@ -0,0 +1,2 @@\n'
            b'+This is not a new file.\n'
            % (b'a' * 40, b'b' * 40)
        )
        diff = SimpleUploadedFile('diff', diff_content,
                                  content_type='text/x-patch')

        validation_info = self._base64_json({
            'r1': {
                'parent_id': 'r0',
                'tree': {
                    'added': [{
                        'filename': 'foo',
                        'revision': 'a' * 40,
                    }],
                    'removed': [],
                    'modified': [],
                },
            },
        })

        form = ValidateCommitForm(
            repository=self.repository,
            request=self.request,
            data={
                'commit_id': 'r2',
                'parent_id': 'r1',
                'validation_info': validation_info,
            },
            files={
                'diff': diff,
            })

        self.assertTrue(form.is_valid())
        form.validate_diff()
Example #11
0
    def test_validate_diff_too_big(self):
        """Testing ValidateCommitForm.validate_diff for a diff that is too
        large
        """
        form = ValidateCommitForm(repository=self.repository,
                                  request=self.request,
                                  data={
                                      'commit_id': 'r1',
                                      'parent_id': 'r0',
                                  },
                                  files={
                                      'diff': self.diff,
                                  })

        self.assertTrue(form.is_valid())

        with self.assertRaises(DiffTooBigError):
            with self.siteconfig_settings({'diffviewer_max_diff_size': 1},
                                          reload_settings=False):
                form.validate_diff()
Example #12
0
    def create(self,
               request,
               repository,
               commit_id,
               parent_id,
               base_commit_id=None,
               local_site_name=None,
               *args,
               **kwargs):
        """Validate a diff for a commit.

        This API has a similar signature to the :ref:`Draft DiffCommit resource
        <webapi2.0-draft-diff-commit-list-resource>` POST API, but instead of
        actually creating commits, it will return a result representing whether
        or not the included diff file parsed and validated correctly.

        This API must be called before posting to the :ref:`Draft DiffCommit
        resource <webapi2.0-draft-diff-commit-list-resource>` because the
        ``validation_info`` field returned by this resource is required for
        posting to that resource.
        """
        local_site = self._get_local_site(local_site_name)

        try:
            q = Q(pk=int(repository))
        except ValueError:
            q = (Q(path=repository) | Q(mirror_path=repository)
                 | Q(name=repository))

        repository_qs = (Repository.objects.accessible(
            request.user, local_site=local_site).filter(q))
        repository_count = len(repository_qs)

        if repository_count == 0:
            return INVALID_REPOSITORY, {
                'repository': repository,
            }
        elif repository_count > 1:
            msg = ('Too many repositories matched "%s". Try specifying the '
                   'repository by name instead.' % repository)

            return INVALID_REPOSITORY.with_message(msg), {
                'repository': repository,
            }

        repository = repository_qs.first()

        if not repository.scmtool_class.supports_history:
            return INVALID_ATTRIBUTE, {
                'reason':
                ('The "%s" repository does not support review requests '
                 'created with history.' % repository.name),
            }

        form = ValidateCommitForm(repository=repository,
                                  request=request,
                                  data=request.POST,
                                  files=request.FILES)

        if not form.is_valid():
            return INVALID_FORM_DATA, {
                'fields': self._get_form_errors(form),
            }

        try:
            filediffs = form.validate_diff()
        except FileNotFoundError as e:
            return REPO_FILE_NOT_FOUND, {
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except EmptyDiffError:
            return DIFF_EMPTY
        except DiffTooBigError as e:
            return DIFF_TOO_BIG, {
                'reason': six.text_type(e),
                'max_size': e.max_diff_size,
            }
        except DiffParserError as e:
            return DIFF_PARSE_ERROR, {
                'reason': six.text_type(e),
                'linenum': e.linenum,
            }
        except ShortSHA1Error as e:
            return REPO_FILE_NOT_FOUND, {
                'reason': six.text_type(e),
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except SCMError as e:
            return DIFF_PARSE_ERROR.with_message(six.text_type(e))
        except Exception as e:
            logger.exception(
                'Unexpected exception occurred while validating commit "%s" '
                'in repository "%s" (id %d) with base_commit_id="%s"',
                commit_id,
                repository.name,
                repository.pk,
                base_commit_id,
                request=request)
            return DIFF_PARSE_ERROR.with_message(
                'Unexpected error while validating the diff: %s' % e)

        validation_info = update_validation_info(
            form.cleaned_data.get('validation_info', {}), commit_id, parent_id,
            filediffs)

        return 200, {
            self.item_result_key: {
                'validation_info': serialize_validation_info(validation_info),
            }
        }
    def create(self, request, repository, commit_id, parent_id,
               base_commit_id=None, local_site_name=None, *args, **kwargs):
        """Validate a diff for a commit.

        This API has a similar signature to the :ref:`Draft DiffCommit resource
        <webapi2.0-draft-diff-commit-list-resource>` POST API, but instead of
        actually creating commits, it will return a result representing whether
        or not the included diff file parsed and validated correctly.

        This API must be called before posting to the :ref:`Draft DiffCommit
        resource <webapi2.0-draft-diff-commit-list-resource>` because the
        ``validation_info`` field returned by this resource is required for
        posting to that resource.
        """
        local_site = self._get_local_site(local_site_name)

        try:
            q = Q(pk=int(repository))
        except ValueError:
            q = (Q(path=repository) |
                 Q(mirror_path=repository) |
                 Q(name=repository))

        repository_qs = (
            Repository.objects
            .accessible(request.user, local_site=local_site)
            .filter(q)
        )
        repository_count = len(repository_qs)

        if repository_count == 0:
            return INVALID_REPOSITORY, {
                'repository': repository,
            }
        elif repository_count > 1:
            msg = (
                'Too many repositories matched "%s". Try specifying the '
                'repository by name instead.'
                % repository
            )

            return INVALID_REPOSITORY.with_message(msg), {
                'repository': repository,
            }

        repository = repository_qs.first()

        if not repository.scmtool_class.supports_history:
            return INVALID_ATTRIBUTE, {
                'reason': (
                    'The "%s" repository does not support review requests '
                    'created with history.'
                    % repository.name
                ),
            }

        form = ValidateCommitForm(repository=repository,
                                  request=request,
                                  data=request.POST,
                                  files=request.FILES)

        if not form.is_valid():
            return INVALID_FORM_DATA, {
                'fields': self._get_form_errors(form),
            }

        try:
            filediffs = form.validate_diff()
        except FileNotFoundError as e:
            return REPO_FILE_NOT_FOUND, {
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except EmptyDiffError:
            return DIFF_EMPTY
        except DiffTooBigError as e:
            return DIFF_TOO_BIG, {
                'reason': six.text_type(e),
                'max_size': e.max_diff_size,
            }
        except DiffParserError as e:
            return DIFF_PARSE_ERROR, {
                'reason': six.text_type(e),
                'linenum': e.linenum,
            }
        except ShortSHA1Error as e:
            return REPO_FILE_NOT_FOUND, {
                'reason': six.text_type(e),
                'file': e.path,
                'revision': six.text_type(e.revision),
            }
        except SCMError as e:
            return DIFF_PARSE_ERROR.with_message(six.text_type(e))
        except Exception as e:
            logger.exception(
                'Unexpected exception occurred while validating commit "%s" '
                'in repository "%s" (id %d) with base_commit_id="%s"',
                commit_id,
                repository.name,
                repository.pk,
                base_commit_id,
                request=request)
            return DIFF_PARSE_ERROR.with_message(
                'Unexpected error while validating the diff: %s' % e)

        validation_info = update_validation_info(
            form.cleaned_data.get('validation_info', {}),
            commit_id,
            parent_id,
            filediffs)

        return 200, {
            self.item_result_key: {
                'validation_info': serialize_validation_info(
                    validation_info),
            }
        }