|
2 | 2 |
|
3 | 3 | from typing import Any
|
4 | 4 | from unittest.mock import patch
|
| 5 | +from uuid import uuid4 |
5 | 6 |
|
6 |
| -from django.urls import reverse |
7 |
| - |
| 7 | +from sentry.models.sentryfunction import SentryFunction |
8 | 8 | from sentry.testutils.cases import APITestCase
|
9 |
| -from sentry.testutils.helpers import Feature |
| 9 | +from sentry.testutils.helpers.features import with_feature |
10 | 10 | from sentry.testutils.silo import region_silo_test
|
11 | 11 |
|
12 | 12 |
|
13 |
| -@region_silo_test(stable=True) |
14 |
| -class OrganizationSentryFunctions(APITestCase): |
| 13 | +class OrganizationSentryFunctionBase(APITestCase): |
15 | 14 | endpoint = "sentry-api-0-organization-sentry-functions"
|
16 | 15 |
|
17 | 16 | def setUp(self):
|
18 | 17 | super().setUp()
|
19 |
| - self.create_organization(owner=self.user, name="RowdyTiger") |
20 |
| - self.url = reverse(self.endpoint, args=[self.organization.slug]) |
21 | 18 | self.login_as(user=self.user)
|
| 19 | + self.code = "exports.yourFunction = (req, res) => {\n\tlet message = req.query.message || req.body.message || 'Hello World!';\n\tconsole.log('Query: ' + req.query);\n\tconsole.log('Body: ' + req.body);\n\tres.status(200).send(message);\n};" |
| 20 | + self.data: dict[str, Any] = { |
| 21 | + "name": "foo", |
| 22 | + "author": "bar", |
| 23 | + "code": self.code, |
| 24 | + "overview": "qux", |
| 25 | + } |
| 26 | + |
| 27 | + |
| 28 | +@region_silo_test(stable=True) |
| 29 | +class OrganizationSentryFunctionsPost(OrganizationSentryFunctionBase): |
| 30 | + method = "POST" |
| 31 | + |
| 32 | + def setUp(self): |
| 33 | + super().setUp() |
| 34 | + self.login_as(user=self.user) |
| 35 | + self.data["env_variables"] = [{"name": "foo", "value": "bar"}] |
22 | 36 |
|
| 37 | + @with_feature("organizations:sentry-functions") |
23 | 38 | @patch("sentry.api.endpoints.organization_sentry_function.create_function")
|
24 | 39 | def test_post_feature_true(self, mock_func):
|
25 |
| - defaultCode = "exports.yourFunction = (req, res) => {\n\tlet message = req.query.message || req.body.message || 'Hello World!';\n\tconsole.log('Query: ' + req.query);\n\tconsole.log('Body: ' + req.body);\n\tres.status(200).send(message);\n};" |
26 |
| - data = { |
| 40 | + response = self.get_success_response(self.organization.slug, status_code=201, **self.data) |
| 41 | + |
| 42 | + assert response.data == { |
27 | 43 | "name": "foo",
|
| 44 | + "slug": "foo", |
28 | 45 | "author": "bar",
|
29 |
| - "code": defaultCode, |
| 46 | + "code": self.code, |
30 | 47 | "overview": "qux",
|
31 |
| - "envVariables": [{"name": "foo", "value": "bar"}], |
| 48 | + # skip checking external id because it has a random suffix |
| 49 | + "external_id": response.data["external_id"], |
| 50 | + "events": [], |
| 51 | + "env_variables": [{"name": "foo", "value": "bar"}], |
32 | 52 | }
|
33 |
| - with Feature("organizations:sentry-functions"): |
34 |
| - response = self.client.post(self.url, data) |
35 |
| - assert response.status_code == 201 |
36 |
| - assert response.data["name"] == "foo" |
37 |
| - assert response.data["author"] == "bar" |
38 |
| - assert response.data["code"] == defaultCode |
39 |
| - assert response.data["overview"] == "qux" |
40 |
| - mock_func.assert_called_once_with( |
41 |
| - defaultCode, response.data["external_id"], "qux", {"foo": "bar"} |
42 |
| - ) |
43 | 53 |
|
| 54 | + mock_func.assert_called_once_with( |
| 55 | + self.code, response.data["external_id"], "qux", {"foo": "bar"} |
| 56 | + ) |
| 57 | + |
| 58 | + @with_feature("organizations:sentry-functions") |
| 59 | + @patch("sentry.api.endpoints.organization_sentry_function.create_function") |
| 60 | + def test_generated_slug_not_entirely_numeric(self, mock_func): |
| 61 | + data = {**self.data, "name": "123"} |
| 62 | + response = self.get_success_response(self.organization.slug, status_code=201, **data) |
| 63 | + |
| 64 | + assert response.data["name"] == "123" |
| 65 | + assert response.data["author"] == "bar" |
| 66 | + assert response.data["code"] == self.code |
| 67 | + assert response.data["overview"] == "qux" |
| 68 | + |
| 69 | + slug = response.data["slug"] |
| 70 | + assert not slug.isdecimal() |
| 71 | + assert slug.startswith("123-") |
| 72 | + |
| 73 | + mock_func.assert_called_once_with( |
| 74 | + self.code, response.data["external_id"], "qux", {"foo": "bar"} |
| 75 | + ) |
| 76 | + |
| 77 | + @with_feature("organizations:sentry-functions") |
44 | 78 | def test_post_missing_params(self):
|
45 |
| - data: dict[str, Any] = {"name": "foo", "overview": "qux"} |
46 |
| - with Feature("organizations:sentry-functions"): |
47 |
| - response = self.client.post(self.url, **data) |
48 |
| - assert response.status_code == 400 |
| 79 | + data = {"name": "foo", "overview": "qux"} |
| 80 | + self.get_error_response(self.organization.slug, status_code=400, **data) |
49 | 81 |
|
50 | 82 | def test_post_feature_false(self):
|
51 |
| - data: dict[str, Any] = {"name": "foo", "author": "bar"} |
52 |
| - response = self.client.post(self.url, **data) |
53 |
| - assert response.status_code == 404 |
| 83 | + data = {"name": "foo", "author": "bar"} |
| 84 | + response = self.get_error_response(self.organization.slug, status_code=404, **data) |
| 85 | + assert response.data == "organizations:sentry-functions flag set to false" |
54 | 86 |
|
55 |
| - def test_get(self): |
56 |
| - with Feature("organizations:sentry-functions"): |
57 |
| - response = self.client.get(self.url) |
58 |
| - assert response.status_code == 200 |
59 |
| - assert response.data == [] |
60 | 87 |
|
61 |
| - @patch("sentry.api.endpoints.organization_sentry_function.create_function") |
62 |
| - def test_get_with_function(self, mock_func): |
63 |
| - defaultCode = "exports.yourFunction = (req, res) => {\n\tlet message = req.query.message || req.body.message || 'Hello World!';\n\tconsole.log('Query: ' + req.query);\n\tconsole.log('Body: ' + req.body);\n\tres.status(200).send(message);\n};" |
64 |
| - data = { |
| 88 | +@region_silo_test(stable=True) |
| 89 | +class OrganizationSentryFunctionsGet(OrganizationSentryFunctionBase): |
| 90 | + endpoint = "sentry-api-0-organization-sentry-functions" |
| 91 | + method = "GET" |
| 92 | + |
| 93 | + def setUp(self): |
| 94 | + super().setUp() |
| 95 | + self.login_as(user=self.user) |
| 96 | + self.post_data = { |
| 97 | + **self.data, |
| 98 | + "slug": "foo", |
| 99 | + "organization_id": self.organization.id, |
| 100 | + "external_id": "foo-" + uuid4().hex, |
| 101 | + } |
| 102 | + |
| 103 | + @with_feature("organizations:sentry-functions") |
| 104 | + def test_get_empty(self): |
| 105 | + response = self.get_success_response(self.organization.slug, status_code=200) |
| 106 | + assert response.data == [] |
| 107 | + |
| 108 | + @with_feature("organizations:sentry-functions") |
| 109 | + def test_get_with_function(self): |
| 110 | + SentryFunction.objects.create(**self.post_data) |
| 111 | + response = self.get_success_response(self.organization.slug, status_code=200) |
| 112 | + assert response.data[0] == { |
| 113 | + "name": "foo", |
| 114 | + "slug": "foo", |
| 115 | + "author": "bar", |
| 116 | + "code": self.code, |
| 117 | + "overview": "qux", |
| 118 | + "external_id": self.post_data["external_id"], |
| 119 | + "events": [], |
| 120 | + "env_variables": [], |
| 121 | + } |
| 122 | + |
| 123 | + @with_feature("organizations:sentry-functions") |
| 124 | + def test_get_with_function_and_env_variables(self): |
| 125 | + # env_variables is expected to be a single dict of key-value pairs if |
| 126 | + # you're directly creating a SentryFunction object using .create() |
| 127 | + SentryFunction.objects.create(**self.post_data, env_variables={"foo": "bar", "baz": "qux"}) |
| 128 | + response = self.get_success_response(self.organization.slug, status_code=200) |
| 129 | + assert response.data[0] == { |
65 | 130 | "name": "foo",
|
| 131 | + "slug": "foo", |
66 | 132 | "author": "bar",
|
67 |
| - "code": defaultCode, |
| 133 | + "code": self.code, |
68 | 134 | "overview": "qux",
|
69 |
| - "envVariables": [{"name": "foo", "value": "bar"}], |
| 135 | + "external_id": self.post_data["external_id"], |
| 136 | + "events": [], |
| 137 | + "env_variables": [{"name": "foo", "value": "bar"}, {"name": "baz", "value": "qux"}], |
70 | 138 | }
|
71 |
| - with Feature("organizations:sentry-functions"): |
72 |
| - self.client.post(self.url, data) |
73 |
| - response = self.client.get(self.url) |
74 |
| - assert response.status_code == 200 |
75 |
| - assert response.data[0]["name"] == "foo" |
76 |
| - assert response.data[0]["author"] == "bar" |
77 |
| - assert response.data[0]["code"] == defaultCode |
78 |
| - assert response.data[0]["overview"] == "qux" |
79 |
| - mock_func.assert_called_once_with( |
80 |
| - defaultCode, response.data[0]["external_id"], "qux", {"foo": "bar"} |
81 |
| - ) |
|
0 commit comments