Query Store Service (#2171)

* Checkpoint

* Checkpoint

* Checkpoint

* checkpoint

* Hooking in calls to QueryExecutionService

* adding cases

* Fleshing out report handlers

* Adding parameter converters

* Adding sqlparam declarations for Top Resource Consumers and Forced Plans

* swapping to object-object to centralize conversion for sqlparams

* Adding sqlparams for GetTrackedQueries

* Added sqlparams for High Variation

* Added Overall ResourceConumption

* Adding params for regressed queries

* Removing WithWaitStats calls, since they're automatically used within QSM when waitstats is an available statistic#

* Adding PlanSummary handlers

* cleaning up orderable queries

* initial test mockout

* adding basic (incorrect) parameter translation

* first test passing, datetimeoffset swapped to ISO format

* Adding test baselines

* Updating nuget package

* Adding get/set

* Adding get/set for result object

* Switching to parameter-less constructor

* Swapping TimeInterval for string-based BasicTimeInterval

* Removing unnecessary usings

* Adding back params comments

* Fixing up request docstrings

* comment tweak

* fix tests failing in pipeline because of line endings not matching

* removing unnecessary usings

* Setting tests to generate queries in UTC for test stability

* Normalizing line endings

---------

Co-authored-by: Kim Santiago <kisantia@microsoft.com>
This commit is contained in:
Benjin Dubishar
2023-09-01 10:56:39 -07:00
committed by GitHub
parent c0a0f27e49
commit 25c18d3390
16 changed files with 2263 additions and 0 deletions

View File

@@ -0,0 +1,284 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.SqlServer.Management.QueryStoreModel.Common;
using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility;
using Microsoft.SqlTools.ServiceLayer.QueryStore;
using Microsoft.SqlTools.ServiceLayer.QueryStore.Contracts;
using Microsoft.SqlTools.ServiceLayer.Test.Common.RequestContextMocking;
using Moq;
using NUnit.Framework;
using static Microsoft.SqlServer.Management.QueryStoreModel.PlanSummary.PlanSummaryConfiguration;
namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.QueryStore
{
public class QueryStoreTests : TestBase
{
private const string TestConnectionOwnerUri = "FakeConnectionOwnerUri";
private static DateTimeOffset TestWindowStart = DateTimeOffset.Parse("6/10/2023 12:34:56 PM +0:00");
private static DateTimeOffset TestWindowEnd = TestWindowStart.AddDays(7);
private static DateTimeOffset TestWindowRecentStart = TestWindowEnd.AddHours(-1);
private static BasicTimeInterval TestTimeInterval => new BasicTimeInterval()
{
StartDateTimeInUtc = TestWindowStart.ToString("O"),
EndDateTimeInUtc = TestWindowEnd.ToString("O")
};
private static BasicTimeInterval RecentTestTimeInterval => new BasicTimeInterval()
{
StartDateTimeInUtc = TestWindowRecentStart.ToString("O"),
EndDateTimeInUtc = TestWindowEnd.ToString("O")
};
[SetUp]
public void Setup()
{
QueryStoreCommonConfiguration.DisplayTimeKind = DateTimeKind.Utc;
}
[Test]
public async Task TopResourceConsumers()
{
QueryStoreService service = GetMock();
MockRequest<QueryStoreQueryResult> request = new();
await service.HandleGetTopResourceConsumersSummaryReportRequest(new GetTopResourceConsumersReportParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
ReturnAllQueries = true,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev,
OrderByColumnId = "query_id",
Descending = true,
MinNumberOfQueryPlans = 1,
TopQueriesReturned = 50,
TimeInterval = TestTimeInterval
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetTopResourceConsumersSummaryReportRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetTopResourceConsumersSummaryReportRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
request = new();
await service.HandleGetTopResourceConsumersDetailedSummaryReportRequest(new GetTopResourceConsumersReportParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
ReturnAllQueries = true,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev,
OrderByColumnId = "query_id",
Descending = true,
MinNumberOfQueryPlans = 1,
TopQueriesReturned = 50,
TimeInterval = TestTimeInterval
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetTopResourceConsumersDetailedSummaryReportRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetTopResourceConsumersDetailedSummaryReportRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
}
[Test]
public async Task ForcedPlanQueries()
{
QueryStoreService service = GetMock();
MockRequest<QueryStoreQueryResult> request = new();
await service.HandleGetForcedPlanQueriesReportRequest(new GetForcedPlanQueriesReportParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
ReturnAllQueries = true,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev,
OrderByColumnId = "query_id",
Descending = true,
MinNumberOfQueryPlans = 1,
TopQueriesReturned = 50,
TimeInterval = TestTimeInterval
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetForcedPlanQueriesReportRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetForcedPlanQueriesReportRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
}
[Test]
public async Task TrackedQueries()
{
QueryStoreService service = GetMock();
MockRequest<QueryStoreQueryResult> request = new();
await service.HandleGetTrackedQueriesReportRequest(new GetTrackedQueriesReportParams()
{
QuerySearchText = "test search text"
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetTrackedQueriesReportRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetTrackedQueriesReportRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
}
[Test]
public async Task HighVariationQueries()
{
QueryStoreService service = GetMock();
MockRequest<QueryStoreQueryResult> request = new();
await service.HandleGetHighVariationQueriesSummaryReportRequest(new GetHighVariationQueriesReportParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
ReturnAllQueries = true,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev,
OrderByColumnId = "query_id",
Descending = true,
MinNumberOfQueryPlans = 1,
TopQueriesReturned = 50,
TimeInterval = TestTimeInterval
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetHighVariationQueriesSummaryReportRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetHighVariationQueriesSummaryReportRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
request = new();
await service.HandleGetHighVariationQueriesDetailedSummaryReportRequest(new GetHighVariationQueriesReportParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
ReturnAllQueries = true,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev,
OrderByColumnId = "query_id",
Descending = true,
MinNumberOfQueryPlans = 1,
TopQueriesReturned = 50,
TimeInterval = TestTimeInterval
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetHighVariationQueriesDetailedSummaryReportRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetHighVariationQueriesDetailedSummaryReportRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
}
[Test]
public async Task OverallResourceConsumption()
{
QueryStoreService service = GetMock();
MockRequest<QueryStoreQueryResult> request = new();
await service.HandleGetOverallResourceConsumptionReportRequest(new GetOverallResourceConsumptionReportParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
ReturnAllQueries = true,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev,
MinNumberOfQueryPlans = 1,
TopQueriesReturned = 50,
SpecifiedTimeInterval = TestTimeInterval,
SpecifiedBucketInterval = BucketInterval.Hour
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetOverallResourceConsumptionReportRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetOverallResourceConsumptionReportRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
}
[Test]
public async Task RegressedQueries()
{
QueryStoreService service = GetMock();
MockRequest<QueryStoreQueryResult> request = new();
await service.HandleGetRegressedQueriesSummaryReportRequest(new GetRegressedQueriesReportParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
ReturnAllQueries = true,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev,
MinNumberOfQueryPlans = 1,
TopQueriesReturned = 50,
MinExecutionCount = 1,
TimeIntervalHistory = TestTimeInterval,
TimeIntervalRecent = RecentTestTimeInterval
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetRegressedQueriesSummaryReportRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetRegressedQueriesSummaryReportRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
request = new();
await service.HandleGetRegressedQueriesDetailedSummaryReportRequest(new GetRegressedQueriesReportParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
ReturnAllQueries = true,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev,
MinNumberOfQueryPlans = 1,
TopQueriesReturned = 50,
MinExecutionCount = 1,
TimeIntervalHistory = TestTimeInterval,
TimeIntervalRecent = RecentTestTimeInterval
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetRegressedQueriesDetailedSummaryReportRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetRegressedQueriesDetailedSummaryReportRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
}
[Test]
public async Task PlanSummary()
{
QueryStoreService service = GetMock();
MockRequest<QueryStoreQueryResult> request = new();
await service.HandleGetPlanSummaryChartViewRequest(new GetPlanSummaryParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
QueryId = 97,
TimeInterval = TestTimeInterval,
TimeIntervalMode = PlanTimeIntervalMode.SpecifiedRange,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetPlanSummaryChartViewRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetPlanSummaryChartViewRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
request = new();
await service.HandleGetPlanSummaryGridViewRequest(new GetPlanSummaryGridViewParams()
{
ConnectionOwnerUri = TestConnectionOwnerUri,
QueryId = 97,
TimeInterval = TestTimeInterval,
TimeIntervalMode = PlanTimeIntervalMode.SpecifiedRange,
SelectedMetric = Metric.WaitTime,
SelectedStatistic = Statistic.Stdev,
OrderByColumnId = "count_executions",
Descending = true
}, request.Object);
request.AssertSuccess(nameof(service.HandleGetPlanSummaryGridViewRequest));
Assert.AreEqual(QueryStoreBaselines.HandleGetPlanSummaryGridViewRequest.ReplaceLineEndings(), request.Result.Query.ReplaceLineEndings());
}
private QueryStoreService GetMock()
{
Mock<QueryStoreService> mock = new Mock<QueryStoreService>();
mock.Setup(s => s.GetAvailableMetrics(It.IsAny<QueryStoreReportParams>()))
.Returns(new List<Metric>()
{
Metric.ClrTime,
Metric.CPUTime,
Metric.Dop,
Metric.Duration,
Metric.ExecutionCount,
Metric.LogicalReads,
Metric.LogicalWrites,
Metric.LogMemoryUsed,
Metric.MemoryConsumption,
Metric.PhysicalReads,
Metric.RowCount,
Metric.TempDbMemoryUsed,
Metric.WaitTime
});
return mock.Object;
}
}
}