From 8e860bbd7b9fbca116d6c355cb9fad1340390e6d Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Tue, 16 Apr 2024 11:32:11 -0700 Subject: [PATCH 01/16] Fixed: markdown in documentation causing anti-virus problems. --- Rivet/Functions/Columns/New-DateColumn.ps1 | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Rivet/Functions/Columns/New-DateColumn.ps1 b/Rivet/Functions/Columns/New-DateColumn.ps1 index e67ac29f..64025e01 100644 --- a/Rivet/Functions/Columns/New-DateColumn.ps1 +++ b/Rivet/Functions/Columns/New-DateColumn.ps1 @@ -26,9 +26,11 @@ function New-DateColumn Demonstrate show to create a nullable, sparse `date` column when adding a new table. .EXAMPLE - Add-Table 'Members' { Date 'Birthday' -NotNull -Default 'get`date`()' } - - Demonstrates how to create a `date` column with a default value, in this case the current `date`. (You alwyas use UTC `date`s, right?) Probably not a great example, setting someone's birthday to the current `date`. Reasons are left as an exercise for the reader. + Add-Table 'Members' { Date 'Birthday' -NotNull -Default 'getdate()' } + + Demonstrates how to create a `date` column with a default value, in this case the current `date`. (You alwyas use + UTC dates, right?) Probably not a great example, setting someone's birthday to the current `date`. Reasons are + left as an exercise for the reader. .EXAMPLE Add-Table 'Members' { Date 'Birthday' -Description 'The members birthday.' } @@ -49,16 +51,16 @@ function New-DateColumn # Store nulls as Sparse. [switch]$Sparse, - # A SQL Server expression for the column's default value + # A SQL Server expression for the column's default value [String]$Default, # The name of the default constraint for the column's default expression. Required if the Default parameter is given. [String]$DefaultConstraintName, - + # A description of the column. [String]$Description ) - + switch ($PSCmdlet.ParameterSetName) { 'Nullable' @@ -70,12 +72,12 @@ function New-DateColumn } [Rivet.Column]::Date($Name, $nullable, $Default, $DefaultConstraintName, $Description) } - + 'NotNull' { [Rivet.Column]::Date($Name, [Rivet.Nullable]::NotNull, $Default, $DefaultConstraintName, $Description) } } } - + Set-Alias -Name 'Date' -Value 'New-DateColumn' \ No newline at end of file From 1af9286542a1f07217597692164cde6952f2027e Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Tue, 16 Apr 2024 12:18:13 -0700 Subject: [PATCH 02/16] Target a newer version of .NET framework. --- Source/Rivet.Test.Fake/Rivet.Test.Fake.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Rivet.Test.Fake/Rivet.Test.Fake.csproj b/Source/Rivet.Test.Fake/Rivet.Test.Fake.csproj index 3e01e360..7f2b257a 100644 --- a/Source/Rivet.Test.Fake/Rivet.Test.Fake.csproj +++ b/Source/Rivet.Test.Fake/Rivet.Test.Fake.csproj @@ -9,7 +9,7 @@ Properties Rivet.Test.Fake Rivet.Test.Fake - v4.5 + v4.6.2 512 true From 5da755f447fcf9a95d60d8cda714abdeba3c4781 Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Tue, 16 Apr 2024 12:20:51 -0700 Subject: [PATCH 03/16] Removing InitializeSchema switch on rivet.ps1 and Invoke-Rivet as it was never implemented. --- CHANGELOG.md | 7 +++++++ Rivet/Functions/Invoke-Rivet.ps1 | 9 +-------- Rivet/Rivet.psd1 | 2 +- Rivet/rivet.ps1 | 24 ++++++++--------------- Test/Checkpoint-Migration.Tests.ps1 | 2 +- Test/RivetTest/Functions/Invoke-Rivet.ps1 | 7 +------ 6 files changed, 19 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dbe2394..0240993d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ # Rivet Changelog +## 0.23.0 + +### Removed + +* Removed the `InitializeSchema` switch from `rivet.ps1` and `Invoke-Rivet` as it was not actually implemented. + + ## 0.22.0 > Released 6 Jul 2023 diff --git a/Rivet/Functions/Invoke-Rivet.ps1 b/Rivet/Functions/Invoke-Rivet.ps1 index 82e8b56f..4a046b2d 100644 --- a/Rivet/Functions/Invoke-Rivet.ps1 +++ b/Rivet/Functions/Invoke-Rivet.ps1 @@ -56,7 +56,6 @@ function Invoke-Rivet [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] - [Parameter(ParameterSetName='InitializeSchema')] [String[]] $Database, # The environment you're working in. Controls which settings Rivet loads from the `rivet.json` configuration file. @@ -69,7 +68,6 @@ function Invoke-Rivet [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] - [Parameter(ParameterSetName='InitializeSchema')] [String] $Environment, # The path to the Rivet configuration file. Default behavior is to look in the current directory for a @@ -83,7 +81,6 @@ function Invoke-Rivet [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] - [Parameter(ParameterSetName='InitializeSchema')] [String] $ConfigFilePath, # Drops the database(s) for the current environment when given. User will be prompted for confirmation when @@ -93,11 +90,7 @@ function Invoke-Rivet # Checkpoints the current state of the database so that it can be re-created. [Parameter(ParameterSetName='Checkpoint')] - [switch] $Checkpoint, - - # Initializes the database, including baseline schema. Use the -Checkpoint switch to create a database baseline. - [Parameter(ParameterSetName='InitializeSchema')] - [switch] $InitializeSchema + [switch] $Checkpoint ) Set-StrictMode -Version 'Latest' diff --git a/Rivet/Rivet.psd1 b/Rivet/Rivet.psd1 index 065f0ac5..45bab55f 100644 --- a/Rivet/Rivet.psd1 +++ b/Rivet/Rivet.psd1 @@ -11,7 +11,7 @@ RootModule = 'Rivet.psm1' # Version number of this module. - ModuleVersion = '0.22.0' + ModuleVersion = '0.23.0' # ID used to uniquely identify this module GUID = '8af34b47-259b-4630-a945-75d38c33b94d' diff --git a/Rivet/rivet.ps1 b/Rivet/rivet.ps1 index 281ac0b1..b3bc1d56 100644 --- a/Rivet/rivet.ps1 +++ b/Rivet/rivet.ps1 @@ -31,7 +31,7 @@ Applies all migrations. .EXAMPLE rivet.ps1 -Push 'CreateTableStarships' -Demonstrates how to apply a named migration. Don't include the timestamp. Wildcards are permitted. +Demonstrates how to apply a named migration. Don't include the timestamp. Wildcards are permitted. *Be careful with this syntax!* If the named migration(s) depend on other migrations that haven't been run, the migration will fail. @@ -53,7 +53,7 @@ Demonstrates how to pop a specific migration. Wildcards supported. Will match .EXAMPLE rivet.ps1 -Redo -Reverts the last migration script, then reapplies its. Equivalent to +Reverts the last migration script, then reapplies its. Equivalent to rivet.ps1 -Pop rivet.ps1 -Push @@ -75,12 +75,12 @@ param( [Switch] # Creates a new migration. $New, - + [Parameter(Mandatory=$true,ParameterSetName='Push')] [Switch] # Applies migrations. $Push, - + [Parameter(Mandatory=$true,ParameterSetName='Pop')] [Parameter(Mandatory=$true,ParameterSetName='PopByCount')] [Parameter(Mandatory=$true,ParameterSetName='PopByName')] @@ -88,7 +88,7 @@ param( [Switch] # Reverts migrations. $Pop, - + [Parameter(Mandatory=$true,ParameterSetName='Redo')] [Switch] # Reverts a migration, then re-applies it. @@ -101,7 +101,7 @@ param( [string[]] # The name of the migrations to create, push, or pop. Matches against the migration's ID, Name, or file name (without extension). Wildcards permitted. $Name, - + [Parameter(Mandatory=$true,ParameterSetName='PopByCount',Position=1)] [UInt32] # The number of migrations to pop. Default is 1. @@ -130,7 +130,6 @@ param( [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] - [Parameter(ParameterSetName='InitializeSchema')] [string[]] # The database(s) to migrate. Optional. Will operate on all databases otherwise. $Database, @@ -144,7 +143,6 @@ param( [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] - [Parameter(ParameterSetName='InitializeSchema')] [string] # The environment you're working in. Controls which settings Rivet loads from the `rivet.json` configuration file. $Environment, @@ -158,7 +156,6 @@ param( [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] - [Parameter(ParameterSetName='InitializeSchema')] [string] # The path to the Rivet configuration file. Default behavior is to look in the current directory for a `rivet.json` file. See `about_Rivet_Configuration` for more information. $ConfigFilePath, @@ -171,12 +168,7 @@ param( [Parameter(ParameterSetName='Checkpoint')] [Switch] # Checkpoints the current state of the database so that it can be re-created. - $Checkpoint, - - [Parameter(ParameterSetName='InitializeSchema')] - [Switch] - # Initializes the database, including baseline schema. Use the -Checkpoint switch to create a database baseline. - $InitializeSchema + $Checkpoint ) Set-StrictMode -Version Latest @@ -189,6 +181,6 @@ if( $PSCmdlet.ParameterSetName -eq 'ShowHelp' ) & (Join-Path -Path $PSScriptRoot -ChildPath Import-Rivet.ps1 -Resolve) -Invoke-Rivet @PSBoundParameters +Invoke-Rivet @PSBoundParameters exit $error.Count diff --git a/Test/Checkpoint-Migration.Tests.ps1 b/Test/Checkpoint-Migration.Tests.ps1 index b8a0f904..f5cb5984 100644 --- a/Test/Checkpoint-Migration.Tests.ps1 +++ b/Test/Checkpoint-Migration.Tests.ps1 @@ -125,7 +125,7 @@ BeforeAll { Remove-RivetTestDatabase -Name $databaseName # Now, check that the schema.ps1 script is runnable - Invoke-RTRivet -InitializeSchema -Database $databaseName -ErrorAction Stop + Invoke-RTRivet -Database $databaseName -ErrorAction Stop Invoke-RTRivet -Pop -Database $databaseName -ErrorAction Stop } } diff --git a/Test/RivetTest/Functions/Invoke-Rivet.ps1 b/Test/RivetTest/Functions/Invoke-Rivet.ps1 index cba95ee2..a6727592 100644 --- a/Test/RivetTest/Functions/Invoke-Rivet.ps1 +++ b/Test/RivetTest/Functions/Invoke-Rivet.ps1 @@ -47,12 +47,7 @@ function Invoke-RTRivet [Parameter(ParameterSetName='Checkpoint')] [Switch] # Checkpoints the current state of the database so that it can be re-created. - $Checkpoint, - - [Parameter(ParameterSetName='InitializeSchema')] - [Switch] - # Initializes the database, including baseline schema. Use the -Checkpoint switch to create a database baseline. - $InitializeSchema + $Checkpoint ) Set-StrictMode -Version Latest From 0c37d69e4df18cd946f247be9dcde41d673de64c Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Tue, 16 Apr 2024 13:11:56 -0700 Subject: [PATCH 04/16] Using a better function name. --- Rivet/Functions/Convert-FileInfoToMigration.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rivet/Functions/Convert-FileInfoToMigration.ps1 b/Rivet/Functions/Convert-FileInfoToMigration.ps1 index c33d3da2..b7827afc 100644 --- a/Rivet/Functions/Convert-FileInfoToMigration.ps1 +++ b/Rivet/Functions/Convert-FileInfoToMigration.ps1 @@ -73,14 +73,14 @@ function Convert-FileInfoToMigration } } - function Clear-Migration + function Clear-MigrationFunction { ('function:Push-Migration','function:Pop-Migration') | Where-Object { Test-Path -Path $_ } | Remove-Item -WhatIf:$false -Confirm:$false } - Clear-Migration + Clear-MigrationFunction Import-RivetPlugin -Path $Session.PluginPaths -ModuleName $Session.PluginModules } @@ -154,7 +154,7 @@ Pop-Migration function not found. All migrations are required to have a Pop-Migr } finally { - Clear-Migration + Clear-MigrationFunction } } } From cfb34b2ff1fca705609869e7eb1e5766b825362e Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Tue, 16 Apr 2024 13:13:05 -0700 Subject: [PATCH 05/16] Using this syntax causes an extra error when a migration throws an exception. --- Rivet/Functions/Update-Database.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rivet/Functions/Update-Database.ps1 b/Rivet/Functions/Update-Database.ps1 index 68720480..4d31e9b7 100644 --- a/Rivet/Functions/Update-Database.ps1 +++ b/Rivet/Functions/Update-Database.ps1 @@ -152,7 +152,7 @@ function Update-Database $migrations = $migrationFilesByDb | - Where-Object 'Name' -eq $dbInfo.Name | + Where-Object { $_.Name -eq $dbInfo.Name } | Select-Object -ExpandProperty Group | Where-Object { $appliedMigration = $appliedMigrations[$_.MigrationID] From bb21d0b322b308d55c0d4a8002e62671a7a984ef Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Tue, 16 Apr 2024 16:29:54 -0700 Subject: [PATCH 06/16] Stop exporting owner information for schemas. --- CHANGELOG.md | 6 ++++++ Rivet/Functions/Export-Migration.ps1 | 2 +- Test/Export-Migration.Tests.ps1 | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0240993d..bfefacc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ ## 0.23.0 +### Changed + +* `Export-Migration` no longer creates an `Add-Schema` operation that includes owner information (i.e. the `Owner` +parameter is omitted). When exporting a schema to DDL in SQL Server Management Studio, the owner information is also +omitted so we think this change should be OK. + ### Removed * Removed the `InitializeSchema` switch from `rivet.ps1` and `Invoke-Rivet` as it was not actually implemented. diff --git a/Rivet/Functions/Export-Migration.ps1 b/Rivet/Functions/Export-Migration.ps1 index 38805e82..5785deb6 100644 --- a/Rivet/Functions/Export-Migration.ps1 +++ b/Rivet/Functions/Export-Migration.ps1 @@ -1224,7 +1224,7 @@ from } Write-ExportingMessage -Schema $Object.schema_name -Type Schema - ' Add-Schema -Name ''{0}'' -Owner ''{1}''{2}' -f $schema.name,$schema.owner, $description + " Add-Schema -Name '$($schema.name)'${description}" $exportedSchemas[$schema.name] = $true Push-PopOperation ('Remove-Schema -Name ''{0}''' -f $schema.name) } diff --git a/Test/Export-Migration.Tests.ps1 b/Test/Export-Migration.Tests.ps1 index c0ed853a..6f1d217f 100644 --- a/Test/Export-Migration.Tests.ps1 +++ b/Test/Export-Migration.Tests.ps1 @@ -1228,7 +1228,7 @@ function Pop-Migration '@ WhenExporting - ThenMigration -HasContent 'Add-Schema -Name ''snap'' -Owner ''dbo'' -Description ''This is the MS Description for the schema snap''' + ThenMigration -HasContent 'Add-Schema -Name ''snap'' -Description ''This is the MS Description for the schema snap''' ThenMigration -HasContent 'Add-Table -SchemaName ''snap'' -Name ''SnapTable''' } From 4f3e88dba0f10dd2fb2f5d3c28b02d39ec2f3db8 Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Tue, 16 Apr 2024 17:31:42 -0700 Subject: [PATCH 07/16] Automatically apply baseline migration when pushing. --- CHANGELOG.md | 7 +- .../Functions/Convert-FileInfoToMigration.ps1 | 33 ++- Rivet/Functions/Get-MigrationFile.ps1 | 16 +- Rivet/Functions/Update-Database.ps1 | 143 ++++++----- Test/Checkpoint-Migration.Tests.ps1 | 2 +- Test/Push-Migration.Tests.ps1 | 2 + .../Functions/Clear-TestDatabase.ps1 | 4 +- .../RivetTest/Functions/Get-MigrationInfo.ps1 | 14 +- Test/RivetTest/Functions/New-Migration.ps1 | 40 +++- .../Functions/Remove-RivetTestDatabase.ps1 | 6 +- Test/schema.ps1.Tests.ps1 | 226 ++++++++++++++++++ 11 files changed, 398 insertions(+), 95 deletions(-) create mode 100644 Test/schema.ps1.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index bfefacc0..84b11485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,15 @@ * `Export-Migration` no longer creates an `Add-Schema` operation that includes owner information (i.e. the `Owner` parameter is omitted). When exporting a schema to DDL in SQL Server Management Studio, the owner information is also omitted so we think this change should be OK. +* Pushing to a database will now apply the baseline schema if it hasn't been applied. + +### Fixed + +* Baseline schema in schema.ps1 doesn't get applied when pushing migrations. ### Removed -* Removed the `InitializeSchema` switch from `rivet.ps1` and `Invoke-Rivet` as it was not actually implemented. +Removed the `InitializeSchema` switch from `rivet.ps1` and `Invoke-Rivet` as it was not actually implemented. ## 0.22.0 diff --git a/Rivet/Functions/Convert-FileInfoToMigration.ps1 b/Rivet/Functions/Convert-FileInfoToMigration.ps1 index b7827afc..e4cd279f 100644 --- a/Rivet/Functions/Convert-FileInfoToMigration.ps1 +++ b/Rivet/Functions/Convert-FileInfoToMigration.ps1 @@ -57,13 +57,19 @@ function Convert-FileInfoToMigration $pluginParameter = @{ Migration = $Migration ; Operation = $_ } [Rivet.Operations.Operation[]]$operations = & { - Invoke-RivetPlugin -Session $Session ` - -Event ([Rivet.Events]::BeforeOperationLoad) ` - -Parameter $pluginParameter + if (-not $Migration.IsRivetMigration) + { + Invoke-RivetPlugin -Session $Session ` + -Event ([Rivet.Events]::BeforeOperationLoad) ` + -Parameter $pluginParameter + } $operationItem - Invoke-RivetPlugin -Session $Session ` - -Event ([Rivet.Events]::AfterOperationLoad) ` - -Parameter $pluginParameter + if (-not $Migration.IsRivetMigration) + { + Invoke-RivetPlugin -Session $Session ` + -Event ([Rivet.Events]::AfterOperationLoad) ` + -Parameter $pluginParameter + } } | Where-Object { $_ -is [Rivet.Operations.Operation] } | Repair-Operation @@ -94,7 +100,11 @@ function Convert-FileInfoToMigration Connect-Database -Session $Session -Name $dbName $m = [Rivet.Migration]::New($fileInfo.MigrationID, $fileInfo.MigrationName, $fileInfo.FullName, $dbName) - $m | Add-Member -Name 'IsRivetMigration' -MemberType NoteProperty -Value $fileInfo.IsRivetMigration + foreach ($noteProperty in ($fileInfo | Get-Member -MemberType NoteProperty)) + { + $propertyName = $noteProperty.Name + $m | Add-Member -Name $propertyName -MemberType NoteProperty -Value ($fileInfo.$propertyName) + } Write-Timing -Message ('Convert-FileInfoToMigration {0}' -f $m.FullName) @@ -146,9 +156,12 @@ Pop-Migration function not found. All migrations are required to have a Pop-Migr $afterMigrationLoadParameter = @{ Migration = $m } & { - Invoke-RivetPlugin -Session $Session ` - -Event ([Rivet.Events]::AfterMigrationLoad) ` - -Parameter $afterMigrationLoadParameter + if (-not $m.IsRivetMigration) + { + Invoke-RivetPlugin -Session $Session ` + -Event ([Rivet.Events]::AfterMigrationLoad) ` + -Parameter $afterMigrationLoadParameter + } } $m | Write-Output } diff --git a/Rivet/Functions/Get-MigrationFile.ps1 b/Rivet/Functions/Get-MigrationFile.ps1 index 28e563cc..d5350887 100644 --- a/Rivet/Functions/Get-MigrationFile.ps1 +++ b/Rivet/Functions/Get-MigrationFile.ps1 @@ -67,6 +67,7 @@ function Get-MigrationFile Write-Debug -Message $Path if( (Test-Path -Path $Path -PathType Container) ) { + Get-ChildItem -Path $Path -Filter $script:schemaFileName -ErrorAction Ignore return Get-ChildItem -Path $Path -Filter '*_*.ps1' } @@ -76,10 +77,12 @@ function Get-MigrationFile } } | ForEach-Object { + $isBaseline = $false if( $_.BaseName -eq 'schema' ) { $id = $script:schemaMigrationId # midnight on year 1, month 0, day 0. $name = $_.BaseName + $isBaseline = $true } elseif( $_.BaseName -notmatch '^(\d{14})_(.+)' ) { @@ -98,7 +101,8 @@ function Get-MigrationFile Add-Member -MemberType NoteProperty -Name 'MigrationID' -Value $id -PassThru | Add-Member -MemberType NoteProperty -Name 'MigrationName' -Value $name -PassThru | Add-Member -MemberType NoteProperty -Name 'DatabaseName' -Value $DatabaseName -PassThru | - Add-Member -MemberType NoteProperty -Name 'IsRivetMigration' -Value $isRivetMigration -PassThru + Add-Member -MemberType NoteProperty -Name 'IsRivetMigration' -Value $isRivetMigration -PassThru | + Add-Member -Membertype NoteProperty -Name 'IsBaselineMigration' -Value $isBaseline -PassThru } | Where-Object { if (-not ($PSBoundParameters.ContainsKey('Include'))) @@ -134,8 +138,8 @@ function Get-MigrationFile foreach( $pattern in $Exclude ) { $foundMatch = $migration.MigrationID -like $pattern -or ` - $migration.MigrationName -like $pattern -or ` - $migration.BaseName -like $pattern + $migration.MigrationName -like $pattern -or ` + $migration.BaseName -like $pattern if( $foundMatch ) { return $false @@ -150,10 +154,10 @@ function Get-MigrationFile return $true } - if ($_.IsRivetMigration) + if ($_.IsRivetMigration -and -not $_.IsBaselineMigration) { - $msg = "Migration '$($_.FullName)' has an invalid ID. IDs lower than $($script:firstMigrationId) " + - 'are reserved for Rivet''s internal use.' + $msg = "Migration '$($_.FullName)' has invalid ID ""$($_.MigrationID)"". IDs lower than $($script:firstMigrationId) " + + 'are reserved for Rivet''s internal use.' Write-Error $msg -ErrorAction Stop return $false } diff --git a/Rivet/Functions/Update-Database.ps1 b/Rivet/Functions/Update-Database.ps1 index 4d31e9b7..3bbd1161 100644 --- a/Rivet/Functions/Update-Database.ps1 +++ b/Rivet/Functions/Update-Database.ps1 @@ -108,6 +108,23 @@ function Update-Database return $howLongAgoMsg.ToString() } + function Get-AppliedMigration + { + [CmdletBinding()] + param( + ) + + $query = "if (object_id('${RivetMigrationsTableFullName}', 'U') is not null) " + + "select ID, Name, Who, AtUtc from ${RivetMigrationsTableFullName}" + $appliedMigrations = @{} + foreach( $migration in (Invoke-Query -Session $Session -Query $query) ) + { + $appliedMigrations[$migration.ID] = $migration + } + + return $appliedMigrations + } + if ($Redo) { $updateArgs = [hashtable]::New($PSBoundParameters) @@ -126,6 +143,7 @@ function Update-Database } $popping = ($PSCmdlet.ParameterSetName -like 'Pop*') + $pushing = -not $popping # We have to load all the migrations from files at the same time so that `Get-MigrationFile` can better track if # a migration with a specific name exists or not. @@ -140,110 +158,109 @@ function Update-Database { Connect-Database -Session $Session -Name $dbInfo.Name - $query = "if (object_id('${RivetMigrationsTableFullName}', 'U') is not null) " + - "select ID, Name, Who, AtUtc from ${RivetMigrationsTableFullName}" - $appliedMigrations = @{} - foreach( $migration in (Invoke-Query -Session $Session -Query $query) ) + $appliedMigrations = Get-AppliedMigration + + $numPopped = 0 + + $migrationFiles = + $migrationFilesByDb | Where-Object 'Name' -EQ $dbInfo.Name | Select-Object -ExpandProperty 'Group' + + if (-not $migrationFiles) { - $appliedMigrations[$migration.ID] = $migration + continue } - $numPopped = 0 - $migrations = - $migrationFilesByDb | - Where-Object { $_.Name -eq $dbInfo.Name } | - Select-Object -ExpandProperty Group | - Where-Object { - $appliedMigration = $appliedMigrations[$_.MigrationID] + $conn = $Session.Connection + foreach ($migrationFile in $migrationFiles) + { + if( $PSCmdlet.ParameterSetName -eq 'PopByCount' -and $numPopped -ge $Count ) + { + break + } - # Only need to parse/push if migration hasn't already been pushed. - if (-not $popping -or $_.IsRivetMigration) - { - if ($appliedMigration) - { - return $false - } - return $true - } + $appliedMigration = $appliedMigrations[$migrationFile.MigrationID] - if( $PSCmdlet.ParameterSetName -eq 'PopByCount' -and $numPopped -ge $Count ) + if ($pushing) + { + # Don't need to push if migration as already been applied. + if ($appliedMigration) { - return $false + continue } - $numPopped++ - # Don't need to pop if migration hasn't been applied. - if (-not $appliedMigration) + # Only apply baseline migration if non-Rivet migrations haven' been applied to the database. + if ($migrationFile.IsBaselineMigration -and ` + ($appliedMigrations.Values | Where-Object 'ID' -GE $script:firstMigrationId)) { - return $false + continue } + } + + # Don't need to pop if migration hasn't been applied. + if ($popping -and (-not $appliedMigration -or $migrationFile.IsRivetMigration)) + { + continue + } - $youngerThan = ((Get-Date).ToUniversalTime()) - (New-TimeSpan -Minutes 20) - if( $appliedMigration.Who -ne $who -or $appliedMigration.AtUtc -lt $youngerThan ) + $youngerThan = ((Get-Date).ToUniversalTime()) - (New-TimeSpan -Minutes 20) + if ($popping -and ($appliedMigration.Who -ne $who -or $appliedMigration.AtUtc -lt $youngerThan)) + { + $howLongAgo = ConvertTo-RelativeTime -DateTime ($appliedMigration.AtUtc.ToLocalTime()) + $conn = $Session.Connection + $migrationName = "$($appliedMigration.ID)_$($appliedMigration.Name)" + $confirmQuery = "Are you sure you want to pop migration ${migrationName} from database " + + "$($conn.Database) on $($conn.DataSource) applied by $($appliedMigration.Who) " + + "${howLongAgo}?" + $confirmCaption = "Pop Migration ${migrationName}?" + if( -not $Force -and -not $PSCmdlet.ShouldContinue( $confirmQuery, $confirmCaption ) ) { - $howLongAgo = ConvertTo-RelativeTime -DateTime ($appliedMigration.AtUtc.ToLocalTime()) - $conn = $Session.Connection - $confirmQuery = "Are you sure you want to pop migration $($_.FullName) from database " + - "$($conn.Database) on $($conn.DataSource) applied by $($appliedMigration.Who) " + - "${howLongAgo}?" - $confirmCaption = "Pop Migration {0}?" -f $_.FullName - if( -not $Force -and -not $PSCmdlet.ShouldContinue( $confirmQuery, $confirmCaption ) ) - { - return $false - } + break } - return $true - } | - Convert-FileInfoToMigration -Session $Session + } - if (-not $migrations) - { - continue - } + # Parse as close to actually running the migration code as possible. + $migration = $migrationFile | Convert-FileInfoToMigration -Session $Session - $conn = $Session.Connection - foreach( $migrationInfo in $migrations ) - { - $migrationInfo.DataSource = $conn.DataSource + $migration.DataSource = $conn.DataSource $trx = $Session.CurrentTransaction = $conn.BeginTransaction() $rollback = $true try { # Rivet's internal migrations should *always* be pushed. - if ($Pop -and -not $migrationInfo.IsRivetMigration) + if ($popping) { - $operations = $migrationInfo.PopOperations + $operations = $migration.PopOperations $action = 'Pop' $sprocName = 'RemoveMigration' } else { - $operations = $migrationInfo.PushOperations + $operations = $migration.PushOperations $action = 'Push' $sprocName = 'InsertMigration' } if (-not $operations.Count) { - Write-Error ('{0} migration''s {1}-Migration function is empty.' -f $migrationInfo.FullName,$action) + Write-Error ('{0} migration''s {1}-Migration function is empty.' -f $migration.FullName,$action) return } - $operations | Invoke-MigrationOperation -Session $Session -Migration $migrationInfo + $operations | Invoke-MigrationOperation -Session $Session -Migration $migration $query = "exec [rivet].[${sprocName}] @ID = @ID, @Name = @Name, @Who = @Who, @ComputerName = @ComputerName" $parameters = @{ - ID = [int64]$migrationInfo.ID; - Name = $migrationInfo.Name; + ID = [int64]$migration.ID; + Name = $migration.Name; Who = $who; ComputerName = $env:COMPUTERNAME; } Invoke-Query -Session $Session -Query $query -NonQuery -Parameter $parameters | Out-Null $target = '{0}.{1}' -f $conn.DataSource,$conn.Database - $operation = '{0} migration {1} {2}' -f $PSCmdlet.ParameterSetName,$migrationInfo.ID,$migrationInfo.Name + $operation = '{0} migration {1} {2}' -f $PSCmdlet.ParameterSetName,$migration.ID,$migration.Name if ($PSCmdlet.ShouldProcess($target, $operation)) { $trx.Commit() @@ -258,6 +275,11 @@ function Update-Database } finally { + if ($popping) + { + $numPopped++ + } + if ($rollback) { $trx.Rollback() @@ -265,6 +287,11 @@ function Update-Database $Session.CurrentTransaction = $null } + + if ($migration.IsBaselineMigration) + { + $appliedMigrations = Get-AppliedMigration + } } } } diff --git a/Test/Checkpoint-Migration.Tests.ps1 b/Test/Checkpoint-Migration.Tests.ps1 index f5cb5984..b01701ad 100644 --- a/Test/Checkpoint-Migration.Tests.ps1 +++ b/Test/Checkpoint-Migration.Tests.ps1 @@ -125,7 +125,7 @@ BeforeAll { Remove-RivetTestDatabase -Name $databaseName # Now, check that the schema.ps1 script is runnable - Invoke-RTRivet -Database $databaseName -ErrorAction Stop + Invoke-RTRivet -Push -Database $databaseName -ErrorAction Stop Invoke-RTRivet -Pop -Database $databaseName -ErrorAction Stop } } diff --git a/Test/Push-Migration.Tests.ps1 b/Test/Push-Migration.Tests.ps1 index a078fc82..815314aa 100644 --- a/Test/Push-Migration.Tests.ps1 +++ b/Test/Push-Migration.Tests.ps1 @@ -173,6 +173,8 @@ Describe 'Push-Migration' { '@ | Set-Content -Path $objectMadeWithRelativePathath $script:testStartedAt = Invoke-RivetTestQuery -Query 'select getutcdate()' -AsScalar + + $Global:Error.Clear() } AfterEach { diff --git a/Test/RivetTest/Functions/Clear-TestDatabase.ps1 b/Test/RivetTest/Functions/Clear-TestDatabase.ps1 index 9092c091..feb01821 100644 --- a/Test/RivetTest/Functions/Clear-TestDatabase.ps1 +++ b/Test/RivetTest/Functions/Clear-TestDatabase.ps1 @@ -5,9 +5,7 @@ function Clear-TestDatabase #> [CmdletBinding()] param( - [Parameter(Mandatory)] - [string] - $Name + [string] $Name = $RTDatabaseName ) Set-StrictMode -Version 'Latest' diff --git a/Test/RivetTest/Functions/Get-MigrationInfo.ps1 b/Test/RivetTest/Functions/Get-MigrationInfo.ps1 index 100f8e0f..fed74b47 100644 --- a/Test/RivetTest/Functions/Get-MigrationInfo.ps1 +++ b/Test/RivetTest/Functions/Get-MigrationInfo.ps1 @@ -8,13 +8,21 @@ function Get-MigrationInfo $Connection, - $DatabaseName + $DatabaseName, + + [switch] $Force ) - + Set-StrictMode -Version Latest + $whereClause = " where ID >= $($script:firstMigrationId)" + if ($Force) + { + $whereClause = '' + } + # Exclude Rivet's internal migrations. - $query = "select * from $($RTRivetSchemaName).Migrations where ID >= $($script:firstMigrationId)" + $query = "select * from $($RTRivetSchemaName).Migrations${whereClause}" if( $Name ) { $query = '{0} and name = ''{1}''' -f $query,$Name diff --git a/Test/RivetTest/Functions/New-Migration.ps1 b/Test/RivetTest/Functions/New-Migration.ps1 index d23f389a..ef841b28 100644 --- a/Test/RivetTest/Functions/New-Migration.ps1 +++ b/Test/RivetTest/Functions/New-Migration.ps1 @@ -1,13 +1,13 @@ function New-TestMigration { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName='NamedMigration')] param( [Parameter(Mandatory,ValueFromPipeline,Position=0)] # The migration contents to output. [String]$InputObject, - [Parameter(Mandatory)] + [Parameter(Mandatory, ParameterSetName='NamedMigration')] [Alias('Name')] # The name of the migration. [String]$Named, @@ -15,7 +15,10 @@ function New-TestMigration # The name of the database. [String]$DatabaseName = $RTDatabaseName, - [String]$ConfigFilePath = $RTConfigFilePath + [String]$ConfigFilePath = $RTConfigFilePath, + + [Parameter(Mandatory, ParameterSetName='SchemaPs1')] + [switch] $AsCheckpoint ) Set-StrictMode -Version 'Latest' @@ -27,18 +30,35 @@ function New-TestMigration New-Item -Path $migrationsRoot -ItemType 'Directory' -Force | Format-Table | Out-String | Write-Verbose } - do + if ($AsCheckpoint) + { + $migrationFileName = 'schema.ps1' + } + else { - $script:RTTimestamp++ - $migrationFileName = "${script:RTTimestamp}_*.ps1" - $migrationPath = Join-Path -Path $migrationsRoot -ChildPath $migrationFileName + do + { + $script:RTTimestamp++ + $migrationFileName = "${script:RTTimestamp}_*.ps1" + $migrationPath = Join-Path -Path $migrationsRoot -ChildPath $migrationFileName + } + while( (Test-Path -Path $migrationPath -PathType Leaf) ) + + $migrationFileName = "${script:RTTimestamp}_${Named}.ps1" } - while( (Test-Path -Path $migrationPath -PathType Leaf) ) - $migrationFileName = "${script:RTTimestamp}_${Named}.ps1" $migrationPath = Join-Path -Path $migrationsRoot -ChildPath $migrationFileName $InputObject | Set-Content -Path $migrationPath - Get-Item -Path $migrationPath + $migrationFile = Get-Item -Path $migrationPath + + if (-not $AsCheckpoint) + { + $migrationFile | + Add-Member -Name 'MigrationID' -MemberType NoteProperty -Value $script:RTTimestamp -PassThru | + Add-Member -Name 'MigrationName' -MemberType NoteProperty -Value $Named + } + + return $migrationFile } Set-Alias -Name 'GivenMigration' -Value 'New-TestMigration' diff --git a/Test/RivetTest/Functions/Remove-RivetTestDatabase.ps1 b/Test/RivetTest/Functions/Remove-RivetTestDatabase.ps1 index 18128563..36bdb8b0 100644 --- a/Test/RivetTest/Functions/Remove-RivetTestDatabase.ps1 +++ b/Test/RivetTest/Functions/Remove-RivetTestDatabase.ps1 @@ -6,13 +6,13 @@ function Remove-RivetTestDatabase # The name of the database to remove. $Name = $RTDatabaseName ) - + Set-StrictMode -Version Latest - + $query = @' if( exists( select name from sys.databases where Name = '{0}' ) ) begin - ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE + ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE DROP DATABASE [{0}] end diff --git a/Test/schema.ps1.Tests.ps1 b/Test/schema.ps1.Tests.ps1 new file mode 100644 index 00000000..f33dc632 --- /dev/null +++ b/Test/schema.ps1.Tests.ps1 @@ -0,0 +1,226 @@ + + +#Requires -Version 5.1 +Set-StrictMode -Version 'Latest' + +BeforeAll { + Set-StrictMode -Version 'Latest' + + & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) + + function GivenPlugins + { + function Global:StopBeforeOpLoad + { + [CmdletBinding()] + [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] + param( + $Operation, + $Migration + ) + throw 'stop before operation load!' + } + + function Global:StopAfterOpLoad + { + [CmdletBinding()] + [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] + param( + $Operation, + $Migration + ) + throw 'stop after operation load!' + } + + function Global:StopAfterMigrationLoad + { + [CmdletBinding()] + [Rivet.Plugin([Rivet.Events]::AfterMigrationLoad)] + param( + $Operation, + $Migration + ) + throw 'stop after migration load!' + } + } + + function ThenBaselineMigration + { + param( + [switch] $Not, + + [Parameter(Mandatory)] + [switch] $Applied + ) + + $rowsmigration = Get-MigrationInfo -Force + $rowsmigration | Should -Not -BeNullOrEmpty + + $migration = $rowsmigration | Where-Object 'ID' -eq 10000000000 + if ($Not) + { + $migration | Should -BeNullOrEmpty + } + else + { + $migration | Should -Not -BeNullOrEmpty + } + } +} + +Describe 'schemaPs1' { + BeforeEach { + Remove-RivetTestDatabase + Start-RivetTest + $Global:Error.Clear() + } + + AfterEach { + Remove-Item -Path 'function:StopBeforeOpLoad' -ErrorAction Ignore + Remove-Item -Path 'function:StopAfterOpLoad' -ErrorAction Ignore + Remove-Item -Path 'function:StopAFterMigrationLoad' -ErrorAction Ignore + Remove-RivetTestDatabase + } + + It 'is applied when pushing' { + { Invoke-RTRivet -Push } | Should -Not -Throw + ThenBaselineMigration -Not -Applied + + @" +function Push-Migration +{ + Add-Table 'SchemaPs1' { + int 'ID' + } +} + +function Pop-Migration +{ + Remove-Table 'SchemaPs1' +} +"@ | New-TestMigration -AsCheckpoint + + { Invoke-RTRivet -Push } | Should -Not -Throw + $Global:Error | Should -BeNullOrEmpty + ThenBaselineMigration -Applied + } + + It 'is never popped' { + @" +function Push-Migration +{ + Add-Table 'SchemaPs1' { + int 'ID' + } +} + +function Pop-Migration +{ + Remove-Table 'SchemaPs1' +} +"@ | New-TestMigration -AsCheckpoint + + { Invoke-RTRivet -Push } | Should -Not -Throw + { Invoke-RTRivet -Pop -All } | Should -Not -Throw + $Global:Error | Should -BeNullOrEmpty + ThenBaselineMigration -Applied + } + + It 'causes included migrations to not get pushed' { + $migration = @' +function Push-Migration +{ + throw 'i should not be run' +} + +function Pop-Migration +{ + throw 'i should not be run' +} +'@ | New-TestMigration -Named 'One' + + @" +function Push-Migration +{ + Add-Table 'SchemaPs1' { + int 'ID' + } + + Add-Row -SchemaName 'rivet' -TableName 'Migrations' -Column @{ + ID = '$($migration.MigrationID)'; + Name = '$($migration.Name)'; + Who = '$([Environment]::UserName)'; + ComputerName = '$([Environment]::MachineName)'; + AtUtc = '$([DateTime]::UtcNow)'; + } +} + +function Pop-Migration +{ + Remove-Table 'SchemaPs1' +} +"@ | New-TestMigration -AsCheckpoint + + { Invoke-RTRivet -Push } | Should -Not -Throw + $Global:Error | Should -BeNullOrEmpty + } + + It 'is immune to plug-ins' { + GivenPlugins + + @" + function Push-Migration + { + Add-Table 'NoPluginsPlease' { + int 'ID' + } + Remove-Table 'NoPluginsPlease' + } + + function Pop-Migration + { + Remove-Table 'NoPluginsPlease' + } +"@ | New-TestMigration -AsCheckpoint + + Invoke-RTRivet -Push + + $Global:Error | Should -BeNullOrEmpty + } + + It 'is only applied to an empty database' { + @" +function Push-Migration +{ + Add-Table 'SchemaPs1' { + int 'ID' + } +} + +function Pop-Migration +{ + Remove-Table 'SchemaPs1' +} +"@ | New-TestMigration -Named 'One' + + { Invoke-RTRivet -Push } | Should -Not -Throw + ThenBaselineMigration -Not -Applied + +@" +function Push-Migration +{ + Add-Table 'SchemaPs1' { + int 'ID' + } +} + +function Pop-Migration +{ + Remove-Table 'SchemaPs1' +} +"@ | New-TestMigration -AsCheckpoint + + { Invoke-RTRivet -Push } | Should -Not -Throw + ThenBaselineMigration -Not -Applied + } +} From c97e46d68d4a8902567ce75ede7416bc774b9c3c Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Wed, 17 Apr 2024 17:18:00 -0700 Subject: [PATCH 08/16] Fixed: Dropping a database fails if the database name has non alphanumeric characters in its name. --- CHANGELOG.md | 1 + Rivet/Functions/Invoke-Rivet.ps1 | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84b11485..e488acfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ omitted so we think this change should be OK. ### Fixed * Baseline schema in schema.ps1 doesn't get applied when pushing migrations. +* The `DropDatabase` command fails if the database name has non alphanumeric characters in its name. ### Removed diff --git a/Rivet/Functions/Invoke-Rivet.ps1 b/Rivet/Functions/Invoke-Rivet.ps1 index 4a046b2d..b32a530a 100644 --- a/Rivet/Functions/Invoke-Rivet.ps1 +++ b/Rivet/Functions/Invoke-Rivet.ps1 @@ -85,11 +85,11 @@ function Invoke-Rivet # Drops the database(s) for the current environment when given. User will be prompted for confirmation when # used. - [Parameter(ParameterSetName='DropDatabase')] + [Parameter(Mandatory, ParameterSetName='DropDatabase')] [switch] $DropDatabase, # Checkpoints the current state of the database so that it can be re-created. - [Parameter(ParameterSetName='Checkpoint')] + [Parameter(Mandatory, ParameterSetName='Checkpoint')] [switch] $Checkpoint ) @@ -153,7 +153,7 @@ Found no databases to migrate. This can be a few things: { foreach( $databaseItem in $databaseList ) { - $query = "drop database $($databaseItem.Name)" + $query = "drop database [$($databaseItem.Name)]" Invoke-Query -Session $session -Query $query } } From 80eefb0d05f274c48352e6a32d345e168f079239 Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Thu, 18 Apr 2024 06:39:52 -0700 Subject: [PATCH 09/16] Removing warnings about future required default constraint names from test output. --- Test/Add-DefaultConstraint.Tests.ps1 | 32 ++++--- Test/Add-Table.Tests.ps1 | 22 ++++- Test/Columns.Tests.ps1 | 126 +++++++++++++-------------- 3 files changed, 102 insertions(+), 78 deletions(-) diff --git a/Test/Add-DefaultConstraint.Tests.ps1 b/Test/Add-DefaultConstraint.Tests.ps1 index 5ee25a44..9d1acb56 100644 --- a/Test/Add-DefaultConstraint.Tests.ps1 +++ b/Test/Add-DefaultConstraint.Tests.ps1 @@ -21,8 +21,10 @@ Describe 'Add-DefaultConstraint' { Int 'Default Constraint Me' -NotNull } - Add-DefaultConstraint -TableName 'AddDefaultConstraint' -ColumnName 'Default Constraint Me' -Expression 101 - + Add-DefaultConstraint -TableName 'AddDefaultConstraint' ` + -ColumnName 'Default Constraint Me' ` + -Expression 101 ` + -Name 'DF_AddDefaultConstraint_Default Constraint Me' } function Pop-Migration() @@ -32,8 +34,7 @@ Describe 'Add-DefaultConstraint' { '@ | New-TestMigration -Name 'AddDefaultConstraint' Invoke-RTRivet -Push 'AddDefaultConstraint' - Assert-DefaultConstraint -TableName 'AddDefaultConstraint' -ColumnName 'Default Constraint Me' - + Assert-DefaultConstraint -Name 'DF_AddDefaultConstraint_Default Constraint Me' } It 'should add default constraint with values' { @@ -44,7 +45,11 @@ Describe 'Add-DefaultConstraint' { Int 'DefaultConstraintMe' -NotNull } - Add-DefaultConstraint -TableName 'AddDefaultConstraint' -ColumnName 'DefaultConstraintMe' -Expression 101 -WithValues + Add-DefaultConstraint -TableName 'AddDefaultConstraint' ` + -ColumnName 'DefaultConstraintMe' ` + -Expression 101 ` + -WithValues ` + -Name 'DF_AddDefaultConstraint_DefaultConstraintMe' } function Pop-Migration() @@ -54,7 +59,7 @@ Describe 'Add-DefaultConstraint' { '@ | New-TestMigration -Name 'AddDefaultConstraintWithValues' Invoke-RTRivet -Push 'AddDefaultConstraintWithValues' - Assert-DefaultConstraint -TableName 'AddDefaultConstraint' -ColumnName 'DefaultConstraintMe' + Assert-DefaultConstraint -Name 'DF_AddDefaultConstraint_DefaultConstraintMe' $Global:Error.Count | Should -Be 0 } @@ -67,7 +72,10 @@ Describe 'Add-DefaultConstraint' { Int 'DefaultConstraintMe' -NotNull } - Add-DefaultConstraint -TableName 'Add-DefaultConstraint' -ColumnName 'DefaultConstraintMe' -Expression 101 + Add-DefaultConstraint -TableName 'Add-DefaultConstraint' ` + -ColumnName 'DefaultConstraintMe' ` + -Expression 101 ` + -Name 'DF_Add-DefaultConstraint_DefaultConstraintMe' } @@ -78,7 +86,7 @@ Describe 'Add-DefaultConstraint' { '@ | New-TestMigration -Name 'AddDefaultConstraintQuotesName' Invoke-RTRivet -Push 'AddDefaultConstraintQuotesName' - Assert-DefaultConstraint -TableName 'Add-DefaultConstraint' -ColumnName 'DefaultConstraintMe' + Assert-DefaultConstraint -Name 'DF_Add-DefaultConstraint_DefaultConstraintMe' } @@ -90,7 +98,10 @@ Describe 'Add-DefaultConstraint' { Int 'DefaultConstraintMe' -NotNull } - Add-DefaultConstraint 'AddDefaultConstraint' 'DefaultConstraintMe' 101 + Add-DefaultConstraint 'AddDefaultConstraint' ` + 'DefaultConstraintMe' ` + 101 ` + -Name 'DF_AddDefaultConstraint_DefaultConstraintMe' } @@ -101,8 +112,7 @@ Describe 'Add-DefaultConstraint' { '@ | New-TestMigration -Name 'AddDefaultConstraintOptionalParameterNames' Invoke-RTRivet -Push 'AddDefaultConstraintOptionalParameterNames' - Assert-DefaultConstraint -TableName 'AddDefaultConstraint' -ColumnName 'DefaultConstraintMe' - + Assert-DefaultConstraint -Name 'DF_AddDefaultConstraint_DefaultConstraintMe' } It 'should use the user''s constraint name' { diff --git a/Test/Add-Table.Tests.ps1 b/Test/Add-Table.Tests.ps1 index 52a6c571..3c7e1dfc 100644 --- a/Test/Add-Table.Tests.ps1 +++ b/Test/Add-Table.Tests.ps1 @@ -23,7 +23,12 @@ Describe 'Add-Table' { function Push-Migration() { Add-Table -Name 'AddTable' -Description 'Testing Add-Table migration' -Column { - VarChar 'varchar' -Max -NotNull -Default "'default'" -Description 'varchar(max) constraint DF_AddTable_varchar default default' + VarChar 'varchar' ` + -Max ` + -NotNull ` + -Default "'default'" ` + -Description 'varchar(max) constraint DF_AddTable_varchar default default' ` + -DefaultConstraintName 'DF_AddTable_varchar' BigInt 'id' -Identity } -Option 'data_compression = none' @@ -39,7 +44,11 @@ Describe 'Add-Table' { Invoke-RTRivet -Push 'CreateTable' Assert-Table 'AddTable' -Description 'Testing Add-Table migration' - Assert-Column -Name 'varchar' 'varchar' -NotNull -Description 'varchar(max) constraint DF_AddTable_varchar default default' -TableName 'AddTable' + Assert-Column -Name 'varchar' ` + 'varchar' ` + -NotNull ` + -Description 'varchar(max) constraint DF_AddTable_varchar default default' ` + -TableName 'AddTable' Assert-Column -Name 'id' 'bigint' -NotNull -Seed 1 -Increment 1 -TableName 'AddTable' # Sql 2012 feature @@ -140,7 +149,12 @@ Describe 'Add-Table' { function Push-Migration() { Add-Table 'AddTableWithOption' -Description 'Testing Add-Table migration' -Column { - VarChar 'varchar' -Max -NotNull -Default "'default'" -Description 'varchar(max) constraint DF_AddTable_varchar default default' + VarChar 'varchar' ` + -Max ` + -NotNull ` + -Default "'default'" ` + -Description 'varchar(max) constraint DF_AddTable_varchar default default' ` + -DefaultConstraintName 'DF_AddTableWithOption_varchar' BigInt 'id' -Identity } -Option 'data_compression = page' } @@ -200,7 +214,7 @@ function Pop-Migration Remove-Table 'Default' } '@ - WhenMigrating 'CustomDefaultConstraint' + WhenMigrating -Push 'CustomDefaultConstraint' ThenDefaultConstraint 'DF_my_custom_constraint_name' -Is '0' } } diff --git a/Test/Columns.Tests.ps1 b/Test/Columns.Tests.ps1 index a19bae13..30c1aaf8 100644 --- a/Test/Columns.Tests.ps1 +++ b/Test/Columns.Tests.ps1 @@ -146,36 +146,36 @@ N' } Update-Table -Name 'AddColumnDefaultsNotNull' -AddColumn { - VarChar 'varchar' -Size 20 -NotNull -Default "'varchar'" -Description 'varchar(20) not null' - VarChar 'varcharmax' -Max -NotNull -Default "'varcharmax'" -Description 'varchar(max) not null' - Char 'char' -Size 10 -NotNull -Default "'char'" -Description 'char(10) not null' - NChar 'nchar' -Size 35 -NotNull -Default "'nchar'" -Description 'nchar(35) not null' - NVarChar 'nvarchar' -Size 30 -NotNull -Default "'nvarchar'" -Description 'nvarchar(30) not null' - NVarChar 'nvarcharmax' -Max -NotNull -Default "'nvarcharmax'" -Description 'nvarchar(max) not null' - Binary 'binary' -Size 40 -NotNull -Default 1 -Description 'binary(40) not null' - VarBinary 'varbinary' -Size 45 -NotNull -Default 2 -Description 'varbinary(45) not null' - VarBinary 'varbinarymax' -Max -NotNull -Default 3 -Description 'varbinary(max) not null' - BigInt 'bigint' -NotNull -Default ([int64]::MaxValue) -Description 'bigint not null' - Int 'int' -NotNull -Default ([int]::MaxValue) -Description 'int not null' - SmallInt 'smallint' -NotNull -Default ([int16]::MaxValue) -Description 'smallint not null' - TinyInt 'tinyint' -NotNull -Default ([byte]::MaxValue) -Description 'tinyint not null' - Decimal 'decimal' -Precision 4 -NotNull -Default '3.33' -Description 'decimal(4) not null' - Decimal 'decimalwithscale' -Precision 5 -Scale 5 -NotNull -Default '4.44' -Description 'decimal(5,5) not null' - Bit 'bit' -NotNull -Default '1' -Description 'bit not null' - Money 'money' -NotNull -Default '6.66' -Description 'money not null' - SmallMoney 'smallmoney' -NotNull -Default '7.77' -Description 'smallmoney not null' - Float 'float' -NotNull -Default '8.88' -Description 'float not null' - Float 'floatwithprecision' -Precision 53 -NotNull -Default '9.99' -Description 'float(53) not null' - Real 'real' -NotNull -Default '10.10' -Description 'real not null' - Date 'date' -NotNull -Default 'getdate()' -Description 'date not null' - DateTime2 'datetime2' -NotNull -Default 'getdate()' -Description 'datetime2 not null' - DateTimeOffset 'datetimeoffset' -NotNull -Default 'getdate()' -Description 'datetimeoffset not null' - SmallDateTime 'smalldatetime' -NotNull -Default 'getdate()' -Description 'smalldatetime not null' - Time 'time' -NotNull -Default 'getdate()' -Description 'time not null' - UniqueIdentifier 'uniqueidentifier' -NotNull -Default 'newid()' -Description 'uniqueidentifier not null' - Xml 'xml' -XmlSchemaCollection 'EmptyXsd' -NotNull -Default "''" -Description 'xml not null' - SqlVariant 'sql_variant' -NotNull -Default "'sql_variant'" -Description 'sql_variant not null' - HierarchyID 'hierarchyid' -NotNull -Default '0x11' -Description 'hierarchyid not null' + VarChar 'varchar' -Size 20 -NotNull -Default "'varchar'" -Description 'varchar(20) not null' -DefaultConstraintName 'DF_One' + VarChar 'varcharmax' -Max -NotNull -Default "'varcharmax'" -Description 'varchar(max) not null' -DefaultConstraintName 'DF_Two' + Char 'char' -Size 10 -NotNull -Default "'char'" -Description 'char(10) not null' -DefaultConstraintName 'DF_Three' + NChar 'nchar' -Size 35 -NotNull -Default "'nchar'" -Description 'nchar(35) not null' -DefaultConstraintName 'DF_Four' + NVarChar 'nvarchar' -Size 30 -NotNull -Default "'nvarchar'" -Description 'nvarchar(30) not null' -DefaultConstraintName 'DF_Five' + NVarChar 'nvarcharmax' -Max -NotNull -Default "'nvarcharmax'" -Description 'nvarchar(max) not null' -DefaultConstraintName 'DF_Six' + Binary 'binary' -Size 40 -NotNull -Default 1 -Description 'binary(40) not null' -DefaultConstraintName 'DF_Seven' + VarBinary 'varbinary' -Size 45 -NotNull -Default 2 -Description 'varbinary(45) not null' -DefaultConstraintName 'DF_Eight' + VarBinary 'varbinarymax' -Max -NotNull -Default 3 -Description 'varbinary(max) not null' -DefaultConstraintName 'DF_Nine' + BigInt 'bigint' -NotNull -Default ([int64]::MaxValue) -Description 'bigint not null' -DefaultConstraintName 'DF_Ten' + Int 'int' -NotNull -Default ([int]::MaxValue) -Description 'int not null' -DefaultConstraintName 'DF_Eleven' + SmallInt 'smallint' -NotNull -Default ([int16]::MaxValue) -Description 'smallint not null' -DefaultConstraintName 'DF_Twelve' + TinyInt 'tinyint' -NotNull -Default ([byte]::MaxValue) -Description 'tinyint not null' -DefaultConstraintName 'DF_Thirteen' + Decimal 'decimal' -Precision 4 -NotNull -Default '3.33' -Description 'decimal(4) not null' -DefaultConstraintName 'DF_Fourteen' + Decimal 'decimalwithscale' -Precision 5 -Scale 5 -NotNull -Default '4.44' -Description 'decimal(5,5) not null' -DefaultConstraintName 'DF_Fifteen' + Bit 'bit' -NotNull -Default '1' -Description 'bit not null' -DefaultConstraintName 'DF_Sixteen' + Money 'money' -NotNull -Default '6.66' -Description 'money not null' -DefaultConstraintName 'DF_Seventeen' + SmallMoney 'smallmoney' -NotNull -Default '7.77' -Description 'smallmoney not null' -DefaultConstraintName 'DF_Eighteen' + Float 'float' -NotNull -Default '8.88' -Description 'float not null' -DefaultConstraintName 'DF_Nineteen' + Float 'floatwithprecision' -Precision 53 -NotNull -Default '9.99' -Description 'float(53) not null' -DefaultConstraintName 'DF_Twenty' + Real 'real' -NotNull -Default '10.10' -Description 'real not null' -DefaultConstraintName 'DF_TwentyOne' + Date 'date' -NotNull -Default 'getdate()' -Description 'date not null' -DefaultConstraintName 'DF_TwentyTwo' + DateTime2 'datetime2' -NotNull -Default 'getdate()' -Description 'datetime2 not null' -DefaultConstraintName 'DF_TwentyThree' + DateTimeOffset 'datetimeoffset' -NotNull -Default 'getdate()' -Description 'datetimeoffset not null' -DefaultConstraintName 'DF_TwentyFour' + SmallDateTime 'smalldatetime' -NotNull -Default 'getdate()' -Description 'smalldatetime not null' -DefaultConstraintName 'DF_TwentyFive' + Time 'time' -NotNull -Default 'getdate()' -Description 'time not null' -DefaultConstraintName 'DF_TwentySix' + UniqueIdentifier 'uniqueidentifier' -NotNull -Default 'newid()' -Description 'uniqueidentifier not null' -DefaultConstraintName 'DF_TwentySeven' + Xml 'xml' -XmlSchemaCollection 'EmptyXsd' -NotNull -Default "''" -Description 'xml not null' -DefaultConstraintName 'DF_TwentyEight' + SqlVariant 'sql_variant' -NotNull -Default "'sql_variant'" -Description 'sql_variant not null' -DefaultConstraintName 'DF_TwentyNine' + HierarchyID 'hierarchyid' -NotNull -Default '0x11' -Description 'hierarchyid not null' -DefaultConstraintName 'DF_Thirty' } } @@ -192,36 +192,36 @@ function Pop-Migration() (Test-Table -Name 'AddColumnDefaultsNotNull') | Should -BeTrue $commonArgs = @{ TableName = 'AddColumnDefaultsNotNull'; NotNull = $true; } - Assert-Column -Name 'varchar' 'varchar' -Size 20 -Default "'varchar'" -Description 'varchar(20) not null' @commonArgs - Assert-Column -Name 'varcharmax' 'varchar' -Max -Default "'varcharmax'" -Description 'varchar(max) not null' @commonArgs - Assert-Column -Name 'char' 'char' -Size 10 -Default "'char'" -Description 'char(10) not null' @commonArgs - Assert-Column -Name 'nvarchar' 'nvarchar' -Size 30 -Default "'nvarchar'" -Description 'nvarchar(30) not null' @commonArgs - Assert-Column -Name 'nvarcharmax' 'nvarchar' -Max -Default "'nvarcharmax'" -Description 'nvarchar(max) not null' @commonArgs - Assert-Column -Name 'nchar' 'nchar' -Size 35 -Default "'nchar'" -Description 'nchar(35) not null' @commonArgs - Assert-Column -Name 'binary' 'binary' -Size 40 -Default 1 -Description 'binary(40) not null' @commonArgs - Assert-Column -Name 'varbinary' 'varbinary' -Size 45 -Default 2 -Description 'varbinary(45) not null' @commonArgs - Assert-Column -Name 'varbinarymax' 'varbinary' -Max -Default 3 -Description 'varbinary(max) not null' @commonArgs - Assert-Column -Name 'bigint' 'bigint' -Default ([int64]::MaxValue) -Description 'bigint not null' @commonArgs - Assert-Column -Name 'int' 'int' -Default ([int]::MaxValue) -Description 'int not null' @commonArgs - Assert-Column -Name 'smallint' 'smallint' -Default ([int16]::MaxValue) -Description 'smallint not null' @commonArgs - Assert-Column -Name 'tinyint' 'tinyint' -Default ([byte]::MaxValue) -Description 'tinyint not null' @commonArgs - Assert-Column -Name 'decimal' 'decimal' -Precision 4 -Default '3.33' -Description 'decimal(4) not null' @commonArgs - Assert-Column -Name 'decimalwithscale' 'decimal' -Precision 5 -Scale 5 -Default '4.44' -Description 'decimal(5,5) not null' @commonArgs - Assert-Column -Name 'bit' 'bit' -Default '1' -Description 'bit not null' @commonArgs - Assert-Column -Name 'money' 'money' -Default '6.66' -Description 'money not null' @commonArgs - Assert-Column -Name 'smallmoney' 'smallmoney' -Default '7.77' -Description 'smallmoney not null' @commonArgs - Assert-Column -Name 'float' 'float' -Default '8.88' -Description 'float not null' @commonArgs - Assert-Column -Name 'floatwithprecision' 'float' -Precision 53 -Default '9.99' -Description 'float(53) not null' @commonArgs - Assert-Column -Name 'real' 'real' -Default '10.10' -Description 'real not null' @commonArgs - Assert-Column -Name 'date' 'date' -Default 'getdate()' -Description 'date not null' @commonArgs - Assert-Column -Name 'datetime2' 'datetime2' -Default 'getdate()' -Description 'datetime2 not null' @commonArgs - Assert-Column -Name 'datetimeoffset' 'datetimeoffset' -Default 'getdate()' -Description 'datetimeoffset not null' @commonArgs - Assert-Column -Name 'smalldatetime' 'smalldatetime' -Default 'getdate()' -Description 'smalldatetime not null' @commonArgs - Assert-Column -Name 'time' 'time' -Default 'getdate()' -Description 'time not null' @commonArgs - Assert-Column -Name 'xml' 'xml' -Default "''" -Description 'xml not null' @commonArgs - Assert-Column -Name 'sql_variant' 'sql_variant' -Default "'sql_variant'" -Description 'sql_variant not null' @commonArgs - Assert-Column -Name 'uniqueidentifier' 'uniqueidentifier' -Default 'newid()' -Description 'uniqueidentifier not null' @commonArgs - Assert-Column -Name 'hierarchyid' 'hierarchyid' -Default '0x11' -Description 'hierarchyid not null' @commonArgs + Assert-Column -Name 'varchar' 'varchar' -Size 20 -Default "'varchar'" -Description 'varchar(20) not null' -DefaultConstraintName 'DF_One' @commonArgs + Assert-Column -Name 'varcharmax' 'varchar' -Max -Default "'varcharmax'" -Description 'varchar(max) not null' -DefaultConstraintName 'DF_Two' @commonArgs + Assert-Column -Name 'char' 'char' -Size 10 -Default "'char'" -Description 'char(10) not null' -DefaultConstraintName 'DF_Three' @commonArgs + Assert-Column -Name 'nchar' 'nchar' -Size 35 -Default "'nchar'" -Description 'nchar(35) not null' -DefaultConstraintName 'DF_Four' @commonArgs + Assert-Column -Name 'nvarchar' 'nvarchar' -Size 30 -Default "'nvarchar'" -Description 'nvarchar(30) not null' -DefaultConstraintName 'DF_Five' @commonArgs + Assert-Column -Name 'nvarcharmax' 'nvarchar' -Max -Default "'nvarcharmax'" -Description 'nvarchar(max) not null' -DefaultConstraintName 'DF_Six' @commonArgs + Assert-Column -Name 'binary' 'binary' -Size 40 -Default 1 -Description 'binary(40) not null' -DefaultConstraintName 'DF_Seven' @commonArgs + Assert-Column -Name 'varbinary' 'varbinary' -Size 45 -Default 2 -Description 'varbinary(45) not null' -DefaultConstraintName 'DF_Eight' @commonArgs + Assert-Column -Name 'varbinarymax' 'varbinary' -Max -Default 3 -Description 'varbinary(max) not null' -DefaultConstraintName 'DF_Nine' @commonArgs + Assert-Column -Name 'bigint' 'bigint' -Default ([int64]::MaxValue) -Description 'bigint not null' -DefaultConstraintName 'DF_Ten' @commonArgs + Assert-Column -Name 'int' 'int' -Default ([int]::MaxValue) -Description 'int not null' -DefaultConstraintName 'DF_Eleven' @commonArgs + Assert-Column -Name 'smallint' 'smallint' -Default ([int16]::MaxValue) -Description 'smallint not null' -DefaultConstraintName 'DF_Twelve' @commonArgs + Assert-Column -Name 'tinyint' 'tinyint' -Default ([byte]::MaxValue) -Description 'tinyint not null' -DefaultConstraintName 'DF_Thirteen' @commonArgs + Assert-Column -Name 'decimal' 'decimal' -Precision 4 -Default '3.33' -Description 'decimal(4) not null' -DefaultConstraintName 'DF_Fourteen' @commonArgs + Assert-Column -Name 'decimalwithscale' 'decimal' -Precision 5 -Scale 5 -Default '4.44' -Description 'decimal(5,5) not null' -DefaultConstraintName 'DF_Fifteen' @commonArgs + Assert-Column -Name 'bit' 'bit' -Default '1' -Description 'bit not null' -DefaultConstraintName 'DF_Sixteen' @commonArgs + Assert-Column -Name 'money' 'money' -Default '6.66' -Description 'money not null' -DefaultConstraintName 'DF_Seventeen' @commonArgs + Assert-Column -Name 'smallmoney' 'smallmoney' -Default '7.77' -Description 'smallmoney not null' -DefaultConstraintName 'DF_Eighteen' @commonArgs + Assert-Column -Name 'float' 'float' -Default '8.88' -Description 'float not null' -DefaultConstraintName 'DF_Nineteen' @commonArgs + Assert-Column -Name 'floatwithprecision' 'float' -Precision 53 -Default '9.99' -Description 'float(53) not null' -DefaultConstraintName 'DF_Twenty' @commonArgs + Assert-Column -Name 'real' 'real' -Default '10.10' -Description 'real not null' -DefaultConstraintName 'DF_TwentyOne' @commonArgs + Assert-Column -Name 'date' 'date' -Default 'getdate()' -Description 'date not null' -DefaultConstraintName 'DF_TwentyTwo' @commonArgs + Assert-Column -Name 'datetime2' 'datetime2' -Default 'getdate()' -Description 'datetime2 not null' -DefaultConstraintName 'DF_TwentyThree' @commonArgs + Assert-Column -Name 'datetimeoffset' 'datetimeoffset' -Default 'getdate()' -Description 'datetimeoffset not null' -DefaultConstraintName 'DF_TwentyFour' @commonArgs + Assert-Column -Name 'smalldatetime' 'smalldatetime' -Default 'getdate()' -Description 'smalldatetime not null' -DefaultConstraintName 'DF_TwentyFive' @commonArgs + Assert-Column -Name 'time' 'time' -Default 'getdate()' -Description 'time not null' -DefaultConstraintName 'DF_TwentySix' @commonArgs + Assert-Column -Name 'uniqueidentifier' 'uniqueidentifier' -Default 'newid()' -Description 'uniqueidentifier not null' -DefaultConstraintName 'DF_TwentySeven' @commonArgs + Assert-Column -Name 'xml' 'xml' -Default "''" -Description 'xml not null' -DefaultConstraintName 'DF_TwentyEight' @commonArgs + Assert-Column -Name 'sql_variant' 'sql_variant' -Default "'sql_variant'" -Description 'sql_variant not null' -DefaultConstraintName 'DF_TwentyNine' @commonArgs + Assert-Column -Name 'hierarchyid' 'hierarchyid' -Default '0x11' -Description 'hierarchyid not null' -DefaultConstraintName 'DF_Thirty' @commonArgs } It 'should create identities' { @@ -575,7 +575,7 @@ function Push-Migration { Add-Table 'CustomColumns' { New-Column 'ID' 'int' -Identity -Seed 101 -Increment 11 -NotForReplication - New-Column 'one' 'varchar' -Collation 'Korean_100_CS_AS_KS_WS_SC' -Default '''fubar''' -Description 'snafu' + New-Column 'one' 'varchar' -Collation 'Korean_100_CS_AS_KS_WS_SC' -Default '''fubar''' -Description 'snafu' -DefaultConstraintName 'DF_CustomColumns_one' New-Column 'two' 'varchar' -Size 50 -NotNull New-Column 'three' 'varchar' -Size 51 -Sparse New-Column 'four' 'decimal' -Precision 4 -Scale 2 -NotNull @@ -604,10 +604,10 @@ function Pop-Migration Remove-Table 'CustomColumns' } '@ - WhenMigrating 'Columns' + WhenMigrating -Push 'Columns' Assert-Table 'CustomColumns' Assert-Column -TableName 'CustomColumns' -Name 'ID' -DataType 'int' -NotNull -Seed 101 -Increment 11 -NotForReplication - Assert-Column -TableName 'CustomColumns' -Name 'one' -DataType 'varchar' -Size 1 -Collation 'Korean_100_CS_AS_KS_WS_SC' -Default 'fubar' -Description 'snafu' + Assert-Column -TableName 'CustomColumns' -Name 'one' -DataType 'varchar' -Size 1 -Collation 'Korean_100_CS_AS_KS_WS_SC' -Default 'fubar' -Description 'snafu' -DefaultConstraintName 'DF_CustomColumns_one' Assert-Column -TableName 'CustomColumns' -Name 'two' -DataType 'varchar' -Size 50 -NotNull Assert-Column -TableName 'CustomColumns' -Name 'three' -DataType 'varchar' -Size 51 -Sparse Assert-Column -TableName 'CustomColumns' -Name 'four' -DataType 'decimal' -Precision 4 -Scale 2 -NotNull From f21fc533f6d6761e75ed0b0bcc3cbe80513dc41f Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Thu, 18 Apr 2024 06:41:32 -0700 Subject: [PATCH 10/16] Checkpoint-Migration is a private function so not required to meet documentation standards. --- Test/Functions.Tests.ps1 | 47 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/Test/Functions.Tests.ps1 b/Test/Functions.Tests.ps1 index 069ce947..f4f5d6d7 100644 --- a/Test/Functions.Tests.ps1 +++ b/Test/Functions.Tests.ps1 @@ -11,29 +11,30 @@ BeforeAll { Describe 'Rivet' { It 'exports all functions' { $privateFunctions = @{ - 'Connect-Database' = $true; - 'Disconnect-Database' = $true; - 'Enable-ForeignKey' = $true; #OBSOLETE - 'Disable-ForeignKey' = $true; #OBSOLETE - 'Export-Row' = $true; - 'Get-MigrationFile' = $true; - 'Convert-FileInfoToMigration' = $true; - 'Get-MigrationScript' = $true; - 'Import-Rivet' = $true; - 'Invoke-Query' = $true; - 'Invoke-MigrationOperation' = $true; - 'New-ConstraintName' = $true; - 'New-TestMigration' = $true; - 'New-MigrationObject' = $true; - 'Repair-Operation' = $true; - 'Split-SqlBatchQuery' = $true; - 'Test-Migration' = $true; - 'Test-Schema' = $true; - 'Test-Table' = $true; - 'Update-Database' = $true; - 'Use-CallerPreference' = $true; - 'Write-RivetError' = $true; - } + 'Checkpoint-Migration' = $true; + 'Connect-Database' = $true; + 'Disconnect-Database' = $true; + 'Enable-ForeignKey' = $true; #OBSOLETE + 'Disable-ForeignKey' = $true; #OBSOLETE + 'Export-Row' = $true; + 'Get-MigrationFile' = $true; + 'Convert-FileInfoToMigration' = $true; + 'Get-MigrationScript' = $true; + 'Import-Rivet' = $true; + 'Invoke-Query' = $true; + 'Invoke-MigrationOperation' = $true; + 'New-ConstraintName' = $true; + 'New-TestMigration' = $true; + 'New-MigrationObject' = $true; + 'Repair-Operation' = $true; + 'Split-SqlBatchQuery' = $true; + 'Test-Migration' = $true; + 'Test-Schema' = $true; + 'Test-Table' = $true; + 'Update-Database' = $true; + 'Use-CallerPreference' = $true; + 'Write-RivetError' = $true; + } $private = & { From 6895fa2e518cb17029dd19e1be2b6e19cdfea675 Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Thu, 18 Apr 2024 06:44:24 -0700 Subject: [PATCH 11/16] Rivet test framework and patterns use global variables and state too much and makes the tests brittle. Refactoring tests that are currently failing on the build server to no longer use global state. --- Test/Get-Migration.Tests.ps1 | 1322 ++++++++--------- Test/Import-RivetPlugin.Tests.ps1 | 2 +- Test/Invoke-Rivet.Tests.ps1 | 483 +++--- Test/Pop-Migration.Tests.ps1 | 462 +++--- Test/Remove-DataType.Tests.ps1 | 64 +- Test/Remove-Synonym.Tests.ps1 | 41 +- Test/Remove-Table.Tests.ps1 | 133 +- Test/RivetTest/Functions/Assert-Column.ps1 | 70 +- .../Functions/Assert-DefaultConstraint.ps1 | 14 +- Test/RivetTest/Functions/Assert-Error.ps1 | 21 + Test/RivetTest/Functions/Assert-Schema.ps1 | 7 +- Test/RivetTest/Functions/Assert-Synonym.ps1 | 15 +- Test/RivetTest/Functions/Assert-Table.ps1 | 6 +- Test/RivetTest/Functions/Get-ActivityInfo.ps1 | 15 +- Test/RivetTest/Functions/Get-Column.ps1 | 35 +- .../Functions/Get-DefaultConstraint.ps1 | 13 +- .../Functions/Get-MigrationScript.ps1 | 5 +- Test/RivetTest/Functions/Get-Schema.ps1 | 15 +- Test/RivetTest/Functions/Get-Synonym.ps1 | 20 +- Test/RivetTest/Functions/Get-Table.ps1 | 21 +- .../RivetTest/Functions/Measure-Migration.ps1 | 7 +- .../Functions/Measure-MigrationScript.ps1 | 5 +- Test/RivetTest/Functions/New-File.ps1 | 41 +- Test/RivetTest/Functions/New-Migration.ps1 | 10 +- .../RivetTest/Functions/New-RivetJsonFile.ps1 | 93 ++ .../Functions/Test-DatabaseObject.ps1 | 79 +- Test/RivetTest/Functions/Test-Table.ps1 | 14 +- Test/RivetTest/Import-RivetTest.ps1 | 8 +- Test/RivetTest/RivetTest.psd1 | 5 + Test/RivetTest/RivetTest.psm1 | 1 + Test/Update-Database.Tests.ps1 | 118 +- Test/Update-Table.Tests.ps1 | 437 +++--- Test/xml.Tests.ps1 | 214 +-- 33 files changed, 2147 insertions(+), 1649 deletions(-) create mode 100644 Test/RivetTest/Functions/Assert-Error.ps1 create mode 100644 Test/RivetTest/Functions/New-RivetJsonFile.ps1 diff --git a/Test/Get-Migration.Tests.ps1 b/Test/Get-Migration.Tests.ps1 index e32b8b69..f39a8080 100644 --- a/Test/Get-Migration.Tests.ps1 +++ b/Test/Get-Migration.Tests.ps1 @@ -6,10 +6,15 @@ BeforeAll { Set-StrictMode -Version 'Latest' & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) + Remove-Item -Path 'alias:GivenMigration' $script:pluginModuleName = 'GetMigrationPlugins' $script:pluginModulePath = '{0}\{0}.psm1' -f $script:pluginModuleName $script:migrations = $null + $script:rivetJsonPath = $null + $script:testDir = $null + $script:testNum = 0 + $script:dbName = 'Get-Migration' $script:noOpMigration = @' function Push-Migration @@ -31,7 +36,7 @@ BeforeAll { ) Set-StrictMode -Version 'Latest' - $Global:Error.Count | Should -Be 0 + $Global:Error | Should -BeNullOrEmpty $m | Should -Not -BeNullOrEmpty $m | Should -BeOfType ([Rivet.Migration]) $m.Name | Should -Be 'ShouldGetMigrationsUsingCurrentRivetJsonFile' @@ -47,19 +52,28 @@ BeforeAll { $popOp.Name | Should -Be 'ShouldGetMigrationsUsingCurrentRivetJsonFile' } - function Init + function GivenMigration { param( - [hashtable] $StartArgument = @{} + [Parameter(Mandatory, Position=0)] + [String] $Named, + + [Parameter(Mandatory, Position=1)] + [String] $WithContent ) - $Global:Error.Clear() - Start-RivetTest @StartArgument - $script:migrations = @() + + $WithContent | + New-TestMigration -Named $Named -DatabaseName $script:dbName -ConfigFilePath $script:rivetJsonPath } - function Reset + function GivenPlugin { - Stop-RivetTest + [CmdletBinding()] + param( + [String] $WithContent + ) + + GivenFile $script:pluginModulePath -In $script:testDir $WithContent } function WhenGettingMigrations @@ -68,762 +82,734 @@ BeforeAll { param( ) - $script:migrations = Get-Migration -ConfigFilePath $RTConfigFilePath + $script:migrations = Get-Migration -ConfigFilePath $script:rivetJsonPath } } Describe 'Get-Migration' { BeforeEach { - Init - } - - AfterEach { - Reset + $script:testDir = Join-Path -Path $TestDrive -ChildPath ($script:testNum++) + New-Item -Path $script:testDir -ItemType Directory + $Global:Error.Clear() + $script:migrations = @() + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDir -Database $script:dbName -PassThru } - It 'should get migrations using current rivet json file' { - New-Item -Path (Join-Path -Path $TestDrive -ChildPath ('Databases\{0}\Migrations' -f $RTDatabaseName)) -ItemType 'Directory' -Force - - $rivetJsonPath = Join-Path -Path $TestDrive -ChildPath 'rivet.json' - (@' - {{ - DatabasesRoot: 'Databases', - SqlServerName: {0} - }} -'@ -f ($RTServer.ToString() | ConvertTo-Json)) | Set-Content -Path $rivetJsonPath - - @' - function Push-Migration - { - Add-Schema 'ShouldGetMigrationsUsingCurrentRivetJsonFile' - } - - function Pop-Migration - { - Remove-Schema 'ShouldGetMigrationsUsingCurrentRivetJsonFile' - } -'@ | New-TestMigration -Name 'ShouldGetMigrationsUsingCurrentRivetJsonFile' -ConfigFilePath $rivetJsonPath | Format-Table | Out-String | Write-Verbose - - Push-Location -Path $TestDrive -StackName $PSCommandPath - try - { - Assert-GetMigration (Get-Migration) - Assert-GetMigration (Get-Migration -Database $RTDatabaseName -ConfigFilePath $rivetJsonPath) - $Global:Error.Count | Should -Be 0 - } - finally - { - Pop-Location -StackName $PSCommandPath + Context 'minimal configuration' { + BeforeEach { + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDir -Database $script:dbName -PassThru } - # Now, use an explicit path. - Assert-GetMigration (Get-Migration -ConfigFilePath $rivetJsonPath) - } + It 'should get migrations using current rivet json file' { + GivenMigration 'ShouldGetMigrationsUsingCurrentRivetJsonFile' @' + function Push-Migration + { + Add-Schema 'ShouldGetMigrationsUsingCurrentRivetJsonFile' + } + + function Pop-Migration + { + Remove-Schema 'ShouldGetMigrationsUsingCurrentRivetJsonFile' + } +'@ - It 'should protect against items returned from pipeline' { - @' - function Push-Migration - { - Invoke-Ddl 'select 1' - } - 1 # See that guy? We should protect ourselves against 💩 like that. - function Pop-Migration - { - Invoke-Ddl 'select 1' - } -'@ | New-TestMigration -Name 'ShouldProtectAgainstItemsReturnedFromPipeline' + Push-Location -Path $script:testDir -StackName $PSCommandPath + try + { + Assert-GetMigration (Get-Migration) + Assert-GetMigration (Get-Migration -Database $script:dbName -ConfigFilePath $script:rivetJsonPath) + $Global:Error | Should -BeNullOrEmpty + } + finally + { + Pop-Location -StackName $PSCommandPath + } + + # Now, use an explicit path. + Assert-GetMigration (Get-Migration -ConfigFilePath $script:rivetJsonPath) + } - $m = Get-Migration -ConfigFilePath $RTConfigFilePath - $Global:Error.Count | Should -Be 0 - $m | Should -BeOfType ([Rivet.Migration]) - } + It 'should protect against items returned from pipeline' { + GivenMigration 'ShouldProtectAgainstItemsReturnedFromPipeline' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + 1 # See that guy? We should protect ourselves against 💩 like that. + function Pop-Migration + { + Invoke-Ddl 'select 1' + } +'@ - It 'should ignore migration with empty push' { - $m = @' - function Push-Migration - { - # I'm empty. - } + $m = Get-Migration -ConfigFilePath $script:rivetJsonPath + $Global:Error | Should -BeNullOrEmpty + $m | Should -BeOfType ([Rivet.Migration]) + } - function Pop-Migration - { - Invoke-Ddl 'select 1' - } -'@ | New-TestMigration -Name 'EmptyPush' + It 'should ignore migration with empty push' { + GivenMigration 'EmptyPush' @' + function Push-Migration + { + # I'm empty. + } + + function Pop-Migration + { + Invoke-Ddl 'select 1' + } +'@ - try - { - $result = Get-Migration -ConfigFilePath $RTConfigFilePath -ErrorAction SilentlyContinue + $result = Get-Migration -ConfigFilePath $script:rivetJsonPath -ErrorAction SilentlyContinue $result | Should -BeNullOrEmpty $Global:Error | Should -BeNullOrEmpty } - finally - { - Remove-Item -Path $m.FullName - } - } - - It 'should ignore migration with empty pop' { - $m = @' - function Push-Migration - { - Invoke-Ddl 'select 1' - } - function Pop-Migration - { - # I'm empty. - } -'@ | New-TestMigration -Name 'EmptyPop' + It 'should ignore migration with empty pop' { + GivenMigration 'EmptyPop' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + + function Pop-Migration + { + # I'm empty. + } +'@ - try - { - $result = Get-Migration -ConfigFilePath $RTConfigFilePath -ErrorAction SilentlyContinue + $result = Get-Migration -ConfigFilePath $script:rivetJsonPath -ErrorAction SilentlyContinue $result | Should -BeNullOrEmpty $Global:Error | Should -BeNullOrEmpty } - finally - { - Remove-Item -Path $m.FullName - } - } - It 'should reject migration with no push migration function' { - $m = @' - function Pop-Migration - { - Invoke-Ddl 'select 1' - } -'@ | New-TestMigration -Name 'MissingPush' + It 'should reject migration with no push migration function' { + GivenMigration 'MissingPush' @' + function Pop-Migration + { + Invoke-Ddl 'select 1' + } +'@ - try - { $result = - { Get-Migration -ConfigFilePath $RTConfigFilePath } | + { Get-Migration -ConfigFilePath $script:rivetJsonPath } | Should -Throw '*Push-Migration function not found*' $result | Should -BeNullOrEmpty $Global:Error.Count | Should -BeGreaterThan 0 $Global:Error[0] | Should -Match 'Push-Migration.*not found' } - finally - { - Remove-Item -Path $m.FullName - } - } - It 'should reject migration with no pop migration function' { - $m = @' - function Push-Migration - { - Invoke-Ddl 'select 1' - } -'@ | New-TestMigration -Name 'MissingPop' + It 'should reject migration with no pop migration function' { + GivenMigration 'MissingPop' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } +'@ - try - { $result = - { Get-Migration -ConfigFilePath $RTConfigFilePath } | + { Get-Migration -ConfigFilePath $script:rivetJsonPath } | Should -Throw '*Pop-Migration function not found*' $result | Should -BeNullOrEmpty $Global:Error.Count | Should -BeGreaterThan 0 $Global:Error[0] | Should -Match 'Pop-Migration.*not found' } - finally - { - Remove-Item -Path $m.FullName + + It 'should write an error if included migration not found' { + { Get-Migration -ConfigFilePath $script:rivetJsonPath -Include 'nomigrationbythisname' } | + Should -Throw "*""nomigrationbythisname""*does not exist*" } - } - It 'should write an error if included migration not found' { - { Get-Migration -ConfigFilePath $RTConfigFilePath -Include 'nomigrationbythisname' } | - Should -Throw "*""nomigrationbythisname""*does not exist*" - } + It 'should not write an error if included wildcarded migration not found' { + $result = Get-Migration -ConfigFilePath $script:rivetJsonPath -Include '*fubar*' + $result | Should -BeNullOrEmpty + $Global:Error | Should -BeNullOrEmpty + } - It 'should not write an error if included wildcarded migration not found' { - $result = Get-Migration -ConfigFilePath $RTConfigFilePath -Include '*fubar*' - $result | Should -BeNullOrEmpty - $Global:Error.Count | Should -Be 0 - } + It 'should include migration by name or ID' { + $m = GivenMigration 'ShouldIncludeMigrationByNameOrID' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + + function Pop-Migration + { + Invoke-Ddl 'select 1' + } +'@ - It 'should include migration by name or ID' { - $m = @' - function Push-Migration - { - Invoke-Ddl 'select 1' - } + $id = ($m.BaseName -split '_')[0] - function Pop-Migration - { - Invoke-Ddl 'select 1' - } -'@ | New-TestMigration -Name 'ShouldIncludeMigrationByNameOrID' + $result = Get-Migration -ConfigFilePath $script:rivetJsonPath -Include 'ShouldIncludeMigrationByNameOrID' + $result | Should -Not -BeNullOrEmpty + $id | Should -Be $result.ID + 'ShouldIncludeMigrationByNameOrID' | Should -Be $result.Name + $m.BaseName | Should -Be $result.FullName - $id = ($m.BaseName -split '_')[0] + $result = Get-Migration -ConfigFilePath $script:rivetJsonPath -Include $id + $result | Should -Not -BeNullOrEmpty + $id | Should -Be $result.ID + 'ShouldIncludeMigrationByNameOrID' | Should -Be $result.Name + $m.BaseName | Should -Be $result.FullName + } - $result = Get-Migration -ConfigFilePath $RTConfigFilePath -Include 'ShouldIncludeMigrationByNameOrID' - $result | Should -Not -BeNullOrEmpty - $id | Should -Be $result.ID - 'ShouldIncludeMigrationByNameOrID' | Should -Be $result.Name - $m.BaseName | Should -Be $result.FullName + It 'should include migration wildcard ID' { + $m = GivenMigration 'ShouldIncludeMigrationWildcardID' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + + function Pop-Migration + { + Invoke-Ddl 'select 1' + } +'@ - $result = Get-Migration -ConfigFilePath $RTConfigFilePath -Include $id - $result | Should -Not -BeNullOrEmpty - $id | Should -Be $result.ID - 'ShouldIncludeMigrationByNameOrID' | Should -Be $result.Name - $m.BaseName | Should -Be $result.FullName - } + $id = ($m.BaseName -split '_')[0] - It 'should include migration wildcard ID' { - $m = @' - function Push-Migration - { - Invoke-Ddl 'select 1' - } + $result = Get-Migration -ConfigFilePath $script:rivetJsonPath -Include ('{0}*' -f $id.Substring(0,10)) + $result | Should -Not -BeNullOrEmpty + $id | Should -Be $result.ID + 'ShouldIncludeMigrationWildcardID' | Should -Be $result.Name + $m.BaseName | Should -Be $result.FullName + } - function Pop-Migration - { - Invoke-Ddl 'select 1' - } -'@ | New-TestMigration -Name 'ShouldIncludeMigrationWildcardID' + It 'should get a migration by base name' { + $m = GivenMigration 'ShouldGetAMigrationByBaseName' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + + function Pop-Migration + { + Invoke-Ddl 'select 1' + } +'@ - $id = ($m.BaseName -split '_')[0] + $id = ($m.BaseName -split '_')[0] - $result = Get-Migration -ConfigFilePath $RTConfigFilePath -Include ('{0}*' -f $id.Substring(0,10)) - $result | Should -Not -BeNullOrEmpty - $id | Should -Be $result.ID - 'ShouldIncludeMigrationWildcardID' | Should -Be $result.Name - $m.BaseName | Should -Be $result.FullName - } + $result = Get-Migration -ConfigFilePath $script:rivetJsonPath -Include $m.BaseName + $result | Should -Not -BeNullOrEmpty + $id | Should -Be $result.ID + 'ShouldGetAMigrationByBaseName' | Should -Be $result.Name + $m.BaseName | Should -Be $result.FullName + } - It 'should get a migration by base name' { - $m = @' - function Push-Migration - { - Invoke-Ddl 'select 1' - } + It 'should get a migration by base name with wildcard' { + $m = GivenMigration 'ShouldGetAMigrationByBaseNameWithWildcard' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + + function Pop-Migration + { + Invoke-Ddl 'select 1' + } +'@ - function Pop-Migration - { - Invoke-Ddl 'select 1' - } -'@ | New-TestMigration -Name 'ShouldGetAMigrationByBaseName' + $id = ($m.BaseName -split '_')[0] - $id = ($m.BaseName -split '_')[0] + $result = Get-Migration -ConfigFilePath $script:rivetJsonPath -Include ('{0}*' -f $m.BaseName.Substring(0,20)) + $result | Should -Not -BeNullOrEmpty + $id | Should -Be $result.ID + 'ShouldGetAMigrationByBaseNameWithWildcard' | Should -Be $result.Name + $m.BaseName | Should -Be $result.FullName + } - $result = Get-Migration -ConfigFilePath $RTConfigFilePath -Include $m.BaseName - $result | Should -Not -BeNullOrEmpty - $id | Should -Be $result.ID - 'ShouldGetAMigrationByBaseName' | Should -Be $result.Name - $m.BaseName | Should -Be $result.FullName - } + It 'should match exclude pattern against ID, name, and base name and support wildcards' { + $m = GivenMigration 'ShouldExcludeMigrationByNameOrID' $script:noOpMigration + $id = ($m.BaseName -split '_')[0] - It 'should get a migration by base name with wildcard' { - $m = @' - function Push-Migration - { - Invoke-Ddl 'select 1' - } + GivenMigration 'ShouldInclude' $script:noOpMigration + GivenMigration 'ShouldExcludeIfUsingWildcards' $script:noOpMigration - function Pop-Migration - { - Invoke-Ddl 'select 1' - } -'@ | New-TestMigration -Name 'ShouldGetAMigrationByBaseNameWithWildcard' + # When excluding a specific migration by name. + Get-Migration -ConfigFilePath $script:rivetJsonPath -Exclude 'ShouldExcludeMigrationByNameOrID' | Should -HaveCount 2 + Get-Migration -ConfigFilePath $script:rivetJsonPath -Exclude 'ShouldExclude*' | Should -HaveCount 1 - $id = ($m.BaseName -split '_')[0] + # Should match against base name. + Get-Migration -ConfigFilePath $script:rivetJsonPath -Exclude $m.BaseName | Should -HaveCount 2 + Get-Migration -ConfigFilePath $script:rivetJsonPath -Exclude "$($id.Substring(0, 4))*_ShouldExcludeMig*" | Should -HaveCount 2 - $result = Get-Migration -ConfigFilePath $RTConfigFilePath -Include ('{0}*' -f $m.BaseName.Substring(0,20)) - $result | Should -Not -BeNullOrEmpty - $id | Should -Be $result.ID - 'ShouldGetAMigrationByBaseNameWithWildcard' | Should -Be $result.Name - $m.BaseName | Should -Be $result.FullName - } + # Should match against ID. + Get-Migration -ConfigFilePath $script:rivetJsonPath -Exclude $id | Should -HaveCount 2 + Get-Migration -ConfigFilePath $script:rivetJsonPath -Exclude "$($id.Substring(0, 4))*" | Should -BeNullOrEmpty - It 'should set timeout duration to default 30 seconds on Rivet operations when CommandTimeout isn''t specified in the Rivet configuration' { - @' - function Push-Migration - { - Invoke-Ddl 'select 1' - } - function Pop-Migration - { - Invoke-Ddl 'select 1' - } -'@ | New-TestMigration -Name 'SetCommandTimeout' + # should match multiple exclude patterns + Get-Migration -ConfigFilePath $script:rivetJsonPath -Exclude '*Wildcards','*ID' | Should -HaveCount 1 - $m = Get-Migration -ConfigFilePath $RTConfigFilePath - $Global:Error.Count | Should -Be 0 - $m | Should -BeOfType ([Rivet.Migration]) - $m.PopOperations[0].CommandTimeout | Should -Be 30 - $m.PushOperations[0].CommandTimeout | Should -Be 30 - } - - It 'should set timeout duration on Rivet operations when CommandTimeout is specified in the Rivet configuration' { - Start-RivetTest -CommandTimeout 60 - @' - function Push-Migration - { - Invoke-Ddl 'select 1' - } - function Pop-Migration - { - Invoke-Ddl 'select 1' + $Global:Error | Should -BeNullOrEmpty } -'@ | New-TestMigration -Name 'SetCommandTimeout' - - $m = Get-Migration -ConfigFilePath $RTConfigFilePath - $Global:Error.Count | Should -Be 0 - $m | Should -BeOfType ([Rivet.Migration]) - $m.PopOperations[0].CommandTimeout | Should -Be 60 - $m.PushOperations[0].CommandTimeout | Should -Be 60 } - It 'should match exclude pattern against ID, name, and base name and support wildcards' { - $m = $script:noOpMigration | New-TestMigration -Name 'ShouldExcludeMigrationByNameOrID' - $id = ($m.BaseName -split '_')[0] - - $script:noOpMigration | New-TestMigration -Name 'ShouldInclude' - $script:noOpMigration | New-TestMigration -Name 'ShouldExcludeIfUsingWildcards' - - # When excluding a specific migration by name. - Get-Migration -ConfigFilePath $RTConfigFilePath -Exclude 'ShouldExcludeMigrationByNameOrID' | Should -HaveCount 2 - Get-Migration -ConfigFilePath $RTConfigFilePath -Exclude 'ShouldExclude*' | Should -HaveCount 1 - - # Should match against base name. - Get-Migration -ConfigFilePath $RTConfigFilePath -Exclude $m.BaseName | Should -HaveCount 2 - Get-Migration -ConfigFilePath $RTConfigFilePath -Exclude "$($id.Substring(0, 4))*_ShouldExcludeMig*" | Should -HaveCount 2 + Context 'CommandTimeout' { + It 'should set timeout duration to default 30 seconds on Rivet operations when CommandTimeout isn''t specified in the Rivet configuration' { + GivenMigration 'SetCommandTimeout' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 1' + } +'@ - # Should match against ID. - Get-Migration -ConfigFilePath $RTConfigFilePath -Exclude $id | Should -HaveCount 2 - Get-Migration -ConfigFilePath $RTConfigFilePath -Exclude "$($id.Substring(0, 4))*" | Should -BeNullOrEmpty + $m = Get-Migration -ConfigFilePath $script:rivetJsonPath + $Global:Error | Should -BeNullOrEmpty + $m | Should -BeOfType ([Rivet.Migration]) + $m.PopOperations[0].CommandTimeout | Should -Be 30 + $m.PushOperations[0].CommandTimeout | Should -Be 30 + } - # should match multiple exclude patterns - Get-Migration -ConfigFilePath $RTConfigFilePath -Exclude '*Wildcards','*ID' | Should -HaveCount 1 + It 'should set timeout duration on Rivet operations when CommandTimeout is specified in the Rivet configuration' { + $script:rivetJsonPath = + GivenRivetJsonFile -In $script:testDir -Database $script:dbName -PassThru -CommandTimeout 60 + + GivenMigration 'SetCommandTimeout' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 1' + } +'@ - $Global:Error | Should -BeNullOrEmpty + $m = Get-Migration -ConfigFilePath $script:rivetJsonPath + $Global:Error | Should -BeNullOrEmpty + $m | Should -BeOfType ([Rivet.Migration]) + $m.PopOperations[0].CommandTimeout | Should -Be 60 + $m.PushOperations[0].CommandTimeout | Should -Be 60 + } } -} -Describe 'Get-Migration' { - BeforeEach { - Init -StartArgument @{ PluginPath = $script:pluginModuleName } - } + Context 'Plugins' { + BeforeEach { + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDir ` + -Database $script:dbName ` + -PluginPath $script:pluginModuleName ` + -PassThru + } - AfterEach { - Reset - if ((Get-Module $script:pluginModuleName)) - { - Remove-Module $script:pluginModuleName + AfterEach { + if ((Get-Module $script:pluginModuleName)) + { + Remove-Module $script:pluginModuleName + } } - } - It ('should run the plugin') { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] - param( - $Migration, - $Operation - ) - - Add-Schema 'boom' -} + It 'should run the plugin' { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] + param( + $Migration, + $Operation + ) + + Add-Schema 'boom' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - WhenGettingMigrations - $script:migrations | Should -Not -BeNullOrEmpty - $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty - $script:migrations.PushOperations[1] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) - $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty - $script:migrations.PopOperations[1] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) - } - - It ('should run all the plugins') { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] - param( - $Migration, - $Operation - ) - - Add-Schema 'boom' -} - -function AnotherOnAdd -{ - [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] - param( - $Migration, - $Operation - ) - - Add-Schema 'boom' -} + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - WhenGettingMigrations - $script:migrations | Should -Not -BeNullOrEmpty - $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -HaveCount 2 - $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -HaveCount 2 - } - - It 'runs before operation load plugins' { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] - param( - $Operation - ) + WhenGettingMigrations + $script:migrations | Should -Not -BeNullOrEmpty + $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty + $script:migrations.PushOperations[1] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) + $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty + $script:migrations.PopOperations[1] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) + } - Add-Schema -Name 'Fubar' -} + It ('should run all the plugins') { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] + param( + $Migration, + $Operation + ) + + Add-Schema 'boom' + } + + function AnotherOnAdd + { + [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] + param( + $Migration, + $Operation + ) + + Add-Schema 'boom' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - { WhenGettingMigrations } | - Should -Throw '*"BeforeOperationLoad" event must have a named "Migration" parameter*' - $script:migrations | Should -BeNullOrEmpty - } - - It 'ignores objects returned by plugin' { - GivenFile $script:pluginModulePath @' -function BeforeOpLoad -{ - [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] - param( - $Migration, - $Operation - ) - - return 'BeforeOperationLoad' -} - -function AfterOpLoad -{ - [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] - param( - $Migration, - $Operation - ) - - return 'AfterOperationLoad' -} - -function AfterMigrationLoad -{ - [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] - [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] - [Rivet.Plugin([Rivet.Events]::AfterMigrationLoad)] - param( - $Migration, - $Operation - ) - - return 'AfterMigrationLoad' -} + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - { WhenGettingMigrations } | Should -Not -Throw - } - - It ('should fail') { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] - param( - $Migration - ) + WhenGettingMigrations + $script:migrations | Should -Not -BeNullOrEmpty + $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -HaveCount 2 + $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -HaveCount 2 + } - Add-Schema -Name 'Fubar' -} + It 'runs before operation load plugins' { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] + param( + $Operation + ) + + Add-Schema -Name 'Fubar' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - { WhenGettingMigrations } | - Should -Throw '*"BeforeOperationLoad" event must have a named "Operation" parameter*' - $script:migrations | Should -BeNullOrEmpty - } - - It ('should run the plugin') { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] - param( - $Migration, - $Operation - ) - - Add-Schema 'boom' -} + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - WhenGettingMigrations - $script:migrations | Should -Not -BeNullOrEmpty - $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty - $script:migrations.PushOperations[0] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) - $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty - $script:migrations.PopOperations[0] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) - } - - It ('should run all the plugins') { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] - param( - $Migration, - $Operation - ) - - Add-Schema 'boom' -} - -function AnotherOnAdd -{ - [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] - param( - $Migration, - $Operation - ) + { WhenGettingMigrations } | + Should -Throw '*"BeforeOperationLoad" event must have a named "Migration" parameter*' + $script:migrations | Should -BeNullOrEmpty + } - Add-Schema 'boom' -} + It 'ignores objects returned by plugin' { + GivenPlugin @' + function BeforeOpLoad + { + [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] + param( + $Migration, + $Operation + ) + + return 'BeforeOperationLoad' + } + + function AfterOpLoad + { + [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] + param( + $Migration, + $Operation + ) + + return 'AfterOperationLoad' + } + + function AfterMigrationLoad + { + [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] + [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] + [Rivet.Plugin([Rivet.Events]::AfterMigrationLoad)] + param( + $Migration, + $Operation + ) + + return 'AfterMigrationLoad' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - WhenGettingMigrations - $script:migrations | Should -Not -BeNullOrEmpty - $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -HaveCount 2 - $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -HaveCount 2 - } - - It ('should fail') { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] - param( - $Operation - ) - - Add-Schema -Name 'Fubar' -} + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - { WhenGettingMigrations } | Should -Throw '*"AfterOperationLoad" event must have a named "Migration" parameter*' - $script:migrations | Should -BeNullOrEmpty - } - - It ('should fail') { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] - param( - $Migration - ) + { WhenGettingMigrations } | Should -Not -Throw + } - Add-Schema -Name 'Fubar' -} + It ('should fail') { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] + param( + $Migration + ) + + Add-Schema -Name 'Fubar' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - { WhenGettingMigrations } | Should -Throw '*"AfterOperationLoad" event must have a named "Operation" parameter*' - $script:migrations | Should -BeNullOrEmpty - $Global:Error | Should -Match - } - - It ('should run the plugin') { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] - param( - $Migration, - $Operation - ) - - 1 -} + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - WhenGettingMigrations - $script:migrations | Should -Not -BeNullOrEmpty - $script:migrations.PushOperations | Should -BeOfType ([Rivet.Operations.Operation]) - $script:migrations.PopOperations | Should -BeOfType ([Rivet.Operations.Operation]) - } - - It ('should run the plugin when an AddSchemaOperation exists') { - GivenFile $script:pluginModulePath @' -function OnAdd -{ - [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] - param( - $Migration, - $Operation - ) - - Add-Schema 'boom' -} + { WhenGettingMigrations } | + Should -Throw '*"BeforeOperationLoad" event must have a named "Operation" parameter*' + $script:migrations | Should -BeNullOrEmpty + } -function AfterMigration -{ + It ('should run the plugin') { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] + param( + $Migration, + $Operation + ) + + Add-Schema 'boom' + } +'@ + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } +'@ + WhenGettingMigrations + $script:migrations | Should -Not -BeNullOrEmpty + $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty + $script:migrations.PushOperations[0] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) + $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty + $script:migrations.PopOperations[0] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) + } - [Rivet.Plugin([Rivet.Events]::AfterMigrationLoad)] - param( - $Migration - ) + It ('should run all the plugins') { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] + param( + $Migration, + $Operation + ) + + Add-Schema 'boom' + } + + function AnotherOnAdd + { + [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] + param( + $Migration, + $Operation + ) + + Add-Schema 'boom' + } +'@ + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } +'@ + WhenGettingMigrations + $script:migrations | Should -Not -BeNullOrEmpty + $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -HaveCount 2 + $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -HaveCount 2 + } - $addSchemaOperation = $Migration.PushOperations | Where-Object{ $_ -is [Rivet.Operations.AddSchemaOperation]} + It ('should fail') { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] + param( + $Operation + ) + + Add-Schema -Name 'Fubar' + } +'@ + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } +'@ + { WhenGettingMigrations } | Should -Throw '*"AfterOperationLoad" event must have a named "Migration" parameter*' + $script:migrations | Should -BeNullOrEmpty + } - if( -not $addSchemaOperation ) - { - Write-Error 'Please add a schema!' - } -} + It ('should fail') { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] + param( + $Migration + ) + + Add-Schema -Name 'Fubar' + } +'@ + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } +'@ + { WhenGettingMigrations } | Should -Throw '*"AfterOperationLoad" event must have a named "Operation" parameter*' + $script:migrations | Should -BeNullOrEmpty + $Global:Error | Should -Match + } + It ('should run the plugin') { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::AfterOperationLoad)] + param( + $Migration, + $Operation + ) + + 1 + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - WhenGettingMigrations - $script:migrations | Should -Not -BeNullOrEmpty - $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty - $script:migrations.PushOperations[1] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) - $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty - $script:migrations.PopOperations[1] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) - } + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } +'@ + WhenGettingMigrations + $script:migrations | Should -Not -BeNullOrEmpty + $script:migrations.PushOperations | Should -BeOfType ([Rivet.Operations.Operation]) + $script:migrations.PopOperations | Should -BeOfType ([Rivet.Operations.Operation]) + } - It ('should throw an error when AddSchemaOperation doesn''t exist') { - GivenFile $script:pluginModulePath @' -function AfterMigration -{ + It ('should run the plugin when an AddSchemaOperation exists') { + GivenPlugin @' + function OnAdd + { + [Rivet.Plugin([Rivet.Events]::BeforeOperationLoad)] + param( + $Migration, + $Operation + ) + + Add-Schema 'boom' + } + + function AfterMigration + { + + [Rivet.Plugin([Rivet.Events]::AfterMigrationLoad)] + param( + $Migration + ) + + $addSchemaOperation = $Migration.PushOperations | Where-Object{ $_ -is [Rivet.Operations.AddSchemaOperation]} + + if( -not $addSchemaOperation ) + { + Write-Error 'Please add a schema!' + } + } +'@ + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } +'@ + WhenGettingMigrations + $script:migrations | Should -Not -BeNullOrEmpty + $script:migrations.PushOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty + $script:migrations.PushOperations[1] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) + $script:migrations.PopOperations | Where-Object { $_ -is [Rivet.Operations.AddSchemaOperation] } | Should -Not -BeNullOrEmpty + $script:migrations.PopOperations[1] | Should -BeOfType ([Rivet.Operations.RawDdlOperation]) + } - [Rivet.Plugin([Rivet.Events]::AfterMigrationLoad)] - param( - $Migration - ) + It ('should throw an error when AddSchemaOperation doesn''t exist') { + GivenPlugin @' + function AfterMigration + { - $problems = $false - $addSchemaOperation = $Migration.PushOperations | Where-Object{ $_ -is [Rivet.Operations.AddSchemaOperation]} + [Rivet.Plugin([Rivet.Events]::AfterMigrationLoad)] + param( + $Migration + ) - if( -not $addSchemaOperation ) - { - throw ('Please add a schema!') - } -} + $problems = $false + $addSchemaOperation = $Migration.PushOperations | Where-Object{ $_ -is [Rivet.Operations.AddSchemaOperation]} + if( -not $addSchemaOperation ) + { + throw ('Please add a schema!') + } + } '@ - @' -function Push-Migration -{ - Invoke-Ddl 'select 1' -} -function Pop-Migration -{ - Invoke-Ddl 'select 2' -} -'@ | New-TestMigration -Name 'One' - { WhenGettingMigrations } | Should -Throw '*Please add a schema!*' - $script:migrations | Should -BeNullOrEmpty + GivenMigration 'One' @' + function Push-Migration + { + Invoke-Ddl 'select 1' + } + function Pop-Migration + { + Invoke-Ddl 'select 2' + } +'@ + { WhenGettingMigrations } | Should -Throw '*Please add a schema!*' + $script:migrations | Should -BeNullOrEmpty + } } } \ No newline at end of file diff --git a/Test/Import-RivetPlugin.Tests.ps1 b/Test/Import-RivetPlugin.Tests.ps1 index 77fb10ab..f2493d48 100644 --- a/Test/Import-RivetPlugin.Tests.ps1 +++ b/Test/Import-RivetPlugin.Tests.ps1 @@ -134,7 +134,7 @@ Describe 'Import-RivetPlugin' { } '@ | New-TestMigration -Name 'AddMyTable' - Import-Module -Name (Join-Path -Path $RTTestRoot -ChildPath 'ImportRivetPluginPlugins' -Resolve) + Import-Module -Name (Join-Path -Path $RTTestRoot -ChildPath 'ImportRivetPluginPlugins' -Resolve) -Verbose:$false Mock -CommandName 'Import-Module' -ModuleName 'Rivet' Set-PluginPath -PluginModule 'ImportRivetPluginPlugins' diff --git a/Test/Invoke-Rivet.Tests.ps1 b/Test/Invoke-Rivet.Tests.ps1 index 3effb0f5..57ed6530 100644 --- a/Test/Invoke-Rivet.Tests.ps1 +++ b/Test/Invoke-Rivet.Tests.ps1 @@ -6,6 +6,14 @@ BeforeAll { Set-StrictMode -Version 'Latest' & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) + Remove-Item -Path 'alias:GivenMigration' + + $script:dbName = 'Invoke-Rivet' + $script:db2Name = 'Invoke-Rivet2' + $script:virtualDbName = 'Invoke-RivetISHOULDNOTEXIST' + $script:testDirPath = $null + $script:testNum = 0 + $script:sqlServerName = Get-Content -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Server.txt') -ReadCount 1 function Assert-OperationsReturned { @@ -16,329 +24,326 @@ BeforeAll { $Operation | Should -Not -BeNullOrEmpty } - function Init + function GivenDirectory { param( - $PluginPath + [String] $Named ) - Start-RivetTest -PluginPath $PluginPath - $Global:Error.Clear() + $path = Join-Path $script:testDirPath -ChildPath $Named + if (-not (Test-Path -Path $path)) + { + New-Item -Path $path -ItemType Directory + } } - function Reset + function GivenMigration { param( - [string[]] - $Plugin - ) + [Parameter(Mandatory, Position=0)] + [String] $Named, - Stop-RivetTest - Remove-Module -Name $Plugin - } + [Parameter(Mandatory, Position=1)] + [String] $WithContent, - } + [string] $ForDatabase = $script:dbName, -Describe 'Invoke-Rivet' { - BeforeEach { - Start-RivetTest -IgnoredDatabase 'Ignored' - $Global:Error.Clear() - } + [UInt64] $WithID + ) - AfterEach { - try + $optionalArgs = @{} + if ($WithID) { - Stop-RivetTest + $optionalArgs['WithID'] = $WithID } - catch - { - } - Clear-TestDatabase -Name $RTDatabase2Name - } - - It 'should create database' { - Remove-RivetTestDatabase - - $query = 'select 1 from sys.databases where name=''{0}''' -f $RTDatabaseName - (Invoke-RivetTestQuery -Query $query -Master -AsScalar) | Should -BeNullOrEmpty + $WithContent | New-TestMigration -Name $Named ` + -ConfigFilePath $script:rivetJsonPath ` + -DatabaseName $ForDatabase ` + @optionalArgs + } - @' - function Push-Migration + function ThenOperationsReturned { - Add-Schema 'fubar' + Assert-OperationsReturned -Operation $script:result } - function Pop-Migration + function WhenRivetInvoked { - Remove-Schema 'fubar' - } -'@ | New-TestMigration -Name 'CreateDatabase' + [CmdletBinding()] + param( + [hashtable] $WithArgs + ) - $result = Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - $Global:Error.Count | Should -Be 0 - Assert-OperationsReturned $result + if (-not $WithArgs.ContainsKey('Database')) + { + $WithArgs['Database'] = $script:dbName + } - (Invoke-RivetTestQuery -Query $query -Master -AsScalar) | Should -Be 1 + $script:result = Invoke-Rivet -ConfigFilePath $script:rivetJsonPath @WithArgs } +} - It 'should apply migrations to duplicate database' { - $config = Get-Content -Raw -Path $RTConfigFilePath | ConvertFrom-Json - $config | Add-Member -MemberType NoteProperty -Name 'TargetDatabases' -Value @{ $RTDatabaseName = @( $RTDatabaseName, $RTDatabase2Name ) } - $config | ConvertTo-Json | Set-Content -Path $RTConfigFilePath - - @' - function Push-Migration - { - Add-Schema 'TargetDatabases' +Describe 'Invoke-Rivet' { + BeforeAll { + Remove-RivetTestDatabase -Name $script:dbName + Remove-RivetTestDatabase -Name $script:db2Name } - function Pop-Migration - { - Remove-Schema 'TargetDatabases' + BeforeEach { + $script:testDirPath = Join-Path -Path $TestDrive -ChildPath ($script:testNum++) + New-Item -Path $script:testDirPath -ItemType Directory + $script:migrations = @() + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -Database $script:dbName -PassThru + $script:result = $null + $Global:Error.Clear() } -'@ | New-TestMigration -Name 'TargetDatabases' -Database $RTDatabaseName - $result = Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - $Global:Error.Count | Should -Be 0 - Assert-OperationsReturned $result + It 'should create database' { + $query = "select 1 from sys.databases where name='${script:dbName}'" + + (Invoke-RivetTestQuery -Query $query -Master -AsScalar) | Should -BeNullOrEmpty + + GivenMigration 'CreateDatabase' @' + function Push-Migration + { + Add-Schema 'fubar' + } - Assert-Schema -Name 'TargetDatabases' - Assert-Schema -Name 'TargetDatabases' -DatabaseName $RTDatabase2Name + function Pop-Migration + { + Remove-Schema 'fubar' + } +'@ + WhenRivetInvoked -WithArgs @{ Push = $true } + ThenError -IsEmpty + ThenOperationsReturned + + (Invoke-RivetTestQuery -Query $query -Master -AsScalar) | Should -Be 1 } - It 'should create target databases' { - Remove-RivetTestDatabase - Remove-RivetTestDatabase -Name $RTDatabase2Name + Context 'TargetDatabases' { + BeforeEach { + Remove-RivetTestDatabase -Name $script:virtualDbName + Remove-RivetTestDatabase -Name $script:dbName + Remove-RivetTestDatabase -Name $script:db2Name + $script:rivetJsonPath = + GivenRivetJson -In $script:testDirPath ` + -Database $script:dbName ` + -TargetDatabase @{ $script:virtualDbName = @($script:dbName,$script:db2Name) } ` + -PassThru + } - $config = Get-Content -Raw -Path $RTConfigFilePath | ConvertFrom-Json - $config | Add-Member -MemberType NoteProperty -Name 'TargetDatabases' -Value @{ $RTDatabaseName = @( $RTDatabaseName, $RTDatabase2Name ) } - $config | ConvertTo-Json | Set-Content -Path $RTConfigFilePath + It 'should apply migrations to duplicate database' { + GivenMigration 'TargetDatabases' -ForDatabase $script:virtualDbName @' + function Push-Migration + { + Add-Schema 'TargetDatabases' + } - Remove-Item -Path $RTDatabaseMigrationRoot -Recurse + function Pop-Migration + { + Remove-Schema 'TargetDatabases' + } +'@ - $result = Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - $Global:Error.Count | Should -Be 0 - (Test-Database) | Should -BeTrue - (Test-Database $RTDatabase2Name) | Should -BeTrue - } + WhenRivetInvoked -WithArgs @{ Push = $true ; Database = $script:virtualDbName } + ThenError -IsEmpty + ThenOperationsReturned + Assert-Schema -Name 'TargetDatabases' -DatabaseName $script:dbName + Assert-Schema -Name 'TargetDatabases' -DatabaseName $script:db2Name + } - It 'should write error if migrating ignored database' { - Push-Location -Path (Split-Path -Parent -Path $RTConfigFilePath) - try - { - & $RTRivetPath -Push -Database 'Ignored' -ErrorAction SilentlyContinue - $Global:Error.Count | Should -BeGreaterThan 0 - $Global:Error[0] | Should -Match ([regex]::Escape($RTConfigFilePath)) + It 'should create target databases' { + WhenRivetInvoked -WithArgs @{ Push = $true ; Database = $script:virtualDbName } + ThenError -IsEmpty + (Test-Database $script:virtualDbName) | Should -BeFalse + (Test-Database $script:dbName) | Should -BeTrue + (Test-Database $script:db2Name) | Should -BeTrue } - finally - { - Pop-Location + + It 'drops virtual databases' { + WhenRivetInvoked -WithArgs @{ Push = $true ; Database = $script:virtualDbName } + ThenError -IsEmpty + (Test-Database $script:virtualDbName) | Should -BeFalse + (Test-Database $script:dbName) | Should -BeTrue + (Test-Database $script:db2Name) | Should -BeTrue + + # Now drop the databases + WhenRivetInvoked -WithArgs @{ DropDatabase = $true ; Database = $script:virtualDbName ; Force = $true } + ThenError -IsEmpty + (Test-Database $script:virtualDbName) | Should -BeFalse + (Test-Database $script:dbName) | Should -BeFalse + (Test-Database $script:db2Name) | Should -BeFalse } - } - It 'should prohibit reserved rivet migration IDs' { - $startedAt = Get-Date - $file = @' - function Push-Migration - { - Add-Schema 'fubar' } - function Pop-Migration - { - Remove-Schema 'fubar' + It 'should write error if migrating ignored database' { + $script:rivetJsonPath = + GivenRivetJson -In $script:testDirPath -Database $script:dbName -IgnoredDatabase 'Ignored' -PassThru + WhenRivetInvoked -WithArgs @{ Push = $true ; Database = 'Ignored' } -ErrorAction SilentlyContinue + ThenError -Matches 'database is on the ignore list' } -'@ | New-TestMigration -Name 'HasReservedID' -Database $RTDatabaseName - $file | Should -Not -BeNullOrEmpty - $file = Rename-Item -Path $file -NewName ('00010100999999_HasReservedID.ps1') -PassThru + It 'should prohibit reserved rivet migration IDs' { + GivenMigration 'HasReservedID' -WithID 10100999999 @' + function Push-Migration + { + Add-Schema 'fubar' + } + + function Pop-Migration + { + Remove-Schema 'fubar' + } +'@ - { Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push } | - Should -Throw '*reserved*' + { WhenRivetInvoked -WithArgs @{ Push = $true } } | Should -Throw '*reserved*' (Test-Schema -Name 'fubar') | Should -BeFalse - - $Global:Error.Clear() - Rename-Item -Path $file -NewName ('00010101000000_HasReservedID.ps1') - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - $Global:Error.Count | Should -Be 0 - Assert-Schema -Name 'fubar' } It 'handles connection failure' { - $config = Get-Content -Raw -Path $RTConfigFilePath | ConvertFrom-Json - $originalSqlServerName = $config.SqlServerName - $config.SqlServerName = '.\IDoNotExist' - $config | ConvertTo-Json | Set-Content -Path $RTConfigFilePath - - try - { - { Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push } | - Should -Throw '*network-related or instance-specific error*' - } - finally - { - $config = Get-Content -Raw -Path $RTConfigFilePath | ConvertFrom-Json - $config.SqlServerName = $originalSqlServerName - $config | ConvertTo-Json | Set-Content -Path $RTConfigFilePath - } + $script:rivetJsonPath = GivenRivetJson -In $script:testDirPath ` + -Database $script:dbName ` + -SqlServerName '.\IDoNotExist' ` + -ConnectionTimeout 1 ` + -PassThru + { WhenRivetInvoked -WithArgs @{ Push = $true } } | + Should -Throw '*network-related or instance-specific error*' } It 'should create multiple migrations' { - $m = Invoke-Rivet -New -Name 'One','Two' -ConfigFilePath $RTConfigFilePath - try - { - $Global:Error | Should -BeNullOrEmpty - ,$m | Should -BeOfType ([object[]]) - $m[0].Name | Should -BeLike '*_One.ps1' - $m[1].Name | Should -BeLike '*_Two.ps1' - } - finally - { - $m | Remove-Item - } + WhenRivetInvoked -WithArgs @{ New = $true ; Name = 'One', 'Two' } + ThenError -IsEmpty + ,$script:result | Should -BeOfType ([object[]]) + $script:result[0].Name | Should -BeLike '*_One.ps1' + $script:result[1].Name | Should -BeLike '*_Two.ps1' } It 'should push multiple migrations' { - $m = @( 'One', 'Two', 'Three' ) | - ForEach-Object { - @' + # Make sure database initialized. + WhenRivetInvoked -WithArgs @{ Push = $true } + foreach ($name in @( 'One', 'Two', 'Three' )) + { + GivenMigration $name @' function Push-Migration { Invoke-Ddl 'select 1' } function Pop-Migration { Invoke-Ddl 'select 1' } -'@ | New-TestMigration -Name $_ - } - [Rivet.OperationResult[]]$result = Invoke-Rivet -Name 'One','Three' -ConfigFilePath $RTConfigFilePath -Push - Assert-OperationsReturned $result - $result[0].Migration.Name | Should -Be 'One' - $result[1].Migration.Name | Should -Be 'Three' +'@ + } + WhenRivetInvoked -WithArgs @{ Push = $true ; Name = 'One', 'Three' } + ThenOperationsReturned + $script:result[0].Migration.Name | Should -Be 'One' + $script:result[1].Migration.Name | Should -Be 'Three' } It 'should pop multiple migrations' { - $m = @( 'One', 'Two', 'Three' ) | - ForEach-Object { - @' + foreach ($name in @( 'One', 'Two', 'Three' )) + { + GivenMigration $name @' function Push-Migration { Invoke-Ddl 'select 1' } function Pop-Migration { Invoke-Ddl 'select 1' } -'@ | New-TestMigration -Name $_ - } - Invoke-Rivet -Name 'One','Three' -ConfigFilePath $RTConfigFilePath -Push - [Rivet.OperationResult[]]$result = Invoke-Rivet -Pop -Name 'One','Three' -ConfigFilePath $RTConfigFilePath - Assert-OperationsReturned $result - $result[0].Migration.Name | Should -Be 'Three' - $result[1].Migration.Name | Should -Be 'One' +'@ + } + WhenRivetInvoked -WithArgs @{ Push = $true ; Name = 'One', 'Three' } + WhenRivetInvoked -WithArgs @{ Pop = $true ; Name = 'One', 'Three' } + ThenOperationsReturned + $script:result[0].Migration.Name | Should -Be 'Three' + $script:result[1].Migration.Name | Should -Be 'One' } - It 'should drop all databases given -DropDatabase with no databases specified' { - Remove-RivetTestDatabase - Remove-RivetTestDatabase -Name $RTDatabase2Name - - $config = Get-Content -Raw -Path $RTConfigFilePath | ConvertFrom-Json - $config | Add-Member -MemberType NoteProperty -Name 'TargetDatabases' -Value @{ $RTDatabaseName = @( $RTDatabaseName, $RTDatabase2Name ) } - $config | ConvertTo-Json | Set-Content -Path $RTConfigFilePath - - # Create databases first - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - $Global:Error.Count | Should -Be 0 - (Test-Database) | Should -BeTrue - (Test-Database $RTDatabase2Name) | Should -BeTrue - - # Now drop the databases - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -DropDatabase -Force - $Global:Error.Count | Should -Be 0 - (Test-Database) | Should -BeFalse - (Test-Database $RTDatabase2Name) | Should -BeFalse - } + Context '-DropDatabase' { + BeforeEach { + Remove-RivetTestDatabase -Name $script:dbName + Remove-RivetTestDatabase -Name $script:db2Name + } - It 'should drop a specific database given -DropDatabase with a database name' { - Remove-RivetTestDatabase - Remove-RivetTestDatabase -Name $RTDatabase2Name - - $config = Get-Content -Raw -Path $RTConfigFilePath | ConvertFrom-Json - $config | Add-Member -MemberType NoteProperty -Name 'TargetDatabases' -Value @{ $RTDatabaseName = @( $RTDatabaseName, $RTDatabase2Name ) } - $config | ConvertTo-Json | Set-Content -Path $RTConfigFilePath - - # Create databases first - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - $Global:Error.Count | Should -Be 0 - (Test-Database) | Should -BeTrue - (Test-Database $RTDatabase2Name) | Should -BeTrue - - # Now drop the database - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -DropDatabase -Force -Database 'RivetTest2' - $Global:Error.Count | Should -Be 0 - (Test-Database) | Should -BeTrue - (Test-Database $RTDatabase2Name) | Should -BeFalse - } + It 'drops specific database' { + $script:rivetJsonPath = + GivenRivetJson -In $script:testDirPath -Database $script:dbName, $script:db2Name -PassThru + WhenRivetInvoked -WithArgs @{ Push = $true ; Database = $script:dbName,$script:db2Name } + ThenError -IsEmpty + (Test-Database $script:dbName) | Should -BeTrue + (Test-Database $script:db2Name) | Should -BeTrue + + # Now drop the database + WhenRivetInvoked -WithArgs @{ DropDatabase = $true ; Database = $script:db2Name ; Force = $true } + ThenError -IsEmpty + (Test-Database $script:dbName) | Should -BeTrue + (Test-Database $script:db2Name) | Should -BeFalse + } - It 'should do nothing when given -DropDatabase with a database name that doesn''t exist' { - Remove-RivetTestDatabase - # Check that database doesn't exist first - (Test-Database) | Should -BeFalse + It 'handles non existent database' { + # Check that database doesn't exist first + (Test-Database $script:dbName) | Should -BeFalse - # Now drop the database - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -DropDatabase -Force -Database 'RivetTest' - $Global:Error.Count | Should -Be 0 - (Test-Database) | Should -BeFalse + # Now drop the database + WhenRivetInvoked -WithArgs @{ DropDatabase = $true ; Database = $script:dbName ; Force = $true} + ThenError -IsEmpty + (Test-Database $script:dbName) | Should -BeFalse + } } -} -Describe 'Invoke-Rivet' { - BeforeEach { Init -PluginPath 'InvokeRivetTestPlugin' } - AfterEach { Reset -Plugin 'InvokeRivetTestPlugin' } - It 'loads plugins' { - GivenFile 'InvokeRivetTestPlugin\InvokeRivetTestPlugin.psm1' @' -function MyPlugin + Context 'Plugins' { + AfterEach { + Get-Module -Name 'InvokeRivetTestPlugin*' | Remove-Module -Force + } + + It 'loads single plugin' { + GivenFile 'InvokeRivetTestPlugin1\InvokeRivetTestPlugin1.psm1' -In $script:testDirPath @' +function MyPlugin1 { } '@ - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - Get-Module -Name 'InvokeRivetTestPlugin' | Should -Not -BeNullOrEmpty - } -} + $rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -PluginPath 'InvokeRivetTestPlugin1' -PassThru + Invoke-Rivet -ConfigFilePath $rivetJsonPath -Database $script:dbName -Push + Get-Module -Name 'InvokeRivetTestPlugin1' | Should -Not -BeNullOrEmpty + Get-Command -Name 'MyPlugin1' | Should -Not -BeNullOrEmpty + } -Describe 'Invoke-Rivet' { - BeforeEach { Init -PluginPath 'InvokeRivetTestPlugin','InvokeRivetTestPlugin2' } - AfterEach { Reset -Plugin 'InvokeRivetTestPlugin','InvokeRivetTestPlugin2' } - It 'loads multiple plugins' { - GivenFile 'InvokeRivetTestPlugin\InvokeRivetTestPlugin.psm1' @' -function MyPlugin + It 'loads multiple plugins' { + GivenFile 'InvokeRivetTestPlugin2\InvokeRivetTestPlugin2.psm1' -In $script:testDirPath @' +function MyPlugin2 { } '@ - GivenFile 'InvokeRivetTestPlugin2\InvokeRivetTestPlugin2.psm1' @' -function MyPlugin2 + GivenFile 'InvokeRivetTestPlugin3\InvokeRivetTestPlugin3.psm1' -In $script:testDirPath @' +function MyPlugin3 { } '@ - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - Get-Module -Name 'InvokeRivetTestPlugin' | Should -Not -BeNullOrEmpty - Get-Module -Name 'InvokeRivetTestPlugin2' | Should -Not -BeNullOrEmpty - } -} + $rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath ` + -PluginPath 'InvokeRivetTestPlugin2', 'InvokeRivetTestPlugin3' ` + -PassThru + Invoke-Rivet -ConfigFilePath $rivetJsonPath -Database $script:dbName -Push + Get-Module -Name 'InvokeRivetTestPlugin2' | Should -Not -BeNullOrEmpty + Get-Command -Name 'MyPlugin2' | Should -Not -BeNullOrEmpty + Get-Module -Name 'InvokeRivetTestPlugin3' | Should -Not -BeNullOrEmpty + Get-Command -Name 'MyPlugin3' | Should -Not -BeNullOrEmpty + } -Describe 'Invoke-Rivet' { - BeforeEach { Init -PluginPath 'InvokeRivetTestPlugin' } - AfterEach { Reset -Plugin 'InvokeRivetTestPlugin' } - It 'reloads plugins' { - GivenFile 'InvokeRivetTestPlugin\InvokeRivetTestPlugin.psm1' @' -function MyPlugin + It 'reloads plugins' { + GivenFile 'InvokeRivetTestPlugin4\InvokeRivetTestPlugin4.psm1' -In $script:testDirPath @' +function MyPlugin4 { } '@ - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - Get-Module -Name 'InvokeRivetTestPlugin' | Should -Not -BeNullOrEmpty - Get-Command -Name 'MyPlugin' | Should -Not -BeNullOrEmpty - - # Now, change the module. - GivenFile 'InvokeRivetTestPlugin\InvokeRivetTestPlugin.psm1' @' -function NewMyPlugin + $rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -PluginPath 'InvokeRivetTestPlugin4' -PassThru + Invoke-Rivet -ConfigFilePath $rivetJsonPath -Database $script:dbName -Push + Get-Module -Name 'InvokeRivetTestPlugin4' | Should -Not -BeNullOrEmpty + Get-Command -Name 'MyPlugin4' | Should -Not -BeNullOrEmpty + + # Now, change the module. + GivenFile 'InvokeRivetTestPlugin4\InvokeRivetTestPlugin4.psm1' -In $script:testDirPath @' +function MyPlugin5 { } '@ - Invoke-Rivet -ConfigFilePath $RTConfigFilePath -Database $RTDatabaseName -Push - Get-Module -Name 'InvokeRivetTestPlugin' | Should -Not -BeNullOrEmpty - Get-Command -Name 'MyPlugin' -ErrorAction Ignore | Should -BeNullOrEmpty - Get-Command -Name 'NewMyPlugin' | Should -Not -BeNullOrEmpty + Invoke-Rivet -ConfigFilePath $rivetJsonPath -Database $script:dbName -Push + Get-Module -Name 'InvokeRivetTestPlugin4' | Should -Not -BeNullOrEmpty + Get-Command -Name 'MyPlugin4' -ErrorAction Ignore | Should -BeNullOrEmpty + Get-Command -Name 'MyPlugin5' | Should -Not -BeNullOrEmpty + } } } diff --git a/Test/Pop-Migration.Tests.ps1 b/Test/Pop-Migration.Tests.ps1 index c82d3b19..b74601ea 100644 --- a/Test/Pop-Migration.Tests.ps1 +++ b/Test/Pop-Migration.Tests.ps1 @@ -4,267 +4,387 @@ Set-StrictMode -Version 'Latest' BeforeAll { Set-StrictMode -Version 'Latest' + & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) + Remove-Item -Path 'alias:GivenMigration' + Remove-Item -Path 'alias:ThenTable' + + $script:testDirPath = $null + $script:testNum = 0 + $script:rivetJsonPath = $null + $script:dbName = 'Pop-Migration' $script:migration1 = $null $script:migration2 = $null $script:migration3 = $null $script:migration4 = $null -} -Describe 'Pop-Migration' { - BeforeEach { - Start-RivetTest - $Global:Error.Clear() + $script:migrationCount = 0 - $script:migration1 = @' - function Push-Migration + function GivenMigration { - Add-Table 'Migration1' { int ID -Identity } - } - function Pop-Migration - { - Remove-Table 'Migration1' - } -'@ | New-TestMigration -Name 'Migration1' + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, - $script:migration2 = @' - function Push-Migration - { - Add-Table 'Migration2' { int ID -Identity } - } - function Pop-Migration - { - Remove-Table 'Migration2' - } -'@ | New-TestMigration -Name 'Migration2' + [Parameter(Mandatory, Position=1)] + [String] $WithContent + ) - $script:migration3 = @' - function Push-Migration - { - Add-Table 'Migration3' { int ID -Identity } + $WithContent | New-TestMigration -Name $Named -ConfigFilePath $script:rivetJsonPath -DatabaseName $script:dbName } - function Pop-Migration - { - Remove-Table 'Migration3' - } -'@ | New-TestMigration -Name 'Migration3' - $script:migration4 = @' - function Push-Migration + function ThenMigrationsTable { - Add-Table 'Migration4' { int ID -Identity } + [CmdletBinding()] + param( + [UInt32] $HasCount, + + [switch] $IsNotEmpty, + + [switch] $IsEmpty, + + [UInt32] $Lost + ) + + $count = Measure-Migration -InDatabase $script:dbName + + if ($PSBoundParameters.ContainsKey('HasCount')) + { + $count | Should -Be $HasCount + } + + if ($PSBoundParameters.ContainsKey('IsNotEmpty')) + { + $count | Should -BeGreaterThan 0 + } + + if ($PSBoundParameters.ContainsKey('IsEmpty')) + { + $count | Should -Be 0 + } + + if ($PSBoundParameters.ContainsKey('Lost')) + { + $count | Should -Be ($script:migrationCount - $Lost) + } } - function Pop-Migration + + function ThenTable { - Remove-Table 'Migration4' - } -'@ | New-TestMigration -Name 'Migration4' + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, - Invoke-RTRivet -Push + [switch] $Not, - $expectedCount = Measure-MigrationScript - (Measure-Migration) | Should -Be $expectedCount - } + [Parameter(Mandatory)] + [switch] $Exists + ) - AfterEach { - Stop-RivetTest + Assert-Table -Name $Named -Not:$Not -Exists -DatabaseName $script:dbName } - It 'should pop all migrations' { - $migrationCount = Measure-Migration - ($migrationCount -gt 1) | Should -BeTrue + function WhenPopping + { + [CmdletBinding(DefaultParameterSetName='LastMigration')] + param( + [Parameter(Mandatory, ParameterSetName='ByCount')] + [UInt32] $Count, - Invoke-RTRivet -Pop $migrationCount + [Parameter(Mandatory, ParameterSetName='ByName')] + [String] $Named, - (Measure-Migration) | Should -Be 0 + [Parameter(Mandatory, ParameterSetName='ByID')] + [String] $WithID, - Get-MigrationScript | ForEach-Object { + [Parameter(Mandatory, ParameterSetName='All')] + [switch] $All, - $id,$name = $_.BaseName -split '_' + [Parameter(ParameterSetName='All')] + [switch] $Force + ) - (Test-Table -Name $name) | Should -BeFalse + $commonArgs = @{ + ConfigFilePath = $script:rivetJsonPath + } + + if ($PSCmdlet.ParameterSetName -eq 'ByCount') + { + Invoke-Rivet -Pop -Count $Count @commonArgs + } + elseif ($PSCmdlet.ParameterSetName -eq 'ByName') + { + Invoke-Rivet -Pop -Name $Named @commonArgs + } + elseif ($PSCmdlet.ParameterSetName -eq 'ByID') + { + Invoke-Rivet -Pop -Name $WithID @commonArgs + } + elseif ($PSCmdlet.ParameterSetName -eq 'All') + { + Invoke-Rivet -Pop -All -Force:$Force @commonArgs + } + else + { + Invoke-Rivet -Pop @commonArgs } } +} - It 'should write to activity table on pop' { - $migrationCount = Measure-Migration - ($migrationCount -gt 1) | Should -BeTrue +Describe 'Pop-Migration' { + BeforeAll { + Remove-RivetTestDatabase -Name $script:dbName + } + + BeforeEach { + $script:testDirPath = Join-Path -Path $TestDrive -ChildPath ($script:testNum++) + New-Item -Path $script:testDirPath -ItemType Directory + $script:migrations = @() + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -Database $script:dbName -PassThru + $script:result = $null + $Global:Error.Clear() - Invoke-RTRivet -Pop + $script:migration1 = GivenMigration 'Migration1' @' + function Push-Migration + { + Add-Table 'Migration1' { int ID -Identity } + } + function Pop-Migration + { + Remove-Table 'Migration1' + } +'@ + + $script:migration2 = GivenMigration 'Migration2' @' + function Push-Migration + { + Add-Table 'Migration2' { int ID -Identity } + } + function Pop-Migration + { + Remove-Table 'Migration2' + } +'@ + + $script:migration3 = GivenMigration 'Migration3' @' + function Push-Migration + { + Add-Table 'Migration3' { int ID -Identity } + } + function Pop-Migration + { + Remove-Table 'Migration3' + } +'@ + + $script:migration4 = GivenMigration 'Migration4' @' + function Push-Migration + { + Add-Table 'Migration4' { int ID -Identity } + } + function Pop-Migration + { + Remove-Table 'Migration4' + } +'@ + + Invoke-Rivet -Push -ConfigFilePath $script:rivetJsonPath + + $dbMigrationsDirPath = + Join-Path -Path $script:testDirPath -ChildPath "Databases\${script:dbName}" -Resolve + $expectedCount = Measure-MigrationScript -In $dbMigrationsDirPath + ThenMigrationsTable -HasCount $expectedCount + + $script:migrationCount = Measure-Migration -InDatabase $script:dbName + } - (Measure-Migration) | Should -Be ($migrationCount-1) + AfterEach { + Invoke-Rivet -Pop -All -Force -ConfigFilePath $script:rivetJsonPath + } - $rows = Get-ActivityInfo + It 'should pop all migrations' { + ThenMigrationsTable -IsNotEmpty + ThenTable 'Migration1' -Exists + ThenTable 'Migration2' -Exists + ThenTable 'Migration3' -Exists + ThenTable 'Migration4' -Exists + WhenPopping -Count $script:migrationCount + ThenMigrationsTable -Lost $script:migrationCount + ThenTable 'Migration1' -Not -Exists + ThenTable 'Migration2' -Not -Exists + ThenTable 'Migration3' -Not -Exists + ThenTable 'Migration4' -Not -Exists + } + + It 'should write to activity table on pop' { + ThenMigrationsTable -IsNotEmpty + WhenPopping + ThenMigrationsTable -Lost 1 + + $rows = Get-ActivityInfo -DatabaseName $script:dbName $rows[-1].Operation | Should -Be 'Pop' $rows[-1].Name | Should -Be 'Migration4' } It 'should pop specific number of database migrations' { - $rivetCount = Measure-Migration - ($rivetCount -gt 1) | Should -BeTrue - - Invoke-RTRivet -Pop 2 - - (Measure-Migration) | Should -Be ($rivetCount - 2) + ThenMigrationsTable -IsNotEmpty + WhenPopping -Count 2 + ThenMigrationsTable -Lost 2 } It 'should pop one migration by default' { - $totalMigrations = Measure-Migration - - Invoke-RTRivet -Pop - - (Measure-Migration) | Should -Be ($totalMigrations - 1) - - $firstMigration = Get-MigrationScript | Select-Object -First 1 - - $id,$name = $firstMigration.BaseName -split '_' - (Test-Table -Name $name) | Should -BeTrue + WhenPopping + ThenMigrationsTable -Lost 1 + ThenTable 'Migration4' -Not -Exists + ThenTable 'Migration3' -Exists + ThenTable 'Migration2' -Exists + ThenTable 'Migration1' -Exist } It 'should not re pop migrations' { - $originalMigrationCount = Measure-Migration - Invoke-RTRivet -Pop - $Global:Error.Count | Should -Be 0 - (Measure-Migration) | Should -Be ($originalMigrationCount - 1) - - Invoke-RTRivet -Pop 2 - $Global:Error.Count | Should -Be 0 - (Measure-Migration) | Should -Be ($originalMigrationCount - 2) - - Invoke-RTRivet -Pop 2 - $Global:Error.Count | Should -Be 0 - (Measure-Migration) | Should -Be ($originalMigrationCount - 2) + WhenPopping + ThenError -IsEmpty + ThenMigrationsTable -Lost 1 + + WhenPopping -Count 2 + ThenError -IsEmpty + ThenMigrationsTable -Lost 3 + + WhenPopping -Count 2 + ThenError -IsEmpty + ThenMigrationsTable -Lost $script:migrationCount } It 'should support popping more than available migrations' { - $migrationCount = Measure-Migration - Invoke-RTRivet -Pop ($migrationCount * 2) - $Global:Error.Count | Should -Be 0 - (Measure-Migration) | Should -Be 0 + WhenPopping -Count ($script:migrationCount * 2) + ThenError -IsEmpty + ThenMigrationsTable -IsEmpty } It 'should stop popping migrations if one gives an error' { - $migrationFileInfo = @' - function Push-Migration - { - Add-Table 'Migration5' { - int 'ID' -Identity - } - } - - function Pop-Migration - { - Remove-Table 'Migration38' - } -'@ | New-TestMigration -Name 'PopFails' + $m = GivenMigration 'PopFails' @' + function Push-Migration + { + Add-Table 'Migration5' { + int 'ID' -Identity + } + } + + function Pop-Migration + { + Remove-Table 'DoNotExist' + } +'@ try { - Invoke-RTRivet -Push - $Global:Error.Count | Should -Be 0 + Invoke-Rivet -Push -ConfigFilePath $script:rivetJsonPath + ThenError -IsEmpty - { Invoke-RTRivet -Pop (Measure-Migration) } | Should -Throw '*cannot drop the table ''dbo.Migration38''*' + { WhenPopping -All } | Should -Throw '*cannot drop the table ''dbo.DoNotExist''*' $Global:Error.Count | Should -BeGreaterThan 0 - (Test-Table -Name 'Migration5') | Should -BeTrue - (Test-Table -Name 'Migration4') | Should -BeTrue - (Test-Table -Name 'Migration3') | Should -BeTrue - (Test-Table -Name 'Migration2') | Should -BeTrue - (Test-Table -Name 'Migration1') | Should -BeTrue + ThenTable 'Migration5' -Exists + ThenTable 'Migration4' -Exists + ThenTable 'Migration3' -Exists + ThenTable 'Migration2' -Exists + ThenTable 'Migration1' -Exists } finally { @' - function Push-Migration - { - Add-Table 'Migration5' { - int 'ID' -Identity - } - } - - function Pop-Migration - { - Remove-Table 'Migration5' - } -'@ | Set-Content -Path $migrationFileInfo + function Push-Migration + { + Add-Table 'Migration5' { + int 'ID' -Identity + } + } + + function Pop-Migration + { + Remove-Table 'Migration5' + } +'@ | Set-Content -Path $m.FullName } } It 'should pop by name' { - Invoke-RTRivet -Pop 'Migration1' + WhenPopping -Named 'Migration1' - (Test-Table -Name 'Migration4') | Should -BeTrue - (Test-Table -Name 'Migration3') | Should -BeTrue - (Test-Table -Name 'Migration2') | Should -BeTrue - (Test-Table -Name 'Migration1') | Should -BeFalse + ThenTable 'Migration4' -Exists + ThenTable 'Migration3' -Exists + ThenTable 'Migration2' -Exists + ThenTable 'Migration1' -Not -Exists } It 'should pop by name with wildcard' { - Invoke-RTRivet -Pop 'Migration*' + WhenPopping -Named 'Migration*' - (Test-Table -Name 'Migration4') | Should -BeFalse - (Test-Table -Name 'Migration3') | Should -BeFalse - (Test-Table -Name 'Migration2') | Should -BeFalse - (Test-Table -Name 'Migration1') | Should -BeFalse + ThenTable 'Migration4' -Not -Exists + ThenTable 'Migration3' -Not -Exists + ThenTable 'Migration2' -Not -Exists + ThenTable 'Migration1' -Not -Exists } It 'should pop by name with no match' { - { Invoke-RTRivet -Pop 'Blah' } | Should -Throw '*Blah*does not exist*' + { WhenPopping -Named 'Blah' } | Should -Throw '*Blah*does not exist*' - (Test-Table -Name 'Migration4') | Should -BeTrue - (Test-Table -Name 'Migration3') | Should -BeTrue - (Test-Table -Name 'Migration2') | Should -BeTrue - (Test-Table -Name 'Migration1') | Should -BeTrue + ThenTable 'Migration4' -Exists + ThenTable 'Migration3' -Exists + ThenTable 'Migration2' -Exists + ThenTable 'Migration1' -Exists } It 'should pop by ID' { - $name = $script:migration1.BaseName.Substring(0,14) - Invoke-RTRivet -Pop $name - Assert-Table -Name 'Migration4' - Assert-Table -Name 'Migration3' - Assert-Table -Name 'Migration2' - (Test-Table -Name 'Migration1') | Should -BeFalse + $id = $script:migration1.BaseName.Substring(0,14) + WhenPopping -WithID $id + ThenTable 'Migration4' -Exists + ThenTable 'Migration3' -Exists + ThenTable 'Migration2' -Exists + ThenTable 'Migration1' -Not -Exists } It 'should pop by ID with wildcard' { - $name = '{0}*' -f $RTTimestamp.ToString().Substring(0,8) - Invoke-RTRivet -Pop $name - (Test-Table -Name 'Migration4') | Should -BeFalse - (Test-Table -Name 'Migration3') | Should -BeFalse - (Test-Table -Name 'Migration2') | Should -BeFalse - (Test-Table -Name 'Migration1') | Should -BeFalse + WhenPopping -WithID '20150101*' + ThenMigrationsTable -IsEmpty + ThenTable 'Migration4' -Not -Exists + ThenTable 'Migration3' -Not -Exists + ThenTable 'Migration2' -Not -Exists + ThenTable 'Migration1' -Not -Exists } It 'should pop all' { - Invoke-RTRivet -Pop -All - (Test-Table -Name 'Migration4') | Should -BeFalse - (Test-Table -Name 'Migration3') | Should -BeFalse - (Test-Table -Name 'Migration2') | Should -BeFalse - (Test-Table -Name 'Migration1') | Should -BeFalse + WhenPopping -All + ThenTable 'Migration4' -Not -Exists + ThenTable 'Migration3' -Not -Exists + ThenTable 'Migration2' -Not -Exists + ThenTable 'Migration1' -Not -Exists } It 'should confirm popping anothers migration' { - Invoke-RivetTestQuery -Query 'update [rivet].[Migrations] set Who = ''LittleLionMan''' - - Invoke-RTRivet -Pop -All -Force - (Test-Table 'Migration4') | Should -BeFalse - (Test-Table 'Migration3') | Should -BeFalse - (Test-Table 'Migration2') | Should -BeFalse - (Test-Table 'Migration1') | Should -BeFalse + Invoke-RivetTestQuery -Query 'update [rivet].[Migrations] set Who = ''LittleLionMan''' ` + -DatabaseName $script:dbName + + WhenPopping -All -Force + ThenTable 'Migration4' -Not -Exists + ThenTable 'Migration3' -Not -Exists + ThenTable 'Migration2' -Not -Exists + ThenTable 'Migration1' -Not -Exists } It 'should confirm popping old migrations' { - Invoke-RivetTestQuery -Query 'update [rivet].[Migrations] set AtUtc = dateadd(minute, -21, AtUtc)' - - Invoke-RTRivet -Pop -All -Force - (Test-Table 'Migration4') | Should -BeFalse - (Test-Table 'Migration3') | Should -BeFalse - (Test-Table 'Migration2') | Should -BeFalse - (Test-Table 'Migration1') | Should -BeFalse + Invoke-RivetTestQuery -Query 'update [rivet].[Migrations] set AtUtc = dateadd(minute, -21, AtUtc)' ` + -DatabaseName $script:dbName + + WhenPopping -All -Force + ThenTable 'Migration4' -Not -Exists + ThenTable 'Migration3' -Not -Exists + ThenTable 'Migration2' -Not -Exists + ThenTable 'Migration1' -Not -Exists } } diff --git a/Test/Remove-DataType.Tests.ps1 b/Test/Remove-DataType.Tests.ps1 index 6c4cb888..f029495a 100644 --- a/Test/Remove-DataType.Tests.ps1 +++ b/Test/Remove-DataType.Tests.ps1 @@ -5,41 +5,63 @@ Set-StrictMode -Version 'Latest' BeforeAll { Set-StrictMode -Version 'Latest' - & (Join-Path -Path $PSScriptRoot -ChildPath 'RivetTest\Import-RivetTest.ps1' -Resolve) + & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) + Remove-Item -Path 'alias:GivenMigration' + + $script:testDirPath = $null + $script:testNum = 0 + $script:rivetJsonPath = $null + $script:dbName = 'Remove-DataType' + + function GivenMigration + { + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, + + [Parameter(Mandatory, Position=1)] + [String] $WithContent + ) + + $WithContent | New-TestMigration -Name $Named -ConfigFilePath $script:rivetJsonPath -DatabaseName $script:dbName + } } Describe 'Remove-DataType' { BeforeEach { - Start-RivetTest + $script:testDirPath = Join-Path -Path $TestDrive -ChildPath ($script:testNum++) + New-Item -Path $script:testDirPath -ItemType Directory + $script:migrations = @() + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -Database $script:dbName -PassThru + $Global:Error.Clear() } AfterEach { - Stop-RivetTest + Invoke-Rivet -Pop -All -Force -ConfigFilePath $script:rivetJsonPath } It 'should remove data type by table' { # Yes. Spaces in names so we check that the names get quoted. - @' -function Push-Migration -{ - Add-DataType 'Users DT' -AsTable { varchar 'Name' 50 } -TableConstraint 'primary key' -} - -function Pop-Migration -{ - Remove-DataType 'Users DT' -} + GivenMigration 'ByTable' @' + function Push-Migration + { + Add-DataType 'Users DT' -AsTable { varchar 'Name' 50 } -TableConstraint 'primary key' + } -'@ | New-TestMigration -Name 'ByTable' + function Pop-Migration + { + Remove-DataType 'Users DT' + } +'@ - Invoke-RTRivet -Push 'ByTable' + Invoke-Rivet -Push -ConfigFilePath $script:rivetJsonPath - $temp = Invoke-RivetTestQuery -Query 'select * from sys.table_types' - $temp | Should -Not -BeNullOrEmpty - 'Users DT' | Should -Be $temp.name + $temp = Invoke-RivetTestQuery -Query 'select * from sys.table_types' -DatabaseName $script:dbName + $temp | Should -Not -BeNullOrEmpty + 'Users DT' | Should -Be $temp.name - Invoke-RTRivet -Pop 1 - $temp = Invoke-RivetTestQuery -Query 'select * from sys.table_types' - $temp | Should -BeNullOrEmpty + Invoke-Rivet -Pop -ConfigFilePath $script:rivetJsonPath + $temp = Invoke-RivetTestQuery -Query 'select * from sys.table_types' -DatabaseName $script:dbName + $temp | Should -BeNullOrEmpty } } diff --git a/Test/Remove-Synonym.Tests.ps1 b/Test/Remove-Synonym.Tests.ps1 index 46431322..c1e48ea6 100644 --- a/Test/Remove-Synonym.Tests.ps1 +++ b/Test/Remove-Synonym.Tests.ps1 @@ -5,20 +5,43 @@ Set-StrictMode -Version 'Latest' BeforeAll { Set-StrictMode -Version 'Latest' - & (Join-Path -Path $PSScriptRoot -ChildPath 'RivetTest\Import-RivetTest.ps1' -Resolve) + & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) + Remove-Item -Path 'alias:GivenMigration' + + $script:testDirPath = $null + $script:testNum = 0 + $script:rivetJsonPath = $null + $script:dbName = 'Remove-Synonym' + + function GivenMigration + { + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, + + [Parameter(Mandatory, Position=1)] + [String] $WithContent + ) + + $WithContent | New-TestMigration -Name $Named -ConfigFilePath $script:rivetJsonPath -DatabaseName $script:dbName + } } Describe 'Remove-Synonym' { BeforeEach { - Start-RivetTest + $script:testDirPath = Join-Path -Path $TestDrive -ChildPath ($script:testNum++) + New-Item -Path $script:testDirPath -ItemType Directory + $script:migrations = @() + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -Database $script:dbName -PassThru + $Global:Error.Clear() } AfterEach { - Stop-RivetTest + Invoke-Rivet -Pop -All -Force -ConfigFilePath $script:rivetJsonPath } It 'should remove synonym' { - @' + GivenMigration 'RemoveSynonym' @' function Push-Migration { Add-Synonym -Name 'Buzz' -TargetObjectName 'Fizz' @@ -28,13 +51,13 @@ Describe 'Remove-Synonym' { { Remove-Synonym -Name 'Buzz' } -'@ | New-TestMigration -Name 'RemoveSynonym' +'@ - Invoke-RTRivet -Push 'RemoveSynonym' - Assert-Synonym -Name 'Buzz' -TargetObjectName '[dbo].[Fizz]' + Invoke-Rivet -Push 'RemoveSynonym' -ConfigFilePath $script:rivetJsonPath + Assert-Synonym -Name 'Buzz' -TargetObjectName '[dbo].[Fizz]' -DatabaseName $script:dbName - Invoke-RTRivet -Pop 1 + Invoke-Rivet -Pop -ConfigFilePath $script:rivetJsonPath - (Get-Synonym -Name 'Buzz') | Should -BeNullOrEmpty + (Get-Synonym -Name 'Buzz' -DatabaseName $script:dbName) | Should -BeNullOrEmpty } } diff --git a/Test/Remove-Table.Tests.ps1 b/Test/Remove-Table.Tests.ps1 index 6bddd41d..2149fbec 100644 --- a/Test/Remove-Table.Tests.ps1 +++ b/Test/Remove-Table.Tests.ps1 @@ -5,45 +5,110 @@ Set-StrictMode -Version 'Latest' BeforeAll { Set-StrictMode -Version 'Latest' - & (Join-Path -Path $PSScriptRoot -ChildPath 'RivetTest\Import-RivetTest.ps1' -Resolve) -} + & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) + Remove-Item -Path 'alias:GivenMigration' + Remove-Item -Path 'alias:ThenTable' -Describe 'Remove-Table' { - BeforeEach { - Start-RivetTest - } + $script:testDirPath = $null + $script:testNum = 0 + $script:rivetJsonPath = $null + $script:dbName = 'Remove-Table' - AfterEach { - Stop-RivetTest + function GivenMigration + { + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, + + [Parameter(Mandatory, Position=1)] + [String] $WithContent + ) + + $WithContent | New-TestMigration -Name $Named -ConfigFilePath $script:rivetJsonPath -DatabaseName $script:dbName } - It 'should remove table' { - @' - function Push-Migration() + function ThenTable { - Add-Table -Name 'Ducati' { - Int 'ID' -Identity - } # -SchemaName + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, + + [String] $InSchema, + + [switch] $Not, + + [Parameter(Mandatory)] + [switch] $Exists + ) + + $schemaArg = @{} + if ($InSchema) + { + $schemaArg['SchemaName'] = $InSchema + } + + $exists = Test-Table -Name $Named -DatabaseName $script:dbName @schemaArg + if ($Not) + { + $exists | Should -BeFalse + } + else + { + $exists | Should -BeTrue + } + } + function WhenPopping + { + Invoke-Rivet -Pop -ConfigFilePath $script:rivetJsonPath } - function Pop-Migration() + function WhenPushing { - Remove-Table -Name 'Ducati' + Invoke-Rivet -Push -ConfigFilePath $script:rivetJsonPath } -'@ | New-TestMigration -Name 'AddTable' - Invoke-RTRivet -Push 'AddTable' - (Test-Table 'Ducati') | Should -BeTrue +} - Invoke-RTRivet -Pop ([Int32]::MaxValue) - (Test-Table 'Ducati') | Should -BeFalse +Describe 'Remove-Table' { + BeforeAll { + Remove-RivetTestDatabase -Name $script:dbName } - It 'should remove table in custom schema' { - $Name = 'Ducati' - $CustomSchemaName = 'notDbo' + BeforeEach { + $script:testDirPath = Join-Path -Path $TestDrive -ChildPath ($script:testNum++) + New-Item -Path $script:testDirPath -ItemType Directory + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -Database $script:dbName -PassThru + $Global:Error.Clear() + } - @' + AfterEach { + Invoke-Rivet -Pop -All -Force -ConfigFilePath $script:rivetJsonPath + } + + It 'should remove table' { + GivenMigration 'AddTable' @' + function Push-Migration() + { + Add-Table -Name 'Ducati' { + Int 'ID' -Identity + } # -SchemaName + + } + + function Pop-Migration() + { + Remove-Table -Name 'Ducati' + } +'@ + WhenPushing + ThenTable 'Ducati' -Exists + + WhenPopping + ThenTable 'Ducati' -Not -Exists + } + + It 'should remove table in custom schema' { + GivenMigration 'AddTablesInDifferentSchemas' @' function Push-Migration() { Add-Table -Name 'Ducati' { @@ -51,26 +116,26 @@ Describe 'Remove-Table' { } Add-Schema -Name 'notDbo' - Add-Table -Name 'Ducati' { + Add-Table -Name 'DucatiNotDbo' { Int 'ID' -Identity } -SchemaName 'notDbo' } function Pop-Migration() { - Remove-Table -Name 'Ducati' -SchemaName 'notDbo' + Remove-Table -Name 'DucatiNotDbo' -SchemaName 'notDbo' Remove-Table 'Ducati' Remove-Schema 'notDbo' } -'@ | New-TestMigration -Name 'AddTablesInDifferentSchemas' +'@ - Invoke-RTRivet -Push 'AddTablesInDifferentSchemas' + WhenPushing - (Test-Table -Name $Name) | Should -BeTrue - (Test-Table -Name $Name -SchemaName $CustomSchemaName) | Should -BeTrue + ThenTable 'Ducati' -Exists + ThenTable 'DucatiNotDbo' -InSchema 'notDbo' -Exists - Invoke-RTRivet -Pop ([Int32]::MaxValue) - (Test-Table -Name $Name) | Should -BeFalse - (Test-Table -Name $Name -SchemaName $CustomSchemaName) | Should -BeFalse + WhenPopping + ThenTable 'Ducati' -Not -Exists + ThenTable 'DucatiNotDbo' -InSchema 'notDbo' -Not -Exists } } diff --git a/Test/RivetTest/Functions/Assert-Column.ps1 b/Test/RivetTest/Functions/Assert-Column.ps1 index 16dfbb95..f33cff51 100644 --- a/Test/RivetTest/Functions/Assert-Column.ps1 +++ b/Test/RivetTest/Functions/Assert-Column.ps1 @@ -2,68 +2,57 @@ function Assert-Column { param( - [Parameter(Position=0,Mandatory=$true)] - [string] - $Name, + [Parameter(Position=0, Mandatory)] + [String] $Name, - [Parameter(Position=1,Mandatory=$true)] - [string] + [Parameter(Position=1, Mandatory)] + [String] $DataType, $Description, - [Switch] - $Max, + [switch] $Max, - [int] - $Size, + [int] $Size, - [int] - $Precision, + [int] $Precision, - [int] - $Scale, + [int] $Scale, - [Switch] - $Sparse, + [switch] $Sparse, - [Switch] - $NotNull, + [switch] $NotNull, - [int] - $Seed, + [int] $Seed, - [int] - $Increment, + [int] $Increment, - [Switch] - $NotForReplication, + [switch] $NotForReplication, - [Switch] - $RowGuidCol, + [switch] $RowGuidCol, - [Switch] - $Document, + [switch] $Document, - [Switch] - $FileStream, + [switch] $FileStream, - [string] - $Collation, + [String] $Collation, - [Object] - $Default, + [Object] $Default, - [Parameter(Mandatory=$true)] - $TableName, + [Parameter(Mandatory)] + [String] $TableName, [Alias('TableSchema')] - $SchemaName = 'dbo' + [String] $SchemaName = 'dbo', + + [String] $DefaultConstraintName, + + [String] $DatabaseName ) Set-StrictMode -Version Latest - $column = Get-Column -SchemaName $SchemaName -TableName $TableName -Name $Name + $column = Get-Column -SchemaName $SchemaName -TableName $TableName -Name $Name -DatabaseName $DatabaseName $column | Should -Not -BeNullOrEmpty @@ -113,8 +102,11 @@ function Assert-Column if( $Default ) { $column.default_constraint | Should -Not -BeNullOrEmpty - $dfConstraintName = New-RTConstraintName -SchemaName $SchemaName -TableName $TableName -ColumnName $Name -Default - $column.default_constraint_name | Should -Be $dfConstraintName + if (-not $DefaultConstraintName) + { + $DefaultConstraintName = New-RTConstraintName -SchemaName $SchemaName -TableName $TableName -ColumnName $Name -Default + } + $column.default_constraint_name | Should -Be $DefaultConstraintName $column.default_constraint | Should -Match ('{0}' -f ([Text.RegularExpressions.Regex]::Escape($Default))) } diff --git a/Test/RivetTest/Functions/Assert-DefaultConstraint.ps1 b/Test/RivetTest/Functions/Assert-DefaultConstraint.ps1 index fdc9757c..6ddaefd2 100644 --- a/Test/RivetTest/Functions/Assert-DefaultConstraint.ps1 +++ b/Test/RivetTest/Functions/Assert-DefaultConstraint.ps1 @@ -9,23 +9,25 @@ function Assert-DefaultConstraint param( [Parameter(ParameterSetName='NoName')] # The table's schema. Default is `dbo`. - [string]$SchemaName = 'dbo', + [string] $SchemaName = 'dbo', [Parameter(Mandatory,ParameterSetName='NoName')] # The name of the table - [String]$TableName, + [String] $TableName, [Parameter(Mandatory,ParameterSetName='NoName')] # Array of Column Names - [String[]]$ColumnName, + [String[]] $ColumnName, [Parameter(Position=0)] # The name of the constraint. - [String]$Name, + [String] $Name, # The expected expression. [Alias('Definition')] - [String]$Is + [String] $Is, + + [String] $DatabaseName ) Set-StrictMode -Version Latest @@ -36,7 +38,7 @@ function Assert-DefaultConstraint $Name = New-RTConstraintName -ColumnName $ColumnName -TableName $TableName -SchemaName $SchemaName -Default } - $constraint = Get-DefaultConstraint -Name $Name + $constraint = Get-DefaultConstraint -Name $Name -DatabaseName $DatabaseName $constraint | Should -Not -BeNullOrEmpty -Because ('Default constraint "{0}" not found.' -f $Name) diff --git a/Test/RivetTest/Functions/Assert-Error.ps1 b/Test/RivetTest/Functions/Assert-Error.ps1 new file mode 100644 index 00000000..8dc8c69c --- /dev/null +++ b/Test/RivetTest/Functions/Assert-Error.ps1 @@ -0,0 +1,21 @@ + +function Assert-Error +{ + param( + [switch] $IsEmpty, + + [String] $MatchesRegex + ) + + if ($IsEmpty) + { + $Global:Error | Should -BeNullOrEmpty + } + + if ($MatchesRegex) + { + $Global:Error | Should -Match $MatchesRegex + } +} + +Set-Alias -Name 'ThenError' -Value 'Assert-Error' \ No newline at end of file diff --git a/Test/RivetTest/Functions/Assert-Schema.ps1 b/Test/RivetTest/Functions/Assert-Schema.ps1 index ce68df76..54624532 100644 --- a/Test/RivetTest/Functions/Assert-Schema.ps1 +++ b/Test/RivetTest/Functions/Assert-Schema.ps1 @@ -2,12 +2,11 @@ function Assert-Schema { param( - [Parameter(Mandatory=$true)] - [string] # The schema name. - $Name, + [Parameter(Mandatory)] + [String] $Name, - $DatabaseName + [String] $DatabaseName ) Set-StrictMode -Version 'Latest' diff --git a/Test/RivetTest/Functions/Assert-Synonym.ps1 b/Test/RivetTest/Functions/Assert-Synonym.ps1 index 15e8988a..85738f8d 100644 --- a/Test/RivetTest/Functions/Assert-Synonym.ps1 +++ b/Test/RivetTest/Functions/Assert-Synonym.ps1 @@ -2,23 +2,22 @@ function Assert-Synonym { param( - [Parameter(Mandatory=$true)] - [string] # The name of the synonym. - $Name, + [Parameter(Mandatory=$true)] + [String] $Name, - [string] # The synonym's schema. - $SchemaName = 'dbo', + [String] $SchemaName = 'dbo', - [string] # The base object name of what the synonym points to. - $TargetObjectName + [String] $TargetObjectName, + + [String] $DatabaseName ) Set-StrictMode -Version 'Latest' - $synonym = Get-Synonym -SchemaName $SchemaName -Name $Name + $synonym = Get-Synonym -SchemaName $SchemaName -Name $Name -DatabaseName $DatabaseName $synonym | Should -Not -BeNullOrEmpty -Because ('Synonym ''{0}.{1}'' not found.' -f $SchemaName,$Name) diff --git a/Test/RivetTest/Functions/Assert-Table.ps1 b/Test/RivetTest/Functions/Assert-Table.ps1 index 26e00ddb..543ce2dd 100644 --- a/Test/RivetTest/Functions/Assert-Table.ps1 +++ b/Test/RivetTest/Functions/Assert-Table.ps1 @@ -12,12 +12,14 @@ function Assert-Table [switch]$Not, - [switch]$Exists + [switch]$Exists, + + [String] $DatabaseName ) Set-StrictMode -Version Latest - $table = Get-Table -Name $Name -SchemaName $SchemaName | Select-Object -First 1 + $table = Get-Table -Name $Name -SchemaName $SchemaName -DatabaseName $DatabaseName | Select-Object -First 1 if( $Not -and $Exists ) { diff --git a/Test/RivetTest/Functions/Get-ActivityInfo.ps1 b/Test/RivetTest/Functions/Get-ActivityInfo.ps1 index 518ad7ac..b276f151 100644 --- a/Test/RivetTest/Functions/Get-ActivityInfo.ps1 +++ b/Test/RivetTest/Functions/Get-ActivityInfo.ps1 @@ -2,17 +2,18 @@ function Get-ActivityInfo { param( - [string] # The name of the activity whose info to get. Otherwise, returns all migrations. - $Name, + [string] $Name, + + [String] $DatabaseName, $Connection ) - + Set-StrictMode -Version Latest - $query = "select * from $($RTRivetSchemaName).Activity where MigrationID >= $($script:firstMigrationId)" - if( $Name ) + $query = "select * from [${RTRivetSchemaName}].[Activity] where MigrationID >= $($script:firstMigrationId)" + if ($Name) { $query = '{0} and name = ''{1}''' -f $query,$Name } @@ -22,9 +23,9 @@ function Get-ActivityInfo } $connParam = @{ } - if( $Connection ) + if ($Connection) { $connParam['Connection'] = $Connection } - Invoke-RivetTestQuery -Query $query @connParam + Invoke-RivetTestQuery -Query $query -DatabaseName $DatabaseName @connParam } diff --git a/Test/RivetTest/Functions/Get-Column.ps1 b/Test/RivetTest/Functions/Get-Column.ps1 index 5380d8c8..34749f7c 100644 --- a/Test/RivetTest/Functions/Get-Column.ps1 +++ b/Test/RivetTest/Functions/Get-Column.ps1 @@ -2,31 +2,32 @@ function Get-Column { param( - [Parameter(Position=0,Mandatory=$true)] - [string] - $Name, + [Parameter(Position=0, Mandatory)] + [String] $Name, - [Parameter(Mandatory=$true)] + [Parameter(Mandatory)] $TableName, [Alias('TableSchema')] - $SchemaName = 'dbo' + $SchemaName = 'dbo', + + [String] $DatabaseName ) - + Set-StrictMode -Version Latest $query = @' - select - ty.name type_name, - c.*, - ex.value MSDescription, - dc.name default_constraint_name, - dc.definition default_constraint, - ic.seed_value, - ic.increment_value, + select + ty.name type_name, + c.*, + ex.value MSDescription, + dc.name default_constraint_name, + dc.definition default_constraint, + ic.seed_value, + ic.increment_value, ic.is_not_for_replication - from sys.columns c join - sys.tables t on c.object_id = t.object_id join + from sys.columns c join + sys.tables t on c.object_id = t.object_id join sys.schemas s on t.schema_id = s.schema_id join sys.types ty on c.user_type_id = ty.user_type_id left outer join sys.extended_properties ex on ex.major_id = c.object_id and ex.minor_id = c.column_id and OBJECTPROPERTY(c.object_id, 'IsMsShipped') = 0 and ex.name = '{0}' left outer join @@ -35,5 +36,5 @@ function Get-Column where s.name = '{1}' and t.name = '{2}' and c.name = '{3}' '@ -f [Rivet.Operations.ExtendedPropertyOperation]::DescriptionPropertyName, $SchemaName, $TableName, $Name - Invoke-RivetTestQuery -Query $query + Invoke-RivetTestQuery -Query $query -DatabaseName $DatabaseName } diff --git a/Test/RivetTest/Functions/Get-DefaultConstraint.ps1 b/Test/RivetTest/Functions/Get-DefaultConstraint.ps1 index d400faa5..82d4733f 100644 --- a/Test/RivetTest/Functions/Get-DefaultConstraint.ps1 +++ b/Test/RivetTest/Functions/Get-DefaultConstraint.ps1 @@ -6,15 +6,16 @@ function Get-DefaultConstraint Gets the default constraints in a database. #> param( - [string] # The name of the default constraint to get. - $Name + [String] $Name, + + [String] $DatabaseName ) - + Set-StrictMode -Version Latest $query = @' - select * + select * from sys.default_constraints '@ if( $Name ) @@ -25,7 +26,7 @@ function Get-DefaultConstraint [name] = '{1}' '@ -f $query,$Name } - - Invoke-RivetTestQuery -Query $query + + Invoke-RivetTestQuery -Query $query -DatabaseName $DatabaseName } diff --git a/Test/RivetTest/Functions/Get-MigrationScript.ps1 b/Test/RivetTest/Functions/Get-MigrationScript.ps1 index 8d2804cb..d82a7635 100644 --- a/Test/RivetTest/Functions/Get-MigrationScript.ps1 +++ b/Test/RivetTest/Functions/Get-MigrationScript.ps1 @@ -2,10 +2,11 @@ function Get-MigrationScript { param( + [String] $In = $RTDatabaseRoot ) Set-StrictMode -Version Latest - - $migrationDir = Join-Path $RTDatabaseRoot Migrations -Resolve + + $migrationDir = Join-Path -Path $In -ChildPath 'Migrations' -Resolve Get-ChildItem $migrationDir *.ps1 | Sort-Object BaseName } diff --git a/Test/RivetTest/Functions/Get-Schema.ps1 b/Test/RivetTest/Functions/Get-Schema.ps1 index e3e8f2c0..10540cd6 100644 --- a/Test/RivetTest/Functions/Get-Schema.ps1 +++ b/Test/RivetTest/Functions/Get-Schema.ps1 @@ -2,28 +2,27 @@ function Get-Schema { param( - [string] # The name of the schema. Optional. Returns all schemas otherwise. - $Name, + [String] $Name, - $DatabaseName + [String] $DatabaseName ) - + Set-StrictMode -Version Latest $query = @' - select + select *, p.name principal_name - from - sys.schemas s inner join + from + sys.schemas s inner join sys.database_principals p on s.principal_id = p.principal_id '@ if( $Name ) { $query = '{0} where s.name = ''{1}''' -f $query,$Name } - + Invoke-RivetTestQuery -Query $query -DatabaseName $DatabaseName } diff --git a/Test/RivetTest/Functions/Get-Synonym.ps1 b/Test/RivetTest/Functions/Get-Synonym.ps1 index 822c2259..c43021f2 100644 --- a/Test/RivetTest/Functions/Get-Synonym.ps1 +++ b/Test/RivetTest/Functions/Get-Synonym.ps1 @@ -6,22 +6,22 @@ function Get-Synonym Gets a synonym. #> param( - [Parameter(Mandatory=$true)] - [string] # The name of the synonym. - $Name, + [Parameter(Mandatory)] + [String] $Name, - [string] # The synonym's schema. - $SchemaName = 'dbo' + [String] $SchemaName = 'dbo', + + [String] $DatabaseName ) - + Set-StrictMode -Version Latest $query = @' - select - sc.name, sy.* - from + select + sc.name, sy.* + from sys.synonyms sy join sys.schemas sc on sy.schema_id = sc.schema_id where @@ -29,6 +29,6 @@ function Get-Synonym sy.name = '{1}' '@ -f $SchemaName,$Name - Invoke-RivetTestQuery -Query $query + Invoke-RivetTestQuery -Query $query -DatabaseName $DatabaseName } diff --git a/Test/RivetTest/Functions/Get-Table.ps1 b/Test/RivetTest/Functions/Get-Table.ps1 index 5509a3a1..bdb055d0 100644 --- a/Test/RivetTest/Functions/Get-Table.ps1 +++ b/Test/RivetTest/Functions/Get-Table.ps1 @@ -2,28 +2,29 @@ function Get-Table { param( - [Parameter(Mandatory=$true)] - [string] # The name of the table to get. - $Name, - - [string] + [Parameter(Mandatory)] + [String] $Name, + # The table's schema. Default is `dbo`. - $SchemaName = 'dbo' + [String] $SchemaName = 'dbo', + + [String] $DatabaseName ) Set-StrictMode -Version Latest + $query = @' - select + select t.*, p.data_compression, ex.value MSDescription - from sys.tables t join + from sys.tables t join sys.partitions p on p.object_id=t.object_id join sys.schemas s on t.schema_id = s.schema_id left outer join - sys.extended_properties ex on ex.major_id = t.object_id and minor_id = 0 and OBJECTPROPERTY(t.object_id, 'IsMsShipped') = 0 and ex.name = '{0}' + sys.extended_properties ex on ex.major_id = t.object_id and minor_id = 0 and OBJECTPROPERTY(t.object_id, 'IsMsShipped') = 0 and ex.name = '{0}' where s.name = '{1}' and t.name = '{2}' '@ -f [Rivet.Operations.ExtendedPropertyOperation]::DescriptionPropertyName, $SchemaName, $Name - Invoke-RivetTestQuery -Query $query + Invoke-RivetTestQuery -Query $query -DatabaseName $DatabaseName } diff --git a/Test/RivetTest/Functions/Measure-Migration.ps1 b/Test/RivetTest/Functions/Measure-Migration.ps1 index 33f63a71..2116dbe4 100644 --- a/Test/RivetTest/Functions/Measure-Migration.ps1 +++ b/Test/RivetTest/Functions/Measure-Migration.ps1 @@ -1,8 +1,11 @@ function Measure-Migration { + param( + [String] $InDatabase + ) Set-StrictMode -Version Latest - + $query = "select count(*) from $($RTRivetSchemaName).Migrations where ID >= $($script:firstMigrationId)" - Invoke-RivetTestQuery -Query $query -AsScalar + Invoke-RivetTestQuery -Query $query -AsScalar -DatabaseName $InDatabase } diff --git a/Test/RivetTest/Functions/Measure-MigrationScript.ps1 b/Test/RivetTest/Functions/Measure-MigrationScript.ps1 index c0e9999d..026ea50a 100644 --- a/Test/RivetTest/Functions/Measure-MigrationScript.ps1 +++ b/Test/RivetTest/Functions/Measure-MigrationScript.ps1 @@ -2,9 +2,10 @@ function Measure-MigrationScript { param( + [String] $In ) - Get-MigrationScript | - Measure-Object | + Get-MigrationScript -In $In | + Measure-Object | Select-Object -ExpandProperty Count } diff --git a/Test/RivetTest/Functions/New-File.ps1 b/Test/RivetTest/Functions/New-File.ps1 index 2fa052bf..a4d64be3 100644 --- a/Test/RivetTest/Functions/New-File.ps1 +++ b/Test/RivetTest/Functions/New-File.ps1 @@ -2,33 +2,48 @@ function New-File { param( - $Name, - $Content + [Parameter(Mandatory, Position=0)] + [String] $Name, + + [Parameter(Mandatory, Position=1)] + [String] $Content, + + [String] $In, + + [switch] $PassThru ) Set-StrictMode -Version 'Latest' - if ($TestDrive | Get-Member 'FullName') - { - $root = $TestDrive.FullName - } - else + if (-not $In) { - $root = $TestDrive - } + if ($TestDrive | Get-Member 'FullName') + { + $In = $TestDrive.FullName + } + else + { + $In = $TestDrive + } - if( $RTTestRoot ) - { - $root = $RTTestRoot + if( $RTTestRoot ) + { + $In = $RTTestRoot + } } - $path = Join-Path -Path $root -ChildPath $Name + $path = Join-Path -Path $In -ChildPath $Name $directoryPath = $path | Split-Path if( -not (Test-Path -Path $directoryPath -PathType Container) ) { New-Item -Path $directoryPath -ItemType 'Directory' | Out-Null } $Content | Set-Content -Path $path + + if ($PassThru) + { + return $path + } } Set-Alias -Name 'GivenFile' -Value 'New-File' \ No newline at end of file diff --git a/Test/RivetTest/Functions/New-Migration.ps1 b/Test/RivetTest/Functions/New-Migration.ps1 index ef841b28..f9ffde83 100644 --- a/Test/RivetTest/Functions/New-Migration.ps1 +++ b/Test/RivetTest/Functions/New-Migration.ps1 @@ -3,7 +3,7 @@ function New-TestMigration { [CmdletBinding(DefaultParameterSetName='NamedMigration')] param( - [Parameter(Mandatory,ValueFromPipeline,Position=0)] + [Parameter(Mandatory, ValueFromPipeline, Position=0)] # The migration contents to output. [String]$InputObject, @@ -18,7 +18,9 @@ function New-TestMigration [String]$ConfigFilePath = $RTConfigFilePath, [Parameter(Mandatory, ParameterSetName='SchemaPs1')] - [switch] $AsCheckpoint + [switch] $AsCheckpoint, + + [UInt64] $WithID ) Set-StrictMode -Version 'Latest' @@ -34,6 +36,10 @@ function New-TestMigration { $migrationFileName = 'schema.ps1' } + elseif ($PSBoundParameters.ContainsKey('WithID')) + { + $migrationFileName = "$('{0:00000000000000}' -f $WithID)_${Named}.ps1" + } else { do diff --git a/Test/RivetTest/Functions/New-RivetJsonFile.ps1 b/Test/RivetTest/Functions/New-RivetJsonFile.ps1 new file mode 100644 index 00000000..293a01be --- /dev/null +++ b/Test/RivetTest/Functions/New-RivetJsonFile.ps1 @@ -0,0 +1,93 @@ + +function New-RivetJsonFile +{ + param( + [Parameter(Mandatory)] + [String] $In, + + [String] $SqlServerName, + + [String[]] $PluginPath, + + [String[]] $Database = @(), + + [UInt32] $CommandTimeout, + + [hashtable] $TargetDatabase, + + [String[]] $IgnoredDatabase, + + [UInt32] $ConnectionTimeout, + + [switch] $PassThru + ) + + Set-StrictMode -Version 'Latest' + + if (-not (Test-Path -Path $In)) + { + New-Item -Path $In -ItemType Directory | Out-Null + } + + if (-not $PSBoundParameters.ContainsKey('SqlServerName')) + { + $serverTxtPath = Join-Path -Path $script:moduleRoot -ChildPath '..\Server.txt' -Resolve + $SqlServerName = Get-Content -Path $serverTxtPath -ReadCount 1 + } + + $rivetJson = [pscustomobject]@{ + SqlServerName = $SqlServerName; + DatabasesRoot = 'Databases'; + Databases = $Database + } + + if ($PSBoundParameters.ContainsKey('CommandTimeout')) + { + $rivetJson | Add-Member -Name 'CommandTimeout' -MemberType NoteProperty -Value $CommandTimeout + } + + if ($PSBoundParameters.ContainsKey('TargetDatabase')) + { + $rivetJson | + Add-Member -Name 'TargetDatabases' -MemberType NoteProperty -Value ([pscustomobject]$TargetDatabase) + } + + if ($PSBoundParameters.ContainsKey('IgnoredDatabase')) + { + $rivetJson | + Add-Member -Name 'IgnoreDatabases' -MemberType NoteProperty -Value $IgnoredDatabase + } + + if ($PSBoundParameters.ContainsKey('ConnectionTimeout')) + { + $rivetJson | + Add-Member -Name 'ConnectionTimeout' -MemberType NoteProperty -Value $ConnectionTimeout + } + + $databasesPath = Join-Path -Path $In -ChildPath 'Databases' + if (-not (Test-Path -Path $databasesPath)) + { + New-Item -Path $databasesPath -ItemType Directory | Out-Null + } + + foreach ($dbName in $Database) + { + $dbMigrationPath = Join-Path -Path $databasesPath -ChildPath "${dbName}\Migrations" + if ((Test-Path -Path $dbMigrationPath)) + { + continue + } + + New-Item -Path $dbMigrationPath -ItemType Directory | Out-Null + } + + if ($PluginPath) + { + $rivetJson | Add-Member -Name 'PluginPaths' -MemberType NoteProperty -Value $PluginPath + } + + GivenFile 'rivet.json' -In $In -Content ($rivetJson | ConvertTo-Json -Depth 100) -PassThru:$PassThru +} + +Set-Alias -Name 'GivenRivetJsonFile' -Value 'New-RivetJsonFile' +Set-Alias -Name 'GivenRivetJson' -Value 'New-RivetJsonFile' diff --git a/Test/RivetTest/Functions/Test-DatabaseObject.ps1 b/Test/RivetTest/Functions/Test-DatabaseObject.ps1 index ab41cdab..c552cf58 100644 --- a/Test/RivetTest/Functions/Test-DatabaseObject.ps1 +++ b/Test/RivetTest/Functions/Test-DatabaseObject.ps1 @@ -2,55 +2,48 @@ function Test-DatabaseObject { param( - [Parameter(Mandatory=$true,ParameterSetName='U')] - [Switch] - $Table, - - [Parameter(Mandatory=$true,ParameterSetName='P')] - [Switch] - $StoredProcedure, - - [Parameter(Mandatory=$true,ParameterSetName='FN')] - [Switch] - $ScalarFunction, - - [Parameter(Mandatory=$true,ParameterSetName='V')] - [Switch] - $View, - - [Parameter(Mandatory=$true,ParameterSetName='TA')] - [Switch] - $AssemblyTrigger, - - [Parameter(Mandatory=$true,ParameterSetName='TR')] - [Switch] - $SQLTrigger, - - [Parameter(Mandatory=$true,ParameterSetName='F')] - [Switch] - $ForeignKey, - - [Parameter(Mandatory=$true,Position=1)] - [string] - $Name, - + [Parameter(Mandatory, ParameterSetName='U')] + [switch] $Table, + + [Parameter(Mandatory, ParameterSetName='P')] + [switch] $StoredProcedure, + + [Parameter(Mandatory, ParameterSetName='FN')] + [switch] $ScalarFunction, + + [Parameter(Mandatory, ParameterSetName='V')] + [switch] $View, + + [Parameter(Mandatory, ParameterSetName='TA')] + [switch] $AssemblyTrigger, + + [Parameter(Mandatory, ParameterSetName='TR')] + [switch] $SQLTrigger, + + [Parameter(Mandatory, ParameterSetName='F')] + [switch] $ForeignKey, + + [Parameter(Mandatory, Position=1)] + [String] $Name, + [Parameter(Position=2)] - [string] - $SchemaName = 'dbo' + [String] $SchemaName = 'dbo', + + [String] $DatabaseName ) - - + + #$query = "select count(*) from sys.objects where type = '{0}' and name = '{1}'" $query = @' - select - count(*) - from - sys.objects o join - sys.schemas s on o.schema_id = s.schema_id - where + select + count(*) + from + sys.objects o join + sys.schemas s on o.schema_id = s.schema_id + where o.type = '{0}' and o.name = '{1}' and s.name = '{2}' '@ -f $pscmdlet.ParameterSetName,$Name,$SchemaName - $objectCount = Invoke-RivetTestQuery -Query $query -AsScalar + $objectCount = Invoke-RivetTestQuery -Query $query -AsScalar -DatabaseName $DatabaseName return ($objectCount -eq 1) } diff --git a/Test/RivetTest/Functions/Test-Table.ps1 b/Test/RivetTest/Functions/Test-Table.ps1 index a2524dd0..07d66b0b 100644 --- a/Test/RivetTest/Functions/Test-Table.ps1 +++ b/Test/RivetTest/Functions/Test-Table.ps1 @@ -2,12 +2,14 @@ function Test-Table { param( - $Name, - - [Parameter()] - [string] + [Parameter(Mandatory)] + [String] $Name, + # The schema name of the table. Defaults to `dbo`. - $SchemaName = 'dbo' + [String] $SchemaName = 'dbo', + + [String] $DatabaseName ) - return Test-DatabaseObject -Table -Name $Name -SchemaName $SchemaName + + return Test-DatabaseObject -Table -Name $Name -SchemaName $SchemaName -DatabaseName $DatabaseName } diff --git a/Test/RivetTest/Import-RivetTest.ps1 b/Test/RivetTest/Import-RivetTest.ps1 index fdff773d..6a524e5a 100644 --- a/Test/RivetTest/Import-RivetTest.ps1 +++ b/Test/RivetTest/Import-RivetTest.ps1 @@ -25,13 +25,11 @@ if( (Test-Path -Path 'env:APPVEYOR') ) & (Join-Path -Path $PSScriptRoot -ChildPath '..\..\Rivet\Import-Rivet.ps1' -Resolve) } - if( -not (Get-Module 'RivetTest') ) - { - Import-Module -Name $rivetTestPsd1Path -ArgumentList $rivetRoot - } + # Always import until tests have moved away from Start-RivetTest/Stop-RivetTest shenanigans. + Import-Module -Name $rivetTestPsd1Path -ArgumentList $rivetRoot -Force -Verbose:$false } else { & (Join-Path -Path $PSScriptRoot -ChildPath '..\..\Rivet\Import-Rivet.ps1' -Resolve) - Import-Module -Name $rivetTestPsd1Path -Force -ArgumentList $rivetRoot + Import-Module -Name $rivetTestPsd1Path -Force -ArgumentList $rivetRoot -Verbose:$false } diff --git a/Test/RivetTest/RivetTest.psd1 b/Test/RivetTest/RivetTest.psd1 index ca8e38ed..649a318a 100644 --- a/Test/RivetTest/RivetTest.psd1 +++ b/Test/RivetTest/RivetTest.psd1 @@ -71,6 +71,7 @@ 'Assert-Column', 'Assert-DataType', 'Assert-DefaultConstraint', + 'Assert-Error', 'Assert-ForeignKey', 'Assert-Index', 'Assert-PrimaryKey', @@ -115,6 +116,7 @@ 'New-RTConstraintName', 'New-Database', 'New-File', + 'New-RivetJsonFile', 'New-TestMigration', 'New-SqlConnection', 'Remove-RivetTestDatabase', @@ -168,7 +170,10 @@ AliasesToExport = @( 'GivenFile', 'GivenMigration', + 'GivenRivetJson', + 'GivenRivetJsonFile', 'ThenDefaultConstraint', + 'ThenError', 'ThenTable', 'ThenWroteError', 'WhenMigrating' diff --git a/Test/RivetTest/RivetTest.psm1 b/Test/RivetTest/RivetTest.psm1 index 48150d34..5a33bbb5 100644 --- a/Test/RivetTest/RivetTest.psm1 +++ b/Test/RivetTest/RivetTest.psm1 @@ -18,6 +18,7 @@ $RTConfigFilePath = $script:RTSession = $null $script:RTTimestamp = 20150101000000 +$script:moduleRoot = $PSScriptRoot if( -not $RivetRoot ) { diff --git a/Test/Update-Database.Tests.ps1 b/Test/Update-Database.Tests.ps1 index e832ec61..e331635f 100644 --- a/Test/Update-Database.Tests.ps1 +++ b/Test/Update-Database.Tests.ps1 @@ -4,61 +4,115 @@ Set-StrictMode -Version 'Latest' BeforeAll { Set-StrictMode -Version 'Latest' + & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) + Remove-Item -Path 'alias:GivenMigration' + Remove-Item -Path 'alias:ThenTable' + + $script:testDirPath = $null + $script:testNum = 0 + $script:rivetJsonPath = $null + $script:dbName = 'Update-Database' + + function GivenMigration + { + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, + + [Parameter(Mandatory, Position=1)] + [String] $WithContent + ) + + $WithContent | New-TestMigration -Name $Named -ConfigFilePath $script:rivetJsonPath -DatabaseName $script:dbName + } + function ThenTable + { + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, + + [Parameter(Mandatory)] + [switch] $Exists + ) + + Test-Table -Name $Named -DatabaseName $script:dbName | Should -BeTrue + } + + + function WhenPushing + { + Invoke-Rivet -Push -ConfigFilePath $script:rivetJsonPath + } } Describe 'Update-Database' { + BeforeAll { + Remove-RivetTestDatabase -Name $script:dbName + } + BeforeEach { - Start-RivetTest + $script:testDirPath = Join-Path -Path $TestDrive -ChildPath ($script:testNum++) + New-Item -Path $script:testDirPath -ItemType Directory + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -Database $script:dbName -PassThru + $Global:Error.Clear() } AfterEach { - Invoke-RTRivet -Pop -All - Stop-RivetTest + Invoke-Rivet -Pop -All -Force -ConfigFilePath $script:rivetJsonPath } It 'allows long migration names' { - $migrationPathLength = $RTDatabaseMigrationRoot.Length + $dbMigrationsDirPath = $script:rivetJsonPath | Split-Path + $dbMigrationsDirPath = Join-Path -Path $dbMigrationsDirPath -ChildPath 'Databases' + $dbMigrationsDirPath = Join-Path -Path $dbMigrationsDirPath -ChildPath $script:dbName + $dbMigrationsDirPath = Join-Path -Path $dbMigrationsDirPath -ChildPath 'Migrations' + $migrationPathLength = $dbMigrationsDirPath.Length # remove length of the separator, timestamp, underscore and extension $name = 'a' * (259 - $migrationPathLength - 1 - 14 - 1 - 4) - @' - function Push-Migration - { - Add-Table Foobar { - BigInt ID - } - } - - function Pop-Migration - { - Remove-Table 'Foobar' - } + GivenMigration $name @' + function Push-Migration + { + Add-Table Foobar { + BigInt ID + } + } -'@ | New-TestMigration -Name $name + function Pop-Migration + { + Remove-Table 'Foobar' + } +'@ - Invoke-RTRivet -Push - $Global:Error.Count | Should -Be 0 - (Test-Table 'Foobar') | Should -BeTrue + WhenPushing + ThenError -IsEmpty + ThenTable 'Foobar' -Exists } It 'does not parse already applied migrations' { $migrationContent = @' -function Push-Migration -{ - Add-Schema 'test' -} + function Push-Migration + { + Add-Schema 'test' + } -function Pop-Migration -{ - Remove-Schema 'test' -} + function Pop-Migration + { + Remove-Schema 'test' + } '@ $migration = GivenMigration -Named 'WillBeUnparsable' $migrationContent - WhenMigrating 'WillBeUnparsable' + WhenPushing '{' | Set-Content -Path $migration.FullName - WhenMigrating 'WillBeUnparsable' - $Global:Error | Should -BeNullOrEmpty - $migrationContent | Set-Content -Path $migration.FullName + try + { + WhenPushing + ThenError -IsEmpty + } + finally + { + $migrationContent | Set-Content -Path $migration.FullName + } } } \ No newline at end of file diff --git a/Test/Update-Table.Tests.ps1 b/Test/Update-Table.Tests.ps1 index 74cb2325..d991a4af 100644 --- a/Test/Update-Table.Tests.ps1 +++ b/Test/Update-Table.Tests.ps1 @@ -6,242 +6,321 @@ BeforeAll { Set-StrictMode -Version 'Latest' & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) -} - -Describe 'Update-Table' { - BeforeEach { - Start-RivetTest + Remove-Item -Path 'alias:GivenMigration' + Remove-Item -Path 'alias:ThenTable' + Remove-Item -Path 'alias:ThenDefaultConstraint' + + $script:testDirPath = $null + $script:testNum = 0 + $script:rivetJsonPath = $null + $script:dbName = 'Update-Table' + + function GivenMigration + { + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, + + [Parameter(Mandatory, Position=1)] + [String] $WithContent + ) + + $WithContent | New-TestMigration -Name $Named -ConfigFilePath $script:rivetJsonPath -DatabaseName $script:dbName } - AfterEach { - Stop-RivetTest + function ThenColumn + { + param( + [String] $Named, + + [String] $OnTable, + + [hashtable] $Is + ) + + Assert-Column -Name $Named -TableName $OnTable -DatabaseName $script:dbName @Is } - It 'should update column from int to bigint with description' { - @' -function Push-Migration -{ - Add-Table -Name 'Foobar' -Column { - Int 'id' -Description 'Foo' - } -Option 'data_compression = none' + function ThenDefaultConstraint + { + param( + [String] $Named, - Update-Table -Name 'Foobar' -UpdateColumn { - BigInt 'id' -Description 'Bar' + [String] $Is + ) + + Assert-DefaultConstraint -Name $Named -Is $Is -DatabaseName $script:dbName } -} -function Pop-Migration -{ - Remove-Table 'Foobar' -} + function ThenTable + { + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, -'@ | New-TestMigration -Name 'UpdateDateColumnWithDescription' + [switch] $Not, - Invoke-RTRivet -Push 'UpdateDateColumnWithDescription' + [Parameter(Mandatory)] + [switch] $Exists + ) - Assert-Table 'Foobar' - Assert-Column -Name 'id' -DataType 'BigInt' -TableName 'Foobar' -Description 'Bar' - } + $exists = Test-Table -Name $Named -DatabaseName $script:dbName - It 'should update column from binary to varbinary' { - @' -function Push-Migration -{ - Add-Table -Name 'Foobar' -Column { - Binary 'id' -NotNull -Size 50 + if ($Not) + { + $exists | Should -BeFalse + } + else + { + $exists | Should -BeTrue + } } - Update-Table -Name 'Foobar' -UpdateColumn { - VarBinary 'id' -Size 40 -Sparse + function WhenPushing + { + Invoke-Rivet -Push -ConfigFilePath $script:rivetJsonPath } } -function Pop-Migration -{ - Remove-Table 'Foobar' -} - -'@ | New-TestMigration -Name 'ShouldUpdateColumnFromBinarytoVarBinary' - - Invoke-RTRivet -Push 'ShouldUpdateColumnFromBinarytoVarBinary' - - Assert-Table 'Foobar' - Assert-Column -Name 'id' -DataType 'VarBinary' -TableName 'Foobar' -Sparse -Size 40 +Describe 'Update-Table' { + BeforeAll { + Remove-RivetTestDatabase -Name $script:dbName } - It 'should update column from nchar to nvarchar' { - @' -function Push-Migration -{ - Add-Table -Name 'Foobar' -Column { - NChar 'id' 30 + BeforeEach { + $script:testDirPath = Join-Path -Path $TestDrive -ChildPath ($script:testNum++) + New-Item -Path $script:testDirPath -ItemType Directory + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -Database $script:dbName -PassThru + $Global:Error.Clear() } - Update-Table -Name 'Foobar' -UpdateColumn { - NVarChar 'id' -Max -Collation "Chinese_Taiwan_Stroke_CI_AS" -NotNull + AfterEach { + Invoke-Rivet -Pop -All -Force -ConfigFilePath $script:rivetJsonPath } -} -function Pop-Migration -{ - Remove-Table 'Foobar' -} + It 'should update column from int to bigint with description' { + GivenMigration 'UpdateDateColumnWithDescription' @' + function Push-Migration + { + Add-Table -Name 'Foobar' -Column { + Int 'id' -Description 'Foo' + } -Option 'data_compression = none' + + Update-Table -Name 'Foobar' -UpdateColumn { + BigInt 'id' -Description 'Bar' + } + } + + function Pop-Migration + { + Remove-Table 'Foobar' + } +'@ -'@ | New-TestMigration -Name 'ShouldUpdateColumnFromNChartoNVarChar' + WhenPushing + ThenTable 'Foobar' -Exists + ThenColumn 'id' -OnTable 'Foobar' -Is @{ DataType = 'BigInt' ; Description = 'Bar' } + } - Invoke-RTRivet -Push 'ShouldUpdateColumnFromNChartoNVarChar' + It 'should update column from binary to varbinary' { + GivenMigration 'ShouldUpdateColumnFromBinarytoVarBinary' @' + function Push-Migration + { + Add-Table -Name 'Foobar' -Column { + Binary 'id' -NotNull -Size 50 + } + + Update-Table -Name 'Foobar' -UpdateColumn { + VarBinary 'id' -Size 40 -Sparse + } + } + + function Pop-Migration + { + Remove-Table 'Foobar' + } +'@ - Assert-Table 'Foobar' - Assert-Column -Name 'id' -DataType 'NVarChar' -TableName 'Foobar' -NotNull -Max -Collation "Chinese_Taiwan_Stroke_CI_AS" + WhenPushing + ThenTable 'Foobar' -Exist + ThenColumn 'id' -OnTable 'Foobar' -Is @{ DataType = 'VarBinary' ; Sparse = $true ; Size = 40 } } - It 'should update column from nvarchar to xml' { - -@" -function Push-Migration -{ - Invoke-Ddl -Query @' -create xml schema collection EmptyXsd as -N' - - - - - -'; + It 'should update column from nchar to nvarchar' { + GivenMigration 'ShouldUpdateColumnFromNChartoNVarChar' @' + function Push-Migration + { + Add-Table -Name 'Foobar' -Column { + NChar 'id' 30 + } + + Update-Table -Name 'Foobar' -UpdateColumn { + NVarChar 'id' -Max -Collation "Chinese_Taiwan_Stroke_CI_AS" -NotNull + } + } + + function Pop-Migration + { + Remove-Table 'Foobar' + } '@ - Add-Table -Name 'WithXmlContent' -Column { - VarChar 'One' -Max -NotNull - Xml 'Two' -XmlSchemaCollection 'EmptyXsd' - } + WhenPushing - Update-Table -Name 'WithXmlContent' -UpdateColumn{ - Xml 'Two' -XmlSchemaCollection 'EmptyXsd' + ThenTable 'Foobar' -Exists + ThenColumn 'id' -OnTable 'Foobar' -Is @{ + DataType = 'NVarChar' + NotNull = $true; + Max = $true; + Collation = "Chinese_Taiwan_Stroke_CI_AS"; + } } -} -function Pop-Migration -{ - Remove-Table 'WithXmlContent' - Invoke-Ddl 'drop xml schema collection EmptyXsd' -} -"@ | New-TestMigration -Name 'ShouldUpdateColumnFromNVarChartoXml' + It 'should update column from nvarchar to xml' { + GivenMigration 'ShouldUpdateColumnFromNVarChartoXml'@" + function Push-Migration + { + Invoke-Ddl -Query @' + create xml schema collection EmptyXsd as + N' + + + + + + '; +'@ - Invoke-RTRivet -Push 'ShouldUpdateColumnFromNVarChartoXml' + Add-Table -Name 'WithXmlContent' -Column { + VarChar 'One' -Max -NotNull + Xml 'Two' -XmlSchemaCollection 'EmptyXsd' + } - Assert-Table 'WithXmlContent' - Assert-Column -Name 'Two' -DataType 'Xml' -TableName 'WithXmlContent' - } + Update-Table -Name 'WithXmlContent' -UpdateColumn{ + Xml 'Two' -XmlSchemaCollection 'EmptyXsd' + } + } - It 'should update column after add column in update table' { - @' -function Push-Migration -{ - Add-Table -Name 'Foobar' -Column { - Int 'id' -Description 'Foo' - } + function Pop-Migration + { + Remove-Table 'WithXmlContent' + Invoke-Ddl 'drop xml schema collection EmptyXsd' + } +"@ - Update-Table -Name 'Foobar' -AddColumn { - VarChar 'id2' -Max -Description 'Foo2' - } + WhenPushing - Update-Table -Name 'FooBar' -UpdateColumn { - BigInt 'id2' -Description 'Bar' + ThenTable 'WithXmlContent' -Exists + ThenColumn -Name 'Two' -OnTable 'WithXmlContent' -Is @{ DataType = 'Xml' } } - Update-Table -Name 'Foobar' -UpdateColumn { - VarChar 'id' -Max -Description 'Bar2' - } -AddColumn { - BigInt 'id3' -Description 'Foo' - } -} - -function Pop-Migration -{ - Remove-Table 'Foobar' -} - -'@ | New-TestMigration -Name 'UpdateDateColumnWithDescription' + It 'should update column after add column in update table' { + GivenMigration 'UpdateDateColumnWithDescription' @' + function Push-Migration + { + Add-Table -Name 'Foobar' -Column { + Int 'id' -Description 'Foo' + } + + Update-Table -Name 'Foobar' -AddColumn { + VarChar 'id2' -Max -Description 'Foo2' + } + + Update-Table -Name 'FooBar' -UpdateColumn { + BigInt 'id2' -Description 'Bar' + } + + Update-Table -Name 'Foobar' -UpdateColumn { + VarChar 'id' -Max -Description 'Bar2' + } -AddColumn { + BigInt 'id3' -Description 'Foo' + } + } + + function Pop-Migration + { + Remove-Table 'Foobar' + } +'@ - Invoke-RTRivet -Push 'UpdateDateColumnWithDescription' + WhenPushing - Assert-Table 'Foobar' - Assert-Column -Name 'id' -DataType 'VarChar' -TableName 'Foobar' -Max -Description 'Bar2' - Assert-Column -Name 'id2' -DataType 'BigInt' -TableName 'Foobar' -Description 'Bar' - Assert-Column -Name 'id3' -DataType 'BigInt' -TableName 'Foobar' -Description 'Foo' + ThenTable 'Foobar' -Exists + ThenColumn 'id' -OnTable 'Foobar' -Is @{ DataType = 'VarChar' ; Max = $true ; Description = 'Bar2' } + ThenColumn 'id2' -OnTable 'Foobar' -Is @{ DataType = 'BigInt' ; Description = 'Bar' } + ThenColumn 'id3' -OnTable 'Foobar' -Is @{ DataType = 'BigInt' ; Description = 'Foo' } } It 'should use custom constraint name' { GivenMigration -Named 'CustomConstraintNames' @' -function Push-Migration -{ - Add-Table 'CustomConstraintNames' { - int 'ID' - } - - Update-Table 'CustomConstraintNames' -AddColumn { - int 'column2' -NotNull -Default 2 -DefaultConstraintName 'DF_Two' - int 'column3' -Identity - } -} - -function Pop-Migration -{ - Remove-Table 'CustomConstraintNames' -} + function Push-Migration + { + Add-Table 'CustomConstraintNames' { + int 'ID' + } + + Update-Table 'CustomConstraintNames' -AddColumn { + int 'column2' -NotNull -Default 2 -DefaultConstraintName 'DF_Two' + int 'column3' -Identity + } + } + + function Pop-Migration + { + Remove-Table 'CustomConstraintNames' + } '@ - WhenMigrating 'CustomConstraintNames' + WhenPushing ThenDefaultConstraint 'DF_Two' -Is 'snafu' } It 'does not add default constraint to an existing column' { - GivenMigration -Named 'DefaultConstraintOnExistingColumn' @' -function Push-Migration -{ - Add-Table 'DefaultConstraintOnExistingColumn' { - int 'column1' - } - - Update-Table 'DefaultConstraintOnExistingColumn' -UpdateColumn { - int 'column1' -NotNull -Default 2 -DefaultConstraintName 'DF_Two' - } -} - -function Pop-Migration -{ - Remove-Table 'DefaultConstraintOnExistingColumn' -} + GivenMigration 'DefaultConstraintOnExistingColumn' @' + function Push-Migration + { + Add-Table 'DefaultConstraintOnExistingColumn' { + int 'column1' + } + + Update-Table 'DefaultConstraintOnExistingColumn' -UpdateColumn { + int 'column1' -NotNull -Default 2 -DefaultConstraintName 'DF_Two' + } + } + + function Pop-Migration + { + Remove-Table 'DefaultConstraintOnExistingColumn' + } '@ - { WhenMigrating 'DefaultConstraintOnExistingColumn' } | Should -Throw - ThenWroteError 'Use the Add-DefaultConstraint operation' + { WhenPushing } | Should -Throw + ThenError -Matches 'Use the Add-DefaultConstraint operation' ThenTable 'DefaultConstraintOnExistingColumn' -Not -Exists } It 'rejects adding an idenity to an existng column' { GivenMigration -Named 'IdentityOnExistingColumn' @' -function Push-Migration -{ - Add-Table 'IdentityOnExistingColumn' { - int 'column1' - } - - Update-Table 'IdentityOnExistingColumn' -UpdateColumn { - int 'column1' -Identity - } -} - -function Pop-Migration -{ - Remove-Table 'IdentityOnExistingColumn' -} + function Push-Migration + { + Add-Table 'IdentityOnExistingColumn' { + int 'column1' + } + + Update-Table 'IdentityOnExistingColumn' -UpdateColumn { + int 'column1' -Identity + } + } + + function Pop-Migration + { + Remove-Table 'IdentityOnExistingColumn' + } '@ - { WhenMigrating 'IdentityOnExistingColumn' } | Should -Throw - ThenWroteError 'identity' + { WhenPushing } | Should -Throw + ThenError -Matches 'identity' ThenTable 'IdentityOnExistingColumn' -Not -Exists } } \ No newline at end of file diff --git a/Test/xml.Tests.ps1 b/Test/xml.Tests.ps1 index 06aed48a..65942fa7 100644 --- a/Test/xml.Tests.ps1 +++ b/Test/xml.Tests.ps1 @@ -6,146 +6,154 @@ BeforeAll { Set-StrictMode -Version 'Latest' & (Join-Path -Path $PSScriptRoot -ChildPath 'Initialize-Test.ps1' -Resolve) + Remove-Item -Path 'alias:GivenMigration' + Remove-Item -Path 'alias:WhenMigrating' + Remove-Item -Path 'alias:ThenTable' + + $script:testDirPath = $null + $script:testNum = 0 + $script:rivetJsonPath = $null + $script:dbName = 'New-XmlColumn' + + function GivenMigration + { + param( + [Parameter(Mandatory, Position=0)] + [String] $Named, + + [Parameter(Mandatory, Position=1)] + [String] $WithContent + ) + + $WithContent | + New-TestMigration -Named $Named -DatabaseName $script:dbName -ConfigFilePath $script:rivetJsonPath + } function ThenMigrationPoppable { - Invoke-RTRivet -Pop + { Invoke-Rivet -Pop -ConfigFilePath $script:rivetJsonPath } | Should -Not -Throw } - function ThenTable + function ThenColumn { param( - [Parameter(Mandatory)] - [string] - $Named, + [String] $Named, - [Parameter(Mandatory)] - [string] - $HasXmlColumn, + [String] $OnTable, - [Switch] - $NoSchema + [String] $HasDataType ) - $column = Get-Column -Name $HasXmlColumn -TableName $Named - It ('should create column' ) { - $column | Should -Not -BeNullOrEmpty - $column.type_name | Should -Be 'xml' - if( $NoSchema ) - { - $column.is_xml_document | Should -BeFalse - $column.xml_collection_id | Should -Be 0 - } - } + Assert-Column -Name $Named -DataType $HasDataType -TableName $OnTable -DatabaseName $script:dbName + } + + function ThenTable + { + [CmdletBinding()] + param( + [String] $Named, + + [switch] $Exists + ) + + Assert-Table 'WithXmlContent' -Exists -DatabaseName $script:dbName } function WhenPushing { - Invoke-RTRivet -Push + Invoke-Rivet -Push -ConfigFilePath $script:rivetJsonPath } } Describe 'New-XmlColumn' { - BeforeEach { - Start-RivetTest + BeforeAll { + Remove-RivetTestDatabase -Name $script:dbName + Invoke-RivetTestQuery -DatabaseName 'master' -Query "create database [${script:dbName}]" + Invoke-RivetTestQuery -DatabaseName $script:dbName -Query @' + create xml schema collection EmptyXsd as + N' + + + + + + '; +'@ } - AfterEach { - Stop-RivetTest + BeforeEach { + $script:testDirPath = Join-Path -Path $TestDrive -ChildPath ($script:testNum++) + New-Item -Path $script:testDirPath -ItemType Directory + $Global:Error.Clear() + $script:migrations = @() + $script:rivetJsonPath = GivenRivetJsonFile -In $script:testDirPath -Database $script:dbName -PassThru } It 'should create xml column with content' { - @" - function Push-Migration - { - Invoke-Ddl -Query @' - create xml schema collection EmptyXsd as - N' - - - - - - '; -'@ - - Add-Table -Name 'WithXmlContent' -Column { - VarChar 'One' -Max -NotNull - Xml 'Two' -XmlSchemaCollection 'EmptyXsd' - } - } - - function Pop-Migration - { - Remove-Table 'WithXmlContent' - Invoke-Ddl 'drop xml schema collection EmptyXsd' - } -"@ | New-TestMigration -Name 'CreateXmlColumn' + GivenMigration 'CreateXmlColumn' @" + function Push-Migration + { + Add-Table -Name 'WithXmlContent' -Column { + VarChar 'One' -Max -NotNull + Xml 'Two' -XmlSchemaCollection 'EmptyXsd' + } + } - Invoke-RTRivet -Push 'CreateXmlColumn' + function Pop-Migration + { + Remove-Table 'WithXmlContent' + Invoke-Ddl 'drop xml schema collection EmptyXsd' + } +"@ - Assert-Table 'WithXmlContent' - Assert-Column -Name 'Two' -DataType 'Xml' -TableName 'WithXmlContent' + WhenPushing + ThenTable 'WithXmlContent' -Exists + ThenColumn 'Two' -OnTable 'WithXmlContent' -HasDataType 'Xml' } It 'should create xml column with document' { - @" - function Push-Migration - { - Invoke-Ddl -Query @' - create xml schema collection EmptyXsd as - N' - - - - - - '; -'@ - - Add-Table -Name 'WithXmlDocument' -Column { - VarChar 'One' -Max -NotNull - Xml 'Two' -Document -XmlSchemaCollection 'EmptyXsd' - } - } - - function Pop-Migration - { - Remove-Table 'WithXmlDocument' - Invoke-Ddl 'drop xml schema collection EmptyXsd' - } -"@ | New-TestMigration -Name 'CreateXmlColumn' + GivenMigration 'CreateXmlColumn' @" + function Push-Migration + { + Add-Table -Name 'WithXmlDocument' -Column { + VarChar 'One' -Max -NotNull + Xml 'Two' -Document -XmlSchemaCollection 'EmptyXsd' + } + } - Invoke-RTRivet -Push 'CreateXmlColumn' + function Pop-Migration + { + Remove-Table 'WithXmlDocument' + Invoke-Ddl 'drop xml schema collection EmptyXsd' + } +"@ - Assert-Table 'WithXmlDocument' - Assert-Column -Name 'Two' -DataType 'Xml' -TableName 'WithXmlDocument' + WhenPushing + ThenTable 'WithXmlDocument' -Exists + ThenColumn 'Two' -OnTable 'WithXmlDocument' -HasDataType 'Xml' } It 'does not require xml schema' { GivenMigration -Named 'Migration' @' - function Push-Migration - { - Add-Table -Name 'WithXmlColumn' -Column { - Xml 'Two' - } - } - function Pop-Migration - { - Remove-Table 'WithXmlColumn' - } + function Push-Migration + { + Add-Table -Name 'WithXmlColumn' -Column { + Xml 'Two' + } + } + function Pop-Migration + { + Remove-Table 'WithXmlColumn' + } '@ - WhenMigrating 'Migration' - ThenTable 'WithXmlColumn' -HasXmlColumn 'Two' -NoSchema + WhenPushing + ThenTable 'WithXmlColumn' -Exists + ThenColumn 'Two' -OnTable 'WithXmlColumn' -HasDataType 'Xml' ThenMigrationPoppable } } From 087c45a2709bfaea1295b3782cf7f45913062a8c Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Thu, 18 Apr 2024 07:04:27 -0700 Subject: [PATCH 12/16] Test failing on the build server. Export-Migration tests don't care if it leaves unpopped objects behind when its done, so allow it to not show the errors that encourages good test behavior --- Test/Export-Migration.Tests.ps1 | 4 ++-- .../Functions/Clear-TestDatabase.ps1 | 20 +++++++++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Test/Export-Migration.Tests.ps1 b/Test/Export-Migration.Tests.ps1 index 6f1d217f..e0555086 100644 --- a/Test/Export-Migration.Tests.ps1 +++ b/Test/Export-Migration.Tests.ps1 @@ -121,7 +121,7 @@ BeforeAll { } finally { - Stop-RivetTest -DatabaseName $Database + Stop-RivetTest -DatabaseName $Database -ErrorAction Ignore } } } @@ -927,7 +927,7 @@ function Pop-Migration Remove-Schema 'export' } '@ - WhenExporting '*.Syn*' + WhenExporting '*.Syn*' -SkipVerification ThenMigration -Not -HasContent 'Add-Table' ThenMigration -Not -HasContent 'AnotherSyn' ThenMigration -HasContent 'Add-Synonym -Name ''Syn1'' -TargetSchemaName ''dbo'' -TargetObjectName ''Target''' diff --git a/Test/RivetTest/Functions/Clear-TestDatabase.ps1 b/Test/RivetTest/Functions/Clear-TestDatabase.ps1 index feb01821..56b37925 100644 --- a/Test/RivetTest/Functions/Clear-TestDatabase.ps1 +++ b/Test/RivetTest/Functions/Clear-TestDatabase.ps1 @@ -18,7 +18,7 @@ function Clear-TestDatabase Invoke-RTRivet -Pop -All -Database $Name -ConfigFilePath $RTConfigFilePath } - if( Test-Database -Name $Name ) + if (Test-Database -Name $Name) { $query = "select * from [$($Name)].[rivet].[Migrations] where ID > $($script:firstMigrationId) order by ID" [object[]]$migrations = Invoke-RivetTestQuery -Query $query -DatabaseName $Name @@ -26,7 +26,11 @@ function Clear-TestDatabase { Remove-RivetTestDatabase -Name $Name $migrationList = $migrations | Format-Table -Property 'ID','Name' -AutoSize | Out-String - Write-Error -Message ('The following migrations weren''t popped from {0}. Please update your test so that its `Pop-Migration` function correctly reverses the operations performed in its `Push-Migration` function.{1}{2}' -f $Name,([Environment]::NewLine),$migrationList) -ErrorAction Stop + $msg = "The following migrations weren't popped from ${Name}. Please update your test so that its " + + '`Pop-Migration` function correctly reverses the operations performed in its `Push-Migration` ' + + "function.$([Environment]::NewLine)${migrationlist}" + Write-Error -Message $msg -ErrorAction $ErrorActionPreference + return } $query = 'select s.name [schema], o.name, o.type_desc from sys.objects o join sys.schemas s on o.schema_id = s.schema_id where s.name != ''rivet'' and o.is_ms_shipped = 0' @@ -35,7 +39,11 @@ function Clear-TestDatabase { Remove-RivetTestDatabase -Name $Name $objectList = $objects | Select-Object | Format-Table -Property 'schema','name','type_desc' -AutoSize | Out-String - Write-Error -Message ('The following objects weren''t properly removed from {0}. Please ensure each of your migrations has a `Pop-Migration` function that reverses the operations performed in its `Push-Migration` function.{1}{2}' -f $Name,([Environment]::NewLine),$objectList) -ErrorAction Stop + $msg = "The following objects weren't properly removed from ${Name}. Please ensure each of your " + + 'migrations has a `Pop-Migration` function that reverses the operations performed in its ' + + "`Push-Migration` function.$([Environment]::NewLine)${objectList}" + Write-Error -Message $msg -ErrorAction $ErrorActionPreference + return } $query = "select name from sys.schemas where name not in ('dbo','guest','INFORMATION_SCHEMA','sys','db_owner','db_accessadmin','db_backupoperator','db_datareader','db_datawriter','db_ddladmin','db_denydatareader','db_denydatawriter','db_securityadmin','rivet')" @@ -44,7 +52,11 @@ function Clear-TestDatabase { Remove-RivetTestDatabase -Name $Name $schemaList = $schemas| Select-Object | Format-Table -Property 'name' -AutoSize | Out-String - Write-Error ('The following schemas weren''t properly removed from {0}. Please ensure each of your migrations has a `Pop-Migration` function that reverses the operations performed in its `Push-Migration` function.{1}{2}' -f $Name,([Environment]::NewLine),$schemaList) -ErrorAction Stop + $msg = "The following schemas weren't properly removed from ${Name}. Please ensure each of your " + + 'migrations has a `Pop-Migration` function that reverses the operations performed in its ' + + "`Push-Migration` function.$([Environment]::NewLine)${schemaList}" + Write-Error -Message $msg -ErrorAction $ErrorActionPreference + return } } From d93a6ba88809b9141cb261a0596d9bb980b9b239 Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Thu, 18 Apr 2024 07:10:49 -0700 Subject: [PATCH 13/16] Minimize the number of times plug-ins are imported. Also, plug-ins should be specific to each Rivet run, not global across Rivet instances, so should be attached to the session. --- .../Functions/Convert-FileInfoToMigration.ps1 | 2 -- Rivet/Functions/Import-RivetPlugin.ps1 | 23 ++++++++----------- Rivet/Functions/Invoke-RivetPlugin.ps1 | 8 ++++--- Rivet/Functions/New-RivetSession.ps1 | 6 ++++- Rivet/Rivet.psm1 | 5 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Rivet/Functions/Convert-FileInfoToMigration.ps1 b/Rivet/Functions/Convert-FileInfoToMigration.ps1 index e4cd279f..535e3748 100644 --- a/Rivet/Functions/Convert-FileInfoToMigration.ps1 +++ b/Rivet/Functions/Convert-FileInfoToMigration.ps1 @@ -87,8 +87,6 @@ function Convert-FileInfoToMigration } Clear-MigrationFunction - - Import-RivetPlugin -Path $Session.PluginPaths -ModuleName $Session.PluginModules } process diff --git a/Rivet/Functions/Import-RivetPlugin.ps1 b/Rivet/Functions/Import-RivetPlugin.ps1 index 59a35ff6..1ee5d86f 100644 --- a/Rivet/Functions/Import-RivetPlugin.ps1 +++ b/Rivet/Functions/Import-RivetPlugin.ps1 @@ -4,21 +4,16 @@ function Import-RivetPlugin [CmdletBinding()] param( [Parameter(Mandatory)] - [AllowEmptyCollection()] - [String[]]$Path, - - [Parameter(Mandatory)] - [AllowEmptyCollection()] - [String[]]$ModuleName + [Rivet_Session] $Session ) Set-StrictMode -Version 'Latest' Use-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState - + Write-Timing -Message 'Import-RivetPlugin BEGIN' -Indent $moduleNames = & { - foreach( $pluginPath in $Path ) + foreach( $pluginPath in $Session.PluginPaths ) { if( [IO.Path]::GetExtension($pluginPath) -eq '.ps1' ) { @@ -27,13 +22,13 @@ function Import-RivetPlugin } Write-Timing -Message " Import BEGIN $($pluginPath)" - Import-Module -Name $pluginPath -Global -Force -PassThru | + Import-Module -Name $pluginPath -Global -Force -PassThru -Verbose:$false | Select-Object -ExpandProperty 'Name' | Write-Output Write-Timing -Message " Import END $($pluginPath)" } - $ModuleName | Write-Output + $Session.PluginModules | Write-Output } $commands = & { @@ -59,9 +54,9 @@ function Import-RivetPlugin Get-Command -CommandType Function | Where-Object { -not $_.Module } Write-Timing -Message (' Get Functions End') } - - $script:plugins = & { - foreach( $command in $commands ) + + $Session.Plugins = & { + foreach( $command in $commands ) { if( -not ($command | Get-Member -Name 'ScriptBlock') ) { @@ -88,7 +83,7 @@ function Import-RivetPlugin } } - Write-Timing -Message (' Discovered {0} plugins.' -f ($plugins | Measure-Object).Count) + Write-Timing -Message (' Discovered {0} plugins.' -f ($Session.Plugins | Measure-Object).Count) Write-Timing -Message 'Import-RivetPlugin END' -Outdent } \ No newline at end of file diff --git a/Rivet/Functions/Invoke-RivetPlugin.ps1 b/Rivet/Functions/Invoke-RivetPlugin.ps1 index 4048d488..678ae384 100644 --- a/Rivet/Functions/Invoke-RivetPlugin.ps1 +++ b/Rivet/Functions/Invoke-RivetPlugin.ps1 @@ -18,13 +18,15 @@ function Invoke-RivetPlugin Write-Timing -Message 'Invoke-RivetPlugin BEGIN' -Indent - try { $responders = - $plugins | + $Session.Plugins | + Where-Object { $_ } | + Where-Object { $_ | Get-Member -Name 'ScriptBlock' } | Where-Object { - $_.ScriptBlock.Attributes | Where-Object { $_ -is [Rivet.PluginAttribute] -and $_.RespondsTo -eq $Event } + $_.ScriptBlock.Attributes | + Where-Object { $_ -is [Rivet.PluginAttribute] -and $_.RespondsTo -eq $Event } } if( -not $responders ) diff --git a/Rivet/Functions/New-RivetSession.ps1 b/Rivet/Functions/New-RivetSession.ps1 index 70da6829..7eaad089 100644 --- a/Rivet/Functions/New-RivetSession.ps1 +++ b/Rivet/Functions/New-RivetSession.ps1 @@ -55,5 +55,9 @@ function New-RivetSession return } - return [Rivet_Session]::New($settings) + $session = [Rivet_Session]::New($settings) + + Import-RivetPlugin -Session $session + + return $session } diff --git a/Rivet/Rivet.psm1 b/Rivet/Rivet.psm1 index 6efab3bc..6616faa9 100644 --- a/Rivet/Rivet.psm1 +++ b/Rivet/Rivet.psm1 @@ -14,6 +14,7 @@ class Rivet_Session $this.PluginModules = $settings.PluginModules $this.PluginPaths = $settings.PluginPaths $this.SqlServerName = $settings.SqlServerName + $this.Plugins = @() } [Object] $Connection @@ -39,6 +40,8 @@ class Rivet_Session [Object] $CurrentTransaction [Rivet.Configuration.Database] $CurrentDatabase + + [Object[]] $Plugins } $RivetSchemaName = 'rivet' @@ -68,8 +71,6 @@ $timer = New-Object 'Diagnostics.Stopwatch' $timerForWrites = New-Object 'Diagnostics.Stopwatch' $timingLevel = 0 -$plugins = @() - function Write-Timing { [CmdletBinding()] From c3a84807b7cd0266a43ae2fa4098f1cf042bdc49 Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Thu, 18 Apr 2024 07:12:35 -0700 Subject: [PATCH 14/16] Linting. --- Rivet/Functions/Export-Migration.ps1 | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Rivet/Functions/Export-Migration.ps1 b/Rivet/Functions/Export-Migration.ps1 index 5785deb6..86dbb068 100644 --- a/Rivet/Functions/Export-Migration.ps1 +++ b/Rivet/Functions/Export-Migration.ps1 @@ -37,16 +37,19 @@ function Export-Migration [Parameter(Mandatory)] [String] $Database, - # The names of the objects to export. Must include the schema if exporting a specific object. Wildcards supported. + # The names of the objects to export. Must include the schema if exporting a specific object. Wildcards + # supported. # # The default behavior is to export all non-system objects. [String[]] $Include, - # The names of any objects *not* to export. Matches the object name *and* its schema name, i.e. `schema.name`. Wildcards supported. + # The names of any objects *not* to export. Matches the object name *and* its schema name, i.e. `schema.name`. + # Wildcards supported. [String[]] $Exclude, # Any object types to exclude. - [ValidateSet('CheckConstraint','DataType','DefaultConstraint','ForeignKey','Function','Index','PrimaryKey','Schema','StoredProcedure','Synonym','Table','Trigger','UniqueKey','View','XmlSchema')] + [ValidateSet('CheckConstraint','DataType','DefaultConstraint','ForeignKey','Function','Index','PrimaryKey', + 'Schema','StoredProcedure','Synonym','Table','Trigger','UniqueKey','View','XmlSchema')] [String[]] $ExcludeType, [Switch] $NoProgress, @@ -146,7 +149,6 @@ function Export-Migration 'View' = 'VIEW'; } - function ConvertTo-SchemaParameter { param( @@ -875,10 +877,10 @@ from $allColumns = $indexColumnsByObjectID[$Object.object_id] | Where-Object { $_.index_id -eq $Object.index_id } $includedColumns = $allColumns | Where-Object { $_.is_included_column } | Sort-Object -Property 'name' # I don't think order matters so order them discretely. - $include = '' + $idxInclude = '' if( $includedColumns ) { - $include = ' -Include ''{0}''' -f (($includedColumns | Select-Object -ExpandProperty 'name') -join ''',''') + $idxInclude = ' -Include ''{0}''' -f (($includedColumns | Select-Object -ExpandProperty 'name') -join ''',''') } $columns = $allColumns | Where-Object { -not $_.is_included_column } | Sort-Object -Property 'key_ordinal' @@ -893,7 +895,7 @@ from $columnNames = $columns | Select-Object -ExpandProperty 'name' Write-ExportingMessage -Schema $Object.schema_name -Name $Object.name -Type Index $schema = ConvertTo-SchemaParameter -SchemaName $Object.schema_name - ' Add-Index{0} -TableName ''{1}'' -ColumnName ''{2}'' -Name ''{3}''{4}{5}{6}{7}{8}' -f $schema,$Object.table_name,($columnNames -join ''','''),$Object.name,$clustered,$unique,$include,$descending,$where + ' Add-Index{0} -TableName ''{1}'' -ColumnName ''{2}'' -Name ''{3}''{4}{5}{6}{7}{8}' -f $schema,$Object.table_name,($columnNames -join ''','''),$Object.name,$clustered,$unique,$idxInclude,$descending,$where if( -not $ForTable ) { Push-PopOperation ('Remove-Index{0} -TableName ''{1}'' -Name ''{2}''' -f $schema,$Object.table_name,$Object.name) From f0a595102b55893c901d980fc499c22763b402d5 Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Thu, 18 Apr 2024 08:59:08 -0700 Subject: [PATCH 15/16] Bringing rivet.ps1 up to current coding standards. --- Rivet/rivet.ps1 | 129 +++++++++++++++++++----------------------------- 1 file changed, 52 insertions(+), 77 deletions(-) diff --git a/Rivet/rivet.ps1 b/Rivet/rivet.ps1 index b3bc1d56..12162bcf 100644 --- a/Rivet/rivet.ps1 +++ b/Rivet/rivet.ps1 @@ -3,9 +3,10 @@ A database migration tool for PowerShell. .DESCRIPTION -Rivet is a database migration tool for SQL Server. Finally! +Rivet is a database migration tool for SQL Server. Finally! -This script is the entry point for Rivet. It is used to create a new migration, and apply/revert migrations against a database. +This script is the entry point for Rivet. It is used to create a new migration, and apply/revert migrations against a +database. Called without any arguments, Rivet will shows this help topic. @@ -31,9 +32,10 @@ Applies all migrations. .EXAMPLE rivet.ps1 -Push 'CreateTableStarships' -Demonstrates how to apply a named migration. Don't include the timestamp. Wildcards are permitted. +Demonstrates how to apply a named migration. Don't include the timestamp. Wildcards are permitted. -*Be careful with this syntax!* If the named migration(s) depend on other migrations that haven't been run, the migration will fail. +*Be careful with this syntax!* If the named migration(s) depend on other migrations that haven't been run, the +migration will fail. .EXAMPLE rivet.ps1 -Pop @@ -43,17 +45,17 @@ Reverts the last migration script. .EXAMPLE rivet.ps1 -Pop 5 -Demonstrates how to revert multiple migrations. The last `-Count` migrations will be popped. +Demonstrates how to revert multiple migrations. The last `-Count` migrations will be popped. .EXAMPLE rivet.ps1 -Pop 'AddTable' -Demonstrates how to pop a specific migration. Wildcards supported. Will match either the migration's name or ID. +Demonstrates how to pop a specific migration. Wildcards supported. Will match either the migration's name or ID. .EXAMPLE rivet.ps1 -Redo -Reverts the last migration script, then reapplies its. Equivalent to +Reverts the last migration script, then reapplies its. Equivalent to rivet.ps1 -Pop rivet.ps1 -Push @@ -61,80 +63,62 @@ Reverts the last migration script, then reapplies its. Equivalent to .EXAMPLE rivet.ps1 -Push -Environment Production -Demonstrates how to migrate databases in a different environment. The `Production` environment should be specified in the `rivet.json` configuration file. +Demonstrates how to migrate databases in a different environment. The `Production` environment should be specified in +the `rivet.json` configuration file. .EXAMPLE rivet.ps1 -DropDatabase -Demonstrates how to drop the database(s) for the current environment. Using this switch will require confirmation from the user but it can be bypassed when given the -Force switch as well. +Demonstrates how to drop the database(s) for the current environment. Using this switch will require confirmation from +the user but it can be bypassed when given the -Force switch as well. #> -#Requires -Version 3 -[CmdletBinding(DefaultParameterSetName='ShowHelp', SupportsShouldProcess=$True)] +[CmdletBinding(DefaultParameterSetName='ShowHelp', SupportsShouldProcess)] param( - [Parameter(Mandatory=$true,ParameterSetName='New')] - [Switch] # Creates a new migration. - $New, + [Parameter(Mandatory, ParameterSetName='New')] + [switch] $New, - [Parameter(Mandatory=$true,ParameterSetName='Push')] - [Switch] # Applies migrations. - $Push, + [Parameter(Mandatory, ParameterSetName='Push')] + [switch] $Push, - [Parameter(Mandatory=$true,ParameterSetName='Pop')] - [Parameter(Mandatory=$true,ParameterSetName='PopByCount')] - [Parameter(Mandatory=$true,ParameterSetName='PopByName')] - [Parameter(Mandatory=$true,ParameterSetName='PopAll')] - [Switch] # Reverts migrations. - $Pop, + [Parameter(Mandatory, ParameterSetName='Pop')] + [Parameter(Mandatory, ParameterSetName='PopByCount')] + [Parameter(Mandatory, ParameterSetName='PopByName')] + [Parameter(Mandatory, ParameterSetName='PopAll')] + [switch] $Pop, - [Parameter(Mandatory=$true,ParameterSetName='Redo')] - [Switch] # Reverts a migration, then re-applies it. - $Redo, - - [Parameter(Mandatory=$true,ParameterSetName='New',Position=1)] - [Parameter(ParameterSetName='Push',Position=1)] - [Parameter(Mandatory=$true,ParameterSetName='PopByName',Position=1)] + [Parameter(Mandatory, ParameterSetName='Redo')] + [switch] $Redo, + + # The name of the migrations to create, push, or pop. Matches against the migration's ID, Name, or file name + # (without extension). Wildcards permitted. + [Parameter(Mandatory, ParameterSetName='New', Position=1)] + [Parameter(ParameterSetName='Push', Position=1)] + [Parameter(Mandatory, ParameterSetName='PopByName', Position=1)] [ValidateLength(1,241)] - [string[]] - # The name of the migrations to create, push, or pop. Matches against the migration's ID, Name, or file name (without extension). Wildcards permitted. - $Name, + [String[]] $Name, - [Parameter(Mandatory=$true,ParameterSetName='PopByCount',Position=1)] - [UInt32] # The number of migrations to pop. Default is 1. - $Count = 1, + [Parameter(Mandatory, ParameterSetName='PopByCount', Position=1)] + [UInt32] $Count = 1, - [Parameter(Mandatory=$true,ParameterSetName='PopAll')] - [Switch] # Pop all migrations - $All, + [Parameter(Mandatory, ParameterSetName='PopAll')] + [switch] $All, - [Parameter(ParameterSetName='Pop')] - [Parameter(ParameterSetName='PopByCount')] - [Parameter(ParameterSetName='PopByName')] - [Parameter(ParameterSetName='PopAll')] - [Parameter(ParameterSetName='DropDatabase')] - [Switch] # Force popping a migration you didn't apply or that is old. - $Force, - - [Parameter(ParameterSetName='New',Position=2)] - [Parameter(ParameterSetName='Push')] [Parameter(ParameterSetName='Pop')] [Parameter(ParameterSetName='PopByCount')] [Parameter(ParameterSetName='PopByName')] [Parameter(ParameterSetName='PopAll')] - [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] - [Parameter(ParameterSetName='Checkpoint')] - [string[]] - # The database(s) to migrate. Optional. Will operate on all databases otherwise. - $Database, + [switch] $Force, - [Parameter(ParameterSetName='New')] + # The database(s) to migrate. Optional. Will operate on all databases otherwise. + [Parameter(ParameterSetName='New', Position=2)] [Parameter(ParameterSetName='Push')] [Parameter(ParameterSetName='Pop')] [Parameter(ParameterSetName='PopByCount')] @@ -143,34 +127,25 @@ param( [Parameter(ParameterSetName='Redo')] [Parameter(ParameterSetName='DropDatabase')] [Parameter(ParameterSetName='Checkpoint')] - [string] - # The environment you're working in. Controls which settings Rivet loads from the `rivet.json` configuration file. - $Environment, + [String[]] $Database, - [Parameter(ParameterSetName='New')] - [Parameter(ParameterSetName='Push')] - [Parameter(ParameterSetName='Pop')] - [Parameter(ParameterSetName='PopByCount')] - [Parameter(ParameterSetName='PopByName')] - [Parameter(ParameterSetName='PopAll')] - [Parameter(ParameterSetName='Redo')] - [Parameter(ParameterSetName='DropDatabase')] - [Parameter(ParameterSetName='Checkpoint')] - [string] - # The path to the Rivet configuration file. Default behavior is to look in the current directory for a `rivet.json` file. See `about_Rivet_Configuration` for more information. - $ConfigFilePath, + # The environment you're working in. Controls which settings Rivet loads from the `rivet.json` configuration file. + [String] $Environment, + + # The path to the Rivet configuration file. Default behavior is to look in the current directory for a `rivet.json` + # file. See `about_Rivet_Configuration` for more information. + [String] $ConfigFilePath, - [Parameter(ParameterSetName='DropDatabase')] - [Switch] # Drops the database(s) for the current environment when given. User will be prompted for confirmation when used. - $DropDatabase, + [Parameter(ParameterSetName='DropDatabase')] + [switch] $DropDatabase, - [Parameter(ParameterSetName='Checkpoint')] - [Switch] # Checkpoints the current state of the database so that it can be re-created. - $Checkpoint + [Parameter(ParameterSetName='Checkpoint')] + [switch] $Checkpoint ) +#Requires -Version 5.1 Set-StrictMode -Version Latest if( $PSCmdlet.ParameterSetName -eq 'ShowHelp' ) @@ -183,4 +158,4 @@ if( $PSCmdlet.ParameterSetName -eq 'ShowHelp' ) Invoke-Rivet @PSBoundParameters -exit $error.Count +exit $Error.Count From 726748194dabe2a097fed932520d5d532fd32360 Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Thu, 18 Apr 2024 10:36:07 -0700 Subject: [PATCH 16/16] Improving changelog. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e488acfb..233ca444 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ ### Changed -* `Export-Migration` no longer creates an `Add-Schema` operation that includes owner information (i.e. the `Owner` +* `Export-Migration` no longer includes owner information when it exports `Add-Schema` operations (i.e. the `Owner` parameter is omitted). When exporting a schema to DDL in SQL Server Management Studio, the owner information is also omitted so we think this change should be OK. * Pushing to a database will now apply the baseline schema if it hasn't been applied.