123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- from __future__ import absolute_import
- import unittest
- from sentry.utils.compat.mock import patch
- from datetime import datetime
- import pytz
- from django.core.urlresolvers import reverse
- from sentry.constants import MAX_VERSION_LENGTH
- from sentry.models import (
- Activity,
- Environment,
- File,
- Release,
- ReleaseCommit,
- ReleaseFile,
- ReleaseProject,
- ReleaseProjectEnvironment,
- Repository,
- )
- from sentry.testutils import APITestCase
- from sentry.api.endpoints.organization_release_details import OrganizationReleaseSerializer
- class ReleaseDetailsTest(APITestCase):
- def test_simple(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- team1 = self.create_team(organization=org)
- team2 = self.create_team(organization=org)
- project = self.create_project(teams=[team1], organization=org)
- project2 = self.create_project(teams=[team2], organization=org)
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release2 = Release.objects.create(organization_id=org.id, version="12345678")
- release.add_project(project)
- release2.add_project(project2)
- environment = Environment.objects.create(organization_id=org.id, name="prod")
- environment.add_project(project)
- environment.add_project(project2)
- self.create_member(teams=[team1], user=user, organization=org)
- self.login_as(user=user)
- ReleaseProjectEnvironment.objects.create(
- project_id=project.id,
- release_id=release.id,
- environment_id=environment.id,
- new_issues_count=5,
- )
- ReleaseProject.objects.filter(project=project, release=release).update(new_groups=5)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.get(url)
- assert response.status_code == 200, response.content
- assert response.data["version"] == release.version
- assert response.data["newGroups"] == 5
- # no access
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release2.version},
- )
- response = self.client.get(url)
- assert response.status_code == 404
- def test_multiple_projects(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- team1 = self.create_team(organization=org)
- team2 = self.create_team(organization=org)
- project = self.create_project(teams=[team1], organization=org)
- project2 = self.create_project(teams=[team2], organization=org)
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release.add_project(project)
- release.add_project(project2)
- self.create_member(teams=[team1, team2], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.get(url)
- assert response.status_code == 200, response.content
- def test_wrong_project(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- team1 = self.create_team(organization=org)
- project = self.create_project(teams=[team1], organization=org)
- project2 = self.create_project(teams=[team1], organization=org)
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release.add_project(project)
- self.create_member(teams=[team1], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.get(url, {"project": project2.id})
- assert response.status_code == 404
- response = self.client.get(url, {"project": project.id})
- assert response.status_code == 200
- class UpdateReleaseDetailsTest(APITestCase):
- @patch("sentry.tasks.commits.fetch_commits")
- def test_simple(self, mock_fetch_commits):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- repo = Repository.objects.create(
- organization_id=org.id, name="example/example", provider="dummy"
- )
- repo2 = Repository.objects.create(
- organization_id=org.id, name="example/example2", provider="dummy"
- )
- team1 = self.create_team(organization=org)
- team2 = self.create_team(organization=org)
- project = self.create_project(teams=[team1], organization=org)
- project2 = self.create_project(teams=[team2], organization=org)
- base_release = Release.objects.create(organization_id=org.id, version="000000000")
- base_release.add_project(project)
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release2 = Release.objects.create(organization_id=org.id, version="12345678")
- release.add_project(project)
- release2.add_project(project2)
- self.create_member(teams=[team1], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": base_release.version},
- )
- self.client.put(
- url,
- {
- "ref": "master",
- "headCommits": [
- {"currentId": "0" * 40, "repository": repo.name},
- {"currentId": "0" * 40, "repository": repo2.name},
- ],
- },
- )
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.put(
- url,
- {
- "ref": "master",
- "refs": [
- {"commit": "a" * 40, "repository": repo.name},
- {"commit": "b" * 40, "repository": repo2.name},
- ],
- },
- )
- mock_fetch_commits.apply_async.assert_called_with(
- kwargs={
- "release_id": release.id,
- "user_id": user.id,
- "refs": [
- {"commit": "a" * 40, "repository": repo.name},
- {"commit": "b" * 40, "repository": repo2.name},
- ],
- "prev_release_id": base_release.id,
- }
- )
- assert response.status_code == 200, response.content
- assert response.data["version"] == release.version
- release = Release.objects.get(id=release.id)
- assert release.ref == "master"
- # no access
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release2.version},
- )
- response = self.client.put(url, {"ref": "master"})
- assert response.status_code == 404
- @patch("sentry.tasks.commits.fetch_commits")
- def test_deprecated_head_commits(self, mock_fetch_commits):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- repo = Repository.objects.create(
- organization_id=org.id, name="example/example", provider="dummy"
- )
- repo2 = Repository.objects.create(
- organization_id=org.id, name="example/example2", provider="dummy"
- )
- team1 = self.create_team(organization=org)
- team2 = self.create_team(organization=org)
- project = self.create_project(teams=[team1], organization=org)
- project2 = self.create_project(teams=[team2], organization=org)
- base_release = Release.objects.create(organization_id=org.id, version="000000000")
- base_release.add_project(project)
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release2 = Release.objects.create(organization_id=org.id, version="12345678")
- release.add_project(project)
- release2.add_project(project2)
- self.create_member(teams=[team1], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": base_release.version},
- )
- self.client.put(
- url,
- {
- "ref": "master",
- "headCommits": [
- {"currentId": "0" * 40, "repository": repo.name},
- {"currentId": "0" * 40, "repository": repo2.name},
- ],
- },
- )
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.put(
- url,
- {
- "ref": "master",
- "headCommits": [
- {"currentId": "a" * 40, "repository": repo.name},
- {"currentId": "b" * 40, "repository": repo2.name},
- ],
- },
- )
- mock_fetch_commits.apply_async.assert_called_with(
- kwargs={
- "release_id": release.id,
- "user_id": user.id,
- "refs": [
- {"commit": "a" * 40, "previousCommit": None, "repository": repo.name},
- {"commit": "b" * 40, "previousCommit": None, "repository": repo2.name},
- ],
- "prev_release_id": base_release.id,
- }
- )
- assert response.status_code == 200, response.content
- assert response.data["version"] == release.version
- release = Release.objects.get(id=release.id)
- assert release.ref == "master"
- # no access
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release2.version},
- )
- response = self.client.put(url, {"ref": "master"})
- assert response.status_code == 404
- def test_commits(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- team = self.create_team(organization=org)
- project = self.create_project(teams=[team], organization=org)
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release.add_project(project)
- self.create_member(teams=[team], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.put(url, data={"commits": [{"id": "a" * 40}, {"id": "b" * 40}]})
- assert response.status_code == 200, (response.status_code, response.content)
- rc_list = list(
- ReleaseCommit.objects.filter(release=release)
- .select_related("commit", "commit__author")
- .order_by("order")
- )
- assert len(rc_list) == 2
- for rc in rc_list:
- assert rc.organization_id == org.id
- def test_activity_generation(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- team = self.create_team(organization=org)
- project = self.create_project(teams=[team], organization=org)
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release.add_project(project)
- self.create_member(teams=[team], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.put(url, data={"dateReleased": datetime.utcnow().isoformat() + "Z"})
- assert response.status_code == 200, (response.status_code, response.content)
- release = Release.objects.get(id=release.id)
- assert release.date_released
- activity = Activity.objects.filter(
- type=Activity.RELEASE, project=project, ident=release.version
- )
- assert activity.exists()
- def test_activity_generation_long_release(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- team = self.create_team(organization=org)
- project = self.create_project(teams=[team], organization=org)
- release = Release.objects.create(organization_id=org.id, version="x" * 65)
- release.add_project(project)
- self.create_member(teams=[team], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.put(url, data={"dateReleased": datetime.utcnow().isoformat() + "Z"})
- assert response.status_code == 200, (response.status_code, response.content)
- release = Release.objects.get(id=release.id)
- assert release.date_released
- activity = Activity.objects.filter(
- type=Activity.RELEASE, project=project, ident=release.version[:64]
- )
- assert activity.exists()
- class ReleaseDeleteTest(APITestCase):
- def test_simple(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- team = self.create_team(organization=org)
- project = self.create_project(teams=[team], organization=org)
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release.add_project(project)
- self.create_member(teams=[team], user=user, organization=org)
- self.login_as(user=user)
- release_file = ReleaseFile.objects.create(
- organization_id=project.organization_id,
- release=release,
- file=File.objects.create(name="application.js", type="release.file"),
- name="http://example.com/application.js",
- )
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.delete(url)
- assert response.status_code == 204, response.content
- assert not Release.objects.filter(id=release.id).exists()
- assert not ReleaseFile.objects.filter(id=release_file.id).exists()
- def test_existing_group(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.organization
- org.flags.allow_joinleave = False
- org.save()
- team = self.create_team(organization=org)
- project = self.create_project(teams=[team], organization=org)
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release.add_project(project)
- self.create_group(first_release=release)
- self.create_member(teams=[team], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.delete(url)
- assert response.status_code == 400, response.content
- assert Release.objects.filter(id=release.id).exists()
- def test_bad_repo_name(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.create_organization()
- org.flags.allow_joinleave = False
- org.save()
- team = self.create_team(organization=org)
- project = self.create_project(name="foo", organization=org, teams=[team])
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release.add_project(project)
- self.create_member(teams=[team], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.put(
- url,
- data={
- "version": "1.2.1",
- "projects": [project.slug],
- "refs": [{"repository": "not_a_repo", "commit": "a" * 40}],
- },
- )
- assert response.status_code == 400
- assert response.data == {"refs": [u"Invalid repository names: not_a_repo"]}
- def test_bad_commit_list(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.create_organization()
- org.flags.allow_joinleave = False
- org.save()
- team = self.create_team(organization=org)
- project = self.create_project(name="foo", organization=org, teams=[team])
- Repository.objects.create(organization_id=org.id, name="a_repo")
- release = Release.objects.create(organization_id=org.id, version="abcabcabc")
- release.add_project(project)
- self.create_member(teams=[team], user=user, organization=org)
- self.login_as(user=user)
- url = reverse(
- "sentry-api-0-organization-release-details",
- kwargs={"organization_slug": org.slug, "version": release.version},
- )
- response = self.client.put(
- url,
- data={
- "version": "1.2.1",
- "projects": [project.slug],
- "commits": [{"repository": "a_repo"}],
- },
- )
- assert response.status_code == 400
- assert response.data == {"commits": {"id": ["This field is required."]}}
- class ReleaseSerializerTest(unittest.TestCase):
- def setUp(self):
- super(ReleaseSerializerTest, self).setUp()
- self.repo_name = "repo/name"
- self.repo2_name = "repo2/name"
- self.commits = [{"id": "a" * 40}, {"id": "b" * 40}]
- self.ref = "master"
- self.url = "https://example.com"
- self.dateReleased = "1000-10-10T06:06"
- self.headCommits = [
- {"currentId": "0" * 40, "repository": self.repo_name},
- {"currentId": "0" * 40, "repository": self.repo2_name},
- ]
- self.refs = [
- {"commit": "a" * 40, "previousCommit": "", "repository": self.repo_name},
- {"commit": "b" * 40, "previousCommit": "", "repository": self.repo2_name},
- ]
- def test_simple(self):
- serializer = OrganizationReleaseSerializer(
- data={
- "ref": self.ref,
- "url": self.url,
- "dateReleased": self.dateReleased,
- "commits": self.commits,
- "headCommits": self.headCommits,
- "refs": self.refs,
- }
- )
- assert serializer.is_valid()
- assert sorted(serializer.fields.keys()) == sorted(
- ["ref", "url", "dateReleased", "commits", "headCommits", "refs"]
- )
- result = serializer.validated_data
- assert result["ref"] == self.ref
- assert result["url"] == self.url
- assert result["dateReleased"] == datetime(1000, 10, 10, 6, 6, tzinfo=pytz.UTC)
- assert result["commits"] == self.commits
- assert result["headCommits"] == self.headCommits
- assert result["refs"] == self.refs
- def test_fields_not_required(self):
- serializer = OrganizationReleaseSerializer(data={})
- assert serializer.is_valid()
- def test_do_not_allow_null_commits(self):
- serializer = OrganizationReleaseSerializer(data={"commits": None})
- assert not serializer.is_valid()
- def test_do_not_allow_null_head_commits(self):
- serializer = OrganizationReleaseSerializer(data={"headCommits": None})
- assert not serializer.is_valid()
- def test_do_not_allow_null_refs(self):
- serializer = OrganizationReleaseSerializer(data={"refs": None})
- assert not serializer.is_valid()
- def test_ref_limited_by_max_version_length(self):
- serializer = OrganizationReleaseSerializer(data={"ref": "a" * MAX_VERSION_LENGTH})
- assert serializer.is_valid()
- serializer = OrganizationReleaseSerializer(data={"ref": "a" * (MAX_VERSION_LENGTH + 1)})
- assert not serializer.is_valid()
- def test_author_email_patch(self):
- serializer = OrganizationReleaseSerializer(
- data={"commits": [{"id": "a", "author_email": "email[test]@example.org"}]}
- )
- assert serializer.is_valid()
|