From 0706bc94c7d464228ed382f4ee2bd84a747098e7 Mon Sep 17 00:00:00 2001 From: SergeyGaluzo <95932081+SergeyGaluzo@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:11:24 -0700 Subject: [PATCH] Fixing flaky query plan test (#3994) * reset in the end * 1 sec * 5 * tweak * delay before query * more waits --- .../Persistence/SqlComplexQueryTests.cs | 58 +++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/test/Microsoft.Health.Fhir.Shared.Tests.Integration/Persistence/SqlComplexQueryTests.cs b/test/Microsoft.Health.Fhir.Shared.Tests.Integration/Persistence/SqlComplexQueryTests.cs index 228ae08f51..008a864ce5 100644 --- a/test/Microsoft.Health.Fhir.Shared.Tests.Integration/Persistence/SqlComplexQueryTests.cs +++ b/test/Microsoft.Health.Fhir.Shared.Tests.Integration/Persistence/SqlComplexQueryTests.cs @@ -48,55 +48,60 @@ public SqlComplexQueryTests(FhirStorageTestsFixture fixture, ITestOutputHelper o [Fact] public async Task GivenSearchQuery_IfReuseQueryPlansIsEnabled_ThenPlansAreReusedAcrossDifferentParameterValues() { - SqlServerSearchService.ResetReuseQueryPlans(); - await DisableResuseQueryPlans(); - await EnableResuseQueryPlans(); - await ResetQueryStore(); - await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City1")], CancellationToken.None); - await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City2")], CancellationToken.None); - //// values are different but plans are reused - await CheckQueryStore(2, 1); + await SetGranularQueryStore(); - SqlServerSearchService.ResetReuseQueryPlans(); - await DisableResuseQueryPlans(); await ResetQueryStore(); await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City1")], CancellationToken.None); + await Task.Delay(1000); await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City2")], CancellationToken.None); //// values are different and plans are NOT reused await CheckQueryStore(2, 2); - SqlServerSearchService.ResetReuseQueryPlans(); - await DisableResuseQueryPlans(); await ResetQueryStore(); - await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City1")], CancellationToken.None); - await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City1")], CancellationToken.None); + await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City")], CancellationToken.None); + await Task.Delay(1000); + await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City")], CancellationToken.None); //// values are same and plans are reused await CheckQueryStore(2, 1); + + await EnableResuseQueryPlans(); //// new behavior + await ResetQueryStore(); + SqlServerSearchService.ResetReuseQueryPlans(); + await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City1")], CancellationToken.None); + await Task.Delay(1000); + await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City2")], CancellationToken.None); + await Task.Delay(1000); + await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City3")], CancellationToken.None); + await Task.Delay(1000); + await _fixture.SearchService.SearchAsync(KnownResourceTypes.Patient, [Tuple.Create("address-city", "City4")], CancellationToken.None); + //// values are different but plans are reused + await CheckQueryStore(4, 1); } private async Task CheckQueryStore(int expected_executions, int expected_compiles) { + await Task.Delay(1000); using var conn = await _fixture.SqlHelper.GetSqlConnectionAsync(); using var cmd = new SqlCommand( @" -DECLARE @count_executions int - ,@count_compiles int +DECLARE @executions int + ,@compiles int ,@msg varchar(1000) BEGIN TRY - SELECT @count_executions = sum(count_executions), @count_compiles = sum(q.count_compiles) + SELECT @executions = sum(count_executions), @compiles = sum(q.count_compiles) FROM sys.query_store_runtime_stats s JOIN sys.query_store_plan p on p.plan_id = s.plan_id JOIN sys.query_store_query q on q.query_id = p.query_id JOIN sys.query_store_query_text qt on qt.query_text_id = q.query_text_id WHERE query_sql_text LIKE '%StringSearchParam%' AND query_sql_text NOT LIKE '%sys.query_store_query%' - IF @expected_executions <> @count_executions + IF @expected_executions <> @executions BEGIN - SET @msg = '@expected_executions='+convert(varchar,@expected_executions)+' <> @count_executions='+convert(varchar,@count_executions) + SET @msg = '@expected_executions='+convert(varchar,@expected_executions)+' <> @executions='+convert(varchar,@executions) RAISERROR(@msg,18,127) END - IF @expected_compiles <> @count_compiles + IF @expected_compiles <> @compiles BEGIN - SET @msg = '@expected_compiles='+convert(varchar,@expected_compiles)+' <> @count_compiles='+convert(varchar,@count_compiles) + SET @msg = '@expected_compiles='+convert(varchar,@expected_compiles)+' <> @compiles='+convert(varchar,@compiles) RAISERROR(@msg,18,127) END END TRY @@ -129,14 +134,21 @@ private async Task EnableResuseQueryPlans() cmd.ExecuteNonQuery(); } + private async Task SetGranularQueryStore() + { + using var conn = await _fixture.SqlHelper.GetSqlConnectionAsync(); + conn.Open(); + using var cmd = new SqlCommand("DECLARE @db varchar(100) = db_name() EXECUTE('ALTER DATABASE ['+@db+'] SET QUERY_STORE = ON (QUERY_CAPTURE_MODE = ALL)')", conn); + cmd.ExecuteNonQuery(); + } + private async Task ResetQueryStore() { using var conn = await _fixture.SqlHelper.GetSqlConnectionAsync(); conn.Open(); using var cmd = new SqlCommand("DECLARE @db varchar(100) = db_name() EXECUTE('ALTER DATABASE ['+@db+'] SET QUERY_STORE CLEAR')", conn); cmd.ExecuteNonQuery(); - using var cmd2 = new SqlCommand("DECLARE @db varchar(100) = db_name() EXECUTE('ALTER DATABASE ['+@db+'] SET QUERY_STORE = ON (QUERY_CAPTURE_MODE = ALL)')", conn); - cmd2.ExecuteNonQuery(); + await Task.Delay(1000); } [SkippableFact]