From 58e65438d894e4635ece39a1400fbb1325e0d88a Mon Sep 17 00:00:00 2001 From: Andreas Jordan Date: Sat, 15 Aug 2026 16:05:46 +0200 Subject: [PATCH] Backup-DbaDatabase - Restore model after the all-databases backup test The context "Properly backups all databases" backs up every database of InstanceCopy1, so it also takes a full backup of model. As model is in the full recovery model, that backup starts its log chain, and because no log backup ever follows, the log can never be reused and grows on every run of this file. The growth is in the file size, so a restart does not undo it, and once the log passes 32 MB it breaks New-DbaDatabase.Tests.ps1, which asserts the exact log size of a new database on the same instance. The new AfterAll records the recovery model and log size before the backup and restores both afterwards. Switching to the simple recovery model is what makes the log reusable again - without it the shrink cannot release anything and the file even grows instead. Also removes a TODO that is answered: 06_configure_instances.ps1 creates the master key on every lab instance at startup. (do Backup-DbaDatabase) Co-Authored-By: Claude Opus 5 (1M context) --- tests/Backup-DbaDatabase.Tests.ps1 | 46 +++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/Backup-DbaDatabase.Tests.ps1 b/tests/Backup-DbaDatabase.Tests.ps1 index b2a277f343c..87cfb32d856 100644 --- a/tests/Backup-DbaDatabase.Tests.ps1 +++ b/tests/Backup-DbaDatabase.Tests.ps1 @@ -81,9 +81,54 @@ Describe $CommandName -Tag IntegrationTests { Context "Properly backups all databases" { BeforeAll { + # This backs up every database of the instance, so it also takes a full backup of model. + # As model is in the full recovery model, that backup starts its log chain, and because no + # log backup ever follows, the log can never be reused and grows a little on every run of + # this file. That growth is in the file size, so a restart does not undo it, and once the + # log passes 32 MB it breaks New-DbaDatabase.Tests.ps1, which asserts the exact log size + # of a new database on the same instance. So we record the state here and restore it below. + $queryModelStateBefore = @" +SELECT d.recovery_model_desc AS RecoveryModel, f.size * 8 AS LogSizeKb +FROM sys.databases AS d +JOIN sys.master_files AS f ON f.database_id = d.database_id AND f.type = 1 +WHERE d.name = N'model' +"@ + $modelStateBefore = Invoke-DbaQuery -SqlInstance $TestConfig.InstanceCopy1 -Database master -Query $queryModelStateBefore + $results = Backup-DbaDatabase -SqlInstance $TestConfig.InstanceCopy1 } + AfterAll { + # We want to run all commands in the AfterAll block with EnableException to ensure that the test fails if the cleanup fails. + $PSDefaultParameterValues["*-Dba*:EnableException"] = $true + + # Break the log chain that the full backup of model started and give the log its original + # size back. Switching to the simple recovery model is what makes the log reusable again - + # without it the shrink cannot release anything, because the log still waits for a log + # backup, and the file even grows instead. + if ($modelStateBefore.RecoveryModel -ne "SIMPLE") { + $modelLogSizeMb = [Math]::Max(1, [Math]::Floor($modelStateBefore.LogSizeKb / 1024)) + + $queryBreakLogChain = @" +ALTER DATABASE model SET RECOVERY SIMPLE WITH NO_WAIT; +"@ + # DBCC SHRINKFILE resolves the logical file name in the current database, so this has to run in model. + $queryShrinkModelLog = @" +CHECKPOINT; +DBCC SHRINKFILE (N'modellog', $modelLogSizeMb) WITH NO_INFOMSGS; +"@ + $queryRestoreRecoveryModel = @" +ALTER DATABASE model SET RECOVERY $($modelStateBefore.RecoveryModel) WITH NO_WAIT; +"@ + + $null = Invoke-DbaQuery -SqlInstance $TestConfig.InstanceCopy1 -Database master -Query $queryBreakLogChain + $null = Invoke-DbaQuery -SqlInstance $TestConfig.InstanceCopy1 -Database model -Query $queryShrinkModelLog + $null = Invoke-DbaQuery -SqlInstance $TestConfig.InstanceCopy1 -Database master -Query $queryRestoreRecoveryModel + } + + $PSDefaultParameterValues.Remove("*-Dba*:EnableException") + } + It "Should return a database name, specifically master" { $results.DatabaseName | Should -Contain "master" } @@ -534,7 +579,6 @@ go } Context "Test Backup Encryption with Certificate" { - # TODO: Should the master key be created at lab startup like in instance3? BeforeAll { $securePass = ConvertTo-SecureString "MyStrongPassword123!" -AsPlainText -Force $cert = New-DbaDbCertificate -SqlInstance $TestConfig.InstanceCopy2 -Database master -Name BackupCertt -Subject BackupCertt