Exemplo n.º 1
0
 def test_aggregate_duration_filter(self):
     assert parse_search_query("avg(transaction.duration):>500s") == [
         SearchFilter(
             key=AggregateKey(name="avg(transaction.duration)"),
             operator=">",
             value=SearchValue(raw_value=500000.0),
         )
     ]
Exemplo n.º 2
0
 def test_aggregate_duration_filter_overrides_numeric_shorthand(self):
     # 2m should mean 2 minutes for duration filters (as opposed to 2 million)
     assert parse_search_query("avg(transaction.duration):>2m") == [
         SearchFilter(
             key=AggregateKey(name="avg(transaction.duration)"),
             operator=">",
             value=SearchValue(raw_value=120000.0),
         )
     ]
Exemplo n.º 3
0
    def test_invalid(self):
        filters = [SearchFilter(SearchKey("status"), "=", SearchValue("wrong"))]
        with self.assertRaises(InvalidSearchQuery, expected_regex="invalid status value"):
            convert_query_values(filters, [self.project], self.user, None)

        filters = [AggregateFilter(AggregateKey("count_unique(user)"), ">", SearchValue("1"))]
        with self.assertRaises(
            InvalidSearchQuery,
            expected_regex="Aggregate filters (count_unique(user)) are not supported in issue searches.",
        ):
            convert_query_values(filters, [self.project], self.user, None)
Exemplo n.º 4
0
 def test_aggregate_rel_time_filter(self):
     now = timezone.now()
     with freeze_time(now):
         assert parse_search_query("last_seen():+7d") == [
             AggregateFilter(
                 key=AggregateKey(name="last_seen()"),
                 operator="<=",
                 value=SearchValue(raw_value=now - timedelta(days=7)),
             )
         ]
         assert parse_search_query("last_seen():-2w") == [
             AggregateFilter(
                 key=AggregateKey(name="last_seen()"),
                 operator=">=",
                 value=SearchValue(raw_value=now - timedelta(days=14)),
             )
         ]
         assert parse_search_query("random:-2w") == [
             SearchFilter(key=SearchKey(name="random"),
                          operator="=",
                          value=SearchValue("-2w"))
         ]
Exemplo n.º 5
0
    def node_visitor(token):
        if token["type"] == "spaces":
            return None

        if token["type"] == "filter":
            # Filters with an invalid reason raises to signal to the test
            # runner that we should expect this exception
            if token.get("invalid"):
                raise InvalidSearchQuery(token["invalid"]["reason"])

            # Transform the operator to match for list values
            if token["value"]["type"] in ["valueTextList", "valueNumberList"]:
                operator = "NOT IN" if token["negated"] else "IN"
            else:
                # Negate the operator if the filter is negated to match
                operator = token["operator"] or "="
                operator = f"!{operator}" if token["negated"] else operator

            key = node_visitor(token["key"])
            value = node_visitor(token["value"])

            if token["filter"] == "boolean" and token["negated"]:
                operator = "="
                value = SearchValue(raw_value=1 if value.raw_value == 0 else 0)

            return SearchFilter(key, operator, value)

        if token["type"] == "keySimple":
            return SearchKey(name=token["value"])

        if token["type"] == "keyExplicitTag":
            return SearchKey(name=f"tags[{token['key']['value']}]")

        if token["type"] == "keyAggregate":
            name = node_visitor(token["name"]).name
            # Consistent join aggregate function parameters
            args = ", ".join(arg["value"]["value"]
                             for arg in token["args"]["args"])
            return AggregateKey(name=f"{name}({args})")

        if token["type"] == "valueText":
            # Noramlize values by removing the escaped quotes
            value = token["value"].replace('\\"', '"')
            return SearchValue(raw_value=value)

        if token["type"] == "valueNumber":
            return SearchValue(
                raw_value=parse_numeric_value(token["value"], token["unit"]))

        if token["type"] == "valueTextList":
            return SearchValue(
                raw_value=[item["value"]["value"] for item in token["items"]])

        if token["type"] == "valueNumberList":
            return SearchValue(raw_value=[
                item["value"]["rawValue"] for item in token["items"]
            ])

        if token["type"] == "valueIso8601Date":
            return SearchValue(raw_value=parse_datetime_string(token["value"]))

        if token["type"] == "valueDuration":
            return SearchValue(
                raw_value=parse_duration(token["value"], token["unit"]))

        if token["type"] == "valueRelativeDate":
            return SearchValue(
                raw_value=parse_duration(token["value"], token["unit"]))

        if token["type"] == "valueBoolean":
            return SearchValue(raw_value=int(token["value"]))

        if token["type"] == "freeText":
            if token["quoted"]:
                # Normalize quotes
                value = token["value"].replace('\\"', '"')
            else:
                # Normalize spacing
                value = token["value"].strip(" ")

            if value == "":
                return None

            return SearchFilter(
                key=SearchKey(name="message"),
                operator="=",
                value=SearchValue(raw_value=value),
            )