def test_not_many_groups_to_exclude(query: ClickhouseQuery) -> None:
    state.set_config("max_group_ids_exclude", 5)
    set_project_exclude_groups(2, [100, 101, 102], ReplacerState.EVENTS)

    PostReplacementConsistencyEnforcer(
        "project_id", ReplacerState.EVENTS
    ).process_query(query, HTTPRequestSettings())

    assert query.get_condition_from_ast() == FunctionCall(
        None,
        BooleanFunctions.AND,
        (
            FunctionCall(
                None,
                "notIn",
                (
                    FunctionCall(
                        None, "assumeNotNull", (Column(None, None, "group_id"),)
                    ),
                    FunctionCall(
                        None,
                        "tuple",
                        (Literal(None, 100), Literal(None, 101), Literal(None, 102),),
                    ),
                ),
            ),
            build_in("project_id", [2]),
        ),
    )
    assert not query.get_from_clause().final
Beispiel #2
0
    def test_query_time_flags(self):
        project_ids = [1, 2]

        assert errors_replacer.get_projects_query_flags(
            project_ids, ReplacerState.ERRORS
        ) == (False, [],)

        errors_replacer.set_project_needs_final(100, ReplacerState.ERRORS)
        assert errors_replacer.get_projects_query_flags(
            project_ids, ReplacerState.ERRORS
        ) == (False, [],)

        errors_replacer.set_project_needs_final(1, ReplacerState.ERRORS)
        assert errors_replacer.get_projects_query_flags(
            project_ids, ReplacerState.ERRORS
        ) == (True, [],)
        assert errors_replacer.get_projects_query_flags(
            project_ids, ReplacerState.EVENTS
        ) == (False, [],)

        errors_replacer.set_project_needs_final(2, ReplacerState.ERRORS)
        assert errors_replacer.get_projects_query_flags(
            project_ids, ReplacerState.ERRORS
        ) == (True, [],)

        errors_replacer.set_project_exclude_groups(1, [1, 2], ReplacerState.ERRORS)
        errors_replacer.set_project_exclude_groups(2, [3, 4], ReplacerState.ERRORS)
        assert errors_replacer.get_projects_query_flags(
            project_ids, ReplacerState.ERRORS
        ) == (True, [1, 2, 3, 4],)
        assert errors_replacer.get_projects_query_flags(
            project_ids, ReplacerState.EVENTS
        ) == (False, [],)
Beispiel #3
0
def test_multiple_not_too_many_excludes(
    query_with_multiple_group_ids: ClickhouseQuery, ) -> None:
    """
    Query is looking for multiple groups and there are not too many groups to exclude, but
    there are fewer groups queried for than replaced.
    """
    enforcer = PostReplacementConsistencyEnforcer("project_id",
                                                  ReplacerState.ERRORS)

    set_project_exclude_groups(
        2,
        [100, 101, 102],
        ReplacerState.ERRORS,
        ReplacementType.
        EXCLUDE_GROUPS,  # Arbitrary replacement type, no impact on tests
    )

    enforcer._set_query_final(query_with_multiple_group_ids, True)
    state.set_config("max_group_ids_exclude", 5)

    enforcer.process_query(query_with_multiple_group_ids, HTTPQuerySettings())
    assert query_with_multiple_group_ids.get_condition() == build_and(
        build_not_in("group_id", [101, 102]),
        build_and(build_in("project_id", [2]),
                  build_in("group_id", [101, 102])),
    )
    assert not query_with_multiple_group_ids.get_from_clause().final
Beispiel #4
0
def test_single_too_many_exclude(
        query_with_single_group_id: ClickhouseQuery) -> None:
    """
    Query is looking for a group that has been replaced, and there are too many
    groups to exclude.
    """
    enforcer = PostReplacementConsistencyEnforcer("project_id",
                                                  ReplacerState.ERRORS)

    set_project_exclude_groups(
        2,
        [100, 101, 102],
        ReplacerState.ERRORS,
        ReplacementType.
        EXCLUDE_GROUPS,  # Arbitrary replacement type, no impact on tests
    )

    enforcer._set_query_final(query_with_single_group_id, True)
    state.set_config("max_group_ids_exclude", 2)

    enforcer.process_query(query_with_single_group_id, HTTPQuerySettings())
    assert query_with_single_group_id.get_condition() == build_and(
        build_not_in("group_id", [101]),
        build_and(build_in("project_id", [2]), build_in("group_id", [101])),
    )
    assert not query_with_single_group_id.get_from_clause().final
Beispiel #5
0
def test_not_many_groups_to_exclude(query: ClickhouseQuery) -> None:
    state.set_config("max_group_ids_exclude", 5)
    set_project_exclude_groups(
        2,
        [100, 101, 102],
        ReplacerState.ERRORS,
        ReplacementType.
        EXCLUDE_GROUPS,  # Arbitrary replacement type, no impact on tests
    )

    PostReplacementConsistencyEnforcer("project_id",
                                       ReplacerState.ERRORS).process_query(
                                           query, HTTPQuerySettings())

    assert query.get_condition() == build_and(
        FunctionCall(
            None,
            "notIn",
            (
                FunctionCall(None, "assumeNotNull",
                             (Column(None, None, "group_id"), )),
                FunctionCall(
                    None,
                    "tuple",
                    (
                        Literal(None, 100),
                        Literal(None, 101),
                        Literal(None, 102),
                    ),
                ),
            ),
        ),
        build_in("project_id", [2]),
    )
    assert not query.get_from_clause().final
Beispiel #6
0
def test_query_overlaps_replacements_processor(
    query: ClickhouseQuery,
    query_with_timestamp: ClickhouseQuery,
    query_with_future_timestamp: ClickhouseQuery,
) -> None:
    enforcer = PostReplacementConsistencyEnforcer("project_id",
                                                  ReplacerState.ERRORS)

    # replacement time unknown, default to "overlaps" but no groups to exclude so shouldn't be final
    enforcer._set_query_final(query_with_timestamp, True)
    enforcer.process_query(query_with_timestamp, HTTPQuerySettings())
    assert not query_with_timestamp.get_from_clause().final

    # overlaps replacement and should be final due to too many groups to exclude
    state.set_config("max_group_ids_exclude", 2)
    set_project_exclude_groups(
        2,
        [100, 101, 102],
        ReplacerState.ERRORS,
        ReplacementType.
        EXCLUDE_GROUPS,  # Arbitrary replacement type, no impact on tests
    )
    enforcer._set_query_final(query_with_timestamp, False)
    enforcer.process_query(query_with_timestamp, HTTPQuerySettings())
    assert query_with_timestamp.get_from_clause().final

    # query time range unknown and should be final due to too many groups to exclude
    enforcer._set_query_final(query, False)
    enforcer.process_query(query, HTTPQuerySettings())
    assert query.get_from_clause().final

    # doesn't overlap replacements
    enforcer._set_query_final(query_with_future_timestamp, True)
    enforcer.process_query(query_with_future_timestamp, HTTPQuerySettings())
    assert not query_with_future_timestamp.get_from_clause().final
Beispiel #7
0
    def test_query_time_flags_project_and_groups(self) -> None:
        """
        Tests errors_replacer.set_project_needs_final() and
        errors_replacer.set_project_exclude_groups() work together as expected.

        ReplacementType's are arbitrary, just need to show up in
        getter appropriately once set.
        """
        redis_client.flushdb()
        project_ids = [7, 8, 9]

        errors_replacer.set_project_needs_final(7, ReplacerState.ERRORS,
                                                ReplacementType.EXCLUDE_GROUPS)
        errors_replacer.set_project_exclude_groups(7, [1, 2],
                                                   ReplacerState.ERRORS,
                                                   ReplacementType.START_MERGE)
        flags = ProjectsQueryFlags.load_from_redis(project_ids,
                                                   ReplacerState.ERRORS)
        assert (
            flags.needs_final,
            flags.group_ids_to_exclude,
            flags.replacement_types,
        ) == (
            True,
            {1, 2},
            # exclude_groups from project setter, start_merge from group setter
            {ReplacementType.EXCLUDE_GROUPS, ReplacementType.START_MERGE},
        )
def test_too_many_groups_to_exclude(query: ClickhouseQuery) -> None:
    state.set_config("max_group_ids_exclude", 2)
    set_project_exclude_groups(2, [100, 101, 102], ReplacerState.EVENTS)

    PostReplacementConsistencyEnforcer(
        "project_id", ReplacerState.EVENTS
    ).process_query(query, HTTPRequestSettings())

    assert query.get_condition_from_ast() == build_in("project_id", [2])
    assert query.get_from_clause().final
    def test_when_there_are_too_many_groups_to_exclude(self):
        request_settings = HTTPRequestSettings()
        state.set_config("max_group_ids_exclude", 2)
        set_project_exclude_groups(2, [100, 101, 102], ReplacerState.EVENTS)

        self.extension.get_processor().process_query(self.query,
                                                     self.valid_data,
                                                     request_settings)

        assert self.query.get_conditions() == [("project_id", "IN", [2])]
        assert self.query.get_condition_from_ast() == build_in(
            "project_id", [2])
        assert self.query.get_final()
Beispiel #10
0
def test_too_many_groups_to_exclude(query: ClickhouseQuery) -> None:
    state.set_config("max_group_ids_exclude", 2)
    set_project_exclude_groups(
        2,
        [100, 101, 102],
        ReplacerState.ERRORS,
        ReplacementType.
        EXCLUDE_GROUPS,  # Arbitrary replacement type, no impact on tests
    )

    PostReplacementConsistencyEnforcer("project_id",
                                       ReplacerState.ERRORS).process_query(
                                           query, HTTPQuerySettings())

    assert query.get_condition() == build_in("project_id", [2])
    assert query.get_from_clause().final
Beispiel #11
0
def test_no_groups_too_many_excludes(query: ClickhouseQuery) -> None:
    """
    Query has no groups, and too many to exclude.
    """
    enforcer = PostReplacementConsistencyEnforcer("project_id",
                                                  ReplacerState.ERRORS)

    set_project_exclude_groups(
        2,
        [100, 101, 102],
        ReplacerState.ERRORS,
        ReplacementType.
        EXCLUDE_GROUPS,  # Arbitrary replacement type, no impact on tests
    )

    enforcer._set_query_final(query, True)
    state.set_config("max_group_ids_exclude", 1)

    enforcer.process_query(query, HTTPQuerySettings())
    assert query.get_condition() == build_in("project_id", [2])
    assert query.get_from_clause().final
    def test_when_there_are_not_many_groups_to_exclude(self):
        request_settings = HTTPRequestSettings()
        state.set_config("max_group_ids_exclude", 5)
        set_project_exclude_groups(2, [100, 101, 102], ReplacerState.EVENTS)

        self.extension.get_processor().process_query(self.query,
                                                     self.valid_data,
                                                     request_settings)

        expected = [
            ("project_id", "IN", [2]),
            (["assumeNotNull", ["group_id"]], "NOT IN", [100, 101, 102]),
        ]
        assert self.query.get_conditions() == expected
        assert self.query.get_condition_from_ast() == FunctionCall(
            None,
            BooleanFunctions.AND,
            (
                FunctionCall(
                    None,
                    "notIn",
                    (
                        FunctionCall(None, "assumeNotNull",
                                     (Column(None, "group_id", None), )),
                        FunctionCall(
                            None,
                            "tuple",
                            (
                                Literal(None, 100),
                                Literal(None, 101),
                                Literal(None, 102),
                            ),
                        ),
                    ),
                ),
                build_in("project_id", [2]),
            ),
        )
        assert not self.query.get_final()
Beispiel #13
0
def test_multiple_disjoint_replaced(
    query_with_multiple_group_ids: ClickhouseQuery, ) -> None:
    """
    Query is looking for multiple groups and there are replaced groups, but these
    sets of group ids are disjoint. (No queried groups have been replaced)
    """
    enforcer = PostReplacementConsistencyEnforcer("project_id",
                                                  ReplacerState.ERRORS)

    set_project_exclude_groups(
        2,
        [110, 120, 130],
        ReplacerState.ERRORS,
        ReplacementType.
        EXCLUDE_GROUPS,  # Arbitrary replacement type, no impact on tests
    )

    enforcer._set_query_final(query_with_multiple_group_ids, True)
    state.set_config("max_group_ids_exclude", 5)

    enforcer.process_query(query_with_multiple_group_ids, HTTPQuerySettings())
    assert query_with_multiple_group_ids.get_condition() == build_and(
        build_in("project_id", [2]), build_in("group_id", [101, 102]))
    assert not query_with_multiple_group_ids.get_from_clause().final
Beispiel #14
0
    def test_query_time_flags_groups(self) -> None:
        """
        Tests errors_replacer.set_project_exclude_groups()

        ReplacementType's are arbitrary, just need to show up in
        getter appropriately once set.
        """
        redis_client.flushdb()
        project_ids = [4, 5, 6]
        errors_replacer.set_project_exclude_groups(
            4, [1, 2], ReplacerState.ERRORS, ReplacementType.EXCLUDE_GROUPS)
        errors_replacer.set_project_exclude_groups(5, [3, 4],
                                                   ReplacerState.ERRORS,
                                                   ReplacementType.START_MERGE)
        flags = ProjectsQueryFlags.load_from_redis(project_ids,
                                                   ReplacerState.ERRORS)
        assert (
            flags.needs_final,
            flags.group_ids_to_exclude,
            flags.replacement_types,
        ) == (
            False,
            {1, 2, 3, 4},
            {ReplacementType.EXCLUDE_GROUPS, ReplacementType.START_MERGE},
        )

        errors_replacer.set_project_exclude_groups(
            4, [1, 2], ReplacerState.ERRORS, ReplacementType.EXCLUDE_GROUPS)
        errors_replacer.set_project_exclude_groups(
            5, [3, 4], ReplacerState.ERRORS, ReplacementType.EXCLUDE_GROUPS)
        errors_replacer.set_project_exclude_groups(
            6, [5, 6], ReplacerState.ERRORS, ReplacementType.START_UNMERGE)

        flags = ProjectsQueryFlags.load_from_redis(project_ids,
                                                   ReplacerState.ERRORS)
        assert (
            flags.needs_final,
            flags.group_ids_to_exclude,
            flags.replacement_types,
        ) == (
            False,
            {1, 2, 3, 4, 5, 6},
            {
                ReplacementType.EXCLUDE_GROUPS,
                # start_merge should show up from previous setter on project id 2
                ReplacementType.START_MERGE,
                ReplacementType.START_UNMERGE,
            },
        )
        flags = ProjectsQueryFlags.load_from_redis([4, 5],
                                                   ReplacerState.ERRORS)
        assert (
            flags.needs_final,
            flags.group_ids_to_exclude,
            flags.replacement_types,
        ) == (
            False,
            {1, 2, 3, 4},
            {ReplacementType.EXCLUDE_GROUPS, ReplacementType.START_MERGE},
        )
        flags = ProjectsQueryFlags.load_from_redis([4], ReplacerState.ERRORS)
        assert (
            flags.needs_final,
            flags.group_ids_to_exclude,
            flags.replacement_types,
        ) == (
            False,
            {1, 2},
            {ReplacementType.EXCLUDE_GROUPS},
        )