PowerShell/test/powershell/engine/Basic/Telemetry.Tests.ps1

157 lines
6.9 KiB
PowerShell

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# unit tests for telemetry
# these tests aren't going to check that telemetry is being sent
# only that we're not treating the telemetry.uuid file correctly
Describe "Telemetry for shell startup" -Tag CI {
BeforeAll {
# if the telemetry file exists, move it out of the way
# the member is internal, but we can retrieve it via reflection
$cacheDir = [System.Management.Automation.Platform].GetField("CacheDirectory","NonPublic,Static").GetValue($null)
$uuidPath = Join-Path -Path $cacheDir -ChildPath telemetry.uuid
$uuidFileExists = Test-Path -Path $uuidPath
if ( $uuidFileExists ) {
$originalBytes = Get-Content -AsByteStream -Path $uuidPath
Rename-Item -Path $uuidPath -NewName "${uuidPath}.original"
}
$PWSH = (Get-Process -Id $PID).MainModule.FileName
$telemetrySet = Test-Path -Path env:POWERSHELL_TELEMETRY_OPTOUT
$SendingTelemetry = $env:POWERSHELL_TELEMETRY_OPTOUT
}
AfterAll {
# check and reset the telemetry.uuid file
if ( $uuidFileExists ) {
if ( Test-Path -Path "${uuidPath}.original" ) {
Rename-Item -NewName $uuidPath -Path "${uuidPath}.original" -Force
}
else {
[System.IO.File]::WriteAllBytes($uuidPath, $originalBytes)
}
}
if ( $telemetrySet ) {
$env:POWERSHELL_TELEMETRY_OPTOUT = $SendingTelemetry
}
}
AfterEach {
if ( Test-Path -Path $uuidPath ) {
Remove-Item -Path $uuidPath
}
if ( Test-Path -Path env:POWERSHELL_TELEMETRY_OPTOUT ) {
Remove-Item env:POWERSHELL_TELEMETRY_OPTOUT
}
}
It "Should not create a uuid file if telemetry is opted out" {
$env:POWERSHELL_TELEMETRY_OPTOUT = 1
& $PWSH -NoProfile -Command "exit"
$uuidPath | Should -Not -Exist
}
It "Should create a uuid file if telemetry is opted in" {
$env:POWERSHELL_TELEMETRY_OPTOUT = "no"
& $PWSH -NoProfile -Command "exit"
$uuidPath | Should -Exist
}
It "Should create a uuid file by default" {
if ( Test-Path env:POWERSHELL_TELEMETRY_OPTOUT ) { Remove-Item -Path env:POWERSHELL_TELEMETRY_OPTOUT }
& $PWSH -NoProfile -Command "exit"
$uuidPath | Should -Exist
}
It "Should create a property uuid file when telemetry is sent" {
$env:POWERSHELL_TELEMETRY_OPTOUT = "no"
& $PWSH -NoProfile -Command "exit"
$uuidPath | Should -Exist
(Get-ChildItem -Path $uuidPath).Length | Should -Be 16
[byte[]]$newBytes = Get-Content -AsByteStream -Path $uuidPath
[System.Guid]::New($newBytes) | Should -BeOfType System.Guid
}
It "Should not create a telemetry file if one already exists and telemetry is opted in" {
[byte[]]$bytes = [System.Guid]::NewGuid().ToByteArray()
[System.IO.File]::WriteAllBytes($uuidPath, $bytes)
& $PWSH -NoProfile -Command "exit"
[byte[]]$newBytes = Get-Content -AsByteStream -Path $uuidPath
Compare-Object -ReferenceObject $bytes -DifferenceObject $newBytes | Should -BeNullOrEmpty
}
It "Should create a new telemetry file if the current one is 00000000-0000-0000-0000-000000000000" {
[byte[]]$zeroGuid = [System.Guid]::Empty.ToByteArray()
[System.IO.File]::WriteAllBytes($uuidPath, $zeroGuid)
& $PWSH -NoProfile -Command "exit"
[byte[]]$newBytes = Get-Content -AsByteStream -Path $uuidPath
# we could legitimately have zeros in the new guid, so we can't check for that
# we're just making sure that there *is* a difference
Compare-Object -ReferenceObject $zeroGuid -DifferenceObject $newBytes | Should -Not -BeNullOrEmpty
}
It "Should create a new telemetry file if the current one is smaller than 16 bytes" {
$badBytes = [byte[]]::new(8);
[System.IO.File]::WriteAllBytes($uuidPath, $badBytes)
& $PWSH -NoProfile -Command "exit"
[byte[]]$nb = Get-Content -AsByteStream -Path $uuidPath
[System.Guid]::New($nb) | Should -BeOfType System.Guid
}
It "Should not create a new telemetry file if the current one has a valid guid and is larger than 16 bytes" {
$g = [Guid]::newGuid()
$tooManyBytes = $g.ToByteArray() * 2
[System.IO.File]::WriteAllBytes($uuidPath, $tooManyBytes)
[byte[]]$nb = Get-Content -Path $uuidPath -AsByteStream | Select-Object -First 16
$ng = [System.Guid]::new($nb)
$g | Should -Be $ng
}
It "Should properly set whether telemetry is sent based on when environment variable is not set" {
$result = & $PWSH -NoProfile -Command '[Microsoft.PowerShell.Telemetry.ApplicationInsightsTelemetry]::CanSendTelemetry'
$result | Should -Be "True"
}
$telemetryIsSetData = @(
@{ name = "set to no"; Value = "no" ; expectedValue = "True" }
@{ name = "set to 0"; Value = "0"; expectedValue = "True" }
@{ name = "set to false"; Value = "false"; expectedValue = "True" }
@{ name = "set to yes"; Value = "yes"; expectedValue = "False" }
@{ name = "set to 1"; Value = "1"; expectedValue = "False" }
@{ name = "set to true"; Value = "true"; expectedValue = "False" }
)
It "Should properly set whether telemetry is sent based on environment variable when <name>" -TestCases $telemetryIsSetData {
param ( [string]$name, [string]$value, [string]$expectedValue )
$env:POWERSHELL_TELEMETRY_OPTOUT = $value
$result = & $PWSH -NoProfile -Command '[Microsoft.PowerShell.Telemetry.ApplicationInsightsTelemetry]::CanSendTelemetry'
$result | Should -Be $expectedValue
}
It "Should resend startup event if the semaphore says we haven't sent telemetry" {
$resultJson = & $PWSH -NoProfile -c {
$telemetryType = [Microsoft.PowerShell.Telemetry.ApplicationInsightsTelemetry]
$bindingFlags = [System.Reflection.BindingFlags]"NonPublic,Static"
$initialValue = ${telemetryType}.GetMember("s_startupEventSent", $bindingFlags)[0].GetValue($null)
# force a resend of the startup telemetry
$null = ${telemetryType}.GetMember("s_startupEventSent", $bindingFlags)[0].SetValue($null,0)
$null = Get-Date | Out-String
# now check it again, it should be true now that something has executed
$finalValue = ${telemetryType}.GetMember("s_startupEventSent", $bindingFlags)[0].GetValue($null)
@{
initialValue = $initialValue
finalValue = $finalValue
} | ConvertTo-Json -Compress
}
$result = $resultJson | ConvertFrom-Json
$result.InitialValue | Should -Be 1 -Because "Should have sent telemetry on console startup"
$result.FinalValue | Should -Be 1 -Because "Should have resent telemetry"
}
}