tests/SyntheticMonitors.tests.ps1

BeforeAll {
  Import-Module '.\NewRelicPS.SyntheticMonitors.psm1' -Force

  $apiKey = 'Fake-API-Key'
}

Describe 'Synthetic Monitor CMDLets' {
  Context 'New-NRSyntheticMonitor' {
    BeforeAll {
      Mock Get-NRSyntheticMonitor -ModuleName 'NewRelicPS.SyntheticMonitors' {
        @{
          id = '12345678'
          name = 'Test1'
          type = 'SCRIPT_API'
        }
      }
      Mock Update-NRSyntheticMonitorScript -ModuleName 'NewRelicPS.SyntheticMonitors' {}
      Mock Invoke-RestMethod -ModuleName 'NewRelicPS.SyntheticMonitors' {}
    }

    It 'Adds a script to the monitor if ScriptPath is provided' {
      $scriptPath = '.\tests\resources\SyntheticMonitor.Script.js'
      New-NRSyntheticMonitor -APIKey $apiKey -ScriptPath $scriptPath -Name 'Test1' -Locations 'AWS_US_EAST1' -Type 'SCRIPT_API'

      # Get base 64 script content
      $base64Script = Get-NRScriptContent -ScriptPath $scriptPath -ScriptVariables @{}

      Assert-MockCalled Update-NRSyntheticMonitorScript -ModuleName 'NewRelicPS.SyntheticMonitors' -ParameterFilter {
        $ScriptContent -eq $base64Script
      }
    }
  }
  Context 'Update-NRSyntheticMonitor' {
    $TestCases = @(
      @{
        CaseName = 'Name'
        Params = [pscustomobject] @{
          name = 'Test123'
        }
      },
      @{
        CaseName = 'Frequency'
        Params = [pscustomobject] @{
          frequency = 30
        }
      },
      @{
        CaseName = 'uri'
        Params = [pscustomobject] @{
          uri = 'https://some.net'
        }
      },
      @{
        CaseName = 'locations'
        Params = [pscustomobject] @{
          locations = 'AWS_US_EAST_1'
        }
      },
      @{
        CaseName = 'Status'
        Params = [pscustomobject] @{
          Status = 'ENABLED'
        }
      },
      @{
        CaseName = 'SlaThreshold'
        Params = [pscustomobject]  @{
          SlaThreshold = 4.25
        }
      },
      @{
        CaseName = 'Multiple properties'
        Params = [pscustomobject] @{
          name = 'Test123'
          frequency = 30
          uri = 'https://some.net'
          locations = 'AWS_US_EAST_1'
          Status = 'ENABLED'
          SlaThreshold = 4.25
        }
      }
    )

    $OptionsTestCases = @(
      @{
        CaseName = 'ValidationString'
        Params = [pscustomobject] @{
          validationString = 'testing'
        }
      },
      @{
        CaseName = 'VerifySSL'
        Params = [pscustomobject] @{
          verifySSL = $false
        }
      },
      @{
        CaseName = 'BypassHEADRequest'
        Params = [pscustomobject] @{
          bypassHEADRequest = $false
        }
      },
      @{
        CaseName = 'TreatRedirectAsFailure'
        Params = [pscustomobject]  @{
          treatRedirectAsFailure = $false
        }
      },
      @{
        CaseName = 'Multiple options'
        Params = [pscustomobject] @{
          validationString = 'testing'
          verifySSL = $false
          bypassHEADRequest = $false
          treatRedirectAsFailure = $false
        }
      }
    )
    BeforeAll {
      Mock Get-NRSyntheticMonitor -ModuleName 'NewRelicPS.SyntheticMonitors' {}
      Mock Update-NRSyntheticMonitorScript -ModuleName 'NewRelicPS.SyntheticMonitors' {}
      Mock Invoke-RestMethod -ModuleName 'NewRelicPS.SyntheticMonitors' {}
    }

    It 'Updates the monitor as expected when <CaseName> specified' -TestCases $TestCases {
      $Params | Update-NRSyntheticMonitor -APIKey $apiKey -Id '123456'
      Foreach ($key in ($Params | Get-Member | Where-Object {$_.membertype -eq 'NoteProperty'}).name) {
        Assert-MockCalled Invoke-RestMethod -ModuleName 'NewRelicPS.SyntheticMonitors' -ParameterFilter {
          ($Body | ConvertFrom-Json).$Key -eq $Params.$Key
        }
      }
    }

    # Some parameters are nested under the 'Options' object so test those as well
    It 'Updates the monitor as expected when <CaseName> specified' -TestCases $OptionsTestCases {
      $Params | Update-NRSyntheticMonitor -APIKey $apiKey -Id '123456'
      Foreach ($Key in ($Params | Get-Member | Where-Object {$_.membertype -eq 'NoteProperty'}).name) {
        Assert-MockCalled Invoke-RestMethod -ModuleName 'NewRelicPS.SyntheticMonitors' -ParameterFilter {
          ($Body | ConvertFrom-Json).options.$Key -eq $Params.$Key
        }
      }
    }

    It 'Updates the script properly when ScriptPath is provided' {
      $scriptPath = '.\tests\resources\SyntheticMonitor.Script.js'
      Update-NRSyntheticMonitor -APIKey $apiKey -Id '123456' -ScriptPath $scriptPath

      # Get base 64 script content
      $base64Script = Get-NRScriptContent -ScriptPath $scriptPath -ScriptVariables @{}

      Assert-MockCalled Update-NRSyntheticMonitorScript -ModuleName 'NewRelicPS.SyntheticMonitors' -ParameterFilter {
        $ScriptContent -eq $base64Script
      }
    }
  }
  Context 'Get-NRScriptContent' {
    BeforeAll {
      $scriptPath = '.\tests\resources\SyntheticMonitor.Script.js'
    }

    It 'Returns a Base64 encoded string' {
      $scriptContent = Get-NRScriptContent -ScriptPath $scriptPath -ScriptVariables @{}
      $scriptContent | Should -Match '^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$'
    }

    It 'Replaces variables with provided parameters' {
      $domain = '166424a7-fcc3-4527-8f26-c284d276e001.com'
      $base64ScriptContent = Get-NRScriptContent -ScriptPath $scriptPath -ScriptVariables @{ENVIRONMENT_DOMAIN_API=$domain}
      $scriptContent = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64ScriptContent))
      $scriptContent | Should -BeLike "*$domain*"
    }

    It 'Does not replace a variable if no matching parameter is provided' {
      $domain = '166424a7-fcc3-4527-8f26-c284d276e001.com'
      $base64ScriptContent = Get-NRScriptContent -ScriptPath $scriptPath -ScriptVariables @{MY_ENVIRONMENT_DOMAIN=$domain}
      $scriptContent = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64ScriptContent))
      $scriptContent | Should -BeLike "*ENVIRONMENT_DOMAIN*"
    }

    It 'Throws a terminating error if script is not found at file path provided' {
      $scriptPath = '.\tests\resources\SyntheticMonitor.NoExist.js'

      # This test also verifies the error message includes the original script path
      {Get-NRScriptContent -ScriptPath $scriptPath -ScriptVariables @{} | Should -Throw $scriptPath -ExceptionType System.IO.FileNotFoundException}
    }
  }
}