src/crm-ci.Tests.ps1

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
. "$here\$sut"

$root = Split-Path -Parent $here

$path = "$env:HOME\$env:USERNAME" + "_$env:COMPUTERNAME.xml"
if (-not (Test-Path $path)) {
  Set-StoredCredentials
}

Function Assert-PropertiesMatch {
  Param (
    $Expected,
    $Actual
  )
  Process {
    foreach ($prop in ($Expected.psobject.properties.name)) {

      if ($Expected."$prop".GetType().Name -eq "DateTime") {
        [string]$Actual."$prop".ToString() | Should -Be $Expected."$prop".ToString()
      }
      else {
        [string]$Actual."$prop" | Should -Be $Expected."$prop"
      }
    }
  }
}

Describe "Get-CrmConnectionString" {
  It "Returns either a connection string or just the url depending on the -UrlOnly switch" {
    [string]$connString = Get-CrmConnectionString -CrmInstance CRMADVISE  
    $connString.StartsWith("RequireNewInstance=True;AuthType=AD;Url=") | Should -Be $true
      
    [string]$urlOnly = Get-CrmConnectionString -CrmInstance CRMADVISE -UrlOnly
    $urlOnly.StartsWith("https://") | Should -Be $true
  }
  It "Returns the correct address based on the crm instance" {
    [string]$connString = Get-CrmConnectionString -CrmInstance CRMADVISETEST
    $connString | Should -Be "RequireNewInstance=True;AuthType=AD;Url=https://advisedevcrm.regent.edu/CRMADVISETEST;"
  }
}

Describe "Get-RegentConnection" {
  It "should call through to Get-CrmConnection" {
    $regent = Get-RegentConnection -CrmInstance CRMRECRUITTEST 
    $datatTools = (Get-CrmConnection -ConnectionString "RequireNewInstance=True;AuthType=AD;Url=https://rctrdevcrm.regent.edu/CRMRECRUITTEST;")
    $regent.GetType() | Should -Be $datatTools.GetType()
  }
}

Describe "Export-RegentSolution" {
  New-Item TestDrive:\solutions -ItemType Directory
  Mock 'Get-Config' {
    [PSCustomObject]@{
      RepositoryPath = "TestDrive:\solutions";
      DefaultBranch  = "master";
    }
  }
  It "should download the solution as both managed and unmanged, and export it to the path specified in the config" {
    $conn = Get-RegentConnection -CrmInstance CRMRECRUITTEST
    $results = Export-RegentSolution -SolutionName "RecordLocked" -conn $conn -Verbose
    $results[0].ExportSolutionResponse.GetType().Name | Should -Be "ExportSolutionResponse"
    $results[1].ExportSolutionResponse.GetType().Name | Should -Be "ExportSolutionResponse"
    Test-Path "TestDrive:/solutions/RecordLocked/" | Should -Be $true
  } -Skip
  Context "Given a function Export-CrmSolution" {
    Mock 'Export-CrmSolution' -Verifiable -MockWith {
      return @{SolutionPath = "TestDrive:\solutions\RecordLocked.zip"}
    }
    It "Should call through with correct params to Export-CrmSolution" {
      $conn = Get-RegentConnection -CrmInstance CRMRECRUITTEST
      try {
        $results = Export-RegentSolution -SolutionName "RecordLocked" -conn $conn -UpdateVersion "1.4" -TargetCRMVersion "8.0"
      }
      catch {
        Write-Host "Skipping Solution packager..."
      }
      finally {
        Assert-MockCalled Export-CrmSolution 1
      }
    }
  }
}

Describe "Get-SolutionImportLog" {
  Context "Given an ImportJob existing in CRM CRMRECRUITTEST with an ID of 60255876-6aae-e511-80c2-0050569b65f8" {
    $exportPath = "TestDrive:\logs\log.xml"
    $id = "60255876-6aae-e511-80c2-0050569b65f8"

    It "Should return the formatted xml results and export them if specified" {
      $results = Get-SolutionImportLog `
        -CrmInstance CRMRECRUITTEST `
        -ImportJobId $id `
        -ExportPath $exportPath `
      
      $results | Should -Not -BeNullOrEmpty
      
      Test-Path $exportPath | Should -Be $true
      $contents = Get-Content $exportPath
      $contents | Should -Be $results[1]
    } 
  }
}

Describe "Import-RegentSolution" {
  Context "Given a config file specifying repository path TestDrive:/solutions" {
    New-Item TestDrive:\solutions -ItemType Directory
    Mock 'Get-Config' {
      [PSCustomObject]@{
        RepositoryPath = "$root\test-data\unpacked";
        DefaultBranch  = "master";
      }
    }

    It "Should Import the solution by default" {
      Import-RegentSolution `
        -SolutionName RecordLocked `
        -CrmInstance CRMRECRUITTEST `
        -Emails "dhines@regent.edu" `
        -Managed $false `
        -Verbose
    }
    It "Should throw any import errors and email the error message" {
      # In this example, I'm importing a managed version of solution into a CRM that
      # has the unmanged version intalled, which will cause an import error
      {
        Import-RegentSolution `
          -SolutionName RecordLocked `
          -CrmInstance CRMRECRUITTEST `
          -Managed $true `
          -Emails "dhines@regent.edu" `
          -Verbose 
      } | Should -Throw
    }
  }
}

Describe "Move-RegentSolution" {
  Mock -CommandName Import-RegentSolution -Verifiable -MockWith {"Hello World!" > success.txt}
  Mock -CommandName Export-RegentSolution -Verifiable -MockWith {return}
  Mock -CommandName Push-RegentSolutionChanges -Verifiable -MockWith {return}
  $configPath = "$env:APPDATA\solution-imports.json"
  Context "Given a config file with a repository path TestDrive:/" { 
    BeforeEach {
      if (Test-Path $configPath) {
        Remove-Item $configPath -Force
      }
    }
    It "Should export the specified solution, unpack it, and push the changes" {
      Move-RegentSolution `
        -SolutionName "RegentUniversity" `
        -SourceCrmInstance CRMRECRUIT `
        -DestinationCrmInstance CRMRECRUIT `
        -Managed $true `
        -PublishCustomizations $true `
        -Emails "dhines@regent.edu;bryatho@regent.edu;acofer@regent.edu" `
        -UpdateVersion "2.5" `
        -TargetCRMVersion "8.0" `
        -CommitMessage "Initial Commit" `
        -Branch "mybranch" `
        -ImportTime (Get-Date).AddSeconds(3) `
        -Force

      Assert-MockCalled -Scope It -CommandName Export-RegentSolution `
        -Exactly 1 `
        -ParameterFilter { 
        $SolutionName -eq "RegentUniversity" `
          -and $UpdateVersion -eq "2.5" `
          -and $TargetCRMVersion -eq "8.0"
      }
      Assert-MockCalled -Scope It -CommandName Push-RegentSolutionChanges `
        -Exactly 1 `
        -ParameterFilter { 
        $CommitMessage -eq "Initial Commit" `
          -and $Branch -eq "mybranch"
      }
    }
    It "Should import the solution immediately if no time is specified" {
      Move-RegentSolution `
        -SolutionName "RegentUniversity" `
        -SourceCrmInstance CRMRECRUIT `
        -DestinationCrmInstance CRMRECRUIT `
        -Managed $true `
        -PublishCustomizations $true `
        -Emails "dhines@regent.edu;bryatho@regent.edu;acofer@regent.edu" `
        -UpdateVersion "2.5" `
        -CommitMessage "Initial Commit" `
        -Branch "mybranch" `
        -Force
      
      Assert-MockCalled -Scope It -CommandName Import-RegentSolution `
        -Exactly 1 `
        -ParameterFilter {
        $SolutionName -eq "RegentUniversity" `
          -and $CrmInstance -eq "CRMRECRUIT" `
          -and $Managed -eq $true `
          -and $PublishCustomizations -eq $true `
          -and $Emails -eq "dhines@regent.edu;bryatho@regent.edu;acofer@regent.edu" `
      }
    }

    It "Should schedule the import job for the specified time by adding it to the config" {
      $time = (Get-Date).AddHours(1).ToUniversalTime()

      $expectedConfig = [pscustomobject] @{ 
        UserName              = $env:USERNAME;
        CrmInstance           = "CRMRECRUIT";
        PublishCustomizations = $true;
        Managed               = $true;
        SolutionName          = "RegentUniversity";
        Emails                = "dhines@regent.edu;bryatho@regent.edu;acofer@regent.edu";
        Time                  = $time;
      }
      $Result = Move-RegentSolution `
        -SolutionName $expectedConfig.SolutionName `
        -SourceCrmInstance CRMRECRUIT `
        -DestinationCrmInstance $expectedConfig.CrmInstance `
        -Managed $expectedConfig.Managed `
        -PublishCustomizations $expectedConfig.PublishCustomizations `
        -Emails $expectedConfig.Emails `
        -CommitMessage "Initial Commit" `
        -Branch "mybranch" `
        -ImportTime  $time `
        -Force
      $Result.Command | Should -Be `
        "Import-RegentSolution -Verbose -PublishCustomizations: `$true -SolutionName: RegentUniversity -Managed: `$true -CrmInstance: CRMRECRUIT -Emails ""dhines@regent.edu;bryatho@regent.edu;acofer@regent.edu"""
    }
    It "Should throw an error if the specified solution isn't found" {
      {Move-RegentSolution `
          -Credential $global:cred `
          -SolutionName "NonExistingSolution" `
          -SourceCrmInstance CRMRECRUIT `
          -DestinationCrmInstance CRMRECRUIT `
          -Managed $true `
          -PublishCustomizations $true `
          -Emails "dhines@regent.edu;bryatho@regent.edu;acofer@regent.edu" `
          -UpdateVersion "2.5" `
          -CommitMessage "Initial Commit" `
          -Branch "mybranch" `
          -ImportTime (Get-Date).AddSeconds(5) `
          -Force} | Should -Throw
    }
  }
}