Esempio n. 1
0
class TagStorageTest(TestCase, SnubaTestCase):
    def setUp(self):
        super(TagStorageTest, self).setUp()

        self.ts = SnubaTagStorage()

        self.proj1 = self.create_project()
        self.proj1env1 = self.create_environment(project=self.proj1,
                                                 name="test")
        self.proj1env2 = self.create_environment(project=self.proj1,
                                                 name="test2")

        self.proj1group1 = self.create_group(self.proj1)
        self.proj1group2 = self.create_group(self.proj1)

        hash1 = "1" * 32
        hash2 = "2" * 32
        GroupHash.objects.create(project=self.proj1,
                                 group=self.proj1group1,
                                 hash=hash1)
        GroupHash.objects.create(project=self.proj1,
                                 group=self.proj1group2,
                                 hash=hash2)

        self.now = timezone.now().replace(microsecond=0)
        data = json.dumps([{
            "event_id":
            six.text_type(r) * 32,
            "primary_hash":
            hash1,
            "group_id":
            self.proj1group1.id,
            "project_id":
            self.proj1.id,
            "message":
            "message 1",
            "platform":
            "python",
            "datetime": (self.now - timedelta(seconds=r)
                         ).strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
            "data": {
                "received": calendar.timegm(self.now.timetuple()) - r,
                "tags": {
                    "foo": "bar",
                    "baz": "quux",
                    "environment": self.proj1env1.name,
                    "sentry:release": 100 * r,
                    "sentry:user": u"id:user{}".format(r),
                },
                "user": {
                    "id": u"user{}".format(r),
                    "email": u"user{}@sentry.io".format(r)
                },
            },
        } for r in [1, 2]] + [{
            "event_id":
            "3" * 32,
            "primary_hash":
            hash2,
            "group_id":
            self.proj1group2.id,
            "project_id":
            self.proj1.id,
            "message":
            "message 2",
            "platform":
            "python",
            "datetime": (self.now - timedelta(seconds=2)
                         ).strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
            "data": {
                "received": calendar.timegm(self.now.timetuple()) - 2,
                "tags": {
                    "browser": "chrome",
                    "environment": self.proj1env1.name,
                    "sentry:user": "******",
                },
                "user": {
                    "id": "user1"
                },
            },
        }] + [{
            "event_id":
            "4" * 32,
            "primary_hash":
            hash2,
            "group_id":
            self.proj1group1.id,
            "project_id":
            self.proj1.id,
            "message":
            "message 2",
            "platform":
            "python",
            "datetime": (self.now - timedelta(seconds=2)
                         ).strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
            "data": {
                "received": calendar.timegm(self.now.timetuple()) - 2,
                "tags": {
                    "foo": "bar",
                    "environment": self.proj1env2.name
                },
                "user": {
                    "id": "user1"
                },
            },
        }])

        assert (requests.post(settings.SENTRY_SNUBA + "/tests/events/insert",
                              data=data).status_code == 200)

    def test_get_group_tag_keys_and_top_values(self):
        result = list(
            self.ts.get_group_tag_keys_and_top_values(self.proj1.id,
                                                      self.proj1group1.id,
                                                      [self.proj1env1.id]))
        tags = [r.key for r in result]
        assert set(tags) == set(
            ["foo", "baz", "environment", "sentry:release", "sentry:user"])

        result.sort(key=lambda r: r.key)
        assert result[0].key == "baz"
        assert result[0].top_values[0].value == "quux"
        assert result[0].count == 2

        assert result[3].key == "sentry:release"
        assert result[3].count == 2
        top_release_values = result[3].top_values
        assert len(top_release_values) == 2
        assert set(v.value for v in top_release_values) == set(["100", "200"])
        assert all(v.times_seen == 1 for v in top_release_values)

        # Now with only a specific set of keys,
        result = list(
            self.ts.get_group_tag_keys_and_top_values(
                self.proj1.id,
                self.proj1group1.id,
                [self.proj1env1.id],
                keys=["environment", "sentry:release"],
            ))
        tags = [r.key for r in result]
        assert set(tags) == set(["environment", "sentry:release"])

        result.sort(key=lambda r: r.key)
        assert result[0].key == "environment"
        assert result[0].top_values[0].value == "test"

        assert result[1].key == "sentry:release"
        top_release_values = result[1].top_values
        assert len(top_release_values) == 2
        assert set(v.value for v in top_release_values) == set(["100", "200"])
        assert all(v.times_seen == 1 for v in top_release_values)

    def test_get_top_group_tag_values(self):
        resp = self.ts.get_top_group_tag_values(self.proj1.id,
                                                self.proj1group1.id,
                                                self.proj1env1.id, "foo", 1)
        assert len(resp) == 1
        assert resp[0].times_seen == 2
        assert resp[0].key == "foo"
        assert resp[0].value == "bar"
        assert resp[0].group_id == self.proj1group1.id

    def test_get_group_tag_value_count(self):
        assert (self.ts.get_group_tag_value_count(self.proj1.id,
                                                  self.proj1group1.id,
                                                  self.proj1env1.id,
                                                  "foo") == 2)

    def test_get_tag_keys(self):
        expected_keys = set([
            "baz", "browser", "environment", "foo", "sentry:release",
            "sentry:user"
        ])
        keys = {
            k.key: k
            for k in self.ts.get_tag_keys(project_id=self.proj1.id,
                                          environment_id=self.proj1env1.id)
        }
        assert set(keys) == expected_keys
        keys = {
            k.key: k
            for k in self.ts.get_tag_keys(project_id=self.proj1.id,
                                          environment_id=self.proj1env1.id,
                                          include_values_seen=True)
        }
        assert set(keys) == expected_keys

    def test_get_group_tag_key(self):
        with pytest.raises(GroupTagKeyNotFound):
            self.ts.get_group_tag_key(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="notreal",
            )

        assert (self.ts.get_group_tag_key(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key="foo",
        ).key == "foo")

        keys = {
            k.key: k
            for k in self.ts.get_group_tag_keys(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_ids=[self.proj1env1.id],
            )
        }
        assert set(keys) == set(
            ["baz", "environment", "foo", "sentry:release", "sentry:user"])

    def test_get_group_tag_value(self):
        with pytest.raises(GroupTagValueNotFound):
            self.ts.get_group_tag_value(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="foo",
                value="notreal",
            )

        assert self.ts.get_group_tag_values(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key="notreal",
        ) == set([])

        assert (list(
            self.ts.get_group_tag_values(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="foo",
            ))[0].value == "bar")

        assert (self.ts.get_group_tag_value(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key="foo",
            value="bar",
        ).value == "bar")

    def test_get_tag_key(self):
        with pytest.raises(TagKeyNotFound):
            self.ts.get_tag_key(project_id=self.proj1.id,
                                environment_id=self.proj1env1.id,
                                key="notreal")

    def test_get_tag_value(self):
        with pytest.raises(TagValueNotFound):
            self.ts.get_tag_value(
                project_id=self.proj1.id,
                environment_id=self.proj1env1.id,
                key="foo",
                value="notreal",
            )

    def test_get_groups_user_counts(self):
        assert self.ts.get_groups_user_counts(
            project_ids=[self.proj1.id],
            group_ids=[self.proj1group1.id, self.proj1group2.id],
            environment_ids=[self.proj1env1.id],
        ) == {
            self.proj1group1.id: 2,
            self.proj1group2.id: 1
        }

        # test filtering by date range where there shouldn't be results
        assert (self.ts.get_groups_user_counts(
            project_ids=[self.proj1.id],
            group_ids=[self.proj1group1.id, self.proj1group2.id],
            environment_ids=[self.proj1env1.id],
            start=self.now - timedelta(days=5),
            end=self.now - timedelta(days=4),
        ) == {})

    def test_get_releases(self):
        assert (self.ts.get_first_release(
            project_id=self.proj1.id, group_id=self.proj1group1.id) == "200")

        assert (self.ts.get_first_release(
            project_id=self.proj1.id, group_id=self.proj1group2.id) is None)

        assert (self.ts.get_last_release(
            project_id=self.proj1.id, group_id=self.proj1group1.id) == "100")

        assert (self.ts.get_last_release(project_id=self.proj1.id,
                                         group_id=self.proj1group2.id) is None)

    def test_get_group_ids_for_users(self):
        assert self.ts.get_group_ids_for_users(
            [self.proj1.id],
            [EventUser(project_id=self.proj1.id, ident="user1")]) == set(
                [self.proj1group1.id, self.proj1group2.id])

        assert self.ts.get_group_ids_for_users(
            [self.proj1.id],
            [EventUser(project_id=self.proj1.id, ident="user2")]) == set(
                [self.proj1group1.id])

    def test_get_group_tag_values_for_users(self):
        result = self.ts.get_group_tag_values_for_users(
            [EventUser(project_id=self.proj1.id, ident="user1")])
        assert len(result) == 2
        assert set(v.group_id for v in result) == set(
            [self.proj1group1.id, self.proj1group2.id])
        assert set(v.last_seen for v in result) == set(
            [self.now - timedelta(seconds=1), self.now - timedelta(seconds=2)])
        result.sort(key=lambda x: x.last_seen)
        assert result[0].last_seen == self.now - timedelta(seconds=2)
        assert result[1].last_seen == self.now - timedelta(seconds=1)
        for v in result:
            assert v.value == "user1"

        result = self.ts.get_group_tag_values_for_users(
            [EventUser(project_id=self.proj1.id, ident="user2")])
        assert len(result) == 1
        assert result[0].value == "user2"
        assert result[0].last_seen == self.now - timedelta(seconds=2)

    def test_get_release_tags(self):
        tags = list(self.ts.get_release_tags([self.proj1.id], None, ["100"]))

        assert len(tags) == 1
        one_second_ago = self.now - timedelta(seconds=1)
        assert tags[0].last_seen == one_second_ago
        assert tags[0].first_seen == one_second_ago
        assert tags[0].times_seen == 1
        assert tags[0].key == "sentry:release"

    def test_get_group_event_filter(self):
        assert self.ts.get_group_event_filter(self.proj1.id,
                                              self.proj1group1.id,
                                              [self.proj1env1.id],
                                              {"foo": "bar"}, None, None) == {
                                                  "event_id__in":
                                                  set(["1" * 32, "2" * 32])
                                              }

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id],
            {"foo": "bar"},
            (self.now - timedelta(seconds=1)),
            None,
        ) == {
            "event_id__in": set(["1" * 32])
        }

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id],
            {"foo": "bar"},
            None,
            (self.now - timedelta(seconds=1)),
        ) == {
            "event_id__in": set(["2" * 32])
        }

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id, self.proj1env2.id],
            {"foo": "bar"},
            None,
            None,
        ) == {
            "event_id__in": set(["1" * 32, "2" * 32, "4" * 32])
        }

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id],
            {
                "foo": "bar",
                "sentry:release": "200"
            },  # AND
            None,
            None,
        ) == {
            "event_id__in": set(["2" * 32])
        }

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group2.id,
            [self.proj1env1.id],
            {"browser": "chrome"},
            None,
            None,
        ) == {
            "event_id__in": set(["3" * 32])
        }

        assert (self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group2.id,
            [self.proj1env1.id],
            {"browser": "ie"},
            None,
            None,
        ) is None)

    def test_get_tag_value_paginator(self):
        from sentry.tagstore.types import TagValue

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id,
                "sentry:user").get_result(10)) == [
                    TagValue(
                        key="sentry:user",
                        value="id:user1",
                        times_seen=2,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=1),
                    ),
                    TagValue(
                        key="sentry:user",
                        value="id:user2",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=2),
                    ),
                ]

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id, "sentry:user",
                query="user1").get_result(10)) == [
                    TagValue(
                        key="sentry:user",
                        value="id:user1",
                        times_seen=2,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=1),
                    )
                ]

    def test_get_group_tag_value_iter(self):
        from sentry.tagstore.types import GroupTagValue

        assert list(
            self.ts.get_group_tag_value_iter(
                self.proj1.id, self.proj1group1.id, self.proj1env1.id,
                "sentry:user")) == [
                    GroupTagValue(
                        group_id=self.proj1group1.id,
                        key="sentry:user",
                        value="id:user1",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=1),
                        last_seen=self.now - timedelta(seconds=1),
                    ),
                    GroupTagValue(
                        group_id=self.proj1group1.id,
                        key="sentry:user",
                        value="id:user2",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=2),
                    ),
                ]

    def test_get_group_tag_value_paginator(self):
        from sentry.tagstore.types import GroupTagValue

        assert list(
            self.ts.get_group_tag_value_paginator(
                self.proj1.id, self.proj1group1.id, self.proj1env1.id,
                "sentry:user").get_result(10)) == [
                    GroupTagValue(
                        group_id=self.proj1group1.id,
                        key="sentry:user",
                        value="id:user1",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=1),
                        last_seen=self.now - timedelta(seconds=1),
                    ),
                    GroupTagValue(
                        group_id=self.proj1group1.id,
                        key="sentry:user",
                        value="id:user2",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=2),
                    ),
                ]

    def test_get_group_seen_values_for_environments(self):
        assert self.ts.get_group_seen_values_for_environments(
            [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id]) == {
                self.proj1group1.id: {
                    "first_seen": self.now - timedelta(seconds=2),
                    "last_seen": self.now - timedelta(seconds=1),
                    "times_seen": 2,
                }
            }

        # test where there should be no results because of time filters
        assert (self.ts.get_group_seen_values_for_environments(
            [self.proj1.id],
            [self.proj1group1.id],
            [self.proj1env1.id],
            start=self.now - timedelta(hours=5),
            end=self.now - timedelta(hours=4),
        ) == {})
Esempio n. 2
0
class TagStorageTest(TestCase, SnubaTestCase):
    def setUp(self):
        super(TagStorageTest, self).setUp()

        self.ts = SnubaTagStorage()

        self.proj1 = self.create_project()
        self.proj1env1 = self.create_environment(project=self.proj1, name="test")
        self.proj1env2 = self.create_environment(project=self.proj1, name="test2")

        self.proj1group1 = self.create_group(self.proj1)
        self.proj1group2 = self.create_group(self.proj1)

        hash1 = "1" * 32
        hash2 = "2" * 32
        GroupHash.objects.create(project=self.proj1, group=self.proj1group1, hash=hash1)
        GroupHash.objects.create(project=self.proj1, group=self.proj1group2, hash=hash2)

        self.now = timezone.now().replace(microsecond=0)
        data = json.dumps(
            [
                {
                    "event_id": six.text_type(r) * 32,
                    "primary_hash": hash1,
                    "group_id": self.proj1group1.id,
                    "project_id": self.proj1.id,
                    "message": "message 1",
                    "platform": "python",
                    "datetime": (self.now - timedelta(seconds=r)).strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
                    "data": {
                        "received": calendar.timegm(self.now.timetuple()) - r,
                        "tags": {
                            "foo": "bar",
                            "baz": "quux",
                            "environment": self.proj1env1.name,
                            "sentry:release": 100 * r,
                            "sentry:user": u"id:user{}".format(r),
                        },
                        "user": {"id": u"user{}".format(r), "email": u"user{}@sentry.io".format(r)},
                        "exception": {"values": [{"stacktrace": {"frames": [{"lineno": 29}]}}]},
                    },
                }
                for r in [1, 2]
            ]
            + [
                {
                    "event_id": "3" * 32,
                    "primary_hash": hash2,
                    "group_id": self.proj1group2.id,
                    "project_id": self.proj1.id,
                    "message": "message 2",
                    "platform": "python",
                    "datetime": (self.now - timedelta(seconds=2)).strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
                    "data": {
                        "received": calendar.timegm(self.now.timetuple()) - 2,
                        "tags": {
                            "browser": "chrome",
                            "environment": self.proj1env1.name,
                            "sentry:user": "******",
                        },
                        "user": {"id": "user1"},
                    },
                }
            ]
            + [
                {
                    "event_id": "4" * 32,
                    "primary_hash": hash2,
                    "group_id": self.proj1group1.id,
                    "project_id": self.proj1.id,
                    "message": "message 2",
                    "platform": "python",
                    "datetime": (self.now - timedelta(seconds=2)).strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
                    "data": {
                        "received": calendar.timegm(self.now.timetuple()) - 2,
                        "tags": {"foo": "bar", "environment": self.proj1env2.name},
                        "user": {"id": "user1"},
                    },
                }
            ]
        )

        assert (
            requests.post(settings.SENTRY_SNUBA + "/tests/events/insert", data=data).status_code
            == 200
        )

    def test_get_group_tag_keys_and_top_values(self):
        result = list(
            self.ts.get_group_tag_keys_and_top_values(
                self.proj1.id, self.proj1group1.id, [self.proj1env1.id]
            )
        )
        tags = [r.key for r in result]
        assert set(tags) == set(["foo", "baz", "environment", "sentry:release", "sentry:user"])

        result.sort(key=lambda r: r.key)
        assert result[0].key == "baz"
        assert result[0].top_values[0].value == "quux"
        assert result[0].count == 2

        assert result[3].key == "sentry:release"
        assert result[3].count == 2
        top_release_values = result[3].top_values
        assert len(top_release_values) == 2
        assert set(v.value for v in top_release_values) == set(["100", "200"])
        assert all(v.times_seen == 1 for v in top_release_values)

        # Now with only a specific set of keys,
        result = list(
            self.ts.get_group_tag_keys_and_top_values(
                self.proj1.id,
                self.proj1group1.id,
                [self.proj1env1.id],
                keys=["environment", "sentry:release"],
            )
        )
        tags = [r.key for r in result]
        assert set(tags) == set(["environment", "sentry:release"])

        result.sort(key=lambda r: r.key)
        assert result[0].key == "environment"
        assert result[0].top_values[0].value == "test"

        assert result[1].key == "sentry:release"
        top_release_values = result[1].top_values
        assert len(top_release_values) == 2
        assert set(v.value for v in top_release_values) == set(["100", "200"])
        assert all(v.times_seen == 1 for v in top_release_values)

    def test_get_top_group_tag_values(self):
        resp = self.ts.get_top_group_tag_values(
            self.proj1.id, self.proj1group1.id, self.proj1env1.id, "foo", 1
        )
        assert len(resp) == 1
        assert resp[0].times_seen == 2
        assert resp[0].key == "foo"
        assert resp[0].value == "bar"
        assert resp[0].group_id == self.proj1group1.id

    def test_get_group_tag_value_count(self):
        assert (
            self.ts.get_group_tag_value_count(
                self.proj1.id, self.proj1group1.id, self.proj1env1.id, "foo"
            )
            == 2
        )

    def test_get_tag_keys(self):
        expected_keys = set(
            ["baz", "browser", "environment", "foo", "sentry:release", "sentry:user"]
        )
        keys = {
            k.key: k
            for k in self.ts.get_tag_keys(
                project_id=self.proj1.id, environment_id=self.proj1env1.id
            )
        }
        assert set(keys) == expected_keys
        keys = {
            k.key: k
            for k in self.ts.get_tag_keys(
                project_id=self.proj1.id, environment_id=self.proj1env1.id, include_values_seen=True
            )
        }
        assert set(keys) == expected_keys

    def test_get_group_tag_key(self):
        with pytest.raises(GroupTagKeyNotFound):
            self.ts.get_group_tag_key(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="notreal",
            )

        assert (
            self.ts.get_group_tag_key(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="foo",
            ).key
            == "foo"
        )

        keys = {
            k.key: k
            for k in self.ts.get_group_tag_keys(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_ids=[self.proj1env1.id],
            )
        }
        assert set(keys) == set(["baz", "environment", "foo", "sentry:release", "sentry:user"])

    def test_get_group_tag_value(self):
        with pytest.raises(GroupTagValueNotFound):
            self.ts.get_group_tag_value(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="foo",
                value="notreal",
            )

        assert self.ts.get_group_tag_values(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key="notreal",
        ) == set([])

        assert (
            list(
                self.ts.get_group_tag_values(
                    project_id=self.proj1.id,
                    group_id=self.proj1group1.id,
                    environment_id=self.proj1env1.id,
                    key="foo",
                )
            )[0].value
            == "bar"
        )

        assert (
            self.ts.get_group_tag_value(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="foo",
                value="bar",
            ).value
            == "bar"
        )

    def test_get_tag_key(self):
        with pytest.raises(TagKeyNotFound):
            self.ts.get_tag_key(
                project_id=self.proj1.id, environment_id=self.proj1env1.id, key="notreal"
            )

    def test_get_tag_value(self):
        with pytest.raises(TagValueNotFound):
            self.ts.get_tag_value(
                project_id=self.proj1.id,
                environment_id=self.proj1env1.id,
                key="foo",
                value="notreal",
            )

    def test_get_tag_value_label(self):
        assert self.ts.get_tag_value_label("foo", "notreal") == "notreal"
        assert self.ts.get_tag_value_label("sentry:user", None) is None
        assert self.ts.get_tag_value_label("sentry:user", "id:stuff") == "stuff"
        assert self.ts.get_tag_value_label("sentry:user", "email:stuff") == "stuff"
        assert self.ts.get_tag_value_label("sentry:user", "username:stuff") == "stuff"
        assert self.ts.get_tag_value_label("sentry:user", "ip:stuff") == "stuff"

    def test_get_groups_user_counts(self):
        assert self.ts.get_groups_user_counts(
            project_ids=[self.proj1.id],
            group_ids=[self.proj1group1.id, self.proj1group2.id],
            environment_ids=[self.proj1env1.id],
        ) == {self.proj1group1.id: 2, self.proj1group2.id: 1}

        # test filtering by date range where there shouldn't be results
        assert (
            self.ts.get_groups_user_counts(
                project_ids=[self.proj1.id],
                group_ids=[self.proj1group1.id, self.proj1group2.id],
                environment_ids=[self.proj1env1.id],
                start=self.now - timedelta(days=5),
                end=self.now - timedelta(days=4),
            )
            == {}
        )

    def test_get_releases(self):
        assert (
            self.ts.get_first_release(project_id=self.proj1.id, group_id=self.proj1group1.id)
            == "200"
        )

        assert (
            self.ts.get_first_release(project_id=self.proj1.id, group_id=self.proj1group2.id)
            is None
        )

        assert (
            self.ts.get_last_release(project_id=self.proj1.id, group_id=self.proj1group1.id)
            == "100"
        )

        assert (
            self.ts.get_last_release(project_id=self.proj1.id, group_id=self.proj1group2.id) is None
        )

    def test_get_group_ids_for_users(self):
        assert self.ts.get_group_ids_for_users(
            [self.proj1.id], [EventUser(project_id=self.proj1.id, ident="user1")]
        ) == set([self.proj1group1.id, self.proj1group2.id])

        assert self.ts.get_group_ids_for_users(
            [self.proj1.id], [EventUser(project_id=self.proj1.id, ident="user2")]
        ) == set([self.proj1group1.id])

    def test_get_group_tag_values_for_users(self):
        result = self.ts.get_group_tag_values_for_users(
            [EventUser(project_id=self.proj1.id, ident="user1")]
        )
        assert len(result) == 2
        assert set(v.group_id for v in result) == set([self.proj1group1.id, self.proj1group2.id])
        assert set(v.last_seen for v in result) == set(
            [self.now - timedelta(seconds=1), self.now - timedelta(seconds=2)]
        )
        result.sort(key=lambda x: x.last_seen)
        assert result[0].last_seen == self.now - timedelta(seconds=2)
        assert result[1].last_seen == self.now - timedelta(seconds=1)
        for v in result:
            assert v.value == "user1"

        result = self.ts.get_group_tag_values_for_users(
            [EventUser(project_id=self.proj1.id, ident="user2")]
        )
        assert len(result) == 1
        assert result[0].value == "user2"
        assert result[0].last_seen == self.now - timedelta(seconds=2)

    def test_get_release_tags(self):
        tags = list(self.ts.get_release_tags([self.proj1.id], None, ["100"]))

        assert len(tags) == 1
        one_second_ago = self.now - timedelta(seconds=1)
        assert tags[0].last_seen == one_second_ago
        assert tags[0].first_seen == one_second_ago
        assert tags[0].times_seen == 1
        assert tags[0].key == "sentry:release"

    def test_get_group_event_filter(self):
        assert self.ts.get_group_event_filter(
            self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, None, None
        ) == {"event_id__in": set(["1" * 32, "2" * 32])}

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id],
            {"foo": "bar"},
            (self.now - timedelta(seconds=1)),
            None,
        ) == {"event_id__in": set(["1" * 32])}

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id],
            {"foo": "bar"},
            None,
            (self.now - timedelta(seconds=1)),
        ) == {"event_id__in": set(["2" * 32])}

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id, self.proj1env2.id],
            {"foo": "bar"},
            None,
            None,
        ) == {"event_id__in": set(["1" * 32, "2" * 32, "4" * 32])}

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id],
            {"foo": "bar", "sentry:release": "200"},  # AND
            None,
            None,
        ) == {"event_id__in": set(["2" * 32])}

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group2.id,
            [self.proj1env1.id],
            {"browser": "chrome"},
            None,
            None,
        ) == {"event_id__in": set(["3" * 32])}

        assert (
            self.ts.get_group_event_filter(
                self.proj1.id,
                self.proj1group2.id,
                [self.proj1env1.id],
                {"browser": "ie"},
                None,
                None,
            )
            is None
        )

    def test_get_tag_value_paginator(self):
        from sentry.tagstore.types import TagValue

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id, "sentry:user"
            ).get_result(10)
        ) == [
            TagValue(
                key="sentry:user",
                value="id:user1",
                times_seen=2,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=1),
            ),
            TagValue(
                key="sentry:user",
                value="id:user2",
                times_seen=1,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=2),
            ),
        ]

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id, "sentry:user", query="user1"
            ).get_result(10)
        ) == [
            TagValue(
                key="sentry:user",
                value="id:user1",
                times_seen=2,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=1),
            )
        ]

    def test_get_tag_value_paginator_with_dates(self):
        from sentry.tagstore.types import TagValue

        day_ago = self.now - timedelta(days=1)
        two_days_ago = self.now - timedelta(days=2)
        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id, "sentry:user", start=day_ago, end=self.now
            ).get_result(10)
        ) == [
            TagValue(
                key="sentry:user",
                value="id:user1",
                times_seen=2,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=1),
            ),
            TagValue(
                key="sentry:user",
                value="id:user2",
                times_seen=1,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=2),
            ),
        ]

        day_ago = self.now - timedelta(days=1)
        assert (
            list(
                self.ts.get_tag_value_paginator(
                    self.proj1.id, self.proj1env1.id, "sentry:user", start=two_days_ago, end=day_ago
                ).get_result(10)
            )
            == []
        )

    def test_numeric_tag_value_paginator(self):
        from sentry.tagstore.types import TagValue

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id, "stack.lineno"
            ).get_result(10)
        ) == [
            TagValue(
                key="stack.lineno",
                value="29",
                times_seen=2,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=1),
            )
        ]

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id, "stack.lineno", query="30"
            ).get_result(10)
        ) == [
            TagValue(
                key="stack.lineno",
                value="29",
                times_seen=2,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=1),
            )
        ]

    def test_get_group_tag_value_iter(self):
        from sentry.tagstore.types import GroupTagValue

        assert list(
            self.ts.get_group_tag_value_iter(
                self.proj1.id, self.proj1group1.id, self.proj1env1.id, "sentry:user"
            )
        ) == [
            GroupTagValue(
                group_id=self.proj1group1.id,
                key="sentry:user",
                value="id:user1",
                times_seen=1,
                first_seen=self.now - timedelta(seconds=1),
                last_seen=self.now - timedelta(seconds=1),
            ),
            GroupTagValue(
                group_id=self.proj1group1.id,
                key="sentry:user",
                value="id:user2",
                times_seen=1,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=2),
            ),
        ]

    def test_get_group_tag_value_paginator(self):
        from sentry.tagstore.types import GroupTagValue

        assert list(
            self.ts.get_group_tag_value_paginator(
                self.proj1.id, self.proj1group1.id, self.proj1env1.id, "sentry:user"
            ).get_result(10)
        ) == [
            GroupTagValue(
                group_id=self.proj1group1.id,
                key="sentry:user",
                value="id:user1",
                times_seen=1,
                first_seen=self.now - timedelta(seconds=1),
                last_seen=self.now - timedelta(seconds=1),
            ),
            GroupTagValue(
                group_id=self.proj1group1.id,
                key="sentry:user",
                value="id:user2",
                times_seen=1,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=2),
            ),
        ]

    def test_get_group_seen_values_for_environments(self):
        assert self.ts.get_group_seen_values_for_environments(
            [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id]
        ) == {
            self.proj1group1.id: {
                "first_seen": self.now - timedelta(seconds=2),
                "last_seen": self.now - timedelta(seconds=1),
                "times_seen": 2,
            }
        }

        # test where there should be no results because of time filters
        assert (
            self.ts.get_group_seen_values_for_environments(
                [self.proj1.id],
                [self.proj1group1.id],
                [self.proj1env1.id],
                start=self.now - timedelta(hours=5),
                end=self.now - timedelta(hours=4),
            )
            == {}
        )

    def test_cache_suffix_time(self):
        starting_key = cache_suffix_time(self.now, 0)
        finishing_key = cache_suffix_time(self.now + timedelta(seconds=300), 0)

        assert starting_key != finishing_key

    def test_cache_suffix_hour_edges(self):
        """ a suffix should still behave correctly around the end of the hour

            At a duration of 10 only one key between 0-10 should flip on the hour, the other 9
            should flip at different times.
        """
        before = datetime(2019, 9, 5, 17, 59, 59)
        on_hour = datetime(2019, 9, 5, 18, 0, 0)
        changed_on_hour = 0
        # Check multiple keyhashes so that this test doesn't depend on implementation
        for key_hash in range(10):
            before_key = cache_suffix_time(before, key_hash, duration=10)
            on_key = cache_suffix_time(on_hour, key_hash, duration=10)
            if before_key != on_key:
                changed_on_hour += 1

        assert changed_on_hour == 1

    def test_cache_suffix_day_edges(self):
        """ a suffix should still behave correctly around the end of a day

            This test is nearly identical to test_cache_suffix_hour_edges, but is to confirm that date changes don't
            cause a different behaviour
        """
        before = datetime(2019, 9, 5, 23, 59, 59)
        next_day = datetime(2019, 9, 6, 0, 0, 0)
        changed_on_hour = 0
        for key_hash in range(10):
            before_key = cache_suffix_time(before, key_hash, duration=10)
            next_key = cache_suffix_time(next_day, key_hash, duration=10)
            if before_key != next_key:
                changed_on_hour += 1

        assert changed_on_hour == 1

    def test_cache_suffix_time_matches_duration(self):
        """ The number of seconds between keys changing should match duration """
        previous_key = cache_suffix_time(self.now, 0, duration=10)
        changes = []
        for i in range(21):
            current_time = self.now + timedelta(seconds=i)
            current_key = cache_suffix_time(current_time, 0, duration=10)
            if current_key != previous_key:
                changes.append(current_time)
                previous_key = current_key

        assert len(changes) == 2
        assert (changes[1] - changes[0]).total_seconds() == 10

    def test_cache_suffix_time_jitter(self):
        """ Different key hashes should change keys at different times

            While starting_key and other_key might begin as the same values they should change at different times
        """
        starting_key = cache_suffix_time(self.now, 0, duration=10)
        for i in range(11):
            current_key = cache_suffix_time(self.now + timedelta(seconds=i), 0, duration=10)
            if current_key != starting_key:
                break

        other_key = cache_suffix_time(self.now, 5, duration=10)
        for j in range(11):
            current_key = cache_suffix_time(self.now + timedelta(seconds=j), 5, duration=10)
            if current_key != other_key:
                break

        assert i != j
Esempio n. 3
0
class TagStorageTest(SnubaTestCase):
    def setUp(self):
        super(TagStorageTest, self).setUp()

        self.ts = SnubaTagStorage()

        self.proj1 = self.create_project()
        self.proj1env1 = self.create_environment(project=self.proj1, name='test')

        self.proj1group1 = self.create_group(self.proj1)
        self.proj1group2 = self.create_group(self.proj1)

        hash1 = '1' * 32
        hash2 = '2' * 32
        GroupHash.objects.create(project=self.proj1, group=self.proj1group1, hash=hash1)
        GroupHash.objects.create(project=self.proj1, group=self.proj1group2, hash=hash2)

        self.now = timezone.now().replace(microsecond=0)
        data = json.dumps([{
            'event_id': six.text_type(r) * 32,
            'primary_hash': hash1,
            'group_id': self.proj1group1.id,
            'project_id': self.proj1.id,
            'message': 'message 1',
            'platform': 'python',
            'datetime': (self.now - timedelta(seconds=r)).strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
            'data': {
                'received': calendar.timegm(self.now.timetuple()) - r,
                'tags': {
                    'foo': 'bar',
                    'baz': 'quux',
                    'environment': self.proj1env1.name,
                    'sentry:release': 100 * r,
                    'sentry:user': u"id:user{}".format(r),
                },
                'user': {
                    'id': u"user{}".format(r),
                    'email': u"user{}@sentry.io".format(r)
                }
            },
        } for r in [1, 2]] + [{
            'event_id': '3' * 32,
            'primary_hash': hash2,
            'group_id': self.proj1group2.id,
            'project_id': self.proj1.id,
            'message': 'message 2',
            'platform': 'python',
            'datetime': (self.now - timedelta(seconds=2)).strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
            'data': {
                'received': calendar.timegm(self.now.timetuple()) - 2,
                'tags': {
                    'browser': 'chrome',
                    'environment': self.proj1env1.name,
                    'sentry:user': "******",
                },
                'user': {
                    'id': "user1"
                }
            },
        }])

        assert requests.post(settings.SENTRY_SNUBA + '/tests/insert', data=data).status_code == 200

    def test_get_group_tag_keys_and_top_values(self):
        result = list(self.ts.get_group_tag_keys_and_top_values(
            self.proj1.id,
            self.proj1group1.id,
            self.proj1env1.id,
        ))
        tags = [r.key for r in result]
        assert set(tags) == set(['foo', 'baz', 'environment', 'sentry:release', 'sentry:user'])

        result.sort(key=lambda r: r.key)
        assert result[0].key == 'baz'
        assert result[0].top_values[0].value == 'quux'
        assert result[0].values_seen == 1
        assert result[0].count == 2

        assert result[3].key == 'sentry:release'
        assert result[3].values_seen == 2
        assert result[3].count == 2
        top_release_values = result[3].top_values
        assert len(top_release_values) == 2
        assert set(v.value for v in top_release_values) == set(['100', '200'])
        assert all(v.times_seen == 1 for v in top_release_values)

        # Now with only a specific set of keys,
        result = list(self.ts.get_group_tag_keys_and_top_values(
            self.proj1.id,
            self.proj1group1.id,
            self.proj1env1.id,
            keys=['environment', 'sentry:release'],
        ))
        tags = [r.key for r in result]
        assert set(tags) == set(['environment', 'sentry:release'])

        result.sort(key=lambda r: r.key)
        assert result[0].key == 'environment'
        assert result[0].top_values[0].value == 'test'

        assert result[1].key == 'sentry:release'
        top_release_values = result[1].top_values
        assert len(top_release_values) == 2
        assert set(v.value for v in top_release_values) == set(['100', '200'])
        assert all(v.times_seen == 1 for v in top_release_values)

    def test_get_top_group_tag_values(self):
        resp = self.ts.get_top_group_tag_values(
            self.proj1.id,
            self.proj1group1.id,
            self.proj1env1.id,
            'foo',
            1
        )
        assert len(resp) == 1
        assert resp[0].times_seen == 2
        assert resp[0].key == 'foo'
        assert resp[0].value == 'bar'
        assert resp[0].group_id == self.proj1group1.id

    def test_get_group_tag_value_count(self):
        assert self.ts.get_group_tag_value_count(
            self.proj1.id,
            self.proj1group1.id,
            self.proj1env1.id,
            'foo'
        ) == 2

    def test_get_group_tag_key(self):
        with pytest.raises(GroupTagKeyNotFound):
            self.ts.get_group_tag_key(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key='notreal',
            )

        assert self.ts.get_group_tag_key(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key='foo',
        ).key == 'foo'

        keys = {
            k.key: k for k in self.ts.get_group_tag_keys(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
            )
        }
        assert set(keys) == set(['baz', 'environment', 'foo', 'sentry:release', 'sentry:user'])
        for k in keys.values():
            if k.key not in set(['sentry:release', 'sentry:user']):
                assert k.values_seen == 1, u'expected {!r} to have 1 unique value'.format(k.key)
            else:
                assert k.values_seen == 2

    def test_get_group_tag_value(self):
        with pytest.raises(GroupTagValueNotFound):
            self.ts.get_group_tag_value(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key='foo',
                value='notreal',
            )

        assert self.ts.get_group_tag_values(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key='notreal',
        ) == set([])

        assert list(self.ts.get_group_tag_values(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key='foo',
        ))[0].value == 'bar'

        assert self.ts.get_group_tag_value(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key='foo',
            value='bar',
        ).value == 'bar'

    def test_get_tag_key(self):
        with pytest.raises(TagKeyNotFound):
            self.ts.get_tag_key(
                project_id=self.proj1.id,
                environment_id=self.proj1env1.id,
                key='notreal'
            )

    def test_get_tag_value(self):
        with pytest.raises(TagValueNotFound):
            self.ts.get_tag_value(
                project_id=self.proj1.id,
                environment_id=self.proj1env1.id,
                key='foo',
                value='notreal',
            )

    def test_get_groups_user_counts(self):
        assert self.ts.get_groups_user_counts(
            project_ids=[self.proj1.id],
            group_ids=[self.proj1group1.id, self.proj1group2.id],
            environment_ids=[self.proj1env1.id]
        ) == {
            self.proj1group1.id: 2,
            self.proj1group2.id: 1,
        }

    def test_get_releases(self):
        assert self.ts.get_first_release(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
        ) == '200'

        assert self.ts.get_first_release(
            project_id=self.proj1.id,
            group_id=self.proj1group2.id,
        ) is None

        assert self.ts.get_last_release(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
        ) == '100'

        assert self.ts.get_last_release(
            project_id=self.proj1.id,
            group_id=self.proj1group2.id,
        ) is None

    def test_get_group_ids_for_users(self):
        assert self.ts.get_group_ids_for_users(
            [self.proj1.id],
            [EventUser(project_id=self.proj1.id, ident='user1')]
        ) == set([self.proj1group1.id, self.proj1group2.id])

        assert self.ts.get_group_ids_for_users(
            [self.proj1.id],
            [EventUser(project_id=self.proj1.id, ident='user2')]
        ) == set([self.proj1group1.id])

    def test_get_group_tag_values_for_users(self):
        result = self.ts.get_group_tag_values_for_users(
            [EventUser(project_id=self.proj1.id, ident='user1')]
        )
        assert len(result) == 2
        assert set(v.group_id for v in result) == set([
            self.proj1group1.id,
            self.proj1group2.id,
        ])
        assert set(v.last_seen for v in result) == \
            set([self.now - timedelta(seconds=1), self.now - timedelta(seconds=2)])
        result.sort(key=lambda x: x.last_seen)
        assert result[0].last_seen == self.now - timedelta(seconds=2)
        assert result[1].last_seen == self.now - timedelta(seconds=1)
        for v in result:
            assert v.value == 'user1'

        result = self.ts.get_group_tag_values_for_users(
            [EventUser(project_id=self.proj1.id, ident='user2')]
        )
        assert len(result) == 1
        assert result[0].value == 'user2'
        assert result[0].last_seen == self.now - timedelta(seconds=2)

    def test_get_release_tags(self):
        tags = list(
            self.ts.get_release_tags(
                [self.proj1.id],
                None,
                ['100']
            )
        )

        assert len(tags) == 1
        one_second_ago = self.now - timedelta(seconds=1)
        assert tags[0].last_seen == one_second_ago
        assert tags[0].first_seen == one_second_ago
        assert tags[0].times_seen == 1
        assert tags[0].key == 'sentry:release'

    def test_get_group_event_filter(self):
        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            self.proj1env1.id,
            {
                'foo': 'bar',
            }
        ) == {'event_id__in': set(["1" * 32, "2" * 32])}

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            self.proj1env1.id,
            {
                'foo': 'bar',  # AND
                'sentry:release': '200'
            }
        ) == {'event_id__in': set(["2" * 32])}

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group2.id,
            self.proj1env1.id,
            {
                'browser': 'chrome'
            }
        ) == {'event_id__in': set(["3" * 32])}

        assert self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group2.id,
            self.proj1env1.id,
            {
                'browser': 'ie'
            }
        ) is None

    def test_get_tag_value_paginator(self):
        from sentry.tagstore.types import TagValue

        assert list(self.ts.get_tag_value_paginator(
            self.proj1.id,
            self.proj1env1.id,
            'sentry:user',
        ).get_result(10)) == [
            TagValue(
                key='sentry:user',
                value='id:user1',
                times_seen=2,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=1)
            ),
            TagValue(
                key='sentry:user',
                value='id:user2',
                times_seen=1,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=2)
            )
        ]

        assert list(self.ts.get_tag_value_paginator(
            self.proj1.id,
            self.proj1env1.id,
            'sentry:user',
            query='user1',
        ).get_result(10)) == [
            TagValue(
                key='sentry:user',
                value='id:user1',
                times_seen=2,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=1)
            ),
        ]

    def test_get_group_tag_value_iter(self):
        from sentry.tagstore.types import GroupTagValue

        assert list(self.ts.get_group_tag_value_iter(
            self.proj1.id,
            self.proj1group1.id,
            self.proj1env1.id,
            'sentry:user',
        )) == [
            GroupTagValue(
                group_id=self.proj1group1.id,
                key='sentry:user',
                value='id:user1',
                times_seen=1,
                first_seen=self.now - timedelta(seconds=1),
                last_seen=self.now - timedelta(seconds=1)
            ),
            GroupTagValue(
                group_id=self.proj1group1.id,
                key='sentry:user',
                value='id:user2',
                times_seen=1,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=2)
            )
        ]

    def test_get_group_tag_value_paginator(self):
        from sentry.tagstore.types import GroupTagValue

        assert list(self.ts.get_group_tag_value_paginator(
            self.proj1.id,
            self.proj1group1.id,
            self.proj1env1.id,
            'sentry:user',
        ).get_result(10)) == [
            GroupTagValue(
                group_id=self.proj1group1.id,
                key='sentry:user',
                value='id:user1',
                times_seen=1,
                first_seen=self.now - timedelta(seconds=1),
                last_seen=self.now - timedelta(seconds=1)
            ),
            GroupTagValue(
                group_id=self.proj1group1.id,
                key='sentry:user',
                value='id:user2',
                times_seen=1,
                first_seen=self.now - timedelta(seconds=2),
                last_seen=self.now - timedelta(seconds=2)
            )
        ]
Esempio n. 4
0
class TagStorageTest(TestCase, SnubaTestCase):
    def setUp(self):
        super().setUp()

        self.ts = SnubaTagStorage()

        self.proj1 = self.create_project()
        env1 = "test"
        env2 = "test2"
        self.env3 = Environment.objects.create(
            organization_id=self.proj1.organization_id, name="test3")
        self.now = timezone.now().replace(microsecond=0)

        self.store_event(
            data={
                "event_id": "1" * 32,
                "message": "message 1",
                "platform": "python",
                "environment": env1,
                "fingerprint": ["group-1"],
                "timestamp": iso_format(self.now - timedelta(seconds=1)),
                "tags": {
                    "foo": "bar",
                    "baz": "quux",
                    "sentry:release": 100,
                    "sentry:user": "******",
                },
                "user": {
                    "id": "user1"
                },
                "exception": exception,
            },
            project_id=self.proj1.id,
        )

        self.proj1group1 = self.store_event(
            data={
                "event_id": "2" * 32,
                "message": "message 1",
                "platform": "python",
                "environment": env1,
                "fingerprint": ["group-1"],
                "timestamp": iso_format(self.now - timedelta(seconds=2)),
                "tags": {
                    "foo": "bar",
                    "baz": "quux",
                    "sentry:release": 200,
                    "sentry:user": "******",
                },
                "user": {
                    "id": "user2"
                },
                "exception": exception,
            },
            project_id=self.proj1.id,
        ).group

        self.proj1group2 = self.store_event(
            data={
                "event_id": "3" * 32,
                "message": "message 2",
                "platform": "python",
                "environment": env1,
                "fingerprint": ["group-2"],
                "timestamp": iso_format(self.now - timedelta(seconds=2)),
                "tags": {
                    "browser": "chrome",
                    "sentry:user": "******"
                },
                "user": {
                    "id": "user1"
                },
            },
            project_id=self.proj1.id,
        ).group

        self.store_event(
            data={
                "event_id": "4" * 32,
                "message": "message2",
                "platform": "python",
                "environment": env2,
                "fingerprint": ["group-1"],
                "timestamp": iso_format(self.now - timedelta(seconds=2)),
                "tags": {
                    "foo": "bar"
                },
            },
            project_id=self.proj1.id,
        )

        self.proj1env1 = Environment.objects.get(name=env1)
        self.proj1env2 = Environment.objects.get(name=env2)

    def test_get_group_tag_keys_and_top_values(self):
        result = list(
            self.ts.get_group_tag_keys_and_top_values(self.proj1.id,
                                                      self.proj1group1.id,
                                                      [self.proj1env1.id]))
        tags = [r.key for r in result]
        assert set(tags) == {
            "foo", "baz", "environment", "sentry:release", "sentry:user",
            "level"
        }

        result.sort(key=lambda r: r.key)
        assert result[0].key == "baz"
        assert result[0].top_values[0].value == "quux"
        assert result[0].count == 2

        assert result[4].key == "sentry:release"
        assert result[4].count == 2
        top_release_values = result[4].top_values
        assert len(top_release_values) == 2
        assert {v.value for v in top_release_values} == {"100", "200"}
        assert all(v.times_seen == 1 for v in top_release_values)

        # Now with only a specific set of keys,
        result = list(
            self.ts.get_group_tag_keys_and_top_values(
                self.proj1.id,
                self.proj1group1.id,
                [self.proj1env1.id],
                keys=["environment", "sentry:release"],
            ))
        tags = [r.key for r in result]
        assert set(tags) == {"environment", "sentry:release"}

        result.sort(key=lambda r: r.key)
        assert result[0].key == "environment"
        assert result[0].top_values[0].value == "test"

        assert result[1].key == "sentry:release"
        top_release_values = result[1].top_values
        assert len(top_release_values) == 2
        assert {v.value for v in top_release_values} == {"100", "200"}
        assert all(v.times_seen == 1 for v in top_release_values)

    def test_get_top_group_tag_values(self):
        resp = self.ts.get_top_group_tag_values(self.proj1.id,
                                                self.proj1group1.id,
                                                self.proj1env1.id, "foo", 1)
        assert len(resp) == 1
        assert resp[0].times_seen == 2
        assert resp[0].key == "foo"
        assert resp[0].value == "bar"
        assert resp[0].group_id == self.proj1group1.id

    def test_get_group_tag_value_count(self):
        assert (self.ts.get_group_tag_value_count(self.proj1.id,
                                                  self.proj1group1.id,
                                                  self.proj1env1.id,
                                                  "foo") == 2)

    def test_get_tag_keys(self):
        expected_keys = {
            "baz",
            "browser",
            "environment",
            "foo",
            "sentry:release",
            "sentry:user",
            "level",
        }
        keys = {
            k.key: k
            for k in self.ts.get_tag_keys(project_id=self.proj1.id,
                                          environment_id=self.proj1env1.id)
        }
        assert set(keys) == expected_keys
        keys = {
            k.key: k
            for k in self.ts.get_tag_keys(project_id=self.proj1.id,
                                          environment_id=self.proj1env1.id,
                                          include_values_seen=True)
        }
        assert set(keys) == expected_keys

    def test_get_group_tag_key(self):
        with pytest.raises(GroupTagKeyNotFound):
            self.ts.get_group_tag_key(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="notreal",
            )

        assert (self.ts.get_group_tag_key(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key="foo",
        ).key == "foo")

        keys = {
            k.key: k
            for k in self.ts.get_group_tag_keys(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_ids=[self.proj1env1.id],
            )
        }
        assert set(keys) == {
            "baz", "environment", "foo", "sentry:release", "sentry:user",
            "level"
        }

    def test_get_group_tag_value(self):
        with pytest.raises(GroupTagValueNotFound):
            self.ts.get_group_tag_value(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="foo",
                value="notreal",
            )

        assert (self.ts.get_group_tag_values(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key="notreal",
        ) == set())

        assert (list(
            self.ts.get_group_tag_values(
                project_id=self.proj1.id,
                group_id=self.proj1group1.id,
                environment_id=self.proj1env1.id,
                key="foo",
            ))[0].value == "bar")

        assert (self.ts.get_group_tag_value(
            project_id=self.proj1.id,
            group_id=self.proj1group1.id,
            environment_id=self.proj1env1.id,
            key="foo",
            value="bar",
        ).value == "bar")

    def test_get_tag_key(self):
        with pytest.raises(TagKeyNotFound):
            self.ts.get_tag_key(project_id=self.proj1.id,
                                environment_id=self.proj1env1.id,
                                key="notreal")

    def test_get_tag_value(self):
        with pytest.raises(TagValueNotFound):
            self.ts.get_tag_value(
                project_id=self.proj1.id,
                environment_id=self.proj1env1.id,
                key="foo",
                value="notreal",
            )

    def test_get_tag_value_label(self):
        assert self.ts.get_tag_value_label("foo", "notreal") == "notreal"
        assert self.ts.get_tag_value_label("sentry:user", None) is None
        assert self.ts.get_tag_value_label("sentry:user",
                                           "id:stuff") == "stuff"
        assert self.ts.get_tag_value_label("sentry:user",
                                           "email:stuff") == "stuff"
        assert self.ts.get_tag_value_label("sentry:user",
                                           "username:stuff") == "stuff"
        assert self.ts.get_tag_value_label("sentry:user",
                                           "ip:stuff") == "stuff"

    def test_get_groups_user_counts(self):
        assert (self.ts.get_groups_user_counts(
            project_ids=[self.proj1.id],
            group_ids=[self.proj1group1.id, self.proj1group2.id],
            environment_ids=[self.proj1env1.id],
        ) == {
            self.proj1group1.id: 2,
            self.proj1group2.id: 1
        })

        # test filtering by date range where there shouldn't be results
        assert (self.ts.get_groups_user_counts(
            project_ids=[self.proj1.id],
            group_ids=[self.proj1group1.id, self.proj1group2.id],
            environment_ids=[self.proj1env1.id],
            start=self.now - timedelta(days=5),
            end=self.now - timedelta(days=4),
        ) == {})

    def test_get_group_ids_for_users(self):
        assert self.ts.get_group_ids_for_users(
            [self.proj1.id],
            [EventUser(project_id=self.proj1.id, ident="user1")]) == {
                self.proj1group1.id, self.proj1group2.id
            }

        assert self.ts.get_group_ids_for_users(
            [self.proj1.id],
            [EventUser(project_id=self.proj1.id, ident="user2")]) == {
                self.proj1group1.id
            }

    def test_get_group_tag_values_for_users(self):
        result = self.ts.get_group_tag_values_for_users(
            [EventUser(project_id=self.proj1.id, ident="user1")])
        assert len(result) == 2
        assert {v.group_id
                for v in result} == {self.proj1group1.id, self.proj1group2.id}
        assert {v.last_seen
                for v in result} == {
                    self.now - timedelta(seconds=1),
                    self.now - timedelta(seconds=2),
                }
        result.sort(key=lambda x: x.last_seen)
        assert result[0].last_seen == self.now - timedelta(seconds=2)
        assert result[1].last_seen == self.now - timedelta(seconds=1)
        for v in result:
            assert v.value == "user1"

        result = self.ts.get_group_tag_values_for_users(
            [EventUser(project_id=self.proj1.id, ident="user2")])
        assert len(result) == 1
        assert result[0].value == "user2"
        assert result[0].last_seen == self.now - timedelta(seconds=2)

    def test_get_release_tags(self):
        tags = list(
            self.ts.get_release_tags(self.proj1.organization_id,
                                     [self.proj1.id], None, ["100"]))

        assert len(tags) == 1
        one_second_ago = self.now - timedelta(seconds=1)
        assert tags[0].last_seen == one_second_ago
        assert tags[0].first_seen == one_second_ago
        assert tags[0].times_seen == 1
        assert tags[0].key == "sentry:release"

    def test_get_release_tags_uses_release_project_environment(self):
        tags = list(
            self.ts.get_release_tags(self.proj1.organization_id,
                                     [self.proj1.id], None, ["100"]))

        assert len(tags) == 1
        one_second_ago = self.now - timedelta(seconds=1)
        assert tags[0].last_seen == one_second_ago
        assert tags[0].first_seen == one_second_ago
        assert tags[0].times_seen == 1

        one_day_ago = self.now - timedelta(days=1)
        two_days_ago = self.now - timedelta(days=2)
        self.store_event(
            data={
                "event_id": "5" * 32,
                "message": "message3",
                "platform": "python",
                "environment": None,
                "fingerprint": ["group-1"],
                "timestamp": iso_format(one_day_ago),
                "tags": {
                    "sentry:release": 100,
                },
            },
            project_id=self.proj1.id,
        )

        release = Release.objects.create(version="100",
                                         organization=self.organization)
        ReleaseProjectEnvironment.objects.create(
            release_id=release.id,
            project_id=self.proj1.id,
            environment_id=self.env3.id,
            first_seen=one_day_ago,
        )

        self.store_event(
            data={
                "event_id": "6" * 32,
                "message": "message3",
                "platform": "python",
                "environment": None,
                "fingerprint": ["group-1"],
                "timestamp": iso_format(two_days_ago),
                "tags": {
                    "sentry:release": 100,
                },
            },
            project_id=self.proj1.id,
        )
        tags = list(
            self.ts.get_release_tags(self.proj1.organization_id,
                                     [self.proj1.id], None, ["100"]))
        assert tags[0].last_seen == one_second_ago
        assert tags[0].first_seen == one_day_ago
        assert (
            tags[0].times_seen == 2
        )  # Isn't 3 because start was limited by the ReleaseProjectEnvironment entry

    def test_get_group_event_filter(self):
        assert self.ts.get_group_event_filter(self.proj1.id,
                                              self.proj1group1.id,
                                              [self.proj1env1.id],
                                              {"foo": "bar"}, None, None) == {
                                                  "event_id__in":
                                                  {"1" * 32, "2" * 32}
                                              }

        assert (self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id],
            {"foo": "bar"},
            (self.now - timedelta(seconds=1)),
            None,
        ) == {
            "event_id__in": {"1" * 32}
        })

        assert (self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id],
            {"foo": "bar"},
            None,
            (self.now - timedelta(seconds=1)),
        ) == {
            "event_id__in": {"2" * 32}
        })

        assert (self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id, self.proj1env2.id],
            {"foo": "bar"},
            None,
            None,
        ) == {
            "event_id__in": {"1" * 32, "2" * 32, "4" * 32}
        })

        assert (self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group1.id,
            [self.proj1env1.id],
            {
                "foo": "bar",
                "sentry:release": "200"
            },  # AND
            None,
            None,
        ) == {
            "event_id__in": {"2" * 32}
        })

        assert (self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group2.id,
            [self.proj1env1.id],
            {"browser": "chrome"},
            None,
            None,
        ) == {
            "event_id__in": {"3" * 32}
        })

        assert (self.ts.get_group_event_filter(
            self.proj1.id,
            self.proj1group2.id,
            [self.proj1env1.id],
            {"browser": "ie"},
            None,
            None,
        ) is None)

    def test_get_tag_value_paginator(self):
        from sentry.tagstore.types import TagValue

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id,
                "sentry:user").get_result(10)) == [
                    TagValue(
                        key="sentry:user",
                        value="id:user1",
                        times_seen=2,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=1),
                    ),
                    TagValue(
                        key="sentry:user",
                        value="id:user2",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=2),
                    ),
                ]

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id, "sentry:user",
                query="user1").get_result(10)) == [
                    TagValue(
                        key="sentry:user",
                        value="id:user1",
                        times_seen=2,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=1),
                    )
                ]

    def test_get_tag_value_paginator_with_dates(self):
        from sentry.tagstore.types import TagValue

        day_ago = self.now - timedelta(days=1)
        two_days_ago = self.now - timedelta(days=2)
        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id,
                self.proj1env1.id,
                "sentry:user",
                start=day_ago,
                end=self.now).get_result(10)) == [
                    TagValue(
                        key="sentry:user",
                        value="id:user1",
                        times_seen=2,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=1),
                    ),
                    TagValue(
                        key="sentry:user",
                        value="id:user2",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=2),
                    ),
                ]

        day_ago = self.now - timedelta(days=1)
        assert (list(
            self.ts.get_tag_value_paginator(self.proj1.id,
                                            self.proj1env1.id,
                                            "sentry:user",
                                            start=two_days_ago,
                                            end=day_ago).get_result(10)) == [])

    def test_numeric_tag_value_paginator(self):
        from sentry.tagstore.types import TagValue

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id,
                "stack.lineno").get_result(10)) == [
                    TagValue(
                        key="stack.lineno",
                        value="29",
                        times_seen=2,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=1),
                    )
                ]

        assert list(
            self.ts.get_tag_value_paginator(
                self.proj1.id, self.proj1env1.id, "stack.lineno",
                query="30").get_result(10)) == [
                    TagValue(
                        key="stack.lineno",
                        value="29",
                        times_seen=2,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=1),
                    )
                ]

    def test_get_group_tag_value_iter(self):
        from sentry.tagstore.types import GroupTagValue

        assert list(
            self.ts.get_group_tag_value_iter(
                self.proj1.id, self.proj1group1.id, [self.proj1env1.id],
                "sentry:user")) == [
                    GroupTagValue(
                        group_id=self.proj1group1.id,
                        key="sentry:user",
                        value="id:user1",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=1),
                        last_seen=self.now - timedelta(seconds=1),
                    ),
                    GroupTagValue(
                        group_id=self.proj1group1.id,
                        key="sentry:user",
                        value="id:user2",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=2),
                    ),
                ]

    def test_get_group_tag_value_paginator(self):
        from sentry.tagstore.types import GroupTagValue

        assert list(
            self.ts.get_group_tag_value_paginator(
                self.proj1.id, self.proj1group1.id, [self.proj1env1.id],
                "sentry:user").get_result(10)) == [
                    GroupTagValue(
                        group_id=self.proj1group1.id,
                        key="sentry:user",
                        value="id:user1",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=1),
                        last_seen=self.now - timedelta(seconds=1),
                    ),
                    GroupTagValue(
                        group_id=self.proj1group1.id,
                        key="sentry:user",
                        value="id:user2",
                        times_seen=1,
                        first_seen=self.now - timedelta(seconds=2),
                        last_seen=self.now - timedelta(seconds=2),
                    ),
                ]

    def test_get_group_tag_value_paginator_times_seen(self):
        from sentry.tagstore.types import GroupTagValue

        self.store_event(
            data={
                "event_id": "5" * 32,
                "message": "message 1",
                "platform": "python",
                "environment": self.proj1env1.name,
                "fingerprint": ["group-1"],
                "timestamp": iso_format(self.now - timedelta(seconds=2)),
                "tags": {
                    "foo": "bar",
                    "baz": "quux",
                    "sentry:release": 100,
                    "sentry:user": "******",
                },
                "user": {
                    "id": "user2"
                },
                "exception": exception,
            },
            project_id=self.proj1.id,
        )

        assert list(
            self.ts.get_group_tag_value_paginator(
                self.proj1.id,
                self.proj1group1.id,
                [self.proj1env1.id],
                "sentry:user",
                order_by="-times_seen",
            ).get_result(10)) == [
                GroupTagValue(
                    group_id=self.proj1group1.id,
                    key="sentry:user",
                    value="id:user2",
                    times_seen=2,
                    first_seen=self.now - timedelta(seconds=2),
                    last_seen=self.now - timedelta(seconds=2),
                ),
                GroupTagValue(
                    group_id=self.proj1group1.id,
                    key="sentry:user",
                    value="id:user1",
                    times_seen=1,
                    first_seen=self.now - timedelta(seconds=1),
                    last_seen=self.now - timedelta(seconds=1),
                ),
            ]

    def test_get_group_seen_values_for_environments(self):
        assert self.ts.get_group_seen_values_for_environments(
            [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id]) == {
                self.proj1group1.id: {
                    "first_seen": self.now - timedelta(seconds=2),
                    "last_seen": self.now - timedelta(seconds=1),
                    "times_seen": 2,
                }
            }

        # test where there should be no results because of time filters
        assert (self.ts.get_group_seen_values_for_environments(
            [self.proj1.id],
            [self.proj1group1.id],
            [self.proj1env1.id],
            start=self.now - timedelta(hours=5),
            end=self.now - timedelta(hours=4),
        ) == {})