def test_massage_no_timeseries(): query = _make_query( "statsPeriod=1d&interval=6h&field=sum(session)&groupby=projects") result_totals = [{"sessions": 4}] # snuba returns the datetimes as strings for now result_timeseries = None expected_result = { "start": "2020-12-17T12:00:00Z", "end": "2020-12-18T11:15:00Z", "query": "", "intervals": [ "2020-12-17T12:00:00Z", "2020-12-17T18:00:00Z", "2020-12-18T00:00:00Z", "2020-12-18T06:00:00Z", ], "groups": [{ "by": {}, "totals": { "sum(session)": 4 } }], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result
def test_nan_duration(): query = _make_query( "statsPeriod=1d&interval=6h&field=avg(session.duration)&field=p50(session.duration)" ) result_totals = [ { "duration_avg": math.nan, "duration_quantiles": [math.inf, math.inf, math.inf, math.inf, math.inf, math.inf], }, ] result_timeseries = [ { "duration_avg": math.nan, "duration_quantiles": [math.nan, math.nan, math.nan, math.nan, math.nan, math.nan], "bucketed_started": "2020-12-17T12:00:00+00:00", }, { "duration_avg": math.inf, "duration_quantiles": [math.inf, math.inf, math.inf, math.inf, math.inf, math.inf], "bucketed_started": "2020-12-18T06:00:00+00:00", }, ] expected_result = { "query": "", "intervals": [ "2020-12-17T12:00:00Z", "2020-12-17T18:00:00Z", "2020-12-18T00:00:00Z", "2020-12-18T06:00:00Z", ], "groups": [ { "by": {}, "series": { "avg(session.duration)": [None, None, None, None], "p50(session.duration)": [None, None, None, None], }, "totals": { "avg(session.duration)": None, "p50(session.duration)": None }, }, ], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result
def massage_outcomes_result( query: QueryDefinition, result_totals: ResultSet, result_timeseries: ResultSet, ) -> Dict[str, List[Any]]: result: Dict[str, List[Any]] = massage_sessions_result( query, result_totals, result_timeseries, ts_col=TS_COL ) del result["query"] return result
def massage_outcomes_result( query: QueryDefinition, result_totals: ResultSet, result_timeseries: Optional[ResultSet], ) -> Dict[str, List[Any]]: result: Dict[str, List[Any]] = massage_sessions_result( query, result_totals, result_timeseries, ts_col=TS_COL ) if result_timeseries is None: del result["intervals"] del result["query"] return result
def test_massage_unordered_timeseries(): query = _make_query("statsPeriod=1d&interval=6h&field=sum(session)") result_totals = [{"sessions": 10}] # snuba returns the datetimes as strings for now result_timeseries = [ { "sessions": 3, "bucketed_started": "2020-12-18T00:00:00+00:00" }, { "sessions": 2, "bucketed_started": "2020-12-17T18:00:00+00:00" }, { "sessions": 4, "bucketed_started": "2020-12-18T06:00:00+00:00" }, { "sessions": 1, "bucketed_started": "2020-12-17T12:00:00+00:00" }, ] expected_result = { "start": "2020-12-17T12:00:00Z", "end": "2020-12-18T11:15:00Z", "query": "", "intervals": [ "2020-12-17T12:00:00Z", "2020-12-17T18:00:00Z", "2020-12-18T00:00:00Z", "2020-12-18T06:00:00Z", ], "groups": [{ "by": {}, "series": { "sum(session)": [1, 2, 3, 4] }, "totals": { "sum(session)": 10 } }], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result
def run_sessions_query( self, org_id: int, query: QueryDefinition, span_op: str, ) -> SessionsQueryResult: with sentry_sdk.start_span(op=span_op, description="run_sessions_query"): totals, series = _run_sessions_query(query) with sentry_sdk.start_span(op=span_op, description="massage_sessions_results"): return massage_sessions_result(query, totals, series) # type: ignore
def get(self, request, organization): with self.handle_query_errors(): with sentry_sdk.start_span(op="sessions.endpoint", description="build_sessions_query"): query = self.build_sessions_query(request, organization) with sentry_sdk.start_span(op="sessions.endpoint", description="run_sessions_query"): result_totals, result_timeseries = run_sessions_query(query) with sentry_sdk.start_span(op="sessions.endpoint", description="massage_sessions_result"): result = massage_sessions_result(query, result_totals, result_timeseries) return Response(result, status=200)
def test_massage_empty(): query = _make_query("statsPeriod=1d&interval=1d&field=sum(session)") result_totals = [] result_timeseries = [] expected_result = { "query": "", "intervals": ["2020-12-18T00:00:00Z"], "groups": [], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result
def test_massage_simple_timeseries(): """A timeseries is filled up when it only receives partial data""" query = _make_query("statsPeriod=1d&interval=6h&field=sum(session)") result_totals = [{"sessions": 4}] # snuba returns the datetimes as strings for now result_timeseries = [ { "sessions": 2, "bucketed_started": "2020-12-18T06:00:00+00:00" }, { "sessions": 2, "bucketed_started": "2020-12-17T12:00:00+00:00" }, ] expected_result = { "start": "2020-12-17T12:00:00Z", "end": "2020-12-18T11:15:00Z", "query": "", "intervals": [ "2020-12-17T12:00:00Z", "2020-12-17T18:00:00Z", "2020-12-18T00:00:00Z", "2020-12-18T06:00:00Z", ], "groups": [{ "by": {}, "series": { "sum(session)": [2, 0, 0, 2] }, "totals": { "sum(session)": 4 } }], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result
def test_massage_exact_timeseries(): query = _make_query( "start=2020-12-17T15:12:34Z&end=2020-12-18T11:14:17Z&interval=6h&field=sum(session)" ) result_totals = [{"sessions": 4}] result_timeseries = [ { "sessions": 2, "bucketed_started": "2020-12-18T06:00:00+00:00" }, { "sessions": 2, "bucketed_started": "2020-12-17T12:00:00+00:00" }, ] expected_result = { "start": "2020-12-17T12:00:00Z", "end": "2020-12-18T12:00:00Z", "query": "", "intervals": [ "2020-12-17T12:00:00Z", "2020-12-17T18:00:00Z", "2020-12-18T00:00:00Z", "2020-12-18T06:00:00Z", ], "groups": [{ "by": {}, "series": { "sum(session)": [2, 0, 0, 2] }, "totals": { "sum(session)": 4 } }], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result
def run_sessions_query( self, org_id: int, query: QueryDefinition, span_op: str, ) -> SessionsQueryResult: # This is necessary because if we are running against the `DuplexReleaseHealthBackend`, the # `query` object gets mutated, and that in turn affects the query results in subsequent # backend calls query_clone = deepcopy(query) with sentry_sdk.start_span(op=span_op, description="run_sessions_query"): totals, series = _run_sessions_query(query_clone) with sentry_sdk.start_span(op=span_op, description="massage_sessions_results"): return massage_sessions_result(query_clone, totals, series) # type: ignore
def test_massage_virtual_groupby_timeseries(): query = _make_query( "statsPeriod=1d&interval=6h&field=sum(session)&field=count_unique(user)&groupBy=session.status" ) result_totals = [{ "users": 1, "users_crashed": 1, "sessions": 6, "sessions_errored": 1, "users_errored": 1, "sessions_abnormal": 0, "sessions_crashed": 1, "users_abnormal": 0, }] # snuba returns the datetimes as strings for now result_timeseries = [ { "sessions_errored": 1, "users": 1, "users_crashed": 1, "sessions_abnormal": 0, "sessions": 3, "users_errored": 1, "users_abnormal": 0, "sessions_crashed": 1, "bucketed_started": "2020-12-18T12:00:00+00:00", }, { "sessions_errored": 0, "users": 1, "users_crashed": 0, "sessions_abnormal": 0, "sessions": 3, "users_errored": 0, "users_abnormal": 0, "sessions_crashed": 0, "bucketed_started": "2020-12-18T06:00:00+00:00", }, ] expected_result = { "query": "", "intervals": [ "2020-12-17T18:00:00Z", "2020-12-18T00:00:00Z", "2020-12-18T06:00:00Z", "2020-12-18T12:00:00Z", ], "groups": [ { "by": { "session.status": "abnormal" }, "series": { "count_unique(user)": [0, 0, 0, 0], "sum(session)": [0, 0, 0, 0] }, "totals": { "count_unique(user)": 0, "sum(session)": 0 }, }, { "by": { "session.status": "crashed" }, "series": { "count_unique(user)": [0, 0, 0, 1], "sum(session)": [0, 0, 0, 1] }, "totals": { "count_unique(user)": 1, "sum(session)": 1 }, }, { "by": { "session.status": "errored" }, "series": { "count_unique(user)": [0, 0, 0, 1], "sum(session)": [0, 0, 0, 1] }, "totals": { "count_unique(user)": 1, "sum(session)": 1 }, }, { "by": { "session.status": "healthy" }, "series": { "count_unique(user)": [0, 0, 1, 0], "sum(session)": [0, 0, 3, 2] }, # while in one of the time slots, we have a healthy user, it is # the *same* user as the one experiencing a crash later on, # so in the *whole* time window, that one user is not counted as healthy, # so the `0` here is expected, as thats an example of the `count_unique` behavior. "totals": { "count_unique(user)": 0, "sum(session)": 5 }, }, ], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result
def test_massage_groupby_timeseries(): query = _make_query( "statsPeriod=1d&interval=6h&field=sum(session)&groupBy=release") result_totals = [ { "release": "test-example-release", "sessions": 4 }, { "release": "test-example-release-2", "sessions": 1 }, ] # snuba returns the datetimes as strings for now result_timeseries = [ { "release": "test-example-release", "sessions": 2, "bucketed_started": "2020-12-17T12:00:00+00:00", }, { "release": "test-example-release", "sessions": 2, "bucketed_started": "2020-12-18T06:00:00+00:00", }, { "release": "test-example-release-2", "sessions": 1, "bucketed_started": "2020-12-18T06:00:00+00:00", }, ] expected_result = { "query": "", "intervals": [ "2020-12-17T12:00:00Z", "2020-12-17T18:00:00Z", "2020-12-18T00:00:00Z", "2020-12-18T06:00:00Z", ], "groups": [ { "by": { "release": "test-example-release" }, "series": { "sum(session)": [2, 0, 0, 2] }, "totals": { "sum(session)": 4 }, }, { "by": { "release": "test-example-release-2" }, "series": { "sum(session)": [0, 0, 0, 1] }, "totals": { "sum(session)": 1 }, }, ], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result
def test_clamping_in_massage_sessions_results_with_groupby_timeseries(): query = _make_query( "statsPeriod=12h&interval=6h&field=sum(session)&field=count_unique(user)&groupBy=session.status" ) # snuba returns the datetimes as strings for now result_timeseries = [ { "sessions": 7, "sessions_errored": 3, "sessions_crashed": 2, "sessions_abnormal": 2, "users": 7, "users_errored": 3, "users_crashed": 2, "users_abnormal": 2, "bucketed_started": "2020-12-18T12:00:00+00:00", }, { "sessions": 5, "sessions_errored": 10, "sessions_crashed": 0, "sessions_abnormal": 0, "users": 5, "users_errored": 10, "users_crashed": 0, "users_abnormal": 0, "bucketed_started": "2020-12-18T06:00:00+00:00", }, ] expected_result = { "start": "2020-12-18T06:00:00Z", "end": "2020-12-18T13:26:00Z", "query": "", "intervals": [ "2020-12-18T06:00:00Z", "2020-12-18T12:00:00Z", ], "groups": [ { "by": { "session.status": "abnormal" }, "series": { "count_unique(user)": [0, 2], "sum(session)": [0, 2] }, "totals": { "count_unique(user)": 0, "sum(session)": 0 }, }, { "by": { "session.status": "crashed" }, "series": { "count_unique(user)": [0, 2], "sum(session)": [0, 2] }, "totals": { "count_unique(user)": 0, "sum(session)": 0 }, }, { "by": { "session.status": "errored" }, "series": { "count_unique(user)": [10, 0], "sum(session)": [10, 0] }, "totals": { "count_unique(user)": 0, "sum(session)": 0 }, }, { "by": { "session.status": "healthy" }, "series": { "count_unique(user)": [0, 4], "sum(session)": [0, 4] }, "totals": { "count_unique(user)": 0, "sum(session)": 0 }, }, ], } actual_result = result_sorted( massage_sessions_result(query, [], result_timeseries)) assert actual_result == expected_result
def test_massage_unbalanced_results(): query = _make_query( "statsPeriod=1d&interval=1d&field=sum(session)&groupBy=release") result_totals = [ { "release": "test-example-release", "sessions": 1 }, ] result_timeseries = [] expected_result = { "start": "2020-12-18T00:00:00Z", "end": "2020-12-18T11:15:00Z", "query": "", "intervals": ["2020-12-18T00:00:00Z"], "groups": [{ "by": { "release": "test-example-release" }, "series": { "sum(session)": [0] }, "totals": { "sum(session)": 1 }, }], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result result_totals = [] result_timeseries = [ { "release": "test-example-release", "sessions": 1, "bucketed_started": "2020-12-18T00:00:00+00:00", }, ] expected_result = { "start": "2020-12-18T00:00:00Z", "end": "2020-12-18T11:15:00Z", "query": "", "intervals": ["2020-12-18T00:00:00Z"], "groups": [{ "by": { "release": "test-example-release" }, "series": { "sum(session)": [1] }, "totals": { "sum(session)": 0 }, }], } actual_result = result_sorted( massage_sessions_result(query, result_totals, result_timeseries)) assert actual_result == expected_result