|
| 1 | +# |
| 2 | +# Licensed to the Apache Software Foundation (ASF) under one |
| 3 | +# or more contributor license agreements. See the NOTICE file |
| 4 | +# distributed with this work for additional information |
| 5 | +# regarding copyright ownership. The ASF licenses this file |
| 6 | +# to you under the Apache License, Version 2.0 (the |
| 7 | +# "License"); you may not use this file except in compliance |
| 8 | +# with the License. You may obtain a copy of the License at |
| 9 | +# |
| 10 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | +# |
| 12 | +# Unless required by applicable law or agreed to in writing, |
| 13 | +# software distributed under the License is distributed on an |
| 14 | +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | +# KIND, either express or implied. See the License for the |
| 16 | +# specific language governing permissions and limitations |
| 17 | +# under the License. |
| 18 | +# |
| 19 | + |
| 20 | +$ErrorActionPreference = 'Stop' |
| 21 | +$repositoryRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent |
| 22 | +$testRoot = Join-Path ([System.IO.Path]::GetTempPath()) ('iotdb-edge-windows-' + [guid]::NewGuid()) |
| 23 | +New-Item -ItemType Directory -Path $testRoot | Out-Null |
| 24 | +$javaStub = Join-Path $testRoot 'java.exe' |
| 25 | +$script:caseCount = 0 |
| 26 | +$portNames = @( |
| 27 | + 'cn_internal_port', 'cn_consensus_port', 'dn_rpc_port', 'dn_internal_port', |
| 28 | + 'dn_mpp_data_exchange_port', 'dn_schema_region_consensus_port', 'dn_data_region_consensus_port' |
| 29 | +) |
| 30 | + |
| 31 | +function Get-FreePorts { |
| 32 | + $result = @{} |
| 33 | + $reservations = @() |
| 34 | + try { |
| 35 | + foreach ($name in $portNames) { |
| 36 | + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) |
| 37 | + $listener.Start() |
| 38 | + $reservations += $listener |
| 39 | + $result[$name] = $listener.LocalEndpoint.Port |
| 40 | + } |
| 41 | + return $result |
| 42 | + } finally { |
| 43 | + foreach ($listener in $reservations) { |
| 44 | + $listener.Stop() |
| 45 | + } |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +function Invoke-EdgeLauncher { |
| 50 | + param( |
| 51 | + [System.Collections.IDictionary]$Ports, |
| 52 | + [string]$Locale = '', |
| 53 | + [string[]]$ExtraLines = @(), |
| 54 | + [switch]$MissingConfig |
| 55 | + ) |
| 56 | + |
| 57 | + $script:caseCount++ |
| 58 | + $caseDir = Join-Path $testRoot "case-$script:caseCount" |
| 59 | + $edgeHome = Join-Path $caseDir 'edge installation' |
| 60 | + $configDir = Join-Path $caseDir 'custom configuration' |
| 61 | + $launcherDir = Join-Path $edgeHome 'sbin/windows' |
| 62 | + $envDir = Join-Path $configDir 'windows' |
| 63 | + $javaHome = Join-Path $caseDir 'fake java' |
| 64 | + $javaBin = Join-Path $javaHome 'bin' |
| 65 | + New-Item -ItemType Directory -Path $launcherDir, $envDir, $javaBin -Force | Out-Null |
| 66 | + foreach ($file in @('start-edge.bat', 'check-edge.ps1')) { |
| 67 | + Copy-Item -LiteralPath (Join-Path $repositoryRoot "scripts/sbin/windows/$file") -Destination $launcherDir |
| 68 | + } |
| 69 | + Copy-Item -LiteralPath (Join-Path $repositoryRoot 'scripts/conf/windows/edge-env.bat') -Destination $envDir |
| 70 | + $common = Get-Content -LiteralPath (Join-Path $repositoryRoot 'scripts/conf/windows/iotdb-common.bat') -Raw |
| 71 | + Set-Content -LiteralPath (Join-Path $envDir 'iotdb-common.bat') -Value $common.Replace('@tsfile.locale.opt@', $Locale) -Encoding ASCII |
| 72 | + if (-not $MissingConfig) { |
| 73 | + $lines = @($ExtraLines) |
| 74 | + foreach ($key in $Ports.Keys) { |
| 75 | + $lines += " $key = $($Ports[$key]) " |
| 76 | + } |
| 77 | + Set-Content -LiteralPath (Join-Path $configDir 'iotdb-system.properties') -Value $lines -Encoding ASCII |
| 78 | + } |
| 79 | + |
| 80 | + Copy-Item -LiteralPath $javaStub -Destination $javaBin |
| 81 | + $argsFile = Join-Path $caseDir 'java-arguments.txt' |
| 82 | + $startInfo = [System.Diagnostics.ProcessStartInfo]::new() |
| 83 | + $startInfo.FileName = $env:ComSpec |
| 84 | + $startInfo.Arguments = '/d /c call "' + (Join-Path $launcherDir 'start-edge.bat') + '"' |
| 85 | + $startInfo.WorkingDirectory = $caseDir |
| 86 | + $startInfo.UseShellExecute = $false |
| 87 | + $startInfo.CreateNoWindow = $true |
| 88 | + $startInfo.RedirectStandardOutput = $true |
| 89 | + $startInfo.RedirectStandardError = $true |
| 90 | + $startInfo.RedirectStandardInput = $true |
| 91 | + $startInfo.EnvironmentVariables['IOTDB_HOME'] = $edgeHome |
| 92 | + $startInfo.EnvironmentVariables['IOTDB_CONF'] = $configDir |
| 93 | + $startInfo.EnvironmentVariables['JAVA_HOME'] = $javaHome |
| 94 | + $startInfo.EnvironmentVariables['EDGE_TEST_JAVA_ARGS'] = $argsFile |
| 95 | + $startInfo.EnvironmentVariables['IOTDB_JMX_OPTS'] = '' |
| 96 | + $startInfo.EnvironmentVariables['TSFILE_LOCALE_JVM_OPT'] = '-Dtsfile.locale=stale' |
| 97 | + $process = [System.Diagnostics.Process]::new() |
| 98 | + $process.StartInfo = $startInfo |
| 99 | + try { |
| 100 | + [void]$process.Start() |
| 101 | + $stdout = $process.StandardOutput.ReadToEndAsync() |
| 102 | + $stderr = $process.StandardError.ReadToEndAsync() |
| 103 | + $process.StandardInput.Close() |
| 104 | + if (-not $process.WaitForExit(30000)) { |
| 105 | + $process.Kill() |
| 106 | + throw 'Timed out running the Edge Windows launcher' |
| 107 | + } |
| 108 | + return [pscustomobject]@{ |
| 109 | + ExitCode = $process.ExitCode |
| 110 | + Output = $stdout.Result + $stderr.Result |
| 111 | + JavaInvoked = Test-Path -LiteralPath $argsFile |
| 112 | + Arguments = if (Test-Path -LiteralPath $argsFile) { Get-Content -LiteralPath $argsFile -Raw } else { '' } |
| 113 | + } |
| 114 | + } finally { |
| 115 | + $process.Dispose() |
| 116 | + } |
| 117 | +} |
| 118 | + |
| 119 | +function Assert-LaunchResult { |
| 120 | + param($Result, [bool]$ShouldLaunch, [string]$Name) |
| 121 | + if ($ShouldLaunch) { |
| 122 | + if ($Result.ExitCode -ne 0 -or -not $Result.JavaInvoked) { |
| 123 | + throw "${Name}: expected a successful Java launch. $($Result.Output)" |
| 124 | + } |
| 125 | + if ($Result.Arguments -notmatch 'org\.apache\.iotdb\.edge\.EdgeNode') { |
| 126 | + throw "${Name}: the Edge main class was not invoked" |
| 127 | + } |
| 128 | + } elseif ($Result.ExitCode -eq 0 -or $Result.JavaInvoked) { |
| 129 | + throw "${Name}: expected rejection before starting Java. $($Result.Output)" |
| 130 | + } |
| 131 | + Write-Host "PASS: $Name" |
| 132 | +} |
| 133 | + |
| 134 | +try { |
| 135 | + # Use an executable stub so batch control flow and argument quoting match a real JVM. |
| 136 | + Add-Type -OutputAssembly $javaStub -OutputType ConsoleApplication -TypeDefinition @' |
| 137 | +using System; |
| 138 | +using System.IO; |
| 139 | +
|
| 140 | +internal static class EdgeJavaStub |
| 141 | +{ |
| 142 | + private static int Main(string[] args) |
| 143 | + { |
| 144 | + if (args.Length == 1 && args[0] == "-fullversion") |
| 145 | + { |
| 146 | + Console.Error.WriteLine("openjdk full version \"17.0.5+8\""); |
| 147 | + return 0; |
| 148 | + } |
| 149 | + File.WriteAllLines(Environment.GetEnvironmentVariable("EDGE_TEST_JAVA_ARGS"), args); |
| 150 | + return 0; |
| 151 | + } |
| 152 | +} |
| 153 | +'@ |
| 154 | + |
| 155 | + $freePorts = Get-FreePorts |
| 156 | + foreach ($locale in @('', '-Dtsfile.locale=zh')) { |
| 157 | + $result = Invoke-EdgeLauncher -Ports $freePorts -Locale $locale |
| 158 | + Assert-LaunchResult $result $true "locale '$locale', custom config and paths with spaces" |
| 159 | + if ($locale -eq '') { |
| 160 | + if ($result.Arguments -match '-Dtsfile\.locale=') { |
| 161 | + throw 'The default package inherited a stale TsFile locale option' |
| 162 | + } |
| 163 | + } elseif ([regex]::Matches($result.Arguments, '-Dtsfile\.locale=zh').Count -ne 1 -or $result.Arguments -match 'tsfile\.locale=stale') { |
| 164 | + throw 'The zh package did not apply exactly one filtered TsFile locale option' |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + foreach ($name in $portNames) { |
| 169 | + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) |
| 170 | + $listener.Start() |
| 171 | + try { |
| 172 | + $ports = $freePorts.Clone() |
| 173 | + $ports[$name] = $listener.LocalEndpoint.Port |
| 174 | + $result = Invoke-EdgeLauncher -Ports $ports |
| 175 | + Assert-LaunchResult $result $false "occupied $name" |
| 176 | + if ($result.Output -notmatch "The $name $($ports[$name]) is already occupied") { |
| 177 | + throw "The occupied port was not identified correctly: $($result.Output)" |
| 178 | + } |
| 179 | + } finally { |
| 180 | + $listener.Stop() |
| 181 | + } |
| 182 | + } |
| 183 | + |
| 184 | + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 0) |
| 185 | + $listener.Start() |
| 186 | + try { |
| 187 | + $result = Invoke-EdgeLauncher -Ports $freePorts -ExtraLines @( |
| 188 | + "# cn_internal_port=$($listener.LocalEndpoint.Port)", |
| 189 | + "! dn_rpc_port=$($listener.LocalEndpoint.Port)", |
| 190 | + "cn_internal_port=$($listener.LocalEndpoint.Port)" |
| 191 | + ) |
| 192 | + Assert-LaunchResult $result $true 'comments, whitespace and the last value of a repeated property' |
| 193 | + } finally { |
| 194 | + $listener.Stop() |
| 195 | + } |
| 196 | + |
| 197 | + $listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Loopback, 10720) |
| 198 | + $listener.Start() |
| 199 | + try { |
| 200 | + $ports = $freePorts.Clone() |
| 201 | + $ports.Remove('cn_consensus_port') |
| 202 | + $result = Invoke-EdgeLauncher -Ports $ports |
| 203 | + Assert-LaunchResult $result $false 'default port for an omitted property' |
| 204 | + $result = Invoke-EdgeLauncher -Ports @{} -MissingConfig |
| 205 | + Assert-LaunchResult $result $false 'default ports when the configuration file is absent' |
| 206 | + if ($result.Output -notmatch 'cn_consensus_port 10720 is already occupied') { |
| 207 | + throw 'The missing-file fallback did not check the default ConfigNode consensus port' |
| 208 | + } |
| 209 | + } finally { |
| 210 | + $listener.Stop() |
| 211 | + } |
| 212 | + |
| 213 | + foreach ($value in @('0', '65536', 'not-a-port')) { |
| 214 | + $ports = $freePorts.Clone() |
| 215 | + $ports['dn_rpc_port'] = $value |
| 216 | + $result = Invoke-EdgeLauncher -Ports $ports |
| 217 | + Assert-LaunchResult $result $false "invalid port '$value'" |
| 218 | + } |
| 219 | + Write-Host "All $script:caseCount Windows Edge launcher cases passed." |
| 220 | +} finally { |
| 221 | + Remove-Item -LiteralPath $testRoot -Recurse -Force |
| 222 | +} |
0 commit comments