| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
- # This script enables you running RocksDB tests by running
- # All the tests concurrently and utilizing all the cores
- Param(
- [switch]$EnableJE = $false, # Look for and use test executable, append _je to listed exclusions
- [switch]$RunAll = $false, # Will attempt discover all *_test[_je].exe binaries and run all
- # of them as Google suites. I.e. It will run test cases concurrently
- # except those mentioned as $Run, those will run as individual test cases
- # And any execlued with $ExcludeExes or $ExcludeCases
- # It will also not run any individual test cases
- # excluded but $ExcludeCasese
- [switch]$RunAllExe = $false, # Look for and use test exdcutables, append _je to exclusions automatically
- # It will attempt to run them in parallel w/o breaking them up on individual
- # test cases. Those listed with $ExcludeExes will be excluded
- [string]$SuiteRun = "", # Split test suites in test cases and run in parallel, not compatible with $RunAll
- [string]$Run = "", # Run specified executables in parallel but do not split to test cases
- [string]$ExcludeCases = "", # Exclude test cases, expects a comma separated list, no spaces
- # Takes effect when $RunAll or $SuiteRun is specified. Must have full
- # Test cases name including a group and a parameter if any
- [string]$ExcludeExes = "", # Exclude exes from consideration, expects a comma separated list,
- # no spaces. Takes effect only when $RunAll is specified
- [string]$WorkFolder = "", # Direct tests to use that folder. SSD or Ram drive are better options.
- # Number of async tasks that would run concurrently. Recommend a number below 64.
- # However, CPU utlization really depends on the storage media. Recommend ram based disk.
- # a value of 1 will run everything serially
- [int]$Concurrency = 8,
- [int]$Limit = -1 # -1 means do not limit for test purposes
- )
- # Folders and commands must be fullpath to run assuming
- # the current folder is at the root of the git enlistment
- $StartDate = (Get-Date)
- $StartDate
- $DebugPreference = "Continue"
- # These tests are not google test suites and we should guard
- # Against running them as suites
- $RunOnly = New-Object System.Collections.Generic.HashSet[string]
- $RunOnly.Add("c_test") | Out-Null
- $RunOnly.Add("compact_on_deletion_collector_test") | Out-Null
- $RunOnly.Add("merge_test") | Out-Null
- $RunOnly.Add("stringappend_test") | Out-Null # Apparently incorrectly written
- $RunOnly.Add("backupable_db_test") | Out-Null # Disabled
- $RunOnly.Add("timer_queue_test") | Out-Null # Not a gtest
- if($RunAll -and $SuiteRun -ne "") {
- Write-Error "$RunAll and $SuiteRun are not compatible"
- exit 1
- }
- if($RunAllExe -and $Run -ne "") {
- Write-Error "$RunAllExe and $Run are not compatible"
- exit 1
- }
- # If running under Appveyor assume that root
- [string]$Appveyor = $Env:APPVEYOR_BUILD_FOLDER
- if($Appveyor -ne "") {
- $RootFolder = $Appveyor
- } else {
- $RootFolder = $PSScriptRoot -replace '\\build_tools', ''
- }
- $LogFolder = -Join($RootFolder, "\db_logs\")
- $BinariesFolder = -Join($RootFolder, "\build\Debug\")
- if($WorkFolder -eq "") {
- # If TEST_TMPDIR is set use it
- [string]$var = $Env:TEST_TMPDIR
- if($var -eq "") {
- $WorkFolder = -Join($RootFolder, "\db_tests\")
- $Env:TEST_TMPDIR = $WorkFolder
- } else {
- $WorkFolder = $var
- }
- } else {
- # Override from a command line
- $Env:TEST_TMPDIR = $WorkFolder
- }
- Write-Output "Root: $RootFolder, WorkFolder: $WorkFolder"
- Write-Output "BinariesFolder: $BinariesFolder, LogFolder: $LogFolder"
- # Create test directories in the current folder
- md -Path $WorkFolder -ErrorAction Ignore | Out-Null
- md -Path $LogFolder -ErrorAction Ignore | Out-Null
- $ExcludeCasesSet = New-Object System.Collections.Generic.HashSet[string]
- if($ExcludeCases -ne "") {
- Write-Host "ExcludeCases: $ExcludeCases"
- $l = $ExcludeCases -split ' '
- ForEach($t in $l) {
- $ExcludeCasesSet.Add($t) | Out-Null
- }
- }
- $ExcludeExesSet = New-Object System.Collections.Generic.HashSet[string]
- if($ExcludeExes -ne "") {
- Write-Host "ExcludeExe: $ExcludeExes"
- $l = $ExcludeExes -split ' '
- ForEach($t in $l) {
- $ExcludeExesSet.Add($t) | Out-Null
- }
- }
- # Extract the names of its tests by running db_test with --gtest_list_tests.
- # This filter removes the "#"-introduced comments, and expands to
- # fully-qualified names by changing input like this:
- #
- # DBTest.
- # Empty
- # WriteEmptyBatch
- # MultiThreaded/MultiThreadedDBTest.
- # MultiThreaded/0 # GetParam() = 0
- # MultiThreaded/1 # GetParam() = 1
- #
- # into this:
- #
- # DBTest.Empty
- # DBTest.WriteEmptyBatch
- # MultiThreaded/MultiThreadedDBTest.MultiThreaded/0
- # MultiThreaded/MultiThreadedDBTest.MultiThreaded/1
- #
- # Output into the parameter in a form TestName -> Log File Name
- function ExtractTestCases([string]$GTestExe, $HashTable) {
- $Tests = @()
- # Run db_test to get a list of tests and store it into $a array
- &$GTestExe --gtest_list_tests | tee -Variable Tests | Out-Null
- # Current group
- $Group=""
- ForEach( $l in $Tests) {
- # Leading whitespace is fine
- $l = $l -replace '^\s+',''
- # Trailing dot is a test group but no whitespace
- if ($l -match "\.$" -and $l -notmatch "\s+") {
- $Group = $l
- } else {
- # Otherwise it is a test name, remove leading space
- $test = $l
- # remove trailing comment if any and create a log name
- $test = $test -replace '\s+\#.*',''
- $test = "$Group$test"
- if($ExcludeCasesSet.Contains($test)) {
- Write-Warning "$test case is excluded"
- continue
- }
- $test_log = $test -replace '[\./]','_'
- $test_log += ".log"
- $log_path = -join ($LogFolder, $test_log)
- # Add to a hashtable
- $HashTable.Add($test, $log_path);
- }
- }
- }
- # The function removes trailing .exe siffix if any,
- # creates a name for the log file
- # Then adds the test name if it was not excluded into
- # a HashTable in a form of test_name -> log_path
- function MakeAndAdd([string]$token, $HashTable) {
- $test_name = $token -replace '.exe$', ''
- $log_name = -join ($test_name, ".log")
- $log_path = -join ($LogFolder, $log_name)
- $HashTable.Add($test_name, $log_path)
- }
- # This function takes a list of Suites to run
- # Lists all the test cases in each of the suite
- # and populates HashOfHashes
- # Ordered by suite(exe) @{ Exe = @{ TestCase = LogName }}
- function ProcessSuites($ListOfSuites, $HashOfHashes) {
- $suite_list = $ListOfSuites
- # Problem: if you run --gtest_list_tests on
- # a non Google Test executable then it will start executing
- # and we will get nowhere
- ForEach($suite in $suite_list) {
- if($RunOnly.Contains($suite)) {
- Write-Warning "$suite is excluded from running as Google test suite"
- continue
- }
- if($EnableJE) {
- $suite += "_je"
- }
- $Cases = [ordered]@{}
- $Cases.Clear()
- $suite_exe = -Join ($BinariesFolder, $suite)
- ExtractTestCases -GTestExe $suite_exe -HashTable $Cases
- if($Cases.Count -gt 0) {
- $HashOfHashes.Add($suite, $Cases);
- }
- }
- # Make logs and run
- if($CasesToRun.Count -lt 1) {
- Write-Error "Failed to extract tests from $SuiteRun"
- exit 1
- }
- }
- # This will contain all test executables to run
- # Hash table that contains all non suite
- # Test executable to run
- $TestExes = [ordered]@{}
- # Check for test exe that are not
- # Google Test Suites
- # Since this is explicitely mentioned it is not subject
- # for exclusions
- if($Run -ne "") {
- $test_list = $Run -split ' '
- ForEach($t in $test_list) {
- if($EnableJE) {
- $t += "_je"
- }
- MakeAndAdd -token $t -HashTable $TestExes
- }
- if($TestExes.Count -lt 1) {
- Write-Error "Failed to extract tests from $Run"
- exit 1
- }
- } elseif($RunAllExe) {
- # Discover all the test binaries
- if($EnableJE) {
- $pattern = "*_test_je.exe"
- } else {
- $pattern = "*_test.exe"
- }
- $search_path = -join ($BinariesFolder, $pattern)
- Write-Host "Binaries Search Path: $search_path"
- $DiscoveredExe = @()
- dir -Path $search_path | ForEach-Object {
- $DiscoveredExe += ($_.Name)
- }
- # Remove exclusions
- ForEach($e in $DiscoveredExe) {
- $e = $e -replace '.exe$', ''
- $bare_name = $e -replace '_je$', ''
- if($ExcludeExesSet.Contains($bare_name)) {
- Write-Warning "Test $e is excluded"
- continue
- }
- MakeAndAdd -token $e -HashTable $TestExes
- }
- if($TestExes.Count -lt 1) {
- Write-Error "Failed to discover test executables"
- exit 1
- }
- }
- # Ordered by exe @{ Exe = @{ TestCase = LogName }}
- $CasesToRun = [ordered]@{}
- if($SuiteRun -ne "") {
- $suite_list = $SuiteRun -split ' '
- ProcessSuites -ListOfSuites $suite_list -HashOfHashes $CasesToRun
- } elseif ($RunAll) {
- # Discover all the test binaries
- if($EnableJE) {
- $pattern = "*_test_je.exe"
- } else {
- $pattern = "*_test.exe"
- }
- $search_path = -join ($BinariesFolder, $pattern)
- Write-Host "Binaries Search Path: $search_path"
- $ListOfExe = @()
- dir -Path $search_path | ForEach-Object {
- $ListOfExe += ($_.Name)
- }
- # Exclude those in RunOnly from running as suites
- $ListOfSuites = @()
- ForEach($e in $ListOfExe) {
- $e = $e -replace '.exe$', ''
- $bare_name = $e -replace '_je$', ''
- if($ExcludeExesSet.Contains($bare_name)) {
- Write-Warning "Test $e is excluded"
- continue
- }
- if($RunOnly.Contains($bare_name)) {
- MakeAndAdd -token $e -HashTable $TestExes
- } else {
- $ListOfSuites += $bare_name
- }
- }
- ProcessSuites -ListOfSuites $ListOfSuites -HashOfHashes $CasesToRun
- }
- # Invoke a test with a filter and redirect all output
- $InvokeTestCase = {
- param($exe, $test, $log);
- &$exe --gtest_filter=$test > $log 2>&1
- }
- # Invoke all tests and redirect output
- $InvokeTestAsync = {
- param($exe, $log)
- &$exe > $log 2>&1
- }
- # Hash that contains tests to rerun if any failed
- # Those tests will be rerun sequentially
- # $Rerun = [ordered]@{}
- # Test limiting factor here
- [int]$count = 0
- # Overall status
- [bool]$script:success = $true;
- function RunJobs($Suites, $TestCmds, [int]$ConcurrencyVal)
- {
- # Array to wait for any of the running jobs
- $jobs = @()
- # Hash JobToLog
- $JobToLog = @{}
- # Wait for all to finish and get the results
- while(($JobToLog.Count -gt 0) -or
- ($TestCmds.Count -gt 0) -or
- ($Suites.Count -gt 0)) {
- # Make sure we have maximum concurrent jobs running if anything
- # and the $Limit either not set or allows to proceed
- while(($JobToLog.Count -lt $ConcurrencyVal) -and
- ((($TestCmds.Count -gt 0) -or ($Suites.Count -gt 0)) -and
- (($Limit -lt 0) -or ($count -lt $Limit)))) {
- # We always favore suites to run if available
- [string]$exe_name = ""
- [string]$log_path = ""
- $Cases = @{}
- if($Suites.Count -gt 0) {
- # Will the first one
- ForEach($e in $Suites.Keys) {
- $exe_name = $e
- $Cases = $Suites[$e]
- break
- }
- [string]$test_case = ""
- [string]$log_path = ""
- ForEach($c in $Cases.Keys) {
- $test_case = $c
- $log_path = $Cases[$c]
- break
- }
- Write-Host "Starting $exe_name::$test_case"
- [string]$Exe = -Join ($BinariesFolder, $exe_name)
- $job = Start-Job -Name "$exe_name::$test_case" -ArgumentList @($Exe,$test_case,$log_path) -ScriptBlock $InvokeTestCase
- $JobToLog.Add($job, $log_path)
- $Cases.Remove($test_case)
- if($Cases.Count -lt 1) {
- $Suites.Remove($exe_name)
- }
- } elseif ($TestCmds.Count -gt 0) {
- ForEach($e in $TestCmds.Keys) {
- $exe_name = $e
- $log_path = $TestCmds[$e]
- break
- }
- Write-Host "Starting $exe_name"
- [string]$Exe = -Join ($BinariesFolder, $exe_name)
- $job = Start-Job -Name $exe_name -ScriptBlock $InvokeTestAsync -ArgumentList @($Exe,$log_path)
- $JobToLog.Add($job, $log_path)
- $TestCmds.Remove($exe_name)
- } else {
- Write-Error "In the job loop but nothing to run"
- exit 1
- }
- ++$count
- } # End of Job starting loop
- if($JobToLog.Count -lt 1) {
- break
- }
- $jobs = @()
- foreach($k in $JobToLog.Keys) { $jobs += $k }
- $completed = Wait-Job -Job $jobs -Any
- $log = $JobToLog[$completed]
- $JobToLog.Remove($completed)
- $message = -join @($completed.Name, " State: ", ($completed.State))
- $log_content = @(Get-Content $log)
- if($completed.State -ne "Completed") {
- $script:success = $false
- Write-Warning $message
- $log_content | Write-Warning
- } else {
- # Scan the log. If we find PASSED and no occurrence of FAILED
- # then it is a success
- [bool]$pass_found = $false
- ForEach($l in $log_content) {
- if(($l -match "^\[\s+FAILED") -or
- ($l -match "Assertion failed:")) {
- $pass_found = $false
- break
- }
- if(($l -match "^\[\s+PASSED") -or
- ($l -match " : PASSED$") -or
- ($l -match "^PASS$") -or # Special c_test case
- ($l -match "Passed all tests!") ) {
- $pass_found = $true
- }
- }
- if(!$pass_found) {
- $script:success = $false;
- Write-Warning $message
- $log_content | Write-Warning
- } else {
- Write-Host $message
- }
- }
- # Remove cached job info from the system
- # Should be no output
- Receive-Job -Job $completed | Out-Null
- }
- }
- RunJobs -Suites $CasesToRun -TestCmds $TestExes -ConcurrencyVal $Concurrency
- $EndDate = (Get-Date)
- New-TimeSpan -Start $StartDate -End $EndDate |
- ForEach-Object {
- "Elapsed time: {0:g}" -f $_
- }
- if(!$script:success) {
- # This does not succeed killing off jobs quick
- # So we simply exit
- # Remove-Job -Job $jobs -Force
- # indicate failure using this exit code
- exit 1
- }
- exit 0
-
|