|
4 | 4 | * You should have received a copy of the CC0 legalcode along with this |
5 | 5 | * work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. |
6 | 6 | */ |
| 7 | +import groovy.json.JsonSlurper |
| 8 | + |
7 | 9 | import java.util.concurrent.Executors |
8 | 10 | import java.util.concurrent.TimeUnit |
9 | 11 |
|
@@ -150,6 +152,157 @@ static List<Map> testAllCommands(String gradleCmd, String target) { |
150 | 152 | } |
151 | 153 | } |
152 | 154 |
|
| 155 | +/* |
| 156 | + * Helper utilities for environment setup, and backup/restore |
| 157 | + * used by testMetadataGeneration. |
| 158 | + */ |
| 159 | +def withUnsetTckDir(List<String> baseArgs) { |
| 160 | + if (System.getProperty("os.name").toLowerCase().contains("windows")) { |
| 161 | + ["cmd.exe", "/d", "/c", "set GVM_TCK_TCKDIR= && " + baseArgs.join(' ')] |
| 162 | + } else { |
| 163 | + ["/usr/bin/env", "-u", "GVM_TCK_TCKDIR"] + baseArgs |
| 164 | + } |
| 165 | +} |
| 166 | + |
| 167 | +def backupDirIfExists(File srcDir, File backupDir) { |
| 168 | + boolean had = srcDir?.isDirectory() |
| 169 | + if (had) { |
| 170 | + backupDir.parentFile?.mkdirs() |
| 171 | + project.copy { |
| 172 | + from(srcDir) |
| 173 | + into(backupDir) |
| 174 | + } |
| 175 | + } |
| 176 | + had |
| 177 | +} |
| 178 | + |
| 179 | +def restoreDir(boolean had, File srcDir, File backupDir) { |
| 180 | + if (had) { |
| 181 | + project.delete(srcDir) |
| 182 | + srcDir.mkdirs() |
| 183 | + project.copy { |
| 184 | + from(backupDir) |
| 185 | + into(srcDir) |
| 186 | + } |
| 187 | + } else { |
| 188 | + project.delete(srcDir) |
| 189 | + } |
| 190 | +} |
| 191 | +def backupFileIfExists(File srcFile, File backupFile) { |
| 192 | + boolean had = srcFile?.isFile() |
| 193 | + if (had) { |
| 194 | + backupFile.parentFile?.mkdirs() |
| 195 | + backupFile.text = srcFile.getText('UTF-8') |
| 196 | + } |
| 197 | + had |
| 198 | +} |
| 199 | +def restoreFileIfBackedUp(boolean had, File srcFile, File backupFile) { |
| 200 | + if (had && backupFile?.isFile()) { |
| 201 | + srcFile.text = backupFile.getText('UTF-8') |
| 202 | + } |
| 203 | +} |
| 204 | + |
| 205 | +// Test metadata generation tasks |
| 206 | +def testMetadataGeneration(String coordinate, String gradleCmd, File logsDir, String newVersion) { |
| 207 | + |
| 208 | + def fileSuffix = coordinate.replaceAll(File.separator, "-") |
| 209 | + |
| 210 | + // Compute paths and snapshot current state to allow revert after the test |
| 211 | + def parts = coordinate.split(":") |
| 212 | + if (parts.length != 3) { |
| 213 | + throw new GradleException("Invalid coordinates '${coordinate}'. Expected 'group:artifact:version'.") |
| 214 | + } |
| 215 | + def group = parts[0] |
| 216 | + def artifact = parts[1] |
| 217 | + def version = parts[2] |
| 218 | + def gaPath = "${group}/${artifact}" |
| 219 | + def versionPath = "${gaPath}/${version}" |
| 220 | + |
| 221 | + def versionDir = new File(tck.metadataRoot.get().asFile, versionPath) |
| 222 | + def testsDir = new File(tck.testRoot.get().asFile, versionPath) |
| 223 | + |
| 224 | + def backupRoot = layout.buildDirectory.dir("gm-backups/${fileSuffix}").get().asFile |
| 225 | + def backupMetadataDir = new File(backupRoot, "metadata-backup") |
| 226 | + def backupTestsDir = new File(backupRoot, "tests-backup") |
| 227 | + backupRoot.mkdirs() |
| 228 | + boolean hadVersionDir = backupDirIfExists(versionDir, backupMetadataDir) |
| 229 | + boolean hadTestsDir = backupDirIfExists(testsDir, backupTestsDir) |
| 230 | + |
| 231 | + try { |
| 232 | + // Build base args once, then prepend an OS-specific unset of GVM_TCK_TCKDIR |
| 233 | + def baseGenArgs = [gradleCmd, "generateMetadata", "-Pcoordinates=${coordinate}", "--agentAllowedPackages=org.postgresql"] |
| 234 | + List<String> genArgs = withUnsetTckDir(baseGenArgs) |
| 235 | + def genLogFile = new File(logsDir, "generateMetadata-${fileSuffix}.log") |
| 236 | + int genExit = project.ext.runLoggedCommand(genArgs, "generateMetadata (${coordinate})", genLogFile, project.rootDir) |
| 237 | + if (genExit != 0) { |
| 238 | + throw new GradleException("generateMetadata failed with exit code ${genExit} (see ${genLogFile})") |
| 239 | + } |
| 240 | + |
| 241 | + // Verify output directory and index.json for the specific version |
| 242 | + if (!versionDir.isDirectory()) { |
| 243 | + throw new GradleException("Version directory not found: ${versionDir}") |
| 244 | + } |
| 245 | + def indexFile = new File(versionDir, "index.json") |
| 246 | + if (!indexFile.isFile()) { |
| 247 | + throw new GradleException("Missing index.json in ${versionDir}") |
| 248 | + } |
| 249 | + |
| 250 | + def actualFiles = versionDir.listFiles()?.findAll { it.isFile() && it.name != 'index.json' }?.collect { it.name }?.sort() ?: [] |
| 251 | + if (actualFiles.isEmpty()) { |
| 252 | + throw new GradleException("No metadata files found in ${versionDir} (besides index.json)") |
| 253 | + } |
| 254 | + |
| 255 | + def indexList = (List) new JsonSlurper().parse(indexFile) |
| 256 | + def sortedIndex = indexList.collect { it.toString() }.sort() |
| 257 | + if (!sortedIndex.equals(actualFiles)) { |
| 258 | + println("==== BEGIN index.json mismatch (${coordinate})") |
| 259 | + println("index.json: ${sortedIndex}") |
| 260 | + println("actual: ${actualFiles}") |
| 261 | + println("==== END index.json mismatch (${coordinate})") |
| 262 | + throw new GradleException("index.json does not match files in ${versionDir}") |
| 263 | + } |
| 264 | + println("Verified generated metadata for ${coordinate}: ${versionDir}") |
| 265 | + } finally { |
| 266 | + // Revert metadata directory changes |
| 267 | + restoreDir(hadVersionDir, versionDir, backupMetadataDir) |
| 268 | + // Revert tests directory changes (including build.gradle and user-code-filter.json) |
| 269 | + restoreDir(hadTestsDir, testsDir, backupTestsDir) |
| 270 | + // Cleanup backups |
| 271 | + project.delete(backupRoot) |
| 272 | + } |
| 273 | + |
| 274 | + |
| 275 | + def newVersionDir = new File(tck.metadataRoot.get().asFile, "${gaPath}/${newVersion}") |
| 276 | + |
| 277 | + def moduleIndexFile = new File(tck.metadataRoot.get().asFile, "${gaPath}/index.json") |
| 278 | + |
| 279 | + def fixBackupRoot = layout.buildDirectory.dir("fixnir-backups/${fileSuffix}").get().asFile |
| 280 | + def backupNewMetadataDir = new File(fixBackupRoot, "new-metadata-backup") |
| 281 | + def fixBackupTestsDir = new File(fixBackupRoot, "new-metadata-backup") |
| 282 | + def backupModuleIndexFile = new File(fixBackupRoot, "module-index.json.bak") |
| 283 | + fixBackupRoot.mkdirs() |
| 284 | + hadTestsDir = backupDirIfExists(testsDir, fixBackupTestsDir) |
| 285 | + def hadNewVersionDir = backupDirIfExists(newVersionDir, backupNewMetadataDir) |
| 286 | + def hadModuleIndexFile = backupFileIfExists(moduleIndexFile, backupModuleIndexFile) |
| 287 | + |
| 288 | + try { |
| 289 | + def baseFixArgs = [gradleCmd, "fixTestNativeImageRun", "-PtestLibraryCoordinates=${coordinate}", "-PnewLibraryVersion=${newVersion}"] |
| 290 | + List<String> fixArgs = withUnsetTckDir(baseFixArgs) |
| 291 | + def fixLogFile = new File(logsDir, "fixTestNativeImageRun-${fileSuffix}.log") |
| 292 | + int fixExit = project.ext.runLoggedCommand(fixArgs, "fixTestNativeImageRun (${coordinate} -> ${newVersion})", fixLogFile, project.rootDir) |
| 293 | + if (fixExit != 0) { |
| 294 | + throw new GradleException("fixTestNativeImageRun failed with exit code ${fixExit} (see ${fixLogFile})") |
| 295 | + } |
| 296 | + } finally { |
| 297 | + // Revert changes |
| 298 | + restoreDir(hadNewVersionDir, newVersionDir, backupNewMetadataDir) |
| 299 | + restoreDir(hadTestsDir, testsDir, fixBackupTestsDir) |
| 300 | + restoreFileIfBackedUp(hadModuleIndexFile, moduleIndexFile, backupModuleIndexFile) |
| 301 | + // Cleanup backups |
| 302 | + project.delete(fixBackupRoot) |
| 303 | + } |
| 304 | +} |
| 305 | + |
153 | 306 | tasks.register('testAllParallel') { t -> |
154 | 307 | t.group = "verification" |
155 | 308 | t.setDescription("For each target, run clean and pullAllowedDockerImages first (sequentially), then run style checks and individual testing stages (${testAllCommands('', '').collect { it.name }.join(', ')}) concurrently with isolated logs. Options: -Pcoordinates to specify a single coordinate or 1/64 for the pull step; -Pparallelism to control the number of concurrent tasks.") |
@@ -244,9 +397,11 @@ tasks.register('testAllParallel') { t -> |
244 | 397 | println("All commands succeeded for coordinates=${coordinate}. Logs in: ${logsDir}") |
245 | 398 | } |
246 | 399 | } |
| 400 | + def newVersionForFix = "42.7.4" |
247 | 401 |
|
248 | 402 | // Run parallel phases sequentially: first the selectedArtifact, then the selectedBatch |
249 | 403 | runPhaseForCoordinate(selectedArtifact) |
| 404 | + testMetadataGeneration(selectedArtifact, gradleCmd, logsDir, newVersionForFix) |
250 | 405 | runPhaseForCoordinate(selectedBatch) |
251 | 406 | } |
252 | 407 | } |
0 commit comments